OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 #include "webrtc/modules/rtp_rtcp/source/h264_bitstream_parser.h" | |
11 | |
12 #include "webrtc/base/bitbuffer.h" | |
13 #include "webrtc/base/bytebuffer.h" | |
14 #include "webrtc/base/checks.h" | |
15 #include "webrtc/base/logging.h" | |
16 #include "webrtc/base/scoped_ptr.h" | |
17 | |
18 namespace webrtc { | |
19 namespace { | |
20 // The size of a NALU header {0 0 0 1}. | |
21 static const size_t kNaluHeaderSize = 4; | |
22 | |
23 // The size of a NALU header plus the type byte. | |
24 static const size_t kNaluHeaderAndTypeSize = kNaluHeaderSize + 1; | |
25 | |
26 // The IDR type. | |
27 static const uint8_t kNaluSps = 7; | |
28 static const uint8_t kNaluPps = 8; | |
29 static const uint8_t kNaluIdr = 0x5; | |
30 static const uint8_t kNaluTypeMask = 0x1F; | |
31 | |
32 static const uint8_t kSliceTypeP = 0; | |
33 static const uint8_t kSliceTypeB = 1; | |
34 // static const uint8_t kSliceTypeI = 2; | |
35 static const uint8_t kSliceTypeSp = 3; | |
36 // static const uint8_t kSliceTypeSi = 4; | |
37 } // namespace | |
38 | |
39 // Parses RBSP from source bytes. Removes emulation bytes, but leaves the | |
40 // rbsp_trailing_bits() in the stream, since none of the parsing reads all the | |
41 // way to the end of a parsed RBSP sequence. When writing, that means the | |
42 // rbsp_trailing_bits() should be preserved and don't need to be restored (i.e. | |
43 // the rbsp_stop_one_bit, which is just a 1, then zero padded), and alignment | |
44 // should "just work". | |
45 // TODO(pbos): Make parsing RBSP something that can be integrated into BitBuffer | |
46 // so we don't have to copy the entire frames when only interested in the | |
47 // headers. | |
48 rtc::ByteBuffer* ParseRbsp(const uint8_t* bytes, size_t length) { | |
49 // Copied from webrtc::H264SpsParser::Parse. | |
50 rtc::ByteBuffer* rbsp_buffer = new rtc::ByteBuffer; | |
51 for (size_t i = 0; i < length;) { | |
52 if (length - i >= 3 && bytes[i] == 0 && bytes[i + 1] == 0 && | |
53 bytes[i + 2] == 3) { | |
54 rbsp_buffer->WriteBytes(reinterpret_cast<const char*>(bytes) + i, 2); | |
55 i += 3; | |
56 } else { | |
57 rbsp_buffer->WriteBytes(reinterpret_cast<const char*>(bytes) + i, 1); | |
58 i++; | |
59 } | |
60 } | |
61 return rbsp_buffer; | |
62 } | |
63 | |
64 #define RETURN_FALSE_ON_FAIL(x) \ | |
65 if (!(x)) { \ | |
66 LOG_F(LS_ERROR) << "FAILED: " #x; \ | |
67 return false; \ | |
68 } | |
69 | |
70 // These functions are similar to webrtc::H264SpsParser::Parse, and based on the | |
71 // same version of the H.264 standard. You can find it here: | |
72 // http://www.itu.int/rec/T-REC-H.264 | |
73 bool H264BitstreamParser::ParseSpsNalu(const uint8_t* sps, size_t length) { | |
74 // Parse out the SPS RBSP. It should be small, so it's ok that we create a | |
75 // copy. We'll eventually write this back. | |
76 rtc::scoped_ptr<rtc::ByteBuffer> sps_rbsp( | |
77 ParseRbsp(sps + kNaluHeaderAndTypeSize, length - kNaluHeaderAndTypeSize)); | |
78 rtc::BitBuffer sps_parser(reinterpret_cast<const uint8*>(sps_rbsp->Data()), | |
79 sps_rbsp->Length()); | |
80 | |
81 uint8_t byte_tmp; | |
82 uint32_t golomb_tmp; | |
83 uint32_t bits_tmp; | |
84 | |
85 // profile_idc: u(8). | |
86 uint8 profile_idc; | |
87 RETURN_FALSE_ON_FAIL(sps_parser.ReadUInt8(&profile_idc)); | |
88 // constraint_set0_flag through constraint_set5_flag + reserved_zero_2bits | |
89 // 1 bit each for the flags + 2 bits = 8 bits = 1 byte. | |
90 RETURN_FALSE_ON_FAIL(sps_parser.ReadUInt8(&byte_tmp)); | |
91 // level_idc: u(8) | |
92 RETURN_FALSE_ON_FAIL(sps_parser.ReadUInt8(&byte_tmp)); | |
93 // seq_parameter_set_id: ue(v) | |
94 RETURN_FALSE_ON_FAIL(sps_parser.ReadExponentialGolomb(&golomb_tmp)); | |
95 separate_colour_plane_flag_ = 0; | |
96 // See if profile_idc has chroma format information. | |
97 if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || | |
98 profile_idc == 244 || profile_idc == 44 || profile_idc == 83 || | |
99 profile_idc == 86 || profile_idc == 118 || profile_idc == 128 || | |
100 profile_idc == 138 || profile_idc == 139 || profile_idc == 134) { | |
101 // chroma_format_idc: ue(v) | |
102 uint32 chroma_format_idc; | |
103 RETURN_FALSE_ON_FAIL(sps_parser.ReadExponentialGolomb(&chroma_format_idc)); | |
104 if (chroma_format_idc == 3) { | |
105 // separate_colour_plane_flag: u(1) | |
106 RETURN_FALSE_ON_FAIL( | |
107 sps_parser.ReadBits(&separate_colour_plane_flag_, 1)); | |
108 } | |
109 // bit_depth_luma_minus8: ue(v) | |
110 RETURN_FALSE_ON_FAIL(sps_parser.ReadExponentialGolomb(&golomb_tmp)); | |
111 // bit_depth_chroma_minus8: ue(v) | |
112 RETURN_FALSE_ON_FAIL(sps_parser.ReadExponentialGolomb(&golomb_tmp)); | |
113 // qpprime_y_zero_transform_bypass_flag: u(1) | |
114 RETURN_FALSE_ON_FAIL(sps_parser.ReadBits(&bits_tmp, 1)); | |
115 // seq_scaling_matrix_present_flag: u(1) | |
116 uint32_t seq_scaling_matrix_present_flag; | |
117 RETURN_FALSE_ON_FAIL( | |
118 sps_parser.ReadBits(&seq_scaling_matrix_present_flag, 1)); | |
119 if (seq_scaling_matrix_present_flag) { | |
120 // seq_scaling_list_present_flags. Either 8 or 12, depending on | |
121 // chroma_format_idc. | |
122 uint32_t seq_scaling_list_present_flags; | |
123 if (chroma_format_idc != 3) { | |
124 RETURN_FALSE_ON_FAIL( | |
125 sps_parser.ReadBits(&seq_scaling_list_present_flags, 8)); | |
126 } else { | |
127 RETURN_FALSE_ON_FAIL( | |
128 sps_parser.ReadBits(&seq_scaling_list_present_flags, 12)); | |
129 } | |
130 // TODO(pbos): Support parsing scaling lists if they're seen in practice. | |
131 CHECK(seq_scaling_list_present_flags == 0) | |
132 << "SPS contains scaling lists, which are unsupported."; | |
133 } | |
134 } | |
135 // log2_max_frame_num_minus4: ue(v) | |
136 RETURN_FALSE_ON_FAIL( | |
137 sps_parser.ReadExponentialGolomb(&log2_max_frame_num_minus4_)); | |
138 // pic_order_cnt_type: ue(v) | |
139 RETURN_FALSE_ON_FAIL( | |
140 sps_parser.ReadExponentialGolomb(&pic_order_cnt_type_)); | |
141 | |
142 if (pic_order_cnt_type_ == 0) { | |
143 // log2_max_pic_order_cnt_lsb_minus4: ue(v) | |
144 RETURN_FALSE_ON_FAIL( | |
145 sps_parser.ReadExponentialGolomb(&log2_max_pic_order_cnt_lsb_minus4_)); | |
146 } else if (pic_order_cnt_type_ == 1) { | |
147 // delta_pic_order_always_zero_flag: u(1) | |
148 RETURN_FALSE_ON_FAIL( | |
149 sps_parser.ReadBits(&delta_pic_order_always_zero_flag_, 1)); | |
150 // offset_for_non_ref_pic: se(v) | |
151 RETURN_FALSE_ON_FAIL(sps_parser.ReadExponentialGolomb(&golomb_tmp)); | |
152 // offset_for_top_to_bottom_field: se(v) | |
153 RETURN_FALSE_ON_FAIL(sps_parser.ReadExponentialGolomb(&golomb_tmp)); | |
154 uint32_t num_ref_frames_in_pic_order_cnt_cycle; | |
155 // num_ref_frames_in_pic_order_cnt_cycle: ue(v) | |
156 RETURN_FALSE_ON_FAIL(sps_parser.ReadExponentialGolomb( | |
157 &num_ref_frames_in_pic_order_cnt_cycle)); | |
158 for (uint32_t i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++) { | |
159 // offset_for_ref_frame[i]: se(v) | |
160 RETURN_FALSE_ON_FAIL(sps_parser.ReadExponentialGolomb(&golomb_tmp)); | |
161 } | |
162 } | |
163 // max_num_ref_frames: ue(v) | |
164 RETURN_FALSE_ON_FAIL(sps_parser.ReadExponentialGolomb(&golomb_tmp)); | |
165 // gaps_in_frame_num_value_allowed_flag: u(1) | |
166 RETURN_FALSE_ON_FAIL(sps_parser.ReadBits(&bits_tmp, 1)); | |
167 // pic_width_in_mbs_minus1: ue(v) | |
168 RETURN_FALSE_ON_FAIL(sps_parser.ReadExponentialGolomb(&golomb_tmp)); | |
169 // pic_height_in_map_units_minus1: ue(v) | |
170 RETURN_FALSE_ON_FAIL(sps_parser.ReadExponentialGolomb(&golomb_tmp)); | |
171 // frame_mbs_only_flag: u(1) | |
172 RETURN_FALSE_ON_FAIL(sps_parser.ReadBits(&frame_mbs_only_flag_, 1)); | |
173 return true; | |
174 } | |
175 | |
176 bool H264BitstreamParser::ParsePpsNalu(const uint8_t* pps, size_t length) { | |
177 // We're starting a new stream, so reset picture type rewriting values. | |
178 rtc::scoped_ptr<rtc::ByteBuffer> buffer( | |
179 ParseRbsp(pps + kNaluHeaderAndTypeSize, length - kNaluHeaderAndTypeSize)); | |
180 rtc::BitBuffer parser(reinterpret_cast<const uint8*>(buffer->Data()), | |
181 buffer->Length()); | |
182 | |
183 uint32_t bits_tmp; | |
184 uint32_t golomb_ignored; | |
185 // pic_parameter_set_id: ue(v) | |
186 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); | |
187 // seq_parameter_set_id: ue(v) | |
188 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); | |
189 // entropy_coding_mode_flag: u(1) | |
190 uint32_t entropy_coding_mode_flag; | |
191 RETURN_FALSE_ON_FAIL(parser.ReadBits(&entropy_coding_mode_flag, 1)); | |
192 // TODO(pbos): Is this true when we don't need to rewrite alignment or is it | |
193 // trivial to parse? | |
194 CHECK(entropy_coding_mode_flag == 0) | |
195 << "Don't know how to parse CABAC streams."; | |
196 // bottom_field_pic_order_in_frame_present_flag: u(1) | |
197 uint32_t bottom_field_pic_order_in_frame_present_flag; | |
198 RETURN_FALSE_ON_FAIL( | |
199 parser.ReadBits(&bottom_field_pic_order_in_frame_present_flag, 1)); | |
200 bottom_field_pic_order_in_frame_present_flag_ = | |
201 static_cast<bool>(bottom_field_pic_order_in_frame_present_flag); | |
202 | |
203 // num_slice_groups_minus1: ue(v) | |
204 uint32_t num_slice_groups_minus1; | |
205 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&num_slice_groups_minus1)); | |
206 if (num_slice_groups_minus1 > 0) { | |
207 uint32_t slice_group_map_type; | |
208 // slice_group_map_type: ue(v) | |
209 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&slice_group_map_type)); | |
210 if (slice_group_map_type == 0) { | |
211 for (uint32_t i_group = 0; i_group <= num_slice_groups_minus1; | |
212 ++i_group) { | |
213 // run_length_minus1[iGroup]: ue(v) | |
214 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); | |
215 } | |
216 } else if (slice_group_map_type == 2) { | |
217 for (uint32_t i_group = 0; i_group <= num_slice_groups_minus1; | |
218 ++i_group) { | |
219 // top_left[iGroup]: ue(v) | |
220 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); | |
221 // bottom_right[iGroup]: ue(v) | |
222 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); | |
223 } | |
224 } else if (slice_group_map_type == 3 || slice_group_map_type == 4 || | |
225 slice_group_map_type == 5) { | |
226 // slice_group_change_direction_flag: u(1) | |
227 RETURN_FALSE_ON_FAIL(parser.ReadBits(&bits_tmp, 1)); | |
228 // slice_group_change_rate_minus1: ue(v) | |
229 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); | |
230 } else if (slice_group_map_type == 6) { | |
231 // pic_size_in_map_units_minus1: ue(v) | |
232 uint32_t pic_size_in_map_units_minus1; | |
233 RETURN_FALSE_ON_FAIL( | |
234 parser.ReadExponentialGolomb(&pic_size_in_map_units_minus1)); | |
235 uint32_t slice_group_id_bits = 0; | |
236 uint32_t num_slice_groups = num_slice_groups_minus1 + 1; | |
237 // If num_slice_groups is not a power of two an additional bit is required | |
238 // to account for the ceil() of log2() below. | |
239 if ((num_slice_groups & (num_slice_groups - 1)) != 0) | |
240 ++slice_group_id_bits; | |
241 while (num_slice_groups > 0) { | |
242 num_slice_groups >>= 1; | |
243 ++slice_group_id_bits; | |
244 } | |
245 for (uint32_t i = 0; i <= pic_size_in_map_units_minus1; i++) { | |
246 // slice_group_id[i]: u(v) | |
247 // Represented by ceil(log2(num_slice_groups_minus1 + 1)) bits. | |
248 RETURN_FALSE_ON_FAIL(parser.ReadBits(&bits_tmp, slice_group_id_bits)); | |
249 } | |
250 } | |
251 } | |
252 // num_ref_idx_l0_default_active_minus1: ue(v) | |
253 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); | |
254 // num_ref_idx_l1_default_active_minus1: ue(v) | |
255 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); | |
256 // weighted_pred_flag: u(1) | |
257 // weighted_bipred_idc: u(2) | |
258 RETURN_FALSE_ON_FAIL(parser.ReadBits(&bits_tmp, 3)); | |
259 | |
260 // pic_init_qp_minus26: se(v) | |
261 RETURN_FALSE_ON_FAIL( | |
262 parser.ReadSignedExponentialGolomb(&pic_init_qp_minus26_)); | |
263 printf("pic_init_qp: %d\n", pic_init_qp_minus26_ + 26); | |
264 // pic_init_qs_minus26: se(v) | |
265 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); | |
266 // chroma_qp_index_offset: se(v) | |
267 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); | |
268 // deblocking_filter_control_present_flag: u(1) | |
269 RETURN_FALSE_ON_FAIL(parser.ReadBits(&bits_tmp, 1)); | |
270 // constrained_intra_pred_flag: u(1) | |
271 RETURN_FALSE_ON_FAIL(parser.ReadBits(&bits_tmp, 1)); | |
272 // redundant_pic_cnt_present_flag: u(1) | |
273 RETURN_FALSE_ON_FAIL(parser.ReadBits(&redundant_pic_cnt_present_flag_, 1)); | |
274 | |
275 return true; | |
276 } | |
277 | |
278 bool H264BitstreamParser::ParseNonParameterSetNalu(const uint8_t* source, | |
279 size_t source_length) { | |
280 rtc::scoped_ptr<rtc::ByteBuffer> slice_rbsp(ParseRbsp( | |
281 source + kNaluHeaderAndTypeSize, source_length - kNaluHeaderAndTypeSize)); | |
282 rtc::BitBuffer slice_reader( | |
283 reinterpret_cast<const uint8*>(slice_rbsp->Data()), slice_rbsp->Length()); | |
284 // Check to see if this is an IDR slice, which has an extra field to parse | |
285 // out. | |
286 bool is_idr = (source[kNaluHeaderSize] & 0x0F) == kNaluIdr; | |
287 uint8_t nal_ref_idc = (source[kNaluHeaderSize] & 0x60) >> 5; | |
288 uint32_t golomb_tmp; | |
289 uint32_t bits_tmp; | |
290 | |
291 // first_mb_in_slice: ue(v) | |
292 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
293 // slice_type: ue(v) | |
294 uint32_t slice_type; | |
295 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&slice_type)); | |
296 // slice_type's 5..9 range is used to indicate things.that all slices of a | |
297 // picture have the same value of slice_type % 5, we don't care about that, so | |
298 // we map to the corresponding 0..4 range. | |
299 slice_type %= 5; | |
300 // pic_parameter_set_id: ue(v) | |
301 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
302 if (separate_colour_plane_flag_ == 1) { | |
303 // colour_plane_id | |
304 RETURN_FALSE_ON_FAIL(slice_reader.ReadBits(&bits_tmp, 2)); | |
305 } | |
306 // frame_num: u(v) | |
307 // Represented by log2_max_frame_num_minus4 + 4 bits. | |
308 RETURN_FALSE_ON_FAIL( | |
309 slice_reader.ReadBits(&bits_tmp, log2_max_frame_num_minus4_ + 4)); | |
310 uint32 field_pic_flag = 0; | |
311 if (frame_mbs_only_flag_ == 0) { | |
312 // field_pic_flag: u(1) | |
313 RETURN_FALSE_ON_FAIL(slice_reader.ReadBits(&field_pic_flag, 1)); | |
314 if (field_pic_flag != 0) { | |
315 // bottom_field_flag: u(1) | |
316 RETURN_FALSE_ON_FAIL(slice_reader.ReadBits(&bits_tmp, 1)); | |
317 } | |
318 } | |
319 if (is_idr) { | |
320 // idr_pic_id: ue(v) | |
321 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
322 } | |
323 // pic_order_cnt_lsb: u(v) | |
noahric
2015/09/03 17:48:58
This needs to be behind a pic_order_cnt_type == 0
pbos-webrtc
2015/09/04 10:01:20
This gives me more reasonable values. Thanks a lot
| |
324 // Represented by log2_max_pic_order_cnt_lsb_minus4_ + 4 bits. | |
325 RETURN_FALSE_ON_FAIL( | |
326 slice_reader.ReadBits(&bits_tmp, log2_max_pic_order_cnt_lsb_minus4_ + 4)); | |
327 if (bottom_field_pic_order_in_frame_present_flag_ && field_pic_flag == 0) { | |
noahric
2015/09/03 17:49:37
(This is also part of pic_order_cnt_type == 0)
pbos-webrtc
2015/09/04 10:01:20
Done.
| |
328 // delta_pic_order_cnt_bottom: se(v) | |
329 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
330 } | |
331 if (pic_order_cnt_type_ == 1 && !delta_pic_order_always_zero_flag_) { | |
332 // delta_pic_order_cnt[0]: se(v) | |
333 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
334 if (bottom_field_pic_order_in_frame_present_flag_ && !field_pic_flag) { | |
335 // delta_pic_order_cnt[1]: se(v) | |
336 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
337 } | |
338 } | |
339 if (redundant_pic_cnt_present_flag_) { | |
340 // redundant_pic_cnt: ue(v) | |
341 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
342 } | |
343 if (slice_type == kSliceTypeB) { | |
344 // direct_spatial_mv_pred_flag: u(1) | |
345 RETURN_FALSE_ON_FAIL(slice_reader.ReadBits(&bits_tmp, 1)); | |
346 } | |
347 if (slice_type == kSliceTypeP || slice_type == kSliceTypeSp || | |
348 slice_type == kSliceTypeB) { | |
349 uint32_t num_ref_idx_active_override_flag; | |
350 // num_ref_idx_active_override_flag: u(1) | |
351 RETURN_FALSE_ON_FAIL( | |
352 slice_reader.ReadBits(&num_ref_idx_active_override_flag, 1)); | |
353 if (num_ref_idx_active_override_flag) { | |
354 // num_ref_idx_l0_active_minus1: ue(v) | |
355 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
356 if (slice_type == kSliceTypeB) { | |
357 // num_ref_idx_l1_active_minus1: ue(v) | |
358 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
359 } | |
360 } | |
361 } | |
362 // assume nal_unit_type != 20 && nal_unit_type != 21: | |
363 // if (nal_unit_type == 20 || nal_unit_type == 21) | |
364 // ref_pic_list_mvc_modification() | |
365 // else | |
366 { | |
367 // ref_pic_list_modification(): | |
368 // |slice_type| checks here don't use named constants as they aren't named | |
369 // in the spec for this segment. Keeping them consistent makes it easier to | |
370 // verify that they are both the same. | |
371 if (slice_type % 5 != 2 && slice_type % 5 != 4) { | |
372 // ref_pic_list_modification_flag_l0: u(1) | |
373 uint32_t ref_pic_list_modification_flag_l0; | |
374 RETURN_FALSE_ON_FAIL( | |
375 slice_reader.ReadBits(&ref_pic_list_modification_flag_l0, 1)); | |
376 if (ref_pic_list_modification_flag_l0) { | |
377 uint32_t modification_of_pic_nums_idc; | |
378 do { | |
379 // modification_of_pic_nums_idc: ue(v) | |
380 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb( | |
381 &modification_of_pic_nums_idc)); | |
382 if (modification_of_pic_nums_idc == 0 || | |
383 modification_of_pic_nums_idc == 1) { | |
384 // abs_diff_pic_num_minus1: ue(v) | |
385 RETURN_FALSE_ON_FAIL( | |
386 slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
387 } else if (modification_of_pic_nums_idc == 2) { | |
388 // long_term_pic_num: ue(v) | |
389 RETURN_FALSE_ON_FAIL( | |
390 slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
391 } | |
392 } while (modification_of_pic_nums_idc != 3); | |
393 } | |
394 } | |
395 if (slice_type % 5 == 1) { | |
396 // ref_pic_list_modification_flag_l1: u(1) | |
397 uint32_t ref_pic_list_modification_flag_l1; | |
398 RETURN_FALSE_ON_FAIL( | |
399 slice_reader.ReadBits(&ref_pic_list_modification_flag_l1, 1)); | |
400 if (ref_pic_list_modification_flag_l1) { | |
401 uint32_t modification_of_pic_nums_idc; | |
402 do { | |
403 // modification_of_pic_nums_idc: ue(v) | |
404 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb( | |
405 &modification_of_pic_nums_idc)); | |
406 if (modification_of_pic_nums_idc == 0 || | |
407 modification_of_pic_nums_idc == 1) { | |
408 // abs_diff_pic_num_minus1: ue(v) | |
409 RETURN_FALSE_ON_FAIL( | |
410 slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
411 } else if (modification_of_pic_nums_idc == 2) { | |
412 // long_term_pic_num: ue(v) | |
413 RETURN_FALSE_ON_FAIL( | |
414 slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
415 } | |
416 } while (modification_of_pic_nums_idc != 3); | |
417 } | |
418 } | |
419 } | |
420 // TODO(pbos): Do we need support for pred_weight_table()? | |
421 // if ((weighted_pred_flag && (slice_type == P || slice_type == SP)) || | |
422 // (weighted_bipred_idc == 1 && slice_type == B)) { | |
423 // pred_weight_table() | |
424 // } | |
425 if (nal_ref_idc) { | |
426 // dec_ref_pic_marking(): | |
427 if (is_idr) { | |
428 // no_output_of_prior_pics_flag: u(1) | |
429 // long_term_reference_flag: u(1) | |
430 RETURN_FALSE_ON_FAIL(slice_reader.ReadBits(&bits_tmp, 2)); | |
431 } else { | |
432 // adaptive_ref_pic_marking_mode_flag: u(1) | |
433 uint32_t adaptive_ref_pic_marking_mode_flag; | |
434 RETURN_FALSE_ON_FAIL( | |
435 slice_reader.ReadBits(&adaptive_ref_pic_marking_mode_flag, 1)); | |
436 if (adaptive_ref_pic_marking_mode_flag) { | |
437 uint32_t memory_management_control_operation; | |
438 do { | |
439 // memory_management_control_operation: ue(v) | |
440 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb( | |
441 &memory_management_control_operation)); | |
442 if (memory_management_control_operation == 1 || | |
443 memory_management_control_operation == 3) { | |
444 // difference_of_pic_nums_minus1: ue(v) | |
445 RETURN_FALSE_ON_FAIL( | |
446 slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
447 } | |
448 if (memory_management_control_operation == 2) { | |
449 // long_term_pic_num: ue(v) | |
450 RETURN_FALSE_ON_FAIL( | |
451 slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
452 } | |
453 if (memory_management_control_operation == 3 || | |
454 memory_management_control_operation == 6) { | |
455 // long_term_frame_idx: ue(v) | |
456 RETURN_FALSE_ON_FAIL( | |
457 slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
458 } | |
459 if (memory_management_control_operation == 4) { | |
460 // max_long_term_frame_idx_plus1: ue(v) | |
461 RETURN_FALSE_ON_FAIL( | |
462 slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
463 } | |
464 } while (memory_management_control_operation != 0); | |
465 } | |
466 } | |
467 } | |
468 // cabac not supported: entropy_coding_mode_flag == 0 asserted above. | |
469 // if (entropy_coding_mode_flag && slice_type != I && slice_type != SI) | |
470 // cabac_init_idc | |
471 RETURN_FALSE_ON_FAIL( | |
472 slice_reader.ReadSignedExponentialGolomb(&slice_qp_delta_)); | |
473 printf("Slice QP: %d\n", GetLastSliceQp()); | |
474 return true; | |
475 } | |
476 | |
477 void H264BitstreamParser::ParseSlice(const uint8_t* slice, size_t length) { | |
478 printf("ParseSlice(%p, %zu): [%u..\n", slice, length, slice[4]); | |
479 uint8_t nalu_type = slice[4] & kNaluTypeMask; | |
480 switch (nalu_type) { | |
481 case kNaluSps: | |
482 CHECK(ParseSpsNalu(slice, length)) << "Failed to parse bitstream SPS."; | |
483 break; | |
484 case kNaluPps: | |
485 CHECK(ParsePpsNalu(slice, length)) << "Failed to parse bitstream PPS."; | |
486 break; | |
487 default: | |
488 CHECK(ParseNonParameterSetNalu(slice, length)) | |
489 << "Failed to parse picture slice."; | |
490 break; | |
491 } | |
492 } | |
493 | |
494 void H264BitstreamParser::ParseBitstream(const uint8_t* bitstream, | |
495 size_t length) { | |
496 assert(length >= 4); | |
497 // Skip first marker. | |
498 bitstream += 4; | |
499 length -= 4; | |
500 const uint8_t* head = bitstream; | |
501 | |
502 // Set end buffer pointer to 4 bytes before actual buffer end so we can | |
503 // access head[1], head[2] and head[3] in a loop without buffer overrun. | |
504 const uint8_t* end = bitstream + length; | |
505 | |
506 while (head < end - 4) { | |
507 if (head[0]) { | |
noahric
2015/09/03 17:48:58
There's a much faster way to loop this (I did an e
| |
508 head++; | |
509 continue; | |
510 } | |
511 if (head[1]) { // got 00xx | |
512 head += 2; | |
513 continue; | |
514 } | |
515 if (head[2]) { // got 0000xx | |
516 head += 3; | |
517 continue; | |
518 } | |
519 if (head[3] != 0x01) { // got 000000xx | |
520 head++; // xx != 1, continue searching. | |
521 continue; | |
522 } | |
523 size_t slice_length = head - bitstream + 4; | |
524 ParseSlice(bitstream - 4, slice_length); | |
525 // Skip separator. | |
526 head += 4; | |
527 bitstream = head; | |
528 } | |
529 // Parse the last slice. | |
530 ParseSlice(bitstream - 4, end - bitstream + 4); | |
531 } | |
532 | |
533 int H264BitstreamParser::GetLastSliceQp() const { | |
534 return 26 + pic_init_qp_minus26_ + slice_qp_delta_; | |
535 } | |
536 | |
537 } // namespace webrtc | |
OLD | NEW |