顯示具有 codec 標籤的文章。 顯示所有文章
顯示具有 codec 標籤的文章。 顯示所有文章

2021年7月14日 星期三

Build x264 by Using Visual Studio

    x264 is a wirely-use H264 encoder for its profound performance, thus to study how it works is an interesting issue. However, its sourcecode build is bash-shell  + gcc in default. It leads to trace the code is not as simple as in an full integrated IDE. For this case, this post wants to instruct how to build x264 by Visual Studio + Microsoft Visual C. 

I use Visual Studio 2015, and the X264_POINTVER= "0.164.x" (2021/6/13 release). 

零. Build and run x264 in the MinGW system (skippable)

     MinGW could be download from here.

     Download and decompress the x264 tar ball, and we configure x264 as:

$ ./configure  --disable-asm --disable-thread --bit-depth=8 --disable-opencl
    ※For study of x264 purpose, we disable asm, thread opengl, and leave bit-depth works for 8 bit only. It brings x264 workflow simpler.

    After make, we test x264 by below command and use VLC player to verify the output.    
$ x264 --input-res 704x480 --bitrate 200 --output out.h264 plush-704x480.yuv
yuv [info]: 704x480p 0:0 @ 25/1 fps (cfr)
:

※ You could download the test yuv420 file from here.

壹. Build x264 by Visual Studio

  甲. Copy  those files into the same folder.
common folder: 
cabac.c -> common_cabac.c
macroblock.c -> common_macroblock.c
set.c -> common_set.c

encoder folder:
cabac.c -> encoder_cabac.c
macroblock.c -> encoder_macroblock.c
set.c -> encoder_set.c

input folder :
raw.c -> input_raw.c

output folder:
raw.c -> output_raw.c

  乙. Create an empty VS solution & project.
  The project file I assume you place at x264 source folder root,  named x264. we add those source file into the project :
common\base.c
common\bitstream.c
common\common.c
common\common_cabac.c
common\common_macroblock.c
common\common_set.c
common\cpu.c
common\dct.c
common\deblock.c
common\frame.c
common\mc.c
common\mvpred.c
common\osdep.c
common\pixel.c
common\predict.c
common\quant.c
common\rectangle.c
common\tables.c
common\vlc.c

encoder\analyse.c
encoder\api.c
encoder\cavlc.c
encoder\encoder.c
encoder\encoder_cabac.c
encoder\encoder_macroblock.c
encoder\encoder_set.c
encoder\lookahead.c
encoder\me.c
encoder\ratecontrol.c
encoder\slicetype-cl.c

filters\filters.c
filters\video\cache.c
filters\video\crop.c
filters\video\depth.c
filters\video\fix_vfr_pts.c
filters\video\internal.c
filters\video\resize.c
filters\video\select_every.c
filters\video\source.c
filters\video\video.c

input\avs.c
input\input.c
input\input_raw.c
input\timecode.c
input\y4m.c

output\flv.c
output\flv_bytestream.c
output\matroska.c
output\matroska_ebml.c
output\output_raw.c

extras\getopt.c

autocomplete.c
x264.c

If you do not build x264 in MinGW, you need to create a file, config.h in the x264 root, which file content is as below :
#define ARCH_X86 1
#define SYS_WINDOWS 1
#define STACK_ALIGNMENT 64
#define HAVE_LOG2F 1
#define HAVE_AVS 1
#define USE_AVXSYNTH 0
#define HAVE_VECTOREXT 1
#define fseek fseeko64
#define ftell ftello64
#define HAVE_BITDEPTH8 1
#define HAVE_GPL 1
#define HAVE_INTERLACED 1
#define HAVE_MALLOC_H 0
#define HAVE_ALTIVEC 0
#define HAVE_ALTIVEC_H 0
#define HAVE_MMX 0
#define HAVE_ARMV6 0
#define HAVE_ARMV6T2 0
#define HAVE_NEON 0
#define HAVE_AARCH64 0
#define HAVE_BEOSTHREAD 0
#define HAVE_POSIXTHREAD 0
#define HAVE_WIN32THREAD 0
#define HAVE_THREAD 0
#define HAVE_SWSCALE 0
#define HAVE_LAVF 0
#define HAVE_FFMS 0
#define HAVE_GPAC 0
#define HAVE_CPU_COUNT 0
#define HAVE_OPENCL 0
#define HAVE_THP 0
#define HAVE_LSMASH 0
#define HAVE_X86_INLINE_ASM 0
#define HAVE_AS_FUNC 0
#define HAVE_INTEL_DISPATCHER 0
#define HAVE_MSA 0
#define HAVE_MMAP 0
#define HAVE_WINRT 0
#define HAVE_VSX 0
#define HAVE_ARM_INLINE_ASM 0
#define HAVE_STRTOK_R 0
#define HAVE_CLOCK_GETTIME 0
#define HAVE_BITDEPTH10 0

  丙. Change the setting of  the VS project :
Main menu ->project -> x264 properies -> C/C++ -> General -> Add include directorie :
.
common
encoder
input
output
filters
filters/video
extras

Main menu ->project -> x264 properies -> C/C++ -> Preprocessor-> Preprocessor Definitions:
HAVE_STRING_H=1
HIGH_BIT_DEPTH=0
BIT_DEPTH=8
fseeko64=_fseeki64
ftello64=_ftelli64

Main menu ->project -> x264 properies -> C/C++ -> Advanced-> Disable Specific Warnings :
4996

  丁. Modify those code to pass the compilation:
common\osdep.h, aboult line 340, avoid MS VC defines REALIGN_STACK:
#define ALIGNED_ARRAY_32 ALIGNED_ARRAY_16
#define ALIGNED_ARRAY_64 ALIGNED_ARRAY_16
#endif

#if (STACK_ALIGNMENT > 16 || (ARCH_X86 && STACK_ALIGNMENT > 4) ) && defined(__GNUC__)
#define REALIGN_STACK __attribute__((force_align_arg_pointer))
#else
#define REALIGN_STACK
#endif

encoder\api.c, about line 97, comment out the "if else" :
        api->x264 = x264_8_encoder_open( param, api );
    }
#if(0)
    else if( HAVE_BITDEPTH10 && param->i_bitdepth == 10 )
    {
        api->nal_encode = x264_10_nal_encode;
        api->encoder_reconfig = x264_10_encoder_reconfig;
        api->encoder_parameters = x264_10_encoder_parameters;
        api->encoder_headers = x264_10_encoder_headers;
        api->encoder_encode = x264_10_encoder_encode;
        api->encoder_close = x264_10_encoder_close;
        api->encoder_delayed_frames = x264_10_encoder_delayed_frames;
        api->encoder_maximum_delayed_frames = x264_10_encoder_maximum_delayed_frames;
        api->encoder_intra_refresh = x264_10_encoder_intra_refresh;
        api->encoder_invalidate_reference = x264_10_encoder_invalidate_reference;

        api->x264 = x264_10_encoder_open( param, api );

    }
#endif
    else
        x264_log_internal( X264_LOG_ERROR, "not compiled with %d bit depth support\n", param->i_bitdepth );

To here, the VS is able to build x264.

參. Run x264 on Visual Studio :
Add the command line arguments, it is in 
Main menu ->project -> x264 properies ->Debugging->Command Arguments :
--input-res 704x480   --output out.h264 plush-704x480.yuv --bitrate 200

The arguments are indentical with what we run in MinGW command line.


Now press the VS "play" button, everything should be fine. If you are in the debug mode, do not be surprised at the encoding is very slow:




2020年6月14日 星期日

Use Intel® Quick Sync Video (QSV)/Media SDK H264 Encoder for Video Streaming

 
    
※ The reference code you could get from here.

    Intel provides Intel® Quick Sync Video(QSV) to deal with the video processing : like encoding, decoding, resize..etc. The QSV libraries are contained in Intel® Media SDK.
In the most cases, the users are interested  in H264 encoding or trancoding when they are using Intel QSV, of course. But the example code from the tutorial package does not work in streaming.

    The root cause is the H264 NAL(Network Abstract Layer) outputted from the media SDK lacking of SPS(Sequence Parameter Set) and PPS(Picture Parameter Set) information. By default, the media SDK would not contain those information into the H264 Nal. However, in the RSTP standard, those information are required. Thus, this post wants to fill the gap : make the Intel® Media SDK able to be used in the streaming cases.

   This post continues my previous one, A RTSP Server Based on Qt Framework and LIVE555,  the x264 encoder here would be replaced as the Intel® Media SDK's.

  零. Implement the QSV H264Encoder class, based on the tutorial simple_3_encode :

   This class we named IntelHDGraphicsH264Encoder, a subclass of H264Encoder (to unify the interfaces) :
class IntelHDGraphicsH264Encoder : public H264Encoder
{
public:
 static bool IsHardwareSupport(QSize resolution);

public:
 IntelHDGraphicsH264Encoder(void);
 ~IntelHDGraphicsH264Encoder(void) Q_DECL_OVERRIDE;

public :
 int Init(int width, int height) Q_DECL_OVERRIDE;
 void Close(void) Q_DECL_OVERRIDE;

 QQueue<int> Encode(unsigned char *p_frame_data, 
  QQueue<QByteArray> &ref_queue) Q_DECL_OVERRIDE;
private:
 mfxStatus ExtendMfxBitstream(mfxU32 new_size);

private:
 int m_width, m_height;
 MFXVideoSession m_session;
 MFXVideoENCODE *m_p_enc;
 mfxU8 *m_p_surface_buffers;
 mfxFrameSurface1 **m_pp_encoding_surfaces;
 mfxU16 m_num_surfaces;
 mfxBitstream m_mfx_bitsream;

private :
 QMutex m_mutex;
};

     There is a class static function IsHardwareSupport to check if there is hardware supporting with Intel QSV, and if the resolution is encodable or not. (QSV supports with the width being a multiply of 16, and maximum resolution is 1920x1200) 


The class definitions are straight forward, we leave out.  But there are two things we should take notice : one is, the QSV encoder input must be NV12; the other is : while the buffer is not enough, it should be resized by the function ExtendMfxBitstream (about line 378):
  :
  else if (MFX_ERR_NOT_ENOUGH_BUFFER == sts)
  {
   mfxVideoParam par;

   memset(&par, 0, sizeof(par));
   sts = m_p_enc->GetVideoParam(&par);

   //printf("require %d KB\r\n", par.mfx.BufferSizeInKB);
   ExtendMfxBitstream( par.mfx.BufferSizeInKB * 1024);

   break;
  } else
  :


Below it is the integration of IntelHDGraphicsH264Encoder in H264NalFactory.cpp about line 51 :
 :
 m_nal_queue.clear();

#if(1)
 if( true == IntelHDGraphicsH264Encoder::IsHardwareSupport(resolution))
 {
  m_p_h264_encoder = new IntelHDGraphicsH264Encoder();
  qDebug() << "Encoder :: Intel QSV";
 }
 else
#endif
 {
  m_p_h264_encoder = new X264Encoder();
  qDebug() << "Encoder :: X264";
 }
 :


Of course, we need to add the dependency library in the Qt project file :
:
INTEL_MEDIA_SDK_PATH =  $$PWD/../libs/"Intel(R) Media SDK 2019 R1"

INCLUDEPATH += $$INTEL_MEDIA_SDK_PATH/include
LIBS += $$INTEL_MEDIA_SDK_PATH/lib/x64/libmfx_vs2015.lib

LIBS += Advapi32.lib
:

And now the encoder works : if we save the output NAL into a file,  ffplay or VLCPlayer could play it.

However, the encoder does not work while we use it in streaming:


ffplay hanging, it would not pop-up a windows to play the streaming.



二. Add the SPS and PPS packets in the streaming.

Refer to here and this example code,  we change the encoder code as :

IntelHDGraphicsH264Encoder.h

 :
 mfxBitstream m_mfx_bitsream;

#if !defined(_NO_SPSPPS)
 mfxExtCodingOptionSPSPPS m_spspps_coding_option;
 mfxU8 m_sps_buffer[128];
 mfxU8 m_pps_buffer[128];
#endif
 :


IntelHDGraphicsH264Encoder.cpp, 

Init function, about line 234:

 :
 sts = m_p_enc->Init(&params_in);
 if (MFX_ERR_NONE != sts)
 {
  printf("MFXVideoENCODE.Init failed, %d\r\n", sts);
  return -4;
 }

#if !defined(_NO_SPSPPS)
 memset(&m_spspps_coding_option, 0, sizeof(mfxExtCodingOptionSPSPPS));

 m_spspps_coding_option.Header.BufferId = MFX_EXTBUFF_CODING_OPTION_SPSPPS;
 m_spspps_coding_option.Header.BufferSz = sizeof(mfxExtCodingOptionSPSPPS);

 m_spspps_coding_option.SPSBuffer = &m_sps_buffer[0];
 m_spspps_coding_option.SPSBufSize = sizeof(m_sps_buffer);
 m_spspps_coding_option.PPSBuffer = &m_pps_buffer[0];
 m_spspps_coding_option.PPSBufSize = sizeof(m_pps_buffer);

 mfxExtBuffer* extendedBuffers[1];
 extendedBuffers[0] = (mfxExtBuffer*) & m_spspps_coding_option;
#endif

 mfxVideoParam video_param;
 memset(&video_param, 0, sizeof(video_param));

#if !defined(_NO_SPSPPS)
 video_param.ExtParam = &extendedBuffers[0];
 video_param.NumExtParam = 1;
#endif

 sts = m_p_enc->GetVideoParam(&video_param);
 :


Encode function, about line 414 :

 :
 array = QByteArray((char*)m_mfx_bitsream.Data + m_mfx_bitsream.DataOffset,
        m_mfx_bitsream.DataLength);

#if !defined(_NO_SPSPPS)
 if( MFX_FRAMETYPE_IDR & m_mfx_bitsream.FrameType)
 {
  //printf("MFX_FRAMETYPE_IDR\r\n");
  ref_queue.enqueue(QByteArray((char*)m_spspps_coding_option.SPSBuffer,
          m_spspps_coding_option.SPSBufSize));
  h264_nal_size_queue.enqueue( m_spspps_coding_option.SPSBufSize);
  ref_queue.enqueue(QByteArray((char*)m_spspps_coding_option.PPSBuffer,
          m_spspps_coding_option.PPSBufSize));
  h264_nal_size_queue.enqueue( m_spspps_coding_option.PPSBufSize);
 }
#endif

 ref_queue.enqueue(array);
 :



And Now the streaming works.





2016年2月22日 星期一

Exploit FFmpeg Libraries to Decode Raw H264 File in Windows, Which Supports Multithread-Decoding



My previous article has demonstrate how to build to ffmpeg libraries in windows. In here, I continue the work, to use the built libraries for decoding a raw h264 file.

I use ffmpeg version 2.4.12 in here.

零.

Provision a raw h264 file


To make a raw h264 video, the zeroth step, is to own a h264 video with container.

This is a website you could download 720p game videos.

for me, I use  World of Warcraft: Warlords of Draenor Cinematic.


This video is h264 format indeed.

  After video has been download, move the mp4 file to  the folder containing ffmpeg executable binary, and  type the command line:


Gaiger@i5-4570 ~/ffmpeg/2.4.12/built/bin
$ ./ffmpeg.exe -i World\ of\ Warcraft_Warlords_of_Draenor_Cinematic_Trailer.mp4
 -vcodec copy -bsf h264_mp4toannexb -an -f h264 wow6.h264



The bold font words be the input/output file name, you could change them.

After the converting done wothou any error, you could use ffplay (which I do not build in previous article, but you could download it from here) to verify if the raw 264 file works or not.


fflpay.exe wow6.h264




Of course, if you would like to use others video as test video ( like porn video for excited :-X), it works always.

一.
 Prepare dependent libraries and headers.


  Create a  Visual Studio  new project name ffmpegh264decode , and Visual studio would create this folder automatically.

Copy the built ffmpeg libraries with header which has been built from previous article.
Copy the raw h264 file to it.
Copy YourMinGWPath\msys\1.0\lib\libmingwex.a file to this folder.
Copy YourMinGWPath\msys\1.0\lib\libiconv.a file to this folder.
Copy YourMinGWPath\msys\1.0\lib\libz.a file to it.
 Copy  YourMinGWPath\msys\1.0\lib\gcc\YourMinGWBitNumber\GCCVersion\libgcc.a to this folder

Download the inttypes.h file from  here and put it in  this folder.
Download the stdint.h file from  here  and put it in  this folder.
Download the win32thread.h and win32thread.c and put them in this folder.




The main.c be empty main function currently.



二.

 Set path and libraries in Visual Studio project.


 Add include path build/include and . in VS project:



Add library path build/lib and .  in VS :




Add dependency libraries,
libavcodec.a libavutil.a libavformat.a libavdevice.a libswscale.a libswresample.a
libgcc.a libmingwex.a libz.a  libiconv.a in VS:

(the bold ones are not necessary/included in older ffmpeg version.)




Add win32thread.c in the compilation source list:



三.

My code:


/*
 ffmpeg api change log:

 https://github.com/FFmpeg/FFmpeg/blob/master/doc/APIchanges#L699

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if defined(_MSC_VER) && !defined(__cplusplus)
#pragma warning( error : 4013 )
#define inline     
#endif

#ifdef __cplusplus
extern "C"{
#endif

#define __STDC_CONSTANT_MACROS
#ifdef _STDINT_H
#undef _STDINT_H
#endif

#include "stdint.h"

#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"

#ifdef _WIN32
 #include "win32thread.h" 
#else
 #include <pthread.h>
#endif

#ifdef __cplusplus
}
#endif

static int LockManagerCallback(void **ppMutex, enum AVLockOp op)
{
 switch(op) 
 {
 case AV_LOCK_CREATE:
  *ppMutex = (pthread_mutex_t *)av_malloc(sizeof(pthread_mutex_t));
  pthread_mutex_init((pthread_mutex_t *)(*ppMutex), NULL);
 break;

 case AV_LOCK_OBTAIN:
  pthread_mutex_lock((pthread_mutex_t *)(*ppMutex));
 break;
 
 case AV_LOCK_RELEASE:
  pthread_mutex_unlock((pthread_mutex_t *)(*ppMutex));
 break;
 
 case AV_LOCK_DESTROY:
  pthread_mutex_destroy((pthread_mutex_t *)(*ppMutex));
  av_free(*ppMutex);
 break;
 }/*switch*/

 return 0;
}/*LockManagerCallback*/


void InitOnceMeterials(void)
{
#ifdef _WIN32
 win32_threading_init();
#endif

#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 0, 100)
 /* must be called before using avcodec lib */
 avcodec_init();
#endif

 /* register all the codecs */
    avcodec_register_all();          

 av_lockmgr_register(LockManagerCallback);

 return;
}/*InitOnceMeterials*/


typedef struct 
{
 pthread_mutex_t mutex;

 AVCodec *pCodec;
 AVCodecParserContext *pParserCtx;
 AVCodecContext *pCtx;
 AVPacket pkt;
 AVFrame *pFrameYUV, *pFrameRGB;
 struct SwsContext *pSwsCtx;   
 unsigned char *pOutputBuffer;
 
}FFMPEGDecoder;


int CloseFFmpegH264Decoder(void *pDecoder)
{
 FFMPEGDecoder *pFFMPEGDecoder;

 if(NULL == pDecoder)
  return 1;

 pFFMPEGDecoder = (FFMPEGDecoder*)pDecoder;

 pFFMPEGDecoder->pOutputBuffer = NULL;

 if(NULL != pFFMPEGDecoder->pCtx)
 {
  if(NULL != pFFMPEGDecoder->pCtx->codec)
   avcodec_close(pFFMPEGDecoder->pCtx);

#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,22, 0)
  av_free(pFFMPEGDecoder->pCtx);
#else
  avcodec_free_context(&pFFMPEGDecoder->pCtx);
#endif
  pFFMPEGDecoder->pCtx = NULL;
 }/*if NULL != c*/

 if(NULL != pFFMPEGDecoder->pParserCtx)
  av_parser_close(pFFMPEGDecoder->pParserCtx);
 pFFMPEGDecoder->pParserCtx = NULL;

 av_free_packet(&pFFMPEGDecoder->pkt);

 if(NULL != pFFMPEGDecoder->pFrameYUV)
 {
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
  av_free(pFFMPEGDecoder->pFrameYUV);
  pFFMPEGDecoder->pFrameYUV = NULL;
#else
  av_frame_free(&pFFMPEGDecoder->pFrameYUV);
#endif
  
 }/*if NULL != pFrameYUV*/

 if(NULL != pFFMPEGDecoder->pFrameRGB)
 {
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
  av_free(pFFMPEGDecoder->pFrameRGB);
  pFFMPEGDecoder->pFrameRGB = NULL;
#else
  av_frame_free(&pFFMPEGDecoder->pFrameYUV);
#endif  
 }/*if NULL != pFrameRGB*/
 
 if(NULL != pFFMPEGDecoder->pSwsCtx)
 {
  sws_freeContext(pFFMPEGDecoder->pSwsCtx);
  pFFMPEGDecoder->pSwsCtx = NULL;
 }/*if NULL == ctx*/

 pthread_mutex_destroy(&pFFMPEGDecoder->mutex);

 av_free(pFFMPEGDecoder);
 pFFMPEGDecoder = NULL;

 return 0;
}/*FFMPEG_H264_Decode_Close*/


void *InitFFMpegH264Decoder(void)
{
 FFMPEGDecoder *pDecoder; 
  
 pDecoder = (FFMPEGDecoder*)av_malloc(1*sizeof(FFMPEGDecoder));
 if(NULL == pDecoder)
  return NULL;

 memset(pDecoder, 0, sizeof(FFMPEGDecoder));
 
 pDecoder->pCodec = avcodec_find_decoder(CODEC_ID_H264);
 pDecoder->pCtx = avcodec_alloc_context3(pDecoder->pCodec); 
 pDecoder->pParserCtx = av_parser_init(pDecoder->pCtx->codec_id);

 av_init_packet(&pDecoder->pkt);

 pDecoder->pSwsCtx = NULL;

#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
 pDecoder->pFrameRGB = avcodec_alloc_frame(); 
 pDecoder->pFrameYUV = avcodec_alloc_frame();   
#else
 pDecoder->pFrameRGB = av_frame_alloc(); 
 pDecoder->pFrameYUV = av_frame_alloc();  
#endif 
 pDecoder->pOutputBuffer = NULL;
 
 if(NULL == pDecoder->pCodec || NULL == pDecoder->pCtx
  || NULL == pDecoder->pFrameRGB 
  || NULL == pDecoder->pFrameYUV)
 {
  CloseFFmpegH264Decoder(pDecoder);
  return NULL;
 }/*init fail*/


 /* we do not send complete frames */
 if(pDecoder->pCodec->capabilities & CODEC_CAP_TRUNCATED)
  pDecoder->pCtx->flags |= CODEC_FLAG_TRUNCATED;  
 
 if( 0 > avcodec_open2(pDecoder->pCtx, pDecoder->pCodec, NULL))
 {
  CloseFFmpegH264Decoder(pDecoder);
  return NULL;
 }/*if 0 > sts*/
 

 pthread_mutex_init(&pDecoder->mutex, NULL);

 return (void*)pDecoder;
 
}/*InitFFMpegDecoder*/


int FFmpegH264Decode(void *pDecoder, unsigned char *pH264,  unsigned int h264Size,  
 unsigned char *pRGB, int *pWidth, int *pHeight)
{
 
 FFMPEGDecoder *pFFMPEGDecoder; 
 int consumeSize;
 BOOL gotPicture;
 AVPacket *pPacket;

 if(NULL == pDecoder)
  return -1;

 consumeSize = 0;
 pFFMPEGDecoder =(FFMPEGDecoder*)pDecoder;

 pPacket = &pFFMPEGDecoder->pkt; 
        
 av_parser_parse2(pFFMPEGDecoder->pParserCtx, pFFMPEGDecoder->pCtx,
  &pPacket->data, &pPacket->size, pH264, h264Size, 
  pPacket->pts, pPacket->dts, AV_NOPTS_VALUE);

 consumeSize = avcodec_decode_video2(pFFMPEGDecoder->pCtx, pFFMPEGDecoder->pFrameYUV, 
  &gotPicture, &pFFMPEGDecoder->pkt);

 if(0 == gotPicture)
  return -2;

 *pWidth = pFFMPEGDecoder->pFrameYUV->width;
 *pHeight = pFFMPEGDecoder->pFrameYUV->height;

 /*only for color converting, it doese not change the image resolution*/
 if(NULL == pFFMPEGDecoder->pSwsCtx)
 {
  sws_freeContext(pFFMPEGDecoder->pSwsCtx);

  pFFMPEGDecoder->pSwsCtx = sws_getContext(
   *pWidth, *pHeight, PIX_FMT_YUV420P, 
   *pWidth, *pHeight, PIX_FMT_BGR24, 
   SWS_FAST_BILINEAR, NULL, NULL, NULL);
 }/*if NULL ==  pFFMPEGDecoder->pSwsCtx*/
 

 if(pRGB != pFFMPEGDecoder->pOutputBuffer)
 {   
  pFFMPEGDecoder->pOutputBuffer = pRGB;
  avpicture_fill( (AVPicture *)(pFFMPEGDecoder->pFrameRGB), 
   (unsigned char*)pRGB, PIX_FMT_BGR24, 
   pFFMPEGDecoder->pCtx->width, pFFMPEGDecoder->pCtx->height);    
 }/*if pFrameBuffer != pFFMPEGDecoder->pFrameBuffer*/

 sws_scale( pFFMPEGDecoder->pSwsCtx, pFFMPEGDecoder->pFrameYUV->data, 
    pFFMPEGDecoder->pFrameYUV->linesize, 0, pFFMPEGDecoder->pCtx->height, 
    pFFMPEGDecoder->pFrameRGB->data, pFFMPEGDecoder->pFrameRGB->linesize);  

 return consumeSize;
}/*FFmpegH264Decode*/


#if defined(_MSC_VER) 
#pragma warning( disable : 4996 )    
#endif 

#define FOUR       (4)
#define ALIGN_TO_FOUR(VAL)    (((VAL) + FOUR - 1) & ~(FOUR - 1) )

int BMPwriter(unsigned char *pRGB, int bitNum, int width, int height, char *pFileName)
{
 FILE *fp; 
 int fileSize;
 unsigned char *pMovRGB;
 int i;
 int widthStep;
 
 unsigned char header[54] = {
  0x42,        // identity : B
  0x4d,        // identity : M
  0, 0, 0, 0,  // file size
  0, 0,        // reserved1
  0, 0,        // reserved2
  54, 0, 0, 0, // RGB data offset
  40, 0, 0, 0, // struct BITMAPINFOHEADER size
  0, 0, 0, 0,  // bmp width
  0, 0, 0, 0,  // bmp height
  1, 0,        // planes
  24, 0,       // bit per pixel
  0, 0, 0, 0,  // compression
  0, 0, 0, 0,  // data size
  0, 0, 0, 0,  // h resolution
  0, 0, 0, 0,  // v resolution 
  0, 0, 0, 0,  // used colors
  0, 0, 0, 0   // important colors
 };
 
 widthStep = ALIGN_TO_FOUR(width*bitNum/8);
 
 fileSize = ALIGN_TO_FOUR(widthStep*height) + sizeof(header);
 
 memcpy(&header[2], &fileSize, sizeof(int));
 memcpy(&header[18], &width, sizeof(int));
 memcpy(&header[22], &height, sizeof(int));
 memcpy(&header[28], &bitNum, sizeof(short)); 
 
 
 printf("written on file %s ...", pFileName);  
 fp = fopen(pFileName, "wb");
  
 fwrite(&header[0], 1, sizeof(header), fp);  
  
 pMovRGB  = pRGB + (height - 1)*widthStep; 
 
 for(i = 0; i < height; i++){
  fwrite(pMovRGB, 1, widthStep, fp);
  pMovRGB -= widthStep;
 }/*for i*/
 
 fclose(fp); 
 printf("done\n"); 
  
 return 0; 
}/*BMPwriter*/


int main(int agrc, char *argv[])
{
 int h264Size;
 unsigned char *pH264;
 void *pH264Decoder;
 char fileName[256];
 FILE *fp;

 sprintf(&fileName[0], "wow6.h264");

 if(agrc > 1) 
  strncpy(&fileName[0], argv[1], 256);
 
 fp = fopen(&fileName[0],"rb");

 if(NULL == fp)
 {
  printf("file %s is not existed\n", &fileName[0]);
  return -1;
 }/*if NULL == fp*/

 {
  fseek(fp, 0L, SEEK_END);
  h264Size = ftell(fp);
  fseek(fp, 0L, SEEK_SET);
 }/*get file size*/

 if(0 == h264Size)
 {
  printf("file %s is empty\n", &fileName[0]);
  return -2;
 }/*if 0 == h264Size*/
 
 pH264 = (unsigned char*)malloc(h264Size);
 fread(pH264, 1, h264Size, fp);
 fclose(fp); fp = NULL;


 InitOnceMeterials();

 pH264Decoder = InitFFMpegH264Decoder();

 if(NULL == pH264Decoder)
 {
  printf("initialize decoder error\n");
  return -3;
 }/*if 0 == h264Size*/

 
 {
  int i;
  int remainSize, consumeRize;
  int width, height;
  unsigned char *pRGB, *pMovH264;  
 
  pRGB = (unsigned char*)malloc(8192 * 4320 * 4); /*8k resolution , RGBA*/
  pMovH264 = pH264;

  remainSize = h264Size;

  i = 0;
  while(0 < remainSize )
  {  
   consumeRize = FFmpegH264Decode(pH264Decoder, pMovH264, remainSize, 
    pRGB, &width, &height);

   if(0 > consumeRize)
    break;
   //printf("frame size = %d Bytes\n", consumeRize);
   remainSize -= consumeRize;
   pMovH264 += consumeRize;
   
   if(0 == i%300)
   {
    char fileOutName[128];
    sprintf(&fileOutName[0], "%d.bmp", i);
    BMPwriter(pRGB, 24, width, height,  &fileOutName[0]);
   }/*save bmp*/

   i++;
  }/*while */

  free(pRGB); pRGB = NULL;
 }/*local variable*/

 CloseFFmpegH264Decoder(pH264Decoder);
 pH264Decoder = NULL; 
 free(pH264); pH264 = NULL;
 
 return 0;
}/*main*/



四.

 After your press the play button on the visual studio, this movie would be decoded and saved BMP files. (My code would save one BMP file per 300 frames.)

   600.bmp :




 2700.bmp:




 Note : my unit test does not demonstrate the multithread decoding, but it support this function, actually. (of cours, you should call InitFFMpegH264Decoder more than once to create multi-docoder handle.)

Reference:

http://stackoverflow.com/questions/10380045/is-there-any-easy-way-to-extract-h-264-raw-stream-in-annexb-format