레이블이 ffmpeg인 게시물을 표시합니다. 모든 게시물 표시
레이블이 ffmpeg인 게시물을 표시합니다. 모든 게시물 표시

2025년 7월 23일 수요일

TI AM69 ffmpeg build

 $ source /opt/ti-processor-sdk-linux-am69-sk-10_00_07_06/linux-devkit/environment-setup


$ ./configure --prefix=/home/kimdh/work/mingw/build/ffmpeg-3.3.3/ffmpeg_am69 --enable-shared --disable-static --enable-gpl --enable-cross-compile --arch=arm64 --target-os=linux --cross-prefix=aarch64-oe-linux- --sysroot=$SDKTARGETSYSROOT --pkgconfigdir=$PKG_CONFIG_SYSROOT_DIR --pkg-config=/opt/ti-processor-sdk-linux-am69-sk-10_00_07_06/linux-devkit/sysroots/x86_64-arago-linux/usr/bin/pkg-config --disable-doc


make 

make install

2025년 2월 26일 수요일

ffmpeg v4l2m2m 디코더 사용법

AVCodec* m_pCodec;
AVCodecContext* m_pCodecCtx;
...

// v4l2m2m 디코더 찾기
m_pCodec = (AVCodec*)avcodec_find_decoder_by_name("h264_v4l2m2m");

// 코덱 컨텍스트 할당
m_pCodecCtx = avcodec_alloc_context3(m_pCodec);

// 픽셀포멧, width, height 지정
m_pCodecCtx->pix_fmt = AV_PIX_FMT_NV12;
m_pCodecCtx->width = 1920;
m_pCodecCtx->height = 1080;

// 코덱 열기
avcodec_open2(m_pCodecCtx, m_pCodec, NULL);

// 디코딩
retLen = avcodec_send_packet(m_pCodecCtx, &m_avPacket);
if (retLen == 0) retLen = avcodec_receive_frame(m_pCodecCtx, frame);


* 디코더 찾기, 픽셀포멧/width/height 지정 외 일반 디코딩 방법과 동일

2024년 2월 1일 목요일

윈도우에서 ffmpeg NVIDIA CUDA Codec 연동 build

 * msys 설치



* Visual Studio 메뉴에서 x64 Native Tools Command Prompt for VS 2022 실행

c:\msys64\msys2_shell.cmd -use-full-path 실행

빌드에 필요한 패키지들을 설치한다.

pacman -Syu
pacman -S make diffutils yasm nasm git pkg-config

where link 하면 아래 두개가 나온다.

C:\msys64\usr\bin\link.exe
C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\<버전>\bin\Hostx64\x64\link.exe

mv /usr/bin/link.exe /usr/bin/link.exe.org => 겹치지 않게 이름 변경


* 소스 다운로드

git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git

nv-codec-headers 폴더 들어가서 아래 실행
make install PREFIX=/usr

ffmpeg 소스 다운로드
git clone https://git.ffmpeg.org/ffmpeg.git


* CUDA Toolkit 설치
https://developer.nvidia.com/cuda-toolkit 에서 툴킷 받아서 설치한다.(혹은 구글에서 cuda toolkit 검색)

홈 디렉토리에서 아래 폴더 생성
mkdir build
mkdir nv_sdk

C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\<버전> 아래에 include 폴더 복사 후 nv_sdk 아래에 불여넣기
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\<버전>\lib 아래에 x64 폴더 복사 후 nv_sdk 아래에 붙여넣기


* 빌드

export PATH="/c/Program Files/NVIDIA GPU Computing Toolkit/CUDA/<버전>/bin/":$PATH

ffmpeg 폴더에 들어가서 아래 실행

./configure --prefix=../build --toolchain=msvc --arch=x86_64 --enable-yasm --enable-shared --enable-gpl --enable-nonfree --enable-w32threads --enable-cuda-nvcc --enable-libnpp --extra-cflags=-I../nv_sdk/include --extra-ldflags=-libpath:../nv_sdk/x64

make
make install



* 32비트 빌드

Visual Studio 메뉴에서 x86 Native Tools Command Prompt for VS 2022 실행 후 c:\msys64\msys2_shell.cmd -use-full-path 실행

./configure --prefix=../build --toolchain=msvc --arch=x86_32 --enable-yasm --enable-shared --enable-gpl --enable-nonfree --enable-w32threads

* x264 빌드 후 ffmpeg 연동 빌드

32/64 비트는 각각 
32비트 => x86 Native Tools Command Prompt for VS 2022 실행 후 c:\msys64\msys2_shell.cmd -use-full-path 실행
64비트 => x64 Native Tools Command Prompt for VS 2022 실행 후 c:\msys64\msys2_shell.cmd -use-full-path 실행

소스 다운로드
git clone http://git.videolan.org/git/x264.git

x264 폴더에서 아래 실행 - 32/64비트 공통
CC=cl ./configure --prefix=../build --enable-static
 
make
make install

export PKG_CONFIG_PATH=../build/lib/pkgconfig/

ffmpeg 폴더에서 아래 실행
64비트
./configure --prefix=../build --toolchain=msvc --arch=x86_64 --enable-yasm --enable-shared --enable-gpl --enable-nonfree --enable-w32threads --enable-cuda-nvcc --enable-libnpp --extra-cflags="-I../nv_sdk/include -I../build/include" --extra-ldflags="-libpath:../nv_sdk/x64 -libpath:../build/lib" --enable-libx264

32비트
./configure --prefix=../build --toolchain=msvc --arch=x86_32 --enable-yasm --enable-shared --enable-gpl --enable-nonfree --enable-w32threads  --extra-cflags="-I../build/include" --extra-ldflags="-libpath:../build/lib" --enable-libx264

make
make install


< 2026.6.12 추가 >
 ./configure --prefix=../build/ffmpeg-8.1.1/x86 --toolchain=msvc --arch=x86_32 --enable-shared --enable-gpl --enable-nonfree --enable-w32threads

 ./configure --prefix=../build/ffmpeg-8.1.1/x64 --toolchain=msvc --arch=x86_64 --enable-shared --enable-gpl --enable-nonfree --enable-w32threads
  
 ./configure --prefix=../build/ffmpeg-8.1.1/x64 --toolchain=msvc --arch=x86_64 \
  --enable-shared --enable-gpl --enable-nonfree --enable-w32threads \
  --enable-cuda-nvcc \
  --extra-cflags="-I../nv_sdk/include" \
  --extra-ldflags="-libpath:../nv_sdk/x64 -libpath:../build/lib" \
  --nvccflags="-gencode arch=compute_60,code=sm_60 -O2 -allow-unsupported-compiler -D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH"

< 2026.07.16 추가 >
ffmpeg-8.1.2 32비트 configure 실패하면 아래 실행 후 재시도
$ sed -i \
  -e 's/grep -q \^Microsoft/grep -q Microsoft/g' \
  -e 's/grep \^Microsoft/grep Microsoft/g' \
  configure

* 참고 : 리눅스 빌드

cd ~
git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git
cd nv-codec-headers
make
sudo make install

./configure --prefix=../build/ffmpeg-5.1.2 --extra-cflags=-I/usr/local/cuda/include --extra-ldflags=-L/usr/local/cuda/lib64 \
--enable-cuda-nvcc --enable-libnpp --enable-shared --enable-gpl --enable-nonfree




2021년 1월 12일 화요일

ffmpeg common.h 에서 C1060 compiler is out of heap space 에러 처리

 libavutil/common.h 제일 위에 아래 코드 추가해준다


#ifndef AVUTIL_COMMON_H
#define AVUTIL_COMMON_H

#ifndef INT64_C
#define INT64_C(c) (c ## LL)
#define UINT64_C(c) (c ## ULL)
#endif
#define INT64_MAX    _I64_MAX 
#define INT64_MIN    ((int64_t)_I64_MIN)


2019년 11월 14일 목요일

avformat_open_input rtsp connection timeout 주기

ffmpeg demuxer 를 사용해서 rtsp client 를 구현할때 접속이 되지않으면 avformat_open_input 에서 무한 블러킹이 걸린다. 이때 아래와 같이 타임아웃을 주면 avformat_open_input 을 빠져나올수 있다.


AVDictionary* dicts = NULL;

av_dict_set(&dicts, "stimeout", "2000000", 0);

int err = avformat_open_input(&m_pFormatCtx, filepath, NULL, &dicts);

2017년 10월 5일 목요일

ffmpeg+x264 윈도우/안드로이드 빌드(32/64비트)

ffmpeg을 빌드하는 방법 중 가장 확실하고 안정적인 방법은 리눅스(우분투)에서 빌드하는 것이다. 윈도우에서 mingw+msys 조합으로 빌드하는 방법도 있는데 여러모로 우분투에서 하는것이 정신건강에 좋다.
우분투는 실제 PC에 설치하지않고 VirtualBox 에 설치하면 간편하게 쓸수있다.

리눅스에서 mingw 설치

리눅스에서 아래 경로의 git 소스를 clone 받는다.

https://github.com/Zeranoe/mingw-w64-build.git

./mingw-w64-build 실행

위 스크립트를 실행하면 필요한 툴과 mingw 소스코드를 다운받은 다음 gcc로 빌드해서 윈도우용 32/64비트 크로스컴파일 툴채인을 만들어준다.
i686-w64-mingw32 아래에 32비트
x86_64-w64-mingw32 아래에 64비트 빌드 툴채인이 만들어진다.

따라서 쉘 환경의 경로설정에 따라 32/64비트 빌드 환경을 결정할 수 있다.

export PATH=$PATH:/home/ubuntu/work/mingw/mingw-w64-build/i686-w64-mingw32/bin => 32비트

export PATH=$PATH:/home/ubuntu/work/mingw/mingw-w64-build/x86_64-w64-mingw32/bin => 64비트

x264 빌드

./configure --cross-prefix=i686-w64-mingw32- --host=i686-w64-mingw32 => 32비트

./configure --cross-prefix=x86_64-w64-mingw32- --host=x86_64-w64-mingw32 => 64비트

make

빌드에 성공하면 libx264.a 파일이 생성된다.

ffmpeg 빌드

위에서 빌드한 libx264.a 파일을 정적으로 링크해서 빌드해주면된다.

※ x264 소스코드 : /home/ubuntu/work/mingw/x264
   ffmpeg 소스코드 : /home/ubuntu/work/mingw/ffmpeg
   output : /home/ubuntu/work/mingw/output

32비트
./configure --arch=x86 --target-os=mingw32 --cross-prefix=i686-w64-mingw32- --pkg-config=pkg-config --enable-w32threads --prefix=../output/ffmpeg_x86/ --enable-shared --disable-static --enable-gpl --enable-libx264 --extra-cflags=-I/home/ubuntu/work/mingw/x264 --extra-ldflags=-L/home/ubuntu/work/mingw/x264

64비트
./configure --arch=x86_64 --target-os=mingw32 --cross-prefix=x86_64-w64-mingw32- --pkg-config=pkg-config --enable-w32threads --prefix=../output/ffmpeg_x64/ --enable-shared --disable-static --enable-gpl --enable-libx264 --extra-cflags=-I/home/ubuntu/work/mingw/x264 --extra-ldflags=-L/home/ubuntu/work/mingw/x264

make
make install 하면 /home/ubuntu/work/mingw/output/ 아래에 빌드파일들 복사됨


안드로이드 NDK 빌드

안드로이드 NDK 를 다운받은 다음 툴채인을 만든다. 툴채인을 꼭 만들필요는 없는데 안만드는 경우 해당 아키텍쳐의 빌드경로만 설정해주면 된다. 여기서는 툴채인을 만들도록 하겠다.(툴채인 만드는법은 다른 포스트 참조 - http://greenday96.blogspot.kr/2015/01/android-ffmpeg-build.html)

툴채인 경로 : /home/ubuntu/work/my-android-toolchain-18

x264 빌드

./configure --cross-prefix=/home/ubuntu/work/my-android-toolchain-18/bin/arm-linux-androideabi- --host=arm-linux --extra-cflags='-marm -march=armv7-a -mfloat-abi=softfp -mfpu=neon -D__ANDROID_API__=18' --extra-ldflags='-Wl,--fix-cortex-a8' --enable-pic

make
빌드를 하면 안드로이드용 libx264.a 라이브러리가 생성된다.


ffmpeg 빌드

./configure --target-os=linux --arch=arm --enable-cross-compile --cc=/home/ubuntu/work/my-android-toolchain-18/bin/arm-linux-androideabi-gcc --cross-prefix=/home/ubuntu/work/my-android-toolchain-18/bin/arm-linux-androideabi- --prefix=../output/android --extra-cflags='-marm -march=armv7-a -mfloat-abi=softfp -mfpu=neon -D__ANDROID_API__=18' --extra-ldflags='-Wl,--fix-cortex-a8 -llog' --enable-shared --enable-gpl --enable-libx264 --extra-cflags=-I/home/ubuntu/work/mingw/x264 --extra-ldflags=-L/home/ubuntu/work/mingw/x264

make
make install
하면 /home/ubuntu/work/mingw/output/android 아래에 빌드된 파일들이 복사된다

Android.mk 파일

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := avcodec
LOCAL_SRC_FILES := $(LOCAL_PATH)/libs/libavcodec.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avformat
LOCAL_SRC_FILES := $(LOCAL_PATH)/libs/libavformat.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := swscale
LOCAL_SRC_FILES := $(LOCAL_PATH)/libs/libswscale.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avutil
LOCAL_SRC_FILES := $(LOCAL_PATH)/libs/libavutil.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := swresample
LOCAL_SRC_FILES := $(LOCAL_PATH)/libs/libswresample.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avfilter
LOCAL_SRC_FILES := $(LOCAL_PATH)/libs/libavfilter.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := postproc
LOCAL_SRC_FILES := $(LOCAL_PATH)/libs/libpostproc.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := x264
LOCAL_SRC_FILES := $(LOCAL_PATH)/libs/libx264.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)

LOCAL_MODULE    := DXMediaPlayer
LOCAL_SRC_FILES := DXMediaPlayer.cpp \
   DXMediaPlayerCtrl.cpp

LOCAL_LDLIBS := -llog -lz -ljnigraphics -landroid -Wl,--no-warn-shared-textrel

LOCAL_STATIC_LIBRARIES := avfilter avformat avcodec avutil swscale swresample x264 postproc

LOCAL_CFLAGS := -DANDROID -D__STDC_CONSTANT_MACROS
LOCAL_CPPFLAGS := -DANDROID -D__STDC_CONSTANT_MACROS

include $(BUILD_SHARED_LIBRARY)



콘솔창에서 빌드

ndk-build

빌드에 성공하면 x264+ffmpeg 포함된 so 파일 생성








2017년 1월 18일 수요일

CUDA 코덱 비디오 인코더 사용 소스코드 - CUDA Codec Video Encoder source code

NvEncoder 샘플소스를 수정한 소스코드, QT 기반으로 작성되었으며 yuv420 포멧으로 입력받은 영상 데이터를 h264로 인코딩한다.
인코딩된 프레임은 m_pEncodeBuffer 버퍼에 저장

< encodethread.h >
 #ifndef ENCODETHREAD_H  
 #define ENCODETHREAD_H  
   
 #include <QThread>  
 #include <opencv2/imgproc/imgproc_c.h>  
 #include "imagequeue.h"  
 #include "./common/inc/NvHWEncoder.h"  
   
   
 #define MAX_ENCODE_QUEUE 32  
 #define FRAME_QUEUE 240  
   
 #define SET_VER(configStruct, type) {configStruct.version = type##_VER;}  
   
 template<class T>  
 class CNvQueue {  
   T** m_pBuffer;  
   unsigned int m_uSize;  
   unsigned int m_uPendingCount;  
   unsigned int m_uAvailableIdx;  
   unsigned int m_uPendingndex;  
 public:  
   CNvQueue(): m_pBuffer(NULL), m_uSize(0), m_uPendingCount(0), m_uAvailableIdx(0),  
         m_uPendingndex(0)  
   {  
   }  
   
   ~CNvQueue()  
   {  
     delete[] m_pBuffer;  
   }  
   
   bool Initialize(T *pItems, unsigned int uSize)  
   {  
     m_uSize = uSize;  
     m_uPendingCount = 0;  
     m_uAvailableIdx = 0;  
     m_uPendingndex = 0;  
     m_pBuffer = new T *[m_uSize];  
     for (unsigned int i = 0; i < m_uSize; i++)  
     {  
       m_pBuffer[i] = &pItems[i];  
     }  
     return true;  
   }  
   
   
   T * GetAvailable()  
   {  
     T *pItem = NULL;  
     if (m_uPendingCount == m_uSize)  
     {  
       return NULL;  
     }  
     pItem = m_pBuffer[m_uAvailableIdx];  
     m_uAvailableIdx = (m_uAvailableIdx+1)%m_uSize;  
     m_uPendingCount += 1;  
     return pItem;  
   }  
   
   T* GetPending()  
   {  
     if (m_uPendingCount == 0)  
     {  
       return NULL;  
     }  
   
     T *pItem = m_pBuffer[m_uPendingndex];  
     m_uPendingndex = (m_uPendingndex+1)%m_uSize;  
     m_uPendingCount -= 1;  
     return pItem;  
   }  
 };  
   
 typedef struct _EncodeFrameConfig  
 {  
   uint8_t *yuv[3];  
   uint32_t stride[3];  
   uint32_t width;  
   uint32_t height;  
 }EncodeFrameConfig;  
   
 typedef enum  
 {  
   NV_ENC_DX9 = 0,  
   NV_ENC_DX11 = 1,  
   NV_ENC_CUDA = 2,  
   NV_ENC_DX10 = 3,  
 } NvEncodeDeviceType;  
   
 class EncodeThread : public QThread  
 {  
   Q_OBJECT  
 public:  
   explicit EncodeThread(QThread *parent = 0, ImageQueue<EncodeFrame> *queue = NULL);  
   virtual ~EncodeThread();  
   
   void start();  
   void stop();  
   
 protected:  
   virtual void run();  
   
 signals:  
   void started();  
   void finished();  
   
 private:  
   bool openEncoder(NV_ENC_BUFFER_FORMAT format, int width, int height);  
   void closeEncoder();  
   
   NVENCSTATUS deinitialize(uint32_t devicetype);  
   NVENCSTATUS encodeFrame(EncodeFrameConfig *pEncodeFrame, bool bFlush, uint32_t width, uint32_t height);  
   NVENCSTATUS initCuda(uint32_t deviceID = 0);  
   NVENCSTATUS allocateIOBuffers(uint32_t uInputWidth, uint32_t uInputHeight, NV_ENC_BUFFER_FORMAT inputFormat);  
   NVENCSTATUS releaseIOBuffers();  
   NVENCSTATUS flushEncoder();  
   
 private:  
   bool  m_bRun;  
   
 private:  
   ImageQueue<EncodeFrame>* m_pQueue;  
   
   EncodeConfig    m_stEncodeConfig;  
   
   CNvHWEncoder*    m_pNvHWEncoder;  
   uint32_t      m_uEncodeBufferCount;  
   uint32_t      m_uPicStruct;  
   void*        m_pDevice;  
   
   CUcontext              m_cuContext;  
   EncodeConfig            m_stEncoderInput;  
   EncodeBuffer            m_stEncodeBuffer[MAX_ENCODE_QUEUE];  
   CNvQueue<EncodeBuffer>       m_EncodeBufferQueue;  
   EncodeOutputBuffer         m_stEOSOutputBfr;  
   
   uint8_t*  m_pEncodeBuffer;  
   int     m_nEncodeBufferSize;  
   
   FILE*    m_pFile;  
 };  
   
 #endif // ENCODETHREAD_H  
   


< encodethread.cpp >
 #include "encodethread.h"  
 #include <QDebug>  
   
 #include "DXMediaPlayerCtrl.h"  
 #include "DXUtil.h"  
 #include "MediaBuffer.h"  
 #include "GlobalTimer.h"  
   
 #define BITSTREAM_BUFFER_SIZE 2 * 1024 * 1024  
   
 EncodeThread::EncodeThread(QThread *parent, ImageQueue<EncodeFrame> *queue) : QThread(parent)  
 {  
   m_bRun = false;  
   m_pQueue = queue;  
   
   m_pNvHWEncoder = new CNvHWEncoder;  
   m_cuContext = NULL;  
   
   m_uEncodeBufferCount = 0;  
   memset(&m_stEncoderInput, 0, sizeof(m_stEncoderInput));  
   memset(&m_stEOSOutputBfr, 0, sizeof(m_stEOSOutputBfr));  
   memset(&m_stEncodeBuffer, 0, sizeof(m_stEncodeBuffer));  
   
   m_pEncodeBuffer = new uint8_t[BITSTREAM_BUFFER_SIZE];  
   m_nEncodeBufferSize = 0;  
   
   m_pFile = NULL;  
 }  
   
 EncodeThread::~EncodeThread()  
 {  
   stop();  
   if (m_pNvHWEncoder) {  
     delete m_pNvHWEncoder;  
     m_pNvHWEncoder = NULL;  
   }  
   
   if (m_pEncodeBuffer) {  
     delete[] m_pEncodeBuffer;  
     m_pEncodeBuffer = NULL;  
   }  
   
   RTSPServer::destroy();  
   GlobalTimer::destroy();  
 }  
   
 void EncodeThread::start()  
 {  
   m_bRun = true;  
   QThread::start();  
 }  
   
 void EncodeThread::stop()  
 {  
   m_bRun = false;  
   wait();  
 }  
   
 void EncodeThread::run()  
 {  
   emit started();  
   
   bool bInit = false;  
   int count = 0;  
   
   EncodeFrameConfig stEncodeFrame;  
   
   CDXMediaPlayerCtrl *player = new CDXMediaPlayerCtrl(NULL, NULL);  
   player->openCaptureServerSession("stream1", AV_CODEC_ID_H264, AV_CODEC_ID_NONE);  
   player->playCaptureServerSession();  
   
   uint16_t port = 8554;  
   if (player->startServer(port) < 0)  
     qDebug() << "failed to start server, port : " << port;  
   
   uint64_t timestamp = 0;  
   MediaBuffer *pBuffer = NULL;  
   
   while (m_bRun) {  
     EncodeFrame *frame = m_pQueue->pop();  
     if (frame == NULL) {  
       QThread::usleep(1);  
       continue;  
     }  
   
     count = m_pQueue->count();  
     if (count > 0) qDebug() << "decode queue : " << count;  
   
     if (!bInit) {  
       NV_ENC_BUFFER_FORMAT format = NV_ENC_BUFFER_FORMAT_UNDEFINED;  
       if (frame->format == 0) format = NV_ENC_BUFFER_FORMAT_NV12;  
       else format = NV_ENC_BUFFER_FORMAT_YUV444;  
   
       if (openEncoder(format, frame->width, frame->height)) {  
         //m_pFile = fopen("output.264", "wb");  
         bInit = true;  
       } else {  
         closeEncoder();  
       }  
     }  
   
     if (bInit) {  
       memset(&stEncodeFrame, 0, sizeof(stEncodeFrame));  
   
       stEncodeFrame.yuv[0] = frame->yuv[0];  
       stEncodeFrame.yuv[1] = frame->yuv[1];  
       stEncodeFrame.yuv[2] = frame->yuv[2];  
   
       stEncodeFrame.stride[0] = frame->stride[0];  
       stEncodeFrame.stride[1] = frame->stride[1];  
       stEncodeFrame.stride[2] = frame->stride[2];  
   
       stEncodeFrame.width = frame->width;  
       stEncodeFrame.height = frame->height;  
   
       if (encodeFrame(&stEncodeFrame, false, frame->width, frame->height) == NV_ENC_SUCCESS) {  
         if (m_pFile) fwrite(m_pEncodeBuffer, 1, m_nEncodeBufferSize, m_pFile);  
   
         timestamp = GetTimeOfDay();  
         pBuffer = MediaBuffer::createBuffer(VideoMedia, m_pEncodeBuffer, m_nEncodeBufferSize, timestamp, timestamp);  
         if (player->pushCaptureInput(pBuffer) < 0) {  
           qDebug() << "cannot push capture input";  
           delete pBuffer;  
         }  
       }  
     }  
   
     delete frame;  
   }  
   
   if (bInit) encodeFrame(NULL, true, m_stEncodeConfig.width, m_stEncodeConfig.height);  
   
   player->close();  
   player->stopServer();  
   delete player;  
   
   closeEncoder();  
   
   if (m_pFile) {  
     fclose(m_pFile);  
     m_pFile = NULL;  
   }  
   
   emit finished();  
 }  
   
 bool EncodeThread::openEncoder(NV_ENC_BUFFER_FORMAT format, int width, int height)  
 {  
   memset(&m_stEncodeConfig, 0, sizeof(EncodeConfig));  
   
   m_stEncodeConfig.endFrameIdx = INT_MAX;  
   m_stEncodeConfig.bitrate = 5000000;  
   m_stEncodeConfig.rcMode = NV_ENC_PARAMS_RC_CONSTQP;  
   //m_stEncodeConfig.gopLength = NVENC_INFINITE_GOPLENGTH;  
   m_stEncodeConfig.deviceType = NV_ENC_CUDA;  
   m_stEncodeConfig.codec = NV_ENC_H264;  
   //m_stEncodeConfig.fps = 30;  
   m_stEncodeConfig.qp = 28;  
   m_stEncodeConfig.i_quant_factor = DEFAULT_I_QFACTOR;  
   m_stEncodeConfig.b_quant_factor = DEFAULT_B_QFACTOR;  
   m_stEncodeConfig.i_quant_offset = DEFAULT_I_QOFFSET;  
   m_stEncodeConfig.b_quant_offset = DEFAULT_B_QOFFSET;  
   m_stEncodeConfig.presetGUID = NV_ENC_PRESET_DEFAULT_GUID;  
   m_stEncodeConfig.pictureStruct = NV_ENC_PIC_STRUCT_FRAME;  
   m_stEncodeConfig.inputFormat = format;  
   
   m_stEncodeConfig.repeatSPSPPS = 1;  
   m_stEncodeConfig.width = width;  
   m_stEncodeConfig.height = height;  
   m_stEncodeConfig.gopLength = 15;  
   m_stEncodeConfig.fps = 15;  
   //m_stEncodeConfig.encoderPreset = "hq";    
   
   switch (m_stEncodeConfig.deviceType)  
   {  
 #if defined(NV_WINDOWS)  
   case NV_ENC_DX9:  
     InitD3D9(m_stEncodeConfig.deviceID);  
     break;  
   
   case NV_ENC_DX10:  
     InitD3D10(m_stEncodeConfig.deviceID);  
     break;  
   
   case NV_ENC_DX11:  
     InitD3D11(m_stEncodeConfig.deviceID);  
     break;  
 #endif  
   case NV_ENC_CUDA:  
     initCuda(m_stEncodeConfig.deviceID);  
     break;  
   }  
   
   NVENCSTATUS nvStatus = NV_ENC_SUCCESS;  
   
   if (m_stEncodeConfig.deviceType != NV_ENC_CUDA)  
     nvStatus = m_pNvHWEncoder->Initialize(m_pDevice, NV_ENC_DEVICE_TYPE_DIRECTX);  
   else  
     nvStatus = m_pNvHWEncoder->Initialize(m_pDevice, NV_ENC_DEVICE_TYPE_CUDA);  
   
   if (nvStatus != NV_ENC_SUCCESS)  
     return false;  
   
   m_stEncodeConfig.presetGUID = m_pNvHWEncoder->GetPresetGUID(m_stEncodeConfig.encoderPreset, m_stEncodeConfig.codec);  
 #if 0  
   m_stEncodeConfig.fOutput = fopen("output.264", "wb");  
   if (!m_stEncodeConfig.fOutput)  
     qDebug() << "failed to open output file";    
 #endif  
   nvStatus = m_pNvHWEncoder->CreateEncoder(&m_stEncodeConfig);  
   if (nvStatus != NV_ENC_SUCCESS)  
     return false;  
   
   m_stEncodeConfig.maxWidth = m_stEncodeConfig.maxWidth ? m_stEncodeConfig.maxWidth : m_stEncodeConfig.width;  
   m_stEncodeConfig.maxHeight = m_stEncodeConfig.maxHeight ? m_stEncodeConfig.maxHeight : m_stEncodeConfig.height;  
   
   m_stEncoderInput.enableAsyncMode = m_stEncodeConfig.enableAsyncMode;  
   
   if (m_stEncodeConfig.numB > 0)  
   {  
     m_uEncodeBufferCount = m_stEncodeConfig.numB + 4; // min buffers is numb + 1 + 3 pipelining  
   }  
   else  
   {  
     int numMBs = ((m_stEncodeConfig.maxHeight + 15) >> 4) * ((m_stEncodeConfig.maxWidth + 15) >> 4);  
     int NumIOBuffers;  
     if (numMBs >= 32768) //4kx2k  
       NumIOBuffers = MAX_ENCODE_QUEUE / 8;  
     else if (numMBs >= 16384) // 2kx2k  
       NumIOBuffers = MAX_ENCODE_QUEUE / 4;  
     else if (numMBs >= 8160) // 1920x1080  
       NumIOBuffers = MAX_ENCODE_QUEUE / 2;  
     else  
       NumIOBuffers = MAX_ENCODE_QUEUE;  
     m_uEncodeBufferCount = NumIOBuffers;  
   }  
   m_uPicStruct = m_stEncodeConfig.pictureStruct;  
   
   nvStatus = allocateIOBuffers(m_stEncodeConfig.width, m_stEncodeConfig.height, m_stEncodeConfig.inputFormat);  
   if (nvStatus != NV_ENC_SUCCESS)  
     return 1;  
   
   unsigned int preloadedFrameCount = FRAME_QUEUE;  
   if (m_stEncodeConfig.preloadedFrameCount >= 2)  
   {  
     preloadedFrameCount = m_stEncodeConfig.preloadedFrameCount;  
   }  
   
   qDebug() << "encoder " << width << "x" << height << " opened";  
   
 #if 0  
   GUID guids[10];  
   uint32_t count;  
   m_pNvHWEncoder->NvEncGetEncodeGUIDs(guids, 10, &count);  
   
   NV_ENC_BUFFER_FORMAT fmt[20];  
   memset(fmt, 0, sizeof(fmt));  
   m_pNvHWEncoder->NvEncGetInputFormats(guids[0], fmt, 10, &count);  
 #endif  
   
   return true;  
 }  
   
 void EncodeThread::closeEncoder()  
 {  
   if (m_stEncodeConfig.fOutput) {  
     fclose(m_stEncodeConfig.fOutput);  
     m_stEncodeConfig.fOutput = NULL;  
   }  
   deinitialize(m_stEncodeConfig.deviceType);  
 }  
   
 void convertYUVpitchtoNV12( unsigned char *yuv_luma, unsigned char *yuv_cb, unsigned char *yuv_cr,  
               unsigned char *nv12_luma, unsigned char *nv12_chroma,  
               int width, int height , int srcStride, int dstStride)  
 {  
   int y;  
   int x;  
   if (srcStride == 0)  
     srcStride = width;  
   if (dstStride == 0)  
     dstStride = width;  
   
   for ( y = 0 ; y < height ; y++)  
   {  
     memcpy( nv12_luma + (dstStride*y), yuv_luma + (srcStride*y) , width );  
   }  
   
   for ( y = 0 ; y < height/2 ; y++)  
   {  
     for ( x= 0 ; x < width; x=x+2)  
     {  
       nv12_chroma[(y*dstStride) + x] =  yuv_cb[((srcStride/2)*y) + (x >>1)];  
       nv12_chroma[(y*dstStride) +(x+1)] = yuv_cr[((srcStride/2)*y) + (x >>1)];  
     }  
   }  
 }  
   
 void convertYUV10pitchtoP010PL(unsigned short *yuv_luma, unsigned short *yuv_cb, unsigned short *yuv_cr,  
   unsigned short *nv12_luma, unsigned short *nv12_chroma, int width, int height, int srcStride, int dstStride)  
 {  
   int x, y;  
   
   for (y = 0; y < height; y++)  
   {  
     for (x = 0; x < width; x++)  
     {  
       nv12_luma[(y*dstStride / 2) + x] = yuv_luma[(srcStride*y) + x] << 6;  
     }  
   }  
   
   for (y = 0; y < height / 2; y++)  
   {  
     for (x = 0; x < width; x = x + 2)  
     {  
       nv12_chroma[(y*dstStride / 2) + x] = yuv_cb[((srcStride / 2)*y) + (x >> 1)] << 6;  
       nv12_chroma[(y*dstStride / 2) + (x + 1)] = yuv_cr[((srcStride / 2)*y) + (x >> 1)] << 6;  
     }  
   }  
 }  
   
 void convertYUVpitchtoYUV444(unsigned char *yuv_luma, unsigned char *yuv_cb, unsigned char *yuv_cr,  
   unsigned char *surf_luma, unsigned char *surf_cb, unsigned char *surf_cr, int width, int height, int srcStride, int dstStride)  
 {  
   int h;  
   
   for (h = 0; h < height; h++)  
   {  
     memcpy(surf_luma + dstStride * h, yuv_luma + srcStride * h, width);  
     memcpy(surf_cb + dstStride * h, yuv_cb + srcStride * h, width);  
     memcpy(surf_cr + dstStride * h, yuv_cr + srcStride * h, width);  
   }  
 }  
   
 void convertYUV10pitchtoYUV444(unsigned short *yuv_luma, unsigned short *yuv_cb, unsigned short *yuv_cr,  
   unsigned short *surf_luma, unsigned short *surf_cb, unsigned short *surf_cr,  
   int width, int height, int srcStride, int dstStride)  
 {  
   int x, y;  
   
   for (y = 0; y < height; y++)  
   {  
     for (x = 0; x < width; x++)  
     {  
       surf_luma[(y*dstStride / 2) + x] = yuv_luma[(srcStride*y) + x] << 6;  
       surf_cb[(y*dstStride / 2) + x] = yuv_cb[(srcStride*y) + x] << 6;  
       surf_cr[(y*dstStride / 2) + x] = yuv_cr[(srcStride*y) + x] << 6;  
     }  
   }  
 }  
   
 NVENCSTATUS EncodeThread::encodeFrame(EncodeFrameConfig *pEncodeFrame, bool bFlush, uint32_t width, uint32_t height)  
 {  
   NVENCSTATUS nvStatus = NV_ENC_SUCCESS;  
   uint32_t lockedPitch = 0;  
   EncodeBuffer *pEncodeBuffer = NULL;  
   
   if (bFlush)  
   {  
     flushEncoder();  
     return NV_ENC_SUCCESS;  
   }  
   
   if (!pEncodeFrame)  
   {  
     return NV_ENC_ERR_INVALID_PARAM;  
   }  
   
   pEncodeBuffer = m_EncodeBufferQueue.GetAvailable();  
   if(!pEncodeBuffer)  
   {  
     m_pNvHWEncoder->ProcessOutput(m_EncodeBufferQueue.GetPending());  
     pEncodeBuffer = m_EncodeBufferQueue.GetAvailable();  
   }  
   
   unsigned char *pInputSurface;  
   
   nvStatus = m_pNvHWEncoder->NvEncLockInputBuffer(pEncodeBuffer->stInputBfr.hInputSurface, (void**)&pInputSurface, &lockedPitch);  
   if (nvStatus != NV_ENC_SUCCESS)  
     return nvStatus;  
   
   if (pEncodeBuffer->stInputBfr.bufferFmt == NV_ENC_BUFFER_FORMAT_NV12_PL)  
   {  
     unsigned char *pInputSurfaceCh = pInputSurface + (pEncodeBuffer->stInputBfr.dwHeight*lockedPitch);  
     convertYUVpitchtoNV12(pEncodeFrame->yuv[0], pEncodeFrame->yuv[1], pEncodeFrame->yuv[2], pInputSurface, pInputSurfaceCh, width, height, width, lockedPitch);  
   }  
   else if (pEncodeBuffer->stInputBfr.bufferFmt == NV_ENC_BUFFER_FORMAT_YUV444)  
   {  
     unsigned char *pInputSurfaceCb = pInputSurface + (pEncodeBuffer->stInputBfr.dwHeight * lockedPitch);  
     unsigned char *pInputSurfaceCr = pInputSurfaceCb + (pEncodeBuffer->stInputBfr.dwHeight * lockedPitch);  
     convertYUVpitchtoYUV444(pEncodeFrame->yuv[0], pEncodeFrame->yuv[1], pEncodeFrame->yuv[2], pInputSurface, pInputSurfaceCb, pInputSurfaceCr, width, height, width, lockedPitch);  
   }  
   else if (pEncodeBuffer->stInputBfr.bufferFmt == NV_ENC_BUFFER_FORMAT_YUV420_10BIT)  
   {  
     unsigned char *pInputSurfaceCh = pInputSurface + (pEncodeBuffer->stInputBfr.dwHeight*lockedPitch);  
     convertYUV10pitchtoP010PL((uint16_t *)pEncodeFrame->yuv[0], (uint16_t *)pEncodeFrame->yuv[1], (uint16_t *)pEncodeFrame->yuv[2], (uint16_t *)pInputSurface, (uint16_t *)pInputSurfaceCh, width, height, width, lockedPitch);  
   }  
   else //if (pEncodeBuffer->stInputBfr.bufferFmt == NV_ENC_BUFFER_FORMAT_YUV444_10BIT)  
   {  
     unsigned char *pInputSurfaceCb = pInputSurface + (pEncodeBuffer->stInputBfr.dwHeight * lockedPitch);  
     unsigned char *pInputSurfaceCr = pInputSurfaceCb + (pEncodeBuffer->stInputBfr.dwHeight * lockedPitch);  
     convertYUV10pitchtoYUV444((uint16_t *)pEncodeFrame->yuv[0], (uint16_t *)pEncodeFrame->yuv[1], (uint16_t *)pEncodeFrame->yuv[2], (uint16_t *)pInputSurface, (uint16_t *)pInputSurfaceCb, (uint16_t *)pInputSurfaceCr, width, height, width, lockedPitch);  
   }  
   nvStatus = m_pNvHWEncoder->NvEncUnlockInputBuffer(pEncodeBuffer->stInputBfr.hInputSurface);  
   if (nvStatus != NV_ENC_SUCCESS)  
     return nvStatus;  
   
   nvStatus = m_pNvHWEncoder->NvEncEncodeFrame(pEncodeBuffer, NULL, width, height, (NV_ENC_PIC_STRUCT)m_uPicStruct);  
   if (nvStatus == NV_ENC_SUCCESS) {  
     NV_ENC_LOCK_BITSTREAM lockBitstreamData;  
   
     memset(&lockBitstreamData, 0, sizeof(lockBitstreamData));  
     SET_VER(lockBitstreamData, NV_ENC_LOCK_BITSTREAM);  
     lockBitstreamData.outputBitstream = pEncodeBuffer->stOutputBfr.hBitstreamBuffer;  
     lockBitstreamData.doNotWait = false;  
   
     if (m_pNvHWEncoder->NvEncLockBitstream(&lockBitstreamData) == NV_ENC_SUCCESS) {        
       memcpy(m_pEncodeBuffer, lockBitstreamData.bitstreamBufferPtr, lockBitstreamData.bitstreamSizeInBytes);  
       m_nEncodeBufferSize = lockBitstreamData.bitstreamSizeInBytes;  
       m_pNvHWEncoder->NvEncUnlockBitstream(pEncodeBuffer->stOutputBfr.hBitstreamBuffer);  
     }  
   }  
   
   return nvStatus;  
 }  
   
 NVENCSTATUS EncodeThread::initCuda(uint32_t deviceID)  
 {  
   CUresult cuResult;  
   CUdevice device;  
   CUcontext cuContextCurr;  
   int deviceCount = 0;  
   int SMminor = 0, SMmajor = 0;  
   
 #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)  
   typedef HMODULE CUDADRIVER;  
 #else  
   typedef void *CUDADRIVER;  
 #endif  
   CUDADRIVER hHandleDriver = 0;  
   cuResult = cuInit(0, __CUDA_API_VERSION, hHandleDriver);  
   if (cuResult != CUDA_SUCCESS)  
   {  
     PRINTERR("cuInit error:0x%x\n", cuResult);  
     assert(0);  
     return NV_ENC_ERR_NO_ENCODE_DEVICE;  
   }  
   
   cuResult = cuDeviceGetCount(&deviceCount);  
   if (cuResult != CUDA_SUCCESS)  
   {  
     PRINTERR("cuDeviceGetCount error:0x%x\n", cuResult);  
     assert(0);  
     return NV_ENC_ERR_NO_ENCODE_DEVICE;  
   }  
   
   // If dev is negative value, we clamp to 0  
   if ((int)deviceID < 0)  
     deviceID = 0;  
   
   if (deviceID >(unsigned int)deviceCount - 1)  
   {  
     PRINTERR("Invalid Device Id = %d\n", deviceID);  
     return NV_ENC_ERR_INVALID_ENCODERDEVICE;  
   }  
   
   cuResult = cuDeviceGet(&device, deviceID);  
   if (cuResult != CUDA_SUCCESS)  
   {  
     PRINTERR("cuDeviceGet error:0x%x\n", cuResult);  
     return NV_ENC_ERR_NO_ENCODE_DEVICE;  
   }  
   
   cuResult = cuDeviceComputeCapability(&SMmajor, &SMminor, deviceID);  
   if (cuResult != CUDA_SUCCESS)  
   {  
     PRINTERR("cuDeviceComputeCapability error:0x%x\n", cuResult);  
     return NV_ENC_ERR_NO_ENCODE_DEVICE;  
   }  
   
   if (((SMmajor << 4) + SMminor) < 0x30)  
   {  
     PRINTERR("GPU %d does not have NVENC capabilities exiting\n", deviceID);  
     return NV_ENC_ERR_NO_ENCODE_DEVICE;  
   }  
   
   cuResult = cuCtxCreate((CUcontext*)(&m_pDevice), 0, device);  
   if (cuResult != CUDA_SUCCESS)  
   {  
     PRINTERR("cuCtxCreate error:0x%x\n", cuResult);  
     assert(0);  
     return NV_ENC_ERR_NO_ENCODE_DEVICE;  
   }  
   
   cuResult = cuCtxPopCurrent(&cuContextCurr);  
   if (cuResult != CUDA_SUCCESS)  
   {  
     PRINTERR("cuCtxPopCurrent error:0x%x\n", cuResult);  
     assert(0);  
     return NV_ENC_ERR_NO_ENCODE_DEVICE;  
   }  
   return NV_ENC_SUCCESS;  
 }  
   
 NVENCSTATUS EncodeThread::allocateIOBuffers(uint32_t uInputWidth, uint32_t uInputHeight, NV_ENC_BUFFER_FORMAT inputFormat)  
 {  
   NVENCSTATUS nvStatus = NV_ENC_SUCCESS;  
   
   m_EncodeBufferQueue.Initialize(m_stEncodeBuffer, m_uEncodeBufferCount);  
   for (uint32_t i = 0; i < m_uEncodeBufferCount; i++)  
   {  
     nvStatus = m_pNvHWEncoder->NvEncCreateInputBuffer(uInputWidth, uInputHeight, &m_stEncodeBuffer[i].stInputBfr.hInputSurface, inputFormat);  
     if (nvStatus != NV_ENC_SUCCESS)  
       return nvStatus;  
   
     m_stEncodeBuffer[i].stInputBfr.bufferFmt = inputFormat;  
     m_stEncodeBuffer[i].stInputBfr.dwWidth = uInputWidth;  
     m_stEncodeBuffer[i].stInputBfr.dwHeight = uInputHeight;  
     nvStatus = m_pNvHWEncoder->NvEncCreateBitstreamBuffer(BITSTREAM_BUFFER_SIZE, &m_stEncodeBuffer[i].stOutputBfr.hBitstreamBuffer);  
     if (nvStatus != NV_ENC_SUCCESS)  
       return nvStatus;  
      m_stEncodeBuffer[i].stOutputBfr.dwBitstreamBufferSize = BITSTREAM_BUFFER_SIZE;  
     if (m_stEncoderInput.enableAsyncMode)  
     {  
       nvStatus = m_pNvHWEncoder->NvEncRegisterAsyncEvent(&m_stEncodeBuffer[i].stOutputBfr.hOutputEvent);  
       if (nvStatus != NV_ENC_SUCCESS)  
         return nvStatus;  
       m_stEncodeBuffer[i].stOutputBfr.bWaitOnEvent = true;  
     }  
     else  
       m_stEncodeBuffer[i].stOutputBfr.hOutputEvent = NULL;  
   }  
   
   m_stEOSOutputBfr.bEOSFlag = TRUE;  
   
   if (m_stEncoderInput.enableAsyncMode)  
   {  
     nvStatus = m_pNvHWEncoder->NvEncRegisterAsyncEvent(&m_stEOSOutputBfr.hOutputEvent);  
     if (nvStatus != NV_ENC_SUCCESS)  
       return nvStatus;  
   }  
   else  
     m_stEOSOutputBfr.hOutputEvent = NULL;  
   
   return NV_ENC_SUCCESS;  
 }  
   
 NVENCSTATUS EncodeThread::releaseIOBuffers()  
 {  
   for (uint32_t i = 0; i < m_uEncodeBufferCount; i++)  
   {  
     m_pNvHWEncoder->NvEncDestroyInputBuffer(m_stEncodeBuffer[i].stInputBfr.hInputSurface);  
     m_stEncodeBuffer[i].stInputBfr.hInputSurface = NULL;  
     m_pNvHWEncoder->NvEncDestroyBitstreamBuffer(m_stEncodeBuffer[i].stOutputBfr.hBitstreamBuffer);  
     m_stEncodeBuffer[i].stOutputBfr.hBitstreamBuffer = NULL;  
     if (m_stEncoderInput.enableAsyncMode)  
     {  
       m_pNvHWEncoder->NvEncUnregisterAsyncEvent(m_stEncodeBuffer[i].stOutputBfr.hOutputEvent);  
       nvCloseFile(m_stEncodeBuffer[i].stOutputBfr.hOutputEvent);  
       m_stEncodeBuffer[i].stOutputBfr.hOutputEvent = NULL;  
     }  
   }  
   
   if (m_stEOSOutputBfr.hOutputEvent)  
   {  
     if (m_stEncoderInput.enableAsyncMode)  
     {  
       m_pNvHWEncoder->NvEncUnregisterAsyncEvent(m_stEOSOutputBfr.hOutputEvent);  
       nvCloseFile(m_stEOSOutputBfr.hOutputEvent);  
       m_stEOSOutputBfr.hOutputEvent = NULL;  
     }  
   }  
   
   return NV_ENC_SUCCESS;  
 }  
   
 NVENCSTATUS EncodeThread::flushEncoder()  
 {  
   NVENCSTATUS nvStatus = m_pNvHWEncoder->NvEncFlushEncoderQueue(m_stEOSOutputBfr.hOutputEvent);  
   if (nvStatus != NV_ENC_SUCCESS)  
   {  
     assert(0);  
     return nvStatus;  
   }  
   
   EncodeBuffer *pEncodeBufer = m_EncodeBufferQueue.GetPending();  
   while (pEncodeBufer)  
   {  
     m_pNvHWEncoder->ProcessOutput(pEncodeBufer);  
     pEncodeBufer = m_EncodeBufferQueue.GetPending();  
   }  
   
 #if defined(NV_WINDOWS)  
   if (m_stEncoderInput.enableAsyncMode)  
   {  
   
     if (WaitForSingleObject(m_stEOSOutputBfr.hOutputEvent, 500) != WAIT_OBJECT_0)  
     {  
       assert(0);  
       nvStatus = NV_ENC_ERR_GENERIC;  
     }  
   }  
 #endif  
   
   return nvStatus;  
 }  
   
 NVENCSTATUS EncodeThread::deinitialize(uint32_t devicetype)  
 {  
   NVENCSTATUS nvStatus = NV_ENC_SUCCESS;  
   
   releaseIOBuffers();  
   
   nvStatus = m_pNvHWEncoder->NvEncDestroyEncoder();  
   
   if (m_pDevice)  
   {  
     switch (devicetype)  
     {  
 #if defined(NV_WINDOWS)  
     case NV_ENC_DX9:  
       ((IDirect3DDevice9*)(m_pDevice))->Release();  
       break;  
   
     case NV_ENC_DX10:  
       ((ID3D10Device*)(m_pDevice))->Release();  
       break;  
   
     case NV_ENC_DX11:  
       ((ID3D11Device*)(m_pDevice))->Release();  
       break;  
 #endif  
   
     case NV_ENC_CUDA:  
       CUresult cuResult = CUDA_SUCCESS;  
       cuResult = cuCtxDestroy((CUcontext)m_pDevice);  
       if (cuResult != CUDA_SUCCESS)  
         PRINTERR("cuCtxDestroy error:0x%x\n", cuResult);  
     }  
   
     m_pDevice = NULL;  
   }  
   
 #if defined (NV_WINDOWS)  
   if (m_pD3D)  
   {  
     m_pD3D->Release();  
     m_pD3D = NULL;  
   }  
 #endif  
   
   return nvStatus;  
 }  
   

2016년 10월 12일 수요일

리눅스 ffmpeg CUDA 비디오 코덱 연동 빌드 - build ffmpeg with cuda video codec on linux

1. nvidia 드라이버, cuda 툴킷 설치 - /usr/local/cuda
2. cuda video codec 설치 - /home/ubuntu/work/Video_Codec_SDK_7.0.1
3. x264 설치(비교 테스트용) - /home/ubuntu/work/x264/build
4. ffmpeg 빌드(64비트)

./configure --prefix=./build/ --enable-shared --disable-static --enable-cuda --enable-nvenc --enable-nonfree --extra-cflags=-I/usr/local/cuda-8.0/include \
--extra-cflags=-I/home/ubuntu/work/Video_Codec_SDK_7.0.1/Samples/common/inc --arch=x86_6
4 --enable-libx264 --enable-gpl --extra-cflags=-I/home/ubuntu/work/x264/build/include --extra-ldflags=-L/home/ubuntu/work/x264/build/lib

2016년 1월 28일 목요일

ffmpeg 비디오 필터 사용 소스코드 - ffmpeg video filter sample source code

뮤텍스 소스

< VideoFilter.h >
 #ifndef __VIDEO_FILTER_H__  
 #define __VIDEO_FILTER_H__  
   
 extern "C" {  
 #include "libavfilter/avfiltergraph.h"  
 #include "libavfilter/buffersink.h"  
 #include "libavfilter/buffersrc.h"  
 }  
   
 #include "Mutex.h"  
   
 struct VideoFilterParam {  
      int width;  
      int height;  
      AVPixelFormat pix_fmt;  
      AVRational time_base;  
      AVRational sample_aspect_ratio;  
 };  
   
 class VideoFilter   
 {  
 public:  
      VideoFilter();  
      virtual ~VideoFilter();  
   
      int initFilter(struct VideoFilterParam &param, int vflip, int hflip, int rotate);  
      void freeFilter();  
   
      int processFilter(AVFrame *newFrame, AVFrame *frame);  
   
      int checkFilter(struct VideoFilterParam &param);  
   
 protected:  
      static void initFilter();  
   
 protected:  
      AVFilterGraph*          m_pFilterGraph;  
      AVFilterContext*     m_pBufferSinkCtx;  
      AVFilterContext*     m_pBufferSrcCtx;       
      AVFrame*               m_pFrame;  
   
      int                    m_nWidth;  
      int                    m_nHeight;  
      AVPixelFormat     m_nPixelFormat;  
      AVRational          m_timeBase;  
      AVRational          m_sampleAspectRatio;  
   
      static MUTEX     m_hMutex;  
      static bool          m_bInit;  
 };  
   
 #endif  
   

< VideoFilter.cpp >
 #include "VideoFilter.h"  
 #include "GlobalEnv.h"  
 #include "CommonType.h"  
   
 bool VideoFilter::m_bInit = false;  
 MUTEX VideoFilter::m_hMutex = PTHREAD_MUTEX_INITIALIZER;  
   
 VideoFilter::VideoFilter() : m_pFilterGraph(NULL), m_pBufferSrcCtx(NULL), m_pBufferSinkCtx(NULL), m_pFrame(NULL)  
 {  
      initFilter();  
      m_nWidth = m_nHeight = 0;  
      m_nPixelFormat = AV_PIX_FMT_NONE;  
      m_timeBase.den = m_timeBase.num = 0;  
      m_sampleAspectRatio.den = m_sampleAspectRatio.num = 0;  
 }  
   
 VideoFilter::~VideoFilter()  
 {  
      freeFilter();  
 }  
   
 void VideoFilter::initFilter()  
 {  
      MUTEX_LOCK(&m_hMutex);  
   
      if (!m_bInit) {  
           avfilter_register_all();  
           m_bInit = true;  
      }  
   
      MUTEX_UNLOCK(&m_hMutex);  
 }  
   
 int VideoFilter::initFilter(struct VideoFilterParam &param, int vflip, int hflip, int rotate)  
 {  
      freeFilter();  
   
      char args[128];  
   snprintf(args, sizeof(args),  
       "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",  
       param.width, param.height, param.pix_fmt,   
                param.time_base.num, param.time_base.den,   
       param.sample_aspect_ratio.num, param.sample_aspect_ratio.den);  
   
      m_pFrame = av_frame_alloc();  
      m_pFilterGraph = avfilter_graph_alloc();  
   
      char errbuf[128];  
      int err = avfilter_graph_create_filter(&m_pBufferSrcCtx, avfilter_get_by_name("buffer"), "buffer1", args, NULL, m_pFilterGraph);       
      if (err < 0) {  
           av_strerror(err, errbuf, sizeof(errbuf));  
           DXPRINTF("avfilter_graph_create_filter failed, err : %s\n", errbuf);  
           return -1;  
      }  
   
      err = avfilter_graph_create_filter(&m_pBufferSinkCtx, avfilter_get_by_name("buffersink"), "buffersink1", NULL, NULL, m_pFilterGraph);  
      if (err < 0) {  
           av_strerror(err, errbuf, sizeof(errbuf));  
           DXPRINTF("avfilter_graph_create_filter failed, err : %s\n", errbuf);  
           return -1;  
      }  
   
      AVFilterContext *vflipCtx = NULL;  
      AVFilterContext *hflipCtx = NULL;  
      AVFilterContext *rotateCtx = NULL;  
      AVFilterContext *prevCtx = m_pBufferSrcCtx;  
   
      if (vflip > 0) {  
           err = avfilter_graph_create_filter(&vflipCtx, avfilter_get_by_name("vflip"), "vflip1", NULL, NULL, m_pFilterGraph);  
           if (err < 0) {  
                av_strerror(err, errbuf, sizeof(errbuf));  
                DXPRINTF("avfilter_graph_create_filter failed, err : %s\n", errbuf);  
                return -1;  
           }  
           err = avfilter_link(prevCtx, 0, vflipCtx, 0);  
           if (err < 0) {  
                av_strerror(err, errbuf, sizeof(errbuf));  
                DXPRINTF("avfilter_link failed, err : %s\n", errbuf);  
                return -1;  
           }  
           prevCtx = vflipCtx;  
      }  
   
      if (hflip > 0) {  
           err = avfilter_graph_create_filter(&hflipCtx, avfilter_get_by_name("hflip"), "hflip1", NULL, NULL, m_pFilterGraph);  
           if (err < 0) {  
                av_strerror(err, errbuf, sizeof(errbuf));  
                DXPRINTF("avfilter_graph_create_filter failed, err : %s\n", errbuf);  
                return -1;  
           }  
           err = avfilter_link(prevCtx, 0, hflipCtx, 0);  
           if (err < 0) {  
                av_strerror(err, errbuf, sizeof(errbuf));  
                DXPRINTF("avfilter_link failed, err : %s\n", errbuf);  
                return -1;  
           }  
           prevCtx = hflipCtx;  
      }  
   
      if (rotate) {  
           snprintf(args, sizeof(args), "PI*2/360*%d", rotate);  
           err = avfilter_graph_create_filter(&rotateCtx, avfilter_get_by_name("rotate"), "rotate1", args, NULL, m_pFilterGraph);  
           if (err < 0) {  
                av_strerror(err, errbuf, sizeof(errbuf));  
                DXPRINTF("avfilter_graph_create_filter failed, err : %s\n", errbuf);  
                return -1;  
           }  
           err = avfilter_link(prevCtx, 0, rotateCtx, 0);  
           if (err < 0) {  
                av_strerror(err, errbuf, sizeof(errbuf));  
                DXPRINTF("avfilter_link failed, err : %s\n", errbuf);  
                return -1;  
           }  
           prevCtx = rotateCtx;  
      }  
   
      err = avfilter_link(prevCtx, 0, m_pBufferSinkCtx, 0);  
      if (err < 0) {  
           av_strerror(err, errbuf, sizeof(errbuf));  
           DXPRINTF("avfilter_link failed, err : %s\n", errbuf);  
           return -1;  
      }  
   
      err = avfilter_graph_config(m_pFilterGraph, NULL);  
      if (err < 0) {  
           av_strerror(err, errbuf, sizeof(errbuf));  
           DXPRINTF("avfilter_graph_config failed, err : %s\n", errbuf);  
           return -1;  
      }  
   
      m_nWidth = param.width;  
      m_nHeight = param.height;  
      m_nPixelFormat = param.pix_fmt;  
      m_timeBase.den = param.time_base.den;  
      m_timeBase.num = param.time_base.num;  
      m_sampleAspectRatio.den = param.sample_aspect_ratio.den;  
      m_sampleAspectRatio.num = param.sample_aspect_ratio.num;  
   
      return 0;  
 }  
   
 void VideoFilter::freeFilter()  
 {  
      avfilter_graph_free(&m_pFilterGraph);  
      av_frame_free(&m_pFrame);  
   
      m_nWidth = m_nHeight = 0;  
      m_nPixelFormat = AV_PIX_FMT_NONE;  
      m_timeBase.den = m_timeBase.num = 0;  
      m_sampleAspectRatio.den = m_sampleAspectRatio.num = 0;  
 }  
   
 AVFrame* copyFrame(AVFrame *frame)  
 {  
      AVFrame *new_frame = avcodec_alloc_frame();  
      if (new_frame) {  
           if (av_image_alloc(new_frame->data, new_frame->linesize,  
                frame->width, frame->height, (AVPixelFormat)frame->format, 1) > 0)   
           {  
                av_image_copy(new_frame->data, new_frame->linesize,  
                     (const uint8_t **)frame->data, frame->linesize, (AVPixelFormat)frame->format,  
                     frame->width, frame->height);  
   
                new_frame->width = frame->width;  
                new_frame->height = frame->height;  
                new_frame->pict_type = frame->pict_type;  
                new_frame->format = frame->format;  
   
                return new_frame;  
           }  
           else  
           {  
                av_free(new_frame->data[0]);  
                av_free(new_frame);  
           }  
      }  
   
      return NULL;  
 }  
   
 int VideoFilter::processFilter(AVFrame *newFrame, AVFrame *frame)  
 {  
      if (!m_pFilterGraph) return -1;  
   
      int ret = av_buffersrc_add_frame_flags(m_pBufferSrcCtx, frame, AV_BUFFERSRC_FLAG_KEEP_REF);  
      if (ret >= 0) {  
           while (1) {  
                ret = av_buffersink_get_frame(m_pBufferSinkCtx, m_pFrame);  
                if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break;  
                if (ret < 0) break;  
        
                newFrame = copyFrame(m_pFrame);  
                av_frame_unref(m_pFrame);  
           }  
      }  
      return 0;  
 }  
   
 int VideoFilter::checkFilter(struct VideoFilterParam &param)  
 {  
      if (m_nWidth != param.width || m_nHeight != param.height ||   
           m_nPixelFormat != param.pix_fmt ||  
           m_timeBase.den != param.time_base.den || m_timeBase.num != param.time_base.num ||  
           m_sampleAspectRatio.den != param.sample_aspect_ratio.den ||   
           m_sampleAspectRatio.num != param.sample_aspect_ratio.num)   
      {  
           return -1;  
      }  
   
      return 0;  
 }  
   

< VideoFilter 사용 >

AVCodecContext *pCodecCtx;
...
struct VideoFilterParam param;
param.width = pCodecCtx->width;
param.height = pCodecCtx->height;
param.pix_fmt = pCodecCtx->pix_fmt;
param.time_base.den = pCodecCtx->time_base.den;
param.time_base.num = pCodecCtx->time_base.num;
param.sample_aspect_ratio.den = pCodecCtx->sample_aspect_ratio.den;
param.sample_aspect_ratio.num = pCodecCtx->sample_aspect_ratio.num;
...
VideoFilter *filter = new VideoFilter();
...
filter->initFilter(param, 1, 1, 30);    // 상하반전, 좌우반전, 30도 회전
...
if (filter->checkFilter(param) < 0) {
    filter->freeFilter();
 
    param.width = pCodecCtx->width;
    param.height = pCodecCtx->height;
    param.pix_fmt = pCodecCtx->pix_fmt;
    param.time_base.den = pCodecCtx->time_base.den;
    param.time_base.num = pCodecCtx->time_base.num;
    param.sample_aspect_ratio.den = pCodecCtx->sample_aspect_ratio.den;
    param.sample_aspect_ratio.num = pCodecCtx->sample_aspect_ratio.num;
}  
filter->processFilter(newFrame, frame);   // newFrame은 처리결과, frame은 디코딩된 프레임
...
filter->freeFilter();

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

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