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.
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"
17 H264Decoder::H264Accelerator::H264Accelerator() {
20 H264Decoder::H264Accelerator::~H264Accelerator() {
23 H264Decoder::H264Decoder(H264Accelerator
* accelerator
)
24 : max_pic_order_cnt_lsb_(0),
27 max_long_term_frame_idx_(0),
28 max_num_reorder_frames_(0),
31 accelerator_(accelerator
) {
34 state_
= kNeedStreamMetadata
;
37 H264Decoder::~H264Decoder() {
40 void H264Decoder::Reset() {
43 curr_slice_hdr_
= nullptr;
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();
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
)
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
);
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
;
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
))
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
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
));
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
) {
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;
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_
;
156 prev_pic_order_cnt_msb
= 0;
157 prev_pic_order_cnt_lsb
= 0;
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_
;
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
+
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
;
191 curr_pic_
->bottom_field_order_cnt
= curr_pic_
->pic_order_cnt_msb
+
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_
;
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
;
215 if (slice_hdr
->nal_ref_idc
== 0 && abs_frame_num
> 0)
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 "
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
;
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
;
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_
;
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
) {
275 2 * (curr_pic_
->frame_num_offset
+ slice_hdr
->frame_num
) - 1;
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
;
287 curr_pic_
->top_field_order_cnt
= temp_pic_order_cnt
;
292 DVLOG(1) << "Invalid pic_order_cnt_type: " << sps
->pic_order_cnt_type
;
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
);
301 case H264Picture::FIELD_TOP
:
302 curr_pic_
->pic_order_cnt
= curr_pic_
->top_field_order_cnt
;
304 case H264Picture::FIELD_BOTTOM
:
305 curr_pic_
->pic_order_cnt
= curr_pic_
->bottom_field_order_cnt
;
312 void H264Decoder::UpdatePicNums() {
313 for (auto& pic
: dpb_
) {
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
;
322 if (pic
->frame_num
> frame_num_
)
323 pic
->frame_num_wrap
= pic
->frame_num
- max_frame_num_
;
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);
448 int H264Decoder::PicNumF(const scoped_refptr
<H264Picture
>& pic
) {
459 int H264Decoder::LongTermPicNumF(const scoped_refptr
<H264Picture
>& pic
) {
460 if (pic
->ref
&& pic
->long_term
)
461 return pic
->long_term_pic_num
;
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
,
471 const scoped_refptr
<H264Picture
>& pic
) {
472 // Security checks, do not disable in Debug mode.
474 CHECK(to
<= std::numeric_limits
<int>::max() - 2);
475 // Additional checks. Debug mode ok.
478 DCHECK((to
+ 1 == static_cast<int>(v
->size())) ||
479 (to
+ 2 == static_cast<int>(v
->size())));
483 for (int i
= to
+ 1; i
> from
; --i
)
484 (*v
)[i
] = (*v
)[i
- 1];
489 bool H264Decoder::ModifyReferencePicList(media::H264SliceHeader
* slice_hdr
,
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.
498 if (!slice_hdr
->ref_pic_list_modification_flag_l0
)
501 list_mod
= slice_hdr
->ref_list_l0_modifications
;
503 if (!slice_hdr
->ref_pic_list_modification_flag_l1
)
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);
513 // Reorder pictures on the list in a way specified in the stream.
514 int pic_num_lx_pred
= curr_pic_
->pic_num
;
516 int pic_num_lx_no_wrap
;
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
) {
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
531 if (pic_num_lx_no_wrap
< 0)
532 pic_num_lx_no_wrap
+= max_pic_num_
;
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
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_
;
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
);
555 DVLOG(1) << "Malformed stream, no pic num " << pic_num_lx
;
558 ShiftRightAndInsert(ref_pic_listx
, ref_idx_lx
,
559 num_ref_idx_lX_active_minus1
, pic
);
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
];
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
);
575 DVLOG(1) << "Malformed stream, no pic num "
576 << list_mod
->long_term_pic_num
;
579 ShiftRightAndInsert(ref_pic_listx
, ref_idx_lx
,
580 num_ref_idx_lX_active_minus1
, pic
);
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
];
592 // End of modification list.
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
;
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);
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.
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
)
647 bool H264Decoder::Flush() {
648 DVLOG(2) << "Decoder flush";
650 if (!OutputAllRemainingPics())
654 DVLOG(2) << "Decoder flush finished";
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
))
665 DCHECK_GT(max_frame_num_
, 0);
669 PrepareRefPicLists(slice_hdr
);
671 const media::H264PPS
* pps
= parser_
.GetPPS(curr_pps_id_
);
673 const media::H264SPS
* sps
= parser_
.GetSPS(pps
->seq_parameter_set_id
);
676 if (!accelerator_
->SubmitFrameMetadata(sps
, pps
, dpb_
, ref_pic_list_p0_
,
677 ref_pic_list_b0_
, ref_pic_list_b1_
,
684 bool H264Decoder::HandleMemoryManagementOps() {
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
;
693 switch (ref_pic_marking
->memory_mgmnt_control_operation
) {
695 // Normal end of operations' specification.
699 // Mark a short term reference picture as unused so it can be removed
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
);
705 to_mark
->ref
= false;
707 DVLOG(1) << "Invalid short ref pic num to unmark";
713 // Mark a long term reference picture as unused so it can be removed
715 to_mark
= dpb_
.GetLongRefPicByLongTermPicNum(
716 ref_pic_marking
->long_term_pic_num
);
718 to_mark
->ref
= false;
720 DVLOG(1) << "Invalid long term ref pic num to unmark";
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
);
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
;
735 DVLOG(1) << "Invalid short term ref pic num to mark as long ref";
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_
))
758 // Unmark all reference pictures.
759 dpb_
.MarkAllUnusedForRef();
760 max_long_term_frame_idx_
= -1;
761 curr_pic_
->mem_mgmt_5
= true;
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
))
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
;
786 // Would indicate a bug in parser.
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.
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;
809 curr_pic_
->long_term
= false;
810 max_long_term_frame_idx_
= -1;
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.
817 if (curr_pic_
->field
== H264Picture::FIELD_NONE
) {
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
,
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
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";
834 to_unmark
->ref
= false;
837 // Shouldn't get here.
838 DVLOG(1) << "Interlaced video not supported.";
841 // Stream has instructions how to discard pictures from DPB and how
842 // to mark/unmark existing reference pictures. Do it.
844 if (curr_pic_
->field
== H264Picture::FIELD_NONE
) {
845 HandleMemoryManagementOps();
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
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_
;
885 // Get all pictures that haven't been outputted yet.
886 H264Picture::Vector not_outputted
;
887 dpb_
.GetNotOutputtedPicsAppending(¬_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
);
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
) {
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!";
942 static int LevelToMaxDpbMbs(int level
) {
943 // See table A-1 in spec.
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;
962 DVLOG(1) << "Invalid codec level (" << level
<< ")";
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()) {
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;
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
) {
991 max_num_reorder_frames_
= 0;
994 max_num_reorder_frames_
= dpb_
.max_num_pics();
998 max_num_reorder_frames_
= dpb_
.max_num_pics();
1004 bool H264Decoder::ProcessSPS(int sps_id
, bool* need_new_buffers
) {
1005 const media::H264SPS
* sps
= parser_
.GetSPS(sps_id
);
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";
1016 if (sps
->gaps_in_frame_num_value_allowed_flag
) {
1017 DVLOG(1) << "Gaps in frame numbers not supported";
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();
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.
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)
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";
1060 dpb_
.set_max_num_pics(max_dpb_size
);
1062 if (!UpdateMaxNumReorderFrames(sps
))
1064 DVLOG(1) << "max_num_reorder_frames: " << max_num_reorder_frames_
;
1066 *need_new_buffers
= true;
1070 bool H264Decoder::ProcessPPS(int pps_id
) {
1071 const media::H264PPS
* pps
= parser_
.GetPPS(pps_id
);
1074 curr_pps_id_
= pps
->pic_parameter_set_id
;
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())
1084 return FinishPicture();
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!";
1099 if (slice_hdr
->field_pic_flag
== 0)
1100 max_pic_num_
= max_frame_num_
;
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.
1109 // A new frame, so first finish the previous one before processing it...
1110 if (!FinishPrevFrameIfPresent())
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.
1123 last_output_poc_
= std::numeric_limits
<int>::min();
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
))
1136 const media::H264PPS
* pps
= parser_
.GetPPS(slice_hdr
->pic_parameter_set_id
);
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
))
1144 curr_slice_hdr_
.reset();
1148 #define SET_ERROR_AND_RETURN() \
1150 DVLOG(1) << "Error during decode"; \
1152 return H264Decoder::kDecodeError; \
1155 void H264Decoder::SetStream(const uint8_t* ptr
, size_t 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
);
1167 media::H264Parser::Result par_res
;
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
)
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.
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());
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();
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();
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();
1225 case media::H264NALU::kSPS
: {
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();
1241 if (need_new_buffers
) {
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
;
1256 case media::H264NALU::kPPS
: {
1257 if (state_
!= kDecoding
)
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();
1275 DVLOG(4) << "Skipping NALU type: " << curr_nalu_
->nal_unit_type
;
1279 DVLOG(4) << "Dropping nalu";
1284 gfx::Size
H264Decoder::GetPicSize() const {
1288 size_t H264Decoder::GetRequiredNumOfPictures() const {
1289 return dpb_
.max_num_pics() + kPicsInPipeline
;
1292 } // namespace content