几个概念认识:
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:
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来分割流数据,是很容易的。格式:
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)FLV可能封装形式:
flv格式不支持封装annexB ,但若想基于flv去做强制封装,可以://最好不要这么做1
2
3对AnnexB:
AVCC头,塞两个NALU sps pps
AVC数据:起始码 nalu关于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:
- 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
- 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 | An AVCC stream always starts with a specific header |
- 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 | 1 b(8),f(n), 基于read_bits,讲究顺序性。后者可以读取多个bit, |
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/
- 整体格式:对AnnexB:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19nalu 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
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
8eg:
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
52forbidden_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等于1到5的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 | Nal Unit Type Possible nal_ref_idc value |
rbsp构成:
rbsp_trailing_bits( ) 5 即在nalu中提到的,用来做stop和align的bits: 如下1
2rbsp_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
23sei_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
3441 在收到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