0

v4l2: Enable HEVC 10-bit decoding

This adds the HEVC Main 10 profiles to V4L2 and then also adds sending
the EXT_CTRLS ioctl before CAPTURE format negotiation if it is a 10-bit
HEVC format we are decoding. Doing that then enables the CAPTURE queue
to return the proper 10-bit formats needed for output.

BUG=b:326972730
TEST=HEVC 10-bit playback works on cherry w/ HEVC forcibly enabled

Change-Id: If7ccfc0cff747016308fbec2971b1a25ebc8b98a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5322262
Reviewed-by: Steve Cho <stevecho@chromium.org>
Commit-Queue: Jeffrey Kardatzke <jkardatzke@google.com>
Cr-Commit-Position: refs/heads/main@{#1265527}
This commit is contained in:
Jeffrey Kardatzke
2024-02-26 23:31:13 +00:00
committed by Chromium LUCI CQ
parent aec1edfdc1
commit 90fa47c897
5 changed files with 64 additions and 5 deletions

@ -185,7 +185,8 @@ static const std::map<v4l2_enum_type, std::vector<VideoCodecProfile>>
H264PROFILE_HIGH,
}},
#if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
{V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, {HEVCPROFILE_MAIN}},
{V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
{HEVCPROFILE_MAIN, HEVCPROFILE_MAIN10}},
#endif // BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
{V4L2_CID_MPEG_VIDEO_VP8_PROFILE, {VP8PROFILE_ANY}},
{V4L2_CID_MPEG_VIDEO_VP9_PROFILE, {VP9PROFILE_PROFILE0}},

@ -344,7 +344,8 @@ static const std::map<v4l2_enum_type, std::vector<VideoCodecProfile>>
H264PROFILE_HIGH,
}},
#if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
{V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, {HEVCPROFILE_MAIN}},
{V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
{HEVCPROFILE_MAIN, HEVCPROFILE_MAIN10}},
#endif // BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
{V4L2_CID_MPEG_VIDEO_VP8_PROFILE, {VP8PROFILE_ANY}},
{V4L2_CID_MPEG_VIDEO_VP9_PROFILE, {VP9PROFILE_PROFILE0}},
@ -363,6 +364,7 @@ static const std::map<VideoCodecProfile,
{H264PROFILE_HIGH, MAKE_V4L2_CODEC_PAIR(V4L2_PIX_FMT_H264, SLICE)},
#if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
{HEVCPROFILE_MAIN, MAKE_V4L2_CODEC_PAIR(V4L2_PIX_FMT_HEVC, SLICE)},
{HEVCPROFILE_MAIN10, MAKE_V4L2_CODEC_PAIR(V4L2_PIX_FMT_HEVC, SLICE)},
#endif // BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
{VP8PROFILE_ANY, MAKE_V4L2_CODEC_PAIR(V4L2_PIX_FMT_VP8, FRAME)},
{VP9PROFILE_PROFILE0, MAKE_V4L2_CODEC_PAIR(V4L2_PIX_FMT_VP9, FRAME)},

@ -648,6 +648,14 @@ CroStatus V4L2VideoDecoder::SetupOutputFormat(const gfx::Size& size,
DVLOGF(3) << "size: " << size.ToString()
<< ", visible_rect: " << visible_rect.ToString();
if (bit_depth == 10u) {
VLOGF(1) << "10-bit format, need to set EXT_CTRLS first";
CroStatus ext_status = SetExtCtrls10Bit(size);
if (ext_status != CroStatus::Codes::kOk) {
return ext_status;
}
}
const auto v4l2_pix_fmts = EnumerateSupportedPixFmts(
base::BindRepeating(&V4L2Device::Ioctl, device_),
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
@ -666,8 +674,9 @@ CroStatus V4L2VideoDecoder::SetupOutputFormat(const gfx::Size& size,
// P010 and NV12, and then down sample to NV12 if it is selected. This is
// not desired, so drop the candidates that don't match the bit depth of the
// stream.
const size_t candidate_bit_depth =
BitDepth(candidate->ToVideoPixelFormat());
size_t candidate_bit_depth = (candidate == Fourcc(Fourcc::MT2T))
? 10u
: (candidate->ToVideoPixelFormat());
if (candidate_bit_depth != bit_depth) {
DVLOGF(1) << "Enumerated format " << candidate->ToString()
<< " with a bit depth of " << candidate_bit_depth
@ -761,6 +770,47 @@ CroStatus V4L2VideoDecoder::SetupOutputFormat(const gfx::Size& size,
return CroStatus::Codes::kOk;
}
CroStatus V4L2VideoDecoder::SetExtCtrls10Bit(const gfx::Size& size) {
struct v4l2_ext_control ctrl;
std::vector<struct v4l2_ext_control> ctrls;
if (input_format_fourcc_ == V4L2_PIX_FMT_HEVC_SLICE) {
VLOGF(1) << "Setting EXT_CTRLS for 10-bit HEVC";
// For 10-bit formats the CAPTURE queue will not report the proper formats
// until the SPS data is sent in to indicate 10-bit content. We also set the
// size and chroma format since that should be all the information needed in
// order to know the format.
struct v4l2_ctrl_hevc_sps v4l2_sps;
memset(&v4l2_sps, 0, sizeof(v4l2_sps));
v4l2_sps.pic_width_in_luma_samples = size.width();
v4l2_sps.pic_height_in_luma_samples = size.height();
v4l2_sps.bit_depth_luma_minus8 = 2;
v4l2_sps.bit_depth_chroma_minus8 = 2;
v4l2_sps.chroma_format_idc = 1; // 4:2:0
memset(&ctrl, 0, sizeof(ctrl));
ctrl.id = V4L2_CID_STATELESS_HEVC_SPS;
ctrl.size = sizeof(v4l2_sps);
ctrl.ptr = &v4l2_sps;
ctrls.push_back(ctrl);
} else {
// TODO(b/): Add other 10-bit codecs
return CroStatus::Codes::kNoDecoderOutputFormatCandidates;
}
struct v4l2_ext_controls ext_ctrls;
memset(&ext_ctrls, 0, sizeof(ext_ctrls));
ext_ctrls.count = ctrls.size();
ext_ctrls.controls = ctrls.data();
ext_ctrls.which = V4L2_CTRL_WHICH_CUR_VAL;
ext_ctrls.request_fd = -1;
if (device_->Ioctl(VIDIOC_S_EXT_CTRLS, &ext_ctrls) != 0) {
VPLOGF(1) << "ioctl() failed: VIDIOC_S_EXT_CTRLS";
return CroStatus::Codes::kNoDecoderOutputFormatCandidates;
}
return CroStatus::Codes::kOk;
}
void V4L2VideoDecoder::Reset(base::OnceClosure closure) {
DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
DVLOGF(3);

@ -135,6 +135,12 @@ class MEDIA_GPU_EXPORT V4L2VideoDecoder
size_t num_codec_reference_frames,
uint8_t bit_depth);
// Sends the EXT_CTRLS ioctl for 10-bit video at the specified |size|. This
// will enable retrieving the proper format from the CAPTURE queue. |size| is
// needed so that we are passing in all the information that might be needed
// by the driver to know what the format is.
CroStatus SetExtCtrls10Bit(const gfx::Size& size);
// Start streaming V4L2 input and (if |start_output_queue| is true) output
// queues. Attempt to start |device_poll_thread_| after streaming starts.
bool StartStreamV4L2Queue(bool start_output_queue);

@ -405,7 +405,7 @@ bool V4L2StatelessVideoDecoderBackend::PumpDecodeTask() {
while (true) {
switch (decoder_->Decode()) {
case AcceleratedVideoDecoder::kConfigChange:
if (decoder_->GetBitDepth() != 8u) {
if (decoder_->GetBitDepth() != 8u && decoder_->GetBitDepth() != 10u) {
VLOGF(2) << "Unsupported bit depth: "
<< base::strict_cast<int>(decoder_->GetBitDepth());
return false;