2015년 11월 27일 금요일

DirectDraw로 draw시 깜빡임 현상 방지

DirectDraw 로 영상을 출력할때 모니터 주파수에 따라 출력 영상 깜빡임 현상이 발생하는데 이것은 draw 주기가 서로 맞지않기 때문이다.
IDirectDraw7::WaitForVerticalBlank() 메소드를 사용해서 주기를 맞춰주면 깜빡임을 막을 수 있다.

// synchronize with vertical-blank interval
if (m_pDDraw[index].isFirstDisplay) {
pDDraw->pDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL);
m_pDDraw[index].isFirstDisplay = false;
}

2015년 11월 26일 목요일

live555 TaskScheduler 수정소스

live555 의 TaskScheduler 를 사용하기 쉽게 수정한 소스이다. 윈도우/리눅스 둘 다 적용가능하며 소켓통신 프로그램 개발시 간편하게 사용할 수 있다.
Mutex/Thread 관련 소스는 http://greenday96.blogspot.com/2015/08/blog-post.html 포스트 참조

< NetCommon.h >
 #ifndef __NETCOMMON_H__  
 #define __NETCOMMON_H__  
   
 #ifdef WIN32  
   
 #include <WinSock2.h>  
 #include <ws2tcpip.h>  
   
 #define closeSocket     closesocket  
 #define EWOULDBLOCK     WSAEWOULDBLOCK  
 #define EINPROGRESS WSAEWOULDBLOCK  
 #define EINTR          WSAEINTR  
   
 #define _strcasecmp     _strnicmp  
 #define snprintf     _snprintf  
   
 #else  
   
 #include <sys/socket.h>  
 #include <netinet/in.h>  
 #include <netinet/tcp.h>  
 #include <arpa/inet.h>  
 #include <unistd.h>  
 #include <fcntl.h>  
 #include <errno.h>  
   
 #define closeSocket               close  
 #define WSAGetLastError()     errno  
   
 #include <ctype.h>  
 #include <stdlib.h>  
 #define _strcasecmp strncasecmp  
 #endif  
   
 #endif  
   


< TaskScheduler.h >
 #ifndef __TASK_SCHEDULER_H__  
 #define __TASK_SCHEDULER_H__  
   
 #include "NetCommon.h"  
 #include "Mutex.h"  
 #include "Thread.h"  
   
 #define SOCKET_READABLE  (1<<1)  
 #define SOCKET_WRITABLE  (1<<2)  
 #define SOCKET_EXCEPTION  (1<<3)  
   
 class HandlerSet;  
   
 class TaskScheduler   
 {  
 public:       
      TaskScheduler();  
      virtual ~TaskScheduler();  
   
      typedef void BackgroundHandlerProc(void* clientData, int mask);  
   
      void turnOnBackgroundReadHandling(int socketNum, BackgroundHandlerProc* handlerProc, void *clientData);  
      void turnOffBackgroundReadHandling(int socketNum);       
   
      int startEventLoop();  
      void stopEventLoop();  
      void doEventLoop();  
   
      int isRunning() { return fTaskLoop; }  
   
 protected:            
      virtual void SingleStep();  
      void taskLock();  
      void taskUnlock();  
   
 protected:  
      int                         fTaskLoop;  
      MUTEX                    fMutex;  
      THREAD                    fThread;  
   
      HandlerSet     *fReadHandlers;  
      int               fLastHandledSocketNum;  
   
      int          fMaxNumSockets;  
      fd_set     fReadSet;  
 };  
   
 class HandlerDescriptor {  
      HandlerDescriptor(HandlerDescriptor* nextHandler);  
      virtual ~HandlerDescriptor();  
   
 public:  
      int socketNum;  
      TaskScheduler::BackgroundHandlerProc* handlerProc;  
      void* clientData;  
   
 private:  
      // Descriptors are linked together in a doubly-linked list:  
      friend class HandlerSet;  
      friend class HandlerIterator;  
      HandlerDescriptor* fNextHandler;  
      HandlerDescriptor* fPrevHandler;  
 };  
   
 class HandlerSet {  
 public:  
      HandlerSet();  
      virtual ~HandlerSet();  
   
      void assignHandler(int socketNum, TaskScheduler::BackgroundHandlerProc* handlerProc, void* clientData);  
      void removeHandler(int socketNum);  
      void moveHandler(int oldSocketNum, int newSocketNum);  
   
 private:  
      HandlerDescriptor* lookupHandler(int socketNum);  
   
 private:  
      friend class HandlerIterator;  
      HandlerDescriptor fHandlers;  
 };  
   
 class HandlerIterator {  
 public:  
      HandlerIterator(HandlerSet& handlerSet);  
      virtual ~HandlerIterator();  
   
      HandlerDescriptor* next(); // returns NULL if none  
      void reset();  
   
 private:  
      HandlerSet& fOurSet;  
      HandlerDescriptor* fNextPtr;  
 };  
   
 #endif  
   


< TaskScheduler.cpp >
 #include "TaskScheduler.h"  
 #include "RTSPCommonEnv.h"  
 #include <stdio.h>  
   
 THREAD_FUNC DoEventThread(void* lpParam)  
 {  
      TaskScheduler *scheduler = (TaskScheduler *)lpParam;  
      scheduler->doEventLoop();  
      return 0;  
 }  
   
 TaskScheduler::TaskScheduler()  
 {  
      fTaskLoop = 0;  
      MUTEX_INIT(&fMutex);  
      FD_ZERO(&fReadSet);  
      fMaxNumSockets = 0;  
      fThread = NULL;  
      fReadHandlers = new HandlerSet();  
 }  
   
 TaskScheduler::~TaskScheduler()  
 {  
      stopEventLoop();  
   
      delete fReadHandlers;  
   
      THREAD_DESTROY(&fThread);  
   
      MUTEX_DESTROY(&fMutex);  
 }  
   
 void TaskScheduler::taskLock()  
 {  
      MUTEX_LOCK(&fMutex);  
 }  
   
 void TaskScheduler::taskUnlock()  
 {  
      MUTEX_UNLOCK(&fMutex);  
 }  
   
 void TaskScheduler::turnOnBackgroundReadHandling(int socketNum, BackgroundHandlerProc* handlerProc, void *clientData)   
 {  
	taskLock();

	if (socketNum < 0) goto exit;

	FD_SET((unsigned)socketNum, &fReadSet);
	fReadHandlers->assignHandler(socketNum, handlerProc, clientData);

	if (socketNum+1 > fMaxNumSockets) {
		fMaxNumSockets = socketNum+1;
	}

exit:
	taskUnlock();
 }  
   
 void TaskScheduler::turnOffBackgroundReadHandling(int socketNum)   
 {  
	taskLock();

	if (socketNum < 0) goto exit;

	FD_CLR((unsigned)socketNum, &fReadSet);
	fReadHandlers->removeHandler(socketNum);

    HandlerIterator iter(*fReadHandlers);
	HandlerDescriptor* handler;

	int maxSocketNum = 0;
	while ((handler = iter.next()) != NULL) {
		if (handler->socketNum+1 > maxSocketNum) {
			maxSocketNum = handler->socketNum+1;
		}
	}
	fMaxNumSockets = maxSocketNum;	

exit:
	taskUnlock();
 }  
   
 int TaskScheduler::startEventLoop()  
 {  
      if (fTaskLoop != 0)  
           return -1;  
   
      fTaskLoop = 1;  
      THREAD_CREATE(&fThread, DoEventThread, this);  
      if (!fThread) {  
           DPRINTF("failed to create event loop thread\n");  
           fTaskLoop = 0;  
           return -1;  
      }  
   
      return 0;  
 }  
   
 void TaskScheduler::stopEventLoop()  
 {  
      fTaskLoop = 0;  
   
      THREAD_JOIN(&fThread);  
      THREAD_DESTROY(&fThread);  
 }  
   
 void TaskScheduler::doEventLoop()   
 {  
      while (fTaskLoop)  
      {  
           SingleStep();  
      }  
 }  
   
 void TaskScheduler::SingleStep()  
 {  
	taskLock();

	fd_set readSet = fReadSet;

	struct timeval timeout;
	timeout.tv_sec = 1;
	timeout.tv_usec = 0;

	int selectResult = select(fMaxNumSockets, &readSet, NULL, NULL, &timeout);
	if (selectResult < 0) {
		int err = WSAGetLastError();
		DPRINTF("TaskScheduler::SingleStep(): select() fails : %d\n", err);
		taskUnlock();
		return;
	}

	HandlerIterator iter(*fReadHandlers);
	HandlerDescriptor* handler;

	while ((handler = iter.next()) != NULL) {
		if (FD_ISSET(handler->socketNum, &readSet) && handler->handlerProc != NULL) {
			(*handler->handlerProc)(handler->clientData, SOCKET_READABLE);
		}
	}

	taskUnlock();
 }  
   
   
 HandlerDescriptor::HandlerDescriptor(HandlerDescriptor* nextHandler)  
 : handlerProc(NULL) {  
      // Link this descriptor into a doubly-linked list:  
      if (nextHandler == this) { // initialization  
           fNextHandler = fPrevHandler = this;  
      } else {  
           fNextHandler = nextHandler;  
           fPrevHandler = nextHandler->fPrevHandler;  
           nextHandler->fPrevHandler = this;  
           fPrevHandler->fNextHandler = this;  
      }  
 }  
   
 HandlerDescriptor::~HandlerDescriptor() {  
      // Unlink this descriptor from a doubly-linked list:  
      fNextHandler->fPrevHandler = fPrevHandler;  
      fPrevHandler->fNextHandler = fNextHandler;  
 }  
   
 HandlerSet::HandlerSet()  
 : fHandlers(&fHandlers) {  
      fHandlers.socketNum = -1; // shouldn't ever get looked at, but in case...  
 }  
   
 HandlerSet::~HandlerSet() {  
      // Delete each handler descriptor:  
      while (fHandlers.fNextHandler != &fHandlers) {  
           delete fHandlers.fNextHandler; // changes fHandlers->fNextHandler  
      }  
 }  
   
 void HandlerSet  
 ::assignHandler(int socketNum, TaskScheduler::BackgroundHandlerProc* handlerProc, void* clientData) {  
      // First, see if there's already a handler for this socket:  
      HandlerDescriptor* handler = lookupHandler(socketNum);  
      if (handler == NULL) { // No existing handler, so create a new descr:  
           handler = new HandlerDescriptor(fHandlers.fNextHandler);  
           handler->socketNum = socketNum;  
      }  
   
      handler->handlerProc = handlerProc;  
      handler->clientData = clientData;  
 }  
   
 void HandlerSet::removeHandler(int socketNum) {  
      HandlerDescriptor* handler = lookupHandler(socketNum);  
      delete handler;  
 }  
   
 void HandlerSet::moveHandler(int oldSocketNum, int newSocketNum) {  
      HandlerDescriptor* handler = lookupHandler(oldSocketNum);  
      if (handler != NULL) {  
           handler->socketNum = newSocketNum;  
      }  
 }  
   
 HandlerDescriptor* HandlerSet::lookupHandler(int socketNum) {  
      HandlerDescriptor* handler;  
      HandlerIterator iter(*this);  
      while ((handler = iter.next()) != NULL) {  
           if (handler->socketNum == socketNum) break;  
      }  
      return handler;  
 }  
   
 HandlerIterator::HandlerIterator(HandlerSet& handlerSet)  
 : fOurSet(handlerSet) {  
      reset();  
 }  
   
 HandlerIterator::~HandlerIterator() {  
 }  
   
 void HandlerIterator::reset() {  
      fNextPtr = fOurSet.fHandlers.fNextHandler;  
 }  
   
 HandlerDescriptor* HandlerIterator::next() {  
      HandlerDescriptor* result = fNextPtr;  
      if (result == &fOurSet.fHandlers) { // no more  
           result = NULL;  
      } else {  
           fNextPtr = fNextPtr->fNextHandler;  
      }  
   
      return result;  
 }  
   


< TaskScheduler 사용 >

TaskScheduler* fTask = new TaskScheduler();
...
fTask->turnOnBackgroundReadHandling(sock, &incomingHandler, this); // 소켓 핸들러 등록
...
fTask->turnOffBackgroundReadHandling(sock); // 소켓 핸들러 해제
delete fTask;

static void incomingHandler(void *data, int)
{
    recvfrom();
    ...
}

2015년 11월 25일 수요일

android JNI 를 이용한 c/c++ -> java 메소드 호출 - call method from c/c++ to java with android jni

1. java 에서 호출 메소드 정의
package com.kimdh.dxmediaplayer;
... 
public class DXMediaPlayer {  
   static {  
     System.loadLibrary("DXMediaPlayer");  
   }  
    
   private native void createPlayer();  
   private native void destroyPlayer();  
    
   protected void onDXEvent(int event_type, String strEvent) {  
     ...  
   }  
   ...  
   protected int writeAudioOut(byte[] buffer) {  
     ...  
   }  
 }  

2. java -> c/c++ 함수 호출에서 JavaVM 등 확보
 static JavaVM*  m_pJVM = NULL;  
 jobject    m_object;  
 ...  
 jmethodID    m_method_onDXEvent;  
 ...  
 jmethodID    m_method_writeAudioOut;  
   
 JNIEXPORT void JNICALL Java_com_kimdh_dxmediaplayer_DXMediaPlayer_createPlayer(JNIEnv *env, jobject obj)  
 {  
   m_object = env->NewGlobalRef(obj);  
   
   jclass cls = env->GetObjectClass(m_object);  
   if (cls == NULL) DXPRINTF("Failed to find class\n");  
   
   m_method_onDXEvent = env->GetMethodID(cls, "onDXEvent", "(ILjava/lang/String;)V");  
   if (m_method_onDXEvent == NULL) DXPRINTF("Unable to get method ref : onDXEvent\n");  
   
   m_method_writeAudioOut = env->GetMethodID(cls, "writeAudioOut", "([B)I");
   if (m_method_writeAudioOut == NULL) DXPRINTF("Unable to get method ref : writeAudioOut\n"); 

   if (m_pJVM == NULL)  
     env->GetJavaVM(&m_pJVM);  
 }  
   

3. 호출 함수 정의
 int OnDXEvent(WPARAM wParam, LPARAM lParam)  
 {  
   ...  
   int type = 123;  
   char strEvent[512] = {0};  
   jstring jstrEvent;  
   
   JNIEnv *env;  
    
   int getEnvStat = m_pJVM->GetEnv((void **)&env, JNI_VERSION_1_6);  
   if (getEnvStat == JNI_EDETACHED) {  
     //DXPRINTF("GetEnv: not attached\n");  
     if (m_pJVM->AttachCurrentThread(&env, NULL) != 0) {  
       DXPRINTF("Failed to attach\n");  
       return -1;  
     }  
   } else if (getEnvStat == JNI_OK) {  
     //  
   } else if (getEnvStat == JNI_EVERSION) {  
     DXPRINTF("GetEnv: version not supported\n");  
     return -1;  
   }  
   
   sprintf(strEvent, "event string");  
   
   jstrEvent = env->NewStringUTF(strEvent);  
   
   if (m_method_onDXEvent)  
     env->CallVoidMethod(m_object, m_method_onDXEvent, type, jstrEvent);  
   
   if (env->ExceptionCheck()) {  
     env->ExceptionDescribe();  
   }  
   
   if (getEnvStat == JNI_EDETACHED)  
     m_pJVM->DetachCurrentThread();  
   
   return 0;  
 }  
   
 int WriteAudioOut(unsigned char *buffer, int size)  
 {  
     JNIEnv *env;  
   
     int getEnvStat = m_pJVM->GetEnv((void **)&env, JNI_VERSION_1_6);  
     if (getEnvStat == JNI_EDETACHED) {  
        //DXPRINTF("GetEnv: not attached\n");  
        if (m_pJVM->AttachCurrentThread(&env, NULL) != 0) {  
            DXPRINTF("Failed to attach\n");  
            return -1;  
        }  
     } else if (getEnvStat == JNI_OK) {  
       //  
     } else if (getEnvStat == JNI_EVERSION) {  
        DXPRINTF("GetEnv: version not supported\n");  
        return -1;  
     }  
   
     int ret = -1;  
     if (m_method_writeAudioOut) {  
         jbyteArray jarr = env->NewByteArray(size);  
         jbyte* jbytes = env->GetByteArrayElements(jarr, NULL);  
   
         memcpy(jbytes, buffer, size);  
         env->SetByteArrayRegion(jarr, 0, size, jbytes);  
    
         ret = env->CallIntMethod(m_object, m_method_writeAudioOut, jarr);  
   
         env->ReleaseByteArrayElements(jarr, jbytes, JNI_ABORT);  
     }  
   
     if (env->ExceptionCheck())  
         env->ExceptionDescribe();  
   
     if (getEnvStat == JNI_EDETACHED)  
         m_pJVM->DetachCurrentThread();  
    
     return ret;  
 }  

4. 함수 호출
...
OnDXEvent(NULL, NULL);
...
WriteAudioOut(buf, size);
...

5. JNI 변수 해제
 JNIEXPORT void JNICALL Java_com_kimdh_dxmediaplayer_DXMediaPlayer_destroyPlayer(JNIEnv *env, jobject obj)  
 {  
   env->DeleteGlobalRef(m_object);  
 }  

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);