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 
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 
22 namespace shaka {
23 namespace media {
24 
25 // Implemented according to ISO/IEC 14496-10:2005 7.4.2.1 Sequence parameter set
26 // RBSP semantics.
27 bool 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 
90 bool H264SliceHeader::IsPSlice() const {
91  return (slice_type % 5 == kPSlice);
92 }
93 
94 bool H264SliceHeader::IsBSlice() const {
95  return (slice_type % 5 == kBSlice);
96 }
97 
98 bool H264SliceHeader::IsISlice() const {
99  return (slice_type % 5 == kISlice);
100 }
101 
102 bool H264SliceHeader::IsSPSlice() const {
103  return (slice_type % 5 == kSPSlice);
104 }
105 
106 bool 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 
175 enum AspectRatioIdc {
176  kExtendedSar = 255,
177 };
178 
179 // ISO 14496 part 10
180 // VUI parameters: Table E-1 "Meaning of sample aspect ratio indicator"
181 static const int kTableSarWidth[] = {
182  0, 1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160, 4, 3, 2
183 };
184 static const int kTableSarHeight[] = {
185  0, 1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1
186 };
187 static_assert(std::size(kTableSarWidth) == std::size(kTableSarHeight),
188  "sar_tables_must_have_same_size");
189 
190 H264Parser::H264Parser() {}
191 
192 H264Parser::~H264Parser() {}
193 
194 const H264Pps* H264Parser::GetPps(int pps_id) {
195  return active_PPSes_[pps_id].get();
196 }
197 
198 const H264Sps* H264Parser::GetSps(int sps_id) {
199  return active_SPSes_[sps_id].get();
200 }
201 
202 // Default scaling lists (per spec).
203 static const int kDefault4x4Intra[kH264ScalingList4x4Length] = {
204  6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, 32, 32, 37, 37, 42, };
205 
206 static const int kDefault4x4Inter[kH264ScalingList4x4Length] = {
207  10, 14, 14, 20, 20, 20, 24, 24, 24, 24, 27, 27, 27, 30, 30, 34, };
208 
209 static 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 
215 static 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 
221 static 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 
232 static 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 
243 static 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 
284 static 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 
325 H264Parser::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 
355 H264Parser::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 
403 H264Parser::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 
469 H264Parser::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 
492 H264Parser::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 
574 static 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 
584 H264Parser::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 
705 H264Parser::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 
778 H264Parser::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 
822 H264Parser::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 
849 H264Parser::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 
894 H264Parser::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 
927 H264Parser::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 
973 H264Parser::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 
1122 H264Parser::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.
Definition: crypto_flags.cc:66