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