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