设为首页 - 加入收藏 ASP站长网(Aspzz.Cn)- 科技、建站、经验、云计算、5G、大数据,站长网!
热搜: 数据 创业者 手机
当前位置: 首页 > 大数据 > 正文

视音频数据处理入门:H.264视频码流解析

发布时间:2021-01-27 14:49 所属栏目:125 来源:网络整理
导读:===================================================== 视音频数据处理入门系列文章: 视音频数据处理入门:RGB、YUV像素数据处理 视音频数据处理入门:PCM音频采样数据处理 视音频数据处理入门:H.264视频码流解析 视音频数据处理入门:AAC音频码流解析

=====================================================

视音频数据处理入门系列文章:

视音频数据处理入门:RGB、YUV像素数据处理

视音频数据处理入门:PCM音频采样数据处理

视音频数据处理入门:H.264视频码流解析

视音频数据处理入门:AAC音频码流解析

视音频数据处理入门:FLV封装格式解析

视音频数据处理入门:UDP-RTP协议解析

=====================================================


前两篇文章介绍的YUV/RGB处理程序以及PCM处理程序都属于视音频原始数据的处理程序。从本文开始介绍视音频码流的处理程序。本文介绍的程序是视频码流处理程序。视频码流在视频播放器中的位置如下所示。

视音频数据处理入门:H.264视频码流解析


本文中的程序是一个H.264码流解析程序。该程序可以从H.264码流中分析得到它的基本单元NALU,并且可以简单解析NALU首部的字段。通过修改该程序可以实现不同的H.264码流处理功能。


原理

H.264原始码流(又称为“裸流”)是由一个一个的NALU组成的。他们的结构如下图所示。

视音频数据处理入门:H.264视频码流解析


其中每个NALU之间通过startcode(起始码)进行分隔,起始码分成两种:0x000001(3Byte)或者0x00000001(4Byte)。如果NALU对应的Slice为一帧的开始就用0x00000001,否则就用0x000001。
H.264码流解析的步骤就是首先从码流中搜索0x000001和0x00000001,分离出NALU;然后再分析NALU的各个字段。本文的程序即实现了上述的两个步骤。

代码 整个程序位于simplest_h264_parser()函数中,如下所示。

[cpp]? view plain ?copy ?

在CODE上查看代码片

派生到我的代码片

  1. /**?
  2. ?*?最简单的视音频数据处理示例?
  3. ?*?Simplest?MediaData?Test?
  4. ?*?
  5. ?*?雷霄骅?Lei?Xiaohua?
  6. ?*?leixiaohua1020@126.com?
  7. ?*?中国传媒大学/数字电视技术?
  8. ?*?Communication?University?of?China?/?Digital?TV?Technology?
  9. ?*?http://blog.csdn.net/leixiaohua1020?
  10. ?*?本项目包含如下几种视音频测试示例:?
  11. ?*??(1)像素数据处理程序。包含RGB和YUV像素格式处理的函数。?
  12. ?*??(2)音频采样数据处理程序。包含PCM音频采样格式处理的函数。?
  13. ?*??(3)H.264码流分析程序。可以分离并解析NALU。?
  14. ?*??(4)AAC码流分析程序。可以分离并解析ADTS帧。?
  15. ?*??(5)FLV封装格式分析程序。可以将FLV中的MP3音频码流分离出来。?
  16. ?*??(6)UDP-RTP协议分析程序。可以将分析UDP/RTP/MPEG-TS数据包。?
  17. ?*?This?project?contains?following?samples?to?handling?multimedia?data:?
  18. ?*??(1)?Video?pixel?data?handling?program.?It?contains?several?examples?to?handle?RGB?and?YUV?data.?
  19. ?*??(2)?Audio?sample?data?handling?program.?It?contains?several?examples?to?handle?PCM?data.?
  20. ?*??(3)?H.264?stream?analysis?program.?It?can?parse?H.264?bitstream?and?analysis?NALU?of?stream.?
  21. ?*??(4)?AAC?stream?analysis?program.?It?can?parse?AAC?bitstream?and?analysis?ADTS?frame?of?stream.?
  22. ?*??(5)?FLV?format?analysis?program.?It?can?analysis?FLV?file?and?extract?MP3?audio?stream.?
  23. ?*??(6)?UDP-RTP?protocol?analysis?program.?It?can?analysis?UDP/RTP/MPEG-TS?Packet.?
  24. ?*/??
  25. #include?<stdio.h>??
  26. #include?<stdlib.h>??
  27. #include?<string.h>??
  28. ??
  29. typedef?enum?{??
  30. ????NALU_TYPE_SLICE????=?1,??
  31. ????NALU_TYPE_DPA??????=?2,??
  32. ????NALU_TYPE_DPB??????=?3,248)"> ????NALU_TYPE_DPC??????=?4,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> ????NALU_TYPE_IDR??????=?5,248)"> ????NALU_TYPE_SEI??????=?6,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> ????NALU_TYPE_SPS??????=?7,248)"> ????NALU_TYPE_PPS??????=?8,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> ????NALU_TYPE_AUD??????=?9,248)"> ????NALU_TYPE_EOSEQ????=?10,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> ????NALU_TYPE_EOSTREAM?=?11,248)"> ????NALU_TYPE_FILL?????=?12,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> }?NaluType;??
  33. ??
  34. enum?{??
  35. ????NALU_PRIORITY_DISPOSABLE?=?0,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> ????NALU_PRIRITY_LOW?????????=?1,248)"> ????NALU_PRIORITY_HIGH???????=?2,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> ????NALU_PRIORITY_HIGHEST????=?3??
  36. }?NaluPriority;??
  37. struct??
  38. {??
  39. ????int?startcodeprefix_len;??????//!?4?for?parameter?sets?and?first?slice?in?picture,?3?for?everything?else?(suggested)??
  40. ????unsigned?len;?????????????????//!?Length?of?the?NAL?unit?(Excluding?the?start?code,?which?does?not?belong?to?the?NALU)??
  41. ????unsigned?max_size;????????????//!?Nal?Unit?Buffer?size??
  42. ????int?forbidden_bit;????????????//!?should?be?always?FALSE??
  43. int?nal_reference_idc;????????//!?NALU_PRIORITY_xxxx??
  44. int?nal_unit_type;????????????//!?NALU_TYPE_xxxx??????
  45. char?*buf;????????????????????//!?contains?the?first?byte?followed?by?the?EBSP??
  46. }?NALU_t;??
  47. FILE?*h264bitstream?=?NULL;????????????????//!<?the?bit?stream?file??
  48. int?info2=0,?info3=0;??
  49. static?int?FindStartCode2?(unsigned?char?*Buf){??
  50. ????if(Buf[0]!=0?||?Buf[1]!=0?||?Buf[2]?!=1)?return?0;?//0x000001???
  51. ????else?return?1;??
  52. }??
  53. int?FindStartCode3?(unsigned?char?*Buf){??
  54. if(Buf[0]!=0?||?Buf[1]!=0?||?Buf[2]?!=0?||?Buf[3]?!=1)?return?0;//0x00000001???
  55. return?1;??
  56. }??
  57. int?GetAnnexbNALU?(NALU_t?*nalu){??
  58. int?pos?=?0;??
  59. int?StartCodeFound,?rewind;??
  60. ????unsigned?char?*Buf;??
  61. if?((Buf?=?(unsigned?char*)calloc?(nalu->max_size?,?sizeof(char)))?==?NULL)???
  62. ????????printf?("GetAnnexbNALU:?Could?not?allocate?Buf?memory\n");??
  63. ????nalu->startcodeprefix_len=3;??
  64. if?(3?!=?fread?(Buf,?1,?3,?h264bitstream)){??
  65. ????????free(Buf);??
  66. ????????return?0;??
  67. ????}??
  68. ????info2?=?FindStartCode2?(Buf);??
  69. if(info2?!=?1)?{??
  70. if(1?!=?fread(Buf+3,248)"> ????????????free(Buf);??
  71. ???????????? ????????}??
  72. ????????info3?=?FindStartCode3?(Buf);??
  73. ????????if?(info3?!=?1){???
  74. ????????????free(Buf);??
  75. ????????????return?-1;??
  76. ????????}??
  77. else?{??
  78. ????????????pos?=?4;??
  79. ????????????nalu->startcodeprefix_len?=?4;??
  80. else{??
  81. ????????nalu->startcodeprefix_len?=?3;??
  82. ????????pos?=?3;??
  83. ????StartCodeFound?=?0;??
  84. ????info2?=?0;??
  85. ????info3?=?0;??
  86. while?(!StartCodeFound){??
  87. if?(feof?(h264bitstream)){??
  88. ????????????nalu->len?=?(pos-1)-nalu->startcodeprefix_len;??
  89. ????????????memcpy?(nalu->buf,?&Buf[nalu->startcodeprefix_len],?nalu->len);???????
  90. ????????????nalu->forbidden_bit?=?nalu->buf[0]?&?0x80;?//1?bit??
  91. ????????????nalu->nal_reference_idc?=?nalu->buf[0]?&?0x60;?//?2?bit??
  92. ????????????nalu->nal_unit_type?=?(nalu->buf[0])?&?0x1f;//?5?bit??
  93. return?pos-1;??
  94. ????????Buf[pos++]?=?fgetc?(h264bitstream);??
  95. ????????info3?=?FindStartCode3(&Buf[pos-4]);??
  96. if(info3?!=?1)??
  97. ????????????info2?=?FindStartCode2(&Buf[pos-3]);??
  98. ????????StartCodeFound?=?(info2?==?1?||?info3?==?1);??
  99. ????//?Here,?we?have?found?another?start?code?(and?read?length?of?startcode?bytes?more?than?we?should??
  100. ????//?have.??Hence,?go?back?in?the?file??
  101. ????rewind?=?(info3?==?1)??-4?:?-3;??
  102. if?(0?!=?fseek?(h264bitstream,?rewind,?SEEK_CUR)){??
  103. ????????free(Buf);??
  104. ????????printf("GetAnnexbNALU:?Cannot?fseek?in?the?bit?stream?file");??
  105. ????}??
  106. //?Here?the?Start?code,?the?complete?NALU,?and?the?next?start?code?is?in?the?Buf.????
  107. //?The?size?of?Buf?is?pos,?pos+rewind?are?the?number?of?bytes?excluding?the?next??
  108. //?start?code,?and?(pos+rewind)-startcodeprefix_len?is?the?size?of?the?NALU?excluding?the?start?code??
  109. ????nalu->len?=?(pos+rewind)-nalu->startcodeprefix_len;??
  110. ????memcpy?(nalu->buf,?nalu->len);//??
  111. ????nalu->forbidden_bit?=?nalu->buf[0]?&?0x80;? ????nalu->nal_reference_idc?=?nalu->buf[0]?&?0x60;? ????nalu->nal_unit_type?=?(nalu->buf[0])?&?0x1f; ????free(Buf);??
  112. return?(pos+rewind);??
  113. ?*?Analysis?H.264?Bitstream?
  114. ?*?@param?url????Location?of?input?H.264?bitstream?file.?
  115. ?*/??
  116. int?simplest_h264_parser(char?*url){??
  117. ????NALU_t?*n;??
  118. int?buffersize=100000;??
  119. //FILE?*myout=fopen("output_log.txt","wb+");??
  120. FILE?*myout=stdout;??
  121. ????h264bitstream=fopen(url,?"rb+");??
  122. if?(h264bitstream==NULL){??
  123. ????????printf("Open?file?error\n");??
  124. return?0;??
  125. ????n?=?(NALU_t*)calloc?(1,?sizeof?(NALU_t));??
  126. if?(n?==?NULL){??
  127. ????????printf("Alloc?NALU?Error\n");??
  128. ????n->max_size=buffersize;??
  129. ????n->buf?=?(char*)calloc?(buffersize,153); font-weight:bold; background-color:inherit">sizeof?(char));??
  130. if?(n->buf?==?NULL){??
  131. ????????free?(n);??
  132. ????????printf?("AllocNALU:?n->buf");??
  133. int?data_offset=0;??
  134. int?nal_num=0;??
  135. ????printf("-----+--------?NALU?Table?------+---------+\n");??
  136. ????printf("?NUM?|????POS??|????IDC?|??TYPE?|???LEN???|\n");??
  137. ????printf("-----+---------+--------+-------+---------+\n");??
  138. while(!feof(h264bitstream))???
  139. ????{??
  140. ????????int?data_lenth;??
  141. ????????data_lenth=GetAnnexbNALU(n);??
  142. ????????char?type_str[20]={0};??
  143. switch(n->nal_unit_type){??
  144. case?NALU_TYPE_SLICE:sprintf(type_str,"SLICE");break;??
  145. case?NALU_TYPE_DPA:sprintf(type_str,"DPA");break;??
  146. case?NALU_TYPE_DPB:sprintf(type_str,"DPB");case?NALU_TYPE_DPC:sprintf(type_str,"DPC");case?NALU_TYPE_IDR:sprintf(type_str,"IDR");case?NALU_TYPE_SEI:sprintf(type_str,"SEI");case?NALU_TYPE_SPS:sprintf(type_str,"SPS");case?NALU_TYPE_PPS:sprintf(type_str,"PPS");case?NALU_TYPE_AUD:sprintf(type_str,"AUD");case?NALU_TYPE_EOSEQ:sprintf(type_str,"EOSEQ");case?NALU_TYPE_EOSTREAM:sprintf(type_str,"EOSTREAM");case?NALU_TYPE_FILL:sprintf(type_str,"FILL");char?idc_str[20]={0};??
  147. switch(n->nal_reference_idc>>5){??
  148. case?NALU_PRIORITY_DISPOSABLE:sprintf(idc_str,"DISPOS");case?NALU_PRIRITY_LOW:sprintf(idc_str,"LOW");case?NALU_PRIORITY_HIGH:sprintf(idc_str,"HIGH");case?NALU_PRIORITY_HIGHEST:sprintf(idc_str,"HIGHEST"); ????????fprintf(myout,"%5d|?%8d|?%7s|?%6s|?%8d|\n",nal_num,data_offset,idc_str,type_str,n->len);??
  149. ????????data_offset=data_offset+data_lenth;??
  150. ????????nal_num++;??
  151. //Free??
  152. if?(n){??
  153. if?(n->buf){??
  154. ????????????free(n->buf);??
  155. ????????????n->buf=NULL;??
  156. }??

上文中的函数调用方法如下所示。
copy ? simplest_h264_parser("sintel.h264");??

结果

本程序的输入为一个H.264原始码流(裸流)的文件路径,输出为该码流的NALU统计数据,如下图所示。

视音频数据处理入门:H.264视频码流解析


下载


Simplest mediadata test


项目主页
SourceForge:https://sourceforge.net/projects/simplest-mediadata-test/

Github:https://github.com/leixiaohua1020/simplest_mediadata_test

开源中国:http://git.oschina.net/leixiaohua1020/simplest_mediadata_test


CSDN下载地址:http://download.csdn.net/detail/leixiaohua1020/9422409

本项目包含如下几种视音频数据解析示例:

?(1)像素数据处理程序。包含RGB和YUV像素格式处理的函数。
?(2)音频采样数据处理程序。包含PCM音频采样格式处理的函数。
?(3)H.264码流分析程序。可以分离并解析NALU。
?(4)AAC码流分析程序。可以分离并解析ADTS帧。
?(5)FLV封装格式分析程序。可以将FLV中的MP3音频码流分离出来。
?(6)UDP-RTP协议分析程序。可以将分析UDP/RTP/MPEG-TS数据包。

雷霄骅 (Lei Xiaohua) leixiaohua1020@126.com http://blog.csdn.net/leixiaohua1020

(编辑:ASP站长网)

    网友评论
    推荐文章
      热点阅读