1 // Copyright 2017 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/callback_helpers.h"
11 #include "base/run_loop.h"
12 #include "base/test/task_environment.h"
13 #include "build/build_config.h"
14 #include "media/base/decoder_buffer.h"
15 #include "media/base/limits.h"
16 #include "media/base/test_data_util.h"
17 #include "media/base/test_helpers.h"
18 #include "media/base/video_frame.h"
19 #include "media/ffmpeg/ffmpeg_common.h"
20 #include "media/filters/in_memory_url_protocol.h"
21 #include "media/filters/vpx_video_decoder.h"
22 #include "testing/gmock/include/gmock/gmock.h"
28 class VpxVideoDecoderTest : public testing::Test {
31 : decoder_(new VpxVideoDecoder()),
32 i_frame_buffer_(ReadTestDataFile("vp9-I-frame-320x240")) {}
34 VpxVideoDecoderTest(const VpxVideoDecoderTest&) = delete;
35 VpxVideoDecoderTest& operator=(const VpxVideoDecoderTest&) = delete;
37 ~VpxVideoDecoderTest() override { Destroy(); }
40 InitializeWithConfig(TestVideoConfig::Normal(VideoCodec::kVP9));
43 void InitializeWithConfigWithResult(const VideoDecoderConfig& config,
45 decoder_->Initialize(config, false, nullptr,
47 [](bool success, DecoderStatus status) {
48 EXPECT_EQ(status.is_ok(), success);
51 base::BindRepeating(&VpxVideoDecoderTest::FrameReady,
52 base::Unretained(this)),
53 base::NullCallback());
54 base::RunLoop().RunUntilIdle();
57 void InitializeWithConfig(const VideoDecoderConfig& config) {
58 InitializeWithConfigWithResult(config, true);
62 InitializeWithConfig(TestVideoConfig::Large(VideoCodec::kVP9));
66 decoder_->Reset(NewExpectedClosure());
67 base::RunLoop().RunUntilIdle();
72 base::RunLoop().RunUntilIdle();
75 // Sets up expectations and actions to put VpxVideoDecoder in an active
77 void ExpectDecodingState() {
78 EXPECT_TRUE(DecodeSingleFrame(i_frame_buffer_).is_ok());
79 ASSERT_EQ(1U, output_frames_.size());
82 // Sets up expectations and actions to put VpxVideoDecoder in an end
84 void ExpectEndOfStreamState() {
85 EXPECT_TRUE(DecodeSingleFrame(DecoderBuffer::CreateEOSBuffer()).is_ok());
86 ASSERT_FALSE(output_frames_.empty());
89 using InputBuffers = std::vector<scoped_refptr<DecoderBuffer>>;
90 using OutputFrames = std::vector<scoped_refptr<VideoFrame>>;
92 // Decodes all buffers in |input_buffers| and push all successfully decoded
93 // output frames into |output_frames|.
94 // Returns the last decode status returned by the decoder.
95 DecoderStatus DecodeMultipleFrames(const InputBuffers& input_buffers) {
96 for (auto iter = input_buffers.begin(); iter != input_buffers.end();
98 DecoderStatus status = Decode(*iter);
99 switch (status.code()) {
100 case DecoderStatus::Codes::kOk:
102 case DecoderStatus::Codes::kAborted:
106 DCHECK(output_frames_.empty());
110 return DecoderStatus::Codes::kOk;
113 // Decodes the single compressed frame in |buffer| and writes the
114 // uncompressed output to |video_frame|. This method works with single
115 // and multithreaded decoders. End of stream buffers are used to trigger
116 // the frame to be returned in the multithreaded decoder case.
117 DecoderStatus DecodeSingleFrame(scoped_refptr<DecoderBuffer> buffer) {
118 InputBuffers input_buffers;
119 input_buffers.push_back(std::move(buffer));
120 input_buffers.push_back(DecoderBuffer::CreateEOSBuffer());
122 return DecodeMultipleFrames(input_buffers);
125 // Decodes |i_frame_buffer_| and then decodes the data contained in
126 // the file named |test_file_name|. This function expects both buffers
127 // to decode to frames that are the same size.
128 void DecodeIFrameThenTestFile(const std::string& test_file_name,
129 const gfx::Size& expected_size) {
131 scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(test_file_name);
133 InputBuffers input_buffers;
134 input_buffers.push_back(i_frame_buffer_);
135 input_buffers.push_back(buffer);
136 input_buffers.push_back(DecoderBuffer::CreateEOSBuffer());
138 DecoderStatus status = DecodeMultipleFrames(input_buffers);
140 EXPECT_TRUE(status.is_ok());
141 ASSERT_EQ(2U, output_frames_.size());
143 gfx::Size original_size = TestVideoConfig::NormalCodedSize();
144 EXPECT_EQ(original_size.width(),
145 output_frames_[0]->visible_rect().size().width());
146 EXPECT_EQ(original_size.height(),
147 output_frames_[0]->visible_rect().size().height());
148 EXPECT_EQ(expected_size.width(),
149 output_frames_[1]->visible_rect().size().width());
150 EXPECT_EQ(expected_size.height(),
151 output_frames_[1]->visible_rect().size().height());
154 DecoderStatus Decode(scoped_refptr<DecoderBuffer> buffer) {
155 DecoderStatus status;
156 EXPECT_CALL(*this, DecodeDone(_)).WillOnce(testing::SaveArg<0>(&status));
158 decoder_->Decode(std::move(buffer),
159 base::BindOnce(&VpxVideoDecoderTest::DecodeDone,
160 base::Unretained(this)));
161 base::RunLoop().RunUntilIdle();
166 void FrameReady(scoped_refptr<VideoFrame> frame) {
167 DCHECK(!frame->metadata().end_of_stream);
168 output_frames_.push_back(std::move(frame));
171 MOCK_METHOD1(DecodeDone, void(DecoderStatus));
173 base::test::TaskEnvironment task_env_;
174 std::unique_ptr<VideoDecoder> decoder_;
176 scoped_refptr<DecoderBuffer> i_frame_buffer_;
177 OutputFrames output_frames_;
180 TEST_F(VpxVideoDecoderTest, Initialize_Normal) {
184 TEST_F(VpxVideoDecoderTest, Reinitialize_AfterReset) {
186 ExpectDecodingState();
191 TEST_F(VpxVideoDecoderTest, DecodeFrame_Normal) {
194 // Simulate decoding a single frame.
195 EXPECT_TRUE(DecodeSingleFrame(i_frame_buffer_).is_ok());
196 ASSERT_EQ(1U, output_frames_.size());
199 TEST_F(VpxVideoDecoderTest, DecodeFrame_OOM) {
201 static_cast<VpxVideoDecoder*>(decoder_.get())
202 ->force_allocation_error_for_testing();
203 EXPECT_FALSE(DecodeSingleFrame(i_frame_buffer_).is_ok());
204 EXPECT_TRUE(output_frames_.empty());
207 // Decode |i_frame_buffer_| and then a frame with a larger width and verify
208 // the output size was adjusted.
209 TEST_F(VpxVideoDecoderTest, DecodeFrame_LargerWidth) {
210 DecodeIFrameThenTestFile("vp9-I-frame-1280x720", gfx::Size(1280, 720));
213 // Decode |i_frame_buffer_| and then a frame with a larger width and verify
214 // the output size was adjusted.
215 TEST_F(VpxVideoDecoderTest, Offloaded_DecodeFrame_LargerWidth) {
216 decoder_ = std::make_unique<OffloadingVpxVideoDecoder>();
217 DecodeIFrameThenTestFile("vp9-I-frame-1280x720", gfx::Size(1280, 720));
220 // Test resetting when decoder has initialized but not decoded.
221 TEST_F(VpxVideoDecoderTest, Reset_Initialized) {
226 // Test resetting when decoder has decoded single frame.
227 TEST_F(VpxVideoDecoderTest, Reset_Decoding) {
229 ExpectDecodingState();
233 // Test resetting when decoder has hit end of stream.
234 TEST_F(VpxVideoDecoderTest, Reset_EndOfStream) {
236 ExpectDecodingState();
237 ExpectEndOfStreamState();
241 // Test destruction when decoder has initialized but not decoded.
242 TEST_F(VpxVideoDecoderTest, Destroy_Initialized) {
247 // Test destruction when decoder has decoded single frame.
248 TEST_F(VpxVideoDecoderTest, Destroy_Decoding) {
250 ExpectDecodingState();
254 // Test destruction when decoder has hit end of stream.
255 TEST_F(VpxVideoDecoderTest, Destroy_EndOfStream) {
257 ExpectDecodingState();
258 ExpectEndOfStreamState();
262 TEST_F(VpxVideoDecoderTest, SimpleFrameReuse) {
264 Decode(i_frame_buffer_);
266 ASSERT_EQ(1u, output_frames_.size());
267 scoped_refptr<VideoFrame> frame = std::move(output_frames_.front());
268 const uint8_t* old_y_data = frame->data(VideoFrame::kYPlane);
269 output_frames_.pop_back();
271 // Clear frame reference to return the frame to the pool.
274 // Since we're decoding I-frames which are marked as having dependent frames,
275 // libvpx will still have a ref on the previous buffer. So verify we see an
276 // increase to two frames.
277 Decode(i_frame_buffer_);
278 EXPECT_NE(old_y_data, output_frames_.front()->data(VideoFrame::kYPlane));
280 // Issuing another decode should reuse the first buffer now that the refs have
281 // been dropped by the previous decode.
282 Decode(i_frame_buffer_);
284 ASSERT_EQ(2u, output_frames_.size());
285 EXPECT_EQ(old_y_data, output_frames_.back()->data(VideoFrame::kYPlane));
288 TEST_F(VpxVideoDecoderTest, SimpleFormatChange) {
289 scoped_refptr<DecoderBuffer> large_frame =
290 ReadTestDataFile("vp9-I-frame-1280x720");
293 Decode(i_frame_buffer_);
294 Decode(i_frame_buffer_);
295 output_frames_.clear();
296 base::RunLoop().RunUntilIdle();
300 TEST_F(VpxVideoDecoderTest, FrameValidAfterPoolDestruction) {
302 Decode(i_frame_buffer_);
305 // Write to the Y plane. The memory tools should detect a
306 // use-after-free if the storage was actually removed by pool destruction.
307 memset(output_frames_.front()->writable_data(VideoFrame::kYPlane), 0xff,
308 output_frames_.front()->rows(VideoFrame::kYPlane) *
309 output_frames_.front()->stride(VideoFrame::kYPlane));
312 // The test stream uses profile 2, which needs high bit depth support in libvpx.
313 // On ARM we fail to decode the final, duplicate frame, so there is no point in
314 // running this test (https://crbug.com/864458).
315 #if !defined(LIBVPX_NO_HIGH_BIT_DEPTH) && !defined(ARCH_CPU_ARM_FAMILY)
316 TEST_F(VpxVideoDecoderTest, MemoryPoolAllowsMultipleDisplay) {
317 // Initialize with dummy data, we could read it from the test clip, but it's
318 // not necessary for this test.
321 scoped_refptr<DecoderBuffer> data =
322 ReadTestDataFile("vp9-duplicate-frame.webm");
323 InMemoryUrlProtocol protocol(data->data(), data->data_size(), false);
324 FFmpegGlue glue(&protocol);
325 ASSERT_TRUE(glue.OpenContext());
327 AVPacket packet = {};
328 while (av_read_frame(glue.format_context(), &packet) >= 0) {
329 DecoderStatus decode_status =
330 Decode(DecoderBuffer::CopyFrom(packet.data, packet.size));
331 av_packet_unref(&packet);
332 if (!decode_status.is_ok())
336 ASSERT_EQ(output_frames_.size(), 26u);
338 // The final frame is a duplicate of the third-from-final one.
339 scoped_refptr<VideoFrame> last_frame = output_frames_[25];
340 scoped_refptr<VideoFrame> dupe_frame = output_frames_[23];
342 EXPECT_EQ(last_frame->data(VideoFrame::kYPlane),
343 dupe_frame->data(VideoFrame::kYPlane));
344 EXPECT_EQ(last_frame->data(VideoFrame::kUPlane),
345 dupe_frame->data(VideoFrame::kUPlane));
346 EXPECT_EQ(last_frame->data(VideoFrame::kVPlane),
347 dupe_frame->data(VideoFrame::kVPlane));
349 // This will release all frames held by the memory pool, but should not
350 // release |last_frame| since we still have a ref despite sharing the same
351 // memory as |dupe_frame|.
352 output_frames_.clear();
353 dupe_frame = nullptr;
356 // ASAN will be very unhappy with this line if the above is incorrect.
357 memset(last_frame->writable_data(VideoFrame::kYPlane), 0,
358 last_frame->row_bytes(VideoFrame::kYPlane));
360 #endif // !defined(LIBVPX_NO_HIGH_BIT_DEPTH) && !defined(ARCH_CPU_ARM_FAMILY)