2012년 9월 4일 화요일

ffmpeg audio encoding/decoding

< Encoder.h >
 #ifndef __ENCODER_H__  
 #define __ENCODER_H__  
 #include <windows.h>  
 extern "C" {  
 #include "libavcodec\avcodec.h"  
 }  
 class Encoder  
 {  
 public:  
      Encoder();  
      virtual ~Encoder();  
      static void initCodec();  
      virtual void close();  
      virtual int encodeFrame(AVFrame *frame) = 0;  
      AVFrame* frame() { return m_pFrame; }  
      unsigned char* outBuf() { return m_pOutBuf; }  
      int outBufSize() { return m_nOutBufSize; }  
 protected:  
      int prepareOpen(enum AVCodecID codecId);  
 protected:  
      AVCodec*          m_pCodec;  
      AVCodecContext*     m_pCodecCtx;  
      AVPacket          m_avPacket;  
      AVFrame*          m_pFrame;  
      unsigned char*     m_pOutBuf;  
      int                    m_nOutBufSize;  
      int                    m_nOutBufMaxSize;  
      static HANDLE     m_hMutexInit;  
      static bool          m_bInit;  
      static int          m_nCPU;  
 };  
 #endif  

< Encoder.cpp >
 #include "Encoder.h"  
 #include "GlobalEnv.h"  
 #include "FFMPEGUtil.h"  
 bool Encoder::m_bInit = false;  
 int Encoder::m_nCPU = 1;  
 HANDLE Encoder::m_hMutexInit = CreateMutex(NULL, FALSE, NULL);  
 Encoder::Encoder() : m_pCodec(NULL), m_pCodecCtx(NULL), m_pFrame(NULL)   
 {  
      initCodec();  
      m_pOutBuf = NULL;  
      m_nOutBufMaxSize = m_nOutBufSize = 0;  
 }  
 Encoder::~Encoder()  
 {  
      close();  
 }  
 void Encoder::initCodec()  
 {  
      WaitForSingleObject(m_hMutexInit, INFINITE);  
      if (!m_bInit) {  
           InitFFmpegLib();  
           SYSTEM_INFO sysinfo;  
           GetSystemInfo(&sysinfo);  
           m_nCPU = sysinfo.dwNumberOfProcessors;  
           m_bInit = true;  
      }  
      ReleaseMutex(m_hMutexInit);  
 }  
 int Encoder::prepareOpen(enum AVCodecID codecId)  
 {  
      av_init_packet(&m_avPacket);  
      m_pCodec = avcodec_find_encoder(codecId);  
      if (!m_pCodec) {  
           DXPRINTF("avcodec_find_encoder failed to find codec %d\n", codecId);  
           return -1;  
      }  
      m_pCodecCtx = avcodec_alloc_context3(m_pCodec);  
      if (!m_pCodecCtx) {  
           DXPRINTF("avcodec_alloc_context3 failed\n");  
           return -1;  
      }  
      m_pFrame = avcodec_alloc_frame();  
      if (!m_pFrame) {  
           DXPRINTF("avcodec_alloc_frame failed\n");            
           return -1;  
      }  
      return 0;  
 }  
 void Encoder::close()  
 {  
      if (m_pCodecCtx) {  
           avcodec_close(m_pCodecCtx);  
           av_free(m_pCodecCtx);  
           m_pCodecCtx = NULL;  
      }  
      avcodec_free_frame(&m_pFrame);  
      if (m_pOutBuf) {  
           delete[] m_pOutBuf;  
           m_pOutBuf = NULL;  
      }  
      m_nOutBufMaxSize = m_nOutBufSize = 0;  
 }  

< AudioEncoder.h >
 #ifndef __AUDIO_ENCODER_H__  
 #define __AUDIO_ENCODER_H__  
 #include "Encoder.h"  
 class AudioEncoder : public Encoder  
 {  
 public:  
      AudioEncoder();  
      virtual ~AudioEncoder();  
      int open(enum AVCodecID codec_id, int bit_rate, int sample_rate, int channels, int channel_layout, enum AVSampleFormat sample_fmt);  
      virtual void close();  
      virtual int encodeFrame(AVFrame *frame);  
      int prepareAudioFrame(unsigned short *pData, int size, int nb_samples);  
 };  
 #endif  

< AudioEncoder.cpp >
 #include "AudioEncoder.h"  
 #include "GlobalEnv.h"  
 /* check that a given sample format is supported by the encoder */  
 static int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt)  
 {  
   const enum AVSampleFormat *p = codec->sample_fmts;  
   while (*p != AV_SAMPLE_FMT_NONE) {  
     if (*p == sample_fmt)  
       return 1;  
     p++;  
   }  
   return 0;  
 }  
 /* just pick the highest supported samplerate */  
 static int select_sample_rate(AVCodec *codec)  
 {  
   const int *p;  
   int best_samplerate = 0;  
   if (!codec->supported_samplerates)  
     return 44100;  
   p = codec->supported_samplerates;  
   while (*p) {  
     best_samplerate = FFMAX(*p, best_samplerate);  
     p++;  
   }  
   return best_samplerate;  
 }  
 /* select layout with the highest channel count */  
 static int select_channel_layout(AVCodec *codec)  
 {  
   const uint64_t *p;  
   uint64_t best_ch_layout = 0;  
   int best_nb_channels  = 0;  
   if (!codec->channel_layouts)  
     return AV_CH_LAYOUT_STEREO;  
   p = codec->channel_layouts;  
   while (*p) {  
     int nb_channels = av_get_channel_layout_nb_channels(*p);  
     if (nb_channels > best_nb_channels) {  
       best_ch_layout  = *p;  
       best_nb_channels = nb_channels;  
     }  
     p++;  
   }  
   return best_ch_layout;  
 }  
 AudioEncoder::AudioEncoder() : Encoder()  
 {       
 }  
 AudioEncoder::~AudioEncoder()  
 {  
 }  
 int AudioEncoder::open(AVCodecID codec_id, int bit_rate, int sample_rate, int channels, int channel_layout, AVSampleFormat sample_fmt)  
 {  
      int err;  
      char errbuf[128];  
      err = prepareOpen(codec_id);  
      if (err < 0) return -1;  
      m_pCodecCtx->bit_rate = bit_rate;  
      m_pCodecCtx->sample_rate = sample_rate == 0 ? select_sample_rate(m_pCodec) : sample_rate;  
      m_pCodecCtx->channel_layout = channel_layout == 0 ? select_channel_layout(m_pCodec) : channel_layout;  
      m_pCodecCtx->channels = channels == 0 ? av_get_channel_layout_nb_channels(m_pCodecCtx->channel_layout) : channels;  
      m_pCodecCtx->sample_fmt = sample_fmt;  
      if (!check_sample_fmt(m_pCodec, m_pCodecCtx->sample_fmt)) {  
           DXPRINTF("failed to open audio encoder, Encoder does not support sample format %s\n",  
                av_get_sample_fmt_name(m_pCodecCtx->sample_fmt));  
           return -1;  
      }  
      if (err=avcodec_open2(m_pCodecCtx, m_pCodec, NULL) < 0) {  
           av_strerror(err, errbuf, sizeof(errbuf));  
           DXPRINTF("avcodec_open2 %s open failed, err: %d %s\n", avcodec_get_name(codec_id), err, errbuf);  
           return -1;  
      }  
      DXPRINTF("audio encoder opened %s\n", avcodec_get_name(codec_id));  
      return 0;  
 }  
 void AudioEncoder::close()  
 {  
      Encoder::close();  
 }  
 int AudioEncoder::prepareAudioFrame(unsigned short *pData, int size, int nb_samples)  
 {  
      int err;  
      char errbuf[128];  
      avcodec_get_frame_defaults(m_pFrame);  
      m_pFrame->nb_samples = nb_samples == 0 ? m_pCodecCtx->frame_size : nb_samples;  
      m_pFrame->format = m_pCodecCtx->sample_fmt;  
      err = avcodec_fill_audio_frame(m_pFrame, m_pCodecCtx->channels, m_pCodecCtx->sample_fmt,  
           (const uint8_t *)pData, size, 0);  
      if (err < 0) {  
           av_strerror(err, errbuf, sizeof(errbuf));  
           DXPRINTF("avcodec_fill_audio_frame failed, err : %d %s\n", err, errbuf);  
           return -1;  
      }  
      return 0;  
 }  
 int AudioEncoder::encodeFrame(AVFrame *frame)  
 {  
      int err;  
      char errbuf[128];  
      av_init_packet(&m_avPacket);  
      m_avPacket.data = NULL;  
      m_avPacket.size = 0;  
      int got_output;  
      err = avcodec_encode_audio2(m_pCodecCtx, &m_avPacket, frame, &got_output);  
      if (err < 0) {  
           av_strerror(err, errbuf, sizeof(errbuf));  
           DXPRINTF("avcodec_encode_audio2 failed, err : %d %s\n", err, errbuf);  
           return -1;  
      }  
      if (got_output) {            
           if (m_avPacket.size > 0) {  
                if (m_nOutBufMaxSize < m_avPacket.size) {  
                     if (m_pOutBuf) delete[] m_pOutBuf;  
                     m_pOutBuf = new unsigned char[m_avPacket.size];  
                     m_nOutBufMaxSize = m_avPacket.size;  
                }  
                memcpy(m_pOutBuf, m_avPacket.data, m_avPacket.size);                 
           }  
           m_nOutBufSize = m_avPacket.size;  
           av_free_packet(&m_avPacket);  
      }  
      return got_output == 1 ? 0 : -1;  
 }  

< AudioEncoder 사용 >
 AudioEncoder*     m_pEncoder = new AudioEncoder();  
 m_pEncoder->open(AV_CODEC_ID_PCM_MULAW, 64000, 8000, 1, AV_CH_LAYOUT_MONO, AV_SAMPLE_FMT_S16);  
 ...  
 m_pEncoder->prepareAudioFrame((unsigned short*)pData, size, nb_samples);  
 int ret = m_pEncoder->encodeFrame(m_pEncoder->frame());
if (ret > 0) {  
   fwrite(m_pEncoder->outBuf(), m_pEncoder->outBufSize(), 1, fp);  
 } 
 ...  
 m_pEncoder->close();  
 delete m_pEncoder;  

< Decoder.h >
 #ifndef __DECODER_H__  
 #define __DECODER_H__  
 #include <windows.h>  
 extern "C" {  
 #include "libavcodec\avcodec.h"  
 }  
 #define MAX_DECODE_BUFFER_SIZE               (1024*1024)  
 class Decoder  
 {  
 public:  
      Decoder();  
      virtual ~Decoder();  
      static void initCodec();  
      virtual int open(enum AVCodecID codecId, int channel);  
      virtual int open(AVCodecContext *codec, int channel);  
      virtual void close();  
      virtual int decodeFrame(unsigned char *inBuf, int inLen, AVFrame *frame) = 0;  
      void flush();  
      enum AVCodecID codecID();  
      AVFrame* frame() { return m_pFrame; }  
      int width();  
      int height();  
      enum AVPixelFormat pixelFormat();  
 protected:  
      virtual int open(enum AVCodecID codecId, AVCodecContext *codec, int channel) = 0;  
      int prepareOpen(enum AVCodecID codecId, AVCodecContext *codec);  
      void prepareDecBuffer(unsigned char *inBuf, int inLen);  
 protected:  
      AVCodec*          m_pCodec;  
      AVCodecContext*     m_pCodecCtx;  
      AVFrame*          m_pFrame;  
      AVPacket          m_avPacket;  
      unsigned char*     m_pDecBuffer;  
      int                    m_nDecBufferSize;  
      bool               m_bCodecCtxAlloc;  
      static HANDLE     m_hMutexInit;  
      static bool          m_bInit;  
      static int          m_nCPU;  
      // dump  
      FILE               *m_pFile;  
 };  
 #endif  

< Decoder.cpp >
 #include "Decoder.h"  
 #include "GlobalEnv.h"  
 #include "FFMPEGUtil.h"  
 bool Decoder::m_bInit = false;  
 int Decoder::m_nCPU = 1;  
 HANDLE Decoder::m_hMutexInit = CreateMutex(NULL, FALSE, NULL);  
 Decoder::Decoder() : m_pCodec(NULL), m_pCodecCtx(NULL), m_pFrame(NULL), m_bCodecCtxAlloc(false), m_pFile(NULL)  
 {  
      initCodec();  
      m_pDecBuffer = new unsigned char[MAX_DECODE_BUFFER_SIZE];  
      m_nDecBufferSize = MAX_DECODE_BUFFER_SIZE;  
 }  
 Decoder::~Decoder()  
 {  
      if (m_pDecBuffer) {  
           delete[] m_pDecBuffer;  
           m_pDecBuffer = NULL;  
      }  
 }  
 void Decoder::initCodec()  
 {  
      WaitForSingleObject(m_hMutexInit, INFINITE);  
      if (!m_bInit) {  
           InitFFmpegLib();  
           SYSTEM_INFO sysinfo;  
           GetSystemInfo(&sysinfo);  
           m_nCPU = sysinfo.dwNumberOfProcessors;  
           m_bInit = true;  
      }  
      ReleaseMutex(m_hMutexInit);  
 }  
 int Decoder::open(AVCodecID codecId, int channel)  
 {  
      return open(codecId, NULL, channel);  
 }  
 int Decoder::open(AVCodecContext *codec, int channel)  
 {  
      return open(codec->codec_id, codec, channel);  
 }  
 int Decoder::prepareOpen(enum AVCodecID codecId, AVCodecContext *codec)  
 {  
      av_init_packet(&m_avPacket);  
      m_pCodec = avcodec_find_decoder(codecId);  
      if (!m_pCodec) {  
           DXPRINTF("avcodec_find_decoder failed to find codec %d\n", codecId);  
           return -1;  
      }  
      if (codec) {  
           m_pCodecCtx = codec;  
           m_bCodecCtxAlloc = false;  
      } else {  
           m_pCodecCtx = avcodec_alloc_context3(m_pCodec);  
           if (!m_pCodecCtx) {  
                DXPRINTF("avcodec_alloc_context3 failed\n");  
                return -1;  
           }  
           m_bCodecCtxAlloc = true;  
      }  
      m_pFrame = avcodec_alloc_frame();  
      if (!m_pFrame) {  
           DXPRINTF("avcodec_alloc_frame failed\n");            
           return -1;  
      }  
      return 0;  
 }  
 void Decoder::close()  
 {  
      if (m_bCodecCtxAlloc) {  
           if (m_pCodecCtx)  
                avcodec_close(m_pCodecCtx);  
           av_free(m_pCodecCtx);  
           m_bCodecCtxAlloc = false;  
      }  
      m_pCodecCtx = NULL;  
      avcodec_free_frame(&m_pFrame);  
      if (m_pFile) {  
           fclose(m_pFile);  
           m_pFile = NULL;  
      }  
 }  
 enum AVCodecID Decoder::codecID()  
 {  
      if (m_pCodecCtx)  
           return m_pCodecCtx->codec_id;  
      return AV_CODEC_ID_NONE;  
 }  
 int Decoder::width()  
 {  
      if (m_pCodecCtx)  
           return m_pCodecCtx->width;  
      return 0;  
 }  
 int Decoder::height()  
 {  
      if (m_pCodecCtx)  
           return m_pCodecCtx->height;  
      return 0;  
 }  
 enum AVPixelFormat Decoder::pixelFormat()  
 {  
      if (m_pCodecCtx)  
           return m_pCodecCtx->pix_fmt;  
      return AV_PIX_FMT_NONE;  
 }  
 void Decoder::prepareDecBuffer(unsigned char *inBuf, int inLen)  
 {  
      if (inLen+FF_INPUT_BUFFER_PADDING_SIZE > m_nDecBufferSize) {  
           delete[] m_pDecBuffer;  
           m_pDecBuffer = new unsigned char[inLen+FF_INPUT_BUFFER_PADDING_SIZE];  
           m_nDecBufferSize = inLen+FF_INPUT_BUFFER_PADDING_SIZE;  
      }  
      memset(&m_pDecBuffer[inLen], 0, FF_INPUT_BUFFER_PADDING_SIZE);  
      memcpy(m_pDecBuffer, inBuf, inLen);  
      av_init_packet(&m_avPacket);  
      m_avPacket.data = m_pDecBuffer;  
      m_avPacket.size = inLen;  
 }  
 void Decoder::flush()  
 {  
      if (m_pCodecCtx)  
           avcodec_flush_buffers(m_pCodecCtx);  
 }  

< AudioDecoder.h>
 #ifndef __AUDIO_DECODER_H__  
 #define __AUDIO_DECODER_H__  
 #include "Decoder.h"  
 extern "C" {  
 #include "libswresample\swresample.h"  
 #include "libavutil\opt.h"  
 }  
 class AudioDecoder : public Decoder  
 {  
 public:  
      AudioDecoder();  
      virtual ~AudioDecoder();  
      virtual void close();  
      virtual int decodeFrame(unsigned char *inBuf, int inLen, AVFrame *frame);  
      unsigned char* outBuf() { return m_pOutBuf; }  
      int outBufSize() { return m_nOutBufSize; }  
      void setExtraData(unsigned char *extradata, int extradatasize);  
 protected:  
      virtual int open(enum AVCodecID codecId, AVCodecContext *codec, int channel);  
      int initResampler(uint64_t channel_layout, int sample_rate, enum AVSampleFormat sample_fmt);  
      int checkResampler();  
 protected:  
      struct SwrContext*     m_pSwrCtx;  
      unsigned char*     m_pOutBuf;  
      int                    m_nOutBufSize;  
      int                    m_nOutBufMaxSize;  
      unsigned char*     m_pExtraData;  
      int                    m_nExtraDataSize;  
 };  
 #endif  

< AudioDecoder.cpp >
 #include "AudioDecoder.h"  
 #include "GlobalEnv.h"  
 AudioDecoder::AudioDecoder() : Decoder(),  
 m_pSwrCtx(NULL), m_pOutBuf(NULL), m_nOutBufSize(0), m_nOutBufMaxSize(0), m_pExtraData(NULL), m_nExtraDataSize(0)  
 {  
 }  
 AudioDecoder::~AudioDecoder()  
 {  
 }  
 int AudioDecoder::open(enum AVCodecID codecId, AVCodecContext *codec, int channel)  
 {  
      int err;  
      char errbuf[128];  
      err = prepareOpen(codecId, codec);  
      if (err < 0) return -1;  
      if (m_bCodecCtxAlloc) {  
           m_pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;  
           m_pCodecCtx->channels = channel;  
           if (codecId == AV_CODEC_ID_PCM_MULAW) {  
                m_pCodecCtx->sample_fmt = AV_SAMPLE_FMT_U8;  
           } else if (codecId == AV_CODEC_ID_AAC) {  
                if (m_pExtraData) {  
                     m_pCodecCtx->extradata = m_pExtraData;  
                     m_pCodecCtx->extradata_size = m_nExtraDataSize;  
                }  
                m_pCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;  
           } else {  
                m_pCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;  
           }  
      }  
      if (err=avcodec_open2(m_pCodecCtx, m_pCodec, NULL) < 0) {  
           av_strerror(err, errbuf, sizeof(errbuf));  
           DXPRINTF("avcodec_open2 %s open failed, err: %d %s\n", avcodec_get_name(codecId), err, errbuf);  
           goto exit;  
      }  
      int channel_layout = m_pCodecCtx->channel_layout;  
      if (channel_layout == 0) {  
           channel_layout = av_get_default_channel_layout(m_pCodecCtx->channels);  
      }  
      err = initResampler(channel_layout, m_pCodecCtx->sample_rate, m_pCodecCtx->sample_fmt);  
      if (err < 0) goto exit;  
      DXPRINTF("audio decoder opened %s\n", avcodec_get_name(codecId));  
 exit:  
      return err;  
 }  
 int AudioDecoder::initResampler(uint64_t channel_layout, int sample_rate, enum AVSampleFormat sample_fmt)  
 {  
      int err;  
      char errbuf[128];  
      if (m_pSwrCtx) {  
           swr_free(&m_pSwrCtx);  
           m_pSwrCtx = NULL;  
      }  
      m_pSwrCtx = swr_alloc();  
      av_opt_set_int(m_pSwrCtx, "in_channel_layout", channel_layout, 0);  
      av_opt_set_int(m_pSwrCtx, "in_sample_rate", sample_rate, 0);  
      av_opt_set_sample_fmt(m_pSwrCtx, "in_sample_fmt", sample_fmt, 0);  
      av_opt_set_int(m_pSwrCtx, "out_channel_layout", channel_layout, 0);  
      av_opt_set_int(m_pSwrCtx, "out_sample_rate", sample_rate, 0);  
      av_opt_set_sample_fmt(m_pSwrCtx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);  
      err = swr_init(m_pSwrCtx);  
      if (err < 0) {  
           av_strerror(err, errbuf, sizeof(errbuf));  
           DXPRINTF("swr_init failed, err: %d %s\n", err, errbuf);  
           return err;  
      }  
      return 0;  
 }  
 void AudioDecoder::close()  
 {  
      Decoder::close();  
      if (m_pSwrCtx) {  
           swr_free(&m_pSwrCtx);  
           m_pSwrCtx = NULL;  
      }  
      if (m_pExtraData) {  
           delete[] m_pExtraData;  
           m_pExtraData = NULL;  
           m_nExtraDataSize = 0;  
      }  
      if (m_pOutBuf) {  
           delete[] m_pOutBuf;  
           m_pOutBuf = NULL;  
           m_nOutBufMaxSize = m_nOutBufSize = 0;  
      }  
      if (m_pFile) {  
           fclose(m_pFile);  
           m_pFile = NULL;  
      }  
 }  
 int AudioDecoder::decodeFrame(unsigned char *inBuf, int inLen, AVFrame *frame)  
 {  
      if (!m_pCodecCtx || !inBuf || inLen <= 0) return 0;  
      int retLen = 0, got_frame;  
      prepareDecBuffer(inBuf, inLen);  
      __try  
      {  
           retLen = avcodec_decode_audio4(m_pCodecCtx, m_pFrame, &got_frame, &m_avPacket);  
      }  
      __except (EXCEPTION_EXECUTE_HANDLER)  
      {  
           GlobalEnv::WriteLogFile("[%s] avcodec_decode_audio4 crashed, (exception code : 0x%x)",   
                __FUNCTION__, GetExceptionCode());  
      }  
      if (retLen <= 0) {  
           DXPRINTF("audio decode error : %d\n", retLen);  
           return retLen;  
      }  
      int out_size = av_samples_get_buffer_size(NULL, m_pCodecCtx->channels, m_pFrame->nb_samples,  
           m_pCodecCtx->sample_fmt, 1);  
      if (out_size > m_nOutBufMaxSize) {  
           if (m_pOutBuf) delete[] m_pOutBuf;  
           m_pOutBuf = new unsigned char[out_size];  
           m_nOutBufMaxSize = out_size;  
      }  
      if (m_pSwrCtx) {  
           // audio resampling  
           if (checkResampler() < 0) return -1;  
           __try  
           {  
                retLen = swr_convert(m_pSwrCtx, &m_pOutBuf, out_size,   
                     (const uint8_t **)m_pFrame->extended_data, m_pFrame->nb_samples);  
           }  
           __except (EXCEPTION_EXECUTE_HANDLER)  
           {  
                GlobalEnv::WriteLogFile("[%s] swr_convert crashed, (exception code : 0x%x)",  
                     __FUNCTION__, GetExceptionCode());  
           }  
      } else {  
           if (m_pFrame->channels == 1) {  
                memcpy(m_pOutBuf, m_pFrame->extended_data[0], out_size);  
           } else {  
                uint8_t *data0 = m_pFrame->extended_data[0];  
                uint8_t *data1 = m_pFrame->extended_data[1];  
                int c = 0;  
                for (int i=0; i<out_size/2; i+=2) {  
                     m_pOutBuf[c++] = data0[i]; m_pOutBuf[c++] = data0[i+1];  
                     m_pOutBuf[c++] = data1[i]; m_pOutBuf[c++] = data1[i+1];  
                }  
                out_size = c;  
           }  
      }  
      out_size = retLen*m_pCodecCtx->channels*av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);  
      m_nOutBufSize = out_size;  
      if (m_pFile)  
           fwrite(m_pOutBuf, m_nOutBufSize, 1, m_pFile);  
      return retLen;  
 }  
 void AudioDecoder::setExtraData(unsigned char *extradata, int extradatasize)  
 {  
      if (m_pExtraData) {  
           delete[] m_pExtraData;  
           m_pExtraData = NULL;  
           m_nExtraDataSize = 0;  
      }  
      if (extradata == NULL || extradatasize <= 0)  
           return;  
      m_pExtraData = new unsigned char[extradatasize];  
      memset(m_pExtraData, 0, extradatasize);  
      memcpy(m_pExtraData, extradata, extradatasize);  
      m_nExtraDataSize = extradatasize;  
 }  
 int AudioDecoder::checkResampler()  
 {  
      int err;  
      int64_t channel_layout = 0;  
      int64_t sample_rate = 0;  
      int64_t sample_fmt = -1;  
      av_opt_get_int(m_pSwrCtx, "in_channel_layout", 0, &channel_layout);  
      av_opt_get_int(m_pSwrCtx, "in_sample_rate", 0, &sample_rate);  
      av_opt_get_int(m_pSwrCtx, "in_sample_fmt", 0, &sample_fmt);  
      if ((m_pCodecCtx->channel_layout != 0) && (channel_layout != m_pCodecCtx->channel_layout) ||  
           sample_rate != m_pCodecCtx->sample_rate ||  
           sample_fmt != m_pCodecCtx->sample_fmt) {  
           err = initResampler(m_pCodecCtx->channel_layout, m_pCodecCtx->sample_rate, m_pCodecCtx->sample_fmt);  
           if (err < 0)   
                return err;  
      }  
      return 0;  
 }  

< AudioDecoder 사용 >
 AudioDecoder *m_pDecoder = new AudioDecoder();  
 m_pDecoder->open(codec_id, channel);  
 ...  
 int ret = m_pDecoder->decodeFrame(pData, size, m_pDecoder->frame());  
 if (ret > 0) {  
   fwrite(m_pDecoder->outBuf(), m_pDecoder->outBufSize(), 1, fp);  
 }  
 ...  
 m_pDecoder->close();  
 delete m_pDecoder;  

DirectDraw Surface Transparent Blt


void CopySurface(IDirectDrawSurface7 *lpSurfaceDst, RECT &rectTarget, IDirectDrawSurface7 *lpSurfaceSrc, RECT &rectSrc)
{
DDBLTFX ddbltfx;
ZeroMemory(&ddbltfx, sizeof(ddbltfx));
ddbltfx.dwSize = sizeof(ddbltfx);

DDCOLORKEY colorKey = {RGB(0,0,0), RGB(0,0,0)};    // Transparent Color - black
ddbltfx.ddckSrcColorkey = colorKey;

DWORD flags = DDBLT_ASYNC | DDBLT_KEYSRCOVERRIDE;

HRESULT hr = lpSurfaceDst->Blt(&rectTarget, lpSurfaceSrc, &rectSrc, flags, &ddbltfx);
if (FAILED(hr)) {
TRACE("[%s] hr:0x%x\n", __FUNCTION__, hr);
}
}

DirectDraw Surface 알파블랜딩 - DirectDraw Surface Alpha Blending


HBITMAP m_hbm;
BITMAP m_bmpInfo;
...

< 비트맵 로드 - bitmap load >


m_hbm = (HBITMAP) LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(123), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
GetObject(m_hbm, sizeof(m_bmpInfo), &m_bmpInfo);



< 알파블랜딩 - alpha blending >

void drawBitmapAlpha(RECT *rectTarget, IDirectDrawSurface7 *lpSurface)
{
HDC hdc;
if (lpSurface->GetDC(&hdc) != DD_OK || m_hbm == NULL)
return;

/* calculate bitmap size */
int targetWidth = rectTarget->right-rectTarget->left;
int targetHeight = rectTarget->bottom-rectTarget->top;
int cx = rectTarget->left+targetWidth/2;
int cy = rectTarget->top+targetHeight/2;

int bmpWidth = m_bmpInfo.bmWidth;
int bmpHeight = m_bmpInfo.bmHeight;

POINT pt;
pt.x = cx-bmpWidth/2;
pt.y = cy-bmpHeight/2;

HDC hMemDC, hAlphaDC;
BOOL ret;

hMemDC = CreateCompatibleDC(hdc);    // create bitmap dc
hAlphaDC = CreateCompatibleDC(hdc);    // create alpha dc

HBITMAP hbmAlpha = CreateCompatibleBitmap(hdc, bmpWidth, bmpHeight);

SelectObject(hMemDC, m_hbm);
SelectObject(hAlphaDC, hbmAlpha);
 
        // copy src image to alpha dc
ret = BitBlt(hAlphaDC, 0, 0, bmpWidth, bmpHeight, hdc, pt.x, pt.y, SRCCOPY);
if (!ret) {
TRACE("[%s] BitBlt failed, err:%d\n", __FUNCTION__, GetLastError());
}

        // copy bitmap image to alpha dc with transparent
ret = TransparentBlt(hAlphaDC, 0, 0, bmpWidth, bmpHeight, hMemDC, 0, 0, m_bmpInfo.bmWidth, m_bmpInfo.bmHeight, RGB(0, 0, 0));
if (!ret) {
TRACE("[%s] TransparentBlt failed, err:%d\n", __FUNCTION__, GetLastError());
}

BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 100;
bf.AlphaFormat = 0;

        // alpha blend alpha dc to dest dc
ret = AlphaBlend(hdc, pt.x, pt.y, bmpWidth, bmpHeight, hAlphaDC, 0, 0, bmpWidth, bmpHeight, bf);
if (!ret) {
TRACE("[%s] AlphaBlend failed, err:%d\n", __FUNCTION__, GetLastError());
}

DeleteObject(hbmAlpha);
DeleteDC(hAlphaDC);
DeleteDC(hMemDC);

lpSurface->ReleaseDC(hdc);
}