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/video_coding/utility/h264_bitstream_parser.h" | |
11 | |
12 #include <memory> | |
13 #include <vector> | |
14 | |
15 #include "webrtc/base/bitbuffer.h" | |
16 #include "webrtc/base/bytebuffer.h" | |
17 #include "webrtc/base/checks.h" | |
18 | |
19 #include "webrtc/common_video/h264/h264_common.h" | |
20 #include "webrtc/base/logging.h" | |
21 | |
22 namespace webrtc { | |
23 | |
24 #define RETURN_FALSE_ON_FAIL(x) \ | |
25 if (!(x)) { \ | |
26 LOG_F(LS_ERROR) << "FAILED: " #x; \ | |
27 return false; \ | |
28 } | |
29 | |
30 H264BitstreamParser::H264BitstreamParser() {} | |
31 H264BitstreamParser::~H264BitstreamParser() {} | |
32 | |
33 bool H264BitstreamParser::ParseNonParameterSetNalu(const uint8_t* source, | |
34 size_t source_length, | |
35 uint8_t nalu_type) { | |
36 RTC_CHECK(sps_); | |
37 RTC_CHECK(pps_); | |
38 last_slice_qp_delta_ = rtc::Optional<int32_t>(); | |
39 std::unique_ptr<rtc::Buffer> slice_rbsp( | |
40 H264::ParseRbsp(source, source_length)); | |
41 rtc::BitBuffer slice_reader(slice_rbsp->data() + H264::kNaluTypeSize, | |
42 slice_rbsp->size() - H264::kNaluTypeSize); | |
43 // Check to see if this is an IDR slice, which has an extra field to parse | |
44 // out. | |
45 bool is_idr = (source[0] & 0x0F) == H264::NaluType::kIdr; | |
46 uint8_t nal_ref_idc = (source[0] & 0x60) >> 5; | |
47 uint32_t golomb_tmp; | |
48 uint32_t bits_tmp; | |
49 | |
50 // first_mb_in_slice: ue(v) | |
51 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
52 // slice_type: ue(v) | |
53 uint32_t slice_type; | |
54 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&slice_type)); | |
55 // slice_type's 5..9 range is used to indicate that all slices of a picture | |
56 // have the same value of slice_type % 5, we don't care about that, so we map | |
57 // to the corresponding 0..4 range. | |
58 slice_type %= 5; | |
59 // pic_parameter_set_id: ue(v) | |
60 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
61 if (sps_->separate_colour_plane_flag == 1) { | |
62 // colour_plane_id | |
63 RETURN_FALSE_ON_FAIL(slice_reader.ReadBits(&bits_tmp, 2)); | |
64 } | |
65 // frame_num: u(v) | |
66 // Represented by log2_max_frame_num_minus4 + 4 bits. | |
67 RETURN_FALSE_ON_FAIL( | |
68 slice_reader.ReadBits(&bits_tmp, sps_->log2_max_frame_num_minus4 + 4)); | |
69 uint32_t field_pic_flag = 0; | |
70 if (sps_->frame_mbs_only_flag == 0) { | |
71 // field_pic_flag: u(1) | |
72 RETURN_FALSE_ON_FAIL(slice_reader.ReadBits(&field_pic_flag, 1)); | |
73 if (field_pic_flag != 0) { | |
74 // bottom_field_flag: u(1) | |
75 RETURN_FALSE_ON_FAIL(slice_reader.ReadBits(&bits_tmp, 1)); | |
76 } | |
77 } | |
78 if (is_idr) { | |
79 // idr_pic_id: ue(v) | |
80 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
81 } | |
82 // pic_order_cnt_lsb: u(v) | |
83 // Represented by sps_.log2_max_pic_order_cnt_lsb_minus4 + 4 bits. | |
84 if (sps_->pic_order_cnt_type == 0) { | |
85 RETURN_FALSE_ON_FAIL(slice_reader.ReadBits( | |
86 &bits_tmp, sps_->log2_max_pic_order_cnt_lsb_minus4 + 4)); | |
87 if (pps_->bottom_field_pic_order_in_frame_present_flag && | |
88 field_pic_flag == 0) { | |
89 // delta_pic_order_cnt_bottom: se(v) | |
90 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
91 } | |
92 } | |
93 if (sps_->pic_order_cnt_type == 1 && | |
94 !sps_->delta_pic_order_always_zero_flag) { | |
95 // delta_pic_order_cnt[0]: se(v) | |
96 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
97 if (pps_->bottom_field_pic_order_in_frame_present_flag && !field_pic_flag) { | |
98 // delta_pic_order_cnt[1]: se(v) | |
99 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
100 } | |
101 } | |
102 if (pps_->redundant_pic_cnt_present_flag) { | |
103 // redundant_pic_cnt: ue(v) | |
104 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
105 } | |
106 if (slice_type == H264::SliceType::kB) { | |
107 // direct_spatial_mv_pred_flag: u(1) | |
108 RETURN_FALSE_ON_FAIL(slice_reader.ReadBits(&bits_tmp, 1)); | |
109 } | |
110 switch (slice_type) { | |
111 case H264::SliceType::kP: | |
112 case H264::SliceType::kB: | |
113 case H264::SliceType::kSp: | |
114 uint32_t num_ref_idx_active_override_flag; | |
115 // num_ref_idx_active_override_flag: u(1) | |
116 RETURN_FALSE_ON_FAIL( | |
117 slice_reader.ReadBits(&num_ref_idx_active_override_flag, 1)); | |
118 if (num_ref_idx_active_override_flag != 0) { | |
119 // num_ref_idx_l0_active_minus1: ue(v) | |
120 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
121 if (slice_type == H264::SliceType::kB) { | |
122 // num_ref_idx_l1_active_minus1: ue(v) | |
123 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
124 } | |
125 } | |
126 break; | |
127 default: | |
128 break; | |
129 } | |
130 // assume nal_unit_type != 20 && nal_unit_type != 21: | |
131 RTC_CHECK_NE(nalu_type, 20); | |
132 RTC_CHECK_NE(nalu_type, 21); | |
133 // if (nal_unit_type == 20 || nal_unit_type == 21) | |
134 // ref_pic_list_mvc_modification() | |
135 // else | |
136 { | |
137 // ref_pic_list_modification(): | |
138 // |slice_type| checks here don't use named constants as they aren't named | |
139 // in the spec for this segment. Keeping them consistent makes it easier to | |
140 // verify that they are both the same. | |
141 if (slice_type % 5 != 2 && slice_type % 5 != 4) { | |
142 // ref_pic_list_modification_flag_l0: u(1) | |
143 uint32_t ref_pic_list_modification_flag_l0; | |
144 RETURN_FALSE_ON_FAIL( | |
145 slice_reader.ReadBits(&ref_pic_list_modification_flag_l0, 1)); | |
146 if (ref_pic_list_modification_flag_l0) { | |
147 uint32_t modification_of_pic_nums_idc; | |
148 do { | |
149 // modification_of_pic_nums_idc: ue(v) | |
150 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb( | |
151 &modification_of_pic_nums_idc)); | |
152 if (modification_of_pic_nums_idc == 0 || | |
153 modification_of_pic_nums_idc == 1) { | |
154 // abs_diff_pic_num_minus1: ue(v) | |
155 RETURN_FALSE_ON_FAIL( | |
156 slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
157 } else if (modification_of_pic_nums_idc == 2) { | |
158 // long_term_pic_num: ue(v) | |
159 RETURN_FALSE_ON_FAIL( | |
160 slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
161 } | |
162 } while (modification_of_pic_nums_idc != 3); | |
163 } | |
164 } | |
165 if (slice_type % 5 == 1) { | |
166 // ref_pic_list_modification_flag_l1: u(1) | |
167 uint32_t ref_pic_list_modification_flag_l1; | |
168 RETURN_FALSE_ON_FAIL( | |
169 slice_reader.ReadBits(&ref_pic_list_modification_flag_l1, 1)); | |
170 if (ref_pic_list_modification_flag_l1) { | |
171 uint32_t modification_of_pic_nums_idc; | |
172 do { | |
173 // modification_of_pic_nums_idc: ue(v) | |
174 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb( | |
175 &modification_of_pic_nums_idc)); | |
176 if (modification_of_pic_nums_idc == 0 || | |
177 modification_of_pic_nums_idc == 1) { | |
178 // abs_diff_pic_num_minus1: ue(v) | |
179 RETURN_FALSE_ON_FAIL( | |
180 slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
181 } else if (modification_of_pic_nums_idc == 2) { | |
182 // long_term_pic_num: ue(v) | |
183 RETURN_FALSE_ON_FAIL( | |
184 slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
185 } | |
186 } while (modification_of_pic_nums_idc != 3); | |
187 } | |
188 } | |
189 } | |
190 // TODO(pbos): Do we need support for pred_weight_table()? | |
191 RTC_CHECK( | |
192 !((pps_->weighted_pred_flag && (slice_type == H264::SliceType::kP || | |
193 slice_type == H264::SliceType::kSp)) || | |
194 (pps_->weighted_bipred_idc != 0 && slice_type == H264::SliceType::kB))) | |
195 << "Missing support for pred_weight_table()."; | |
196 // if ((weighted_pred_flag && (slice_type == P || slice_type == SP)) || | |
197 // (weighted_bipred_idc == 1 && slice_type == B)) { | |
198 // pred_weight_table() | |
199 // } | |
200 if (nal_ref_idc != 0) { | |
201 // dec_ref_pic_marking(): | |
202 if (is_idr) { | |
203 // no_output_of_prior_pics_flag: u(1) | |
204 // long_term_reference_flag: u(1) | |
205 RETURN_FALSE_ON_FAIL(slice_reader.ReadBits(&bits_tmp, 2)); | |
206 } else { | |
207 // adaptive_ref_pic_marking_mode_flag: u(1) | |
208 uint32_t adaptive_ref_pic_marking_mode_flag; | |
209 RETURN_FALSE_ON_FAIL( | |
210 slice_reader.ReadBits(&adaptive_ref_pic_marking_mode_flag, 1)); | |
211 if (adaptive_ref_pic_marking_mode_flag) { | |
212 uint32_t memory_management_control_operation; | |
213 do { | |
214 // memory_management_control_operation: ue(v) | |
215 RETURN_FALSE_ON_FAIL(slice_reader.ReadExponentialGolomb( | |
216 &memory_management_control_operation)); | |
217 if (memory_management_control_operation == 1 || | |
218 memory_management_control_operation == 3) { | |
219 // difference_of_pic_nums_minus1: ue(v) | |
220 RETURN_FALSE_ON_FAIL( | |
221 slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
222 } | |
223 if (memory_management_control_operation == 2) { | |
224 // long_term_pic_num: ue(v) | |
225 RETURN_FALSE_ON_FAIL( | |
226 slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
227 } | |
228 if (memory_management_control_operation == 3 || | |
229 memory_management_control_operation == 6) { | |
230 // long_term_frame_idx: ue(v) | |
231 RETURN_FALSE_ON_FAIL( | |
232 slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
233 } | |
234 if (memory_management_control_operation == 4) { | |
235 // max_long_term_frame_idx_plus1: ue(v) | |
236 RETURN_FALSE_ON_FAIL( | |
237 slice_reader.ReadExponentialGolomb(&golomb_tmp)); | |
238 } | |
239 } while (memory_management_control_operation != 0); | |
240 } | |
241 } | |
242 } | |
243 // cabac not supported: entropy_coding_mode_flag == 0 asserted above. | |
244 // if (entropy_coding_mode_flag && slice_type != I && slice_type != SI) | |
245 // cabac_init_idc | |
246 int32_t last_slice_qp_delta; | |
247 RETURN_FALSE_ON_FAIL( | |
248 slice_reader.ReadSignedExponentialGolomb(&last_slice_qp_delta)); | |
249 last_slice_qp_delta_ = rtc::Optional<int32_t>(last_slice_qp_delta); | |
250 return true; | |
251 } | |
252 | |
253 void H264BitstreamParser::ParseSlice(const uint8_t* slice, size_t length) { | |
254 H264::NaluType nalu_type = H264::ParseNaluType(slice[0]); | |
255 switch (nalu_type) { | |
256 case H264::NaluType::kSps: { | |
257 sps_ = SpsParser::ParseSps(slice + H264::kNaluTypeSize, | |
258 length - H264::kNaluTypeSize); | |
259 if (!sps_) | |
260 FATAL() << "Unable to parse SPS from H264 bitstream."; | |
261 break; | |
262 } | |
263 case H264::NaluType::kPps: { | |
264 pps_ = PpsParser::ParsePps(slice + H264::kNaluTypeSize, | |
265 length - H264::kNaluTypeSize); | |
266 if (!pps_) | |
267 FATAL() << "Unable to parse PPS from H264 bitstream."; | |
268 break; | |
269 } | |
270 default: | |
271 RTC_CHECK(ParseNonParameterSetNalu(slice, length, nalu_type)) | |
272 << "Failed to parse picture slice."; | |
273 break; | |
274 } | |
275 } | |
276 | |
277 void H264BitstreamParser::ParseBitstream(const uint8_t* bitstream, | |
278 size_t length) { | |
279 std::vector<H264::NaluIndex> nalu_indices = | |
280 H264::FindNaluIndices(bitstream, length); | |
281 RTC_CHECK(!nalu_indices.empty()); | |
282 for (const H264::NaluIndex& index : nalu_indices) | |
283 ParseSlice(&bitstream[index.payload_start_offset], index.payload_size); | |
284 } | |
285 | |
286 bool H264BitstreamParser::GetLastSliceQp(int* qp) const { | |
287 if (!last_slice_qp_delta_ || !pps_) | |
288 return false; | |
289 *qp = 26 + pps_->pic_init_qp_minus26 + *last_slice_qp_delta_; | |
290 return true; | |
291 } | |
292 | |
293 } // namespace webrtc | |
OLD | NEW |