zoukankan      html  css  js  c++  java
  • 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

    };

  • 相关阅读:
    7-2 一元多项式的乘法与加法运算 (20 分)
    cvc-complex-type.2.4.a: Invalid content was found starting with element(servlet)
    MOOC 2.3 队列
    MOOC 2.2 堆栈
    MOOC 2.1 线性表及其实现
    MOOC 1.3 最大子列和
    计时程序
    MOOC 1.1 什么是数据结构
    poj3253
    二分法查找——对数
  • 原文地址:https://www.cnblogs.com/k1988/p/2165642.html
Copyright © 2011-2022 走看看