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