1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
10 #include "base/bind.h"
11 #include "base/callback_helpers.h"
12 #include "base/hash/md5.h"
13 #include "base/run_loop.h"
14 #include "base/test/task_environment.h"
15 #include "build/build_config.h"
16 #include "media/base/decoder_buffer.h"
17 #include "media/base/limits.h"
18 #include "media/base/mock_media_log.h"
19 #include "media/base/test_data_util.h"
20 #include "media/base/test_helpers.h"
21 #include "media/base/video_frame.h"
22 #include "media/ffmpeg/ffmpeg_common.h"
23 #include "media/filters/dav1d_video_decoder.h"
24 #include "media/filters/in_memory_url_protocol.h"
25 #include "testing/gmock/include/gmock/gmock.h"
33 MATCHER(ContainsDecoderErrorLog, "") {
34 return CONTAINS_STRING(arg, "dav1d_send_data() failed");
39 class Dav1dVideoDecoderTest : public testing::Test {
41 Dav1dVideoDecoderTest()
42 : decoder_(new Dav1dVideoDecoder(&media_log_)),
43 i_frame_buffer_(ReadTestDataFile("av1-I-frame-320x240")) {}
45 Dav1dVideoDecoderTest(const Dav1dVideoDecoderTest&) = delete;
46 Dav1dVideoDecoderTest& operator=(const Dav1dVideoDecoderTest&) = delete;
48 ~Dav1dVideoDecoderTest() override { Destroy(); }
51 InitializeWithConfig(TestVideoConfig::Normal(VideoCodec::kAV1));
54 void InitializeWithConfigWithResult(const VideoDecoderConfig& config,
57 config, true, // Use low delay so we get 1 frame out for each frame in.
60 [](bool success, DecoderStatus status) {
61 EXPECT_EQ(status.is_ok(), success);
64 base::BindRepeating(&Dav1dVideoDecoderTest::FrameReady,
65 base::Unretained(this)),
66 base::NullCallback());
67 base::RunLoop().RunUntilIdle();
70 void InitializeWithConfig(const VideoDecoderConfig& config) {
71 InitializeWithConfigWithResult(config, true);
75 InitializeWithConfig(TestVideoConfig::Large(VideoCodec::kAV1));
79 decoder_->Reset(NewExpectedClosure());
80 base::RunLoop().RunUntilIdle();
85 base::RunLoop().RunUntilIdle();
88 // Sets up expectations and actions to put Dav1dVideoDecoder in an active
90 void ExpectDecodingState() {
91 EXPECT_TRUE(DecodeSingleFrame(i_frame_buffer_).is_ok());
92 ASSERT_EQ(1U, output_frames_.size());
95 // Sets up expectations and actions to put Dav1dVideoDecoder in an end
97 void ExpectEndOfStreamState() {
98 EXPECT_TRUE(DecodeSingleFrame(DecoderBuffer::CreateEOSBuffer()).is_ok());
99 ASSERT_FALSE(output_frames_.empty());
102 using InputBuffers = std::vector<scoped_refptr<DecoderBuffer>>;
103 using OutputFrames = std::vector<scoped_refptr<VideoFrame>>;
105 // Decodes all buffers in |input_buffers| and push all successfully decoded
106 // output frames into |output_frames|. Returns the last decode status returned
108 DecoderStatus DecodeMultipleFrames(const InputBuffers& input_buffers) {
109 for (auto iter = input_buffers.begin(); iter != input_buffers.end();
111 DecoderStatus status = Decode(*iter);
112 switch (status.code()) {
113 case DecoderStatus::Codes::kOk:
115 case DecoderStatus::Codes::kAborted:
119 DCHECK(output_frames_.empty());
123 return DecoderStatus::Codes::kOk;
126 // Decodes the single compressed frame in |buffer|.
127 DecoderStatus DecodeSingleFrame(scoped_refptr<DecoderBuffer> buffer) {
128 InputBuffers input_buffers;
129 input_buffers.push_back(std::move(buffer));
130 return DecodeMultipleFrames(input_buffers);
133 // Decodes |i_frame_buffer_| and then decodes the data contained in the file
134 // named |test_file_name|. This function expects both buffers to decode to
135 // frames that are the same size.
136 void DecodeIFrameThenTestFile(const std::string& test_file_name,
137 const gfx::Size& expected_size) {
139 scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(test_file_name);
141 InputBuffers input_buffers;
142 input_buffers.push_back(i_frame_buffer_);
143 input_buffers.push_back(buffer);
144 input_buffers.push_back(DecoderBuffer::CreateEOSBuffer());
146 DecoderStatus status = DecodeMultipleFrames(input_buffers);
148 EXPECT_TRUE(status.is_ok());
149 ASSERT_EQ(2U, output_frames_.size());
151 gfx::Size original_size = TestVideoConfig::NormalCodedSize();
152 EXPECT_EQ(original_size.width(),
153 output_frames_[0]->visible_rect().size().width());
154 EXPECT_EQ(original_size.height(),
155 output_frames_[0]->visible_rect().size().height());
156 EXPECT_EQ(expected_size.width(),
157 output_frames_[1]->visible_rect().size().width());
158 EXPECT_EQ(expected_size.height(),
159 output_frames_[1]->visible_rect().size().height());
162 DecoderStatus Decode(scoped_refptr<DecoderBuffer> buffer) {
163 DecoderStatus status;
164 EXPECT_CALL(*this, DecodeDone(_)).WillOnce(testing::SaveArg<0>(&status));
166 decoder_->Decode(std::move(buffer),
167 base::BindOnce(&Dav1dVideoDecoderTest::DecodeDone,
168 base::Unretained(this)));
169 base::RunLoop().RunUntilIdle();
174 void FrameReady(scoped_refptr<VideoFrame> frame) {
175 DCHECK(!frame->metadata().end_of_stream);
176 output_frames_.push_back(std::move(frame));
179 std::string GetVideoFrameHash(const VideoFrame& frame) {
180 base::MD5Context md5_context;
181 base::MD5Init(&md5_context);
182 VideoFrame::HashFrameForTesting(&md5_context, frame);
183 base::MD5Digest digest;
184 base::MD5Final(&digest, &md5_context);
185 return base::MD5DigestToBase16(digest);
188 MOCK_METHOD1(DecodeDone, void(DecoderStatus));
190 testing::StrictMock<MockMediaLog> media_log_;
192 base::test::SingleThreadTaskEnvironment task_environment_;
193 std::unique_ptr<Dav1dVideoDecoder> decoder_;
195 scoped_refptr<DecoderBuffer> i_frame_buffer_;
196 OutputFrames output_frames_;
199 TEST_F(Dav1dVideoDecoderTest, Initialize_Normal) {
203 TEST_F(Dav1dVideoDecoderTest, Reinitialize_Normal) {
208 TEST_F(Dav1dVideoDecoderTest, Reinitialize_AfterDecodeFrame) {
210 ExpectDecodingState();
214 TEST_F(Dav1dVideoDecoderTest, Reinitialize_AfterReset) {
216 ExpectDecodingState();
221 TEST_F(Dav1dVideoDecoderTest, DecodeFrame_Normal) {
224 // Simulate decoding a single frame.
225 EXPECT_TRUE(DecodeSingleFrame(i_frame_buffer_).is_ok());
226 ASSERT_EQ(1U, output_frames_.size());
228 const auto& frame = output_frames_.front();
229 EXPECT_EQ(PIXEL_FORMAT_I420, frame->format());
230 EXPECT_EQ("589dc641b7742ffe7a2b0d4c16aa3e86", GetVideoFrameHash(*frame));
233 TEST_F(Dav1dVideoDecoderTest, DecodeFrame_8bitMono) {
236 DecodeSingleFrame(ReadTestDataFile("av1-monochrome-I-frame-320x240-8bpp"))
238 ASSERT_EQ(1U, output_frames_.size());
240 const auto& frame = output_frames_.front();
241 EXPECT_EQ(PIXEL_FORMAT_I420, frame->format());
242 EXPECT_EQ(frame->data(VideoFrame::kUPlane), frame->data(VideoFrame::kVPlane));
243 EXPECT_EQ("eeba03dcc9c22c4632bf74b481db36b2", GetVideoFrameHash(*frame));
246 TEST_F(Dav1dVideoDecoderTest, DecodeFrame_10bitMono) {
248 EXPECT_TRUE(DecodeSingleFrame(
249 ReadTestDataFile("av1-monochrome-I-frame-320x240-10bpp"))
251 ASSERT_EQ(1U, output_frames_.size());
253 const auto& frame = output_frames_.front();
254 EXPECT_EQ(PIXEL_FORMAT_YUV420P10, frame->format());
255 EXPECT_EQ(frame->data(VideoFrame::kUPlane), frame->data(VideoFrame::kVPlane));
256 EXPECT_EQ("026c1fed9e161f09d816ac7278458a80", GetVideoFrameHash(*frame));
259 TEST_F(Dav1dVideoDecoderTest, DecodeFrame_12bitMono) {
261 EXPECT_TRUE(DecodeSingleFrame(
262 ReadTestDataFile("av1-monochrome-I-frame-320x240-12bpp"))
264 ASSERT_EQ(1U, output_frames_.size());
266 const auto& frame = output_frames_.front();
267 EXPECT_EQ(PIXEL_FORMAT_YUV420P12, frame->format());
268 EXPECT_EQ(frame->data(VideoFrame::kUPlane), frame->data(VideoFrame::kVPlane));
269 EXPECT_EQ("32115092dc00fbe86823b0b714a0f63e", GetVideoFrameHash(*frame));
272 // Decode |i_frame_buffer_| and then a frame with a larger width and verify
273 // the output size was adjusted.
274 TEST_F(Dav1dVideoDecoderTest, DecodeFrame_LargerWidth) {
275 DecodeIFrameThenTestFile("av1-I-frame-1280x720", gfx::Size(1280, 720));
278 // Decode a VP9 frame which should trigger a decoder error.
279 TEST_F(Dav1dVideoDecoderTest, DecodeFrame_Error) {
281 EXPECT_MEDIA_LOG(ContainsDecoderErrorLog());
282 DecodeSingleFrame(ReadTestDataFile("vp9-I-frame-320x240"));
285 // Test resetting when decoder has initialized but not decoded.
286 TEST_F(Dav1dVideoDecoderTest, Reset_Initialized) {
291 // Test resetting when decoder has decoded single frame.
292 TEST_F(Dav1dVideoDecoderTest, Reset_Decoding) {
294 ExpectDecodingState();
298 // Test resetting when decoder has hit end of stream.
299 TEST_F(Dav1dVideoDecoderTest, Reset_EndOfStream) {
301 ExpectDecodingState();
302 ExpectEndOfStreamState();
306 // Test destruction when decoder has initialized but not decoded.
307 TEST_F(Dav1dVideoDecoderTest, Destroy_Initialized) {
312 // Test destruction when decoder has decoded single frame.
313 TEST_F(Dav1dVideoDecoderTest, Destroy_Decoding) {
315 ExpectDecodingState();
319 // Test destruction when decoder has hit end of stream.
320 TEST_F(Dav1dVideoDecoderTest, Destroy_EndOfStream) {
322 ExpectDecodingState();
323 ExpectEndOfStreamState();
327 TEST_F(Dav1dVideoDecoderTest, FrameValidAfterPoolDestruction) {
329 Decode(i_frame_buffer_);
332 ASSERT_FALSE(output_frames_.empty());
334 // Write to the Y plane. The memory tools should detect a
335 // use-after-free if the storage was actually removed by pool destruction.
336 memset(output_frames_.front()->writable_data(VideoFrame::kYPlane), 0xff,
337 output_frames_.front()->rows(VideoFrame::kYPlane) *
338 output_frames_.front()->stride(VideoFrame::kYPlane));