2015년 11월 20일 금요일

ffmpeg 오디오 리샘플러 사용법 - how to use ffmpeg audio resampler

< Resampler.h >
 #ifndef __RESAMPLER_H__  
 #define __RESAMPLER_H__  
   
 extern "C" {  
 #include "libswresample/swresample.h"  
 #include "libavutil/frame.h"  
 }  
   
 class Resampler  
 {  
 public:  
      Resampler();  
      virtual ~Resampler();  
   
      int open(int in_sample_rate,   
           int in_channel_count,   
           uint64_t in_channel_layout,   
           enum AVSampleFormat in_sample_fmt,  
           int out_sample_rate,   
           int out_channel_count,   
           uint64_t out_channel_layout,   
           enum AVSampleFormat out_sample_fmt);  
      void close();  
      int resample(AVFrame *frame, int inLen);  
      int checkResampler(int sample_rate, int channel_count, int channel_layout, enum AVSampleFormat sample_fmt);  
   
      void moveOutBuffer(int len);  
      unsigned char* outBuf() { return m_pOutBuf; }  
      int outBufIndex() { return m_nOutBufIndex; }  
      void resetOutBufIndex() { m_nOutBufIndex = 0; }  
   
 protected:  
      struct SwrContext*     m_pSwrCtx;  
   
      int                         m_nSampleRateIn;  
      int                         m_nChannelCountIn;  
      uint64_t               m_nChannelLayoutIn;  
      enum AVSampleFormat     m_nSampleFormatIn;  
      int                         m_nSampleRateOut;  
      int                         m_nChannelCountOut;  
      uint64_t               m_nChannelLayoutOut;  
      enum AVSampleFormat     m_nSampleFormatOut;  
   
      unsigned char*     m_pOutBuf;  
      int                    m_nOutBufSize;       
      int                    m_nOutBufIndex;  
   
      FILE*               m_pFile;  
 };  
   
 #endif  
   

< Resampler.cpp >
 #include "Resampler.h"  
 #include "GlobalEnv.h"  
   
 extern "C" {  
 #include "libavutil\opt.h"  
 }  
   
 Resampler::Resampler()  
 {  
      m_pSwrCtx = NULL;  
      m_nSampleRateIn = m_nSampleRateOut = 0;  
      m_nChannelCountIn = m_nChannelCountOut = 0;  
      m_nChannelLayoutIn = m_nChannelLayoutOut = 0;  
      m_nSampleFormatIn = m_nSampleFormatOut = AV_SAMPLE_FMT_NONE;  
      m_pOutBuf = NULL;  
      m_nOutBufSize = m_nOutBufIndex = 0;  
      m_pFile = NULL;  
 }  
   
 Resampler::~Resampler()  
 {  
      if (m_pOutBuf) {  
           delete[] m_pOutBuf;  
           m_pOutBuf = NULL;  
      }  
 }  
   
 int Resampler::open(int in_sample_rate,   
                          int in_channel_count,   
                          uint64_t in_channel_layout,   
                          enum AVSampleFormat in_sample_fmt,  
                          int out_sample_rate,   
                          int out_channel_count,   
                          uint64_t out_channel_layout,   
                          enum AVSampleFormat out_sample_fmt)  
 {  
      int err;  
      char errbuf[128];  
   
      m_pSwrCtx = swr_alloc();  
   
      av_opt_set_int(m_pSwrCtx, "in_sample_rate", in_sample_rate, 0);  
      av_opt_set_int(m_pSwrCtx, "in_channel_count", in_channel_count, 0);  
      av_opt_set_int(m_pSwrCtx, "in_channel_layout", in_channel_layout, 0);  
      av_opt_set_sample_fmt(m_pSwrCtx, "in_sample_fmt", in_sample_fmt, 0);  
   
      av_opt_set_int(m_pSwrCtx, "out_sample_rate", out_sample_rate, 0);  
      av_opt_set_int(m_pSwrCtx, "out_channel_count", out_channel_count, 0);  
      av_opt_set_int(m_pSwrCtx, "out_channel_layout", out_channel_layout, 0);  
      av_opt_set_sample_fmt(m_pSwrCtx, "out_sample_fmt", out_sample_fmt, 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;  
      }  
   
      m_nSampleRateIn = in_sample_rate;  
      m_nChannelCountIn = in_channel_count;  
      m_nChannelLayoutIn = in_channel_layout;  
      m_nSampleFormatIn = in_sample_fmt;  
   
      m_nSampleRateOut = out_sample_rate;  
      m_nChannelCountOut = out_channel_count;  
      m_nChannelLayoutOut = out_channel_layout;  
      m_nSampleFormatOut = out_sample_fmt;  
   
      m_nOutBufIndex = 0;  
   
      DXPRINTF("resampler opened\n");  
   
 #if 0  
      m_pFile = fopen("resample.wav", "wb");  
 #endif  
   
      return 0;  
 }  
   
 void Resampler::close()  
 {  
      if (m_pSwrCtx) {  
           swr_free(&m_pSwrCtx);  
           m_pSwrCtx = NULL;  
      }  
   
      if (m_pOutBuf) {  
           delete[] m_pOutBuf;  
           m_pOutBuf = NULL;  
           m_nOutBufSize = m_nOutBufIndex = 0;  
      }  
   
      if (m_pFile) {  
           fclose(m_pFile);  
           m_pFile = NULL;  
      }  
 }  
   
 int Resampler::resample(AVFrame *frame, int inLen)  
 {  
      int out_size = av_rescale_rnd(inLen, m_nSampleRateOut, m_nSampleRateIn, AV_ROUND_UP);  
   
      if (out_size*m_nChannelCountOut > m_nOutBufSize) {  
           if (m_pOutBuf) delete[] m_pOutBuf;  
           m_pOutBuf = new unsigned char[out_size*m_nChannelCountOut];  
           m_nOutBufSize = out_size*m_nChannelCountOut;  
      }  
   
      uint8_t *ptr = &m_pOutBuf[m_nOutBufIndex];  

      int ret = swr_convert(m_pSwrCtx, &m_pOutBuf, out_size,   
           (const uint8_t **)frame->extended_data, frame->nb_samples);  
   
      int dst_bufsize = av_samples_get_buffer_size(NULL, m_nChannelCountOut, ret, m_nSampleFormatOut, 1);  
      m_nOutBufIndex += dst_bufsize;  
        
      if (m_pFile) fwrite(ptr, dst_bufsize, 1, m_pFile);  
   
      return ret;  
 }  
   
 int Resampler::checkResampler(int sample_rate, int channel_count, int channel_layout, enum AVSampleFormat sample_fmt)  
 {  
      if (  
      sample_rate != m_nSampleRateIn ||   
      channel_count != m_nChannelCountIn ||  
      channel_layout != m_nChannelLayoutIn ||  
      sample_fmt != m_nSampleFormatIn  
      ) {  
           return -1;  
      }  
   
      return 0;  
 }  
   
 void Resampler::moveOutBuffer(int len)  
 {  
      if (len > 0) {  
           memcpy(m_pOutBuf, &m_pOutBuf[m_nOutBufIndex-len], len);  
           m_nOutBufIndex = len;  
      }  
 }  
   


< Resampler 사용 >
Resampler *m_pResampler;
AVCodec* m_pCodec;
AVCodecContext* m_pCodecCtx;

...
avcodec_open2(m_pCodecCtx, m_pCodec, NULL);
           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);  

 int 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;
 }

 retLen = m_pResampler->resample(m_pFrame, out_size);
 out_size = m_pResampler->outBufIndex();
 memcpy(m_pOutBuf, m_pResampler->outBuf(), out_size);    // now m_pOutBuf has resampled audio data
 m_pResampler->resetOutBufIndex();
 
 m_nOutBufSize = out_size;

 if (m_pFile) fwrite(m_pOutBuf, m_nOutBufSize, 1, m_pFile);
 



댓글 없음:

댓글 쓰기