FFmpeg 获取h264裸码流

原帖链接如下:http://blog.csdn.net/ren65432/article/details/43449391

有时候我们需要获取h264裸码流进行分析。本文介绍如何通过FFmpeg 获取h264 码流。获取到的h264码流文件 可以直接通过vlc 等播放器直接播放。


一、 .h264文件数据流

如下图 是通过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的获取

H.264的SPS和PPS串,包含了初始化H.264解码器所需要的信息参数,包括编码所用的profile,level,图像的宽和高,deblock滤波器等。

(1)avcC的数据结构:

  1. aligned(8) class AVCDecoderConfigurationRecord {     
  2.  unsigned int(8) configurationVersion = 1;     
  3.  unsigned int(8) AVCProfileIndication;     
  4.  unsigned int(8) profile_compatibility;     
  5.  unsigned int(8) AVCLevelIndication;     
  6.  bit(6) reserved = '111111'b;     
  7.  unsigned int(2) lengthSizeMinusOne;     
  8.  bit(3) reserved = '111'b;     
  9.  unsigned int(5) numOfSequenceParameterSets;     
  10. for (i=0; i< numOfSequenceParameterSetsispan>    
  11.  unsigned int(16) sequenceParameterSetLength ;     
  12.  bit(8*sequenceParameterSetLength) sequenceParameterSetNALUnit;     
  13.  }     
  14.  unsigned int(8) numOfPictureParameterSets;     
  15. for (i=0; i< numOfPictureParameterSetsispan>    
  16.  unsigned int(16) pictureParameterSetLength;     
  17.  bit(8*pictureParameterSetLength) pictureParameterSetNALUnit;     
  18.  }     
  19. }     
avcC的数据结构对应sps和pps流。

(2) FFmpeg 如何获取sps和pps

ffmpeg获取sps和pps非常简单。avcC数据结构对应于AVFormatContext->streams[H264Index]->codec->extradata。

代码如下:

  1.     if ((ret = avformat_open_input(&ic, InputFileName, NULL, NULL)) < 0)  
  2.     {  
  3.         xprintf->Trace(0,"******** Decode avformat_open_input() Function result=%d",ret);  
  4.         return ret;  
  5.     }  
  6.   
  7.     if ((ret = avformat_find_stream_info(ic, NULL)) < 0)   
  8.     {    
  9.         xprintf->Trace(0,"******** Decode avformat_find_stream_info() Function result=%d ",ret);  
  10.         avformat_close_input(&ic);    
  11.         return ret;    
  12.     }    
  13.   
  14.     for (int i=0;i<ic->streams[0]->codec->extradata_size;i++)  
  15.     {  
  16.         printf("%x ",ic->streams[0]->codec->extradata[i]);  
  17.     }  
输出打印结果如下:


对应上面的avcC结构体我们知道:

第7,8位, 为sps长度(0,18)即为24。

接下来的24位为sps数据,(67,64,0,20,ac,b2,0,a0,b,76,2,20,0,0,3,0,20,0,0,c,81,e3,6,49)。

接下来的1表示后面跟着PPS:

  1. numOfPictureParameterSets, 为1。  
接下来2位为pps长度:(0,6) 即为6。

接下来6位为pps数据,(68,eb,c3,cb,22,c0)。


三、以上各部分的详细代码如下:


  1. int GetH264Stream()  
  2. {  
  3.     int ret;  
  4.     AVFormatContext *ic=NULL;  
  5.     AVFormatContext *oc=NULL;  
  6.   
  7.     uint8_t sps[100];  
  8.     uint8_t pps[100];  
  9.     int spsLength=0;  
  10.     int ppsLength=0;  
  11.     uint8_t startcode[4]={00,00,00,01};  
  12.     FILE *fp;  
  13.   
  14.     fp=fopen("123.h264","wb+");   
  15.   
  16.     char *InputFileName="11111.mp4";  
  17.   
  18.     if ((ret = avformat_open_input(&ic, InputFileName, NULL, NULL)) < 0)  
  19.     {  
  20.         return ret;  
  21.     }  
  22.   
  23.     if ((ret = avformat_find_stream_info(ic, NULL)) < 0)   
  24.     {    
  25.         avformat_close_input(&ic);    
  26.         return ret;    
  27.     }    
  28.   
  29.     spsLength=ic->streams[0]->codec->extradata[6]*0xFF+ic->streams[0]->codec->extradata[7];  
  30.   
  31.     ppsLength=ic->streams[0]->codec->extradata[8+spsLength+1]*0xFF+ic->streams[0]->codec->extradata[8+spsLength+2];  
  32.   
  33.     for (int i=0;i<spsLength;i++)  
  34.     {  
  35.         sps[i]=ic->streams[0]->codec->extradata[i+8];  
  36.     }  
  37.       
  38.     for (int i=0;i<ppsLength;i++)  
  39.     {  
  40.         pps[i]=ic->streams[0]->codec->extradata[i+8+2+1+spsLength];  
  41.     }  
  42.   
  43.   
  44.     for(int i=0;i<ic->nb_streams;i++)  
  45.     {   
  46.         if(ic->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)  
  47.         {  
  48.             videoindex=i;  
  49.         }  
  50.         else if(ic->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO)  
  51.         {  
  52.             audioindex=i;  
  53.         }  
  54.     }  
  55.   
  56.     AVOutputFormat *ofmt = NULL;  
  57.     AVPacket pkt;  
  58.       
  59.     avformat_alloc_output_context2(&oc, NULL, NULL, OutPutPath);  
  60.   
  61.     if (!oc)   
  62.     {  
  63.         printf( "Could not create output context\n");  
  64.         ret = AVERROR_UNKNOWN;  
  65.     }  
  66.     ofmt = oc->oformat;  
  67.     int i;  
  68.   
  69.     for (i = 0; i < ic->nb_streams; i++)   
  70.     {  
  71.         AVStream *in_stream = ic->streams[i];  
  72.         AVStream *out_stream = avformat_new_stream(oc, in_stream->codec->codec);  
  73.   
  74.         if (!out_stream)   
  75.         {  
  76.             printf( "Failed allocating output stream\n");  
  77.             ret = AVERROR_UNKNOWN;  
  78.         }  
  79.         ret = avcodec_copy_context(out_stream->codec, in_stream->codec);  
  80.         if (ret < 0)   
  81.         {  
  82.             printf( "Failed to copy context from input to output stream codec context\n");  
  83.         }  
  84.         out_stream->codec->codec_tag = 0;  
  85.         if (oc->oformat->flags & AVFMT_GLOBALHEADER)  
  86.             out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;  
  87.     }  
  88.   
  89.     if (!(ofmt->flags & AVFMT_NOFILE))   
  90.     {  
  91.         ret = avio_open(&oc->pb, OutPutPath, AVIO_FLAG_WRITE);  
  92.         if (ret < 0)   
  93.         {  
  94.             printf( "Could not open output file '%s'", OutPutPath);  
  95.   
  96.         }  
  97.     }  
  98.     ret = avformat_write_header(oc, NULL);  
  99.   
  100.     int frame_index=0;  
  101.     int flag=1;  
  102.   
  103.     av_init_packet(&pkt);  
  104.     pkt.data = NULL;  
  105.     pkt.size = 0;  
  106.   
  107.     while (1)   
  108.     {  
  109.         AVStream *in_stream, *out_stream;  
  110.   
  111.         ret = av_read_frame(ic, &pkt);  
  112.   
  113.         if (ret < 0)  
  114.             break;  
  115.         in_stream  = ic->streams[pkt.stream_index];  
  116.         out_stream = oc->streams[pkt.stream_index];  
  117.   
  118.         AVPacket tmppkt;  
  119.         if (in_stream->codec->codec_type==AVMEDIA_TYPE_VIDEO )  
  120.         {  
  121.   
  122.             if (flag)  
  123.             {  
  124.                 fwrite(startcode,4,1,fp);  
  125.                 fwrite(sps,spsLength,1,fp);  
  126.                 fwrite(startcode,4,1,fp);  
  127.                 fwrite(pps,ppsLength,1,fp);  
  128.   
  129.                 pkt.data[0]=0x00;  
  130.                 pkt.data[1]=0x00;  
  131.                 pkt.data[2]=0x00;  
  132.                 pkt.data[3]=0x01;  
  133.                 fwrite(pkt.data,pkt.size,1,fp);  
  134.   
  135.                 flag=0;  
  136.             }  
  137.             else  
  138.             {  
  139.                 pkt.data[0]=0x00;  
  140.                 pkt.data[1]=0x00;  
  141.                 pkt.data[2]=0x00;  
  142.                 pkt.data[3]=0x01;  
  143.                 fwrite(pkt.data,pkt.size,1,fp);  
  144.             }  
  145.   
  146.             pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));  
  147.             pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));  
  148.             pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);  
  149.             pkt.pos = -1;  
  150.               
  151.             pkt.stream_index=0;  
  152.             ret = av_interleaved_write_frame(oc, &pkt);  
  153.         }  
  154.   
  155.         av_free_packet(&pkt);  
  156.     }  
  157.   
  158.     fclose(fp);  
  159.     fp=NULL;  
  160.   
  161.     av_write_trailer(oc);  
  162.     return 0;  
  163. }  

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值