Shaka Packager SDK
Loading...
Searching...
No Matches
h264_parser.cc
1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <packager/media/codecs/h264_parser.h>
6
7#include <cstddef>
8#include <cstdint>
9#include <cstring>
10#include <iterator>
11#include <memory>
12#include <utility>
13
14#include <absl/log/check.h>
15#include <absl/log/log.h>
16
17#include <packager/macros/logging.h>
18#include <packager/media/codecs/h26x_bit_reader.h>
19#include <packager/media/codecs/nalu_reader.h>
20
21#define LOG_ERROR_ONCE(msg) \
22 do { \
23 static bool logged_once = false; \
24 LOG_IF(ERROR, !logged_once) << msg; \
25 logged_once = true; \
26 } while (0)
27
28namespace shaka {
29namespace media {
30
31// Implemented according to ISO/IEC 14496-10:2005 7.4.2.1 Sequence parameter set
32// RBSP semantics.
33bool ExtractResolutionFromSps(const H264Sps& sps,
34 uint32_t* coded_width,
35 uint32_t* coded_height,
36 uint32_t* pixel_width,
37 uint32_t* pixel_height) {
38 int crop_x = 0;
39 int crop_y = 0;
40 if (sps.frame_cropping_flag) {
41 int sub_width_c = 0;
42 int sub_height_c = 0;
43 // Table 6-1.
44 switch (sps.chroma_format_idc) {
45 case 0: // monochrome
46 // SubWidthC and SubHeightC are not defined for monochrome. For ease of
47 // computation afterwards, assign both to 1.
48 sub_width_c = 1;
49 sub_height_c = 1;
50 break;
51 case 1: // 4:2:0
52 sub_width_c = 2;
53 sub_height_c = 2;
54 break;
55 case 2: // 4:2:2
56 sub_width_c = 2;
57 sub_height_c = 1;
58 break;
59 case 3: // 4:4:4
60 sub_width_c = 1;
61 sub_height_c = 1;
62 break;
63 default:
64 LOG(ERROR) << "Unexpected chroma_format_idc " << sps.chroma_format_idc;
65 return false;
66 }
67
68 // Formula 7-16, 7-17, 7-18, 7-19.
69 int crop_unit_x = sub_width_c;
70 int crop_unit_y = sub_height_c * (2 - (sps.frame_mbs_only_flag ? 1 : 0));
71 crop_x = crop_unit_x *
72 (sps.frame_crop_left_offset + sps.frame_crop_right_offset);
73 crop_y = crop_unit_y *
74 (sps.frame_crop_top_offset + sps.frame_crop_bottom_offset);
75 }
76
77 // Formula 7-10, 7-11.
78 int pic_width_in_mbs = sps.pic_width_in_mbs_minus1 + 1;
79 *coded_width = pic_width_in_mbs * 16 - crop_x;
80
81 // Formula 7-13, 7-15.
82 int pic_height_in_mbs = (2 - (sps.frame_mbs_only_flag ? 1 : 0)) *
83 (sps.pic_height_in_map_units_minus1 + 1);
84 *coded_height = pic_height_in_mbs * 16 - crop_y;
85
86 // 0 means it wasn't in the SPS and therefore assume 1.
87 *pixel_width = sps.sar_width == 0 ? 1 : sps.sar_width;
88 *pixel_height = sps.sar_height == 0 ? 1 : sps.sar_height;
89 DVLOG(2) << "Found coded_width: " << *coded_width
90 << " coded_height: " << *coded_height
91 << " pixel_width: " << *pixel_width
92 << " pixel_height: " << *pixel_height;
93 return true;
94}
95
96bool H264SliceHeader::IsPSlice() const {
97 return (slice_type % 5 == kPSlice);
98}
99
100bool H264SliceHeader::IsBSlice() const {
101 return (slice_type % 5 == kBSlice);
102}
103
104bool H264SliceHeader::IsISlice() const {
105 return (slice_type % 5 == kISlice);
106}
107
108bool H264SliceHeader::IsSPSlice() const {
109 return (slice_type % 5 == kSPSlice);
110}
111
112bool H264SliceHeader::IsSISlice() const {
113 return (slice_type % 5 == kSISlice);
114}
115
116#define READ_BITS_OR_RETURN(num_bits, out) \
117 do { \
118 if (!br->ReadBits(num_bits, (out))) { \
119 DVLOG(1) \
120 << "Error in stream: unexpected EOS while trying to read " #out; \
121 return kInvalidStream; \
122 } \
123 } while (0)
124
125#define READ_LONG_OR_RETURN(out) \
126 do { \
127 long _out; \
128 int _tmp_out; \
129 READ_BITS_OR_RETURN(16, &_tmp_out); \
130 _out = (long)(_tmp_out) << 16; \
131 READ_BITS_OR_RETURN(16, &_tmp_out); \
132 _out |= _tmp_out; \
133 *(out) = _out; \
134 } while (0)
135
136#define READ_BOOL_OR_RETURN(out) \
137 do { \
138 int _out; \
139 if (!br->ReadBits(1, &_out)) { \
140 DVLOG(1) \
141 << "Error in stream: unexpected EOS while trying to read " #out; \
142 return kInvalidStream; \
143 } \
144 *(out) = _out != 0; \
145 } while (0)
146
147#define READ_UE_OR_RETURN(out) \
148 do { \
149 if (!br->ReadUE(out)) { \
150 DVLOG(1) << "Error in stream: invalid value while trying to read " #out; \
151 return kInvalidStream; \
152 } \
153 } while (0)
154
155#define READ_SE_OR_RETURN(out) \
156 do { \
157 if (!br->ReadSE(out)) { \
158 DVLOG(1) << "Error in stream: invalid value while trying to read " #out; \
159 return kInvalidStream; \
160 } \
161 } while (0)
162
163#define IN_RANGE_OR_RETURN(val, min, max) \
164 do { \
165 if ((val) < (min) || (val) > (max)) { \
166 DVLOG(1) << "Error in stream: invalid value, expected " #val " to be" \
167 << " in range [" << (min) << ":" << (max) << "]" \
168 << " found " << (val) << " instead"; \
169 return kInvalidStream; \
170 } \
171 } while (0)
172
173#define TRUE_OR_RETURN(a) \
174 do { \
175 if (!(a)) { \
176 DVLOG(1) << "Error in stream: invalid value, expected " << #a; \
177 return kInvalidStream; \
178 } \
179 } while (0)
180
181enum AspectRatioIdc {
182 kExtendedSar = 255,
183};
184
185// ISO 14496 part 10
186// VUI parameters: Table E-1 "Meaning of sample aspect ratio indicator"
187static const int kTableSarWidth[] = {0, 1, 12, 10, 16, 40, 24, 20, 32,
188 80, 18, 15, 64, 160, 4, 3, 2};
189static const int kTableSarHeight[] = {0, 1, 11, 11, 11, 33, 11, 11, 11,
190 33, 11, 11, 33, 99, 3, 2, 1};
191static_assert(std::size(kTableSarWidth) == std::size(kTableSarHeight),
192 "sar_tables_must_have_same_size");
193
194H264Parser::H264Parser() {}
195
196H264Parser::~H264Parser() {}
197
198const H264Pps* H264Parser::GetPps(int pps_id) {
199 return active_PPSes_[pps_id].get();
200}
201
202const H264Sps* H264Parser::GetSps(int sps_id) {
203 return active_SPSes_[sps_id].get();
204}
205
206// Default scaling lists (per spec).
207static const int kDefault4x4Intra[kH264ScalingList4x4Length] = {
208 6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, 32, 32, 37, 37, 42,
209};
210
211static const int kDefault4x4Inter[kH264ScalingList4x4Length] = {
212 10, 14, 14, 20, 20, 20, 24, 24, 24, 24, 27, 27, 27, 30, 30, 34,
213};
214
215static const int kDefault8x8Intra[kH264ScalingList8x8Length] = {
216 6, 10, 10, 13, 11, 13, 16, 16, 16, 16, 18, 18, 18, 18, 18, 23,
217 23, 23, 23, 23, 23, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27,
218 27, 27, 27, 27, 29, 29, 29, 29, 29, 29, 29, 31, 31, 31, 31, 31,
219 31, 33, 33, 33, 33, 33, 36, 36, 36, 36, 38, 38, 38, 40, 40, 42,
220};
221
222static const int kDefault8x8Inter[kH264ScalingList8x8Length] = {
223 9, 13, 13, 15, 13, 15, 17, 17, 17, 17, 19, 19, 19, 19, 19, 21,
224 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24, 24,
225 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27,
226 27, 28, 28, 28, 28, 28, 30, 30, 30, 30, 32, 32, 32, 33, 33, 35,
227};
228
229static inline void DefaultScalingList4x4(
230 int i,
231 int scaling_list4x4[][kH264ScalingList4x4Length]) {
232 DCHECK_LT(i, 6);
233
234 if (i < 3)
235 memcpy(scaling_list4x4[i], kDefault4x4Intra, sizeof(kDefault4x4Intra));
236 else if (i < 6)
237 memcpy(scaling_list4x4[i], kDefault4x4Inter, sizeof(kDefault4x4Inter));
238}
239
240static inline void DefaultScalingList8x8(
241 int i,
242 int scaling_list8x8[][kH264ScalingList8x8Length]) {
243 DCHECK_LT(i, 6);
244
245 if (i % 2 == 0)
246 memcpy(scaling_list8x8[i], kDefault8x8Intra, sizeof(kDefault8x8Intra));
247 else
248 memcpy(scaling_list8x8[i], kDefault8x8Inter, sizeof(kDefault8x8Inter));
249}
250
251static void FallbackScalingList4x4(
252 int i,
253 const int default_scaling_list_intra[],
254 const int default_scaling_list_inter[],
255 int scaling_list4x4[][kH264ScalingList4x4Length]) {
256 static const int kScalingList4x4ByteSize =
257 sizeof(scaling_list4x4[0][0]) * kH264ScalingList4x4Length;
258
259 switch (i) {
260 case 0:
261 memcpy(scaling_list4x4[i], default_scaling_list_intra,
262 kScalingList4x4ByteSize);
263 break;
264
265 case 1:
266 memcpy(scaling_list4x4[i], scaling_list4x4[0], kScalingList4x4ByteSize);
267 break;
268
269 case 2:
270 memcpy(scaling_list4x4[i], scaling_list4x4[1], kScalingList4x4ByteSize);
271 break;
272
273 case 3:
274 memcpy(scaling_list4x4[i], default_scaling_list_inter,
275 kScalingList4x4ByteSize);
276 break;
277
278 case 4:
279 memcpy(scaling_list4x4[i], scaling_list4x4[3], kScalingList4x4ByteSize);
280 break;
281
282 case 5:
283 memcpy(scaling_list4x4[i], scaling_list4x4[4], kScalingList4x4ByteSize);
284 break;
285
286 default:
287 NOTIMPLEMENTED() << "index out of range [0,5]: " << i;
288 break;
289 }
290}
291
292static void FallbackScalingList8x8(
293 int i,
294 const int default_scaling_list_intra[],
295 const int default_scaling_list_inter[],
296 int scaling_list8x8[][kH264ScalingList8x8Length]) {
297 static const int kScalingList8x8ByteSize =
298 sizeof(scaling_list8x8[0][0]) * kH264ScalingList8x8Length;
299
300 switch (i) {
301 case 0:
302 memcpy(scaling_list8x8[i], default_scaling_list_intra,
303 kScalingList8x8ByteSize);
304 break;
305
306 case 1:
307 memcpy(scaling_list8x8[i], default_scaling_list_inter,
308 kScalingList8x8ByteSize);
309 break;
310
311 case 2:
312 memcpy(scaling_list8x8[i], scaling_list8x8[0], kScalingList8x8ByteSize);
313 break;
314
315 case 3:
316 memcpy(scaling_list8x8[i], scaling_list8x8[1], kScalingList8x8ByteSize);
317 break;
318
319 case 4:
320 memcpy(scaling_list8x8[i], scaling_list8x8[2], kScalingList8x8ByteSize);
321 break;
322
323 case 5:
324 memcpy(scaling_list8x8[i], scaling_list8x8[3], kScalingList8x8ByteSize);
325 break;
326
327 default:
328 NOTIMPLEMENTED() << "index out of range [0,5]: " << i;
329 break;
330 }
331}
332
333H264Parser::Result H264Parser::ParseScalingList(H26xBitReader* br,
334 int size,
335 int* scaling_list,
336 bool* use_default) {
337 // See chapter 7.3.2.1.1.1.
338 int last_scale = 8;
339 int next_scale = 8;
340 int delta_scale;
341
342 *use_default = false;
343
344 for (int j = 0; j < size; ++j) {
345 if (next_scale != 0) {
346 READ_SE_OR_RETURN(&delta_scale);
347 IN_RANGE_OR_RETURN(delta_scale, -128, 127);
348 next_scale = (last_scale + delta_scale + 256) & 0xff;
349
350 if (j == 0 && next_scale == 0) {
351 *use_default = true;
352 return kOk;
353 }
354 }
355
356 scaling_list[j] = (next_scale == 0) ? last_scale : next_scale;
357 last_scale = scaling_list[j];
358 }
359
360 return kOk;
361}
362
363H264Parser::Result H264Parser::ParseSpsScalingLists(H26xBitReader* br,
364 H264Sps* sps) {
365 // See 7.4.2.1.1.
366 bool seq_scaling_list_present_flag;
367 bool use_default;
368 Result res;
369
370 // Parse scaling_list4x4.
371 for (int i = 0; i < 6; ++i) {
372 READ_BOOL_OR_RETURN(&seq_scaling_list_present_flag);
373
374 if (seq_scaling_list_present_flag) {
375 res = ParseScalingList(br, std::size(sps->scaling_list4x4[i]),
376 sps->scaling_list4x4[i], &use_default);
377 if (res != kOk)
378 return res;
379
380 if (use_default)
381 DefaultScalingList4x4(i, sps->scaling_list4x4);
382
383 } else {
384 FallbackScalingList4x4(i, kDefault4x4Intra, kDefault4x4Inter,
385 sps->scaling_list4x4);
386 }
387 }
388
389 // Parse scaling_list8x8.
390 for (int i = 0; i < ((sps->chroma_format_idc != 3) ? 2 : 6); ++i) {
391 READ_BOOL_OR_RETURN(&seq_scaling_list_present_flag);
392
393 if (seq_scaling_list_present_flag) {
394 res = ParseScalingList(br, std::size(sps->scaling_list8x8[i]),
395 sps->scaling_list8x8[i], &use_default);
396 if (res != kOk)
397 return res;
398
399 if (use_default)
400 DefaultScalingList8x8(i, sps->scaling_list8x8);
401
402 } else {
403 FallbackScalingList8x8(i, kDefault8x8Intra, kDefault8x8Inter,
404 sps->scaling_list8x8);
405 }
406 }
407
408 return kOk;
409}
410
411H264Parser::Result H264Parser::ParsePpsScalingLists(H26xBitReader* br,
412 const H264Sps& sps,
413 H264Pps* pps) {
414 // See 7.4.2.2.
415 bool pic_scaling_list_present_flag;
416 bool use_default;
417 Result res;
418
419 for (int i = 0; i < 6; ++i) {
420 READ_BOOL_OR_RETURN(&pic_scaling_list_present_flag);
421
422 if (pic_scaling_list_present_flag) {
423 res = ParseScalingList(br, std::size(pps->scaling_list4x4[i]),
424 pps->scaling_list4x4[i], &use_default);
425 if (res != kOk)
426 return res;
427
428 if (use_default)
429 DefaultScalingList4x4(i, pps->scaling_list4x4);
430
431 } else {
432 if (sps.seq_scaling_matrix_present_flag) {
433 // Table 7-2 fallback rule A in spec.
434 FallbackScalingList4x4(i, kDefault4x4Intra, kDefault4x4Inter,
435 pps->scaling_list4x4);
436 } else {
437 // Table 7-2 fallback rule B in spec.
438 FallbackScalingList4x4(i, sps.scaling_list4x4[0],
439 sps.scaling_list4x4[3], pps->scaling_list4x4);
440 }
441 }
442 }
443
444 if (pps->transform_8x8_mode_flag) {
445 for (int i = 0; i < ((sps.chroma_format_idc != 3) ? 2 : 6); ++i) {
446 READ_BOOL_OR_RETURN(&pic_scaling_list_present_flag);
447
448 if (pic_scaling_list_present_flag) {
449 res = ParseScalingList(br, std::size(pps->scaling_list8x8[i]),
450 pps->scaling_list8x8[i], &use_default);
451 if (res != kOk)
452 return res;
453
454 if (use_default)
455 DefaultScalingList8x8(i, pps->scaling_list8x8);
456
457 } else {
458 if (sps.seq_scaling_matrix_present_flag) {
459 // Table 7-2 fallback rule A in spec.
460 FallbackScalingList8x8(i, kDefault8x8Intra, kDefault8x8Inter,
461 pps->scaling_list8x8);
462 } else {
463 // Table 7-2 fallback rule B in spec.
464 FallbackScalingList8x8(i, sps.scaling_list8x8[0],
465 sps.scaling_list8x8[1], pps->scaling_list8x8);
466 }
467 }
468 }
469 }
470 return kOk;
471}
472
473H264Parser::Result H264Parser::ParseAndIgnoreHRDParameters(
474 H26xBitReader* br,
475 bool* hrd_parameters_present) {
476 int data;
477 READ_BOOL_OR_RETURN(&data); // {nal,vcl}_hrd_parameters_present_flag
478 if (!data)
479 return kOk;
480
481 *hrd_parameters_present = true;
482
483 int cpb_cnt_minus1;
484 READ_UE_OR_RETURN(&cpb_cnt_minus1);
485 IN_RANGE_OR_RETURN(cpb_cnt_minus1, 0, 31);
486 READ_BITS_OR_RETURN(8, &data); // bit_rate_scale, cpb_size_scale
487 for (int i = 0; i <= cpb_cnt_minus1; ++i) {
488 READ_UE_OR_RETURN(&data); // bit_rate_value_minus1[i]
489 READ_UE_OR_RETURN(&data); // cpb_size_value_minus1[i]
490 READ_BOOL_OR_RETURN(&data); // cbr_flag
491 }
492 READ_BITS_OR_RETURN(20, &data); // cpb/dpb delays, etc.
493
494 return kOk;
495}
496
497H264Parser::Result H264Parser::ParseVUIParameters(H26xBitReader* br,
498 H264Sps* sps) {
499 bool aspect_ratio_info_present_flag;
500 READ_BOOL_OR_RETURN(&aspect_ratio_info_present_flag);
501 if (aspect_ratio_info_present_flag) {
502 int aspect_ratio_idc;
503 READ_BITS_OR_RETURN(8, &aspect_ratio_idc);
504 if (aspect_ratio_idc == kExtendedSar) {
505 READ_BITS_OR_RETURN(16, &sps->sar_width);
506 READ_BITS_OR_RETURN(16, &sps->sar_height);
507 } else {
508 const int max_aspect_ratio_idc = std::size(kTableSarWidth) - 1;
509 IN_RANGE_OR_RETURN(aspect_ratio_idc, 0, max_aspect_ratio_idc);
510 sps->sar_width = kTableSarWidth[aspect_ratio_idc];
511 sps->sar_height = kTableSarHeight[aspect_ratio_idc];
512 }
513 }
514
515 int data;
516 // Read and ignore overscan and video signal type info.
517 READ_BOOL_OR_RETURN(&data); // overscan_info_present_flag
518 if (data)
519 READ_BOOL_OR_RETURN(&data); // overscan_appropriate_flag
520
521 READ_BOOL_OR_RETURN(&data); // video_signal_type_present_flag
522 if (data) {
523 READ_BITS_OR_RETURN(3, &data); // video_format
524 READ_BOOL_OR_RETURN(&data); // video_full_range_flag
525 READ_BOOL_OR_RETURN(&data); // colour_description_present_flag
526 if (data) {
527 READ_BITS_OR_RETURN(8, &sps->color_primaries); // colour primaries
528 READ_BITS_OR_RETURN(8, &sps->transfer_characteristics);
529 READ_BITS_OR_RETURN(8, &sps->matrix_coefficients); // matrix coeffs
530 }
531 }
532
533 READ_BOOL_OR_RETURN(&data); // chroma_loc_info_present_flag
534 if (data) {
535 READ_UE_OR_RETURN(&data); // chroma_sample_loc_type_top_field
536 READ_UE_OR_RETURN(&data); // chroma_sample_loc_type_bottom_field
537 }
538
539 // Read timing info.
540 READ_BOOL_OR_RETURN(&sps->timing_info_present_flag);
541 if (sps->timing_info_present_flag) {
542 READ_LONG_OR_RETURN(&sps->num_units_in_tick);
543 READ_LONG_OR_RETURN(&sps->time_scale);
544 READ_BOOL_OR_RETURN(&sps->fixed_frame_rate_flag);
545 }
546
547 // Read and ignore NAL HRD parameters, if present.
548 bool hrd_parameters_present = false;
549 Result res = ParseAndIgnoreHRDParameters(br, &hrd_parameters_present);
550 if (res != kOk)
551 return res;
552
553 // Read and ignore VCL HRD parameters, if present.
554 res = ParseAndIgnoreHRDParameters(br, &hrd_parameters_present);
555 if (res != kOk)
556 return res;
557
558 if (hrd_parameters_present) // One of NAL or VCL params present is enough.
559 READ_BOOL_OR_RETURN(&data); // low_delay_hrd_flag
560
561 READ_BOOL_OR_RETURN(&data); // pic_struct_present_flag
562 READ_BOOL_OR_RETURN(&sps->bitstream_restriction_flag);
563 if (sps->bitstream_restriction_flag) {
564 READ_BOOL_OR_RETURN(&data); // motion_vectors_over_pic_boundaries_flag
565 READ_UE_OR_RETURN(&data); // max_bytes_per_pic_denom
566 READ_UE_OR_RETURN(&data); // max_bits_per_mb_denom
567 READ_UE_OR_RETURN(&data); // log2_max_mv_length_horizontal
568 READ_UE_OR_RETURN(&data); // log2_max_mv_length_vertical
569 READ_UE_OR_RETURN(&sps->max_num_reorder_frames);
570 READ_UE_OR_RETURN(&sps->max_dec_frame_buffering);
571 TRUE_OR_RETURN(sps->max_dec_frame_buffering >= sps->max_num_ref_frames);
572 IN_RANGE_OR_RETURN(sps->max_num_reorder_frames, 0,
573 sps->max_dec_frame_buffering);
574 }
575
576 return kOk;
577}
578
579static void FillDefaultSeqScalingLists(H264Sps* sps) {
580 for (int i = 0; i < 6; ++i)
581 for (int j = 0; j < kH264ScalingList4x4Length; ++j)
582 sps->scaling_list4x4[i][j] = 16;
583
584 for (int i = 0; i < 6; ++i)
585 for (int j = 0; j < kH264ScalingList8x8Length; ++j)
586 sps->scaling_list8x8[i][j] = 16;
587}
588
589H264Parser::Result H264Parser::ParseSps(const Nalu& nalu, int* sps_id) {
590 // See 7.4.2.1.
591 int data;
592 Result res;
593 H26xBitReader reader;
594 reader.Initialize(nalu.data() + nalu.header_size(), nalu.payload_size());
595 H26xBitReader* br = &reader;
596
597 *sps_id = -1;
598
599 std::unique_ptr<H264Sps> sps(new H264Sps());
600
601 READ_BITS_OR_RETURN(8, &sps->profile_idc);
602 READ_BOOL_OR_RETURN(&sps->constraint_set0_flag);
603 READ_BOOL_OR_RETURN(&sps->constraint_set1_flag);
604 READ_BOOL_OR_RETURN(&sps->constraint_set2_flag);
605 READ_BOOL_OR_RETURN(&sps->constraint_set3_flag);
606 READ_BOOL_OR_RETURN(&sps->constraint_set4_flag);
607 READ_BOOL_OR_RETURN(&sps->constraint_set5_flag);
608 READ_BITS_OR_RETURN(2, &data); // reserved_zero_2bits
609 READ_BITS_OR_RETURN(8, &sps->level_idc);
610 READ_UE_OR_RETURN(&sps->seq_parameter_set_id);
611 TRUE_OR_RETURN(sps->seq_parameter_set_id < 32);
612
613 if (sps->profile_idc == 100 || sps->profile_idc == 110 ||
614 sps->profile_idc == 122 || sps->profile_idc == 244 ||
615 sps->profile_idc == 44 || sps->profile_idc == 83 ||
616 sps->profile_idc == 86 || sps->profile_idc == 118 ||
617 sps->profile_idc == 128) {
618 READ_UE_OR_RETURN(&sps->chroma_format_idc);
619 TRUE_OR_RETURN(sps->chroma_format_idc < 4);
620
621 if (sps->chroma_format_idc == 3)
622 READ_BOOL_OR_RETURN(&sps->separate_colour_plane_flag);
623
624 READ_UE_OR_RETURN(&sps->bit_depth_luma_minus8);
625 TRUE_OR_RETURN(sps->bit_depth_luma_minus8 < 7);
626
627 READ_UE_OR_RETURN(&sps->bit_depth_chroma_minus8);
628 TRUE_OR_RETURN(sps->bit_depth_chroma_minus8 < 7);
629
630 READ_BOOL_OR_RETURN(&sps->qpprime_y_zero_transform_bypass_flag);
631 READ_BOOL_OR_RETURN(&sps->seq_scaling_matrix_present_flag);
632
633 if (sps->seq_scaling_matrix_present_flag) {
634 DVLOG(4) << "Scaling matrix present";
635 res = ParseSpsScalingLists(br, sps.get());
636 if (res != kOk)
637 return res;
638 } else {
639 FillDefaultSeqScalingLists(sps.get());
640 }
641 } else {
642 sps->chroma_format_idc = 1;
643 FillDefaultSeqScalingLists(sps.get());
644 }
645
646 if (sps->separate_colour_plane_flag)
647 sps->chroma_array_type = 0;
648 else
649 sps->chroma_array_type = sps->chroma_format_idc;
650
651 READ_UE_OR_RETURN(&sps->log2_max_frame_num_minus4);
652 TRUE_OR_RETURN(sps->log2_max_frame_num_minus4 < 13);
653
654 READ_UE_OR_RETURN(&sps->pic_order_cnt_type);
655 TRUE_OR_RETURN(sps->pic_order_cnt_type < 3);
656
657 sps->expected_delta_per_pic_order_cnt_cycle = 0;
658 if (sps->pic_order_cnt_type == 0) {
659 READ_UE_OR_RETURN(&sps->log2_max_pic_order_cnt_lsb_minus4);
660 TRUE_OR_RETURN(sps->log2_max_pic_order_cnt_lsb_minus4 < 13);
661 } else if (sps->pic_order_cnt_type == 1) {
662 READ_BOOL_OR_RETURN(&sps->delta_pic_order_always_zero_flag);
663 READ_SE_OR_RETURN(&sps->offset_for_non_ref_pic);
664 READ_SE_OR_RETURN(&sps->offset_for_top_to_bottom_field);
665 READ_UE_OR_RETURN(&sps->num_ref_frames_in_pic_order_cnt_cycle);
666 TRUE_OR_RETURN(sps->num_ref_frames_in_pic_order_cnt_cycle < 255);
667
668 for (int i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; ++i) {
669 READ_SE_OR_RETURN(&sps->offset_for_ref_frame[i]);
670 sps->expected_delta_per_pic_order_cnt_cycle +=
671 sps->offset_for_ref_frame[i];
672 }
673 }
674
675 READ_UE_OR_RETURN(&sps->max_num_ref_frames);
676 READ_BOOL_OR_RETURN(&sps->gaps_in_frame_num_value_allowed_flag);
677
678 READ_UE_OR_RETURN(&sps->pic_width_in_mbs_minus1);
679 READ_UE_OR_RETURN(&sps->pic_height_in_map_units_minus1);
680
681 READ_BOOL_OR_RETURN(&sps->frame_mbs_only_flag);
682 if (!sps->frame_mbs_only_flag)
683 READ_BOOL_OR_RETURN(&sps->mb_adaptive_frame_field_flag);
684
685 READ_BOOL_OR_RETURN(&sps->direct_8x8_inference_flag);
686
687 READ_BOOL_OR_RETURN(&sps->frame_cropping_flag);
688 if (sps->frame_cropping_flag) {
689 READ_UE_OR_RETURN(&sps->frame_crop_left_offset);
690 READ_UE_OR_RETURN(&sps->frame_crop_right_offset);
691 READ_UE_OR_RETURN(&sps->frame_crop_top_offset);
692 READ_UE_OR_RETURN(&sps->frame_crop_bottom_offset);
693 }
694
695 READ_BOOL_OR_RETURN(&sps->vui_parameters_present_flag);
696 if (sps->vui_parameters_present_flag) {
697 DVLOG(4) << "VUI parameters present";
698 res = ParseVUIParameters(br, sps.get());
699 if (res != kOk)
700 return res;
701 }
702
703 // If an SPS with the same id already exists, replace it.
704 *sps_id = sps->seq_parameter_set_id;
705 active_SPSes_[*sps_id] = std::move(sps);
706
707 return kOk;
708}
709
710H264Parser::Result H264Parser::ParsePps(const Nalu& nalu, int* pps_id) {
711 // See 7.4.2.2.
712 const H264Sps* sps;
713 Result res;
714 H26xBitReader reader;
715 reader.Initialize(nalu.data() + nalu.header_size(), nalu.payload_size());
716 H26xBitReader* br = &reader;
717
718 *pps_id = -1;
719
720 std::unique_ptr<H264Pps> pps(new H264Pps());
721
722 READ_UE_OR_RETURN(&pps->pic_parameter_set_id);
723 READ_UE_OR_RETURN(&pps->seq_parameter_set_id);
724 TRUE_OR_RETURN(pps->seq_parameter_set_id < 32);
725
726 sps = GetSps(pps->seq_parameter_set_id);
727 TRUE_OR_RETURN(sps);
728
729 READ_BOOL_OR_RETURN(&pps->entropy_coding_mode_flag);
730 READ_BOOL_OR_RETURN(&pps->bottom_field_pic_order_in_frame_present_flag);
731
732 READ_UE_OR_RETURN(&pps->num_slice_groups_minus1);
733 if (pps->num_slice_groups_minus1 > 1) {
734 LOG_ERROR_ONCE("Slice groups not supported");
735 return kUnsupportedStream;
736 }
737
738 READ_UE_OR_RETURN(&pps->num_ref_idx_l0_default_active_minus1);
739 TRUE_OR_RETURN(pps->num_ref_idx_l0_default_active_minus1 < 32);
740
741 READ_UE_OR_RETURN(&pps->num_ref_idx_l1_default_active_minus1);
742 TRUE_OR_RETURN(pps->num_ref_idx_l1_default_active_minus1 < 32);
743
744 READ_BOOL_OR_RETURN(&pps->weighted_pred_flag);
745 READ_BITS_OR_RETURN(2, &pps->weighted_bipred_idc);
746 TRUE_OR_RETURN(pps->weighted_bipred_idc < 3);
747
748 READ_SE_OR_RETURN(&pps->pic_init_qp_minus26);
749 IN_RANGE_OR_RETURN(pps->pic_init_qp_minus26, -26, 25);
750
751 READ_SE_OR_RETURN(&pps->pic_init_qs_minus26);
752 IN_RANGE_OR_RETURN(pps->pic_init_qs_minus26, -26, 25);
753
754 READ_SE_OR_RETURN(&pps->chroma_qp_index_offset);
755 IN_RANGE_OR_RETURN(pps->chroma_qp_index_offset, -12, 12);
756 pps->second_chroma_qp_index_offset = pps->chroma_qp_index_offset;
757
758 READ_BOOL_OR_RETURN(&pps->deblocking_filter_control_present_flag);
759 READ_BOOL_OR_RETURN(&pps->constrained_intra_pred_flag);
760 READ_BOOL_OR_RETURN(&pps->redundant_pic_cnt_present_flag);
761
762 if (br->HasMoreRBSPData()) {
763 READ_BOOL_OR_RETURN(&pps->transform_8x8_mode_flag);
764 READ_BOOL_OR_RETURN(&pps->pic_scaling_matrix_present_flag);
765
766 if (pps->pic_scaling_matrix_present_flag) {
767 DVLOG(4) << "Picture scaling matrix present";
768 res = ParsePpsScalingLists(br, *sps, pps.get());
769 if (res != kOk)
770 return res;
771 }
772
773 READ_SE_OR_RETURN(&pps->second_chroma_qp_index_offset);
774 }
775
776 // If a PPS with the same id already exists, replace it.
777 *pps_id = pps->pic_parameter_set_id;
778 active_PPSes_[*pps_id] = std::move(pps);
779
780 return kOk;
781}
782
783H264Parser::Result H264Parser::ParseRefPicListModification(
784 H26xBitReader* br,
785 int num_ref_idx_active_minus1,
786 H264ModificationOfPicNum* ref_list_mods) {
787 H264ModificationOfPicNum* pic_num_mod;
788
789 if (num_ref_idx_active_minus1 >= 32)
790 return kInvalidStream;
791
792 for (int i = 0; i < 32; ++i) {
793 pic_num_mod = &ref_list_mods[i];
794 READ_UE_OR_RETURN(&pic_num_mod->modification_of_pic_nums_idc);
795 TRUE_OR_RETURN(pic_num_mod->modification_of_pic_nums_idc < 4);
796
797 switch (pic_num_mod->modification_of_pic_nums_idc) {
798 case 0:
799 case 1:
800 READ_UE_OR_RETURN(&pic_num_mod->abs_diff_pic_num_minus1);
801 break;
802
803 case 2:
804 READ_UE_OR_RETURN(&pic_num_mod->long_term_pic_num);
805 break;
806
807 case 3:
808 // Per spec, list cannot be empty.
809 if (i == 0)
810 return kInvalidStream;
811 return kOk;
812
813 default:
814 return kInvalidStream;
815 }
816 }
817
818 // If we got here, we didn't get loop end marker prematurely,
819 // so make sure it is there for our client.
820 int modification_of_pic_nums_idc;
821 READ_UE_OR_RETURN(&modification_of_pic_nums_idc);
822 TRUE_OR_RETURN(modification_of_pic_nums_idc == 3);
823
824 return kOk;
825}
826
827H264Parser::Result H264Parser::ParseRefPicListModifications(
828 H26xBitReader* br,
829 H264SliceHeader* shdr) {
830 Result res;
831
832 if (!shdr->IsISlice() && !shdr->IsSISlice()) {
833 READ_BOOL_OR_RETURN(&shdr->ref_pic_list_modification_flag_l0);
834 if (shdr->ref_pic_list_modification_flag_l0) {
835 res = ParseRefPicListModification(br, shdr->num_ref_idx_l0_active_minus1,
836 shdr->ref_list_l0_modifications);
837 if (res != kOk)
838 return res;
839 }
840 }
841
842 if (shdr->IsBSlice()) {
843 READ_BOOL_OR_RETURN(&shdr->ref_pic_list_modification_flag_l1);
844 if (shdr->ref_pic_list_modification_flag_l1) {
845 res = ParseRefPicListModification(br, shdr->num_ref_idx_l1_active_minus1,
846 shdr->ref_list_l1_modifications);
847 if (res != kOk)
848 return res;
849 }
850 }
851
852 return kOk;
853}
854
855H264Parser::Result H264Parser::ParseWeightingFactors(
856 H26xBitReader* br,
857 int num_ref_idx_active_minus1,
858 int chroma_array_type,
859 int luma_log2_weight_denom,
860 int chroma_log2_weight_denom,
861 H264WeightingFactors* w_facts) {
862 int def_luma_weight = 1 << luma_log2_weight_denom;
863 int def_chroma_weight = 1 << chroma_log2_weight_denom;
864
865 for (int i = 0; i < num_ref_idx_active_minus1 + 1; ++i) {
866 READ_BOOL_OR_RETURN(&w_facts->luma_weight_flag[i]);
867 if (w_facts->luma_weight_flag[i]) {
868 READ_SE_OR_RETURN(&w_facts->luma_weight[i]);
869 IN_RANGE_OR_RETURN(w_facts->luma_weight[i], -128, 127);
870
871 READ_SE_OR_RETURN(&w_facts->luma_offset[i]);
872 IN_RANGE_OR_RETURN(w_facts->luma_offset[i], -128, 127);
873 } else {
874 w_facts->luma_weight[i] = def_luma_weight;
875 w_facts->luma_offset[i] = 0;
876 }
877
878 if (chroma_array_type != 0) {
879 READ_BOOL_OR_RETURN(&w_facts->chroma_weight_flag[i]);
880 if (w_facts->chroma_weight_flag[i]) {
881 for (int j = 0; j < 2; ++j) {
882 READ_SE_OR_RETURN(&w_facts->chroma_weight[i][j]);
883 IN_RANGE_OR_RETURN(w_facts->chroma_weight[i][j], -128, 127);
884
885 READ_SE_OR_RETURN(&w_facts->chroma_offset[i][j]);
886 IN_RANGE_OR_RETURN(w_facts->chroma_offset[i][j], -128, 127);
887 }
888 } else {
889 for (int j = 0; j < 2; ++j) {
890 w_facts->chroma_weight[i][j] = def_chroma_weight;
891 w_facts->chroma_offset[i][j] = 0;
892 }
893 }
894 }
895 }
896
897 return kOk;
898}
899
900H264Parser::Result H264Parser::ParsePredWeightTable(H26xBitReader* br,
901 const H264Sps& sps,
902 H264SliceHeader* shdr) {
903 READ_UE_OR_RETURN(&shdr->luma_log2_weight_denom);
904 TRUE_OR_RETURN(shdr->luma_log2_weight_denom < 8);
905
906 if (sps.chroma_array_type != 0)
907 READ_UE_OR_RETURN(&shdr->chroma_log2_weight_denom);
908 TRUE_OR_RETURN(shdr->chroma_log2_weight_denom < 8);
909
910 Result res = ParseWeightingFactors(
911 br, shdr->num_ref_idx_l0_active_minus1, sps.chroma_array_type,
912 shdr->luma_log2_weight_denom, shdr->chroma_log2_weight_denom,
913 &shdr->pred_weight_table_l0);
914 if (res != kOk)
915 return res;
916
917 if (shdr->IsBSlice()) {
918 res = ParseWeightingFactors(
919 br, shdr->num_ref_idx_l1_active_minus1, sps.chroma_array_type,
920 shdr->luma_log2_weight_denom, shdr->chroma_log2_weight_denom,
921 &shdr->pred_weight_table_l1);
922 if (res != kOk)
923 return res;
924 }
925
926 return kOk;
927}
928
929H264Parser::Result H264Parser::ParseDecRefPicMarking(H26xBitReader* br,
930 H264SliceHeader* shdr) {
931 if (shdr->idr_pic_flag) {
932 READ_BOOL_OR_RETURN(&shdr->no_output_of_prior_pics_flag);
933 READ_BOOL_OR_RETURN(&shdr->long_term_reference_flag);
934 } else {
935 READ_BOOL_OR_RETURN(&shdr->adaptive_ref_pic_marking_mode_flag);
936
937 H264DecRefPicMarking* marking;
938 if (shdr->adaptive_ref_pic_marking_mode_flag) {
939 size_t i;
940 for (i = 0; i < std::size(shdr->ref_pic_marking); ++i) {
941 marking = &shdr->ref_pic_marking[i];
942
943 READ_UE_OR_RETURN(&marking->memory_mgmnt_control_operation);
944 if (marking->memory_mgmnt_control_operation == 0)
945 break;
946
947 if (marking->memory_mgmnt_control_operation == 1 ||
948 marking->memory_mgmnt_control_operation == 3)
949 READ_UE_OR_RETURN(&marking->difference_of_pic_nums_minus1);
950
951 if (marking->memory_mgmnt_control_operation == 2)
952 READ_UE_OR_RETURN(&marking->long_term_pic_num);
953
954 if (marking->memory_mgmnt_control_operation == 3 ||
955 marking->memory_mgmnt_control_operation == 6)
956 READ_UE_OR_RETURN(&marking->long_term_frame_idx);
957
958 if (marking->memory_mgmnt_control_operation == 4)
959 READ_UE_OR_RETURN(&marking->max_long_term_frame_idx_plus1);
960
961 if (marking->memory_mgmnt_control_operation > 6)
962 return kInvalidStream;
963 }
964
965 if (i == std::size(shdr->ref_pic_marking)) {
966 LOG_ERROR_ONCE("Ran out of dec ref pic marking fields");
967 return kUnsupportedStream;
968 }
969 }
970 }
971
972 return kOk;
973}
974
975H264Parser::Result H264Parser::ParseSliceHeader(const Nalu& nalu,
976 H264SliceHeader* shdr) {
977 // See 7.4.3.
978 const H264Sps* sps;
979 const H264Pps* pps;
980 Result res;
981 H26xBitReader reader;
982 reader.Initialize(nalu.data() + nalu.header_size(), nalu.payload_size());
983 H26xBitReader* br = &reader;
984
985 *shdr = {};
986
987 shdr->idr_pic_flag = (nalu.type() == 5);
988 shdr->nal_ref_idc = nalu.ref_idc();
989 shdr->nalu_data = nalu.data();
990 shdr->nalu_size = nalu.header_size() + nalu.payload_size();
991
992 READ_UE_OR_RETURN(&shdr->first_mb_in_slice);
993 READ_UE_OR_RETURN(&shdr->slice_type);
994 TRUE_OR_RETURN(shdr->slice_type < 10);
995
996 READ_UE_OR_RETURN(&shdr->pic_parameter_set_id);
997
998 pps = GetPps(shdr->pic_parameter_set_id);
999 TRUE_OR_RETURN(pps);
1000
1001 sps = GetSps(pps->seq_parameter_set_id);
1002 TRUE_OR_RETURN(sps);
1003
1004 if (sps->separate_colour_plane_flag) {
1005 LOG_ERROR_ONCE("Interlaced streams not supported");
1006 return kUnsupportedStream;
1007 }
1008
1009 READ_BITS_OR_RETURN(sps->log2_max_frame_num_minus4 + 4, &shdr->frame_num);
1010 if (!sps->frame_mbs_only_flag) {
1011 READ_BOOL_OR_RETURN(&shdr->field_pic_flag);
1012 if (shdr->field_pic_flag) {
1013 LOG_ERROR_ONCE("Interlaced streams not supported");
1014 return kUnsupportedStream;
1015 }
1016 }
1017
1018 if (shdr->idr_pic_flag)
1019 READ_UE_OR_RETURN(&shdr->idr_pic_id);
1020
1021 if (sps->pic_order_cnt_type == 0) {
1022 READ_BITS_OR_RETURN(sps->log2_max_pic_order_cnt_lsb_minus4 + 4,
1023 &shdr->pic_order_cnt_lsb);
1024 if (pps->bottom_field_pic_order_in_frame_present_flag &&
1025 !shdr->field_pic_flag)
1026 READ_SE_OR_RETURN(&shdr->delta_pic_order_cnt_bottom);
1027 }
1028
1029 if (sps->pic_order_cnt_type == 1 && !sps->delta_pic_order_always_zero_flag) {
1030 READ_SE_OR_RETURN(&shdr->delta_pic_order_cnt[0]);
1031 if (pps->bottom_field_pic_order_in_frame_present_flag &&
1032 !shdr->field_pic_flag)
1033 READ_SE_OR_RETURN(&shdr->delta_pic_order_cnt[1]);
1034 }
1035
1036 if (pps->redundant_pic_cnt_present_flag) {
1037 READ_UE_OR_RETURN(&shdr->redundant_pic_cnt);
1038 TRUE_OR_RETURN(shdr->redundant_pic_cnt < 128);
1039 }
1040
1041 if (shdr->IsBSlice())
1042 READ_BOOL_OR_RETURN(&shdr->direct_spatial_mv_pred_flag);
1043
1044 if (shdr->IsPSlice() || shdr->IsSPSlice() || shdr->IsBSlice()) {
1045 READ_BOOL_OR_RETURN(&shdr->num_ref_idx_active_override_flag);
1046 if (shdr->num_ref_idx_active_override_flag) {
1047 READ_UE_OR_RETURN(&shdr->num_ref_idx_l0_active_minus1);
1048 if (shdr->IsBSlice())
1049 READ_UE_OR_RETURN(&shdr->num_ref_idx_l1_active_minus1);
1050 } else {
1051 shdr->num_ref_idx_l0_active_minus1 =
1052 pps->num_ref_idx_l0_default_active_minus1;
1053 if (shdr->IsBSlice()) {
1054 shdr->num_ref_idx_l1_active_minus1 =
1055 pps->num_ref_idx_l1_default_active_minus1;
1056 }
1057 }
1058 }
1059 if (shdr->field_pic_flag) {
1060 TRUE_OR_RETURN(shdr->num_ref_idx_l0_active_minus1 < 32);
1061 TRUE_OR_RETURN(shdr->num_ref_idx_l1_active_minus1 < 32);
1062 } else {
1063 TRUE_OR_RETURN(shdr->num_ref_idx_l0_active_minus1 < 16);
1064 TRUE_OR_RETURN(shdr->num_ref_idx_l1_active_minus1 < 16);
1065 }
1066
1067 if (nalu.type() == Nalu::H264_CodedSliceExtension) {
1068 return kUnsupportedStream;
1069 } else {
1070 res = ParseRefPicListModifications(br, shdr);
1071 if (res != kOk)
1072 return res;
1073 }
1074
1075 if ((pps->weighted_pred_flag && (shdr->IsPSlice() || shdr->IsSPSlice())) ||
1076 (pps->weighted_bipred_idc == 1 && shdr->IsBSlice())) {
1077 res = ParsePredWeightTable(br, *sps, shdr);
1078 if (res != kOk)
1079 return res;
1080 }
1081
1082 if (nalu.ref_idc() != 0) {
1083 res = ParseDecRefPicMarking(br, shdr);
1084 if (res != kOk)
1085 return res;
1086 }
1087
1088 if (pps->entropy_coding_mode_flag && !shdr->IsISlice() &&
1089 !shdr->IsSISlice()) {
1090 READ_UE_OR_RETURN(&shdr->cabac_init_idc);
1091 TRUE_OR_RETURN(shdr->cabac_init_idc < 3);
1092 }
1093
1094 READ_SE_OR_RETURN(&shdr->slice_qp_delta);
1095
1096 if (shdr->IsSPSlice() || shdr->IsSISlice()) {
1097 if (shdr->IsSPSlice())
1098 READ_BOOL_OR_RETURN(&shdr->sp_for_switch_flag);
1099 READ_SE_OR_RETURN(&shdr->slice_qs_delta);
1100 }
1101
1102 if (pps->deblocking_filter_control_present_flag) {
1103 READ_UE_OR_RETURN(&shdr->disable_deblocking_filter_idc);
1104 TRUE_OR_RETURN(shdr->disable_deblocking_filter_idc < 3);
1105
1106 if (shdr->disable_deblocking_filter_idc != 1) {
1107 READ_SE_OR_RETURN(&shdr->slice_alpha_c0_offset_div2);
1108 IN_RANGE_OR_RETURN(shdr->slice_alpha_c0_offset_div2, -6, 6);
1109
1110 READ_SE_OR_RETURN(&shdr->slice_beta_offset_div2);
1111 IN_RANGE_OR_RETURN(shdr->slice_beta_offset_div2, -6, 6);
1112 }
1113 }
1114
1115 if (pps->num_slice_groups_minus1 > 0) {
1116 LOG_ERROR_ONCE("Slice groups not supported");
1117 return kUnsupportedStream;
1118 }
1119
1120 shdr->header_bit_size = nalu.payload_size() * 8 - br->NumBitsLeft();
1121 return kOk;
1122}
1123
1124H264Parser::Result H264Parser::ParseSEI(const Nalu& nalu,
1125 H264SEIMessage* sei_msg) {
1126 int byte;
1127 H26xBitReader reader;
1128 reader.Initialize(nalu.data() + nalu.header_size(), nalu.payload_size());
1129 H26xBitReader* br = &reader;
1130
1131 *sei_msg = {};
1132
1133 READ_BITS_OR_RETURN(8, &byte);
1134 while (byte == 0xff) {
1135 sei_msg->type += 255;
1136 READ_BITS_OR_RETURN(8, &byte);
1137 }
1138 sei_msg->type += byte;
1139
1140 READ_BITS_OR_RETURN(8, &byte);
1141 while (byte == 0xff) {
1142 sei_msg->payload_size += 255;
1143 READ_BITS_OR_RETURN(8, &byte);
1144 }
1145 sei_msg->payload_size += byte;
1146
1147 DVLOG(4) << "Found SEI message type: " << sei_msg->type
1148 << " payload size: " << sei_msg->payload_size;
1149
1150 switch (sei_msg->type) {
1151 case H264SEIMessage::kSEIRecoveryPoint:
1152 READ_UE_OR_RETURN(&sei_msg->recovery_point.recovery_frame_cnt);
1153 READ_BOOL_OR_RETURN(&sei_msg->recovery_point.exact_match_flag);
1154 READ_BOOL_OR_RETURN(&sei_msg->recovery_point.broken_link_flag);
1155 READ_BITS_OR_RETURN(2, &sei_msg->recovery_point.changing_slice_group_idc);
1156 break;
1157
1158 default:
1159 DVLOG(4) << "Unsupported SEI message";
1160 break;
1161 }
1162
1163 return kOk;
1164}
1165
1166} // namespace media
1167} // namespace shaka
All the methods that are virtual are virtual for mocking.