Migrate away from the PrefMetricsService-based device ID in PrefHashCalculator.
[chromium-blink-merge.git] / media / filters / h264_parser.cc
blobee21ab82a1fca5381d91e9abe5908a23d831ca76
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 // ISO 14496 part 10
110 // VUI parameters: Table E-1 "Meaning of sample aspect ratio indicator"
111 static const int kTableSarWidth[] = {
112 0, 1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160, 4, 3, 2
114 static const int kTableSarHeight[] = {
115 0, 1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1
117 COMPILE_ASSERT(arraysize(kTableSarWidth) == arraysize(kTableSarHeight),
118 sar_tables_must_have_same_size);
120 H264Parser::H264Parser() {
121 Reset();
124 H264Parser::~H264Parser() {
125 STLDeleteValues(&active_SPSes_);
126 STLDeleteValues(&active_PPSes_);
129 void H264Parser::Reset() {
130 stream_ = NULL;
131 bytes_left_ = 0;
134 void H264Parser::SetStream(const uint8* stream, off_t stream_size) {
135 DCHECK(stream);
136 DCHECK_GT(stream_size, 0);
138 stream_ = stream;
139 bytes_left_ = stream_size;
142 const H264PPS* H264Parser::GetPPS(int pps_id) {
143 return active_PPSes_[pps_id];
146 const H264SPS* H264Parser::GetSPS(int sps_id) {
147 return active_SPSes_[sps_id];
150 static inline bool IsStartCode(const uint8* data) {
151 return data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x01;
154 // static
155 bool H264Parser::FindStartCode(const uint8* data, off_t data_size,
156 off_t* offset, off_t* start_code_size) {
157 DCHECK_GE(data_size, 0);
158 off_t bytes_left = data_size;
160 while (bytes_left >= 3) {
161 if (IsStartCode(data)) {
162 // Found three-byte start code, set pointer at its beginning.
163 *offset = data_size - bytes_left;
164 *start_code_size = 3;
166 // If there is a zero byte before this start code,
167 // then it's actually a four-byte start code, so backtrack one byte.
168 if (*offset > 0 && *(data - 1) == 0x00) {
169 --(*offset);
170 ++(*start_code_size);
173 return true;
176 ++data;
177 --bytes_left;
180 // End of data: offset is pointing to the first byte that was not considered
181 // as a possible start of a start code.
182 // Note: there is no security issue when receiving a negative |data_size|
183 // since in this case, |bytes_left| is equal to |data_size| and thus
184 // |*offset| is equal to 0 (valid offset).
185 *offset = data_size - bytes_left;
186 *start_code_size = 0;
187 return false;
190 bool H264Parser::LocateNALU(off_t* nalu_size, off_t* start_code_size) {
191 // Find the start code of next NALU.
192 off_t nalu_start_off = 0;
193 off_t annexb_start_code_size = 0;
194 if (!FindStartCode(stream_, bytes_left_,
195 &nalu_start_off, &annexb_start_code_size)) {
196 DVLOG(4) << "Could not find start code, end of stream?";
197 return false;
200 // Move the stream to the beginning of the NALU (pointing at the start code).
201 stream_ += nalu_start_off;
202 bytes_left_ -= nalu_start_off;
204 const uint8* nalu_data = stream_ + annexb_start_code_size;
205 off_t max_nalu_data_size = bytes_left_ - annexb_start_code_size;
206 if (max_nalu_data_size <= 0) {
207 DVLOG(3) << "End of stream";
208 return false;
211 // Find the start code of next NALU;
212 // if successful, |nalu_size_without_start_code| is the number of bytes from
213 // after previous start code to before this one;
214 // if next start code is not found, it is still a valid NALU since there
215 // are some bytes left after the first start code: all the remaining bytes
216 // belong to the current NALU.
217 off_t next_start_code_size = 0;
218 off_t nalu_size_without_start_code = 0;
219 if (!FindStartCode(nalu_data, max_nalu_data_size,
220 &nalu_size_without_start_code, &next_start_code_size)) {
221 nalu_size_without_start_code = max_nalu_data_size;
223 *nalu_size = nalu_size_without_start_code + annexb_start_code_size;
224 *start_code_size = annexb_start_code_size;
225 return true;
228 H264Parser::Result H264Parser::ReadUE(int* val) {
229 int num_bits = -1;
230 int bit;
231 int rest;
233 // Count the number of contiguous zero bits.
234 do {
235 READ_BITS_OR_RETURN(1, &bit);
236 num_bits++;
237 } while (bit == 0);
239 if (num_bits > 31)
240 return kInvalidStream;
242 // Calculate exp-Golomb code value of size num_bits.
243 *val = (1 << num_bits) - 1;
245 if (num_bits > 0) {
246 READ_BITS_OR_RETURN(num_bits, &rest);
247 *val += rest;
250 return kOk;
253 H264Parser::Result H264Parser::ReadSE(int* val) {
254 int ue;
255 Result res;
257 // See Chapter 9 in the spec.
258 res = ReadUE(&ue);
259 if (res != kOk)
260 return res;
262 if (ue % 2 == 0)
263 *val = -(ue / 2);
264 else
265 *val = ue / 2 + 1;
267 return kOk;
270 H264Parser::Result H264Parser::AdvanceToNextNALU(H264NALU* nalu) {
271 off_t start_code_size;
272 off_t nalu_size_with_start_code;
273 if (!LocateNALU(&nalu_size_with_start_code, &start_code_size)) {
274 DVLOG(4) << "Could not find next NALU, bytes left in stream: "
275 << bytes_left_;
276 return kEOStream;
279 nalu->data = stream_ + start_code_size;
280 nalu->size = nalu_size_with_start_code - start_code_size;
281 DVLOG(4) << "NALU found: size=" << nalu_size_with_start_code;
283 // Initialize bit reader at the start of found NALU.
284 if (!br_.Initialize(nalu->data, nalu->size))
285 return kEOStream;
287 // Move parser state to after this NALU, so next time AdvanceToNextNALU
288 // is called, we will effectively be skipping it;
289 // other parsing functions will use the position saved
290 // in bit reader for parsing, so we don't have to remember it here.
291 stream_ += nalu_size_with_start_code;
292 bytes_left_ -= nalu_size_with_start_code;
294 // Read NALU header, skip the forbidden_zero_bit, but check for it.
295 int data;
296 READ_BITS_OR_RETURN(1, &data);
297 TRUE_OR_RETURN(data == 0);
299 READ_BITS_OR_RETURN(2, &nalu->nal_ref_idc);
300 READ_BITS_OR_RETURN(5, &nalu->nal_unit_type);
302 DVLOG(4) << "NALU type: " << static_cast<int>(nalu->nal_unit_type)
303 << " at: " << reinterpret_cast<const void*>(nalu->data)
304 << " size: " << nalu->size
305 << " ref: " << static_cast<int>(nalu->nal_ref_idc);
307 return kOk;
310 // Default scaling lists (per spec).
311 static const int kDefault4x4Intra[kH264ScalingList4x4Length] = {
312 6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, 32, 32, 37, 37, 42, };
314 static const int kDefault4x4Inter[kH264ScalingList4x4Length] = {
315 10, 14, 14, 20, 20, 20, 24, 24, 24, 24, 27, 27, 27, 30, 30, 34, };
317 static const int kDefault8x8Intra[kH264ScalingList8x8Length] = {
318 6, 10, 10, 13, 11, 13, 16, 16, 16, 16, 18, 18, 18, 18, 18, 23,
319 23, 23, 23, 23, 23, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27,
320 27, 27, 27, 27, 29, 29, 29, 29, 29, 29, 29, 31, 31, 31, 31, 31,
321 31, 33, 33, 33, 33, 33, 36, 36, 36, 36, 38, 38, 38, 40, 40, 42, };
323 static const int kDefault8x8Inter[kH264ScalingList8x8Length] = {
324 9, 13, 13, 15, 13, 15, 17, 17, 17, 17, 19, 19, 19, 19, 19, 21,
325 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24, 24,
326 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27,
327 27, 28, 28, 28, 28, 28, 30, 30, 30, 30, 32, 32, 32, 33, 33, 35, };
329 static inline void DefaultScalingList4x4(
330 int i,
331 int scaling_list4x4[][kH264ScalingList4x4Length]) {
332 DCHECK_LT(i, 6);
334 if (i < 3)
335 memcpy(scaling_list4x4[i], kDefault4x4Intra, sizeof(kDefault4x4Intra));
336 else if (i < 6)
337 memcpy(scaling_list4x4[i], kDefault4x4Inter, sizeof(kDefault4x4Inter));
340 static inline void DefaultScalingList8x8(
341 int i,
342 int scaling_list8x8[][kH264ScalingList8x8Length]) {
343 DCHECK_LT(i, 6);
345 if (i % 2 == 0)
346 memcpy(scaling_list8x8[i], kDefault8x8Intra, sizeof(kDefault8x8Intra));
347 else
348 memcpy(scaling_list8x8[i], kDefault8x8Inter, sizeof(kDefault8x8Inter));
351 static void FallbackScalingList4x4(
352 int i,
353 const int default_scaling_list_intra[],
354 const int default_scaling_list_inter[],
355 int scaling_list4x4[][kH264ScalingList4x4Length]) {
356 static const int kScalingList4x4ByteSize =
357 sizeof(scaling_list4x4[0][0]) * kH264ScalingList4x4Length;
359 switch (i) {
360 case 0:
361 memcpy(scaling_list4x4[i], default_scaling_list_intra,
362 kScalingList4x4ByteSize);
363 break;
365 case 1:
366 memcpy(scaling_list4x4[i], scaling_list4x4[0], kScalingList4x4ByteSize);
367 break;
369 case 2:
370 memcpy(scaling_list4x4[i], scaling_list4x4[1], kScalingList4x4ByteSize);
371 break;
373 case 3:
374 memcpy(scaling_list4x4[i], default_scaling_list_inter,
375 kScalingList4x4ByteSize);
376 break;
378 case 4:
379 memcpy(scaling_list4x4[i], scaling_list4x4[3], kScalingList4x4ByteSize);
380 break;
382 case 5:
383 memcpy(scaling_list4x4[i], scaling_list4x4[4], kScalingList4x4ByteSize);
384 break;
386 default:
387 NOTREACHED();
388 break;
392 static void FallbackScalingList8x8(
393 int i,
394 const int default_scaling_list_intra[],
395 const int default_scaling_list_inter[],
396 int scaling_list8x8[][kH264ScalingList8x8Length]) {
397 static const int kScalingList8x8ByteSize =
398 sizeof(scaling_list8x8[0][0]) * kH264ScalingList8x8Length;
400 switch (i) {
401 case 0:
402 memcpy(scaling_list8x8[i], default_scaling_list_intra,
403 kScalingList8x8ByteSize);
404 break;
406 case 1:
407 memcpy(scaling_list8x8[i], default_scaling_list_inter,
408 kScalingList8x8ByteSize);
409 break;
411 case 2:
412 memcpy(scaling_list8x8[i], scaling_list8x8[0], kScalingList8x8ByteSize);
413 break;
415 case 3:
416 memcpy(scaling_list8x8[i], scaling_list8x8[1], kScalingList8x8ByteSize);
417 break;
419 case 4:
420 memcpy(scaling_list8x8[i], scaling_list8x8[2], kScalingList8x8ByteSize);
421 break;
423 case 5:
424 memcpy(scaling_list8x8[i], scaling_list8x8[3], kScalingList8x8ByteSize);
425 break;
427 default:
428 NOTREACHED();
429 break;
433 H264Parser::Result H264Parser::ParseScalingList(int size,
434 int* scaling_list,
435 bool* use_default) {
436 // See chapter 7.3.2.1.1.1.
437 int last_scale = 8;
438 int next_scale = 8;
439 int delta_scale;
441 *use_default = false;
443 for (int j = 0; j < size; ++j) {
444 if (next_scale != 0) {
445 READ_SE_OR_RETURN(&delta_scale);
446 IN_RANGE_OR_RETURN(delta_scale, -128, 127);
447 next_scale = (last_scale + delta_scale + 256) & 0xff;
449 if (j == 0 && next_scale == 0) {
450 *use_default = true;
451 return kOk;
455 scaling_list[j] = (next_scale == 0) ? last_scale : next_scale;
456 last_scale = scaling_list[j];
459 return kOk;
462 H264Parser::Result H264Parser::ParseSPSScalingLists(H264SPS* sps) {
463 // See 7.4.2.1.1.
464 bool seq_scaling_list_present_flag;
465 bool use_default;
466 Result res;
468 // Parse scaling_list4x4.
469 for (int i = 0; i < 6; ++i) {
470 READ_BOOL_OR_RETURN(&seq_scaling_list_present_flag);
472 if (seq_scaling_list_present_flag) {
473 res = ParseScalingList(arraysize(sps->scaling_list4x4[i]),
474 sps->scaling_list4x4[i],
475 &use_default);
476 if (res != kOk)
477 return res;
479 if (use_default)
480 DefaultScalingList4x4(i, sps->scaling_list4x4);
482 } else {
483 FallbackScalingList4x4(
484 i, kDefault4x4Intra, kDefault4x4Inter, sps->scaling_list4x4);
488 // Parse scaling_list8x8.
489 for (int i = 0; i < ((sps->chroma_format_idc != 3) ? 2 : 6); ++i) {
490 READ_BOOL_OR_RETURN(&seq_scaling_list_present_flag);
492 if (seq_scaling_list_present_flag) {
493 res = ParseScalingList(arraysize(sps->scaling_list8x8[i]),
494 sps->scaling_list8x8[i],
495 &use_default);
496 if (res != kOk)
497 return res;
499 if (use_default)
500 DefaultScalingList8x8(i, sps->scaling_list8x8);
502 } else {
503 FallbackScalingList8x8(
504 i, kDefault8x8Intra, kDefault8x8Inter, sps->scaling_list8x8);
508 return kOk;
511 H264Parser::Result H264Parser::ParsePPSScalingLists(const H264SPS& sps,
512 H264PPS* pps) {
513 // See 7.4.2.2.
514 bool pic_scaling_list_present_flag;
515 bool use_default;
516 Result res;
518 for (int i = 0; i < 6; ++i) {
519 READ_BOOL_OR_RETURN(&pic_scaling_list_present_flag);
521 if (pic_scaling_list_present_flag) {
522 res = ParseScalingList(arraysize(pps->scaling_list4x4[i]),
523 pps->scaling_list4x4[i],
524 &use_default);
525 if (res != kOk)
526 return res;
528 if (use_default)
529 DefaultScalingList4x4(i, pps->scaling_list4x4);
531 } else {
532 if (sps.seq_scaling_matrix_present_flag) {
533 // Table 7-2 fallback rule A in spec.
534 FallbackScalingList4x4(
535 i, kDefault4x4Intra, kDefault4x4Inter, pps->scaling_list4x4);
536 } else {
537 // Table 7-2 fallback rule B in spec.
538 FallbackScalingList4x4(i,
539 sps.scaling_list4x4[0],
540 sps.scaling_list4x4[3],
541 pps->scaling_list4x4);
546 if (pps->transform_8x8_mode_flag) {
547 for (int i = 0; i < ((sps.chroma_format_idc != 3) ? 2 : 6); ++i) {
548 READ_BOOL_OR_RETURN(&pic_scaling_list_present_flag);
550 if (pic_scaling_list_present_flag) {
551 res = ParseScalingList(arraysize(pps->scaling_list8x8[i]),
552 pps->scaling_list8x8[i],
553 &use_default);
554 if (res != kOk)
555 return res;
557 if (use_default)
558 DefaultScalingList8x8(i, pps->scaling_list8x8);
560 } else {
561 if (sps.seq_scaling_matrix_present_flag) {
562 // Table 7-2 fallback rule A in spec.
563 FallbackScalingList8x8(
564 i, kDefault8x8Intra, kDefault8x8Inter, pps->scaling_list8x8);
565 } else {
566 // Table 7-2 fallback rule B in spec.
567 FallbackScalingList8x8(i,
568 sps.scaling_list8x8[0],
569 sps.scaling_list8x8[1],
570 pps->scaling_list8x8);
575 return kOk;
578 H264Parser::Result H264Parser::ParseAndIgnoreHRDParameters(
579 bool* hrd_parameters_present) {
580 int data;
581 READ_BOOL_OR_RETURN(&data); // {nal,vcl}_hrd_parameters_present_flag
582 if (!data)
583 return kOk;
585 *hrd_parameters_present = true;
587 int cpb_cnt_minus1;
588 READ_UE_OR_RETURN(&cpb_cnt_minus1);
589 IN_RANGE_OR_RETURN(cpb_cnt_minus1, 0, 31);
590 READ_BITS_OR_RETURN(8, &data); // bit_rate_scale, cpb_size_scale
591 for (int i = 0; i <= cpb_cnt_minus1; ++i) {
592 READ_UE_OR_RETURN(&data); // bit_rate_value_minus1[i]
593 READ_UE_OR_RETURN(&data); // cpb_size_value_minus1[i]
594 READ_BOOL_OR_RETURN(&data); // cbr_flag
596 READ_BITS_OR_RETURN(20, &data); // cpb/dpb delays, etc.
598 return kOk;
601 H264Parser::Result H264Parser::ParseVUIParameters(H264SPS* sps) {
602 bool aspect_ratio_info_present_flag;
603 READ_BOOL_OR_RETURN(&aspect_ratio_info_present_flag);
604 if (aspect_ratio_info_present_flag) {
605 int aspect_ratio_idc;
606 READ_BITS_OR_RETURN(8, &aspect_ratio_idc);
607 if (aspect_ratio_idc == H264SPS::kExtendedSar) {
608 READ_BITS_OR_RETURN(16, &sps->sar_width);
609 READ_BITS_OR_RETURN(16, &sps->sar_height);
610 } else {
611 const int max_aspect_ratio_idc = arraysize(kTableSarWidth) - 1;
612 IN_RANGE_OR_RETURN(aspect_ratio_idc, 0, max_aspect_ratio_idc);
613 sps->sar_width = kTableSarWidth[aspect_ratio_idc];
614 sps->sar_height = kTableSarHeight[aspect_ratio_idc];
618 int data;
619 // Read and ignore overscan and video signal type info.
620 READ_BOOL_OR_RETURN(&data); // overscan_info_present_flag
621 if (data)
622 READ_BOOL_OR_RETURN(&data); // overscan_appropriate_flag
624 READ_BOOL_OR_RETURN(&data); // video_signal_type_present_flag
625 if (data) {
626 READ_BITS_OR_RETURN(3, &data); // video_format
627 READ_BOOL_OR_RETURN(&data); // video_full_range_flag
628 READ_BOOL_OR_RETURN(&data); // colour_description_present_flag
629 if (data)
630 READ_BITS_OR_RETURN(24, &data); // color description syntax elements
633 READ_BOOL_OR_RETURN(&data); // chroma_loc_info_present_flag
634 if (data) {
635 READ_UE_OR_RETURN(&data); // chroma_sample_loc_type_top_field
636 READ_UE_OR_RETURN(&data); // chroma_sample_loc_type_bottom_field
639 // Read and ignore timing info.
640 READ_BOOL_OR_RETURN(&data); // timing_info_present_flag
641 if (data) {
642 READ_BITS_OR_RETURN(16, &data); // num_units_in_tick
643 READ_BITS_OR_RETURN(16, &data); // num_units_in_tick
644 READ_BITS_OR_RETURN(16, &data); // time_scale
645 READ_BITS_OR_RETURN(16, &data); // time_scale
646 READ_BOOL_OR_RETURN(&data); // fixed_frame_rate_flag
649 // Read and ignore NAL HRD parameters, if present.
650 bool hrd_parameters_present = false;
651 Result res = ParseAndIgnoreHRDParameters(&hrd_parameters_present);
652 if (res != kOk)
653 return res;
655 // Read and ignore VCL HRD parameters, if present.
656 res = ParseAndIgnoreHRDParameters(&hrd_parameters_present);
657 if (res != kOk)
658 return res;
660 if (hrd_parameters_present) // One of NAL or VCL params present is enough.
661 READ_BOOL_OR_RETURN(&data); // low_delay_hrd_flag
663 READ_BOOL_OR_RETURN(&data); // pic_struct_present_flag
664 READ_BOOL_OR_RETURN(&sps->bitstream_restriction_flag);
665 if (sps->bitstream_restriction_flag) {
666 READ_BOOL_OR_RETURN(&data); // motion_vectors_over_pic_boundaries_flag
667 READ_UE_OR_RETURN(&data); // max_bytes_per_pic_denom
668 READ_UE_OR_RETURN(&data); // max_bits_per_mb_denom
669 READ_UE_OR_RETURN(&data); // log2_max_mv_length_horizontal
670 READ_UE_OR_RETURN(&data); // log2_max_mv_length_vertical
671 READ_UE_OR_RETURN(&sps->max_num_reorder_frames);
672 READ_UE_OR_RETURN(&sps->max_dec_frame_buffering);
673 TRUE_OR_RETURN(sps->max_dec_frame_buffering >= sps->max_num_ref_frames);
674 IN_RANGE_OR_RETURN(
675 sps->max_num_reorder_frames, 0, sps->max_dec_frame_buffering);
678 return kOk;
681 static void FillDefaultSeqScalingLists(H264SPS* sps) {
682 for (int i = 0; i < 6; ++i)
683 for (int j = 0; j < kH264ScalingList4x4Length; ++j)
684 sps->scaling_list4x4[i][j] = 16;
686 for (int i = 0; i < 6; ++i)
687 for (int j = 0; j < kH264ScalingList8x8Length; ++j)
688 sps->scaling_list8x8[i][j] = 16;
691 H264Parser::Result H264Parser::ParseSPS(int* sps_id) {
692 // See 7.4.2.1.
693 int data;
694 Result res;
696 *sps_id = -1;
698 scoped_ptr<H264SPS> sps(new H264SPS());
700 READ_BITS_OR_RETURN(8, &sps->profile_idc);
701 READ_BOOL_OR_RETURN(&sps->constraint_set0_flag);
702 READ_BOOL_OR_RETURN(&sps->constraint_set1_flag);
703 READ_BOOL_OR_RETURN(&sps->constraint_set2_flag);
704 READ_BOOL_OR_RETURN(&sps->constraint_set3_flag);
705 READ_BOOL_OR_RETURN(&sps->constraint_set4_flag);
706 READ_BOOL_OR_RETURN(&sps->constraint_set5_flag);
707 READ_BITS_OR_RETURN(2, &data); // reserved_zero_2bits
708 READ_BITS_OR_RETURN(8, &sps->level_idc);
709 READ_UE_OR_RETURN(&sps->seq_parameter_set_id);
710 TRUE_OR_RETURN(sps->seq_parameter_set_id < 32);
712 if (sps->profile_idc == 100 || sps->profile_idc == 110 ||
713 sps->profile_idc == 122 || sps->profile_idc == 244 ||
714 sps->profile_idc == 44 || sps->profile_idc == 83 ||
715 sps->profile_idc == 86 || sps->profile_idc == 118 ||
716 sps->profile_idc == 128) {
717 READ_UE_OR_RETURN(&sps->chroma_format_idc);
718 TRUE_OR_RETURN(sps->chroma_format_idc < 4);
720 if (sps->chroma_format_idc == 3)
721 READ_BOOL_OR_RETURN(&sps->separate_colour_plane_flag);
723 READ_UE_OR_RETURN(&sps->bit_depth_luma_minus8);
724 TRUE_OR_RETURN(sps->bit_depth_luma_minus8 < 7);
726 READ_UE_OR_RETURN(&sps->bit_depth_chroma_minus8);
727 TRUE_OR_RETURN(sps->bit_depth_chroma_minus8 < 7);
729 READ_BOOL_OR_RETURN(&sps->qpprime_y_zero_transform_bypass_flag);
730 READ_BOOL_OR_RETURN(&sps->seq_scaling_matrix_present_flag);
732 if (sps->seq_scaling_matrix_present_flag) {
733 DVLOG(4) << "Scaling matrix present";
734 res = ParseSPSScalingLists(sps.get());
735 if (res != kOk)
736 return res;
737 } else {
738 FillDefaultSeqScalingLists(sps.get());
740 } else {
741 sps->chroma_format_idc = 1;
742 FillDefaultSeqScalingLists(sps.get());
745 if (sps->separate_colour_plane_flag)
746 sps->chroma_array_type = 0;
747 else
748 sps->chroma_array_type = sps->chroma_format_idc;
750 READ_UE_OR_RETURN(&sps->log2_max_frame_num_minus4);
751 TRUE_OR_RETURN(sps->log2_max_frame_num_minus4 < 13);
753 READ_UE_OR_RETURN(&sps->pic_order_cnt_type);
754 TRUE_OR_RETURN(sps->pic_order_cnt_type < 3);
756 sps->expected_delta_per_pic_order_cnt_cycle = 0;
757 if (sps->pic_order_cnt_type == 0) {
758 READ_UE_OR_RETURN(&sps->log2_max_pic_order_cnt_lsb_minus4);
759 TRUE_OR_RETURN(sps->log2_max_pic_order_cnt_lsb_minus4 < 13);
760 } else if (sps->pic_order_cnt_type == 1) {
761 READ_BOOL_OR_RETURN(&sps->delta_pic_order_always_zero_flag);
762 READ_SE_OR_RETURN(&sps->offset_for_non_ref_pic);
763 READ_SE_OR_RETURN(&sps->offset_for_top_to_bottom_field);
764 READ_UE_OR_RETURN(&sps->num_ref_frames_in_pic_order_cnt_cycle);
765 TRUE_OR_RETURN(sps->num_ref_frames_in_pic_order_cnt_cycle < 255);
767 for (int i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; ++i) {
768 READ_SE_OR_RETURN(&sps->offset_for_ref_frame[i]);
769 sps->expected_delta_per_pic_order_cnt_cycle +=
770 sps->offset_for_ref_frame[i];
774 READ_UE_OR_RETURN(&sps->max_num_ref_frames);
775 READ_BOOL_OR_RETURN(&sps->gaps_in_frame_num_value_allowed_flag);
777 if (sps->gaps_in_frame_num_value_allowed_flag)
778 return kUnsupportedStream;
780 READ_UE_OR_RETURN(&sps->pic_width_in_mbs_minus1);
781 READ_UE_OR_RETURN(&sps->pic_height_in_map_units_minus1);
783 READ_BOOL_OR_RETURN(&sps->frame_mbs_only_flag);
784 if (!sps->frame_mbs_only_flag)
785 READ_BOOL_OR_RETURN(&sps->mb_adaptive_frame_field_flag);
787 READ_BOOL_OR_RETURN(&sps->direct_8x8_inference_flag);
789 READ_BOOL_OR_RETURN(&sps->frame_cropping_flag);
790 if (sps->frame_cropping_flag) {
791 READ_UE_OR_RETURN(&sps->frame_crop_left_offset);
792 READ_UE_OR_RETURN(&sps->frame_crop_right_offset);
793 READ_UE_OR_RETURN(&sps->frame_crop_top_offset);
794 READ_UE_OR_RETURN(&sps->frame_crop_bottom_offset);
797 READ_BOOL_OR_RETURN(&sps->vui_parameters_present_flag);
798 if (sps->vui_parameters_present_flag) {
799 DVLOG(4) << "VUI parameters present";
800 res = ParseVUIParameters(sps.get());
801 if (res != kOk)
802 return res;
805 // If an SPS with the same id already exists, replace it.
806 *sps_id = sps->seq_parameter_set_id;
807 delete active_SPSes_[*sps_id];
808 active_SPSes_[*sps_id] = sps.release();
810 return kOk;
813 H264Parser::Result H264Parser::ParsePPS(int* pps_id) {
814 // See 7.4.2.2.
815 const H264SPS* sps;
816 Result res;
818 *pps_id = -1;
820 scoped_ptr<H264PPS> pps(new H264PPS());
822 READ_UE_OR_RETURN(&pps->pic_parameter_set_id);
823 READ_UE_OR_RETURN(&pps->seq_parameter_set_id);
824 TRUE_OR_RETURN(pps->seq_parameter_set_id < 32);
826 sps = GetSPS(pps->seq_parameter_set_id);
827 TRUE_OR_RETURN(sps);
829 READ_BOOL_OR_RETURN(&pps->entropy_coding_mode_flag);
830 READ_BOOL_OR_RETURN(&pps->bottom_field_pic_order_in_frame_present_flag);
832 READ_UE_OR_RETURN(&pps->num_slice_groups_minus1);
833 if (pps->num_slice_groups_minus1 > 1) {
834 DVLOG(1) << "Slice groups not supported";
835 return kUnsupportedStream;
838 READ_UE_OR_RETURN(&pps->num_ref_idx_l0_default_active_minus1);
839 TRUE_OR_RETURN(pps->num_ref_idx_l0_default_active_minus1 < 32);
841 READ_UE_OR_RETURN(&pps->num_ref_idx_l1_default_active_minus1);
842 TRUE_OR_RETURN(pps->num_ref_idx_l1_default_active_minus1 < 32);
844 READ_BOOL_OR_RETURN(&pps->weighted_pred_flag);
845 READ_BITS_OR_RETURN(2, &pps->weighted_bipred_idc);
846 TRUE_OR_RETURN(pps->weighted_bipred_idc < 3);
848 READ_SE_OR_RETURN(&pps->pic_init_qp_minus26);
849 IN_RANGE_OR_RETURN(pps->pic_init_qp_minus26, -26, 25);
851 READ_SE_OR_RETURN(&pps->pic_init_qs_minus26);
852 IN_RANGE_OR_RETURN(pps->pic_init_qs_minus26, -26, 25);
854 READ_SE_OR_RETURN(&pps->chroma_qp_index_offset);
855 IN_RANGE_OR_RETURN(pps->chroma_qp_index_offset, -12, 12);
856 pps->second_chroma_qp_index_offset = pps->chroma_qp_index_offset;
858 READ_BOOL_OR_RETURN(&pps->deblocking_filter_control_present_flag);
859 READ_BOOL_OR_RETURN(&pps->constrained_intra_pred_flag);
860 READ_BOOL_OR_RETURN(&pps->redundant_pic_cnt_present_flag);
862 if (br_.HasMoreRBSPData()) {
863 READ_BOOL_OR_RETURN(&pps->transform_8x8_mode_flag);
864 READ_BOOL_OR_RETURN(&pps->pic_scaling_matrix_present_flag);
866 if (pps->pic_scaling_matrix_present_flag) {
867 DVLOG(4) << "Picture scaling matrix present";
868 res = ParsePPSScalingLists(*sps, pps.get());
869 if (res != kOk)
870 return res;
873 READ_SE_OR_RETURN(&pps->second_chroma_qp_index_offset);
876 // If a PPS with the same id already exists, replace it.
877 *pps_id = pps->pic_parameter_set_id;
878 delete active_PPSes_[*pps_id];
879 active_PPSes_[*pps_id] = pps.release();
881 return kOk;
884 H264Parser::Result H264Parser::ParseRefPicListModification(
885 int num_ref_idx_active_minus1,
886 H264ModificationOfPicNum* ref_list_mods) {
887 H264ModificationOfPicNum* pic_num_mod;
889 if (num_ref_idx_active_minus1 >= 32)
890 return kInvalidStream;
892 for (int i = 0; i < 32; ++i) {
893 pic_num_mod = &ref_list_mods[i];
894 READ_UE_OR_RETURN(&pic_num_mod->modification_of_pic_nums_idc);
895 TRUE_OR_RETURN(pic_num_mod->modification_of_pic_nums_idc < 4);
897 switch (pic_num_mod->modification_of_pic_nums_idc) {
898 case 0:
899 case 1:
900 READ_UE_OR_RETURN(&pic_num_mod->abs_diff_pic_num_minus1);
901 break;
903 case 2:
904 READ_UE_OR_RETURN(&pic_num_mod->long_term_pic_num);
905 break;
907 case 3:
908 // Per spec, list cannot be empty.
909 if (i == 0)
910 return kInvalidStream;
911 return kOk;
913 default:
914 return kInvalidStream;
918 // If we got here, we didn't get loop end marker prematurely,
919 // so make sure it is there for our client.
920 int modification_of_pic_nums_idc;
921 READ_UE_OR_RETURN(&modification_of_pic_nums_idc);
922 TRUE_OR_RETURN(modification_of_pic_nums_idc == 3);
924 return kOk;
927 H264Parser::Result H264Parser::ParseRefPicListModifications(
928 H264SliceHeader* shdr) {
929 Result res;
931 if (!shdr->IsISlice() && !shdr->IsSISlice()) {
932 READ_BOOL_OR_RETURN(&shdr->ref_pic_list_modification_flag_l0);
933 if (shdr->ref_pic_list_modification_flag_l0) {
934 res = ParseRefPicListModification(shdr->num_ref_idx_l0_active_minus1,
935 shdr->ref_list_l0_modifications);
936 if (res != kOk)
937 return res;
941 if (shdr->IsBSlice()) {
942 READ_BOOL_OR_RETURN(&shdr->ref_pic_list_modification_flag_l1);
943 if (shdr->ref_pic_list_modification_flag_l1) {
944 res = ParseRefPicListModification(shdr->num_ref_idx_l1_active_minus1,
945 shdr->ref_list_l1_modifications);
946 if (res != kOk)
947 return res;
951 return kOk;
954 H264Parser::Result H264Parser::ParseWeightingFactors(
955 int num_ref_idx_active_minus1,
956 int chroma_array_type,
957 int luma_log2_weight_denom,
958 int chroma_log2_weight_denom,
959 H264WeightingFactors* w_facts) {
961 int def_luma_weight = 1 << luma_log2_weight_denom;
962 int def_chroma_weight = 1 << chroma_log2_weight_denom;
964 for (int i = 0; i < num_ref_idx_active_minus1 + 1; ++i) {
965 READ_BOOL_OR_RETURN(&w_facts->luma_weight_flag);
966 if (w_facts->luma_weight_flag) {
967 READ_SE_OR_RETURN(&w_facts->luma_weight[i]);
968 IN_RANGE_OR_RETURN(w_facts->luma_weight[i], -128, 127);
970 READ_SE_OR_RETURN(&w_facts->luma_offset[i]);
971 IN_RANGE_OR_RETURN(w_facts->luma_offset[i], -128, 127);
972 } else {
973 w_facts->luma_weight[i] = def_luma_weight;
974 w_facts->luma_offset[i] = 0;
977 if (chroma_array_type != 0) {
978 READ_BOOL_OR_RETURN(&w_facts->chroma_weight_flag);
979 if (w_facts->chroma_weight_flag) {
980 for (int j = 0; j < 2; ++j) {
981 READ_SE_OR_RETURN(&w_facts->chroma_weight[i][j]);
982 IN_RANGE_OR_RETURN(w_facts->chroma_weight[i][j], -128, 127);
984 READ_SE_OR_RETURN(&w_facts->chroma_offset[i][j]);
985 IN_RANGE_OR_RETURN(w_facts->chroma_offset[i][j], -128, 127);
987 } else {
988 for (int j = 0; j < 2; ++j) {
989 w_facts->chroma_weight[i][j] = def_chroma_weight;
990 w_facts->chroma_offset[i][j] = 0;
996 return kOk;
999 H264Parser::Result H264Parser::ParsePredWeightTable(const H264SPS& sps,
1000 H264SliceHeader* shdr) {
1001 READ_UE_OR_RETURN(&shdr->luma_log2_weight_denom);
1002 TRUE_OR_RETURN(shdr->luma_log2_weight_denom < 8);
1004 if (sps.chroma_array_type != 0)
1005 READ_UE_OR_RETURN(&shdr->chroma_log2_weight_denom);
1006 TRUE_OR_RETURN(shdr->chroma_log2_weight_denom < 8);
1008 Result res = ParseWeightingFactors(shdr->num_ref_idx_l0_active_minus1,
1009 sps.chroma_array_type,
1010 shdr->luma_log2_weight_denom,
1011 shdr->chroma_log2_weight_denom,
1012 &shdr->pred_weight_table_l0);
1013 if (res != kOk)
1014 return res;
1016 if (shdr->IsBSlice()) {
1017 res = ParseWeightingFactors(shdr->num_ref_idx_l1_active_minus1,
1018 sps.chroma_array_type,
1019 shdr->luma_log2_weight_denom,
1020 shdr->chroma_log2_weight_denom,
1021 &shdr->pred_weight_table_l1);
1022 if (res != kOk)
1023 return res;
1026 return kOk;
1029 H264Parser::Result H264Parser::ParseDecRefPicMarking(H264SliceHeader* shdr) {
1030 if (shdr->idr_pic_flag) {
1031 READ_BOOL_OR_RETURN(&shdr->no_output_of_prior_pics_flag);
1032 READ_BOOL_OR_RETURN(&shdr->long_term_reference_flag);
1033 } else {
1034 READ_BOOL_OR_RETURN(&shdr->adaptive_ref_pic_marking_mode_flag);
1036 H264DecRefPicMarking* marking;
1037 if (shdr->adaptive_ref_pic_marking_mode_flag) {
1038 size_t i;
1039 for (i = 0; i < arraysize(shdr->ref_pic_marking); ++i) {
1040 marking = &shdr->ref_pic_marking[i];
1042 READ_UE_OR_RETURN(&marking->memory_mgmnt_control_operation);
1043 if (marking->memory_mgmnt_control_operation == 0)
1044 break;
1046 if (marking->memory_mgmnt_control_operation == 1 ||
1047 marking->memory_mgmnt_control_operation == 3)
1048 READ_UE_OR_RETURN(&marking->difference_of_pic_nums_minus1);
1050 if (marking->memory_mgmnt_control_operation == 2)
1051 READ_UE_OR_RETURN(&marking->long_term_pic_num);
1053 if (marking->memory_mgmnt_control_operation == 3 ||
1054 marking->memory_mgmnt_control_operation == 6)
1055 READ_UE_OR_RETURN(&marking->long_term_frame_idx);
1057 if (marking->memory_mgmnt_control_operation == 4)
1058 READ_UE_OR_RETURN(&marking->max_long_term_frame_idx_plus1);
1060 if (marking->memory_mgmnt_control_operation > 6)
1061 return kInvalidStream;
1064 if (i == arraysize(shdr->ref_pic_marking)) {
1065 DVLOG(1) << "Ran out of dec ref pic marking fields";
1066 return kUnsupportedStream;
1071 return kOk;
1074 H264Parser::Result H264Parser::ParseSliceHeader(const H264NALU& nalu,
1075 H264SliceHeader* shdr) {
1076 // See 7.4.3.
1077 const H264SPS* sps;
1078 const H264PPS* pps;
1079 Result res;
1081 memset(shdr, 0, sizeof(*shdr));
1083 shdr->idr_pic_flag = (nalu.nal_unit_type == 5);
1084 shdr->nal_ref_idc = nalu.nal_ref_idc;
1085 shdr->nalu_data = nalu.data;
1086 shdr->nalu_size = nalu.size;
1088 READ_UE_OR_RETURN(&shdr->first_mb_in_slice);
1089 READ_UE_OR_RETURN(&shdr->slice_type);
1090 TRUE_OR_RETURN(shdr->slice_type < 10);
1092 READ_UE_OR_RETURN(&shdr->pic_parameter_set_id);
1094 pps = GetPPS(shdr->pic_parameter_set_id);
1095 TRUE_OR_RETURN(pps);
1097 sps = GetSPS(pps->seq_parameter_set_id);
1098 TRUE_OR_RETURN(sps);
1100 if (sps->separate_colour_plane_flag) {
1101 DVLOG(1) << "Interlaced streams not supported";
1102 return kUnsupportedStream;
1105 READ_BITS_OR_RETURN(sps->log2_max_frame_num_minus4 + 4, &shdr->frame_num);
1106 if (!sps->frame_mbs_only_flag) {
1107 READ_BOOL_OR_RETURN(&shdr->field_pic_flag);
1108 if (shdr->field_pic_flag) {
1109 DVLOG(1) << "Interlaced streams not supported";
1110 return kUnsupportedStream;
1114 if (shdr->idr_pic_flag)
1115 READ_UE_OR_RETURN(&shdr->idr_pic_id);
1117 if (sps->pic_order_cnt_type == 0) {
1118 READ_BITS_OR_RETURN(sps->log2_max_pic_order_cnt_lsb_minus4 + 4,
1119 &shdr->pic_order_cnt_lsb);
1120 if (pps->bottom_field_pic_order_in_frame_present_flag &&
1121 !shdr->field_pic_flag)
1122 READ_SE_OR_RETURN(&shdr->delta_pic_order_cnt_bottom);
1125 if (sps->pic_order_cnt_type == 1 && !sps->delta_pic_order_always_zero_flag) {
1126 READ_SE_OR_RETURN(&shdr->delta_pic_order_cnt[0]);
1127 if (pps->bottom_field_pic_order_in_frame_present_flag &&
1128 !shdr->field_pic_flag)
1129 READ_SE_OR_RETURN(&shdr->delta_pic_order_cnt[1]);
1132 if (pps->redundant_pic_cnt_present_flag) {
1133 READ_UE_OR_RETURN(&shdr->redundant_pic_cnt);
1134 TRUE_OR_RETURN(shdr->redundant_pic_cnt < 128);
1137 if (shdr->IsBSlice())
1138 READ_BOOL_OR_RETURN(&shdr->direct_spatial_mv_pred_flag);
1140 if (shdr->IsPSlice() || shdr->IsSPSlice() || shdr->IsBSlice()) {
1141 READ_BOOL_OR_RETURN(&shdr->num_ref_idx_active_override_flag);
1142 if (shdr->num_ref_idx_active_override_flag) {
1143 READ_UE_OR_RETURN(&shdr->num_ref_idx_l0_active_minus1);
1144 if (shdr->IsBSlice())
1145 READ_UE_OR_RETURN(&shdr->num_ref_idx_l1_active_minus1);
1146 } else {
1147 shdr->num_ref_idx_l0_active_minus1 =
1148 pps->num_ref_idx_l0_default_active_minus1;
1149 if (shdr->IsBSlice()) {
1150 shdr->num_ref_idx_l1_active_minus1 =
1151 pps->num_ref_idx_l1_default_active_minus1;
1155 if (shdr->field_pic_flag) {
1156 TRUE_OR_RETURN(shdr->num_ref_idx_l0_active_minus1 < 32);
1157 TRUE_OR_RETURN(shdr->num_ref_idx_l1_active_minus1 < 32);
1158 } else {
1159 TRUE_OR_RETURN(shdr->num_ref_idx_l0_active_minus1 < 16);
1160 TRUE_OR_RETURN(shdr->num_ref_idx_l1_active_minus1 < 16);
1163 if (nalu.nal_unit_type == H264NALU::kCodedSliceExtension) {
1164 return kUnsupportedStream;
1165 } else {
1166 res = ParseRefPicListModifications(shdr);
1167 if (res != kOk)
1168 return res;
1171 if ((pps->weighted_pred_flag && (shdr->IsPSlice() || shdr->IsSPSlice())) ||
1172 (pps->weighted_bipred_idc == 1 && shdr->IsBSlice())) {
1173 res = ParsePredWeightTable(*sps, shdr);
1174 if (res != kOk)
1175 return res;
1178 if (nalu.nal_ref_idc != 0) {
1179 res = ParseDecRefPicMarking(shdr);
1180 if (res != kOk)
1181 return res;
1184 if (pps->entropy_coding_mode_flag && !shdr->IsISlice() &&
1185 !shdr->IsSISlice()) {
1186 READ_UE_OR_RETURN(&shdr->cabac_init_idc);
1187 TRUE_OR_RETURN(shdr->cabac_init_idc < 3);
1190 READ_SE_OR_RETURN(&shdr->slice_qp_delta);
1192 if (shdr->IsSPSlice() || shdr->IsSISlice()) {
1193 if (shdr->IsSPSlice())
1194 READ_BOOL_OR_RETURN(&shdr->sp_for_switch_flag);
1195 READ_SE_OR_RETURN(&shdr->slice_qs_delta);
1198 if (pps->deblocking_filter_control_present_flag) {
1199 READ_UE_OR_RETURN(&shdr->disable_deblocking_filter_idc);
1200 TRUE_OR_RETURN(shdr->disable_deblocking_filter_idc < 3);
1202 if (shdr->disable_deblocking_filter_idc != 1) {
1203 READ_SE_OR_RETURN(&shdr->slice_alpha_c0_offset_div2);
1204 IN_RANGE_OR_RETURN(shdr->slice_alpha_c0_offset_div2, -6, 6);
1206 READ_SE_OR_RETURN(&shdr->slice_beta_offset_div2);
1207 IN_RANGE_OR_RETURN(shdr->slice_beta_offset_div2, -6, 6);
1211 if (pps->num_slice_groups_minus1 > 0) {
1212 DVLOG(1) << "Slice groups not supported";
1213 return kUnsupportedStream;
1216 size_t epb = br_.NumEmulationPreventionBytesRead();
1217 shdr->header_bit_size = (shdr->nalu_size - epb) * 8 - br_.NumBitsLeft();
1219 return kOk;
1222 H264Parser::Result H264Parser::ParseSEI(H264SEIMessage* sei_msg) {
1223 int byte;
1225 memset(sei_msg, 0, sizeof(*sei_msg));
1227 READ_BITS_OR_RETURN(8, &byte);
1228 while (byte == 0xff) {
1229 sei_msg->type += 255;
1230 READ_BITS_OR_RETURN(8, &byte);
1232 sei_msg->type += byte;
1234 READ_BITS_OR_RETURN(8, &byte);
1235 while (byte == 0xff) {
1236 sei_msg->payload_size += 255;
1237 READ_BITS_OR_RETURN(8, &byte);
1239 sei_msg->payload_size += byte;
1241 DVLOG(4) << "Found SEI message type: " << sei_msg->type
1242 << " payload size: " << sei_msg->payload_size;
1244 switch (sei_msg->type) {
1245 case H264SEIMessage::kSEIRecoveryPoint:
1246 READ_UE_OR_RETURN(&sei_msg->recovery_point.recovery_frame_cnt);
1247 READ_BOOL_OR_RETURN(&sei_msg->recovery_point.exact_match_flag);
1248 READ_BOOL_OR_RETURN(&sei_msg->recovery_point.broken_link_flag);
1249 READ_BITS_OR_RETURN(2, &sei_msg->recovery_point.changing_slice_group_idc);
1250 break;
1252 default:
1253 DVLOG(4) << "Unsupported SEI message";
1254 break;
1257 return kOk;
1260 } // namespace media