summaryrefslogtreecommitdiffstats
path: root/chromium/content/common/gpu/media/vaapi_h264_decoder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/common/gpu/media/vaapi_h264_decoder.cc')
-rw-r--r--chromium/content/common/gpu/media/vaapi_h264_decoder.cc149
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;
}
}