ffmpeg 解码h264

VC6+FFmpeg-full-SDK-3.2:

 

1:编码:

    关于编码,x264就可以了(当然有空的话,会继续写一点关于ffmpeg编码的东西);

  

 

2:解码:

     解码主要参考了apiexample.c,下面我列出一个函数将解码后的AVFrame转为bmp;

 

 int AVFrame_create_bmp(AVFrame *pAVFrame,int width,int height,int bpp = 24)
 {

  //{
   struct SwsContext *img_convert_ctx;
   AVFrame         *pFrameRGB;
   pFrameRGB=avcodec_alloc_frame();
   if(pFrameRGB==NULL)return 0 ;
   int numBytes = avpicture_get_size(PIX_FMT_RGB24, m_pCodecCtx->width,  m_pCodecCtx->height);
   uint8_t * buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
   
   avpicture_fill((AVPicture *)pFrameRGB, buffer, /*PIX_FMT_RGB24*/PIX_FMT_BGR24,m_pCodecCtx->width, m_pCodecCtx->height);
   
   img_convert_ctx = sws_getContext( 
    m_pCodecCtx->width, 
    m_pCodecCtx->height,
    m_pCodecCtx->pix_fmt,
    m_pCodecCtx->width, 
    m_pCodecCtx->height,
    /*PIX_FMT_RGB24*/PIX_FMT_BGR24,//PIX_FMT_YUV420P,
    SWS_BICUBIC, NULL, NULL, NULL);
   
   sws_scale (img_convert_ctx, pAVFrame->data, pAVFrame->linesize,    
    0, m_pCodecCtx->height,
    ((AVPicture *)pFrameRGB)->data, ((AVPicture *)pFrameRGB)->linesize );
   
   sws_freeContext(img_convert_ctx);

   av_free(buffer); 
  //}
 
   DWORD   w =    m_pCodecCtx->width;    
   DWORD   h =    m_pCodecCtx->height;   
   DWORD   BufferLen = WIDTHBYTES(w*24)*h; //当然,如果仔细考虑,还要考利位图字节对齐;
   BYTE *  pBuffer = new BYTE[BufferLen]; memset(pBuffer,0,BufferLen);

   for(int i =0; i<height; i++)
   {
    //将图像转为bmp存到内存中,这里的图像是倒立的;
    memcpy(pBuffer +(WIDTHBYTES(w*24)*i),pFrameRGB->data[0]+i*pFrameRGB->linesize[0],width*3);
   }  
   
   LPBYTE pbmp = new BYTE[sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+BufferLen]; 
   
   BITMAPFILEHEADER bitmapfileheader; memset( &bitmapfileheader, 0, sizeof( BITMAPFILEHEADER ) );     
   bitmapfileheader.bfType = 'MB';    
   bitmapfileheader.bfSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+BufferLen ;   
   bitmapfileheader.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);    
   memcpy(pbmp,&bitmapfileheader,sizeof(BITMAPFILEHEADER));    

   BITMAPINFOHEADER fmtFrame; memset(&fmtFrame, 0, sizeof(fmtFrame));     
   fmtFrame.biSize = sizeof(fmtFrame);  
   fmtFrame.biPlanes  = 1;  
   fmtFrame.biBitCount = 24;  
   fmtFrame.biWidth =   w;   
   fmtFrame.biHeight =  -h;//注意,这里的bmpinfo.bmiHeader.biHeight变量的正负决定bmp文件的存储方式,如果为负值,表示像素是倒过来的*/
   fmtFrame.biSizeImage = BufferLen;  
   memcpy(pbmp+sizeof(BITMAPFILEHEADER),&fmtFrame,sizeof(BITMAPINFOHEADER));   
   memcpy(pbmp+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER),pBuffer, BufferLen);  
   
   FILE * f = fopen("frame.bmp","w+b");
   fwrite(pbmp,1,sizeof(BITMAPFILEHEADER)+sizeof(fmtFrame)+BufferLen, f );  
   fclose(f) ; 
   
   delete [] pbmp; pbmp = NULL;
   delete [] pBuffer; pBuffer = NULL; 
 }


 

这里转一篇文章,写到不错:

本文以H264视频流为例,讲解解码流数据的步骤。

为突出重点,本文只专注于讨论解码视频流数据,不涉及其它(如开发环境的配置等)。如果您需要这方面的信息,请和我联系。

  • 准备变量

定义AVCodecContext。如果您使用类,可以定义成类成员。我这里定义成全局变量。

static AVCodecContext * g_pCodecCtx = NULL;

定义一个AVFrame,AVFrame描述一个多媒体帧。解码后的数据将被放在其中。

static AVFrame * g_pavfFrame = NULL;

  • 初始化解码器

现在开始初始化您的解码器。我把整个初始化过程包在了一个函数里,除非您有更好的主意,我建议您也这么做。函数长得象这样:

BOOL H264_Init()

{

}

初始化libavcodec,MMPEG要求,这个函数一定要第一个被调用:

avcodec_init();

挂上所有的codec。也许只挂一个H264的codec就行,我没试过:

av_register_all();

得到H264的解码器:

AVCodec * pCodec = avcodec_find_decoder(CODEC_ID_H264);

创建一个AVCodecContext,并用默认值初始化:

g_pCodecCtx = avcodec_alloc_context();

更改g_pCodecCtx的一些成员变量的值,您应该从解码方得到这些变量值:

g_pCodecCtx->time_base.num = 1; //这两行:一秒钟25帧

g_pCodecCtx->time_base.den = 25;

g_pCodecCtx->bit_rate = 0; //初始化为0

g_pCodecCtx->frame_number = 1; //每包一个视频帧

g_pCodecCtx->codec_type = CODEC_TYPE_VIDEO;

g_pCodecCtx->width = 704; //这两行:视频的宽度和高度

g_pCodecCtx->height = 576;

打开codec。如果打开成功的话,分配AVFrame:

if(avcodec_open(g_pCodecCtx, pCodec) >= 0)

{

g_pavfFrame = avcodec_alloc_frame();// Allocate video frame

}

列出完整的初始化解码库的代码:

image

  • 解码

如果您只要求解成YUV 420I数据,只需一次调用就可以了:

avcodec_decode_video(g_pCodecCtx, g_pavfFrame, (int *)&nGot, (unsigned  __int8 *)pSrcData, dwDataLen);

这里,nGot用来返回解码成功与否,avcodec_decode_video调用完成后,如果nGot不等于0,则表示解码成功,否则未解出视频帧。

pSrcData是待解的H264编码的一段数据流,dwDataLen表示该段数据流的长度,单位是byte。

解码后的视频帧(YUV数据)被存入g_pavfFrame,g_pavfFrame->data[0]、g_pavfFrame->data[1]、g_pavfFrame->data[2]即是YUV数据。下面的示例代码把YUV数据压在了一块内存里,排列方式为:

YY

YY

U

V

该函数有返回值:如果解码成功,则返回本次解码使用的码流字节数,否则返回0。为简单起见,我这里假设pSrcData只包含一个视频帧。

同样,出于模块化的要求和代码维护的方便,我把解码动作也包在了一个函数里:

BOOL H264_Decode(const PBYTE pSrcData, const DWORD dwDataLen, PBYTE pDeData,  int * pnWidth, int * pnHeight)

pSrcData – 待解码数据

dwDataLen – 待解码数据字节数

pDeData – 用来返回解码后的YUV数据

pnWidth, pnHeight – 用来返回视频的长度和宽度

下面列出完整的代码:

image

  • 释放解码器

以上其实已经完成了本文的任务,但从负责任的角度,要善始善终嘛。

释放的过程没什么好说的,一看就明白。同样,我也把它们包在了一个函数里:

image

http://blog.csdn.net/gwinner/article/details/5462855

转至http://blog.csdn.net/chinabinlang/article/details/7088590

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值