Commit 790d98e7 authored by Hirokazu Honda's avatar Hirokazu Honda Committed by Chromium LUCI CQ

media/gpu: Confirm a video is YUV 4:2:0 in AcceleratedVideoDecoder

Existing hardware decoders support only YUV 4:2:0 videos. We
currently rely the underlying libraries and drivers to deny non
YUV 4:2:0 videos. We would rater confirm it in
AcceleratedVideoDecoder. From this CL,
AcceleratedVideoDecoder::Decode() returns kDecodeError if
a video is not YUV 4:2:0.

Bug: b:172223934
Test: media_unittests
Change-Id: Ib0ddbe526a801476e382f0b7665a74573bd6a28d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2562618
Commit-Queue: Hirokazu Honda <hiroh@chromium.org>
Reviewed-by: default avatarDale Curtis <dalecurtis@chromium.org>
Reviewed-by: default avatarMiguel Casas <mcasas@chromium.org>
Reviewed-by: default avatarAndres Calderon Jaramillo <andrescj@chromium.org>
Cr-Commit-Position: refs/heads/master@{#833594}
parent 855c88e4
......@@ -56,7 +56,7 @@ bool SequenceUsesScalability(int operating_point_idc) {
}
bool IsYUV420Sequence(const libgav1::ColorConfig& color_config) {
return color_config.subsampling_x == 1 && color_config.subsampling_y == 1 &&
return color_config.subsampling_x == 1u && color_config.subsampling_y == 1u &&
!color_config.is_monochrome;
}
......
......@@ -410,7 +410,17 @@ TEST_F(AV1DecoderTest, DecodeSVCStream) {
EXPECT_EQ(Decode(buffers[1]), expected);
}
// TODO(hiroh): Add more tests, non-YUV420 stream, Reset() flow, mid-stream
// configuration change, and reference frame tracking.
TEST_F(AV1DecoderTest, DenyDecodeNonYUV420) {
const std::string kYUV444Stream("blackwhite_yuv444p-frame.av1.ivf");
std::vector<scoped_refptr<DecoderBuffer>> buffers = ReadIVF(kYUV444Stream);
ASSERT_EQ(buffers.size(), 1u);
std::vector<DecodeResult> expected = {DecodeResult::kDecodeError};
EXPECT_EQ(Decode(buffers[0]), expected);
// Once AV1Decoder gets into an error state, Decode() returns kDecodeError
// until Reset().
EXPECT_EQ(Decode(buffers[0]), expected);
}
// TODO(hiroh): Add more tests, Reset() flow, mid-stream configuration change,
// and reference frame tracking.
} // namespace
} // namespace media
......@@ -18,6 +18,7 @@
namespace media {
namespace {
bool ParseBitDepth(const H264SPS& sps, uint8_t& bit_depth) {
// Spec 7.4.2.1.1
if (sps.bit_depth_luma_minus8 != sps.bit_depth_chroma_minus8) {
......@@ -77,6 +78,11 @@ bool IsValidBitDepth(uint8_t bit_depth, VideoCodecProfile profile) {
return false;
}
}
bool IsYUV420Sequence(const H264SPS& sps) {
// Spec 6.2
return sps.chroma_format_idc == 1;
}
} // namespace
H264Decoder::H264Accelerator::H264Accelerator() = default;
......@@ -1156,6 +1162,11 @@ bool H264Decoder::ProcessSPS(int sps_id, bool* need_new_buffers) {
DVLOG(1) << "Invalid DPB size: " << max_dpb_size;
return false;
}
if (!IsYUV420Sequence(*sps)) {
DVLOG(1) << "Only YUV 4:2:0 is supported";
return false;
}
VideoCodecProfile new_profile =
H264Parser::ProfileIDCToVideoCodecProfile(sps->profile_idc);
uint8_t new_bit_depth = 0;
......
......@@ -46,6 +46,7 @@ const std::string k10BitFrame0 = "bear-320x180-10bit-frame-0.h264";
const std::string k10BitFrame1 = "bear-320x180-10bit-frame-1.h264";
const std::string k10BitFrame2 = "bear-320x180-10bit-frame-2.h264";
const std::string k10BitFrame3 = "bear-320x180-10bit-frame-3.h264";
const std::string kYUV444Frame = "blackwhite_yuv444p-frame.h264";
// Checks whether the decrypt config in the picture matches the decrypt config
// passed to this matcher.
......@@ -456,6 +457,12 @@ TEST_F(H264DecoderTest, DecodeProfileHigh) {
ASSERT_TRUE(decoder_->Flush());
}
TEST_F(H264DecoderTest, DenyDecodeNonYUV420) {
// YUV444 frame causes kDecodeError.
SetInputFrameFiles({kYUV444Frame});
ASSERT_EQ(AcceleratedVideoDecoder::kDecodeError, Decode());
}
TEST_F(H264DecoderTest, SwitchBaselineToHigh) {
SetInputFrameFiles({
kBaselineFrame0, kHighFrame0, kHighFrame1, kHighFrame2, kHighFrame3,
......@@ -555,6 +562,25 @@ TEST_F(H264DecoderTest, SwitchHighToBaseline) {
ASSERT_TRUE(decoder_->Flush());
}
TEST_F(H264DecoderTest, SwitchYUV420ToNonYUV420) {
SetInputFrameFiles({kBaselineFrame0, kYUV444Frame});
// The first frame, YUV420, is decoded with no error.
ASSERT_EQ(AcceleratedVideoDecoder::kConfigChange, Decode());
EXPECT_EQ(gfx::Size(320, 192), decoder_->GetPicSize());
EXPECT_EQ(H264PROFILE_BASELINE, decoder_->GetProfile());
EXPECT_LE(9u, decoder_->GetRequiredNumOfPictures());
{
InSequence sequence;
EXPECT_CALL(*accelerator_, CreateH264Picture());
EXPECT_CALL(*accelerator_, SubmitFrameMetadata(_, _, _, _, _, _, _));
EXPECT_CALL(*accelerator_, SubmitSlice(_, _, _, _, _, _, _, _));
EXPECT_CALL(*accelerator_, SubmitDecode(_));
EXPECT_CALL(*accelerator_, OutputPicture(WithPoc(0)));
}
// The second frame, YUV444, causes kDecodeError.
ASSERT_EQ(AcceleratedVideoDecoder::kDecodeError, Decode());
}
// Verify that the decryption config is passed to the accelerator.
TEST_F(H264DecoderTest, SetEncryptedStream) {
std::string bitstream;
......
......@@ -44,6 +44,11 @@ bool IsValidBitDepth(uint8_t bit_depth, VideoCodecProfile profile) {
return false;
}
}
bool IsYUV420Sequence(const H265SPS& sps) {
// Spec 6.2
return sps.chroma_format_idc == 1;
}
} // namespace
H265Decoder::H265Accelerator::H265Accelerator() = default;
......@@ -369,6 +374,10 @@ bool H265Decoder::ProcessPPS(int pps_id, bool* need_new_buffers) {
DVLOG(2) << "New visible rect: " << new_visible_rect.ToString();
visible_rect_ = new_visible_rect;
}
if (!IsYUV420Sequence(*sps)) {
DVLOG(1) << "Only YUV 4:2:0 is supported";
return false;
}
// Equation 7-8
max_pic_order_cnt_lsb_ =
......
......@@ -41,6 +41,7 @@ constexpr char k10BitFrame0[] = "bear-320x180-10bit-frame-0.hevc";
constexpr char k10BitFrame1[] = "bear-320x180-10bit-frame-1.hevc";
constexpr char k10BitFrame2[] = "bear-320x180-10bit-frame-2.hevc";
constexpr char k10BitFrame3[] = "bear-320x180-10bit-frame-3.hevc";
constexpr char kYUV444Frame[] = "blackwhite_yuv444p-frame.hevc";
// Checks whether the decrypt config in the picture matches the decrypt config
// passed to this matcher.
......@@ -310,6 +311,12 @@ TEST_F(H265DecoderTest, Decode10BitStream) {
EXPECT_TRUE(decoder_->Flush());
}
TEST_F(H265DecoderTest, DenyDecodeNonYUV420) {
// YUV444 frame causes kDecodeError.
SetInputFrameFiles({kYUV444Frame});
ASSERT_EQ(AcceleratedVideoDecoder::kDecodeError, Decode());
}
TEST_F(H265DecoderTest, OutputPictureFailureCausesDecodeToFail) {
// Provide enough data that Decode() will try to output a frame.
SetInputFrameFiles({kSpsPps, kFrame0, kFrame1, kFrame2, kFrame3});
......
......@@ -70,6 +70,11 @@ bool IsValidBitDepth(uint8_t bit_depth, VideoCodecProfile profile) {
return false;
}
}
bool IsYUV420Sequence(const Vp9FrameHeader& frame_header) {
// Spec 7.2.2
return frame_header.subsampling_x == 1u && frame_header.subsampling_y == 1u;
}
} // namespace
VP9Decoder::VP9Accelerator::VP9Accelerator() {}
......@@ -237,6 +242,10 @@ VP9Decoder::DecodeResult VP9Decoder::Decode() {
<< ", profile=" << GetProfileName(new_profile);
return kDecodeError;
}
if (!IsYUV420Sequence(*curr_frame_hdr_)) {
DVLOG(1) << "Only YUV 4:2:0 is supported";
return kDecodeError;
}
DCHECK(!new_pic_size.IsEmpty());
if (new_pic_size != pic_size_ || new_profile != profile_ ||
......
......@@ -186,6 +186,9 @@ AV1 data that contains frames with `show_existing_frame=1`.
This is the same as 00000592.ivf in
https://people.xiph.org/~tterribe/av1/samples-all/
#### blackwhite\_yuv444p-frame.av1.ivf
The first frame of blackwhite\_yuv444p.mp4 coded in AV1 by the following command.
`ffmpeg -i blackwhite_yuv444p.mp4 -strict -2 -vcodec av1 -vframes 1 blackwhite_yuv444p-frame.av1.ivf`
### Alpha Channel
......@@ -898,6 +901,13 @@ Created using "avconv -i bear-vp9.webm -vcodec copy -an -f ivf bear-vp9.ivf".
Manually dumped from libvpx with bear-vp9.ivf and test-25fps.vp9. See
vp9_parser_unittest.cc for description of their format.
### H264 decoder test files:
#### blackwhite\_yuv444p-frame.h264
The first frame of blackwhite_yuv444p.mp4 by the following command.
`ffmpeg -i blackwhite_yuv444p.mp4 -vcodec copy -vframes 1 blackwhite_yuv444p-frame.h264`
### HEVC parser/decoder test files:
#### bear.hevc
......@@ -925,6 +935,10 @@ bear-320x180-10bit-frame-1.hevc: B
bear-320x180-10bit-frame-2.hevc: B
bear-320x180-10bit-frame-3.hevc: P
#### blackwhite\_yuv444p-frame.hevc
The first frame of blackwhite_yuv444p.mp4 coded in HEVC by the following command.
`ffmpeg -i blackwhite_yuv444p.mp4 -vcodec hevc -vframes 1 blackwhite_yuv444p-frame.hevc`
### WebM files for testing multiple tracks.
#### green-a300hz.webm
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment