加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

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

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

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

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

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

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

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

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

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

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

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


前两篇文章介绍了音频码流处理程序和视频码流处理程序,本文介绍将他们打包到一起后的数据——封装格式数据的处理程序。封装格式数据在视频播放器中的位置如下所示。


本文中的程序是一个FLV封装格式解析程序。该程序可以从FLV中分析得到它的基本单元Tag,并且可以简单解析Tag首部的字段。通过修改该程序可以实现不同的FLV格式数据处理功能。

原理

FLV封装格式是由一个FLV Header文件头和一个一个的Tag组成的。Tag中包含了音频数据以及视频数据。FLV的结构如下图所示。


有关FLV的格式本文不再做记录。可以参考文章《 视音频编解码学习工程:FLV封装格式分析器 》。本文的程序实现了FLV中的FLV Header和Tag的解析,并可以分离出其中的音频流。
代码 整个程序位于simplest_flv_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. //Important!??
  30. #pragma?pack(1)??
  31. ??
  32. #define?TAG_TYPE_SCRIPT?18??
  33. #define?TAG_TYPE_AUDIO??8??
  34. #define?TAG_TYPE_VIDEO??9??
  35. typedef?unsigned?char?byte;??
  36. int?uint;??
  37. typedef?struct?{??
  38. ????byte?Signature[3];??
  39. ????byte?Version;??
  40. ????byte?Flags;??
  41. ????uint?DataOffset;??
  42. }?FLV_HEADER;??
  43. struct?{??
  44. ????byte?TagType;??
  45. ????byte?DataSize[3];??
  46. ????byte?Timestamp[3];??
  47. ????uint?Reserved;??
  48. }?TAG_HEADER;??
  49. //reverse_bytes?-?turn?a?BigEndian?byte?array?into?a?LittleEndian?integer??
  50. uint?reverse_bytes(byte?*p,?char?c)?{??
  51. ????int?r?=?0;??
  52. ????int?i;??
  53. ????for?(i=0;?i<c;?i++)???
  54. ????????r?|=?(?*(p+i)?<<?(((c-1)*8)-8*i));??
  55. return?r;??
  56. }??
  57. ?*?Analysis?FLV?file?
  58. ?*?@param?url????Location?of?input?FLV?file.?
  59. ?*/??
  60. int?simplest_flv_parser(char?*url){??
  61. ????//whether?output?audio/video?stream??
  62. int?output_a=1;??
  63. int?output_v=1;??
  64. ????//-------------??
  65. FILE?*ifh=NULL,*vfh=NULL,?*afh?=?NULL;??
  66. //FILE?*myout=fopen("output_log.txt","wb+");??
  67. FILE?*myout=stdout;??
  68. ????FLV_HEADER?flv;??
  69. ????TAG_HEADER?tagheader;??
  70. ????uint?previoustagsize,?previoustagsize_z=0;??
  71. ????uint?ts=0,?ts_new=0;??
  72. ????ifh?=?fopen(url,?"rb+");??
  73. ????if?(?ifh==?NULL)?{??
  74. ????????printf("Failed?to?open?files!");??
  75. ????????return?-1;??
  76. ????}??
  77. //FLV?file?header??
  78. ????fread((char?*)&flv,1,sizeof(FLV_HEADER),ifh);??
  79. ????fprintf(myout,"==============?FLV?Header?==============n");??
  80. ????fprintf(myout,"Signature:??0x?%c?%c?%cn",flv.Signature[0],flv.Signature[1],flv.Signature[2]);??
  81. "Version:????0x?%Xn",flv.Version);??
  82. "Flags??:????0x?%Xn",flv.Flags);??
  83. "HeaderSize:?0x?%Xn",reverse_bytes((byte?*)&flv.DataOffset,?sizeof(flv.DataOffset)));??
  84. "========================================n");??
  85. //move?the?file?pointer?to?the?end?of?the?header??
  86. ????fseek(ifh,?reverse_bytes((byte?*)&flv.DataOffset,?sizeof(flv.DataOffset)),?SEEK_SET);??
  87. //process?each?tag??
  88. do?{??
  89. ????????previoustagsize?=?_getw(ifh);??
  90. ????????fread((void?*)&tagheader,153); font-weight:bold; background-color:inherit">sizeof(TAG_HEADER),ifh);??
  91. ????????//int?temp_datasize1=reverse_bytes((byte?*)&tagheader.DataSize,?sizeof(tagheader.DataSize));??
  92. ????????int?tagheader_datasize=tagheader.DataSize[0]*65536+tagheader.DataSize[1]*256+tagheader.DataSize[2];??
  93. ????????int?tagheader_timestamp=tagheader.Timestamp[0]*65536+tagheader.Timestamp[1]*256+tagheader.Timestamp[2];??
  94. char?tagtype_str[10];??
  95. switch(tagheader.TagType){??
  96. ????????case?TAG_TYPE_AUDIO:sprintf(tagtype_str,"AUDIO");break;??
  97. case?TAG_TYPE_VIDEO:sprintf(tagtype_str,"VIDEO");break;??
  98. case?TAG_TYPE_SCRIPT:sprintf(tagtype_str,"SCRIPT");default:sprintf(tagtype_str,"UNKNOWN"); ????????}??
  99. ????????fprintf(myout,"[%6s]?%6d?%6d?|",tagtype_str,tagheader_datasize,tagheader_timestamp);??
  100. ????????//if?we?are?not?past?the?end?of?file,?process?the?tag??
  101. if?(feof(ifh))?{??
  102. ????????????//process?tag?by?type??
  103. switch?(tagheader.TagType)?{??
  104. case?TAG_TYPE_AUDIO:{???
  105. ????????????char?audiotag_str[100]={0};??
  106. ????????????strcat(audiotag_str,"|?");??
  107. char?tagdata_first_byte;??
  108. ????????????tagdata_first_byte=fgetc(ifh);??
  109. int?x=tagdata_first_byte&0xF0;??
  110. ????????????x=x>>4;??
  111. ????????????switch?(x)??
  112. ????????????{??
  113. case?0:strcat(audiotag_str,"Linear?PCM,?platform?endian");case?1:strcat(audiotag_str,"ADPCM");case?2:strcat(audiotag_str,"MP3");case?3:strcat(audiotag_str,?little?endian");case?4:strcat(audiotag_str,"Nellymoser?16-kHz?mono");case?5:strcat(audiotag_str,"Nellymoser?8-kHz?mono");case?6:strcat(audiotag_str,"Nellymoser");case?7:strcat(audiotag_str,"G.711?A-law?logarithmic?PCM");case?8:strcat(audiotag_str,"G.711?mu-law?logarithmic?PCM");case?9:strcat(audiotag_str,"reserved");case?10:strcat(audiotag_str,"AAC");case?11:strcat(audiotag_str,"Speex");case?14:strcat(audiotag_str,"MP3?8-Khz");case?15:strcat(audiotag_str,"Device-specific?sound");default:strcat(audiotag_str,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> ????????????}??
  114. ????????????strcat(audiotag_str,"|?");??
  115. ????????????x=tagdata_first_byte&0x0C;??
  116. ????????????x=x>>2;??
  117. switch?(x)??
  118. ????????????{??
  119. "5.5-kHz");"1-kHz");"22-kHz");"44-kHz"); ????????????}??
  120. ????????????x=tagdata_first_byte&0x02;??
  121. ????????????x=x>>1;??
  122. "8Bit");"16Bit"); ????????????x=tagdata_first_byte&0x01;??
  123. "Mono");"Stereo"); ????????????fprintf(myout,"%s",audiotag_str);??
  124. ????????????//if?the?output?file?hasn't?been?opened,?open?it.??
  125. if(output_a!=0&&afh?==?NULL){??
  126. ????????????????afh?=?fopen("output.mp3",?"wb");??
  127. ????????????//TagData?-?First?Byte?Data??
  128. int?data_size=reverse_bytes((byte?*)&tagheader.DataSize,153); font-weight:bold; background-color:inherit">sizeof(tagheader.DataSize))-1;??
  129. if(output_a!=0){??
  130. ????????????????//TagData+1??
  131. ????????????????for?(int?i=0;?i<data_size;?i++)??
  132. ????????????????????fputc(fgetc(ifh),afh);??
  133. ????????????}else{??
  134. ????????????????????fgetc(ifh);??
  135. ????????}??
  136. case?TAG_TYPE_VIDEO:{??
  137. ????????????char?videotag_str[100]={0};??
  138. ????????????strcat(videotag_str,87); font-weight:bold; background-color:inherit">char?tagdata_first_byte;??
  139. ????????????tagdata_first_byte=fgetc(ifh);??
  140. int?x=tagdata_first_byte&0xF0;??
  141. ????????????x=x>>4;??
  142. case?1:strcat(videotag_str,"key?frame??");case?2:strcat(videotag_str,"inter?frame");case?3:strcat(videotag_str,"disposable?inter?frame");case?4:strcat(videotag_str,"generated?keyframe");case?5:strcat(videotag_str,"video?info/command?frame");default:strcat(videotag_str,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> ????????????x=tagdata_first_byte&0x0F;??
  143. "JPEG?(currently?unused)");"Sorenson?H.263");"Screen?video");"On2?VP6");"On2?VP6?with?alpha?channel");case?6:strcat(videotag_str,"Screen?video?version?2");case?7:strcat(videotag_str,"AVC"); ????????????fprintf(myout,videotag_str);??
  144. ????????????fseek(ifh,?-1,?SEEK_CUR);??
  145. if?(vfh?==?NULL&&output_v!=0)?{??
  146. //write?the?flv?header?(reuse?the?original?file's?hdr)?and?first?previoustagsize??
  147. ????????????????????vfh?=?fopen("output.flv",?"wb");??
  148. ????????????????????fwrite((sizeof(flv),vfh);??
  149. ????????????????????fwrite((char?*)&previoustagsize_z,153); font-weight:bold; background-color:inherit">sizeof(previoustagsize_z),vfh);??
  150. #if?0??
  151. //Change?Timestamp??
  152. //Get?Timestamp??
  153. ????????????ts?=?reverse_bytes((byte?*)&tagheader.Timestamp,153); font-weight:bold; background-color:inherit">sizeof(tagheader.Timestamp));??
  154. ????????????ts=ts*2;??
  155. //Writeback?Timestamp??
  156. ????????????ts_new?=?reverse_bytes((byte?*)&ts,153); font-weight:bold; background-color:inherit">sizeof(ts));??
  157. ????????????memcpy(&tagheader.Timestamp,?((char?*)&ts_new)?+?1,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> #endif??
  158. //TagData?+?Previous?Tag?Size??
  159. sizeof(tagheader.DataSize))+4;??
  160. if(output_v!=0){??
  161. ????????????????//TagHeader??
  162. ????????????????fwrite((char?*)&tagheader,153); font-weight:bold; background-color:inherit">sizeof(tagheader),0); background-color:inherit">//TagData??
  163. ????????????????int?i=0;?i<data_size;?i++)??
  164. ????????????????????fputc(fgetc(ifh),vfh);??
  165. //rewind?4?bytes,?because?we?need?to?read?the?previoustagsize?again?for?the?loop's?sake??
  166. default:??
  167. //skip?the?data?of?this?tag??
  168. ????????????fseek(ifh,?reverse_bytes((byte?*)&tagheader.DataSize,153); font-weight:bold; background-color:inherit">sizeof(tagheader.DataSize)),?SEEK_CUR);??
  169. "n");??
  170. ????}?while?(!feof(ifh));??
  171. ????_fcloseall();??
  172. return?0;??
  173. }??

上文中的函数调用方法如下所示。
copy
? simplest_flv_parser("cuc_ieschool.flv");??

结果

本程序的输入为一个FLV的文件路径,输出为FLV的统计数据,如下图所示。


此外本程序还可以分离FLV中的视频码流和音频码流。需要注意的是本程序并不能分离一些特定类型的音频(例如AAC)和视频,这一工作有待以后有时间再完成。


下载
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数据包。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读