0%

video_h264

几个概念认识:

h.264,avc, avcc,annexb, h.265,hevc,av1等概念的理解:

  • h.264/avc: 这两个其实是一样的概念,avc是advance video coding的简称,要说不一样的话,avc限定了一些封装的格式和要求,且支持mvc和svc
    而h.264则更加靠近编码层面。比如h.264支持使用annexb或avcc方式封装,而avc不支持annexb .
  • avcc,annexb是两种不同的封装h.264的nalu的方式,前者更靠近容器文件,后者更靠近流媒体,下详述。且avc不支持annexb,flv只支持avc的话,也不能封为annexb
  • h.265是H.264的升级版,hevc是avc的升级版,av1是google开发对标h.265的协议。

AnnexB,AVCC,RBSP,等概念

1 AnnexB,AVCC,HVCC
H.264码流分Annex-B和AVCC两种格式
H.265码流是Annex-B和HVCC格式。

  • AVCC格式 也叫AVC1格式,MPEG-4格式,字节对齐,因此也叫Byte-Stream Format。用于mp4/flv/mkv, VideoToolbox。
  • Annex-B格式 也叫MPEG-2 transport stream format格式(ts格式), ElementaryStream格式。
    2 AnnexB和AVCC的区别:
    区别有两点:一个是参数集(SPS, PPS)组织格式;一个是分隔。
  • Annex-B:使用start code分隔NAL(start code为三字节或四字节,0x000001或0x00000001,一般是四字节);SPS和PPS按流的方式写在头部。
  • AVCC:使用NALU长度(固定字节,通常为4字节)分隔NAL;在头部包含extradata(或sequence header)的结构体。(extradata包含分隔的字节数、SPS和PPS,具体结构见下)
  • AnnexB:
  1. AnnexB格式—-用于实时播放
    处于H264文档附录B(Annex-B Byte stream format)中
    开始前缀start code(00000001或000001)+NALU数据  绝大部分编码器的默认输出格式
      一共有两种起始码start_code
       ①3字节0x000001  单帧多slice(即单帧多个NALU)之间间隔
       ②4字节0x00000001 帧之间,或者SPS等之前
    4字节类型的开始码在在连续的数据传输中非常有用,因为用字节来对齐、分割流数据,比如:用连续的31个bit0后接一个bit1来分割流数据,是很容易的。

  2. 格式:
    AnnexB格式每个NALU都包含起始码,且通常会周期性的在关键帧之前重复SPS和PPS,所以解码器可以从视频流随机点开始进行解码,实时的流格式
    AnnexB format: In annexb, [start code] may be 0x000001 or 0x00000001.
    ([start code] NALU) | ( [start code] NALU) | more detail: ([start code] SPS NALU) | ( [start code] PPS NALU) ([start code] NALU) | ( [start code] NALU)

  3. FLV可能封装形式:
    flv格式不支持封装annexB ,但若想基于flv去做强制封装,可以://最好不要这么做

    1
    2
    3
    对AnnexB:  
    AVCC头,塞两个NALU sps pps
    AVC数据:起始码 nalu
  4. 关于RBSP和AnnexB如何处理竞争码:
    RBSP:是没有竞争码字节的NALU即RBSP:A NALU representation without emulation prevention bytes is called a Raw Byte Sequence Payload, or RBSP
    为啥需要竞争码?
    我们知道,AnnexB是通过start code(上述)来分割Nalu的,但如果Nalu数据中就有start_code,这个时候分割就会出现问题,如何处理?
    spec这样处理,认为四字节序列0x00000000、0x00000001、0x00000002和0x00000003在非rbsp NALU中是非法的,因此进行字节填充:
    为了将RBSP转换为具有开始代码的NALU,字节填充是通过在两个连续的0x00字节之后插入一个预防字节0x03(竞争码)来实现的。所以,要反转这种情况,在读取流时,删除两个连续的0x00字节之后的任何0x03。
    才能还原原始的RBSP.
    要确定NALU的长度,从一个字节流开始(它将有一个开始代码),跳到下一个开始代码,并计算中间的字节数。

  • AVCC:
  1. AVCC—用于存储
    解码器配置参数在一开始就配置好了,系统可以很容易的识别NALU的边界,不需要额外的起始码,减少了资源的浪费,同时可以在播放时调到视频的中间位置。这种格式通常被用于可以被随机访问的多媒体数据,如存储在硬盘的文件。MP4、MKV通常用AVCC格式来存储。

AVCC格式不使用起始码作为NALU的分界,这种格式在每个NALU前都加上一个大端格式的前缀(1、2、4字节,代表NALU长度)
所以在解析AVCC格式的时候需要将指定的前缀字节数的值保存在一个头部对象中,这个都通常称为extradata或者sequence header。同时,SPS和PPS数据也需要保存在extradata或者叫’sequence header’中。
H.264 extradata / sequence header

  1. AVCC format:
    ([extradata]) | ([length] NALU) | ([length] NALU) |

In avcc, the bytes of [length] depends on NALULengthSizeMinusOne in avcc extradata, the value of [length] depends on the size of following NALU and in both annexb and avcc format, the NALUs are no different.

AVCC中的extradata格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
An AVCC stream always starts with a specific header
- 8 bits = 0x01 (this is illegal in Annex B)
- 8 bits of avc profile (from sps[0][1])
- 8 bits of avc compatibility (from sps[0][2])
- 8 bits of avc level (from sps[0][3])
- 6 bits = 0b111111
- 2 bits of NALULengthSizeMinusOne (typically 3)
- 3 bits of 0b111
- 5 bits of number of SPS NALU (usually 1)
- Repeated per SPS
- 16 bits of SPS size -
- Variable SPS NALU data
- 8 bits of number of PPS NALU (usually 1)
- Repeated once per PPS
- 16 bits of PPS size
- Variable PPS NALU data

ref:http://neurocline.github.io/dev/2016/07/28/video-and-containers.html
  1. FLV streams must be written as AVCC.
    AVCC封装到flv:
    对AVCC:
    AVC 头: flvtag + flvvideotag + extradata + pretagsize
    AVC 数据: flvtag + flvvideotag + 长度 + nalu 长度+nalu ,..+ pretagsize ,一个tag可能有多个nalu,但是不会跨

RTP封装:转换为rtp: 去掉起始码,带nalu长度,头和数据,如果是IDR,需要在前面加sps pps nalu

  • H264的流,封装nalu的方式常见分为两种,Annex B和 AVCC ,其实还有Annex A。。。

nalu

字段描述规定:

The following descriptors specify the parsing process of each syntax element. For some syntax elements, two descriptors, separated by a vertical bar, are used. In these cases, the left descriptors apply when entropy_coding_mode_flag is equal to 0 and the right descriptor applies when entropy_coding_mode_flag is equal to 1.以下描述符指定了每个语法元素的解析过程。对于某些语法元素,使用两个描述符,用竖线分隔。在这些情况下,当 entropy_coding_mode_flag 等于 0 时应用左描述符,当 entropy_coding_mode_flag 等于 1 时应用右描述符。
– ae(v): context-adaptive arithmetic entropy-coded syntax element. The parsing process for this descriptor is specified in clause 9.3.上下文自适应算术熵编码语法元素。该描述符的解析过程在第 9.3 节中规定
– b(8): byte having any pattern of bit string (8 bits). The parsing process for this descriptor is specified by the return value of the function read_bits( 8 ).具有任何位串模式(8 位)的字节。该描述符的解析过程由函数 read_bits(8) 的返回值指定。
– ce(v): context-adaptive variable-length entropy-coded syntax element with the left bit first. The parsing process for this descriptor is specified in clause 9.2.上下文自适应可变长度熵编码语法元素,左位在前。该描述符的解析过程在第 9.2 节中规定。
– f(n): fixed-pattern bit string using n bits written (from left to right) with the left bit first. The parsing process for this descriptor is specified by the return value of the function read_bits( n ).固定模式位串使用 n 位写入(从左到右),左位在前。该描述符的解析过程由函数 read_bits( n ) 的返回值指定。
– i(n): signed integer using n bits. When n is “v” in the syntax table, the number of bits varies in a manner dependent on the value of other syntax elements. The parsing process for this descriptor is specified by the return value of the function read_bits( n ) interpreted as a two’s complement integer representation with most significant bit written first.使用 n 位的有符号整数。当语法表中的n为“v”时,比特数以依赖于其他语法元素的值的方式变化。该描述符的解析过程由函数 read_bits( n ) 的返回值指定,解释为二进制补码整数表示,最高有效位首先写入。
– me(v): mapped Exp-Golomb-coded syntax element with the left bit first. The parsing process for this descriptor is specified in clause 9.1.映射 Exp-Golomb 编码的语法元素,左位在前。该描述符的解析过程在第 9.1 节中规定。
– se(v): signed integer Exp-Golomb-coded syntax element with the left bit first. The parsing process for this descriptor is specified in clause 9.1.左位在前的有符号整数 Exp-Golomb 编码语法元素。该描述符的解析过程在第 9.1 节中规定。
– te(v): truncated Exp-Golomb-coded syntax element with left bit first. The parsing process for this descriptor is specified in clause 9.1.截断的 Exp-Golomb 编码语法元素,左位在前。该描述符的解析过程在第 9.1 节中规定。
– u(n): unsigned integer using n bits. When n is “v” in the syntax table, the number of bits varies in a manner dependent on the value of other syntax elements. The parsing process for this descriptor is specified by the return value of the function read_bits( n ) interpreted as a binary representation of an unsigned integer with most significant bit written first.使用 n 位的无符号整数。当语法表中的n为“v”时,比特数以依赖于其他语法元素的值的方式变化。该描述符的解析过程由函数 read_bits( n ) 的返回值指定,该函数解释为无符号整数的二进制表示,最高有效位首先写入。
– ue(v): unsigned integer Exp-Golomb-coded syntax element with the left bit first. The parsing process for this descriptor is specified in clause 9.1.无符号整数 Exp-Golomb 编码的语法元素,左位在前。该描述符的解析过程在第 9.1 节中规定。

1
2
3
4
5
6
1 b(8),f(n), 基于read_bits,讲究顺序性。后者可以读取多个bit,  
2. i(n), u(n),两者的区别是一个是有符号的整数,一个是无符号的。 两个都是基于read_bits,但是支持可变的长度,长度由另一个字段决定;
seq_parameter_set_data( ) 中获得的一对语法元素 log2_max_frame_num_minus4 [ue(v)] 和在 slice_header( ) 中获得的 frame_num [u(v)] 就是一个很好的例子,其中 frame_num = log2_max_frame_num_minus4 + 4
假设 log2_max_frame_num_minus4 = 4(参考下一节关于解析 ue(v)),那么 frame_num = 4 + 4 = 8。所以,为了得到 frame_num 的值,你可以用 u(8) = b(8)= f(8) = read_bits( 8 ) 解析比特流。
3. ue(v), te(v), se(v), me(v)
这些都是 Exp-Golomb 编码。要解码,您需要一个可以通过以下方式计算的 codeNum:

ref:
https://yumichan.net/video-processing/video-compression/explanation-of-descriptors-in-itu-t-publication-on-h-264-coding-standardrecommendation-with-example/

rfc: file:///C:/Users/Administrator/Downloads/T-REC-H.264-200503-S!!PDF-E.pdf

nalu 格式:

ref: https://yumichan.net/video-processing/video-compression/introduction-to-h264-2-sodb-vs-rbsp-vs-ebsp/

  • 整体格式:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    nalu header format:  F(1) NRI(2) TYPE(5)
    nal_unit( NumBytesInNALunit ) { C Descriptor
    // NAL Unit Header 1Byte
    forbidden_zero_bit All f(1) 第一位
    nal_ref_idc All u(2) 2bit
    nal_unit_type All u(5) 5bit
    NumBytesInRBSP = 0
    //下面的过程是为了去掉 0x03 ,因为编码时会加入
    for( i = 1; i < NumBytesInNALunit; i++ ) {
    if( i + 2 < NumBytesInNALunit && next_bits( 24 ) = = 0x000003 ) {
    rbsp_byte[ NumBytesInRBSP++ ] All b(8)
    rbsp_byte[ NumBytesInRBSP++ ] All b(8)
    i += 2
    emulation_prevention_three_byte /* equal to 0x03 */ All f(8)
    } else
    rbsp_byte[ NumBytesInRBSP++ ] All b(8)
    }
    }
    SODB + RBSP Stop bit + 0 bit(s) => RBSP
    对AnnexB:
    RBSP part 1 + 0x03 + RBSP part 2 + 0x03 + … + RBSP part n => EBSP
    NALU Header + EBSP => NALU

In Byte Stream Format (Annex B),
Start Code + NALU + … + Start Code + NALU => H.264 Byte Stream

对AVCC 略,参考上面

  • example:

    1
    2
    3
    4
    5
    6
    7
    8
    eg:
    Hex Binary
    0x67 0110 0111

    So, for 0x67, we have:
    forbidden_zero_bit = 0,
    nal_ref_idc = 3,
    nal_unit_type = 7
  • 字段解释:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    forbidden_zero_bit: 1bit
    The 1st bit is forbidden_zero_bit which is used to check whether there is any error occurred during the transmission. 0 means that it is normal while 1 indicates a syntax violation. So, we should always find that forbidden_zero_bit equals 0. 检查是否传输错误,0表示没有,1表示有错误。

    nal_ref_idc: 2bit
    nal_ref_idc not equal to 0 specifies that the content of the NAL unit contains a sequence parameter set or a picture parameter set or a slice of a reference picture or a slice data partition of a reference picture. 不为0表示包含一个sps或pps,或一个参考帧slice或一个参考帧的一部分slice数据
    nal_ref_idc equal to 0 for a NAL unit containing a slice or slice data partition indicates that the slice or slice data partition is part of a non-reference picture. 为0表示,在NALU单元中,表示包含一个slice或slice data部分,不是参考帧
    nal_ref_idc shall not be equal to 0 for sequence parameter set or sequence parameter set extension or picture parameter set NAL units. When nal_ref_idc is equal to 0 for one slice or slice data partition NAL unit of a particular picture, it shall be equal to 0 for all slice and slice data partition NAL units of the picture.
    nal_ref_idc shall not be equal to 0 for IDR NAL units, i.e., NAL units with nal_unit_type equal to 5.
    nal_ref_idc shall be equal to 0 for all NAL units having nal_unit_type equal to 6, 9, 10, 11, or 12.
    总结:
    nal_ref_idc indicating whether this NAL unit is a reference field / frame / picture. 是否是一个参考帧或图片
    On one hand, if it is a reference field / frame / picture, nal_ref_idc is not equal to 0. 若是,则不为0
    根据建议,非0,则表示nalu单元的内容包含一个sps,一个sps扩展,一个sps子集,一个PPS,一个参考帧的slice,一个参考帧中的一个slice部分,或一个在参考图像的切片之前的一种前缀NAL单元。
    另一方面,若不是一个参考帧,则这个值是0
    对任何非0 的值,值越大,则越重要。 在这里 它是0x11,实际上它是一个sps

    nal_unit_type
    nalu 单元类型:
    指定NAL单元中包含的RBSP数据结构的类型,如表所示。VCL NAL单位被指定为nal_unit_type等于15的NAL单位。所有剩余的NAL单位称为非vcl NAL单位。
    1 非IDR slice
    2 -4 parg of slice
    5 IDR slice
    6 sei
    7 sps
    8 pps
    9: access unit delimiter: 访问单元分隔符可用于指示主编码图像中出现的片的类型,并简化对访问单元之间边界的检测。没有与访问单元分隔符关联的规范解码过程
    {
    语法:
    access_unit_delimiter_rbsp( ) { C Descriptor
    primary_pic_type 6 u(3) 3bit
    rbsp_trailing_bits( ) 6
    }
    primary_pic_type表示主代码图片的所有切片的slice_type值都是给定primary_pic_type值的表7-5中列出的集合的成员。

    primary_pic_type slice_type values that may be present in the primary coded picture
    0 I
    1 I, P
    2 I, P, B
    3 SI
    4 SI, SP
    5 I, SI
    6 I, SI, P, SP
    7 I, SI, P, SP, B
    }
    10 End of sequence RBSP semantics;
    序列结束RBSP指定在解码顺序位流中(如果有)下一个后续访问单元为IDR访问单元。序列RBSP结尾的SODB和RBSP语法内容为空。没有为序列RBSP的结束指定规范的解码过程。

    11 End of Stream:
    流RBSP结束表示在解码顺序上,流RBSP结束后的位流中不应出现任何额外的NAL单元。流RBSP结束时的SODB和RBSP语法内容为空。没有为流RBSP的结束指定标准解码过程。
    ...
    more: spec:
    Table 7-1 – NAL unit type codes, syntax element categories, and NAL unit type classes

标记为C的列列出了NAL单元中可能存在的语法元素的类别。此外,还可能存在语法类别为All的语法元素,这是由RBSP数据结构的语法和语义决定的。具体列出的类别中是否存在任何语法元素,取决于相关RBSP数据结构的语法和语义。nal_unit_type不应该等于3或4,除非在RBSP数据结构中存在至少一个语法元素,其语法元素类别值等于nal_unit_type的值,而不是分类为All。
具有nal_unit_type等于13和19的NAL单元可能被解码器丢弃,而不影响对具有nal_unit_type不等于13或19的NAL单元的解码过程,且不影响符合此国际标准

对应的NRI 值

1
2
3
4
5
6
7
8
Nal Unit Type                             Possible nal_ref_idc value
14 If one of the NALU is 0, all NAL units with Type in the tang of 14, inclusive, of the picture are 0
5 Coded slice of an IDR picture non-zero IDR picture
7 Sequence parameter set non-zero sps
8 Picture parameter set non-zero pps
13 Sequence parameter set extension non-zero
15 Subset sequence parameter set non-zero
6, 9, 10, 11 or 12 0
  • rbsp构成:
    rbsp_trailing_bits( ) 5 即在nalu中提到的,用来做stop和align的bits: 如下

    1
    2
    rbsp_stop_one_bit = 1
    rbsp_alignment_zero_bit(s) = 0(s) [[Must make the SODB byte-aligned]]
  • sps格式:

  • pps格式:

  • sei:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    sei_rbsp( ) {                     C Descriptor
    do
    sei_message( ) 5
    while( more_rbsp_data( ) )
    rbsp_trailing_bits( ) 5

    sei_message( ) { C Descriptor
    payloadType = 0
    while( next_bits( 8 ) = = 0xFF ) {
    ff_byte /* equal to 0xFF */ 5 f(8)
    payloadType += 255
    }
    last_payload_type_byte 5 u(8)
    payloadType += last_payload_type_byte
    payloadSize = 0
    while( next_bits( 8 ) = = 0xFF ) {
    ff_byte /* equal to 0xFF */ 5 f(8)
    payloadSize += 255
    }
    last_payload_size_byte 5 u(8)
    payloadSize += last_payload_size_byte
    sei_payload( payloadType, payloadSize ) 5
    }
  • slice格式:一个Nalu一般是一个slice?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59

    Slice layer without partitioning RBSP syntax
    slice_layer_without_partitioning_rbsp( ) { C Descriptor
    slice_header( ) 2
    slice_data( ) /* all categories of slice_data( ) syntax */ 2 | 3 | 4
    rbsp_slice_trailing_bits( ) 2
    }

    Slice data partition RBSP syntax
    1 Slice data partition A RBSP syntax
    slice_data_partition_a_layer_rbsp( ) { C Descriptor
    slice_header( ) 2
    slice_id All ue(v)
    slice_data( ) /* only category 2 parts of slice_data( ) syntax */ 2
    rbsp_slice_trailing_bits( ) 2
    }


    Slice data partition B RBSP syntax
    slice_data_partition_b_layer_rbsp( ) { C Descriptor
    slice_id All ue(v)
    if( redundant_pic_cnt_present_flag )
    redundant_pic_cnt All ue(v)
    slice_data( ) /* only category 3 parts of slice_data( ) syntax */ 3
    rbsp_slice_trailing_bits( ) 3
    }

    Slice data partition C RBSP syntax
    slice_data_partition_c_layer_rbsp( ) { C Descriptor
    slice_id All ue(v)
    if( redundant_pic_cnt_present_flag )
    redundant_pic_cnt All ue(v)
    slice_data( ) /* only category 4 parts of slice_data( ) syntax */ 4
    rbsp_slice_trailing_bits( ) 4
    }


    ------------------------------------------------------------
    RBSP slice trailing bits syntax
    rbsp_slice_trailing_bits( ) { C Descriptor
    rbsp_trailing_bits( ) All
    if( entropy_coding_mode_flag )
    while( more_rbsp_trailing_data( ) )
    cabac_zero_word /* equal to 0x0000 */ All f(16)
    }


    RBSP trailing bits syntax
    rbsp_trailing_bits( ) { C Descriptor
    rbsp_stop_one_bit /* equal to 1 */ All f(1)
    while( !byte_aligned( ) )
    rbsp_alignment_zero_bit /* equal to 0 */ All f(1)
    }


    ----------------------------------------------

    slice_header( ) {
    ...

    srs如何处理AnnexB和AVCC:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    1 在收到rtmp包时,其实携带的是flv tag,所以会从flv tag入手解析:
    若是avc header时,srs假定不管是avcc还是annexB都是把 sps,pps以 extradata形式放在avc header的,实际上annexB标准并不是extradata;

    若不是avc header,srs解析 avcc和annexB的nalu ,这个时候前者通过长度来分离nalu到sample数组,后者通过起始码来分离nalu到数组;


    代码如下:
    srs_error_t SrsFormat::on_video(int64_t timestamp, char* data, int size)
    {
    srs_error_t err = srs_success;

    if (!data || size <= 0) {
    srs_trace("no video present, ignore it.");
    return err;
    }

    SrsBuffer* buffer = new SrsBuffer(data, size);
    SrsAutoFree(SrsBuffer, buffer);

    // We already checked the size is positive and data is not NULL.
    srs_assert(buffer->require(1));

    // @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78
    int8_t frame_type = buffer->read_1bytes();
    SrsVideoCodecId codec_id = (SrsVideoCodecId)(frame_type & 0x0f);

    // TODO: Support other codecs.
    if (codec_id != SrsVideoCodecIdAVC) {
    return err;
    }

    if (!vcodec) {
    vcodec = new SrsVideoCodecConfig();
    }
    if (!video) {
    video = new SrsVideoFrame();
    }

    if ((err = video->initialize(vcodec)) != srs_success) {
    return srs_error_wrap(err, "init video");
    }

    buffer->skip(-1 * buffer->pos());
    return video_avc_demux(buffer, timestamp);
    }
    srs_error_t SrsFormat::video_avc_demux(SrsBuffer* stream, int64_t timestamp)
    {
    srs_error_t err = srs_success;

    // @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78
    int8_t frame_type = stream->read_1bytes();
    SrsVideoCodecId codec_id = (SrsVideoCodecId)(frame_type & 0x0f);//flvvideotagheader codecid: avc
    frame_type = (frame_type >> 4) & 0x0f;//frametype(UB[4]): avc key frame or

    video->frame_type = (SrsVideoAvcFrameType)frame_type;

    // ignore info frame without error,
    // @see https://github.com/ossrs/srs/issues/288#issuecomment-69863909
    if (video->frame_type == SrsVideoAvcFrameTypeVideoInfoFrame) {
    srs_warn("avc igone the info frame");
    return err;
    }

    // only support h.264/avc
    if (codec_id != SrsVideoCodecIdAVC) {
    return srs_error_new(ERROR_HLS_DECODE_ERROR, "avc only support video h.264/avc, actual=%d", codec_id);
    }
    vcodec->id = codec_id;

    if (!stream->require(4)) {
    return srs_error_new(ERROR_HLS_DECODE_ERROR, "avc decode avc_packet_type");
    }
    int8_t avc_packet_type = stream->read_1bytes();//avc sequence header or avc nalu
    int32_t composition_time = stream->read_3bytes();//compostion time cts

    // pts = dts + cts.
    video->dts = timestamp;
    video->cts = composition_time;
    video->avc_packet_type = (SrsVideoAvcFrameTrait)avc_packet_type;

    // Update the RAW AVC data.
    raw = stream->data() + stream->pos();
    nb_raw = stream->size() - stream->pos();

    if (avc_packet_type == SrsVideoAvcFrameTraitSequenceHeader) {//如果是avc 头
    // TODO: FIXME: Maybe we should ignore any error for parsing sps/pps.
    if ((err = avc_demux_sps_pps(stream)) != srs_success) {//提取sps pps,后面遇到idr时要用
    return srs_error_wrap(err, "demux SPS/PPS");
    }
    } else if (avc_packet_type == SrsVideoAvcFrameTraitNALU){//是nalu数据,
    if ((err = video_nalu_demux(stream)) != srs_success) {
    return srs_error_wrap(err, "demux NALU");
    }
    } else {
    // ignored.
    }

    return err;
    }
    //提取sps pps,以extradata方式来解析:
    srs_error_t SrsFormat::avc_demux_sps_pps(SrsBuffer* stream)
    {
    // AVCDecoderConfigurationRecord
    // 5.2.4.1.1 Syntax, ISO_IEC_14496-15-AVC-format-2012.pdf, page 16
    int avc_extra_size = stream->size() - stream->pos();
    if (avc_extra_size > 0) {
    char *copy_stream_from = stream->data() + stream->pos();
    vcodec->avc_extra_data = std::vector<char>(copy_stream_from, copy_stream_from + avc_extra_size);
    }

    if (!stream->require(6)) {
    return srs_error_new(ERROR_HLS_DECODE_ERROR, "avc decode sequence header");
    }
    //int8_t configurationVersion = stream->read_1bytes();
    uint8_t confversion = stream->read_1bytes();
    if(confversion == 0)//avcc version == 1 ,annexb 东家 = 0 start code
    {
    annexb_demux_sps_pps(stream); //因为主播网是在avc header带两个nalu表示sps pps,所以这里加了代码;
    }
    //int8_t AVCProfileIndication = stream->read_1bytes();
    vcodec->avc_profile = (SrsAvcProfile)stream->read_1bytes();
    //int8_t profile_compatibility = stream->read_1bytes();
    stream->read_1bytes();
    //int8_t AVCLevelIndication = stream->read_1bytes();
    vcodec->avc_level = (SrsAvcLevel)stream->read_1bytes();

    // parse the NALU size.
    int8_t lengthSizeMinusOne = stream->read_1bytes();
    lengthSizeMinusOne &= 0x03;
    vcodec->NAL_unit_length = lengthSizeMinusOne;

    // 5.3.4.2.1 Syntax, ISO_IEC_14496-15-AVC-format-2012.pdf, page 16
    // 5.2.4.1 AVC decoder configuration record
    // 5.2.4.1.2 Semantics
    // The value of this field shall be one of 0, 1, or 3 corresponding to a
    // length encoded with 1, 2, or 4 bytes, respectively.
    if (vcodec->NAL_unit_length == 2) {
    return srs_error_new(ERROR_HLS_DECODE_ERROR, "sps lengthSizeMinusOne should never be 2");
    }

    // 1 sps, 7.3.2.1 Sequence parameter set RBSP syntax
    // ISO_IEC_14496-10-AVC-2003.pdf, page 45.
    if (!stream->require(1)) {
    return srs_error_new(ERROR_HLS_DECODE_ERROR, "decode SPS");
    }
    int8_t numOfSequenceParameterSets = stream->read_1bytes();//读取sps nalu数量,后5位
    numOfSequenceParameterSets &= 0x1f;
    if (numOfSequenceParameterSets != 1) {//只允许一个sps
    return srs_error_new(ERROR_HLS_DECODE_ERROR, "decode SPS");
    }
    if (!stream->require(2)) {
    return srs_error_new(ERROR_HLS_DECODE_ERROR, "decode SPS size");
    }
    uint16_t sequenceParameterSetLength = stream->read_2bytes();//读取sps nalu长度
    if (!stream->require(sequenceParameterSetLength)) {
    return srs_error_new(ERROR_HLS_DECODE_ERROR, "decode SPS data");
    }
    if (sequenceParameterSetLength > 0) {
    vcodec->sequenceParameterSetNALUnit.resize(sequenceParameterSetLength);//将存放sps的数组设置长度
    stream->read_bytes(&vcodec->sequenceParameterSetNALUnit[0], sequenceParameterSetLength);//将sps nalu长度的数据填充到vcodec->se..结构中
    }
    // 1 pps
    if (!stream->require(1)) {
    return srs_error_new(ERROR_HLS_DECODE_ERROR, "decode PPS");
    }
    int8_t numOfPictureParameterSets = stream->read_1bytes();//读取pps数量
    numOfPictureParameterSets &= 0x1f;
    if (numOfPictureParameterSets != 1) {//只允许一个pps
    return srs_error_new(ERROR_HLS_DECODE_ERROR, "decode PPS");
    }
    if (!stream->require(2)) {
    return srs_error_new(ERROR_HLS_DECODE_ERROR, "decode PPS size");
    }
    uint16_t pictureParameterSetLength = stream->read_2bytes();//读取pps nalu长度
    if (!stream->require(pictureParameterSetLength)) {
    return srs_error_new(ERROR_HLS_DECODE_ERROR, "decode PPS data");
    }
    if (pictureParameterSetLength > 0) {
    vcodec->pictureParameterSetNALUnit.resize(pictureParameterSetLength);
    stream->read_bytes(&vcodec->pictureParameterSetNALUnit[0], pictureParameterSetLength);//同样的填充
    }

    return avc_demux_sps();
    }

    //下面是对nalu的解析,分annexB和AVCC的:
    srs_error_t SrsFormat::video_nalu_demux(SrsBuffer* stream)
    {
    srs_error_t err = srs_success;

    // ensure the sequence header demuxed
    if (!vcodec->is_avc_codec_ok()) {
    srs_warn("avc ignore type=%d for no sequence header", SrsVideoAvcFrameTraitNALU);
    return err;
    }

    // guess for the first time.
    if (vcodec->payload_format == SrsAvcPayloadFormatGuess) {
    // One or more NALUs (Full frames are required)
    // try "AnnexB" from ISO_IEC_14496-10-AVC-2003.pdf, page 211.
    if ((err = avc_demux_annexb_format(stream)) != srs_success) {
    // stop try when system error.
    if (srs_error_code(err) != ERROR_HLS_AVC_TRY_OTHERS) {
    return srs_error_wrap(err, "avc demux for annexb");
    }
    srs_freep(err);

    // try "ISO Base Media File Format" from ISO_IEC_14496-15-AVC-format-2012.pdf, page 20
    if ((err = avc_demux_ibmf_format(stream)) != srs_success) {
    return srs_error_wrap(err, "avc demux ibmf");
    } else {
    vcodec->payload_format = SrsAvcPayloadFormatIbmf;
    }
    } else {
    vcodec->payload_format = SrsAvcPayloadFormatAnnexb;
    }
    } else if (vcodec->payload_format == SrsAvcPayloadFormatIbmf) {
    // try "ISO Base Media File Format" from ISO_IEC_14496-15-AVC-format-2012.pdf, page 20
    if ((err = avc_demux_ibmf_format(stream)) != srs_success) {
    return srs_error_wrap(err, "avc demux ibmf");
    }
    } else {
    // One or more NALUs (Full frames are required)
    // try "AnnexB" from ISO_IEC_14496-10-AVC-2003.pdf, page 211.
    if ((err = avc_demux_annexb_format(stream)) != srs_success) {
    // ok, we guess out the payload is annexb, but maybe changed to ibmf.
    if (srs_error_code(err) != ERROR_HLS_AVC_TRY_OTHERS) {
    return srs_error_wrap(err, "avc demux annexb");
    }
    srs_freep(err);

    // try "ISO Base Media File Format" from ISO_IEC_14496-15-AVC-format-2012.pdf, page 20
    if ((err = avc_demux_ibmf_format(stream)) != srs_success) {
    return srs_error_wrap(err, "avc demux ibmf");
    } else {
    vcodec->payload_format = SrsAvcPayloadFormatIbmf;
    }
    }
    }

    return err;
    }

    srs_error_t SrsFormat::avc_demux_annexb_format(SrsBuffer* stream)
    {
    srs_error_t err = srs_success;

    // not annexb, try others
    if (!srs_avc_startswith_annexb(stream, NULL)) {
    return srs_error_new(ERROR_HLS_AVC_TRY_OTHERS, "try others");
    }

    // AnnexB
    // B.1.1 Byte stream NAL unit syntax,
    // ISO_IEC_14496-10-AVC-2003.pdf, page 211.
    while (!stream->empty()) {
    // find start code
    int nb_start_code = 0;
    if (!srs_avc_startswith_annexb(stream, &nb_start_code)) {
    return err;
    }

    // skip the start code.
    if (nb_start_code > 0) {
    stream->skip(nb_start_code);
    }

    // the NALU start bytes.
    char* p = stream->data() + stream->pos();

    // get the last matched NALU
    while (!stream->empty()) {
    if (srs_avc_startswith_annexb(stream, NULL)) {
    break;
    }

    stream->skip(1);
    }

    char* pp = stream->data() + stream->pos();

    // skip the empty.
    if (pp - p <= 0) {
    continue;
    }

    // got the NALU.
    if ((err = video->add_sample(p, (int)(pp - p))) != srs_success) {//可能有多个nalu,这个区间可能包含多个
    return srs_error_wrap(err, "add video frame");
    }
    }

    return err;
    }

    srs_error_t SrsFormat::avc_demux_ibmf_format(SrsBuffer* stream)
    {
    srs_error_t err = srs_success;

    int PictureLength = stream->size() - stream->pos();

    // 5.3.4.2.1 Syntax, ISO_IEC_14496-15-AVC-format-2012.pdf, page 16
    // 5.2.4.1 AVC decoder configuration record
    // 5.2.4.1.2 Semantics
    // The value of this field shall be one of 0, 1, or 3 corresponding to a
    // length encoded with 1, 2, or 4 bytes, respectively.
    srs_assert(vcodec->NAL_unit_length != 2);

    // 5.3.4.2.1 Syntax, ISO_IEC_14496-15-AVC-format-2012.pdf, page 20
    for (int i = 0; i < PictureLength;) {
    // unsigned int((NAL_unit_length+1)*8) NALUnitLength;
    if (!stream->require(vcodec->NAL_unit_length + 1)) {
    return srs_error_new(ERROR_HLS_DECODE_ERROR, "avc decode NALU size");
    }
    int32_t NALUnitLength = 0;
    if (vcodec->NAL_unit_length == 3) {
    NALUnitLength = stream->read_4bytes();
    } else if (vcodec->NAL_unit_length == 1) {
    NALUnitLength = stream->read_2bytes();
    } else {
    NALUnitLength = stream->read_1bytes();
    }

    // maybe stream is invalid format.
    // see: https://github.com/ossrs/srs/issues/183
    if (NALUnitLength < 0) {
    return srs_error_new(ERROR_HLS_DECODE_ERROR, "maybe stream is AnnexB format");
    }

    // NALUnit
    if (!stream->require(NALUnitLength)) {
    return srs_error_new(ERROR_HLS_DECODE_ERROR, "avc decode NALU data");
    }
    // 7.3.1 NAL unit syntax, ISO_IEC_14496-10-AVC-2003.pdf, page 44.
    if ((err = video->add_sample(stream->data() + stream->pos(), NALUnitLength)) != srs_success) {
    return srs_error_wrap(err, "avc add video frame");
    }
    stream->skip(NALUnitLength);

    i += vcodec->NAL_unit_length + 1 + NALUnitLength;
    }

    return err;
    }
    其他debug:

    1 可能是视频头和视频数据不匹配
    2 出现一例: pts和dts对不上,导致将帧丢弃所以花
    3 绿屏问题:一般是头错了,比如sps,pps错误导致解析不出来视频,全部都是0,绿色

ref:T-REC-H.264.pdf