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());
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]);
439 int H264Decoder::PicNumF(const scoped_refptr
<H264Picture
>& pic
) {
450 int H264Decoder::LongTermPicNumF(const scoped_refptr
<H264Picture
>& pic
) {
451 if (pic
->ref
&& pic
->long_term
)
452 return pic
->long_term_pic_num
;
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
,
462 const scoped_refptr
<H264Picture
>& pic
) {
463 // Security checks, do not disable in Debug mode.
465 CHECK(to
<= std::numeric_limits
<int>::max() - 2);
466 // Additional checks. Debug mode ok.
469 DCHECK((to
+ 1 == static_cast<int>(v
->size())) ||
470 (to
+ 2 == static_cast<int>(v
->size())));
474 for (int i
= to
+ 1; i
> from
; --i
)
475 (*v
)[i
] = (*v
)[i
- 1];
480 bool H264Decoder::ModifyReferencePicList(media::H264SliceHeader
* slice_hdr
,
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.
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
;
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
)
515 // Reorder pictures on the list in a way specified in the stream.
516 int pic_num_lx_pred
= curr_pic_
->pic_num
;
518 int pic_num_lx_no_wrap
;
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
) {
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
533 if (pic_num_lx_no_wrap
< 0)
534 pic_num_lx_no_wrap
+= max_pic_num_
;
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
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_
;
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
);
557 DVLOG(1) << "Malformed stream, no pic num " << pic_num_lx
;
560 ShiftRightAndInsert(ref_pic_listx
, ref_idx_lx
,
561 num_ref_idx_lX_active_minus1
, pic
);
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
];
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
);
577 DVLOG(1) << "Malformed stream, no pic num "
578 << list_mod
->long_term_pic_num
;
581 ShiftRightAndInsert(ref_pic_listx
, ref_idx_lx
,
582 num_ref_idx_lX_active_minus1
, pic
);
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
];
594 // End of modification list.
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
;
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);
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.
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
)
649 bool H264Decoder::Flush() {
650 DVLOG(2) << "Decoder flush";
652 if (!OutputAllRemainingPics())
656 DVLOG(2) << "Decoder flush finished";
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
))
667 DCHECK_GT(max_frame_num_
, 0);
671 PrepareRefPicLists(slice_hdr
);
673 const media::H264PPS
* pps
= parser_
.GetPPS(curr_pps_id_
);
675 const media::H264SPS
* sps
= parser_
.GetSPS(pps
->seq_parameter_set_id
);
678 if (!accelerator_
->SubmitFrameMetadata(sps
, pps
, dpb_
, ref_pic_list_p0_
,
679 ref_pic_list_b0_
, ref_pic_list_b1_
,
686 bool H264Decoder::HandleMemoryManagementOps() {
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
;
695 switch (ref_pic_marking
->memory_mgmnt_control_operation
) {
697 // Normal end of operations' specification.
701 // Mark a short term reference picture as unused so it can be removed
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
);
707 to_mark
->ref
= false;
709 DVLOG(1) << "Invalid short ref pic num to unmark";
715 // Mark a long term reference picture as unused so it can be removed
717 to_mark
= dpb_
.GetLongRefPicByLongTermPicNum(
718 ref_pic_marking
->long_term_pic_num
);
720 to_mark
->ref
= false;
722 DVLOG(1) << "Invalid long term ref pic num to unmark";
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
);
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
;
737 DVLOG(1) << "Invalid short term ref pic num to mark as long ref";
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_
))
760 // Unmark all reference pictures.
761 dpb_
.MarkAllUnusedForRef();
762 max_long_term_frame_idx_
= -1;
763 curr_pic_
->mem_mgmt_5
= true;
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
))
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
;
788 // Would indicate a bug in parser.
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.
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;
811 curr_pic_
->long_term
= false;
812 max_long_term_frame_idx_
= -1;
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.
819 if (curr_pic_
->field
== H264Picture::FIELD_NONE
) {
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
,
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
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";
836 to_unmark
->ref
= false;
839 // Shouldn't get here.
840 DVLOG(1) << "Interlaced video not supported.";
843 // Stream has instructions how to discard pictures from DPB and how
844 // to mark/unmark existing reference pictures. Do it.
846 if (curr_pic_
->field
== H264Picture::FIELD_NONE
) {
847 HandleMemoryManagementOps();
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
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_
;
887 // Get all pictures that haven't been outputted yet.
888 H264Picture::Vector not_outputted
;
889 dpb_
.GetNotOutputtedPicsAppending(¬_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
);
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
) {
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!";
944 static int LevelToMaxDpbMbs(int level
) {
945 // See table A-1 in spec.
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;
964 DVLOG(1) << "Invalid codec level (" << level
<< ")";
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()) {
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;
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
) {
993 max_num_reorder_frames_
= 0;
996 max_num_reorder_frames_
= dpb_
.max_num_pics();
1000 max_num_reorder_frames_
= dpb_
.max_num_pics();
1006 bool H264Decoder::ProcessSPS(int sps_id
, bool* need_new_buffers
) {
1007 const media::H264SPS
* sps
= parser_
.GetSPS(sps_id
);
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";
1018 if (sps
->gaps_in_frame_num_value_allowed_flag
) {
1019 DVLOG(1) << "Gaps in frame numbers not supported";
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();
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.
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)
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";
1062 dpb_
.set_max_num_pics(max_dpb_size
);
1064 if (!UpdateMaxNumReorderFrames(sps
))
1066 DVLOG(1) << "max_num_reorder_frames: " << max_num_reorder_frames_
;
1068 *need_new_buffers
= true;
1072 bool H264Decoder::ProcessPPS(int pps_id
) {
1073 const media::H264PPS
* pps
= parser_
.GetPPS(pps_id
);
1076 curr_pps_id_
= pps
->pic_parameter_set_id
;
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())
1086 return FinishPicture();
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!";
1101 if (slice_hdr
->field_pic_flag
== 0)
1102 max_pic_num_
= max_frame_num_
;
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.
1111 // A new frame, so first finish the previous one before processing it...
1112 if (!FinishPrevFrameIfPresent())
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.
1125 last_output_poc_
= std::numeric_limits
<int>::min();
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
))
1138 const media::H264PPS
* pps
= parser_
.GetPPS(slice_hdr
->pic_parameter_set_id
);
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
))
1146 curr_slice_hdr_
.reset();
1150 #define SET_ERROR_AND_RETURN() \
1152 DVLOG(1) << "Error during decode"; \
1154 return H264Decoder::kDecodeError; \
1157 void H264Decoder::SetStream(const uint8_t* ptr
, size_t 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
);
1169 media::H264Parser::Result par_res
;
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
)
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.
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());
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();
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();
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();
1227 case media::H264NALU::kSPS
: {
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();
1243 if (need_new_buffers
) {
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
;
1258 case media::H264NALU::kPPS
: {
1259 if (state_
!= kDecoding
)
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();
1277 DVLOG(4) << "Skipping NALU type: " << curr_nalu_
->nal_unit_type
;
1281 DVLOG(4) << "Dropping nalu";
1286 gfx::Size
H264Decoder::GetPicSize() const {
1290 size_t H264Decoder::GetRequiredNumOfPictures() const {
1291 return dpb_
.max_num_pics() + kPicsInPipeline
;
1294 } // namespace content