Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / common / gpu / media / h264_decoder.cc
blob6f9c91804828a7f51a99ea78f81f135c55b58df6
1 // Copyright (c) 2012 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 <algorithm>
6 #include <limits>
8 #include "base/bind.h"
9 #include "base/bind_helpers.h"
10 #include "base/callback_helpers.h"
11 #include "base/numerics/safe_conversions.h"
12 #include "base/stl_util.h"
13 #include "content/common/gpu/media/h264_decoder.h"
15 namespace content {
17 H264Decoder::H264Accelerator::H264Accelerator() {
20 H264Decoder::H264Accelerator::~H264Accelerator() {
23 H264Decoder::H264Decoder(H264Accelerator* accelerator)
24 : max_pic_order_cnt_lsb_(0),
25 max_frame_num_(0),
26 max_pic_num_(0),
27 max_long_term_frame_idx_(0),
28 max_num_reorder_frames_(0),
29 curr_sps_id_(-1),
30 curr_pps_id_(-1),
31 accelerator_(accelerator) {
32 DCHECK(accelerator_);
33 Reset();
34 state_ = kNeedStreamMetadata;
37 H264Decoder::~H264Decoder() {
40 void H264Decoder::Reset() {
41 curr_pic_ = nullptr;
42 curr_nalu_ = nullptr;
43 curr_slice_hdr_ = nullptr;
45 frame_num_ = 0;
46 prev_frame_num_ = -1;
47 prev_frame_num_offset_ = -1;
49 prev_ref_has_memmgmnt5_ = false;
50 prev_ref_top_field_order_cnt_ = -1;
51 prev_ref_pic_order_cnt_msb_ = -1;
52 prev_ref_pic_order_cnt_lsb_ = -1;
53 prev_ref_field_ = H264Picture::FIELD_NONE;
55 ref_pic_list_p0_.clear();
56 ref_pic_list_b0_.clear();
57 ref_pic_list_b1_.clear();
58 dpb_.Clear();
59 parser_.Reset();
60 accelerator_->Reset();
61 last_output_poc_ = std::numeric_limits<int>::min();
63 // If we are in kDecoding, we can resume without processing an SPS.
64 if (state_ == kDecoding)
65 state_ = kAfterReset;
68 void H264Decoder::PrepareRefPicLists(media::H264SliceHeader* slice_hdr) {
69 ConstructReferencePicListsP(slice_hdr);
70 ConstructReferencePicListsB(slice_hdr);
73 bool H264Decoder::ModifyReferencePicLists(media::H264SliceHeader* slice_hdr,
74 H264Picture::Vector* ref_pic_list0,
75 H264Picture::Vector* ref_pic_list1) {
76 ref_pic_list0->clear();
77 ref_pic_list1->clear();
79 // Fill reference picture lists for B and S/SP slices.
80 if (slice_hdr->IsPSlice() || slice_hdr->IsSPSlice()) {
81 *ref_pic_list0 = ref_pic_list_p0_;
82 return ModifyReferencePicList(slice_hdr, 0, ref_pic_list0);
83 } else if (slice_hdr->IsBSlice()) {
84 *ref_pic_list0 = ref_pic_list_b0_;
85 *ref_pic_list1 = ref_pic_list_b1_;
86 return ModifyReferencePicList(slice_hdr, 0, ref_pic_list0) &&
87 ModifyReferencePicList(slice_hdr, 1, ref_pic_list1);
90 return true;
93 bool H264Decoder::DecodePicture() {
94 DCHECK(curr_pic_.get());
96 DVLOG(4) << "Decoding POC " << curr_pic_->pic_order_cnt;
97 return accelerator_->SubmitDecode(curr_pic_);
100 bool H264Decoder::InitCurrPicture(media::H264SliceHeader* slice_hdr) {
101 DCHECK(curr_pic_.get());
103 curr_pic_->idr = slice_hdr->idr_pic_flag;
105 if (slice_hdr->field_pic_flag) {
106 curr_pic_->field = slice_hdr->bottom_field_flag ? H264Picture::FIELD_BOTTOM
107 : H264Picture::FIELD_TOP;
108 } else {
109 curr_pic_->field = H264Picture::FIELD_NONE;
112 curr_pic_->ref = slice_hdr->nal_ref_idc != 0;
113 // This assumes non-interlaced stream.
114 curr_pic_->frame_num = curr_pic_->pic_num = slice_hdr->frame_num;
116 if (!CalculatePicOrderCounts(slice_hdr))
117 return false;
119 curr_pic_->long_term_reference_flag = slice_hdr->long_term_reference_flag;
120 curr_pic_->adaptive_ref_pic_marking_mode_flag =
121 slice_hdr->adaptive_ref_pic_marking_mode_flag;
123 // If the slice header indicates we will have to perform reference marking
124 // process after this picture is decoded, store required data for that
125 // purpose.
126 if (slice_hdr->adaptive_ref_pic_marking_mode_flag) {
127 static_assert(sizeof(curr_pic_->ref_pic_marking) ==
128 sizeof(slice_hdr->ref_pic_marking),
129 "Array sizes of ref pic marking do not match.");
130 memcpy(curr_pic_->ref_pic_marking, slice_hdr->ref_pic_marking,
131 sizeof(curr_pic_->ref_pic_marking));
134 return true;
137 bool H264Decoder::CalculatePicOrderCounts(media::H264SliceHeader* slice_hdr) {
138 DCHECK_NE(curr_sps_id_, -1);
139 const media::H264SPS* sps = parser_.GetSPS(curr_sps_id_);
141 int pic_order_cnt_lsb = slice_hdr->pic_order_cnt_lsb;
142 curr_pic_->pic_order_cnt_lsb = pic_order_cnt_lsb;
144 switch (sps->pic_order_cnt_type) {
145 case 0:
146 // See spec 8.2.1.1.
147 int prev_pic_order_cnt_msb, prev_pic_order_cnt_lsb;
148 if (slice_hdr->idr_pic_flag) {
149 prev_pic_order_cnt_msb = prev_pic_order_cnt_lsb = 0;
150 } else {
151 if (prev_ref_has_memmgmnt5_) {
152 if (prev_ref_field_ != H264Picture::FIELD_BOTTOM) {
153 prev_pic_order_cnt_msb = 0;
154 prev_pic_order_cnt_lsb = prev_ref_top_field_order_cnt_;
155 } else {
156 prev_pic_order_cnt_msb = 0;
157 prev_pic_order_cnt_lsb = 0;
159 } else {
160 prev_pic_order_cnt_msb = prev_ref_pic_order_cnt_msb_;
161 prev_pic_order_cnt_lsb = prev_ref_pic_order_cnt_lsb_;
165 DCHECK_NE(max_pic_order_cnt_lsb_, 0);
166 if ((pic_order_cnt_lsb < prev_pic_order_cnt_lsb) &&
167 (prev_pic_order_cnt_lsb - pic_order_cnt_lsb >=
168 max_pic_order_cnt_lsb_ / 2)) {
169 curr_pic_->pic_order_cnt_msb = prev_pic_order_cnt_msb +
170 max_pic_order_cnt_lsb_;
171 } else if ((pic_order_cnt_lsb > prev_pic_order_cnt_lsb) &&
172 (pic_order_cnt_lsb - prev_pic_order_cnt_lsb >
173 max_pic_order_cnt_lsb_ / 2)) {
174 curr_pic_->pic_order_cnt_msb = prev_pic_order_cnt_msb -
175 max_pic_order_cnt_lsb_;
176 } else {
177 curr_pic_->pic_order_cnt_msb = prev_pic_order_cnt_msb;
180 if (curr_pic_->field != H264Picture::FIELD_BOTTOM) {
181 curr_pic_->top_field_order_cnt = curr_pic_->pic_order_cnt_msb +
182 pic_order_cnt_lsb;
185 if (curr_pic_->field != H264Picture::FIELD_TOP) {
186 // TODO posciak: perhaps replace with pic->field?
187 if (!slice_hdr->field_pic_flag) {
188 curr_pic_->bottom_field_order_cnt = curr_pic_->top_field_order_cnt +
189 slice_hdr->delta_pic_order_cnt_bottom;
190 } else {
191 curr_pic_->bottom_field_order_cnt = curr_pic_->pic_order_cnt_msb +
192 pic_order_cnt_lsb;
195 break;
197 case 1: {
198 // See spec 8.2.1.2.
199 if (prev_has_memmgmnt5_)
200 prev_frame_num_offset_ = 0;
202 if (slice_hdr->idr_pic_flag)
203 curr_pic_->frame_num_offset = 0;
204 else if (prev_frame_num_ > slice_hdr->frame_num)
205 curr_pic_->frame_num_offset = prev_frame_num_offset_ + max_frame_num_;
206 else
207 curr_pic_->frame_num_offset = prev_frame_num_offset_;
209 int abs_frame_num = 0;
210 if (sps->num_ref_frames_in_pic_order_cnt_cycle != 0)
211 abs_frame_num = curr_pic_->frame_num_offset + slice_hdr->frame_num;
212 else
213 abs_frame_num = 0;
215 if (slice_hdr->nal_ref_idc == 0 && abs_frame_num > 0)
216 --abs_frame_num;
218 int expected_pic_order_cnt = 0;
219 if (abs_frame_num > 0) {
220 if (sps->num_ref_frames_in_pic_order_cnt_cycle == 0) {
221 DVLOG(1) << "Invalid num_ref_frames_in_pic_order_cnt_cycle "
222 << "in stream";
223 return false;
226 int pic_order_cnt_cycle_cnt = (abs_frame_num - 1) /
227 sps->num_ref_frames_in_pic_order_cnt_cycle;
228 int frame_num_in_pic_order_cnt_cycle = (abs_frame_num - 1) %
229 sps->num_ref_frames_in_pic_order_cnt_cycle;
231 expected_pic_order_cnt = pic_order_cnt_cycle_cnt *
232 sps->expected_delta_per_pic_order_cnt_cycle;
233 // frame_num_in_pic_order_cnt_cycle is verified < 255 in parser
234 for (int i = 0; i <= frame_num_in_pic_order_cnt_cycle; ++i)
235 expected_pic_order_cnt += sps->offset_for_ref_frame[i];
238 if (!slice_hdr->nal_ref_idc)
239 expected_pic_order_cnt += sps->offset_for_non_ref_pic;
241 if (!slice_hdr->field_pic_flag) {
242 curr_pic_->top_field_order_cnt = expected_pic_order_cnt +
243 slice_hdr->delta_pic_order_cnt0;
244 curr_pic_->bottom_field_order_cnt = curr_pic_->top_field_order_cnt +
245 sps->offset_for_top_to_bottom_field +
246 slice_hdr->delta_pic_order_cnt1;
247 } else if (!slice_hdr->bottom_field_flag) {
248 curr_pic_->top_field_order_cnt = expected_pic_order_cnt +
249 slice_hdr->delta_pic_order_cnt0;
250 } else {
251 curr_pic_->bottom_field_order_cnt = expected_pic_order_cnt +
252 sps->offset_for_top_to_bottom_field +
253 slice_hdr->delta_pic_order_cnt0;
255 break;
258 case 2:
259 // See spec 8.2.1.3.
260 if (prev_has_memmgmnt5_)
261 prev_frame_num_offset_ = 0;
263 if (slice_hdr->idr_pic_flag)
264 curr_pic_->frame_num_offset = 0;
265 else if (prev_frame_num_ > slice_hdr->frame_num)
266 curr_pic_->frame_num_offset = prev_frame_num_offset_ + max_frame_num_;
267 else
268 curr_pic_->frame_num_offset = prev_frame_num_offset_;
270 int temp_pic_order_cnt;
271 if (slice_hdr->idr_pic_flag) {
272 temp_pic_order_cnt = 0;
273 } else if (!slice_hdr->nal_ref_idc) {
274 temp_pic_order_cnt =
275 2 * (curr_pic_->frame_num_offset + slice_hdr->frame_num) - 1;
276 } else {
277 temp_pic_order_cnt = 2 * (curr_pic_->frame_num_offset +
278 slice_hdr->frame_num);
281 if (!slice_hdr->field_pic_flag) {
282 curr_pic_->top_field_order_cnt = temp_pic_order_cnt;
283 curr_pic_->bottom_field_order_cnt = temp_pic_order_cnt;
284 } else if (slice_hdr->bottom_field_flag) {
285 curr_pic_->bottom_field_order_cnt = temp_pic_order_cnt;
286 } else {
287 curr_pic_->top_field_order_cnt = temp_pic_order_cnt;
289 break;
291 default:
292 DVLOG(1) << "Invalid pic_order_cnt_type: " << sps->pic_order_cnt_type;
293 return false;
296 switch (curr_pic_->field) {
297 case H264Picture::FIELD_NONE:
298 curr_pic_->pic_order_cnt = std::min(curr_pic_->top_field_order_cnt,
299 curr_pic_->bottom_field_order_cnt);
300 break;
301 case H264Picture::FIELD_TOP:
302 curr_pic_->pic_order_cnt = curr_pic_->top_field_order_cnt;
303 break;
304 case H264Picture::FIELD_BOTTOM:
305 curr_pic_->pic_order_cnt = curr_pic_->bottom_field_order_cnt;
306 break;
309 return true;
312 void H264Decoder::UpdatePicNums() {
313 for (auto& pic : dpb_) {
314 if (!pic->ref)
315 continue;
317 // Below assumes non-interlaced stream.
318 DCHECK_EQ(pic->field, H264Picture::FIELD_NONE);
319 if (pic->long_term) {
320 pic->long_term_pic_num = pic->long_term_frame_idx;
321 } else {
322 if (pic->frame_num > frame_num_)
323 pic->frame_num_wrap = pic->frame_num - max_frame_num_;
324 else
325 pic->frame_num_wrap = pic->frame_num;
327 pic->pic_num = pic->frame_num_wrap;
332 struct PicNumDescCompare {
333 bool operator()(const scoped_refptr<H264Picture>& a,
334 const scoped_refptr<H264Picture>& b) const {
335 return a->pic_num > b->pic_num;
339 struct LongTermPicNumAscCompare {
340 bool operator()(const scoped_refptr<H264Picture>& a,
341 const scoped_refptr<H264Picture>& b) const {
342 return a->long_term_pic_num < b->long_term_pic_num;
346 void H264Decoder::ConstructReferencePicListsP(
347 media::H264SliceHeader* slice_hdr) {
348 // RefPicList0 (8.2.4.2.1) [[1] [2]], where:
349 // [1] shortterm ref pics sorted by descending pic_num,
350 // [2] longterm ref pics by ascending long_term_pic_num.
351 ref_pic_list_p0_.clear();
353 // First get the short ref pics...
354 dpb_.GetShortTermRefPicsAppending(&ref_pic_list_p0_);
355 size_t num_short_refs = ref_pic_list_p0_.size();
357 // and sort them to get [1].
358 std::sort(ref_pic_list_p0_.begin(), ref_pic_list_p0_.end(),
359 PicNumDescCompare());
361 // Now get long term pics and sort them by long_term_pic_num to get [2].
362 dpb_.GetLongTermRefPicsAppending(&ref_pic_list_p0_);
363 std::sort(ref_pic_list_p0_.begin() + num_short_refs, ref_pic_list_p0_.end(),
364 LongTermPicNumAscCompare());
367 struct POCAscCompare {
368 bool operator()(const scoped_refptr<H264Picture>& a,
369 const scoped_refptr<H264Picture>& b) const {
370 return a->pic_order_cnt < b->pic_order_cnt;
374 struct POCDescCompare {
375 bool operator()(const scoped_refptr<H264Picture>& a,
376 const scoped_refptr<H264Picture>& b) const {
377 return a->pic_order_cnt > b->pic_order_cnt;
381 void H264Decoder::ConstructReferencePicListsB(
382 media::H264SliceHeader* slice_hdr) {
383 // RefPicList0 (8.2.4.2.3) [[1] [2] [3]], where:
384 // [1] shortterm ref pics with POC < curr_pic's POC sorted by descending POC,
385 // [2] shortterm ref pics with POC > curr_pic's POC by ascending POC,
386 // [3] longterm ref pics by ascending long_term_pic_num.
387 ref_pic_list_b0_.clear();
388 ref_pic_list_b1_.clear();
389 dpb_.GetShortTermRefPicsAppending(&ref_pic_list_b0_);
390 size_t num_short_refs = ref_pic_list_b0_.size();
392 // First sort ascending, this will put [1] in right place and finish [2].
393 std::sort(ref_pic_list_b0_.begin(), ref_pic_list_b0_.end(), POCAscCompare());
395 // Find first with POC > curr_pic's POC to get first element in [2]...
396 H264Picture::Vector::iterator iter;
397 iter = std::upper_bound(ref_pic_list_b0_.begin(), ref_pic_list_b0_.end(),
398 curr_pic_.get(), POCAscCompare());
400 // and sort [1] descending, thus finishing sequence [1] [2].
401 std::sort(ref_pic_list_b0_.begin(), iter, POCDescCompare());
403 // Now add [3] and sort by ascending long_term_pic_num.
404 dpb_.GetLongTermRefPicsAppending(&ref_pic_list_b0_);
405 std::sort(ref_pic_list_b0_.begin() + num_short_refs, ref_pic_list_b0_.end(),
406 LongTermPicNumAscCompare());
408 // RefPicList1 (8.2.4.2.4) [[1] [2] [3]], where:
409 // [1] shortterm ref pics with POC > curr_pic's POC sorted by ascending POC,
410 // [2] shortterm ref pics with POC < curr_pic's POC by descending POC,
411 // [3] longterm ref pics by ascending long_term_pic_num.
413 dpb_.GetShortTermRefPicsAppending(&ref_pic_list_b1_);
414 num_short_refs = ref_pic_list_b1_.size();
416 // First sort by descending POC.
417 std::sort(ref_pic_list_b1_.begin(), ref_pic_list_b1_.end(), POCDescCompare());
419 // Find first with POC < curr_pic's POC to get first element in [2]...
420 iter = std::upper_bound(ref_pic_list_b1_.begin(), ref_pic_list_b1_.end(),
421 curr_pic_.get(), POCDescCompare());
423 // and sort [1] ascending.
424 std::sort(ref_pic_list_b1_.begin(), iter, POCAscCompare());
426 // Now add [3] and sort by ascending long_term_pic_num
427 dpb_.GetShortTermRefPicsAppending(&ref_pic_list_b1_);
428 std::sort(ref_pic_list_b1_.begin() + num_short_refs, ref_pic_list_b1_.end(),
429 LongTermPicNumAscCompare());
431 // If lists identical, swap first two entries in RefPicList1 (spec 8.2.4.2.3)
432 if (ref_pic_list_b1_.size() > 1 &&
433 std::equal(ref_pic_list_b0_.begin(), ref_pic_list_b0_.end(),
434 ref_pic_list_b1_.begin()))
435 std::swap(ref_pic_list_b1_[0], ref_pic_list_b1_[1]);
438 // See 8.2.4
439 int H264Decoder::PicNumF(const scoped_refptr<H264Picture>& pic) {
440 if (!pic)
441 return -1;
443 if (!pic->long_term)
444 return pic->pic_num;
445 else
446 return max_pic_num_;
449 // See 8.2.4
450 int H264Decoder::LongTermPicNumF(const scoped_refptr<H264Picture>& pic) {
451 if (pic->ref && pic->long_term)
452 return pic->long_term_pic_num;
453 else
454 return 2 * (max_long_term_frame_idx_ + 1);
457 // Shift elements on the |v| starting from |from| to |to|, inclusive,
458 // one position to the right and insert pic at |from|.
459 static void ShiftRightAndInsert(H264Picture::Vector* v,
460 int from,
461 int to,
462 const scoped_refptr<H264Picture>& pic) {
463 // Security checks, do not disable in Debug mode.
464 CHECK(from <= to);
465 CHECK(to <= std::numeric_limits<int>::max() - 2);
466 // Additional checks. Debug mode ok.
467 DCHECK(v);
468 DCHECK(pic);
469 DCHECK((to + 1 == static_cast<int>(v->size())) ||
470 (to + 2 == static_cast<int>(v->size())));
472 v->resize(to + 2);
474 for (int i = to + 1; i > from; --i)
475 (*v)[i] = (*v)[i - 1];
477 (*v)[from] = pic;
480 bool H264Decoder::ModifyReferencePicList(media::H264SliceHeader* slice_hdr,
481 int list,
482 H264Picture::Vector* ref_pic_listx) {
483 bool ref_pic_list_modification_flag_lX;
484 int num_ref_idx_lX_active_minus1;
485 media::H264ModificationOfPicNum* list_mod;
487 // This can process either ref_pic_list0 or ref_pic_list1, depending on
488 // the list argument. Set up pointers to proper list to be processed here.
489 if (list == 0) {
490 ref_pic_list_modification_flag_lX =
491 slice_hdr->ref_pic_list_modification_flag_l0;
492 num_ref_idx_lX_active_minus1 =
493 slice_hdr->num_ref_idx_l0_active_minus1;
494 list_mod = slice_hdr->ref_list_l0_modifications;
495 } else {
496 ref_pic_list_modification_flag_lX =
497 slice_hdr->ref_pic_list_modification_flag_l1;
498 num_ref_idx_lX_active_minus1 =
499 slice_hdr->num_ref_idx_l1_active_minus1;
500 list_mod = slice_hdr->ref_list_l1_modifications;
503 // Resize the list to the size requested in the slice header.
504 // Note that per 8.2.4.2 it's possible for num_ref_idx_lX_active_minus1 to
505 // indicate there should be more ref pics on list than we constructed.
506 // Those superfluous ones should be treated as non-reference and will be
507 // initialized to nullptr, which must be handled by clients.
508 DCHECK_GE(num_ref_idx_lX_active_minus1, 0);
509 ref_pic_listx->resize(num_ref_idx_lX_active_minus1 + 1);
511 if (!ref_pic_list_modification_flag_lX)
512 return true;
514 // Spec 8.2.4.3:
515 // Reorder pictures on the list in a way specified in the stream.
516 int pic_num_lx_pred = curr_pic_->pic_num;
517 int ref_idx_lx = 0;
518 int pic_num_lx_no_wrap;
519 int pic_num_lx;
520 bool done = false;
521 scoped_refptr<H264Picture> pic;
522 for (int i = 0; i < media::H264SliceHeader::kRefListModSize && !done; ++i) {
523 switch (list_mod->modification_of_pic_nums_idc) {
524 case 0:
525 case 1:
526 // Modify short reference picture position.
527 if (list_mod->modification_of_pic_nums_idc == 0) {
528 // Subtract given value from predicted PicNum.
529 pic_num_lx_no_wrap = pic_num_lx_pred -
530 (static_cast<int>(list_mod->abs_diff_pic_num_minus1) + 1);
531 // Wrap around max_pic_num_ if it becomes < 0 as result
532 // of subtraction.
533 if (pic_num_lx_no_wrap < 0)
534 pic_num_lx_no_wrap += max_pic_num_;
535 } else {
536 // Add given value to predicted PicNum.
537 pic_num_lx_no_wrap = pic_num_lx_pred +
538 (static_cast<int>(list_mod->abs_diff_pic_num_minus1) + 1);
539 // Wrap around max_pic_num_ if it becomes >= max_pic_num_ as result
540 // of the addition.
541 if (pic_num_lx_no_wrap >= max_pic_num_)
542 pic_num_lx_no_wrap -= max_pic_num_;
545 // For use in next iteration.
546 pic_num_lx_pred = pic_num_lx_no_wrap;
548 if (pic_num_lx_no_wrap > curr_pic_->pic_num)
549 pic_num_lx = pic_num_lx_no_wrap - max_pic_num_;
550 else
551 pic_num_lx = pic_num_lx_no_wrap;
553 DCHECK_LT(num_ref_idx_lX_active_minus1 + 1,
554 media::H264SliceHeader::kRefListModSize);
555 pic = dpb_.GetShortRefPicByPicNum(pic_num_lx);
556 if (!pic) {
557 DVLOG(1) << "Malformed stream, no pic num " << pic_num_lx;
558 return false;
560 ShiftRightAndInsert(ref_pic_listx, ref_idx_lx,
561 num_ref_idx_lX_active_minus1, pic);
562 ref_idx_lx++;
564 for (int src = ref_idx_lx, dst = ref_idx_lx;
565 src <= num_ref_idx_lX_active_minus1 + 1; ++src) {
566 if (PicNumF((*ref_pic_listx)[src]) != pic_num_lx)
567 (*ref_pic_listx)[dst++] = (*ref_pic_listx)[src];
569 break;
571 case 2:
572 // Modify long term reference picture position.
573 DCHECK_LT(num_ref_idx_lX_active_minus1 + 1,
574 media::H264SliceHeader::kRefListModSize);
575 pic = dpb_.GetLongRefPicByLongTermPicNum(list_mod->long_term_pic_num);
576 if (!pic) {
577 DVLOG(1) << "Malformed stream, no pic num "
578 << list_mod->long_term_pic_num;
579 return false;
581 ShiftRightAndInsert(ref_pic_listx, ref_idx_lx,
582 num_ref_idx_lX_active_minus1, pic);
583 ref_idx_lx++;
585 for (int src = ref_idx_lx, dst = ref_idx_lx;
586 src <= num_ref_idx_lX_active_minus1 + 1; ++src) {
587 if (LongTermPicNumF((*ref_pic_listx)[src]) !=
588 static_cast<int>(list_mod->long_term_pic_num))
589 (*ref_pic_listx)[dst++] = (*ref_pic_listx)[src];
591 break;
593 case 3:
594 // End of modification list.
595 done = true;
596 break;
598 default:
599 // May be recoverable.
600 DVLOG(1) << "Invalid modification_of_pic_nums_idc="
601 << list_mod->modification_of_pic_nums_idc
602 << " in position " << i;
603 break;
606 ++list_mod;
609 // Per NOTE 2 in 8.2.4.3.2, the ref_pic_listx size in the above loop is
610 // temporarily made one element longer than the required final list.
611 // Resize the list back to its required size.
612 ref_pic_listx->resize(num_ref_idx_lX_active_minus1 + 1);
614 return true;
617 void H264Decoder::OutputPic(scoped_refptr<H264Picture> pic) {
618 DCHECK(!pic->outputted);
619 pic->outputted = true;
621 DVLOG_IF(1, pic->pic_order_cnt < last_output_poc_)
622 << "Outputting out of order, likely a broken stream";
623 last_output_poc_ = pic->pic_order_cnt;
625 DVLOG(4) << "Posting output task for POC: " << pic->pic_order_cnt;
626 accelerator_->OutputPicture(pic);
629 void H264Decoder::ClearDPB() {
630 // Clear DPB contents, marking the pictures as unused first.
631 dpb_.Clear();
632 last_output_poc_ = std::numeric_limits<int>::min();
635 bool H264Decoder::OutputAllRemainingPics() {
636 // Output all pictures that are waiting to be outputted.
637 FinishPrevFrameIfPresent();
638 H264Picture::Vector to_output;
639 dpb_.GetNotOutputtedPicsAppending(&to_output);
640 // Sort them by ascending POC to output in order.
641 std::sort(to_output.begin(), to_output.end(), POCAscCompare());
643 for (auto& pic : to_output)
644 OutputPic(pic);
646 return true;
649 bool H264Decoder::Flush() {
650 DVLOG(2) << "Decoder flush";
652 if (!OutputAllRemainingPics())
653 return false;
655 ClearDPB();
656 DVLOG(2) << "Decoder flush finished";
657 return true;
660 bool H264Decoder::StartNewFrame(media::H264SliceHeader* slice_hdr) {
661 // TODO posciak: add handling of max_num_ref_frames per spec.
662 CHECK(curr_pic_.get());
664 if (!InitCurrPicture(slice_hdr))
665 return false;
667 DCHECK_GT(max_frame_num_, 0);
669 UpdatePicNums();
670 DCHECK(slice_hdr);
671 PrepareRefPicLists(slice_hdr);
673 const media::H264PPS* pps = parser_.GetPPS(curr_pps_id_);
674 DCHECK(pps);
675 const media::H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id);
676 DCHECK(sps);
678 if (!accelerator_->SubmitFrameMetadata(sps, pps, dpb_, ref_pic_list_p0_,
679 ref_pic_list_b0_, ref_pic_list_b1_,
680 curr_pic_.get()))
681 return false;
683 return true;
686 bool H264Decoder::HandleMemoryManagementOps() {
687 // 8.2.5.4
688 for (unsigned int i = 0; i < arraysize(curr_pic_->ref_pic_marking); ++i) {
689 // Code below does not support interlaced stream (per-field pictures).
690 media::H264DecRefPicMarking* ref_pic_marking =
691 &curr_pic_->ref_pic_marking[i];
692 scoped_refptr<H264Picture> to_mark;
693 int pic_num_x;
695 switch (ref_pic_marking->memory_mgmnt_control_operation) {
696 case 0:
697 // Normal end of operations' specification.
698 return true;
700 case 1:
701 // Mark a short term reference picture as unused so it can be removed
702 // if outputted.
703 pic_num_x = curr_pic_->pic_num -
704 (ref_pic_marking->difference_of_pic_nums_minus1 + 1);
705 to_mark = dpb_.GetShortRefPicByPicNum(pic_num_x);
706 if (to_mark) {
707 to_mark->ref = false;
708 } else {
709 DVLOG(1) << "Invalid short ref pic num to unmark";
710 return false;
712 break;
714 case 2:
715 // Mark a long term reference picture as unused so it can be removed
716 // if outputted.
717 to_mark = dpb_.GetLongRefPicByLongTermPicNum(
718 ref_pic_marking->long_term_pic_num);
719 if (to_mark) {
720 to_mark->ref = false;
721 } else {
722 DVLOG(1) << "Invalid long term ref pic num to unmark";
723 return false;
725 break;
727 case 3:
728 // Mark a short term reference picture as long term reference.
729 pic_num_x = curr_pic_->pic_num -
730 (ref_pic_marking->difference_of_pic_nums_minus1 + 1);
731 to_mark = dpb_.GetShortRefPicByPicNum(pic_num_x);
732 if (to_mark) {
733 DCHECK(to_mark->ref && !to_mark->long_term);
734 to_mark->long_term = true;
735 to_mark->long_term_frame_idx = ref_pic_marking->long_term_frame_idx;
736 } else {
737 DVLOG(1) << "Invalid short term ref pic num to mark as long ref";
738 return false;
740 break;
742 case 4: {
743 // Unmark all reference pictures with long_term_frame_idx over new max.
744 max_long_term_frame_idx_ =
745 ref_pic_marking->max_long_term_frame_idx_plus1 - 1;
746 H264Picture::Vector long_terms;
747 dpb_.GetLongTermRefPicsAppending(&long_terms);
748 for (size_t i = 0; i < long_terms.size(); ++i) {
749 scoped_refptr<H264Picture>& pic = long_terms[i];
750 DCHECK(pic->ref && pic->long_term);
751 // Ok to cast, max_long_term_frame_idx is much smaller than 16bit.
752 if (pic->long_term_frame_idx >
753 static_cast<int>(max_long_term_frame_idx_))
754 pic->ref = false;
756 break;
759 case 5:
760 // Unmark all reference pictures.
761 dpb_.MarkAllUnusedForRef();
762 max_long_term_frame_idx_ = -1;
763 curr_pic_->mem_mgmt_5 = true;
764 break;
766 case 6: {
767 // Replace long term reference pictures with current picture.
768 // First unmark if any existing with this long_term_frame_idx...
769 H264Picture::Vector long_terms;
770 dpb_.GetLongTermRefPicsAppending(&long_terms);
771 for (size_t i = 0; i < long_terms.size(); ++i) {
772 scoped_refptr<H264Picture>& pic = long_terms[i];
773 DCHECK(pic->ref && pic->long_term);
774 // Ok to cast, long_term_frame_idx is much smaller than 16bit.
775 if (pic->long_term_frame_idx ==
776 static_cast<int>(ref_pic_marking->long_term_frame_idx))
777 pic->ref = false;
780 // and mark the current one instead.
781 curr_pic_->ref = true;
782 curr_pic_->long_term = true;
783 curr_pic_->long_term_frame_idx = ref_pic_marking->long_term_frame_idx;
784 break;
787 default:
788 // Would indicate a bug in parser.
789 NOTREACHED();
793 return true;
796 // This method ensures that DPB does not overflow, either by removing
797 // reference pictures as specified in the stream, or using a sliding window
798 // procedure to remove the oldest one.
799 // It also performs marking and unmarking pictures as reference.
800 // See spac 8.2.5.1.
801 void H264Decoder::ReferencePictureMarking() {
802 if (curr_pic_->idr) {
803 // If current picture is an IDR, all reference pictures are unmarked.
804 dpb_.MarkAllUnusedForRef();
806 if (curr_pic_->long_term_reference_flag) {
807 curr_pic_->long_term = true;
808 curr_pic_->long_term_frame_idx = 0;
809 max_long_term_frame_idx_ = 0;
810 } else {
811 curr_pic_->long_term = false;
812 max_long_term_frame_idx_ = -1;
814 } else {
815 if (!curr_pic_->adaptive_ref_pic_marking_mode_flag) {
816 // If non-IDR, and the stream does not indicate what we should do to
817 // ensure DPB doesn't overflow, discard oldest picture.
818 // See spec 8.2.5.3.
819 if (curr_pic_->field == H264Picture::FIELD_NONE) {
820 DCHECK_LE(
821 dpb_.CountRefPics(),
822 std::max<int>(parser_.GetSPS(curr_sps_id_)->max_num_ref_frames, 1));
823 if (dpb_.CountRefPics() ==
824 std::max<int>(parser_.GetSPS(curr_sps_id_)->max_num_ref_frames,
825 1)) {
826 // Max number of reference pics reached,
827 // need to remove one of the short term ones.
828 // Find smallest frame_num_wrap short reference picture and mark
829 // it as unused.
830 scoped_refptr<H264Picture> to_unmark =
831 dpb_.GetLowestFrameNumWrapShortRefPic();
832 if (to_unmark == NULL) {
833 DVLOG(1) << "Couldn't find a short ref picture to unmark";
834 return;
836 to_unmark->ref = false;
838 } else {
839 // Shouldn't get here.
840 DVLOG(1) << "Interlaced video not supported.";
842 } else {
843 // Stream has instructions how to discard pictures from DPB and how
844 // to mark/unmark existing reference pictures. Do it.
845 // Spec 8.2.5.4.
846 if (curr_pic_->field == H264Picture::FIELD_NONE) {
847 HandleMemoryManagementOps();
848 } else {
849 // Shouldn't get here.
850 DVLOG(1) << "Interlaced video not supported.";
856 bool H264Decoder::FinishPicture() {
857 DCHECK(curr_pic_.get());
859 // Finish processing previous picture.
860 // Start by storing previous reference picture data for later use,
861 // if picture being finished is a reference picture.
862 if (curr_pic_->ref) {
863 ReferencePictureMarking();
864 prev_ref_has_memmgmnt5_ = curr_pic_->mem_mgmt_5;
865 prev_ref_top_field_order_cnt_ = curr_pic_->top_field_order_cnt;
866 prev_ref_pic_order_cnt_msb_ = curr_pic_->pic_order_cnt_msb;
867 prev_ref_pic_order_cnt_lsb_ = curr_pic_->pic_order_cnt_lsb;
868 prev_ref_field_ = curr_pic_->field;
870 prev_has_memmgmnt5_ = curr_pic_->mem_mgmt_5;
871 prev_frame_num_offset_ = curr_pic_->frame_num_offset;
873 // Remove unused (for reference or later output) pictures from DPB, marking
874 // them as such.
875 dpb_.DeleteUnused();
877 DVLOG(4) << "Finishing picture, entries in DPB: " << dpb_.size();
879 // Whatever happens below, curr_pic_ will stop managing the pointer to the
880 // picture after this. The ownership will either be transferred to DPB, if
881 // the image is still needed (for output and/or reference), or the memory
882 // will be released if we manage to output it here without having to store
883 // it for future reference.
884 scoped_refptr<H264Picture> pic = curr_pic_;
885 curr_pic_ = nullptr;
887 // Get all pictures that haven't been outputted yet.
888 H264Picture::Vector not_outputted;
889 dpb_.GetNotOutputtedPicsAppending(&not_outputted);
890 // Include the one we've just decoded.
891 not_outputted.push_back(pic);
893 // Sort in output order.
894 std::sort(not_outputted.begin(), not_outputted.end(), POCAscCompare());
896 // Try to output as many pictures as we can. A picture can be output,
897 // if the number of decoded and not yet outputted pictures that would remain
898 // in DPB afterwards would at least be equal to max_num_reorder_frames.
899 // If the outputted picture is not a reference picture, it doesn't have
900 // to remain in the DPB and can be removed.
901 H264Picture::Vector::iterator output_candidate = not_outputted.begin();
902 size_t num_remaining = not_outputted.size();
903 while (num_remaining > max_num_reorder_frames_ ||
904 // If the condition below is used, this is an invalid stream. We should
905 // not be forced to output beyond max_num_reorder_frames in order to
906 // make room in DPB to store the current picture (if we need to do so).
907 // However, if this happens, ignore max_num_reorder_frames and try
908 // to output more. This may cause out-of-order output, but is not
909 // fatal, and better than failing instead.
910 ((dpb_.IsFull() && (!pic->outputted || pic->ref)) && num_remaining)) {
911 DVLOG_IF(1, num_remaining <= max_num_reorder_frames_)
912 << "Invalid stream: max_num_reorder_frames not preserved";
914 OutputPic(*output_candidate);
916 if (!(*output_candidate)->ref) {
917 // Current picture hasn't been inserted into DPB yet, so don't remove it
918 // if we managed to output it immediately.
919 int outputted_poc = (*output_candidate)->pic_order_cnt;
920 if (outputted_poc != pic->pic_order_cnt)
921 dpb_.DeleteByPOC(outputted_poc);
924 ++output_candidate;
925 --num_remaining;
928 // If we haven't managed to output the picture that we just decoded, or if
929 // it's a reference picture, we have to store it in DPB.
930 if (!pic->outputted || pic->ref) {
931 if (dpb_.IsFull()) {
932 // If we haven't managed to output anything to free up space in DPB
933 // to store this picture, it's an error in the stream.
934 DVLOG(1) << "Could not free up space in DPB!";
935 return false;
938 dpb_.StorePic(pic);
941 return true;
944 static int LevelToMaxDpbMbs(int level) {
945 // See table A-1 in spec.
946 switch (level) {
947 case 10: return 396;
948 case 11: return 900;
949 case 12: // fallthrough
950 case 13: // fallthrough
951 case 20: return 2376;
952 case 21: return 4752;
953 case 22: // fallthrough
954 case 30: return 8100;
955 case 31: return 18000;
956 case 32: return 20480;
957 case 40: // fallthrough
958 case 41: return 32768;
959 case 42: return 34816;
960 case 50: return 110400;
961 case 51: // fallthrough
962 case 52: return 184320;
963 default:
964 DVLOG(1) << "Invalid codec level (" << level << ")";
965 return 0;
969 bool H264Decoder::UpdateMaxNumReorderFrames(const media::H264SPS* sps) {
970 if (sps->vui_parameters_present_flag && sps->bitstream_restriction_flag) {
971 max_num_reorder_frames_ =
972 base::checked_cast<size_t>(sps->max_num_reorder_frames);
973 if (max_num_reorder_frames_ > dpb_.max_num_pics()) {
974 DVLOG(1)
975 << "max_num_reorder_frames present, but larger than MaxDpbFrames ("
976 << max_num_reorder_frames_ << " > " << dpb_.max_num_pics() << ")";
977 max_num_reorder_frames_ = 0;
978 return false;
980 return true;
983 // max_num_reorder_frames not present, infer from profile/constraints
984 // (see VUI semantics in spec).
985 if (sps->constraint_set3_flag) {
986 switch (sps->profile_idc) {
987 case 44:
988 case 86:
989 case 100:
990 case 110:
991 case 122:
992 case 244:
993 max_num_reorder_frames_ = 0;
994 break;
995 default:
996 max_num_reorder_frames_ = dpb_.max_num_pics();
997 break;
999 } else {
1000 max_num_reorder_frames_ = dpb_.max_num_pics();
1003 return true;
1006 bool H264Decoder::ProcessSPS(int sps_id, bool* need_new_buffers) {
1007 const media::H264SPS* sps = parser_.GetSPS(sps_id);
1008 DCHECK(sps);
1009 DVLOG(4) << "Processing SPS";
1011 *need_new_buffers = false;
1013 if (sps->frame_mbs_only_flag == 0) {
1014 DVLOG(1) << "frame_mbs_only_flag != 1 not supported";
1015 return false;
1018 if (sps->gaps_in_frame_num_value_allowed_flag) {
1019 DVLOG(1) << "Gaps in frame numbers not supported";
1020 return false;
1023 curr_sps_id_ = sps->seq_parameter_set_id;
1025 // Calculate picture height/width in macroblocks and pixels
1026 // (spec 7.4.2.1.1, 7.4.3).
1027 int width_mb = sps->pic_width_in_mbs_minus1 + 1;
1028 int height_mb = (2 - sps->frame_mbs_only_flag) *
1029 (sps->pic_height_in_map_units_minus1 + 1);
1031 gfx::Size new_pic_size(16 * width_mb, 16 * height_mb);
1032 if (new_pic_size.IsEmpty()) {
1033 DVLOG(1) << "Invalid picture size: " << new_pic_size.ToString();
1034 return false;
1037 if (!pic_size_.IsEmpty() && new_pic_size == pic_size_) {
1038 // Already have surfaces and this SPS keeps the same resolution,
1039 // no need to request a new set.
1040 return true;
1043 pic_size_ = new_pic_size;
1044 DVLOG(1) << "New picture size: " << pic_size_.ToString();
1046 max_pic_order_cnt_lsb_ = 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
1047 max_frame_num_ = 1 << (sps->log2_max_frame_num_minus4 + 4);
1049 int level = sps->level_idc;
1050 int max_dpb_mbs = LevelToMaxDpbMbs(level);
1051 if (max_dpb_mbs == 0)
1052 return false;
1054 size_t max_dpb_size = std::min(max_dpb_mbs / (width_mb * height_mb),
1055 static_cast<int>(H264DPB::kDPBMaxSize));
1056 DVLOG(1) << "Codec level: " << level << ", DPB size: " << max_dpb_size;
1057 if (max_dpb_size == 0) {
1058 DVLOG(1) << "Invalid DPB Size";
1059 return false;
1062 dpb_.set_max_num_pics(max_dpb_size);
1064 if (!UpdateMaxNumReorderFrames(sps))
1065 return false;
1066 DVLOG(1) << "max_num_reorder_frames: " << max_num_reorder_frames_;
1068 *need_new_buffers = true;
1069 return true;
1072 bool H264Decoder::ProcessPPS(int pps_id) {
1073 const media::H264PPS* pps = parser_.GetPPS(pps_id);
1074 DCHECK(pps);
1076 curr_pps_id_ = pps->pic_parameter_set_id;
1078 return true;
1081 bool H264Decoder::FinishPrevFrameIfPresent() {
1082 // If we already have a frame waiting to be decoded, decode it and finish.
1083 if (curr_pic_ != NULL) {
1084 if (!DecodePicture())
1085 return false;
1086 return FinishPicture();
1089 return true;
1092 bool H264Decoder::PreprocessSlice(media::H264SliceHeader* slice_hdr) {
1093 prev_frame_num_ = frame_num_;
1094 frame_num_ = slice_hdr->frame_num;
1096 if (prev_frame_num_ > 0 && prev_frame_num_ < frame_num_ - 1) {
1097 DVLOG(1) << "Gap in frame_num!";
1098 return false;
1101 if (slice_hdr->field_pic_flag == 0)
1102 max_pic_num_ = max_frame_num_;
1103 else
1104 max_pic_num_ = 2 * max_frame_num_;
1106 // TODO posciak: switch to new picture detection per 7.4.1.2.4.
1107 if (curr_pic_ != NULL && slice_hdr->first_mb_in_slice != 0) {
1108 // More slice data of the current picture.
1109 return true;
1110 } else {
1111 // A new frame, so first finish the previous one before processing it...
1112 if (!FinishPrevFrameIfPresent())
1113 return false;
1116 // If the new frame is an IDR, output what's left to output and clear DPB
1117 if (slice_hdr->idr_pic_flag) {
1118 // (unless we are explicitly instructed not to do so).
1119 if (!slice_hdr->no_output_of_prior_pics_flag) {
1120 // Output DPB contents.
1121 if (!Flush())
1122 return false;
1124 dpb_.Clear();
1125 last_output_poc_ = std::numeric_limits<int>::min();
1128 return true;
1131 bool H264Decoder::ProcessSlice(media::H264SliceHeader* slice_hdr) {
1132 DCHECK(curr_pic_.get());
1133 H264Picture::Vector ref_pic_list0, ref_pic_list1;
1135 if (!ModifyReferencePicLists(slice_hdr, &ref_pic_list0, &ref_pic_list1))
1136 return false;
1138 const media::H264PPS* pps = parser_.GetPPS(slice_hdr->pic_parameter_set_id);
1139 DCHECK(pps);
1141 if (!accelerator_->SubmitSlice(pps, slice_hdr, ref_pic_list0, ref_pic_list1,
1142 curr_pic_.get(), slice_hdr->nalu_data,
1143 slice_hdr->nalu_size))
1144 return false;
1146 curr_slice_hdr_.reset();
1147 return true;
1150 #define SET_ERROR_AND_RETURN() \
1151 do { \
1152 DVLOG(1) << "Error during decode"; \
1153 state_ = kError; \
1154 return H264Decoder::kDecodeError; \
1155 } while (0)
1157 void H264Decoder::SetStream(const uint8_t* ptr, size_t size) {
1158 DCHECK(ptr);
1159 DCHECK(size);
1161 DVLOG(4) << "New input stream at: " << (void*)ptr << " size: " << size;
1162 parser_.SetStream(ptr, size);
1165 H264Decoder::DecodeResult H264Decoder::Decode() {
1166 DCHECK_NE(state_, kError);
1168 while (1) {
1169 media::H264Parser::Result par_res;
1171 if (!curr_nalu_) {
1172 curr_nalu_.reset(new media::H264NALU());
1173 par_res = parser_.AdvanceToNextNALU(curr_nalu_.get());
1174 if (par_res == media::H264Parser::kEOStream)
1175 return kRanOutOfStreamData;
1176 else if (par_res != media::H264Parser::kOk)
1177 SET_ERROR_AND_RETURN();
1180 DVLOG(4) << "NALU found: " << static_cast<int>(curr_nalu_->nal_unit_type);
1182 switch (curr_nalu_->nal_unit_type) {
1183 case media::H264NALU::kNonIDRSlice:
1184 // We can't resume from a non-IDR slice.
1185 if (state_ != kDecoding)
1186 break;
1187 // else fallthrough
1188 case media::H264NALU::kIDRSlice: {
1189 // TODO(posciak): the IDR may require an SPS that we don't have
1190 // available. For now we'd fail if that happens, but ideally we'd like
1191 // to keep going until the next SPS in the stream.
1192 if (state_ == kNeedStreamMetadata) {
1193 // We need an SPS, skip this IDR and keep looking.
1194 break;
1197 // If after reset, we should be able to recover from an IDR.
1198 if (!curr_slice_hdr_) {
1199 curr_slice_hdr_.reset(new media::H264SliceHeader());
1200 par_res =
1201 parser_.ParseSliceHeader(*curr_nalu_, curr_slice_hdr_.get());
1202 if (par_res != media::H264Parser::kOk)
1203 SET_ERROR_AND_RETURN();
1205 if (!PreprocessSlice(curr_slice_hdr_.get()))
1206 SET_ERROR_AND_RETURN();
1209 if (!curr_pic_) {
1210 // New picture/finished previous one, try to start a new one
1211 // or tell the client we need more surfaces.
1212 curr_pic_ = accelerator_->CreateH264Picture();
1213 if (!curr_pic_)
1214 return kRanOutOfSurfaces;
1216 if (!StartNewFrame(curr_slice_hdr_.get()))
1217 SET_ERROR_AND_RETURN();
1220 if (!ProcessSlice(curr_slice_hdr_.get()))
1221 SET_ERROR_AND_RETURN();
1223 state_ = kDecoding;
1224 break;
1227 case media::H264NALU::kSPS: {
1228 int sps_id;
1230 if (!FinishPrevFrameIfPresent())
1231 SET_ERROR_AND_RETURN();
1233 par_res = parser_.ParseSPS(&sps_id);
1234 if (par_res != media::H264Parser::kOk)
1235 SET_ERROR_AND_RETURN();
1237 bool need_new_buffers = false;
1238 if (!ProcessSPS(sps_id, &need_new_buffers))
1239 SET_ERROR_AND_RETURN();
1241 state_ = kDecoding;
1243 if (need_new_buffers) {
1244 if (!Flush())
1245 return kDecodeError;
1247 curr_pic_ = nullptr;
1248 curr_nalu_ = nullptr;
1249 ref_pic_list_p0_.clear();
1250 ref_pic_list_b0_.clear();
1251 ref_pic_list_b1_.clear();
1253 return kAllocateNewSurfaces;
1255 break;
1258 case media::H264NALU::kPPS: {
1259 if (state_ != kDecoding)
1260 break;
1262 int pps_id;
1264 if (!FinishPrevFrameIfPresent())
1265 SET_ERROR_AND_RETURN();
1267 par_res = parser_.ParsePPS(&pps_id);
1268 if (par_res != media::H264Parser::kOk)
1269 SET_ERROR_AND_RETURN();
1271 if (!ProcessPPS(pps_id))
1272 SET_ERROR_AND_RETURN();
1273 break;
1276 default:
1277 DVLOG(4) << "Skipping NALU type: " << curr_nalu_->nal_unit_type;
1278 break;
1281 DVLOG(4) << "Dropping nalu";
1282 curr_nalu_.reset();
1286 gfx::Size H264Decoder::GetPicSize() const {
1287 return pic_size_;
1290 size_t H264Decoder::GetRequiredNumOfPictures() const {
1291 return dpb_.max_num_pics() + kPicsInPipeline;
1294 } // namespace content