[Android WebView] Fix webview perf bot switchover to use org.chromium.webview_shell...
[chromium-blink-merge.git] / content / common / gpu / media / h264_decoder.cc
blob9953ff21a593d28c9508f51715091f8b10f81203
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());
366 // Cut off if we have more than requested in slice header.
367 ref_pic_list_p0_.resize(slice_hdr->num_ref_idx_l0_active_minus1 + 1);
370 struct POCAscCompare {
371 bool operator()(const scoped_refptr<H264Picture>& a,
372 const scoped_refptr<H264Picture>& b) const {
373 return a->pic_order_cnt < b->pic_order_cnt;
377 struct POCDescCompare {
378 bool operator()(const scoped_refptr<H264Picture>& a,
379 const scoped_refptr<H264Picture>& b) const {
380 return a->pic_order_cnt > b->pic_order_cnt;
384 void H264Decoder::ConstructReferencePicListsB(
385 media::H264SliceHeader* slice_hdr) {
386 // RefPicList0 (8.2.4.2.3) [[1] [2] [3]], where:
387 // [1] shortterm ref pics with POC < curr_pic's POC sorted by descending POC,
388 // [2] shortterm ref pics with POC > curr_pic's POC by ascending POC,
389 // [3] longterm ref pics by ascending long_term_pic_num.
390 ref_pic_list_b0_.clear();
391 ref_pic_list_b1_.clear();
392 dpb_.GetShortTermRefPicsAppending(&ref_pic_list_b0_);
393 size_t num_short_refs = ref_pic_list_b0_.size();
395 // First sort ascending, this will put [1] in right place and finish [2].
396 std::sort(ref_pic_list_b0_.begin(), ref_pic_list_b0_.end(), POCAscCompare());
398 // Find first with POC > curr_pic's POC to get first element in [2]...
399 H264Picture::Vector::iterator iter;
400 iter = std::upper_bound(ref_pic_list_b0_.begin(), ref_pic_list_b0_.end(),
401 curr_pic_.get(), POCAscCompare());
403 // and sort [1] descending, thus finishing sequence [1] [2].
404 std::sort(ref_pic_list_b0_.begin(), iter, POCDescCompare());
406 // Now add [3] and sort by ascending long_term_pic_num.
407 dpb_.GetLongTermRefPicsAppending(&ref_pic_list_b0_);
408 std::sort(ref_pic_list_b0_.begin() + num_short_refs, ref_pic_list_b0_.end(),
409 LongTermPicNumAscCompare());
411 // RefPicList1 (8.2.4.2.4) [[1] [2] [3]], where:
412 // [1] shortterm ref pics with POC > curr_pic's POC sorted by ascending POC,
413 // [2] shortterm ref pics with POC < curr_pic's POC by descending POC,
414 // [3] longterm ref pics by ascending long_term_pic_num.
416 dpb_.GetShortTermRefPicsAppending(&ref_pic_list_b1_);
417 num_short_refs = ref_pic_list_b1_.size();
419 // First sort by descending POC.
420 std::sort(ref_pic_list_b1_.begin(), ref_pic_list_b1_.end(), POCDescCompare());
422 // Find first with POC < curr_pic's POC to get first element in [2]...
423 iter = std::upper_bound(ref_pic_list_b1_.begin(), ref_pic_list_b1_.end(),
424 curr_pic_.get(), POCDescCompare());
426 // and sort [1] ascending.
427 std::sort(ref_pic_list_b1_.begin(), iter, POCAscCompare());
429 // Now add [3] and sort by ascending long_term_pic_num
430 dpb_.GetShortTermRefPicsAppending(&ref_pic_list_b1_);
431 std::sort(ref_pic_list_b1_.begin() + num_short_refs, ref_pic_list_b1_.end(),
432 LongTermPicNumAscCompare());
434 // If lists identical, swap first two entries in RefPicList1 (spec 8.2.4.2.3)
435 if (ref_pic_list_b1_.size() > 1 &&
436 std::equal(ref_pic_list_b0_.begin(), ref_pic_list_b0_.end(),
437 ref_pic_list_b1_.begin()))
438 std::swap(ref_pic_list_b1_[0], ref_pic_list_b1_[1]);
440 // Per 8.2.4.2 it's possible for num_ref_idx_lX_active_minus1 to indicate
441 // there should be more ref pics on list than we constructed.
442 // Those superfluous ones should be treated as non-reference.
443 ref_pic_list_b0_.resize(slice_hdr->num_ref_idx_l0_active_minus1 + 1);
444 ref_pic_list_b1_.resize(slice_hdr->num_ref_idx_l1_active_minus1 + 1);
447 // See 8.2.4
448 int H264Decoder::PicNumF(const scoped_refptr<H264Picture>& pic) {
449 if (!pic)
450 return -1;
452 if (!pic->long_term)
453 return pic->pic_num;
454 else
455 return max_pic_num_;
458 // See 8.2.4
459 int H264Decoder::LongTermPicNumF(const scoped_refptr<H264Picture>& pic) {
460 if (pic->ref && pic->long_term)
461 return pic->long_term_pic_num;
462 else
463 return 2 * (max_long_term_frame_idx_ + 1);
466 // Shift elements on the |v| starting from |from| to |to|, inclusive,
467 // one position to the right and insert pic at |from|.
468 static void ShiftRightAndInsert(H264Picture::Vector* v,
469 int from,
470 int to,
471 const scoped_refptr<H264Picture>& pic) {
472 // Security checks, do not disable in Debug mode.
473 CHECK(from <= to);
474 CHECK(to <= std::numeric_limits<int>::max() - 2);
475 // Additional checks. Debug mode ok.
476 DCHECK(v);
477 DCHECK(pic);
478 DCHECK((to + 1 == static_cast<int>(v->size())) ||
479 (to + 2 == static_cast<int>(v->size())));
481 v->resize(to + 2);
483 for (int i = to + 1; i > from; --i)
484 (*v)[i] = (*v)[i - 1];
486 (*v)[from] = pic;
489 bool H264Decoder::ModifyReferencePicList(media::H264SliceHeader* slice_hdr,
490 int list,
491 H264Picture::Vector* ref_pic_listx) {
492 int num_ref_idx_lX_active_minus1;
493 media::H264ModificationOfPicNum* list_mod;
495 // This can process either ref_pic_list0 or ref_pic_list1, depending on
496 // the list argument. Set up pointers to proper list to be processed here.
497 if (list == 0) {
498 if (!slice_hdr->ref_pic_list_modification_flag_l0)
499 return true;
501 list_mod = slice_hdr->ref_list_l0_modifications;
502 } else {
503 if (!slice_hdr->ref_pic_list_modification_flag_l1)
504 return true;
506 list_mod = slice_hdr->ref_list_l1_modifications;
509 num_ref_idx_lX_active_minus1 = ref_pic_listx->size() - 1;
510 DCHECK_GE(num_ref_idx_lX_active_minus1, 0);
512 // Spec 8.2.4.3:
513 // Reorder pictures on the list in a way specified in the stream.
514 int pic_num_lx_pred = curr_pic_->pic_num;
515 int ref_idx_lx = 0;
516 int pic_num_lx_no_wrap;
517 int pic_num_lx;
518 bool done = false;
519 scoped_refptr<H264Picture> pic;
520 for (int i = 0; i < media::H264SliceHeader::kRefListModSize && !done; ++i) {
521 switch (list_mod->modification_of_pic_nums_idc) {
522 case 0:
523 case 1:
524 // Modify short reference picture position.
525 if (list_mod->modification_of_pic_nums_idc == 0) {
526 // Subtract given value from predicted PicNum.
527 pic_num_lx_no_wrap = pic_num_lx_pred -
528 (static_cast<int>(list_mod->abs_diff_pic_num_minus1) + 1);
529 // Wrap around max_pic_num_ if it becomes < 0 as result
530 // of subtraction.
531 if (pic_num_lx_no_wrap < 0)
532 pic_num_lx_no_wrap += max_pic_num_;
533 } else {
534 // Add given value to predicted PicNum.
535 pic_num_lx_no_wrap = pic_num_lx_pred +
536 (static_cast<int>(list_mod->abs_diff_pic_num_minus1) + 1);
537 // Wrap around max_pic_num_ if it becomes >= max_pic_num_ as result
538 // of the addition.
539 if (pic_num_lx_no_wrap >= max_pic_num_)
540 pic_num_lx_no_wrap -= max_pic_num_;
543 // For use in next iteration.
544 pic_num_lx_pred = pic_num_lx_no_wrap;
546 if (pic_num_lx_no_wrap > curr_pic_->pic_num)
547 pic_num_lx = pic_num_lx_no_wrap - max_pic_num_;
548 else
549 pic_num_lx = pic_num_lx_no_wrap;
551 DCHECK_LT(num_ref_idx_lX_active_minus1 + 1,
552 media::H264SliceHeader::kRefListModSize);
553 pic = dpb_.GetShortRefPicByPicNum(pic_num_lx);
554 if (!pic) {
555 DVLOG(1) << "Malformed stream, no pic num " << pic_num_lx;
556 return false;
558 ShiftRightAndInsert(ref_pic_listx, ref_idx_lx,
559 num_ref_idx_lX_active_minus1, pic);
560 ref_idx_lx++;
562 for (int src = ref_idx_lx, dst = ref_idx_lx;
563 src <= num_ref_idx_lX_active_minus1 + 1; ++src) {
564 if (PicNumF((*ref_pic_listx)[src]) != pic_num_lx)
565 (*ref_pic_listx)[dst++] = (*ref_pic_listx)[src];
567 break;
569 case 2:
570 // Modify long term reference picture position.
571 DCHECK_LT(num_ref_idx_lX_active_minus1 + 1,
572 media::H264SliceHeader::kRefListModSize);
573 pic = dpb_.GetLongRefPicByLongTermPicNum(list_mod->long_term_pic_num);
574 if (!pic) {
575 DVLOG(1) << "Malformed stream, no pic num "
576 << list_mod->long_term_pic_num;
577 return false;
579 ShiftRightAndInsert(ref_pic_listx, ref_idx_lx,
580 num_ref_idx_lX_active_minus1, pic);
581 ref_idx_lx++;
583 for (int src = ref_idx_lx, dst = ref_idx_lx;
584 src <= num_ref_idx_lX_active_minus1 + 1; ++src) {
585 if (LongTermPicNumF((*ref_pic_listx)[src]) !=
586 static_cast<int>(list_mod->long_term_pic_num))
587 (*ref_pic_listx)[dst++] = (*ref_pic_listx)[src];
589 break;
591 case 3:
592 // End of modification list.
593 done = true;
594 break;
596 default:
597 // May be recoverable.
598 DVLOG(1) << "Invalid modification_of_pic_nums_idc="
599 << list_mod->modification_of_pic_nums_idc
600 << " in position " << i;
601 break;
604 ++list_mod;
607 // Per NOTE 2 in 8.2.4.3.2, the ref_pic_listx size in the above loop is
608 // temporarily made one element longer than the required final list.
609 // Resize the list back to its required size.
610 ref_pic_listx->resize(num_ref_idx_lX_active_minus1 + 1);
612 return true;
615 void H264Decoder::OutputPic(scoped_refptr<H264Picture> pic) {
616 DCHECK(!pic->outputted);
617 pic->outputted = true;
619 DVLOG_IF(1, pic->pic_order_cnt < last_output_poc_)
620 << "Outputting out of order, likely a broken stream";
621 last_output_poc_ = pic->pic_order_cnt;
623 DVLOG(4) << "Posting output task for POC: " << pic->pic_order_cnt;
624 accelerator_->OutputPicture(pic);
627 void H264Decoder::ClearDPB() {
628 // Clear DPB contents, marking the pictures as unused first.
629 dpb_.Clear();
630 last_output_poc_ = std::numeric_limits<int>::min();
633 bool H264Decoder::OutputAllRemainingPics() {
634 // Output all pictures that are waiting to be outputted.
635 FinishPrevFrameIfPresent();
636 H264Picture::Vector to_output;
637 dpb_.GetNotOutputtedPicsAppending(&to_output);
638 // Sort them by ascending POC to output in order.
639 std::sort(to_output.begin(), to_output.end(), POCAscCompare());
641 for (auto& pic : to_output)
642 OutputPic(pic);
644 return true;
647 bool H264Decoder::Flush() {
648 DVLOG(2) << "Decoder flush";
650 if (!OutputAllRemainingPics())
651 return false;
653 ClearDPB();
654 DVLOG(2) << "Decoder flush finished";
655 return true;
658 bool H264Decoder::StartNewFrame(media::H264SliceHeader* slice_hdr) {
659 // TODO posciak: add handling of max_num_ref_frames per spec.
660 CHECK(curr_pic_.get());
662 if (!InitCurrPicture(slice_hdr))
663 return false;
665 DCHECK_GT(max_frame_num_, 0);
667 UpdatePicNums();
668 DCHECK(slice_hdr);
669 PrepareRefPicLists(slice_hdr);
671 const media::H264PPS* pps = parser_.GetPPS(curr_pps_id_);
672 DCHECK(pps);
673 const media::H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id);
674 DCHECK(sps);
676 if (!accelerator_->SubmitFrameMetadata(sps, pps, dpb_, ref_pic_list_p0_,
677 ref_pic_list_b0_, ref_pic_list_b1_,
678 curr_pic_.get()))
679 return false;
681 return true;
684 bool H264Decoder::HandleMemoryManagementOps() {
685 // 8.2.5.4
686 for (unsigned int i = 0; i < arraysize(curr_pic_->ref_pic_marking); ++i) {
687 // Code below does not support interlaced stream (per-field pictures).
688 media::H264DecRefPicMarking* ref_pic_marking =
689 &curr_pic_->ref_pic_marking[i];
690 scoped_refptr<H264Picture> to_mark;
691 int pic_num_x;
693 switch (ref_pic_marking->memory_mgmnt_control_operation) {
694 case 0:
695 // Normal end of operations' specification.
696 return true;
698 case 1:
699 // Mark a short term reference picture as unused so it can be removed
700 // if outputted.
701 pic_num_x = curr_pic_->pic_num -
702 (ref_pic_marking->difference_of_pic_nums_minus1 + 1);
703 to_mark = dpb_.GetShortRefPicByPicNum(pic_num_x);
704 if (to_mark) {
705 to_mark->ref = false;
706 } else {
707 DVLOG(1) << "Invalid short ref pic num to unmark";
708 return false;
710 break;
712 case 2:
713 // Mark a long term reference picture as unused so it can be removed
714 // if outputted.
715 to_mark = dpb_.GetLongRefPicByLongTermPicNum(
716 ref_pic_marking->long_term_pic_num);
717 if (to_mark) {
718 to_mark->ref = false;
719 } else {
720 DVLOG(1) << "Invalid long term ref pic num to unmark";
721 return false;
723 break;
725 case 3:
726 // Mark a short term reference picture as long term reference.
727 pic_num_x = curr_pic_->pic_num -
728 (ref_pic_marking->difference_of_pic_nums_minus1 + 1);
729 to_mark = dpb_.GetShortRefPicByPicNum(pic_num_x);
730 if (to_mark) {
731 DCHECK(to_mark->ref && !to_mark->long_term);
732 to_mark->long_term = true;
733 to_mark->long_term_frame_idx = ref_pic_marking->long_term_frame_idx;
734 } else {
735 DVLOG(1) << "Invalid short term ref pic num to mark as long ref";
736 return false;
738 break;
740 case 4: {
741 // Unmark all reference pictures with long_term_frame_idx over new max.
742 max_long_term_frame_idx_ =
743 ref_pic_marking->max_long_term_frame_idx_plus1 - 1;
744 H264Picture::Vector long_terms;
745 dpb_.GetLongTermRefPicsAppending(&long_terms);
746 for (size_t i = 0; i < long_terms.size(); ++i) {
747 scoped_refptr<H264Picture>& pic = long_terms[i];
748 DCHECK(pic->ref && pic->long_term);
749 // Ok to cast, max_long_term_frame_idx is much smaller than 16bit.
750 if (pic->long_term_frame_idx >
751 static_cast<int>(max_long_term_frame_idx_))
752 pic->ref = false;
754 break;
757 case 5:
758 // Unmark all reference pictures.
759 dpb_.MarkAllUnusedForRef();
760 max_long_term_frame_idx_ = -1;
761 curr_pic_->mem_mgmt_5 = true;
762 break;
764 case 6: {
765 // Replace long term reference pictures with current picture.
766 // First unmark if any existing with this long_term_frame_idx...
767 H264Picture::Vector long_terms;
768 dpb_.GetLongTermRefPicsAppending(&long_terms);
769 for (size_t i = 0; i < long_terms.size(); ++i) {
770 scoped_refptr<H264Picture>& pic = long_terms[i];
771 DCHECK(pic->ref && pic->long_term);
772 // Ok to cast, long_term_frame_idx is much smaller than 16bit.
773 if (pic->long_term_frame_idx ==
774 static_cast<int>(ref_pic_marking->long_term_frame_idx))
775 pic->ref = false;
778 // and mark the current one instead.
779 curr_pic_->ref = true;
780 curr_pic_->long_term = true;
781 curr_pic_->long_term_frame_idx = ref_pic_marking->long_term_frame_idx;
782 break;
785 default:
786 // Would indicate a bug in parser.
787 NOTREACHED();
791 return true;
794 // This method ensures that DPB does not overflow, either by removing
795 // reference pictures as specified in the stream, or using a sliding window
796 // procedure to remove the oldest one.
797 // It also performs marking and unmarking pictures as reference.
798 // See spac 8.2.5.1.
799 void H264Decoder::ReferencePictureMarking() {
800 if (curr_pic_->idr) {
801 // If current picture is an IDR, all reference pictures are unmarked.
802 dpb_.MarkAllUnusedForRef();
804 if (curr_pic_->long_term_reference_flag) {
805 curr_pic_->long_term = true;
806 curr_pic_->long_term_frame_idx = 0;
807 max_long_term_frame_idx_ = 0;
808 } else {
809 curr_pic_->long_term = false;
810 max_long_term_frame_idx_ = -1;
812 } else {
813 if (!curr_pic_->adaptive_ref_pic_marking_mode_flag) {
814 // If non-IDR, and the stream does not indicate what we should do to
815 // ensure DPB doesn't overflow, discard oldest picture.
816 // See spec 8.2.5.3.
817 if (curr_pic_->field == H264Picture::FIELD_NONE) {
818 DCHECK_LE(
819 dpb_.CountRefPics(),
820 std::max<int>(parser_.GetSPS(curr_sps_id_)->max_num_ref_frames, 1));
821 if (dpb_.CountRefPics() ==
822 std::max<int>(parser_.GetSPS(curr_sps_id_)->max_num_ref_frames,
823 1)) {
824 // Max number of reference pics reached,
825 // need to remove one of the short term ones.
826 // Find smallest frame_num_wrap short reference picture and mark
827 // it as unused.
828 scoped_refptr<H264Picture> to_unmark =
829 dpb_.GetLowestFrameNumWrapShortRefPic();
830 if (to_unmark == NULL) {
831 DVLOG(1) << "Couldn't find a short ref picture to unmark";
832 return;
834 to_unmark->ref = false;
836 } else {
837 // Shouldn't get here.
838 DVLOG(1) << "Interlaced video not supported.";
840 } else {
841 // Stream has instructions how to discard pictures from DPB and how
842 // to mark/unmark existing reference pictures. Do it.
843 // Spec 8.2.5.4.
844 if (curr_pic_->field == H264Picture::FIELD_NONE) {
845 HandleMemoryManagementOps();
846 } else {
847 // Shouldn't get here.
848 DVLOG(1) << "Interlaced video not supported.";
854 bool H264Decoder::FinishPicture() {
855 DCHECK(curr_pic_.get());
857 // Finish processing previous picture.
858 // Start by storing previous reference picture data for later use,
859 // if picture being finished is a reference picture.
860 if (curr_pic_->ref) {
861 ReferencePictureMarking();
862 prev_ref_has_memmgmnt5_ = curr_pic_->mem_mgmt_5;
863 prev_ref_top_field_order_cnt_ = curr_pic_->top_field_order_cnt;
864 prev_ref_pic_order_cnt_msb_ = curr_pic_->pic_order_cnt_msb;
865 prev_ref_pic_order_cnt_lsb_ = curr_pic_->pic_order_cnt_lsb;
866 prev_ref_field_ = curr_pic_->field;
868 prev_has_memmgmnt5_ = curr_pic_->mem_mgmt_5;
869 prev_frame_num_offset_ = curr_pic_->frame_num_offset;
871 // Remove unused (for reference or later output) pictures from DPB, marking
872 // them as such.
873 dpb_.DeleteUnused();
875 DVLOG(4) << "Finishing picture, entries in DPB: " << dpb_.size();
877 // Whatever happens below, curr_pic_ will stop managing the pointer to the
878 // picture after this. The ownership will either be transferred to DPB, if
879 // the image is still needed (for output and/or reference), or the memory
880 // will be released if we manage to output it here without having to store
881 // it for future reference.
882 scoped_refptr<H264Picture> pic = curr_pic_;
883 curr_pic_ = nullptr;
885 // Get all pictures that haven't been outputted yet.
886 H264Picture::Vector not_outputted;
887 dpb_.GetNotOutputtedPicsAppending(&not_outputted);
888 // Include the one we've just decoded.
889 not_outputted.push_back(pic);
891 // Sort in output order.
892 std::sort(not_outputted.begin(), not_outputted.end(), POCAscCompare());
894 // Try to output as many pictures as we can. A picture can be output,
895 // if the number of decoded and not yet outputted pictures that would remain
896 // in DPB afterwards would at least be equal to max_num_reorder_frames.
897 // If the outputted picture is not a reference picture, it doesn't have
898 // to remain in the DPB and can be removed.
899 H264Picture::Vector::iterator output_candidate = not_outputted.begin();
900 size_t num_remaining = not_outputted.size();
901 while (num_remaining > max_num_reorder_frames_ ||
902 // If the condition below is used, this is an invalid stream. We should
903 // not be forced to output beyond max_num_reorder_frames in order to
904 // make room in DPB to store the current picture (if we need to do so).
905 // However, if this happens, ignore max_num_reorder_frames and try
906 // to output more. This may cause out-of-order output, but is not
907 // fatal, and better than failing instead.
908 ((dpb_.IsFull() && (!pic->outputted || pic->ref)) && num_remaining)) {
909 DVLOG_IF(1, num_remaining <= max_num_reorder_frames_)
910 << "Invalid stream: max_num_reorder_frames not preserved";
912 OutputPic(*output_candidate);
914 if (!(*output_candidate)->ref) {
915 // Current picture hasn't been inserted into DPB yet, so don't remove it
916 // if we managed to output it immediately.
917 int outputted_poc = (*output_candidate)->pic_order_cnt;
918 if (outputted_poc != pic->pic_order_cnt)
919 dpb_.DeleteByPOC(outputted_poc);
922 ++output_candidate;
923 --num_remaining;
926 // If we haven't managed to output the picture that we just decoded, or if
927 // it's a reference picture, we have to store it in DPB.
928 if (!pic->outputted || pic->ref) {
929 if (dpb_.IsFull()) {
930 // If we haven't managed to output anything to free up space in DPB
931 // to store this picture, it's an error in the stream.
932 DVLOG(1) << "Could not free up space in DPB!";
933 return false;
936 dpb_.StorePic(pic);
939 return true;
942 static int LevelToMaxDpbMbs(int level) {
943 // See table A-1 in spec.
944 switch (level) {
945 case 10: return 396;
946 case 11: return 900;
947 case 12: // fallthrough
948 case 13: // fallthrough
949 case 20: return 2376;
950 case 21: return 4752;
951 case 22: // fallthrough
952 case 30: return 8100;
953 case 31: return 18000;
954 case 32: return 20480;
955 case 40: // fallthrough
956 case 41: return 32768;
957 case 42: return 34816;
958 case 50: return 110400;
959 case 51: // fallthrough
960 case 52: return 184320;
961 default:
962 DVLOG(1) << "Invalid codec level (" << level << ")";
963 return 0;
967 bool H264Decoder::UpdateMaxNumReorderFrames(const media::H264SPS* sps) {
968 if (sps->vui_parameters_present_flag && sps->bitstream_restriction_flag) {
969 max_num_reorder_frames_ =
970 base::checked_cast<size_t>(sps->max_num_reorder_frames);
971 if (max_num_reorder_frames_ > dpb_.max_num_pics()) {
972 DVLOG(1)
973 << "max_num_reorder_frames present, but larger than MaxDpbFrames ("
974 << max_num_reorder_frames_ << " > " << dpb_.max_num_pics() << ")";
975 max_num_reorder_frames_ = 0;
976 return false;
978 return true;
981 // max_num_reorder_frames not present, infer from profile/constraints
982 // (see VUI semantics in spec).
983 if (sps->constraint_set3_flag) {
984 switch (sps->profile_idc) {
985 case 44:
986 case 86:
987 case 100:
988 case 110:
989 case 122:
990 case 244:
991 max_num_reorder_frames_ = 0;
992 break;
993 default:
994 max_num_reorder_frames_ = dpb_.max_num_pics();
995 break;
997 } else {
998 max_num_reorder_frames_ = dpb_.max_num_pics();
1001 return true;
1004 bool H264Decoder::ProcessSPS(int sps_id, bool* need_new_buffers) {
1005 const media::H264SPS* sps = parser_.GetSPS(sps_id);
1006 DCHECK(sps);
1007 DVLOG(4) << "Processing SPS";
1009 *need_new_buffers = false;
1011 if (sps->frame_mbs_only_flag == 0) {
1012 DVLOG(1) << "frame_mbs_only_flag != 1 not supported";
1013 return false;
1016 if (sps->gaps_in_frame_num_value_allowed_flag) {
1017 DVLOG(1) << "Gaps in frame numbers not supported";
1018 return false;
1021 curr_sps_id_ = sps->seq_parameter_set_id;
1023 // Calculate picture height/width in macroblocks and pixels
1024 // (spec 7.4.2.1.1, 7.4.3).
1025 int width_mb = sps->pic_width_in_mbs_minus1 + 1;
1026 int height_mb = (2 - sps->frame_mbs_only_flag) *
1027 (sps->pic_height_in_map_units_minus1 + 1);
1029 gfx::Size new_pic_size(16 * width_mb, 16 * height_mb);
1030 if (new_pic_size.IsEmpty()) {
1031 DVLOG(1) << "Invalid picture size: " << new_pic_size.ToString();
1032 return false;
1035 if (!pic_size_.IsEmpty() && new_pic_size == pic_size_) {
1036 // Already have surfaces and this SPS keeps the same resolution,
1037 // no need to request a new set.
1038 return true;
1041 pic_size_ = new_pic_size;
1042 DVLOG(1) << "New picture size: " << pic_size_.ToString();
1044 max_pic_order_cnt_lsb_ = 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
1045 max_frame_num_ = 1 << (sps->log2_max_frame_num_minus4 + 4);
1047 int level = sps->level_idc;
1048 int max_dpb_mbs = LevelToMaxDpbMbs(level);
1049 if (max_dpb_mbs == 0)
1050 return false;
1052 size_t max_dpb_size = std::min(max_dpb_mbs / (width_mb * height_mb),
1053 static_cast<int>(H264DPB::kDPBMaxSize));
1054 DVLOG(1) << "Codec level: " << level << ", DPB size: " << max_dpb_size;
1055 if (max_dpb_size == 0) {
1056 DVLOG(1) << "Invalid DPB Size";
1057 return false;
1060 dpb_.set_max_num_pics(max_dpb_size);
1062 if (!UpdateMaxNumReorderFrames(sps))
1063 return false;
1064 DVLOG(1) << "max_num_reorder_frames: " << max_num_reorder_frames_;
1066 *need_new_buffers = true;
1067 return true;
1070 bool H264Decoder::ProcessPPS(int pps_id) {
1071 const media::H264PPS* pps = parser_.GetPPS(pps_id);
1072 DCHECK(pps);
1074 curr_pps_id_ = pps->pic_parameter_set_id;
1076 return true;
1079 bool H264Decoder::FinishPrevFrameIfPresent() {
1080 // If we already have a frame waiting to be decoded, decode it and finish.
1081 if (curr_pic_ != NULL) {
1082 if (!DecodePicture())
1083 return false;
1084 return FinishPicture();
1087 return true;
1090 bool H264Decoder::PreprocessSlice(media::H264SliceHeader* slice_hdr) {
1091 prev_frame_num_ = frame_num_;
1092 frame_num_ = slice_hdr->frame_num;
1094 if (prev_frame_num_ > 0 && prev_frame_num_ < frame_num_ - 1) {
1095 DVLOG(1) << "Gap in frame_num!";
1096 return false;
1099 if (slice_hdr->field_pic_flag == 0)
1100 max_pic_num_ = max_frame_num_;
1101 else
1102 max_pic_num_ = 2 * max_frame_num_;
1104 // TODO posciak: switch to new picture detection per 7.4.1.2.4.
1105 if (curr_pic_ != NULL && slice_hdr->first_mb_in_slice != 0) {
1106 // More slice data of the current picture.
1107 return true;
1108 } else {
1109 // A new frame, so first finish the previous one before processing it...
1110 if (!FinishPrevFrameIfPresent())
1111 return false;
1114 // If the new frame is an IDR, output what's left to output and clear DPB
1115 if (slice_hdr->idr_pic_flag) {
1116 // (unless we are explicitly instructed not to do so).
1117 if (!slice_hdr->no_output_of_prior_pics_flag) {
1118 // Output DPB contents.
1119 if (!Flush())
1120 return false;
1122 dpb_.Clear();
1123 last_output_poc_ = std::numeric_limits<int>::min();
1126 return true;
1129 bool H264Decoder::ProcessSlice(media::H264SliceHeader* slice_hdr) {
1130 DCHECK(curr_pic_.get());
1131 H264Picture::Vector ref_pic_list0, ref_pic_list1;
1133 if (!ModifyReferencePicLists(slice_hdr, &ref_pic_list0, &ref_pic_list1))
1134 return false;
1136 const media::H264PPS* pps = parser_.GetPPS(slice_hdr->pic_parameter_set_id);
1137 DCHECK(pps);
1139 if (!accelerator_->SubmitSlice(pps, slice_hdr, ref_pic_list0, ref_pic_list1,
1140 curr_pic_.get(), slice_hdr->nalu_data,
1141 slice_hdr->nalu_size))
1142 return false;
1144 curr_slice_hdr_.reset();
1145 return true;
1148 #define SET_ERROR_AND_RETURN() \
1149 do { \
1150 DVLOG(1) << "Error during decode"; \
1151 state_ = kError; \
1152 return H264Decoder::kDecodeError; \
1153 } while (0)
1155 void H264Decoder::SetStream(const uint8_t* ptr, size_t size) {
1156 DCHECK(ptr);
1157 DCHECK(size);
1159 DVLOG(4) << "New input stream at: " << (void*)ptr << " size: " << size;
1160 parser_.SetStream(ptr, size);
1163 H264Decoder::DecodeResult H264Decoder::Decode() {
1164 DCHECK_NE(state_, kError);
1166 while (1) {
1167 media::H264Parser::Result par_res;
1169 if (!curr_nalu_) {
1170 curr_nalu_.reset(new media::H264NALU());
1171 par_res = parser_.AdvanceToNextNALU(curr_nalu_.get());
1172 if (par_res == media::H264Parser::kEOStream)
1173 return kRanOutOfStreamData;
1174 else if (par_res != media::H264Parser::kOk)
1175 SET_ERROR_AND_RETURN();
1178 DVLOG(4) << "NALU found: " << static_cast<int>(curr_nalu_->nal_unit_type);
1180 switch (curr_nalu_->nal_unit_type) {
1181 case media::H264NALU::kNonIDRSlice:
1182 // We can't resume from a non-IDR slice.
1183 if (state_ != kDecoding)
1184 break;
1185 // else fallthrough
1186 case media::H264NALU::kIDRSlice: {
1187 // TODO(posciak): the IDR may require an SPS that we don't have
1188 // available. For now we'd fail if that happens, but ideally we'd like
1189 // to keep going until the next SPS in the stream.
1190 if (state_ == kNeedStreamMetadata) {
1191 // We need an SPS, skip this IDR and keep looking.
1192 break;
1195 // If after reset, we should be able to recover from an IDR.
1196 if (!curr_slice_hdr_) {
1197 curr_slice_hdr_.reset(new media::H264SliceHeader());
1198 par_res =
1199 parser_.ParseSliceHeader(*curr_nalu_, curr_slice_hdr_.get());
1200 if (par_res != media::H264Parser::kOk)
1201 SET_ERROR_AND_RETURN();
1203 if (!PreprocessSlice(curr_slice_hdr_.get()))
1204 SET_ERROR_AND_RETURN();
1207 if (!curr_pic_) {
1208 // New picture/finished previous one, try to start a new one
1209 // or tell the client we need more surfaces.
1210 curr_pic_ = accelerator_->CreateH264Picture();
1211 if (!curr_pic_)
1212 return kRanOutOfSurfaces;
1214 if (!StartNewFrame(curr_slice_hdr_.get()))
1215 SET_ERROR_AND_RETURN();
1218 if (!ProcessSlice(curr_slice_hdr_.get()))
1219 SET_ERROR_AND_RETURN();
1221 state_ = kDecoding;
1222 break;
1225 case media::H264NALU::kSPS: {
1226 int sps_id;
1228 if (!FinishPrevFrameIfPresent())
1229 SET_ERROR_AND_RETURN();
1231 par_res = parser_.ParseSPS(&sps_id);
1232 if (par_res != media::H264Parser::kOk)
1233 SET_ERROR_AND_RETURN();
1235 bool need_new_buffers = false;
1236 if (!ProcessSPS(sps_id, &need_new_buffers))
1237 SET_ERROR_AND_RETURN();
1239 state_ = kDecoding;
1241 if (need_new_buffers) {
1242 if (!Flush())
1243 return kDecodeError;
1245 curr_pic_ = nullptr;
1246 curr_nalu_ = nullptr;
1247 ref_pic_list_p0_.clear();
1248 ref_pic_list_b0_.clear();
1249 ref_pic_list_b1_.clear();
1251 return kAllocateNewSurfaces;
1253 break;
1256 case media::H264NALU::kPPS: {
1257 if (state_ != kDecoding)
1258 break;
1260 int pps_id;
1262 if (!FinishPrevFrameIfPresent())
1263 SET_ERROR_AND_RETURN();
1265 par_res = parser_.ParsePPS(&pps_id);
1266 if (par_res != media::H264Parser::kOk)
1267 SET_ERROR_AND_RETURN();
1269 if (!ProcessPPS(pps_id))
1270 SET_ERROR_AND_RETURN();
1271 break;
1274 default:
1275 DVLOG(4) << "Skipping NALU type: " << curr_nalu_->nal_unit_type;
1276 break;
1279 DVLOG(4) << "Dropping nalu";
1280 curr_nalu_.reset();
1284 gfx::Size H264Decoder::GetPicSize() const {
1285 return pic_size_;
1288 size_t H264Decoder::GetRequiredNumOfPictures() const {
1289 return dpb_.max_num_pics() + kPicsInPipeline;
1292 } // namespace content