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

使用ffmpeg解码h264数据其实相对使用x264进行视频编码是简单了许多的,因为ffmpeg提供了一个decoding_encoding.c的文件,这个文件里面有简单的使用ffmpeg进行视频、音频编解码的例子,不过可能有的人也会找不到这个示例,我就讲我改造过的这个示例放在这里,同时加一些解释。

其中需要注意的的一点我需要在此说明,就是ffmpeg在进行解码的时候是会考虑要解码的数据包是否有0x00 00 001这样的头的,如果没有的话,ffmpeg会认为是错误的数据包。下面是使用opencv对解码后的图像进行显示,所以还要配置opencv的环境,如果没有的话,可以注释掉ShowImage这个函数,然后使用pgm_save这个函数将解码后的图像保存。

下面将我的代码放在下面,同样,过程参见代码注释,相对来说比较简单,不在此过多叙述:

[cpp] view
plain
 copy

  1. static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize,char*filename)
  2. {
  3. FILE *f;
  4. int i;
  5. f=fopen(filename,"wb");
  6. fprintf(f,"P5\n%d%d\n%d\n",xsize,ysize,255);
  7. for(i=0;i<ysize;i++)
  8. fwrite(buf + i * wrap,1,xsize,f);
  9. fclose(f);
  10. }
  11. //通过查找0x000001或者0x00000001找到下一个数据包的头部
  12. static int _find_head(unsigned char*buffer, int len)
  13. {
  14. int i;
  15. for(i=512;i<len;i++)
  16. {
  17. if(buffer[i] == 0 && buffer[i+1] == 0 && buffer[i+2] == 0&& buffer[i+3] == 1)
  18. break;
  19. if(buffer[i]== 0 && buffer[i+1] == 0 && buffer[i+2] == 1)
  20. break;
  21. }
  22. if (i ==len)
  23. return0;
  24. if (i ==512)
  25. return0;
  26. return i;
  27. }
  28. //将文件中的一个数据包转换成AVPacket类型以便ffmpeg进行解码
  29. #define FILE_READING_BUFFER (1*1024*1024)
  30. static void build_avpkt(AVPacket *avpkt, FILE *fp)
  31. {
  32. static unsigned charbuffer[1*1024*1024];
  33. static int readptr = 0;
  34. static int writeptr = 0;
  35. intlen,toread;
  36. intnexthead;
  37. if (writeptr- readptr < 200 * 1024)
  38. {
  39. memmove(buffer, &buffer[readptr],writeptr - readptr);
  40. writeptr -= readptr;
  41. readptr = 0;
  42. toread = FILE_READING_BUFFER - writeptr;
  43. len = fread(&buffer[writeptr], 1,toread, fp);
  44. writeptr += len;
  45. }
  46. nexthead = _find_head(&buffer[readptr], writeptr-readptr);
  47. if (nexthead== 0)
  48. {
  49. printf("failedfind next head...\n");
  50. nexthead = writeptr - readptr;
  51. }
  52. avpkt->size = nexthead;
  53. avpkt->data = &buffer[readptr];
  54. readptr += nexthead;
  55. }
  56. static voidvideo_decode_example(const char *outfilename, constchar *filename)
  57. {
  58. AVCodec *codec;
  59. AVCodecContext *c= NULL;
  60. int frame,got_picture, len;
  61. FILE *f, *fout;
  62. AVFrame *picture;
  63. uint8_t inbuf[INBUF_SIZE +FF_INPUT_BUFFER_PADDING_SIZE];
  64. charbuf[1024];
  65. AVPacket avpkt;
  66. av_init_packet(&avpkt);
  67. /* set end ofbuffer to 0 (this ensures that no overreading happens for damaged mpeg streams)*/
  68. memset(inbuf + INBUF_SIZE, 0,FF_INPUT_BUFFER_PADDING_SIZE);
  69. printf("Videodecoding\n");
  70. opts = NULL;
  71. //av_dict_set(&opts,"b", "2.5M", 0);
  72. /* find the h264video decoder */
  73. codec = avcodec_find_decoder(CODEC_ID_H264);
  74. if (!codec){
  75. fprintf(stderr, "codecnot found\n");
  76. return ;
  77. }
  78. c = avcodec_alloc_context3(codec);
  79. picture= avcodec_alloc_frame();
  80. if(codec->capabilities&CODEC_CAP_TRUNCATED)
  81. c->flags|= CODEC_FLAG_TRUNCATED; /* we do not send complete frames */
  82. /* For somecodecs, such as msmpeg4 and mpeg4, width and height
  83. MUST be initialized there because thisinformation is not
  84. available in the bitstream. */
  85. /* open it */
  86. if(avcodec_open2(c, codec, NULL) < 0) {
  87. fprintf(stderr, "couldnot open codec\n");
  88. exit(1);
  89. }
  90. //  fout=fopen(outfilename,"wb");
  91. /* the codec givesus the frame size, in samples */
  92. f = fopen(filename, "rb");
  93. if (!f) {
  94. fprintf(stderr, "couldnot open %s\n", filename);
  95. exit(1);
  96. }
  97. //解码与显示需要的辅助的数据结构,需要注意的是,AVFrame必须经过alloc才能使用,不然其内存的缓存空间指针是空的,程序会崩溃
  98. AVFrame frameRGB;
  99. IplImage *showImage =cvCreateImage(cvSize(352,288),8,3);
  100. avpicture_alloc((AVPicture*)&frameRGB,PIX_FMT_RGB24,352,288);
  101. cvNamedWindow("decode");
  102. frame = 0;
  103. for(;;) {
  104. build_avpkt(&avpkt, f);
  105. if(avpkt.size == 0)
  106. break;
  107. while(avpkt.size > 0) {
  108. len = avcodec_decode_video2(c,picture, &got_picture, &avpkt);//解码每一帧
  109. if(len < 0) {
  110. fprintf(stderr, "Error while decoding frame %d\n",frame);
  111. break;
  112. }
  113. if(got_picture) {
  114. printf("savingframe %3d\n", frame);
  115. fflush(stdout);
  116. /* thepicture is allocated by the decoder. no need to free it */
  117. //将YUV420格式的图像转换成RGB格式所需要的转换上下文
  118. SwsContext* scxt =sws_getContext(picture->width,picture->height,PIX_FMT_YUV420P,
  119. picture->width,picture->height,PIX_FMT_RGB24,
  120. 2,NULL,NULL,NULL);
  121. if(scxt != NULL)
  122. {
  123. sws_scale(scxt,picture->data,picture->linesize,0,c->height,frameRGB.data,frameRGB.linesize);//图像格式转换
  124. showImage->imageSize =frameRGB.linesize[0];//指针赋值给要显示的图像
  125. showImage->imageData = (char *)frameRGB.data[0];
  126. cvShowImage("decode",showImage);//显示
  127. cvWaitKey(0.5);//设置0.5s显示一帧,如果不设置由于这是个循环,会导致看不到显示出来的图像
  128. }
  129. //sprintf(buf,outfilename,frame);
  130. //pgm_save(picture->data[0],picture->linesize[0],
  131. //c->width,c->height, buf);
  132. //pgm_save(picture->data[1],picture->linesize[1],
  133. //c->width/2,c->height/2, fout);
  134. //pgm_save(picture->data[2],picture->linesize[2],
  135. //c->width/2,c->height/2, fout);
  136. frame++;
  137. }
  138. avpkt.size -= len;
  139. avpkt.data += len;
  140. }
  141. }
  142. /* some codecs,such as MPEG, transmit the I and P frame with a
  143. latency of one frame. You must do thefollowing to have a
  144. chance to get the last frame of the video */
  145. avpkt.data = NULL;
  146. avpkt.size = 0;
  147. len = avcodec_decode_video2(c, picture,&got_picture, &avpkt);
  148. if(got_picture) {
  149. printf("savinglast frame %3d\n", frame);
  150. fflush(stdout);
  151. /* the pictureis allocated by the decoder. no need to
  152. free it */
  153. sprintf(buf, outfilename, frame);
  154. //pgm_save(picture->data[0],picture->linesize[0],
  155. //       c->width, c->height, fout);
  156. pgm_save(picture->data[0],picture->linesize[0],c->width, c->height, fout);
  157. pgm_save(picture->data[1],picture->linesize[1],c->width/2, c->height/2, fout);
  158. pgm_save(picture->data[2],picture->linesize[2],c->width/2, c->height/2, fout);
  159. frame++;
  160. }
  161. fclose(f);
  162. //  fclose(fout);
  163. avcodec_close(c);
  164. av_free(c);
  165. av_free(picture);
  166. printf("\n");
  167. }
  168. int main(int argc, char* argv[])
  169. {
  170. avcodec_register_all();//注册所有的编解码器,一定要注意,如果没有这行代码则会出错,提示没有找不到编解码器
  171. video_decode_example("%3d.pgm","test.264");//可以使用x264编码出来的264文件
  172. system("pause");
  173. return 0;
  174. }

【FFMPEG】从内存中获取H264数据并进行decode的更多相关文章

  1. FFmpeg 如何探测网络流格式/如何从内存中获取数据

    文章转自:http://blog.csdn.net/rootusers/article/details/42551935 一般ffmpeg都是直接从文件中读取或者从网络流中读取,比如rtp://xx. ...

  2. C# 操作地址 从内存中读取写入数据(初级)

    本示例以植物大战僵尸为例, 实现功能为 每1秒让阳光刷新为 9999.本示例使用的游戏版本为 [植物大战僵尸2010年度版], 使用的辅助查看内存地址的工具是  CE. 由于每次启动游戏, 游戏中阳光 ...

  3. <转>libjpeg解码内存中的jpeg数据

    转自http://my.unix-center.net/~Simon_fu/?p=565 熟悉libjpeg的朋友都知道libjpeg是一个开源的库.Linux和Android都是用libjpeg来 ...

  4. 通过DialogFragment从DatePicker或TimePicker中获取日期数据

    通过DialogFragment从DatePicker或TimePicker中获取日期数据 一个activity类,里面存有date和time的变量,想通过dialogfragment的方式获取用户输 ...

  5. ffmpeg 从内存中读取数据(或将数据输出到内存)

    更新记录(2014.7.24): 1.为了使本文更通俗易懂,更新了部分内容,将例子改为从内存中打开. 2.增加了将数据输出到内存的方法. 从内存中读取数据 ffmpeg一般情况下支持打开一个本地文件, ...

  6. ffmpeg 从内存中读取数据(或将数据输出到内存)(转)

    更新记录(2014.7.24): 1.为了使本文更通俗易懂,更新了部分内容,将例子改为从内存中打开. 2.增加了将数据输出到内存的方法. 从内存中读取数据 ffmpeg一般情况下支持打开一个本地文件, ...

  7. ffmpeg 从内存中读取数据 .

    http://blog.csdn.net/leixiaohua1020/article/details/12980423 ——————————————————————————————————————— ...

  8. 【在网页中获取截图数据】Chrome和Firefox下的实战经验

    [转载自我在segmentfault的专栏:https://segmentfault.com/a/1190000004584071] 最近在实现一个功能,需求如下: 前提:当前页面无弹窗 页面任意位置 ...

  9. Android中获取网络数据时的分页加载

    //此实在Fragment中实现的,黄色部分为自动加载,红色部分是需要注意的和手动加载,    蓝色部分是睡眠时间,自我感觉不用写  ,还有就是手动加载时,不知道为什么进去后显示的就是最后一行,求大神 ...

随机推荐

  1. libev+TCP服务器事件轮询实例demo

    #include <stdio.h> #include <netinet/in.h> #include <arpa/inet.h> #include <std ...

  2. qt 防止应用重复启动

    QApplication a(argc, argv); QSharedMemory singleton(a.applicationName()); if(!singleton.create(1)) { ...

  3. HDU 6073 - Matching In Multiplication | 2017 Multi-University Training Contest 4

    /* HDU 6073 - Matching In Multiplication [ 图论 ] | 2017 Multi-University Training Contest 4 题意: 定义一张二 ...

  4. 洛谷P4317 花神的数论题

    洛谷题目链接 数位$dp$ 我们对$n$进行二进制拆分,于是就阔以像十进制一样数位$dp$了,基本就是套模板.. 接下来是美滋滋的代码时间~~~ #include<iostream> #i ...

  5. CentOS7从一般用户切换到root用户

    可以使用如下命令从普通用户切换到root用户: su root 键入回车后,系统提示输入密码(此密码即你平时使用的那个用户的密码.关于这一点我还没有确定是否所有用户都可以切换到root用户身份).验证 ...

  6. jQuery属性操作之html属性操作

    jQuery的属性操作, 是对html文档中的属性进行读取.设置和移除操作.比如,attr(). removeAttr(). 1. attr() attr()可以设置属性值或者返回被选元素的属性值 1 ...

  7. [JZOJ6346]:ZYB和售货机(拓扑+基环内向森林)

    题目描述 可爱的$ZYB$来到一个售货机前. 售货机里有一共有$N(\leqslant 10^5)$个物品,每个物品有$A_i$个.自然,还有$N$个购买按钮.正常情况下,按下第$i$个按钮,需要支付 ...

  8. redis服务及其配置与应用(window 环境下)

    一.redis简介:Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API(源自百度百科),个人更喜欢下面的解释:我们 ...

  9. SQL和HQL 区别浅析!!!

    hql是面向对象查询,格式:from + 类名 + 类对象 + where + 对象的属性 sql是面向数据库表查询,格式:from + 表名 + where + 表中字段 1.查询 一般在hiber ...

  10. 机器学习朴素贝叶斯 SVC对新闻文本进行分类

    朴素贝叶斯分类器模型(Naive Bayles) Model basic introduction: 朴素贝叶斯分类器是通过数学家贝叶斯的贝叶斯理论构造的,下面先简单介绍贝叶斯的几个公式: 先验概率: ...