2015년 12월 3일 목요일

윈도우/리눅스/안드로이드 공통 ffmpeg 디코더 라이브러리 소스 - ffmpeg decoder library source code for window/linux/android

ffmpeg 비디오/오디오 디코더 라이브러리 - 윈도우/리눅스/안드로이드 환경에서 빌드 및 테스트

뮤텍스 소스
오디오 리샘플러 소스

< FFMPEGUtil.h >
 #ifndef __FFMPEG_UTIL_H__  
 #define __FFMPEG_UTIL_H__  
   
 extern "C" {  
 #include "libavformat/avformat.h"  
 #include "libavutil/pixdesc.h"  
 }  
   
 void InitFFmpegLib();  
 enum AVCodecID GetCodecID(const char *codecName);  
 enum AVSampleFormat GetSampleFormat(enum AVCodecID codec_id);  
 unsigned int GetCodecTag(const AVCodecTag *tags, enum AVCodecID id);  
 enum AVCodecID GetCodecID(const AVCodecTag *tags, unsigned int tag);   
 char* GetCodecName(enum AVCodecID codec_id);  
 int GetBitPerPixel(AVPixelFormat pix_fmt);  
   
 #endif     

< FFMPEGUtil.cpp >
 #include "util.h"  
 #include "FFMPEGUtil.h"  
 #include "GlobalEnv.h"  
 #include "Mutex.h"  
 #include <ctype.h>  
   
 typedef struct AVCodecTag {  
   enum AVCodecID id;  
   unsigned int tag;  
 } AVCodecTag;  
   
 static bool isInit = false;  
 static MUTEX hMutex = PTHREAD_MUTEX_INITIALIZER;  
   
 static int lockmgr(void **mtx, enum AVLockOp op)  
 {  
   switch(op) {  
    case AV_LOCK_CREATE:  
            MUTEX_INIT((MUTEX *)mtx);  
      if(!*mtx)  
        return 1;  
      return 0;  
    case AV_LOCK_OBTAIN:  
            return !!MUTEX_LOCK((MUTEX *)mtx);  
    case AV_LOCK_RELEASE:  
            return !!MUTEX_UNLOCK((MUTEX *)mtx);  
    case AV_LOCK_DESTROY:  
            MUTEX_DESTROY((MUTEX *)mtx);  
      return 0;  
   }  
   return 1;  
 }  
   
 void InitFFmpegLib()  
 {  
      MUTEX_LOCK(&hMutex);  
   
      if (!isInit) {  
           av_register_all();  
   
           if (av_lockmgr_register(lockmgr)) {  
                DXPRINTF("Could not initialize lock manager!\n");  
                exit(1);  
           }  
           isInit = true;  
      }  
   
      MUTEX_UNLOCK(&hMutex);  
 }  
   
 enum AVCodecID GetCodecID(const char *codecName)  
 {       
      if (!codecName) return AV_CODEC_ID_NONE;  
   
      if (strcmp(codecName, "H264") == 0)  
           return AV_CODEC_ID_H264;  
      else if (strcmp(codecName, "MP4V-ES") == 0)  
           return AV_CODEC_ID_MPEG4;  
      else if (strcmp(codecName, "MPEG4-GENERIC") == 0)  
           return AV_CODEC_ID_AAC;  
      else if (strcmp(codecName, "JPEG") == 0)  
           return AV_CODEC_ID_MJPEG;  
      else if (strcmp(codecName, "AC3") == 0)  
           return AV_CODEC_ID_AC3;  
      else if (strcmp(codecName, "L16") == 0)  
           return AV_CODEC_ID_PCM_S16BE;  
      else if (strcmp(codecName, "PCMU") == 0)  
           return AV_CODEC_ID_PCM_MULAW;  
      else if (strcmp(codecName, "PCMA") == 0)  
           return AV_CODEC_ID_PCM_ALAW;  
      else DXPRINTF("cannot find %s codec id\n", codecName);  
   
      return AV_CODEC_ID_NONE;  
 }  
   
 char* GetCodecName(AVCodecID codec_id)  
 {  
      char *temp = NULL;  
   
      switch (codec_id) {  
           case AV_CODEC_ID_H264: { temp = "H264"; break; }  
           case AV_CODEC_ID_MPEG4: { temp = "MP4V-ES"; break; }  
           case AV_CODEC_ID_AAC: { temp = "MPEG4-GENERIC"; break; }  
           case AV_CODEC_ID_MJPEG: { temp = "JPEG"; break; }  
           case AV_CODEC_ID_AC3: { temp = "AC3"; break; }  
           case AV_CODEC_ID_PCM_S16BE: { temp = "L16"; break; }  
           case AV_CODEC_ID_PCM_MULAW: { temp = "PCMU"; break; }  
           case AV_CODEC_ID_PCM_ALAW: { temp = "PCMA"; break; }  
      }  
   
      return strDup(temp);  
 }  
   
 enum AVSampleFormat GetSampleFormat(enum AVCodecID codec_id)  
 {  
      if (codec_id == AV_CODEC_ID_PCM_MULAW)  
           return AV_SAMPLE_FMT_U8;  
      else if (codec_id == AV_CODEC_ID_AAC)  
           return AV_SAMPLE_FMT_S16;  
      else if (codec_id == AV_CODEC_ID_AC3)  
           return AV_SAMPLE_FMT_S16;  
      else if (codec_id == AV_CODEC_ID_PCM_S16BE)  
           return AV_SAMPLE_FMT_S16;  
      else DXPRINTF("cannot find codec id %d sample format\n", codec_id);  
   
      return AV_SAMPLE_FMT_NONE;  
 }  
  
 unsigned int GetCodecTag(const AVCodecTag *tags, enum AVCodecID id)  
 {  
   while (tags->id != AV_CODEC_ID_NONE) {  
     if (tags->id == id)  
       return tags->tag;  
     tags++;  
   }  
   return 0;  
 }  
   
 static unsigned int avpriv_toupper4(unsigned int x)  
 {  
   return toupper(x & 0xFF) +  
      (toupper((x >> 8) & 0xFF) << 8) +  
      (toupper((x >> 16) & 0xFF) << 16) +  
      (toupper((x >> 24) & 0xFF) << 24);  
 }  
   
 enum AVCodecID GetCodecID(const AVCodecTag *tags, unsigned int tag)  
 {  
   int i;  
   for(i=0; tags[i].id != AV_CODEC_ID_NONE;i++) {  
     if(tag == tags[i].tag)  
       return tags[i].id;  
   }  
   for(i=0; tags[i].id != AV_CODEC_ID_NONE; i++) {  
     if (avpriv_toupper4(tag) == avpriv_toupper4(tags[i].tag))  
       return tags[i].id;  
   }  
   return AV_CODEC_ID_NONE;  
 }  
   
 int GetBitPerPixel(AVPixelFormat pix_fmt)  
 {  
      const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);  
      return av_get_bits_per_pixel(desc);  
 }     

< Decoder.h >
 #ifndef __DECODER_H__  
 #define __DECODER_H__  
   
 #ifdef WIN32  
 #include <windows.h>  
 #endif  
 #include "Mutex.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 *codecCtx, 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 *codecCtx, int channel) = 0;  
      int prepareOpen(enum AVCodecID codecId, AVCodecContext *codecCtx);  
      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 MUTEX     m_hMutex;  
      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;  
 MUTEX Decoder::m_hMutex = PTHREAD_MUTEX_INITIALIZER;  
   
 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()  
 {  
      MUTEX_LOCK(&m_hMutex);  
   
      if (!m_bInit) {  
           InitFFmpegLib();  
 #ifdef WIN32  
           SYSTEM_INFO sysinfo;  
           GetSystemInfo(&sysinfo);  
           m_nCPU = sysinfo.dwNumberOfProcessors;  
 #else  
           int ret = sysconf(_SC_NPROCESSORS_ONLN);  
           if (ret != -1) m_nCPU = ret;            
 #endif  
           DXPRINTF("CPU : %d\n", m_nCPU);  
           m_bInit = true;  
      }  
   
      MUTEX_UNLOCK(&m_hMutex);  
 }  
   
 int Decoder::open(AVCodecID codecId, int channel)  
 {  
      return open(codecId, NULL, channel);  
 }  
   
 int Decoder::open(AVCodecContext *codecCtx, int channel)  
 {  
      return open(codecCtx->codec_id, codecCtx, channel);  
 }  
   
 int Decoder::prepareOpen(enum AVCodecID codecId, AVCodecContext *codecCtx)  
 {  
      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 (codecCtx) {  
           m_pCodecCtx = codecCtx;  
           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_pCodecCtx)  
           avcodec_close(m_pCodecCtx);  
   
      if (m_bCodecCtxAlloc) {  
           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);  
 }     

< VideoDecoder.h >
 #ifndef __VIDEO_DECODER_H__  
 #define __VIDEO_DECODER_H__  
   
 #include "Decoder.h"  
   
 class VideoDecoder : public Decoder  
 {  
 public:  
      VideoDecoder();  
      virtual ~VideoDecoder();  
   
      virtual int decodeFrame(unsigned char *inBuf, int inLen, AVFrame *frame);  
   
 protected:  
      virtual int open(enum AVCodecID codecId, AVCodecContext *codecCtx, int channel);  
   
 protected:  
      int writeYUVStream(FILE *fp, unsigned char *buf, int wrap, int xsize, int ysize);  
 };  
   
 #endif  

< VideoDecoder.cpp >
 #include "VideoDecoder.h"  
 #include "GlobalEnv.h"  
   
 VideoDecoder::VideoDecoder() : Decoder()  
 {  
 }  
   
 VideoDecoder::~VideoDecoder()  
 {  
 }  
   
 int VideoDecoder::open(enum AVCodecID codecId, AVCodecContext *codecCtx, int channel)  
 {       
      int err;  
      char errbuf[128];  
   
      err = prepareOpen(codecId, codecCtx);  
      if (err < 0) return -1;  
   
      m_pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;  
      m_pCodecCtx->thread_type = FF_THREAD_SLICE;  
      m_pCodecCtx->thread_count = m_nCPU;  
   
      if (codecId == CODEC_ID_H264) {  
           if (m_pCodec->capabilities&CODEC_CAP_TRUNCATED)  
                m_pCodecCtx->flags |= CODEC_FLAG_TRUNCATED;  
      }  
   
      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;  
      }  
   
      DXPRINTF("video decoder opened %s\n", avcodec_get_name(codecId));  
   
      //m_pFile = fopen("c:/video.yuv", "wb");  
   
 exit:  
      return err;  
 }  
   
 int VideoDecoder::decodeFrame(unsigned char *inBuf, int inLen, AVFrame *frame)  
 {  
      if (!m_pCodecCtx || !inBuf || inLen <= 0) return 0;  
   
      int retLen = 0, got_picture;  
   
      prepareDecBuffer(inBuf, inLen);  
   
      retLen = avcodec_decode_video2(m_pCodecCtx, frame, &got_picture, &m_avPacket);  
   
      if (frame->pict_type == AV_PICTURE_TYPE_NONE)  
           return 0;  
   
      if (m_pFile) {  
           writeYUVStream(m_pFile, frame->data[0], frame->linesize[0], m_pCodecCtx->width, m_pCodecCtx->height);  
           writeYUVStream(m_pFile, frame->data[1], frame->linesize[0]/2, m_pCodecCtx->width/2, m_pCodecCtx->height/2);  
           writeYUVStream(m_pFile, frame->data[2], frame->linesize[0]/2, m_pCodecCtx->width/2, m_pCodecCtx->height/2);  
      }  
   
      return retLen;  
 }  
   
 int VideoDecoder::writeYUVStream(FILE *fp, unsigned char *buf, int wrap, int xsize, int ysize)  
 {  
      for(int i=0;i<ysize;i++) {  
           if (fp)  
                fwrite(buf + i * wrap, 1, xsize, fp);  
      }  
      return 0;  
 }  
   

< AudioDecoder.h >
 #ifndef __AUDIO_DECODER_H__  
 #define __AUDIO_DECODER_H__  
   
 #include "Decoder.h"  
 #include "Resampler.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 const *extradata, unsigned extradatasize);  
   
      int sampleRate();  
      int channels();  
      uint64_t channelLayout();  
   
 protected:  
      virtual int open(enum AVCodecID codecId, AVCodecContext *codecCtx, int channel);  
      int initResampler(uint64_t channel_layout, int sample_rate, enum AVSampleFormat sample_fmt);  
      int checkResampler();  
   
 protected:  
      Resampler*          m_pResampler;  
   
      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_pResampler(NULL), m_pOutBuf(NULL), m_nOutBufSize(0), m_nOutBufMaxSize(0), m_pExtraData(NULL), m_nExtraDataSize(0)  
 {  
 }  
   
 AudioDecoder::~AudioDecoder()  
 {  
      DX_DELETE_OBJECT(m_pResampler);  
 }  
   
 int AudioDecoder::open(enum AVCodecID codecId, AVCodecContext *codecCtx, int channel)  
 {  
      int err;  
      char errbuf[128];  
   
      err = prepareOpen(codecId, codecCtx);  
      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);  
           return err;  
      }  
   
      if (m_pCodecCtx->sample_fmt != AV_SAMPLE_FMT_S16 || m_pCodecCtx->channels > 2) {  
           m_pResampler = new Resampler();  
           err = m_pResampler->open(  
                m_pCodecCtx->sample_rate, m_pCodecCtx->channels, m_pCodecCtx->channel_layout, m_pCodecCtx->sample_fmt,  
                m_pCodecCtx->sample_rate, m_pCodecCtx->channels, m_pCodecCtx->channel_layout, AV_SAMPLE_FMT_S16);  
   
           if (err < 0) {  
                DXPRINTF("failed to open resampler %d %d %d %d\n",   
                     m_pCodecCtx->sample_rate,  
                     m_pCodecCtx->channels,  
                     m_pCodecCtx->channel_layout,  
                     AV_SAMPLE_FMT_S16);  
                return err;  
           }  
      }  
   
      DXPRINTF("audio decoder opened %s\n", avcodec_get_name(codecId));  
   
 #if 0  
      m_pFile = fopen("audio_decoder.wav", "wb");  
 #endif  
   
      return err;  
 }  
   
 void AudioDecoder::close()  
 {  
      Decoder::close();  
   
      if (m_pResampler) {  
           m_pResampler->close();  
           DX_DELETE_OBJECT(m_pResampler);  
      }  
   
      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);  
   
      retLen = avcodec_decode_audio4(m_pCodecCtx, m_pFrame, &got_frame, &m_avPacket);  
   
      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 <= 0) {  
           return -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_pResampler) {  
           if (m_pResampler->checkResampler(m_pCodecCtx->sample_rate, m_pCodecCtx->channels,   
                m_pCodecCtx->channel_layout, m_pCodecCtx->sample_fmt) < 0)   
           {  
                m_pResampler->close();  
   
                int err = m_pResampler->open(  
                     m_pCodecCtx->sample_rate, m_pCodecCtx->channels, m_pCodecCtx->channel_layout, m_pCodecCtx->sample_fmt,  
                     m_pCodecCtx->sample_rate, m_pCodecCtx->channels, m_pCodecCtx->channel_layout, AV_SAMPLE_FMT_S16);  
   
                if (err < 0) {  
                     DXPRINTF("failed to open resampler %d %d %d %d\n",   
                          m_pCodecCtx->sample_rate,  
                          m_pCodecCtx->channels,  
                          m_pCodecCtx->channel_layout,  
                          AV_SAMPLE_FMT_S16);  
                     return err;  
                }  
           }  
           retLen = m_pResampler->resample(m_pFrame, out_size);  
           out_size = m_pResampler->outBufIndex();  
           memcpy(m_pOutBuf, m_pResampler->outBuf(), out_size);  
           m_pResampler->resetOutBufIndex();  
      } else {  
           if (m_pCodecCtx->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 const *extradata, unsigned extradatasize)  
 {  
      if (m_pExtraData) {  
           delete[] m_pExtraData;  
           m_pExtraData = NULL;  
           m_nExtraDataSize = 0;  
      }  
   
      if (!extradatasize)  
           return;  
   
      m_pExtraData = new unsigned char[extradatasize];  
      memset(m_pExtraData, 0, extradatasize);  
      memcpy(m_pExtraData, extradata, extradatasize);  
      m_nExtraDataSize = extradatasize;  
 }  
   
 int AudioDecoder::sampleRate()  
 {  
      if (m_pCodecCtx) return m_pCodecCtx->sample_rate;  
      return 0;  
 }  
   
 int AudioDecoder::channels()  
 {  
      if (m_pCodecCtx) return m_pCodecCtx->channels;  
      return 0;  
 }  
   
 uint64_t AudioDecoder::channelLayout()  
 {  
      if (m_pCodecCtx) return m_pCodecCtx->channel_layout;  
      return 0;  
 }  
   

< 라이브러리 사용 >

Decoder *pVideoDecoder = new VideoDecoder();
Decoder *pAudioDecoder = new AudioDecoder();
...
// 코덱열기
pVideoDecoder->open(AV_CODEC_ID_H264, 0);    // 비디오 코덱은 채널 사용X
pAudioDecoder->open(AV_CODEC_ID_AAC, 2);

...
// 디코딩
unsigned char *buf => encoded data buffer
int size => encoded data buffer size

if (pVideoDecoder->decodeFrame(buf, size, pVideoDecoder->frame()) > 0) {
    // now pVideoDecoder->frame() has decoded picture
}
...
if (pAudioDecoder->decodeFrame(buf, size, pAudioDecoder->frame()) > 0) {
    // now pAudioDecoder->outBuf() has decoded audio pcm data &&
    // pAudioDecoder->outBufSize() has decoded audio pcm data size
}
...

// 코덱닫기
pVideoDecoder->close();
pAudioDecoder->close();

댓글 없음:

댓글 쓰기