【FFMPEG】从内存中获取H264数据并进行decode

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