diff options
Diffstat (limited to 'chromium/content/common/gpu/media/vaapi_h264_decoder.cc')
-rw-r--r-- | chromium/content/common/gpu/media/vaapi_h264_decoder.cc | 149 |
1 files changed, 99 insertions, 50 deletions
diff --git a/chromium/content/common/gpu/media/vaapi_h264_decoder.cc b/chromium/content/common/gpu/media/vaapi_h264_decoder.cc index 402369bb2b3..9654a3c246a 100644 --- a/chromium/content/common/gpu/media/vaapi_h264_decoder.cc +++ b/chromium/content/common/gpu/media/vaapi_h264_decoder.cc @@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/numerics/safe_conversions.h" #include "base/stl_util.h" #include "content/common/gpu/media/vaapi_h264_decoder.h" @@ -62,6 +63,7 @@ VaapiH264Decoder::VaapiH264Decoder( max_frame_num_(0), max_pic_num_(0), max_long_term_frame_idx_(0), + max_num_reorder_frames_(0), curr_sps_id_(-1), curr_pps_id_(-1), vaapi_wrapper_(vaapi_wrapper), @@ -105,7 +107,7 @@ void VaapiH264Decoder::Reset() { dpb_.Clear(); parser_.Reset(); - last_output_poc_ = 0; + last_output_poc_ = std::numeric_limits<int>::min(); // If we are in kDecoding, we can resume without processing an SPS. if (state_ == kDecoding) @@ -219,10 +221,10 @@ void VaapiH264Decoder::UnassignSurfaceFromPoC(int poc) { } bool VaapiH264Decoder::SendPPS() { - const H264PPS* pps = parser_.GetPPS(curr_pps_id_); + const media::H264PPS* pps = parser_.GetPPS(curr_pps_id_); DCHECK(pps); - const H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id); + const media::H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id); DCHECK(sps); DCHECK(curr_pic_.get()); @@ -306,7 +308,7 @@ bool VaapiH264Decoder::SendPPS() { } bool VaapiH264Decoder::SendIQMatrix() { - const H264PPS* pps = parser_.GetPPS(curr_pps_id_); + const media::H264PPS* pps = parser_.GetPPS(curr_pps_id_); DCHECK(pps); VAIQMatrixBufferH264 iq_matrix_buf; @@ -323,7 +325,7 @@ bool VaapiH264Decoder::SendIQMatrix() { iq_matrix_buf.ScalingList8x8[i][j] = pps->scaling_list8x8[i][j]; } } else { - const H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id); + const media::H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id); DCHECK(sps); for (int i = 0; i < 6; ++i) { for (int j = 0; j < 16; ++j) @@ -341,11 +343,11 @@ bool VaapiH264Decoder::SendIQMatrix() { &iq_matrix_buf); } -bool VaapiH264Decoder::SendVASliceParam(H264SliceHeader* slice_hdr) { - const H264PPS* pps = parser_.GetPPS(slice_hdr->pic_parameter_set_id); +bool VaapiH264Decoder::SendVASliceParam(media::H264SliceHeader* slice_hdr) { + const media::H264PPS* pps = parser_.GetPPS(slice_hdr->pic_parameter_set_id); DCHECK(pps); - const H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id); + const media::H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id); DCHECK(sps); VASliceParameterBufferH264 slice_param; @@ -440,7 +442,7 @@ bool VaapiH264Decoder::SendSliceData(const uint8* ptr, size_t size) { non_const_ptr); } -bool VaapiH264Decoder::PrepareRefPicLists(H264SliceHeader* slice_hdr) { +bool VaapiH264Decoder::PrepareRefPicLists(media::H264SliceHeader* slice_hdr) { ref_pic_list0_.clear(); ref_pic_list1_.clear(); @@ -459,7 +461,7 @@ bool VaapiH264Decoder::PrepareRefPicLists(H264SliceHeader* slice_hdr) { return true; } -bool VaapiH264Decoder::QueueSlice(H264SliceHeader* slice_hdr) { +bool VaapiH264Decoder::QueueSlice(media::H264SliceHeader* slice_hdr) { DCHECK(curr_pic_.get()); if (!PrepareRefPicLists(slice_hdr)) @@ -495,8 +497,7 @@ bool VaapiH264Decoder::DecodePicture() { return true; } - -bool VaapiH264Decoder::InitCurrPicture(H264SliceHeader* slice_hdr) { +bool VaapiH264Decoder::InitCurrPicture(media::H264SliceHeader* slice_hdr) { DCHECK(curr_pic_.get()); memset(curr_pic_.get(), 0, sizeof(H264Picture)); @@ -541,9 +542,10 @@ bool VaapiH264Decoder::InitCurrPicture(H264SliceHeader* slice_hdr) { return true; } -bool VaapiH264Decoder::CalculatePicOrderCounts(H264SliceHeader* slice_hdr) { +bool VaapiH264Decoder::CalculatePicOrderCounts( + media::H264SliceHeader* slice_hdr) { DCHECK_NE(curr_sps_id_, -1); - const H264SPS* sps = parser_.GetSPS(curr_sps_id_); + const media::H264SPS* sps = parser_.GetSPS(curr_sps_id_); int pic_order_cnt_lsb = slice_hdr->pic_order_cnt_lsb; curr_pic_->pic_order_cnt_lsb = pic_order_cnt_lsb; @@ -750,7 +752,8 @@ struct LongTermPicNumAscCompare { } }; -void VaapiH264Decoder::ConstructReferencePicListsP(H264SliceHeader* slice_hdr) { +void VaapiH264Decoder::ConstructReferencePicListsP( + media::H264SliceHeader* slice_hdr) { // RefPicList0 (8.2.4.2.1) [[1] [2]], where: // [1] shortterm ref pics sorted by descending pic_num, // [2] longterm ref pics by ascending long_term_pic_num. @@ -783,7 +786,8 @@ struct POCDescCompare { } }; -void VaapiH264Decoder::ConstructReferencePicListsB(H264SliceHeader* slice_hdr) { +void VaapiH264Decoder::ConstructReferencePicListsB( + media::H264SliceHeader* slice_hdr) { // RefPicList0 (8.2.4.2.3) [[1] [2] [3]], where: // [1] shortterm ref pics with POC < curr_pic's POC sorted by descending POC, // [2] shortterm ref pics with POC > curr_pic's POC by ascending POC, @@ -886,11 +890,11 @@ static void ShiftRightAndInsert(H264Picture::PtrVector *v, (*v)[from] = pic; } -bool VaapiH264Decoder::ModifyReferencePicList(H264SliceHeader *slice_hdr, +bool VaapiH264Decoder::ModifyReferencePicList(media::H264SliceHeader* slice_hdr, int list) { int num_ref_idx_lX_active_minus1; H264Picture::PtrVector* ref_pic_listx; - H264ModificationOfPicNum* list_mod; + media::H264ModificationOfPicNum* list_mod; // This can process either ref_pic_list0 or ref_pic_list1, depending on // the list argument. Set up pointers to proper list to be processed here. @@ -922,7 +926,7 @@ bool VaapiH264Decoder::ModifyReferencePicList(H264SliceHeader *slice_hdr, int pic_num_lx; bool done = false; H264Picture* pic; - for (int i = 0; i < H264SliceHeader::kRefListModSize && !done; ++i) { + for (int i = 0; i < media::H264SliceHeader::kRefListModSize && !done; ++i) { switch (list_mod->modification_of_pic_nums_idc) { case 0: case 1: @@ -954,7 +958,7 @@ bool VaapiH264Decoder::ModifyReferencePicList(H264SliceHeader *slice_hdr, pic_num_lx = pic_num_lx_no_wrap; DCHECK_LT(num_ref_idx_lX_active_minus1 + 1, - H264SliceHeader::kRefListModSize); + media::H264SliceHeader::kRefListModSize); pic = dpb_.GetShortRefPicByPicNum(pic_num_lx); if (!pic) { DVLOG(1) << "Malformed stream, no pic num " << pic_num_lx; @@ -974,7 +978,7 @@ bool VaapiH264Decoder::ModifyReferencePicList(H264SliceHeader *slice_hdr, case 2: // Modify long term reference picture position. DCHECK_LT(num_ref_idx_lX_active_minus1 + 1, - H264SliceHeader::kRefListModSize); + media::H264SliceHeader::kRefListModSize); pic = dpb_.GetLongRefPicByLongTermPicNum(list_mod->long_term_pic_num); if (!pic) { DVLOG(1) << "Malformed stream, no pic num " @@ -1040,7 +1044,7 @@ void VaapiH264Decoder::ClearDPB() { UnassignSurfaceFromPoC((*it)->pic_order_cnt); dpb_.Clear(); - last_output_poc_ = 0; + last_output_poc_ = std::numeric_limits<int>::min(); } bool VaapiH264Decoder::OutputAllRemainingPics() { @@ -1074,7 +1078,7 @@ bool VaapiH264Decoder::Flush() { return true; } -bool VaapiH264Decoder::StartNewFrame(H264SliceHeader* slice_hdr) { +bool VaapiH264Decoder::StartNewFrame(media::H264SliceHeader* slice_hdr) { // TODO posciak: add handling of max_num_ref_frames per spec. // If the new frame is an IDR, output what's left to output and clear DPB @@ -1086,7 +1090,7 @@ bool VaapiH264Decoder::StartNewFrame(H264SliceHeader* slice_hdr) { return false; } dpb_.Clear(); - last_output_poc_ = 0; + last_output_poc_ = std::numeric_limits<int>::min(); } // curr_pic_ should have either been added to DPB or discarded when finishing @@ -1120,7 +1124,8 @@ bool VaapiH264Decoder::HandleMemoryManagementOps() { // 8.2.5.4 for (unsigned int i = 0; i < arraysize(curr_pic_->ref_pic_marking); ++i) { // Code below does not support interlaced stream (per-field pictures). - H264DecRefPicMarking* ref_pic_marking = &curr_pic_->ref_pic_marking[i]; + media::H264DecRefPicMarking* ref_pic_marking = + &curr_pic_->ref_pic_marking[i]; H264Picture* to_mark; int pic_num_x; @@ -1326,20 +1331,18 @@ bool VaapiH264Decoder::FinishPicture() { dpb_.GetNotOutputtedPicsAppending(not_outputted); // Include the one we've just decoded. not_outputted.push_back(pic.get()); + // Sort in output order. std::sort(not_outputted.begin(), not_outputted.end(), POCAscCompare()); - // Try to output as many pictures as we can. A picture can be output - // if its POC is next after the previously outputted one (which means - // last_output_poc_ + 2, because POCs are incremented by 2 to accommodate - // fields when decoding interleaved streams). POC can also be equal to - // last outputted picture's POC when it wraps around back to 0. + // Try to output as many pictures as we can. A picture can be output, + // if the number of decoded and not yet outputted pictures that would remain + // in DPB afterwards would at least be equal to max_num_reorder_frames. // If the outputted picture is not a reference picture, it doesn't have // to remain in the DPB and can be removed. H264Picture::PtrVector::iterator output_candidate = not_outputted.begin(); - for (; output_candidate != not_outputted.end() && - (*output_candidate)->pic_order_cnt <= last_output_poc_ + 2; - ++output_candidate) { + size_t num_remaining = not_outputted.size(); + while (num_remaining > max_num_reorder_frames_) { int poc = (*output_candidate)->pic_order_cnt; DCHECK_GE(poc, last_output_poc_); if (!OutputPic(*output_candidate)) @@ -1353,6 +1356,9 @@ bool VaapiH264Decoder::FinishPicture() { // Mark as unused. UnassignSurfaceFromPoC(poc); } + + ++output_candidate; + --num_remaining; } // If we haven't managed to output the picture that we just decoded, or if @@ -1396,8 +1402,45 @@ static int LevelToMaxDpbMbs(int level) { } } +bool VaapiH264Decoder::UpdateMaxNumReorderFrames(const media::H264SPS* sps) { + if (sps->vui_parameters_present_flag && sps->bitstream_restriction_flag) { + max_num_reorder_frames_ = + base::checked_cast<size_t>(sps->max_num_reorder_frames); + if (max_num_reorder_frames_ > dpb_.max_num_pics()) { + DVLOG(1) + << "max_num_reorder_frames present, but larger than MaxDpbFrames (" + << max_num_reorder_frames_ << " > " << dpb_.max_num_pics() << ")"; + max_num_reorder_frames_ = 0; + return false; + } + return true; + } + + // max_num_reorder_frames not present, infer from profile/constraints + // (see VUI semantics in spec). + if (sps->constraint_set3_flag) { + switch (sps->profile_idc) { + case 44: + case 86: + case 100: + case 110: + case 122: + case 244: + max_num_reorder_frames_ = 0; + break; + default: + max_num_reorder_frames_ = dpb_.max_num_pics(); + break; + } + } else { + max_num_reorder_frames_ = dpb_.max_num_pics(); + } + + return true; +} + bool VaapiH264Decoder::ProcessSPS(int sps_id, bool* need_new_buffers) { - const H264SPS* sps = parser_.GetSPS(sps_id); + const media::H264SPS* sps = parser_.GetSPS(sps_id); DCHECK(sps); DVLOG(4) << "Processing SPS"; @@ -1456,12 +1499,16 @@ bool VaapiH264Decoder::ProcessSPS(int sps_id, bool* need_new_buffers) { dpb_.set_max_num_pics(max_dpb_size); + if (!UpdateMaxNumReorderFrames(sps)) + return false; + DVLOG(1) << "max_num_reorder_frames: " << max_num_reorder_frames_; + *need_new_buffers = true; return true; } bool VaapiH264Decoder::ProcessPPS(int pps_id) { - const H264PPS* pps = parser_.GetPPS(pps_id); + const media::H264PPS* pps = parser_.GetPPS(pps_id); DCHECK(pps); curr_pps_id_ = pps->pic_parameter_set_id; @@ -1480,7 +1527,7 @@ bool VaapiH264Decoder::FinishPrevFrameIfPresent() { return true; } -bool VaapiH264Decoder::ProcessSlice(H264SliceHeader* slice_hdr) { +bool VaapiH264Decoder::ProcessSlice(media::H264SliceHeader* slice_hdr) { prev_frame_num_ = frame_num_; frame_num_ = slice_hdr->frame_num; @@ -1518,7 +1565,9 @@ bool VaapiH264Decoder::ProcessSlice(H264SliceHeader* slice_hdr) { return VaapiH264Decoder::kDecodeError; \ } while (0) -void VaapiH264Decoder::SetStream(uint8* ptr, size_t size, int32 input_id) { +void VaapiH264Decoder::SetStream(const uint8* ptr, + size_t size, + int32 input_id) { DCHECK(ptr); DCHECK(size); @@ -1530,8 +1579,8 @@ void VaapiH264Decoder::SetStream(uint8* ptr, size_t size, int32 input_id) { } VaapiH264Decoder::DecResult VaapiH264Decoder::Decode() { - H264Parser::Result par_res; - H264NALU nalu; + media::H264Parser::Result par_res; + media::H264NALU nalu; DCHECK_NE(state_, kError); while (1) { @@ -1547,20 +1596,20 @@ VaapiH264Decoder::DecResult VaapiH264Decoder::Decode() { } par_res = parser_.AdvanceToNextNALU(&nalu); - if (par_res == H264Parser::kEOStream) + if (par_res == media::H264Parser::kEOStream) return kRanOutOfStreamData; - else if (par_res != H264Parser::kOk) + else if (par_res != media::H264Parser::kOk) SET_ERROR_AND_RETURN(); DVLOG(4) << "NALU found: " << static_cast<int>(nalu.nal_unit_type); switch (nalu.nal_unit_type) { - case H264NALU::kNonIDRSlice: + case media::H264NALU::kNonIDRSlice: // We can't resume from a non-IDR slice. if (state_ != kDecoding) break; // else fallthrough - case H264NALU::kIDRSlice: { + case media::H264NALU::kIDRSlice: { // TODO(posciak): the IDR may require an SPS that we don't have // available. For now we'd fail if that happens, but ideally we'd like // to keep going until the next SPS in the stream. @@ -1570,10 +1619,10 @@ VaapiH264Decoder::DecResult VaapiH264Decoder::Decode() { } // If after reset, we should be able to recover from an IDR. - H264SliceHeader slice_hdr; + media::H264SliceHeader slice_hdr; par_res = parser_.ParseSliceHeader(nalu, &slice_hdr); - if (par_res != H264Parser::kOk) + if (par_res != media::H264Parser::kOk) SET_ERROR_AND_RETURN(); if (!ProcessSlice(&slice_hdr)) @@ -1583,14 +1632,14 @@ VaapiH264Decoder::DecResult VaapiH264Decoder::Decode() { break; } - case H264NALU::kSPS: { + case media::H264NALU::kSPS: { int sps_id; if (!FinishPrevFrameIfPresent()) SET_ERROR_AND_RETURN(); par_res = parser_.ParseSPS(&sps_id); - if (par_res != H264Parser::kOk) + if (par_res != media::H264Parser::kOk) SET_ERROR_AND_RETURN(); bool need_new_buffers = false; @@ -1609,7 +1658,7 @@ VaapiH264Decoder::DecResult VaapiH264Decoder::Decode() { break; } - case H264NALU::kPPS: { + case media::H264NALU::kPPS: { if (state_ != kDecoding) break; @@ -1619,7 +1668,7 @@ VaapiH264Decoder::DecResult VaapiH264Decoder::Decode() { SET_ERROR_AND_RETURN(); par_res = parser_.ParsePPS(&pps_id); - if (par_res != H264Parser::kOk) + if (par_res != media::H264Parser::kOk) SET_ERROR_AND_RETURN(); if (!ProcessPPS(pps_id)) @@ -1628,7 +1677,7 @@ VaapiH264Decoder::DecResult VaapiH264Decoder::Decode() { } default: - DVLOG(4) << "Skipping NALU type: " << nalu.nal_unit_type;; + DVLOG(4) << "Skipping NALU type: " << nalu.nal_unit_type; break; } } |