当前位置: 首页 > news >正文

h264解码时的AVCDecoderConfigurationRecord 与 CodecPrivateData

  1. 计算 AVCDecoderConfigurationRecord 得到 CodecPrivateData 数据(只有第一帧需要);
  2. 计算 NALUs 得到帧数据。

计算 AVCDecoderConfigurationRecord 得到 CodecPrivateData 数据

H.264 视频流的 CodecPrivateData 实际上就是 AVCDecoderConfigurationRecord 中 SequenceParameterSets(SPS)和 PictureParameterSets(PPS)使用 byte[] {00, 00, 01} 连接的字节数组。

注意!FLV 文件中第一个 VIDEOTAG 的 VIDEODATA 的 AVCVIDEOPACKET 的 Data 总是 AVCDecoderConfigurationRecord(在 ISO/IEC 14496-15 中定义),解码的时候注意跳过这个 VIDOETAG。

AVCDecoderConfigurationRecord 结构的定义:

aligned(8) class AVCDecoderConfigurationRecord {
unsigned int(8) configurationVersion = 1;
unsigned int(8) AVCProfileIndication;
unsigned int(8) profile_compatibility;
unsigned int(8) AVCLevelIndication;
bit(6) reserved = ‘111111’b;
unsigned int(2) lengthSizeMinusOne;
bit(3) reserved = ‘111’b;
unsigned int(5) numOfSequenceParameterSets;
for (i=0; i< numOfSequenceParameterSets; i++) {
unsigned int(16) sequenceParameterSetLength ;
bit(8*sequenceParameterSetLength) sequenceParameterSetNALUnit;
}
unsigned int(8) numOfPictureParameterSets;
for (i=0; i< numOfPictureParameterSets; i++) {
unsigned int(16) pictureParameterSetLength;
bit(8*pictureParameterSetLength) pictureParameterSetNALUnit;
}
}

下面蓝色的部分就是 FLV 文件中的 AVCDecoderConfigurationRecord 部分。

00000130h: 00 00 00 17 00 00 00 00 01 4D 40 15 FF E1 00 0A ; .........M@.?.
00000140h: 67 4D 40 15 96 53 01 00 4A 20 01 00 05 68 E9 23 ; gM@.朣..J ...h?
00000150h: 88 00 00 00 00 2A 08 00 00 52 00 00 00 00 00 00 ; ?...*...R......

根据 AVCDecoderConfigurationRecord 结构的定义:

  • configurationVersion = 01
  • AVCProfileIndication = 4D
  • profile_compatibility = 40
  • AVCLevelIndication = 15
  • lengthSizeMinusOne = FF <- 非常重要,是 H.264 视频中 NALU 的长度,计算方法是 1 + (lengthSizeMinusOne & 3)
  • numOfSequenceParameterSets = E1 <- SPS 的个数,计算方法是 numOfSequenceParameterSets & 0x1F
  • sequenceParameterSetLength = 00 0A <- SPS 的长度
  • sequenceParameterSetNALUnits = 67 4D 40 15 96 53 01 00 4A 20 <- SPS
  • numOfPictureParameterSets = 01 <- PPS 的个数
  • pictureParameterSetLength = 00 05 <- PPS 的长度
  • pictureParameterSetNALUnits = 68 E9 23 88 00 <- PPS

因此 CodecPrivateData 的字符串表示就是 000001674D4015965301004A2000000168E9238800

但是设置 MediaStreamAttributeKeys.CodecPrivateData 是没用的(只有 H.264 是这样,其他类型的视频流仍然需要设置),只有将 CodecPrivateData 写入 H.264 视频流第一帧数据的前面 Silverlight 才能正常解码。

也就是说,Silverlight 的 H.264 解码器会读取第一帧前面的 CodecPrivateData 数据来进行配置。

因为 CodecPrivateData 数据已经包含视频流的解码器参数(包括视频的宽高),所以就不需要设置 MediaStreamAttributeKeys.CodecPrivateData、MediaStreamAttributeKeys.Width 和 MediaStreamAttributeKeys.Height 了。

计算 NALU 得到帧数据

FLV 文件中 VIDEOTAG 的 VIDEODATA 的 AVCVIDEOPACKET 的 Data 不是原始视频帧数据,而是一个或更多个 NALU 数据片段。在这篇文章中,你认为 H.264 视频帧数据是由多个 NALU 组成的。当然实际上并不是这样,关于这部分的概念请自行 Google,本文将不做讨论。

下面是 FLV 文件中 VIDEOTAG 的 VIDEODATA 的 AVCVIDEOPACKET 的 Data 属性的数据(第一帧数据)。

  • 红色的部分是 NALU 数据的长度,而红色部分的长度则由 lengthSizeMinusOne 决定。
  • 蓝色的部分是 NALU 数据部分。
  • 删除的部分是废弃的数据。

00000300h: 00 00 00 00 00 17 01 00 00 22 00 00 00 31 65 88 ; ........."...1e?
00000310h: 80 40 05 B7 95 53 67 FF 84 6C 07 EB 00 F8 45 FB ; €@.窌Sg刲.?鳨?
00000320h: F9 15 71 0D A4 C5 2C 00 00 03 00 00 03 00 3F 2B ; ?q.づ,.......?+
00000330h: 5B 06 57 48 29 F4 08 00 00 0A 10 02 D0 7A FE 00 ; [.WH)?.....衵?
00000340h: 00 00 38 65 01 22 22 01 00 17 B7 95 53 67 FF 84 ; ..8e.""...窌Sg?
00000350h: 6C 07 EB 00 F8 45 FB F9 15 71 0D A4 C5 2C 00 E8 ; l.?鳨.q.づ,.?
00000360h: F3 37 75 43 90 00 00 03 00 15 EF AA A8 53 86 01 ; ?uC?....铼⊿?
00000370h: DD 57 60 00 00 03 01 59 0C F4 3C 00 00 00 33 65 ; 軼`....Y.?...3e
00000380h: 00 90 88 80 40 05 B7 95 53 67 FF 84 6C 07 EB 00 ; .悎€@.窌Sg刲.?
00000390h: F8 45 FB F9 15 71 0D A4 C5 2C 00 00 03 00 00 03 ; 鳨.q.づ,......
000003a0h: 00 3F 2B 5B 06 57 48 29 F4 08 00 00 0A 10 02 D0 ; .?+[.WH)?.....?
000003b0h: 7A FE 00 00 00 38 65 00 D8 88 80 40 05 B7 95 53 ; z?..8e.貓€@.窌S
000003c0h: 67 FF 84 6C 07 EB 00 F8 45 FB F9 15 71 0D A4 C5 ; g刲.?鳨.q.づ
000003d0h: 2C 00 E8 F3 37 75 43 90 00 00 03 00 15 EF AA A8 ; ,.梵7uC?....铼?
000003e0h: 53 86 01 DD 57 60 00 00 03 01 59 0C F4 3C 00 00 ; S?軼`....Y.?..
000003f0h: 00 F4 08 00 01 33 00 00 17 00 00 00 00 AF 01 27 ; .?..3.......?'

帧数据是将多个 NALU 使用 byte[] {00, 00, 01} 连接的字节数组。

byte[] = {

00,00,01,65,88,
80,40,05,B7,95,53,67,FF,84,6C,07,EB,00,F8,45,FB,
F9,15,71,0D,A4,C5,2C,00,00,03,00,00,03,00,3F,2B,
5B,06,57,48,29,F4,08,00,00,0A,10,02,D0,7A,FE,

00,00,01,65,01,22,22,01,00,17,B7,95,53,67,FF,84,
6C,07,EB,00,F8,45,FB,F9,15,71,0D,A4,C5,2C,00,E8,
F3,37,75,43,90,00,00,03,00,15,EF,AA,A8,53,86,01,
DD,57,60,00,00,03,01,59,0C,F4,3C,

00,00,01,65,
00,90,88,80,40,05,B7,95,53,67,FF,84,6C,07,EB,00,
F8,45,FB,F9,15,71,0D,A4,C5,2C,00,00,03,00,00,03,
00,3F,2B,5B,06,57,48,29,F4,08,00,00,0A,10,02,D0,
7A,FE,

00,00,01,65,00,D8,88,80,40,05,B7,95,53,
67,FF,84,6C,07,EB,00,F8,45,FB,F9,15,71,0D,A4,C5,
2C,00,E8,F3,37,75,43,90,00,00,03,00,15,EF,AA,A8,
53,86,01,DD,57,60,00,00,03,01,59,0C,F4,3C

};


如果是第一帧数据,那么前面还要加上 CodecPrivateData 数据。

byte[] = {

00,00,01,67,4D,40,15,96,53,01,00,4A,20,

00,00,01,68,E9,23,88,00,

00,00,01,65,88,
80,40,05,B7,95,53,67,FF,84,6C,07,EB,00,F8,45,FB,
F9,15,71,0D,A4,C5,2C,00,00,03,00,00,03,00,3F,2B,
5B,06,57,48,29,F4,08,00,00,0A,10,02,D0,7A,FE,

00,00,01,65,01,22,22,01,00,17,B7,95,53,67,FF,84,
6C,07,EB,00,F8,45,FB,F9,15,71,0D,A4,C5,2C,00,E8,
F3,37,75,43,90,00,00,03,00,15,EF,AA,A8,53,86,01,
DD,57,60,00,00,03,01,59,0C,F4,3C,

00,00,01,65,
00,90,88,80,40,05,B7,95,53,67,FF,84,6C,07,EB,00,
F8,45,FB,F9,15,71,0D,A4,C5,2C,00,00,03,00,00,03,
00,3F,2B,5B,06,57,48,29,F4,08,00,00,0A,10,02,D0,
7A,FE,

00,00,01,65,00,D8,88,80,40,05,B7,95,53,
67,FF,84,6C,07,EB,00,F8,45,FB,F9,15,71,0D,A4,C5,
2C,00,E8,F3,37,75,43,90,00,00,03,00,15,EF,AA,A8,
53,86,01,DD,57,60,00,00,03,01,59,0C,F4,3C

};

相关文章:

  • PHP导出数据到淘宝助手CSV的方法分享
  • 公司最近招招.net程序员
  • 从一棵“微博树”透视物联网的未来
  • 挚爱一生---结婚周年纪念
  • 我对国内软件开发类书籍出版与写作的体会与努力
  • 『软件周边』ColorSchemer Studio 2.0 注册码
  • 转 如何有效的使用C#读取文件 及如何解决中文乱码问题
  • 说出你的想法,赢取Windows Phone 7手机
  • 读了本书, 发现百度要比想象的有意思多了
  • ArcSDE vs. Oracle Spatial 12
  • 0318 NEEK_VIP_demo_LCD_SVGA_成功修改
  • ArcSDE vs. Oracle Spatial 13
  • JQuery 模式窗口插件
  • 基于Windows Phone的对讲机
  • Cheatsheet: 2010 04.01 ~ 04.07
  • JavaScript-如何实现克隆(clone)函数
  • Dubbo 整合 Pinpoint 做分布式服务请求跟踪
  • ECMAScript6(0):ES6简明参考手册
  • github指令
  • HTML中设置input等文本框为不可操作
  • httpie使用详解
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • iOS编译提示和导航提示
  • Java精华积累:初学者都应该搞懂的问题
  • Js基础——数据类型之Null和Undefined
  • LeetCode541. Reverse String II -- 按步长反转字符串
  • redis学习笔记(三):列表、集合、有序集合
  • 给第三方使用接口的 URL 签名实现
  • 湖南卫视:中国白领因网络偷菜成当代最寂寞的人?
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 前端技术周刊 2019-01-14:客户端存储
  • 无服务器化是企业 IT 架构的未来吗?
  • 数据可视化之下发图实践
  • #基础#使用Jupyter进行Notebook的转换 .ipynb文件导出为.md文件
  • $.each()与$(selector).each()
  • (007)XHTML文档之标题——h1~h6
  • (12)Hive调优——count distinct去重优化
  • (4) PIVOT 和 UPIVOT 的使用
  • (TOJ2804)Even? Odd?
  • (附源码)ssm本科教学合格评估管理系统 毕业设计 180916
  • (十八)SpringBoot之发送QQ邮件
  • (转)linux自定义开机启动服务和chkconfig使用方法
  • (转)mysql使用Navicat 导出和导入数据库
  • ./indexer: error while loading shared libraries: libmysqlclient.so.18: cannot open shared object fil
  • .bat批处理(六):替换字符串中匹配的子串
  • .MSSQLSERVER 导入导出 命令集--堪称经典,值得借鉴!
  • .net core开源商城系统源码,支持可视化布局小程序
  • .NET gRPC 和RESTful简单对比
  • .NET 反射的使用
  • .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态
  • .NET简谈互操作(五:基础知识之Dynamic平台调用)
  • @WebServiceClient注解,wsdlLocation 可配置
  • [ SNOI 2013 ] Quare
  • [.NET]桃源网络硬盘 v7.4