利用ffmpeg将H264流 解码为RGB

利用H264解码分为几个步骤:

注意一点在添加头文件的时候要添加extern "C",不然会出现错误

[cpp] view plaincopy

  1. extern "C"
  2. {
  3. #include <avcodec.h>
  4. #include <avformat.h>
  5. #include <avutil.h>
  6. #include <swscale.h>
  7. };

这里申明了几个全局变量

[cpp] view plaincopy

  1. AVCodec         *pCodec = NULL;
  2. AVCodecContext  *pCodecCtx = NULL;
  3. SwsContext      *img_convert_ctx = NULL;
  4. AVFrame         *pFrame = NULL;
  5. AVFrame         *pFrameRGB = NULL;

1. 初始化

[cpp] view plaincopy

  1. int H264_Init(void)
  2. {
  3. /* must be called before using avcodec lib*/
  4. avcodec_init();
  5. /* register all the codecs */
  6. avcodec_register_all();
  7. /* find the h264 video decoder */
  8. pCodec = avcodec_find_decoder(CODEC_ID_H264);
  9. if (!pCodec) {
  10. fprintf(stderr, "codec not found\n");
  11. }
  12. pCodecCtx = avcodec_alloc_context();
  13. /* open the coderc */
  14. if (avcodec_open(pCodecCtx, pCodec) < 0) {
  15. fprintf(stderr, "could not open codec\n");
  16. }
  17. // Allocate video frame
  18. pFrame = avcodec_alloc_frame();
  19. if(pFrame == NULL)
  20. return -1;
  21. // Allocate an AVFrame structure
  22. pFrameRGB=avcodec_alloc_frame();
  23. if(pFrameRGB == NULL)
  24. return -1;
  25. return 0;
  26. }

在最早使用的时候没有使用全局变量,初始化中也就只有init和regisger这两个函数,而这样做的下场是,非关键帧全部无法解码,只有关键帧才有办法解码。

2. 解码

解码的时候avcodec_decode_video函数是进行解码操作,在外部定义outputbuf的大小时,pixes*3,outsize是返回的outputbuf的size,值也是pixes*3。

在解码的时候这几句话的意义是将YUV420P的数据倒置。在原先使用中,发现解出来的图像居然是中心旋转图,后面在网上找了些办法,觉得这个比较实用。解码实时是很重要的,图像转化完之后也可以讲RGB图再次转化,那样也能成为一个正的图,但是那样效率就明显低了。

[cpp] view plaincopy

  1. pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height-1);
  2. pFrame->linesize[0] *= -1;
  3. pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height/2 - 1);;
  4. pFrame->linesize[1] *= -1;
  5. pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height/2 - 1);;
  6. pFrame->linesize[2] *= -1;

[cpp] view plaincopy

  1. int H264_2_RGB(unsigned char *inputbuf, int frame_size, unsigned char *outputbuf, unsigned int*outsize)
  2. {
  3. int             decode_size;
  4. int             numBytes;
  5. int             av_result;
  6. uint8_t         *buffer = NULL;
  7. printf("Video decoding\n");
  8. av_result = avcodec_decode_video(pCodecCtx, pFrame, &decode_size, inputbuf, frame_size);
  9. if (av_result < 0)
  10. {
  11. fprintf(stderr, "decode failed: inputbuf = 0x%x , input_framesize = %d\n", inputbuf, frame_size);
  12. return -1;
  13. }
  14. // Determine required buffer size and allocate buffer
  15. numBytes=avpicture_get_size(PIX_FMT_BGR24, pCodecCtx->width,
  16. pCodecCtx->height);
  17. buffer = (uint8_t*)malloc(numBytes * sizeof(uint8_t));
  18. // Assign appropriate parts of buffer to image planes in pFrameRGB
  19. avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_BGR24,
  20. pCodecCtx->width, pCodecCtx->height);
  21. img_convert_ctx = sws_getCachedContext(img_convert_ctx,pCodecCtx->width,pCodecCtx->height,
  22. //PIX_FMT_YUV420P,pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,
  23. pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,PIX_FMT_RGB24 ,
  24. SWS_X ,NULL,NULL,NULL) ;
  25. if (img_convert_ctx == NULL)
  26. {
  27. printf("can‘t init convert context!\n") ;
  28. return -1;
  29. }
  30. pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height-1);
  31. pFrame->linesize[0] *= -1;
  32. pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height/2 - 1);;
  33. pFrame->linesize[1] *= -1;
  34. pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height/2 - 1);;
  35. pFrame->linesize[2] *= -1;
  36. sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize,
  37. 0, 0 - pCodecCtx->width, pFrameRGB->data, pFrameRGB->linesize);
  38. if (decode_size)
  39. {
  40. *outsize = pCodecCtx->width * pCodecCtx->height * 3;
  41. memcpy(outputbuf, pFrameRGB->data[0], *outsize);
  42. }
  43. free(buffer);
  44. return 0;
  45. }
//解码yuv 修改 PIX_FMT_YUV420P
memcpy(outputbuf, pFrameRGB->data[2], 720*576/4);
			memcpy(outputbuf, pFrameRGB->data[1], 720*576/4);
			memcpy(outputbuf, pFrameRGB->data[0], 720*576);

3. 释放资源

资源的回收。

[cpp] view plaincopy

  1. void H264_Release(void)
  2. {
  3. avcodec_close(pCodecCtx);
  4. av_free(pCodecCtx);
  5. av_free(pFrame);
  6. av_free(pFrameRGB);
  7. }

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-27 16:38:52

利用ffmpeg将H264流 解码为RGB的相关文章

FFMPEG实现H264的解码(从源代码角度)

农历2014年底了,将前段时间工作中研究的FFMPEG解码H264流程在此做一下整理,也算作年终技术总结了! H264解码原理: H264的原理参考另一篇博文 http://blog.csdn.net/rootusers/article/details/43563133 H264分为NAL(网络抽象层)和VCL(视频编码层) 解码器的总框架: 解码器的流程为:将NAL数据位流输入到H264的解码器中,熵解码模块解码后输出量化系数X:系数经过反量化和反变换得到残差数据R:解码器使用从码流中解码的头

用ffmpeg把H264数据流解码成YUV420P

在网上找了很久这方面的内容,发现网上的代码都太旧了,所使用的函数旧到连最新版本的ffmpeg都已经不包含了,所以对于我这个初学者来说太坑拉.不过经过多次查找ffmpeg的头文件和结合网上的内容,终于成功可以解码拉.现在贴出来. 首先是初始化一些参数 [cpp] view plaincopy //下面初始化h264解码库 avcodec_init(); av_register_all(); AVFrame *pFrame_ = NULL; AVCodecContext *codec_ = avco

FFmpeg 获取h264裸码流

有时候我们需要获取h264裸码流进行分析.本文介绍如何通过FFmpeg 获取h264 码流.获取到的h264码流文件 可以直接通过vlc 等播放器直接播放. 如下图 是通过WinHex工具 分析的一个h264文件 ffmpeg 获取h264 思路如下: 1,写4位头(00,00,00,01) 2,写sps 3,写4位头(00,00,00,01) 4,写pps 5,将读到的AVPacket.data 的前4位替换成(00,00,00,01)写文件. sps pps的获取参考上篇博文. 详细代码如下

利用FFMPEG简单分离音视频数据流

上一篇文章我们搭好了环境并编译出所需的ffmpeg库,本篇我们讨论如何利用ffmpeg提供的API函数进行多媒体文件的解封装(demux)过程.在讲解之前,我们需要了解一些基本的多媒体文件知识,大虾请飘过. 容器格式:不管是音频文件还是视频格式的文件,都是一个多媒体的容器,即container,比如常见的视频容器格式有avi.mp4.mkv.flv.rm/rmvb.mov.ts.vob.dat,音频容器格式有MP3.WAV.AAC.APE,FLAC等等,它容纳了视频.音频.字幕(subtitle

利用FFmpeg玩转Android视频录制与压缩(二)&lt;转&gt;

转载出处:http://blog.csdn.net/mabeijianxi/article/details/72983362 预热 时光荏苒,光阴如梭,离上一次吹牛逼已经过去了两三个月,身边很多人的女票已经分了又合,合了又分,本屌依旧骄傲单身.上一次啊我们大致说了一些简单的FFmpeg命令以及Java层简单的调用方式,然后有很多朋友在github或者csdn上给我留言,很多时候我都选择避而不答,原因是本库以前用的so包是不开源的,我根本改不了里面东西.但是这一次啊我们玩点大的,我重新编译了FFm

H264 编解码框架简单介绍

阅读完H264/AVC 编解码器的介绍,脑海中仅仅是留下下面三条: 1.H264并没有明白规定一个编解码器怎样实现,仅仅是规定了一个编码后的视频比特流的句法,和该比特流的解码方法,这个与MPEG 类似. 2.H264和曾经的标准(如H261.H263.MPEG-1.MPEG-4)的编解码器实现流程没有太大差别,基本的不同在于各功能块的细节. 3.H264就是利用实现的复杂性获得压缩性能的明显改善.(至于复杂度的评估,以后会介绍) 以下介绍一下H264的编码器框图: 编码器採用的仍是变换和预測的混

嵌入式专题: S5PV210 - H264硬件解码(MFC)

先说一下编码的例子好像找不到了,只提供一下解码的例子吧.淡疼的三星要是能以YUV420P为基本图像格式就好了,这样结合FFmpeg来开发,各种应用都比较方法.再设计一个RGB/YUV硬件转码单元,最好. #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include "../mfc/SsbSipMfcApi.h" #includ

ffmpeg解析TS流

介绍:  MPEG的系统层编码为不同的应用场景设计了两种格式: TS(Transport Stream) 和PS(Program Stream), 它们两者之间不具有层级关系, 在逻辑上,它们两者都是由PES(Packetized Elementary Stream)包组成的, 所以可以很方便地实现相互转换. TS(Transport Stream): 是将具有一个或多个独立时间基的一个或多个节目(包括音频和视频)组成一个流, 组成同一个节目的基本流(如一个视频流,多个音频流)的PES包有一个共

ffmpeg接收rtsp流问题

项目使用mingw环境g++5.3,C++调用ffmpeg接收rtsp流,再通过C#显示.结构上是C#调用C++的so文件,读取得到的视频帧(RGB888格式),通过图片控件显示. 一开始是使用opencv打开视频源,本地文件和rtsp的源使用一样的接口,方便使用.但是通过opencv打开rtsp源的时候,发现720p2Mbit的视频能够正常打开,但1080p的视频打开后出马赛克,卡顿比较多. 而同样的视频源,使用VLC就能流畅的打开,不过延时很高,大约1s. 后来又发现,使用i3低电压版CPU