zoukankan      html  css  js  c++  java
  • 【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 %d%d %d ",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... ");  
    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 ");  
    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 ");  
    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 ");  
    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 ", 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 ",frame);  
    136.                 break;  
    137.             }  
    138.             if(got_picture) {  
    139.                 printf("savingframe %3d ", 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 ", 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(" ");  
    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. }  
  • 相关阅读:
    插件开发遇到的坑------final 型变量,编译过程被优化
    java.lang.NoClassDefFoundError 错误解决思路
    Android stadio bug
    android去掉button默认的点击阴影
    Andrid 打印调用堆栈
    Gradle 设置本地meaven
    Android log 里面快速搜索错误堆栈 ( 关键字)
    java doc 编写
    android 怎么判断activity 从哪里启动的
    Android Stadio调试gradle 插件 || Android Stadio 远程调试 || Anroid APT调试
  • 原文地址:https://www.cnblogs.com/huty/p/8518757.html
Copyright © 2011-2022 走看看