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