cleanup: pass string as const reference from c/b/extension
[chromium-blink-merge.git] / media / filters / h264_parser.cc
blob4cdc695933fa49eb68285f7d0789dd5fbd8f4eb8
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.
5 #include "base/logging.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "base/stl_util.h"
9 #include "media/filters/h264_parser.h"
11 namespace media {
13 bool H264SliceHeader::IsPSlice() const {
14 return (slice_type % 5 == kPSlice);
17 bool H264SliceHeader::IsBSlice() const {
18 return (slice_type % 5 == kBSlice);
21 bool H264SliceHeader::IsISlice() const {
22 return (slice_type % 5 == kISlice);
25 bool H264SliceHeader::IsSPSlice() const {
26 return (slice_type % 5 == kSPSlice);
29 bool H264SliceHeader::IsSISlice() const {
30 return (slice_type % 5 == kSISlice);
33 H264NALU::H264NALU() {
34 memset(this, 0, sizeof(*this));
37 H264SPS::H264SPS() {
38 memset(this, 0, sizeof(*this));
41 H264PPS::H264PPS() {
42 memset(this, 0, sizeof(*this));
45 H264SliceHeader::H264SliceHeader() {
46 memset(this, 0, sizeof(*this));
49 H264SEIMessage::H264SEIMessage() {
50 memset(this, 0, sizeof(*this));
53 #define READ_BITS_OR_RETURN(num_bits, out) \
54 do { \
55 int _out; \
56 if (!br_.ReadBits(num_bits, &_out)) { \
57 DVLOG(1) \
58 << "Error in stream: unexpected EOS while trying to read " #out; \
59 return kInvalidStream; \
60 } \
61 *out = _out; \
62 } while (0)
64 #define READ_BOOL_OR_RETURN(out) \
65 do { \
66 int _out; \
67 if (!br_.ReadBits(1, &_out)) { \
68 DVLOG(1) \
69 << "Error in stream: unexpected EOS while trying to read " #out; \
70 return kInvalidStream; \
71 } \
72 *out = _out != 0; \
73 } while (0)
75 #define READ_UE_OR_RETURN(out) \
76 do { \
77 if (ReadUE(out) != kOk) { \
78 DVLOG(1) << "Error in stream: invalid value while trying to read " #out; \
79 return kInvalidStream; \
80 } \
81 } while (0)
83 #define READ_SE_OR_RETURN(out) \
84 do { \
85 if (ReadSE(out) != kOk) { \
86 DVLOG(1) << "Error in stream: invalid value while trying to read " #out; \
87 return kInvalidStream; \
88 } \
89 } while (0)
91 #define IN_RANGE_OR_RETURN(val, min, max) \
92 do { \
93 if ((val) < (min) || (val) > (max)) { \
94 DVLOG(1) << "Error in stream: invalid value, expected " #val " to be" \
95 << " in range [" << (min) << ":" << (max) << "]" \
96 << " found " << (val) << " instead"; \
97 return kInvalidStream; \
98 } \
99 } while (0)
101 #define TRUE_OR_RETURN(a) \
102 do { \
103 if (!(a)) { \
104 DVLOG(1) << "Error in stream: invalid value, expected " << #a; \
105 return kInvalidStream; \
107 } while (0)
109 enum AspectRatioIdc {
110 kExtendedSar = 255,
113 // ISO 14496 part 10
114 // VUI parameters: Table E-1 "Meaning of sample aspect ratio indicator"
115 static const int kTableSarWidth[] = {
116 0, 1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160, 4, 3, 2
118 static const int kTableSarHeight[] = {
119 0, 1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1
121 COMPILE_ASSERT(arraysize(kTableSarWidth) == arraysize(kTableSarHeight),
122 sar_tables_must_have_same_size);
124 H264Parser::H264Parser() {
125 Reset();
128 H264Parser::~H264Parser() {
129 STLDeleteValues(&active_SPSes_);
130 STLDeleteValues(&active_PPSes_);
133 void H264Parser::Reset() {
134 stream_ = NULL;
135 bytes_left_ = 0;
138 void H264Parser::SetStream(const uint8* stream, off_t stream_size) {
139 DCHECK(stream);
140 DCHECK_GT(stream_size, 0);
142 stream_ = stream;
143 bytes_left_ = stream_size;
146 const H264PPS* H264Parser::GetPPS(int pps_id) {
147 return active_PPSes_[pps_id];
150 const H264SPS* H264Parser::GetSPS(int sps_id) {
151 return active_SPSes_[sps_id];
154 static inline bool IsStartCode(const uint8* data) {
155 return data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x01;
158 // static
159 bool H264Parser::FindStartCode(const uint8* data, off_t data_size,
160 off_t* offset, off_t* start_code_size) {
161 DCHECK_GE(data_size, 0);
162 off_t bytes_left = data_size;
164 while (bytes_left >= 3) {
165 if (IsStartCode(data)) {
166 // Found three-byte start code, set pointer at its beginning.
167 *offset = data_size - bytes_left;
168 *start_code_size = 3;
170 // If there is a zero byte before this start code,
171 // then it's actually a four-byte start code, so backtrack one byte.
172 if (*offset > 0 && *(data - 1) == 0x00) {
173 --(*offset);
174 ++(*start_code_size);
177 return true;
180 ++data;
181 --bytes_left;
184 // End of data: offset is pointing to the first byte that was not considered
185 // as a possible start of a start code.
186 // Note: there is no security issue when receiving a negative |data_size|
187 // since in this case, |bytes_left| is equal to |data_size| and thus
188 // |*offset| is equal to 0 (valid offset).
189 *offset = data_size - bytes_left;
190 *start_code_size = 0;
191 return false;
194 bool H264Parser::LocateNALU(off_t* nalu_size, off_t* start_code_size) {
195 // Find the start code of next NALU.
196 off_t nalu_start_off = 0;
197 off_t annexb_start_code_size = 0;
198 if (!FindStartCode(stream_, bytes_left_,
199 &nalu_start_off, &annexb_start_code_size)) {
200 DVLOG(4) << "Could not find start code, end of stream?";
201 return false;
204 // Move the stream to the beginning of the NALU (pointing at the start code).
205 stream_ += nalu_start_off;
206 bytes_left_ -= nalu_start_off;
208 const uint8* nalu_data = stream_ + annexb_start_code_size;
209 off_t max_nalu_data_size = bytes_left_ - annexb_start_code_size;
210 if (max_nalu_data_size <= 0) {
211 DVLOG(3) << "End of stream";
212 return false;
215 // Find the start code of next NALU;
216 // if successful, |nalu_size_without_start_code| is the number of bytes from
217 // after previous start code to before this one;
218 // if next start code is not found, it is still a valid NALU since there
219 // are some bytes left after the first start code: all the remaining bytes
220 // belong to the current NALU.
221 off_t next_start_code_size = 0;
222 off_t nalu_size_without_start_code = 0;
223 if (!FindStartCode(nalu_data, max_nalu_data_size,
224 &nalu_size_without_start_code, &next_start_code_size)) {
225 nalu_size_without_start_code = max_nalu_data_size;
227 *nalu_size = nalu_size_without_start_code + annexb_start_code_size;
228 *start_code_size = annexb_start_code_size;
229 return true;
232 H264Parser::Result H264Parser::ReadUE(int* val) {
233 int num_bits = -1;
234 int bit;
235 int rest;
237 // Count the number of contiguous zero bits.
238 do {
239 READ_BITS_OR_RETURN(1, &bit);
240 num_bits++;
241 } while (bit == 0);
243 if (num_bits > 31)
244 return kInvalidStream;
246 // Calculate exp-Golomb code value of size num_bits.
247 *val = (1 << num_bits) - 1;
249 if (num_bits > 0) {
250 READ_BITS_OR_RETURN(num_bits, &rest);
251 *val += rest;
254 return kOk;
257 H264Parser::Result H264Parser::ReadSE(int* val) {
258 int ue;
259 Result res;
261 // See Chapter 9 in the spec.
262 res = ReadUE(&ue);
263 if (res != kOk)
264 return res;
266 if (ue % 2 == 0)
267 *val = -(ue / 2);
268 else
269 *val = ue / 2 + 1;
271 return kOk;
274 H264Parser::Result H264Parser::AdvanceToNextNALU(H264NALU* nalu) {
275 off_t start_code_size;
276 off_t nalu_size_with_start_code;
277 if (!LocateNALU(&nalu_size_with_start_code, &start_code_size)) {
278 DVLOG(4) << "Could not find next NALU, bytes left in stream: "
279 << bytes_left_;
280 return kEOStream;
283 nalu->data = stream_ + start_code_size;
284 nalu->size = nalu_size_with_start_code - start_code_size;
285 DVLOG(4) << "NALU found: size=" << nalu_size_with_start_code;
287 // Initialize bit reader at the start of found NALU.
288 if (!br_.Initialize(nalu->data, nalu->size))
289 return kEOStream;
291 // Move parser state to after this NALU, so next time AdvanceToNextNALU
292 // is called, we will effectively be skipping it;
293 // other parsing functions will use the position saved
294 // in bit reader for parsing, so we don't have to remember it here.
295 stream_ += nalu_size_with_start_code;
296 bytes_left_ -= nalu_size_with_start_code;
298 // Read NALU header, skip the forbidden_zero_bit, but check for it.
299 int data;
300 READ_BITS_OR_RETURN(1, &data);
301 TRUE_OR_RETURN(data == 0);
303 READ_BITS_OR_RETURN(2, &nalu->nal_ref_idc);
304 READ_BITS_OR_RETURN(5, &nalu->nal_unit_type);
306 DVLOG(4) << "NALU type: " << static_cast<int>(nalu->nal_unit_type)
307 << " at: " << reinterpret_cast<const void*>(nalu->data)
308 << " size: " << nalu->size
309 << " ref: " << static_cast<int>(nalu->nal_ref_idc);
311 return kOk;
314 // Default scaling lists (per spec).
315 static const int kDefault4x4Intra[kH264ScalingList4x4Length] = {
316 6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, 32, 32, 37, 37, 42, };
318 static const int kDefault4x4Inter[kH264ScalingList4x4Length] = {
319 10, 14, 14, 20, 20, 20, 24, 24, 24, 24, 27, 27, 27, 30, 30, 34, };
321 static const int kDefault8x8Intra[kH264ScalingList8x8Length] = {
322 6, 10, 10, 13, 11, 13, 16, 16, 16, 16, 18, 18, 18, 18, 18, 23,
323 23, 23, 23, 23, 23, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27,
324 27, 27, 27, 27, 29, 29, 29, 29, 29, 29, 29, 31, 31, 31, 31, 31,
325 31, 33, 33, 33, 33, 33, 36, 36, 36, 36, 38, 38, 38, 40, 40, 42, };
327 static const int kDefault8x8Inter[kH264ScalingList8x8Length] = {
328 9, 13, 13, 15, 13, 15, 17, 17, 17, 17, 19, 19, 19, 19, 19, 21,
329 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24, 24,
330 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27,
331 27, 28, 28, 28, 28, 28, 30, 30, 30, 30, 32, 32, 32, 33, 33, 35, };
333 static inline void DefaultScalingList4x4(
334 int i,
335 int scaling_list4x4[][kH264ScalingList4x4Length]) {
336 DCHECK_LT(i, 6);
338 if (i < 3)
339 memcpy(scaling_list4x4[i], kDefault4x4Intra, sizeof(kDefault4x4Intra));
340 else if (i < 6)
341 memcpy(scaling_list4x4[i], kDefault4x4Inter, sizeof(kDefault4x4Inter));
344 static inline void DefaultScalingList8x8(
345 int i,
346 int scaling_list8x8[][kH264ScalingList8x8Length]) {
347 DCHECK_LT(i, 6);
349 if (i % 2 == 0)
350 memcpy(scaling_list8x8[i], kDefault8x8Intra, sizeof(kDefault8x8Intra));
351 else
352 memcpy(scaling_list8x8[i], kDefault8x8Inter, sizeof(kDefault8x8Inter));
355 static void FallbackScalingList4x4(
356 int i,
357 const int default_scaling_list_intra[],
358 const int default_scaling_list_inter[],
359 int scaling_list4x4[][kH264ScalingList4x4Length]) {
360 static const int kScalingList4x4ByteSize =
361 sizeof(scaling_list4x4[0][0]) * kH264ScalingList4x4Length;
363 switch (i) {
364 case 0:
365 memcpy(scaling_list4x4[i], default_scaling_list_intra,
366 kScalingList4x4ByteSize);
367 break;
369 case 1:
370 memcpy(scaling_list4x4[i], scaling_list4x4[0], kScalingList4x4ByteSize);
371 break;
373 case 2:
374 memcpy(scaling_list4x4[i], scaling_list4x4[1], kScalingList4x4ByteSize);
375 break;
377 case 3:
378 memcpy(scaling_list4x4[i], default_scaling_list_inter,
379 kScalingList4x4ByteSize);
380 break;
382 case 4:
383 memcpy(scaling_list4x4[i], scaling_list4x4[3], kScalingList4x4ByteSize);
384 break;
386 case 5:
387 memcpy(scaling_list4x4[i], scaling_list4x4[4], kScalingList4x4ByteSize);
388 break;
390 default:
391 NOTREACHED();
392 break;
396 static void FallbackScalingList8x8(
397 int i,
398 const int default_scaling_list_intra[],
399 const int default_scaling_list_inter[],
400 int scaling_list8x8[][kH264ScalingList8x8Length]) {
401 static const int kScalingList8x8ByteSize =
402 sizeof(scaling_list8x8[0][0]) * kH264ScalingList8x8Length;
404 switch (i) {
405 case 0:
406 memcpy(scaling_list8x8[i], default_scaling_list_intra,
407 kScalingList8x8ByteSize);
408 break;
410 case 1:
411 memcpy(scaling_list8x8[i], default_scaling_list_inter,
412 kScalingList8x8ByteSize);
413 break;
415 case 2:
416 memcpy(scaling_list8x8[i], scaling_list8x8[0], kScalingList8x8ByteSize);
417 break;
419 case 3:
420 memcpy(scaling_list8x8[i], scaling_list8x8[1], kScalingList8x8ByteSize);
421 break;
423 case 4:
424 memcpy(scaling_list8x8[i], scaling_list8x8[2], kScalingList8x8ByteSize);
425 break;
427 case 5:
428 memcpy(scaling_list8x8[i], scaling_list8x8[3], kScalingList8x8ByteSize);
429 break;
431 default:
432 NOTREACHED();
433 break;
437 H264Parser::Result H264Parser::ParseScalingList(int size,
438 int* scaling_list,
439 bool* use_default) {
440 // See chapter 7.3.2.1.1.1.
441 int last_scale = 8;
442 int next_scale = 8;
443 int delta_scale;
445 *use_default = false;
447 for (int j = 0; j < size; ++j) {
448 if (next_scale != 0) {
449 READ_SE_OR_RETURN(&delta_scale);
450 IN_RANGE_OR_RETURN(delta_scale, -128, 127);
451 next_scale = (last_scale + delta_scale + 256) & 0xff;
453 if (j == 0 && next_scale == 0) {
454 *use_default = true;
455 return kOk;
459 scaling_list[j] = (next_scale == 0) ? last_scale : next_scale;
460 last_scale = scaling_list[j];
463 return kOk;
466 H264Parser::Result H264Parser::ParseSPSScalingLists(H264SPS* sps) {
467 // See 7.4.2.1.1.
468 bool seq_scaling_list_present_flag;
469 bool use_default;
470 Result res;
472 // Parse scaling_list4x4.
473 for (int i = 0; i < 6; ++i) {
474 READ_BOOL_OR_RETURN(&seq_scaling_list_present_flag);
476 if (seq_scaling_list_present_flag) {
477 res = ParseScalingList(arraysize(sps->scaling_list4x4[i]),
478 sps->scaling_list4x4[i],
479 &use_default);
480 if (res != kOk)
481 return res;
483 if (use_default)
484 DefaultScalingList4x4(i, sps->scaling_list4x4);
486 } else {
487 FallbackScalingList4x4(
488 i, kDefault4x4Intra, kDefault4x4Inter, sps->scaling_list4x4);
492 // Parse scaling_list8x8.
493 for (int i = 0; i < ((sps->chroma_format_idc != 3) ? 2 : 6); ++i) {
494 READ_BOOL_OR_RETURN(&seq_scaling_list_present_flag);
496 if (seq_scaling_list_present_flag) {
497 res = ParseScalingList(arraysize(sps->scaling_list8x8[i]),
498 sps->scaling_list8x8[i],
499 &use_default);
500 if (res != kOk)
501 return res;
503 if (use_default)
504 DefaultScalingList8x8(i, sps->scaling_list8x8);
506 } else {
507 FallbackScalingList8x8(
508 i, kDefault8x8Intra, kDefault8x8Inter, sps->scaling_list8x8);
512 return kOk;
515 H264Parser::Result H264Parser::ParsePPSScalingLists(const H264SPS& sps,
516 H264PPS* pps) {
517 // See 7.4.2.2.
518 bool pic_scaling_list_present_flag;
519 bool use_default;
520 Result res;
522 for (int i = 0; i < 6; ++i) {
523 READ_BOOL_OR_RETURN(&pic_scaling_list_present_flag);
525 if (pic_scaling_list_present_flag) {
526 res = ParseScalingList(arraysize(pps->scaling_list4x4[i]),
527 pps->scaling_list4x4[i],
528 &use_default);
529 if (res != kOk)
530 return res;
532 if (use_default)
533 DefaultScalingList4x4(i, pps->scaling_list4x4);
535 } else {
536 if (sps.seq_scaling_matrix_present_flag) {
537 // Table 7-2 fallback rule A in spec.
538 FallbackScalingList4x4(
539 i, kDefault4x4Intra, kDefault4x4Inter, pps->scaling_list4x4);
540 } else {
541 // Table 7-2 fallback rule B in spec.
542 FallbackScalingList4x4(i,
543 sps.scaling_list4x4[0],
544 sps.scaling_list4x4[3],
545 pps->scaling_list4x4);
550 if (pps->transform_8x8_mode_flag) {
551 for (int i = 0; i < ((sps.chroma_format_idc != 3) ? 2 : 6); ++i) {
552 READ_BOOL_OR_RETURN(&pic_scaling_list_present_flag);
554 if (pic_scaling_list_present_flag) {
555 res = ParseScalingList(arraysize(pps->scaling_list8x8[i]),
556 pps->scaling_list8x8[i],
557 &use_default);
558 if (res != kOk)
559 return res;
561 if (use_default)
562 DefaultScalingList8x8(i, pps->scaling_list8x8);
564 } else {
565 if (sps.seq_scaling_matrix_present_flag) {
566 // Table 7-2 fallback rule A in spec.
567 FallbackScalingList8x8(
568 i, kDefault8x8Intra, kDefault8x8Inter, pps->scaling_list8x8);
569 } else {
570 // Table 7-2 fallback rule B in spec.
571 FallbackScalingList8x8(i,
572 sps.scaling_list8x8[0],
573 sps.scaling_list8x8[1],
574 pps->scaling_list8x8);
579 return kOk;
582 H264Parser::Result H264Parser::ParseAndIgnoreHRDParameters(
583 bool* hrd_parameters_present) {
584 int data;
585 READ_BOOL_OR_RETURN(&data); // {nal,vcl}_hrd_parameters_present_flag
586 if (!data)
587 return kOk;
589 *hrd_parameters_present = true;
591 int cpb_cnt_minus1;
592 READ_UE_OR_RETURN(&cpb_cnt_minus1);
593 IN_RANGE_OR_RETURN(cpb_cnt_minus1, 0, 31);
594 READ_BITS_OR_RETURN(8, &data); // bit_rate_scale, cpb_size_scale
595 for (int i = 0; i <= cpb_cnt_minus1; ++i) {
596 READ_UE_OR_RETURN(&data); // bit_rate_value_minus1[i]
597 READ_UE_OR_RETURN(&data); // cpb_size_value_minus1[i]
598 READ_BOOL_OR_RETURN(&data); // cbr_flag
600 READ_BITS_OR_RETURN(20, &data); // cpb/dpb delays, etc.
602 return kOk;
605 H264Parser::Result H264Parser::ParseVUIParameters(H264SPS* sps) {
606 bool aspect_ratio_info_present_flag;
607 READ_BOOL_OR_RETURN(&aspect_ratio_info_present_flag);
608 if (aspect_ratio_info_present_flag) {
609 int aspect_ratio_idc;
610 READ_BITS_OR_RETURN(8, &aspect_ratio_idc);
611 if (aspect_ratio_idc == kExtendedSar) {
612 READ_BITS_OR_RETURN(16, &sps->sar_width);
613 READ_BITS_OR_RETURN(16, &sps->sar_height);
614 } else {
615 const int max_aspect_ratio_idc = arraysize(kTableSarWidth) - 1;
616 IN_RANGE_OR_RETURN(aspect_ratio_idc, 0, max_aspect_ratio_idc);
617 sps->sar_width = kTableSarWidth[aspect_ratio_idc];
618 sps->sar_height = kTableSarHeight[aspect_ratio_idc];
622 int data;
623 // Read and ignore overscan and video signal type info.
624 READ_BOOL_OR_RETURN(&data); // overscan_info_present_flag
625 if (data)
626 READ_BOOL_OR_RETURN(&data); // overscan_appropriate_flag
628 READ_BOOL_OR_RETURN(&data); // video_signal_type_present_flag
629 if (data) {
630 READ_BITS_OR_RETURN(3, &data); // video_format
631 READ_BOOL_OR_RETURN(&data); // video_full_range_flag
632 READ_BOOL_OR_RETURN(&data); // colour_description_present_flag
633 if (data)
634 READ_BITS_OR_RETURN(24, &data); // color description syntax elements
637 READ_BOOL_OR_RETURN(&data); // chroma_loc_info_present_flag
638 if (data) {
639 READ_UE_OR_RETURN(&data); // chroma_sample_loc_type_top_field
640 READ_UE_OR_RETURN(&data); // chroma_sample_loc_type_bottom_field
643 // Read and ignore timing info.
644 READ_BOOL_OR_RETURN(&data); // timing_info_present_flag
645 if (data) {
646 READ_BITS_OR_RETURN(16, &data); // num_units_in_tick
647 READ_BITS_OR_RETURN(16, &data); // num_units_in_tick
648 READ_BITS_OR_RETURN(16, &data); // time_scale
649 READ_BITS_OR_RETURN(16, &data); // time_scale
650 READ_BOOL_OR_RETURN(&data); // fixed_frame_rate_flag
653 // Read and ignore NAL HRD parameters, if present.
654 bool hrd_parameters_present = false;
655 Result res = ParseAndIgnoreHRDParameters(&hrd_parameters_present);
656 if (res != kOk)
657 return res;
659 // Read and ignore VCL HRD parameters, if present.
660 res = ParseAndIgnoreHRDParameters(&hrd_parameters_present);
661 if (res != kOk)
662 return res;
664 if (hrd_parameters_present) // One of NAL or VCL params present is enough.
665 READ_BOOL_OR_RETURN(&data); // low_delay_hrd_flag
667 READ_BOOL_OR_RETURN(&data); // pic_struct_present_flag
668 READ_BOOL_OR_RETURN(&sps->bitstream_restriction_flag);
669 if (sps->bitstream_restriction_flag) {
670 READ_BOOL_OR_RETURN(&data); // motion_vectors_over_pic_boundaries_flag
671 READ_UE_OR_RETURN(&data); // max_bytes_per_pic_denom
672 READ_UE_OR_RETURN(&data); // max_bits_per_mb_denom
673 READ_UE_OR_RETURN(&data); // log2_max_mv_length_horizontal
674 READ_UE_OR_RETURN(&data); // log2_max_mv_length_vertical
675 READ_UE_OR_RETURN(&sps->max_num_reorder_frames);
676 READ_UE_OR_RETURN(&sps->max_dec_frame_buffering);
677 TRUE_OR_RETURN(sps->max_dec_frame_buffering >= sps->max_num_ref_frames);
678 IN_RANGE_OR_RETURN(
679 sps->max_num_reorder_frames, 0, sps->max_dec_frame_buffering);
682 return kOk;
685 static void FillDefaultSeqScalingLists(H264SPS* sps) {
686 for (int i = 0; i < 6; ++i)
687 for (int j = 0; j < kH264ScalingList4x4Length; ++j)
688 sps->scaling_list4x4[i][j] = 16;
690 for (int i = 0; i < 6; ++i)
691 for (int j = 0; j < kH264ScalingList8x8Length; ++j)
692 sps->scaling_list8x8[i][j] = 16;
695 H264Parser::Result H264Parser::ParseSPS(int* sps_id) {
696 // See 7.4.2.1.
697 int data;
698 Result res;
700 *sps_id = -1;
702 scoped_ptr<H264SPS> sps(new H264SPS());
704 READ_BITS_OR_RETURN(8, &sps->profile_idc);
705 READ_BOOL_OR_RETURN(&sps->constraint_set0_flag);
706 READ_BOOL_OR_RETURN(&sps->constraint_set1_flag);
707 READ_BOOL_OR_RETURN(&sps->constraint_set2_flag);
708 READ_BOOL_OR_RETURN(&sps->constraint_set3_flag);
709 READ_BOOL_OR_RETURN(&sps->constraint_set4_flag);
710 READ_BOOL_OR_RETURN(&sps->constraint_set5_flag);
711 READ_BITS_OR_RETURN(2, &data); // reserved_zero_2bits
712 READ_BITS_OR_RETURN(8, &sps->level_idc);
713 READ_UE_OR_RETURN(&sps->seq_parameter_set_id);
714 TRUE_OR_RETURN(sps->seq_parameter_set_id < 32);
716 if (sps->profile_idc == 100 || sps->profile_idc == 110 ||
717 sps->profile_idc == 122 || sps->profile_idc == 244 ||
718 sps->profile_idc == 44 || sps->profile_idc == 83 ||
719 sps->profile_idc == 86 || sps->profile_idc == 118 ||
720 sps->profile_idc == 128) {
721 READ_UE_OR_RETURN(&sps->chroma_format_idc);
722 TRUE_OR_RETURN(sps->chroma_format_idc < 4);
724 if (sps->chroma_format_idc == 3)
725 READ_BOOL_OR_RETURN(&sps->separate_colour_plane_flag);
727 READ_UE_OR_RETURN(&sps->bit_depth_luma_minus8);
728 TRUE_OR_RETURN(sps->bit_depth_luma_minus8 < 7);
730 READ_UE_OR_RETURN(&sps->bit_depth_chroma_minus8);
731 TRUE_OR_RETURN(sps->bit_depth_chroma_minus8 < 7);
733 READ_BOOL_OR_RETURN(&sps->qpprime_y_zero_transform_bypass_flag);
734 READ_BOOL_OR_RETURN(&sps->seq_scaling_matrix_present_flag);
736 if (sps->seq_scaling_matrix_present_flag) {
737 DVLOG(4) << "Scaling matrix present";
738 res = ParseSPSScalingLists(sps.get());
739 if (res != kOk)
740 return res;
741 } else {
742 FillDefaultSeqScalingLists(sps.get());
744 } else {
745 sps->chroma_format_idc = 1;
746 FillDefaultSeqScalingLists(sps.get());
749 if (sps->separate_colour_plane_flag)
750 sps->chroma_array_type = 0;
751 else
752 sps->chroma_array_type = sps->chroma_format_idc;
754 READ_UE_OR_RETURN(&sps->log2_max_frame_num_minus4);
755 TRUE_OR_RETURN(sps->log2_max_frame_num_minus4 < 13);
757 READ_UE_OR_RETURN(&sps->pic_order_cnt_type);
758 TRUE_OR_RETURN(sps->pic_order_cnt_type < 3);
760 sps->expected_delta_per_pic_order_cnt_cycle = 0;
761 if (sps->pic_order_cnt_type == 0) {
762 READ_UE_OR_RETURN(&sps->log2_max_pic_order_cnt_lsb_minus4);
763 TRUE_OR_RETURN(sps->log2_max_pic_order_cnt_lsb_minus4 < 13);
764 } else if (sps->pic_order_cnt_type == 1) {
765 READ_BOOL_OR_RETURN(&sps->delta_pic_order_always_zero_flag);
766 READ_SE_OR_RETURN(&sps->offset_for_non_ref_pic);
767 READ_SE_OR_RETURN(&sps->offset_for_top_to_bottom_field);
768 READ_UE_OR_RETURN(&sps->num_ref_frames_in_pic_order_cnt_cycle);
769 TRUE_OR_RETURN(sps->num_ref_frames_in_pic_order_cnt_cycle < 255);
771 for (int i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; ++i) {
772 READ_SE_OR_RETURN(&sps->offset_for_ref_frame[i]);
773 sps->expected_delta_per_pic_order_cnt_cycle +=
774 sps->offset_for_ref_frame[i];
778 READ_UE_OR_RETURN(&sps->max_num_ref_frames);
779 READ_BOOL_OR_RETURN(&sps->gaps_in_frame_num_value_allowed_flag);
781 if (sps->gaps_in_frame_num_value_allowed_flag)
782 return kUnsupportedStream;
784 READ_UE_OR_RETURN(&sps->pic_width_in_mbs_minus1);
785 READ_UE_OR_RETURN(&sps->pic_height_in_map_units_minus1);
787 READ_BOOL_OR_RETURN(&sps->frame_mbs_only_flag);
788 if (!sps->frame_mbs_only_flag)
789 READ_BOOL_OR_RETURN(&sps->mb_adaptive_frame_field_flag);
791 READ_BOOL_OR_RETURN(&sps->direct_8x8_inference_flag);
793 READ_BOOL_OR_RETURN(&sps->frame_cropping_flag);
794 if (sps->frame_cropping_flag) {
795 READ_UE_OR_RETURN(&sps->frame_crop_left_offset);
796 READ_UE_OR_RETURN(&sps->frame_crop_right_offset);
797 READ_UE_OR_RETURN(&sps->frame_crop_top_offset);
798 READ_UE_OR_RETURN(&sps->frame_crop_bottom_offset);
801 READ_BOOL_OR_RETURN(&sps->vui_parameters_present_flag);
802 if (sps->vui_parameters_present_flag) {
803 DVLOG(4) << "VUI parameters present";
804 res = ParseVUIParameters(sps.get());
805 if (res != kOk)
806 return res;
809 // If an SPS with the same id already exists, replace it.
810 *sps_id = sps->seq_parameter_set_id;
811 delete active_SPSes_[*sps_id];
812 active_SPSes_[*sps_id] = sps.release();
814 return kOk;
817 H264Parser::Result H264Parser::ParsePPS(int* pps_id) {
818 // See 7.4.2.2.
819 const H264SPS* sps;
820 Result res;
822 *pps_id = -1;
824 scoped_ptr<H264PPS> pps(new H264PPS());
826 READ_UE_OR_RETURN(&pps->pic_parameter_set_id);
827 READ_UE_OR_RETURN(&pps->seq_parameter_set_id);
828 TRUE_OR_RETURN(pps->seq_parameter_set_id < 32);
830 sps = GetSPS(pps->seq_parameter_set_id);
831 TRUE_OR_RETURN(sps);
833 READ_BOOL_OR_RETURN(&pps->entropy_coding_mode_flag);
834 READ_BOOL_OR_RETURN(&pps->bottom_field_pic_order_in_frame_present_flag);
836 READ_UE_OR_RETURN(&pps->num_slice_groups_minus1);
837 if (pps->num_slice_groups_minus1 > 1) {
838 DVLOG(1) << "Slice groups not supported";
839 return kUnsupportedStream;
842 READ_UE_OR_RETURN(&pps->num_ref_idx_l0_default_active_minus1);
843 TRUE_OR_RETURN(pps->num_ref_idx_l0_default_active_minus1 < 32);
845 READ_UE_OR_RETURN(&pps->num_ref_idx_l1_default_active_minus1);
846 TRUE_OR_RETURN(pps->num_ref_idx_l1_default_active_minus1 < 32);
848 READ_BOOL_OR_RETURN(&pps->weighted_pred_flag);
849 READ_BITS_OR_RETURN(2, &pps->weighted_bipred_idc);
850 TRUE_OR_RETURN(pps->weighted_bipred_idc < 3);
852 READ_SE_OR_RETURN(&pps->pic_init_qp_minus26);
853 IN_RANGE_OR_RETURN(pps->pic_init_qp_minus26, -26, 25);
855 READ_SE_OR_RETURN(&pps->pic_init_qs_minus26);
856 IN_RANGE_OR_RETURN(pps->pic_init_qs_minus26, -26, 25);
858 READ_SE_OR_RETURN(&pps->chroma_qp_index_offset);
859 IN_RANGE_OR_RETURN(pps->chroma_qp_index_offset, -12, 12);
860 pps->second_chroma_qp_index_offset = pps->chroma_qp_index_offset;
862 READ_BOOL_OR_RETURN(&pps->deblocking_filter_control_present_flag);
863 READ_BOOL_OR_RETURN(&pps->constrained_intra_pred_flag);
864 READ_BOOL_OR_RETURN(&pps->redundant_pic_cnt_present_flag);
866 if (br_.HasMoreRBSPData()) {
867 READ_BOOL_OR_RETURN(&pps->transform_8x8_mode_flag);
868 READ_BOOL_OR_RETURN(&pps->pic_scaling_matrix_present_flag);
870 if (pps->pic_scaling_matrix_present_flag) {
871 DVLOG(4) << "Picture scaling matrix present";
872 res = ParsePPSScalingLists(*sps, pps.get());
873 if (res != kOk)
874 return res;
877 READ_SE_OR_RETURN(&pps->second_chroma_qp_index_offset);
880 // If a PPS with the same id already exists, replace it.
881 *pps_id = pps->pic_parameter_set_id;
882 delete active_PPSes_[*pps_id];
883 active_PPSes_[*pps_id] = pps.release();
885 return kOk;
888 H264Parser::Result H264Parser::ParseRefPicListModification(
889 int num_ref_idx_active_minus1,
890 H264ModificationOfPicNum* ref_list_mods) {
891 H264ModificationOfPicNum* pic_num_mod;
893 if (num_ref_idx_active_minus1 >= 32)
894 return kInvalidStream;
896 for (int i = 0; i < 32; ++i) {
897 pic_num_mod = &ref_list_mods[i];
898 READ_UE_OR_RETURN(&pic_num_mod->modification_of_pic_nums_idc);
899 TRUE_OR_RETURN(pic_num_mod->modification_of_pic_nums_idc < 4);
901 switch (pic_num_mod->modification_of_pic_nums_idc) {
902 case 0:
903 case 1:
904 READ_UE_OR_RETURN(&pic_num_mod->abs_diff_pic_num_minus1);
905 break;
907 case 2:
908 READ_UE_OR_RETURN(&pic_num_mod->long_term_pic_num);
909 break;
911 case 3:
912 // Per spec, list cannot be empty.
913 if (i == 0)
914 return kInvalidStream;
915 return kOk;
917 default:
918 return kInvalidStream;
922 // If we got here, we didn't get loop end marker prematurely,
923 // so make sure it is there for our client.
924 int modification_of_pic_nums_idc;
925 READ_UE_OR_RETURN(&modification_of_pic_nums_idc);
926 TRUE_OR_RETURN(modification_of_pic_nums_idc == 3);
928 return kOk;
931 H264Parser::Result H264Parser::ParseRefPicListModifications(
932 H264SliceHeader* shdr) {
933 Result res;
935 if (!shdr->IsISlice() && !shdr->IsSISlice()) {
936 READ_BOOL_OR_RETURN(&shdr->ref_pic_list_modification_flag_l0);
937 if (shdr->ref_pic_list_modification_flag_l0) {
938 res = ParseRefPicListModification(shdr->num_ref_idx_l0_active_minus1,
939 shdr->ref_list_l0_modifications);
940 if (res != kOk)
941 return res;
945 if (shdr->IsBSlice()) {
946 READ_BOOL_OR_RETURN(&shdr->ref_pic_list_modification_flag_l1);
947 if (shdr->ref_pic_list_modification_flag_l1) {
948 res = ParseRefPicListModification(shdr->num_ref_idx_l1_active_minus1,
949 shdr->ref_list_l1_modifications);
950 if (res != kOk)
951 return res;
955 return kOk;
958 H264Parser::Result H264Parser::ParseWeightingFactors(
959 int num_ref_idx_active_minus1,
960 int chroma_array_type,
961 int luma_log2_weight_denom,
962 int chroma_log2_weight_denom,
963 H264WeightingFactors* w_facts) {
965 int def_luma_weight = 1 << luma_log2_weight_denom;
966 int def_chroma_weight = 1 << chroma_log2_weight_denom;
968 for (int i = 0; i < num_ref_idx_active_minus1 + 1; ++i) {
969 READ_BOOL_OR_RETURN(&w_facts->luma_weight_flag);
970 if (w_facts->luma_weight_flag) {
971 READ_SE_OR_RETURN(&w_facts->luma_weight[i]);
972 IN_RANGE_OR_RETURN(w_facts->luma_weight[i], -128, 127);
974 READ_SE_OR_RETURN(&w_facts->luma_offset[i]);
975 IN_RANGE_OR_RETURN(w_facts->luma_offset[i], -128, 127);
976 } else {
977 w_facts->luma_weight[i] = def_luma_weight;
978 w_facts->luma_offset[i] = 0;
981 if (chroma_array_type != 0) {
982 READ_BOOL_OR_RETURN(&w_facts->chroma_weight_flag);
983 if (w_facts->chroma_weight_flag) {
984 for (int j = 0; j < 2; ++j) {
985 READ_SE_OR_RETURN(&w_facts->chroma_weight[i][j]);
986 IN_RANGE_OR_RETURN(w_facts->chroma_weight[i][j], -128, 127);
988 READ_SE_OR_RETURN(&w_facts->chroma_offset[i][j]);
989 IN_RANGE_OR_RETURN(w_facts->chroma_offset[i][j], -128, 127);
991 } else {
992 for (int j = 0; j < 2; ++j) {
993 w_facts->chroma_weight[i][j] = def_chroma_weight;
994 w_facts->chroma_offset[i][j] = 0;
1000 return kOk;
1003 H264Parser::Result H264Parser::ParsePredWeightTable(const H264SPS& sps,
1004 H264SliceHeader* shdr) {
1005 READ_UE_OR_RETURN(&shdr->luma_log2_weight_denom);
1006 TRUE_OR_RETURN(shdr->luma_log2_weight_denom < 8);
1008 if (sps.chroma_array_type != 0)
1009 READ_UE_OR_RETURN(&shdr->chroma_log2_weight_denom);
1010 TRUE_OR_RETURN(shdr->chroma_log2_weight_denom < 8);
1012 Result res = ParseWeightingFactors(shdr->num_ref_idx_l0_active_minus1,
1013 sps.chroma_array_type,
1014 shdr->luma_log2_weight_denom,
1015 shdr->chroma_log2_weight_denom,
1016 &shdr->pred_weight_table_l0);
1017 if (res != kOk)
1018 return res;
1020 if (shdr->IsBSlice()) {
1021 res = ParseWeightingFactors(shdr->num_ref_idx_l1_active_minus1,
1022 sps.chroma_array_type,
1023 shdr->luma_log2_weight_denom,
1024 shdr->chroma_log2_weight_denom,
1025 &shdr->pred_weight_table_l1);
1026 if (res != kOk)
1027 return res;
1030 return kOk;
1033 H264Parser::Result H264Parser::ParseDecRefPicMarking(H264SliceHeader* shdr) {
1034 if (shdr->idr_pic_flag) {
1035 READ_BOOL_OR_RETURN(&shdr->no_output_of_prior_pics_flag);
1036 READ_BOOL_OR_RETURN(&shdr->long_term_reference_flag);
1037 } else {
1038 READ_BOOL_OR_RETURN(&shdr->adaptive_ref_pic_marking_mode_flag);
1040 H264DecRefPicMarking* marking;
1041 if (shdr->adaptive_ref_pic_marking_mode_flag) {
1042 size_t i;
1043 for (i = 0; i < arraysize(shdr->ref_pic_marking); ++i) {
1044 marking = &shdr->ref_pic_marking[i];
1046 READ_UE_OR_RETURN(&marking->memory_mgmnt_control_operation);
1047 if (marking->memory_mgmnt_control_operation == 0)
1048 break;
1050 if (marking->memory_mgmnt_control_operation == 1 ||
1051 marking->memory_mgmnt_control_operation == 3)
1052 READ_UE_OR_RETURN(&marking->difference_of_pic_nums_minus1);
1054 if (marking->memory_mgmnt_control_operation == 2)
1055 READ_UE_OR_RETURN(&marking->long_term_pic_num);
1057 if (marking->memory_mgmnt_control_operation == 3 ||
1058 marking->memory_mgmnt_control_operation == 6)
1059 READ_UE_OR_RETURN(&marking->long_term_frame_idx);
1061 if (marking->memory_mgmnt_control_operation == 4)
1062 READ_UE_OR_RETURN(&marking->max_long_term_frame_idx_plus1);
1064 if (marking->memory_mgmnt_control_operation > 6)
1065 return kInvalidStream;
1068 if (i == arraysize(shdr->ref_pic_marking)) {
1069 DVLOG(1) << "Ran out of dec ref pic marking fields";
1070 return kUnsupportedStream;
1075 return kOk;
1078 H264Parser::Result H264Parser::ParseSliceHeader(const H264NALU& nalu,
1079 H264SliceHeader* shdr) {
1080 // See 7.4.3.
1081 const H264SPS* sps;
1082 const H264PPS* pps;
1083 Result res;
1085 memset(shdr, 0, sizeof(*shdr));
1087 shdr->idr_pic_flag = (nalu.nal_unit_type == 5);
1088 shdr->nal_ref_idc = nalu.nal_ref_idc;
1089 shdr->nalu_data = nalu.data;
1090 shdr->nalu_size = nalu.size;
1092 READ_UE_OR_RETURN(&shdr->first_mb_in_slice);
1093 READ_UE_OR_RETURN(&shdr->slice_type);
1094 TRUE_OR_RETURN(shdr->slice_type < 10);
1096 READ_UE_OR_RETURN(&shdr->pic_parameter_set_id);
1098 pps = GetPPS(shdr->pic_parameter_set_id);
1099 TRUE_OR_RETURN(pps);
1101 sps = GetSPS(pps->seq_parameter_set_id);
1102 TRUE_OR_RETURN(sps);
1104 if (sps->separate_colour_plane_flag) {
1105 DVLOG(1) << "Interlaced streams not supported";
1106 return kUnsupportedStream;
1109 READ_BITS_OR_RETURN(sps->log2_max_frame_num_minus4 + 4, &shdr->frame_num);
1110 if (!sps->frame_mbs_only_flag) {
1111 READ_BOOL_OR_RETURN(&shdr->field_pic_flag);
1112 if (shdr->field_pic_flag) {
1113 DVLOG(1) << "Interlaced streams not supported";
1114 return kUnsupportedStream;
1118 if (shdr->idr_pic_flag)
1119 READ_UE_OR_RETURN(&shdr->idr_pic_id);
1121 if (sps->pic_order_cnt_type == 0) {
1122 READ_BITS_OR_RETURN(sps->log2_max_pic_order_cnt_lsb_minus4 + 4,
1123 &shdr->pic_order_cnt_lsb);
1124 if (pps->bottom_field_pic_order_in_frame_present_flag &&
1125 !shdr->field_pic_flag)
1126 READ_SE_OR_RETURN(&shdr->delta_pic_order_cnt_bottom);
1129 if (sps->pic_order_cnt_type == 1 && !sps->delta_pic_order_always_zero_flag) {
1130 READ_SE_OR_RETURN(&shdr->delta_pic_order_cnt[0]);
1131 if (pps->bottom_field_pic_order_in_frame_present_flag &&
1132 !shdr->field_pic_flag)
1133 READ_SE_OR_RETURN(&shdr->delta_pic_order_cnt[1]);
1136 if (pps->redundant_pic_cnt_present_flag) {
1137 READ_UE_OR_RETURN(&shdr->redundant_pic_cnt);
1138 TRUE_OR_RETURN(shdr->redundant_pic_cnt < 128);
1141 if (shdr->IsBSlice())
1142 READ_BOOL_OR_RETURN(&shdr->direct_spatial_mv_pred_flag);
1144 if (shdr->IsPSlice() || shdr->IsSPSlice() || shdr->IsBSlice()) {
1145 READ_BOOL_OR_RETURN(&shdr->num_ref_idx_active_override_flag);
1146 if (shdr->num_ref_idx_active_override_flag) {
1147 READ_UE_OR_RETURN(&shdr->num_ref_idx_l0_active_minus1);
1148 if (shdr->IsBSlice())
1149 READ_UE_OR_RETURN(&shdr->num_ref_idx_l1_active_minus1);
1150 } else {
1151 shdr->num_ref_idx_l0_active_minus1 =
1152 pps->num_ref_idx_l0_default_active_minus1;
1153 if (shdr->IsBSlice()) {
1154 shdr->num_ref_idx_l1_active_minus1 =
1155 pps->num_ref_idx_l1_default_active_minus1;
1159 if (shdr->field_pic_flag) {
1160 TRUE_OR_RETURN(shdr->num_ref_idx_l0_active_minus1 < 32);
1161 TRUE_OR_RETURN(shdr->num_ref_idx_l1_active_minus1 < 32);
1162 } else {
1163 TRUE_OR_RETURN(shdr->num_ref_idx_l0_active_minus1 < 16);
1164 TRUE_OR_RETURN(shdr->num_ref_idx_l1_active_minus1 < 16);
1167 if (nalu.nal_unit_type == H264NALU::kCodedSliceExtension) {
1168 return kUnsupportedStream;
1169 } else {
1170 res = ParseRefPicListModifications(shdr);
1171 if (res != kOk)
1172 return res;
1175 if ((pps->weighted_pred_flag && (shdr->IsPSlice() || shdr->IsSPSlice())) ||
1176 (pps->weighted_bipred_idc == 1 && shdr->IsBSlice())) {
1177 res = ParsePredWeightTable(*sps, shdr);
1178 if (res != kOk)
1179 return res;
1182 if (nalu.nal_ref_idc != 0) {
1183 res = ParseDecRefPicMarking(shdr);
1184 if (res != kOk)
1185 return res;
1188 if (pps->entropy_coding_mode_flag && !shdr->IsISlice() &&
1189 !shdr->IsSISlice()) {
1190 READ_UE_OR_RETURN(&shdr->cabac_init_idc);
1191 TRUE_OR_RETURN(shdr->cabac_init_idc < 3);
1194 READ_SE_OR_RETURN(&shdr->slice_qp_delta);
1196 if (shdr->IsSPSlice() || shdr->IsSISlice()) {
1197 if (shdr->IsSPSlice())
1198 READ_BOOL_OR_RETURN(&shdr->sp_for_switch_flag);
1199 READ_SE_OR_RETURN(&shdr->slice_qs_delta);
1202 if (pps->deblocking_filter_control_present_flag) {
1203 READ_UE_OR_RETURN(&shdr->disable_deblocking_filter_idc);
1204 TRUE_OR_RETURN(shdr->disable_deblocking_filter_idc < 3);
1206 if (shdr->disable_deblocking_filter_idc != 1) {
1207 READ_SE_OR_RETURN(&shdr->slice_alpha_c0_offset_div2);
1208 IN_RANGE_OR_RETURN(shdr->slice_alpha_c0_offset_div2, -6, 6);
1210 READ_SE_OR_RETURN(&shdr->slice_beta_offset_div2);
1211 IN_RANGE_OR_RETURN(shdr->slice_beta_offset_div2, -6, 6);
1215 if (pps->num_slice_groups_minus1 > 0) {
1216 DVLOG(1) << "Slice groups not supported";
1217 return kUnsupportedStream;
1220 size_t epb = br_.NumEmulationPreventionBytesRead();
1221 shdr->header_bit_size = (shdr->nalu_size - epb) * 8 - br_.NumBitsLeft();
1223 return kOk;
1226 H264Parser::Result H264Parser::ParseSEI(H264SEIMessage* sei_msg) {
1227 int byte;
1229 memset(sei_msg, 0, sizeof(*sei_msg));
1231 READ_BITS_OR_RETURN(8, &byte);
1232 while (byte == 0xff) {
1233 sei_msg->type += 255;
1234 READ_BITS_OR_RETURN(8, &byte);
1236 sei_msg->type += byte;
1238 READ_BITS_OR_RETURN(8, &byte);
1239 while (byte == 0xff) {
1240 sei_msg->payload_size += 255;
1241 READ_BITS_OR_RETURN(8, &byte);
1243 sei_msg->payload_size += byte;
1245 DVLOG(4) << "Found SEI message type: " << sei_msg->type
1246 << " payload size: " << sei_msg->payload_size;
1248 switch (sei_msg->type) {
1249 case H264SEIMessage::kSEIRecoveryPoint:
1250 READ_UE_OR_RETURN(&sei_msg->recovery_point.recovery_frame_cnt);
1251 READ_BOOL_OR_RETURN(&sei_msg->recovery_point.exact_match_flag);
1252 READ_BOOL_OR_RETURN(&sei_msg->recovery_point.broken_link_flag);
1253 READ_BITS_OR_RETURN(2, &sei_msg->recovery_point.changing_slice_group_idc);
1254 break;
1256 default:
1257 DVLOG(4) << "Unsupported SEI message";
1258 break;
1261 return kOk;
1264 } // namespace media