• (转)h264中avc和flv数据的解析


    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

    };

  • 相关阅读:
    9.Vue技术栈开发实战-使用Mock模拟Ajax请求
    8.Vue技术栈开发实战-Ajax请求实战
    7.Vue技术栈开发实战-状态管理Vuex进阶
    6.Vue技术栈开发实战-状态管理Vuex(二)
    5.Vue技术栈开发实战-状态管理Vuex(一)
    4.Vue技术栈开发实战-状态管理bus的使用
    3.Vue技术栈开发实战-路由进阶篇
    2.Vue技术栈开发实战-路由基础篇
    Vue技术栈开发实战_汇总贴
    1.Vue技术栈开发实战-使用vue-cli3创建项目
  • 原文地址:https://www.cnblogs.com/zjoch/p/3286298.html
Copyright © 2020-2023  润新知