Upload upstream chromium 108.0.5359.1
[platform/framework/web/chromium-efl.git] / media / filters / vpx_video_decoder_unittest.cc
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.
4
5 #include <memory>
6 #include <string>
7 #include <vector>
8
9 #include "base/bind.h"
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"
23
24 using ::testing::_;
25
26 namespace media {
27
28 class VpxVideoDecoderTest : public testing::Test {
29  public:
30   VpxVideoDecoderTest()
31       : decoder_(new VpxVideoDecoder()),
32         i_frame_buffer_(ReadTestDataFile("vp9-I-frame-320x240")) {}
33
34   VpxVideoDecoderTest(const VpxVideoDecoderTest&) = delete;
35   VpxVideoDecoderTest& operator=(const VpxVideoDecoderTest&) = delete;
36
37   ~VpxVideoDecoderTest() override { Destroy(); }
38
39   void Initialize() {
40     InitializeWithConfig(TestVideoConfig::Normal(VideoCodec::kVP9));
41   }
42
43   void InitializeWithConfigWithResult(const VideoDecoderConfig& config,
44                                       bool success) {
45     decoder_->Initialize(config, false, nullptr,
46                          base::BindOnce(
47                              [](bool success, DecoderStatus status) {
48                                EXPECT_EQ(status.is_ok(), success);
49                              },
50                              success),
51                          base::BindRepeating(&VpxVideoDecoderTest::FrameReady,
52                                              base::Unretained(this)),
53                          base::NullCallback());
54     base::RunLoop().RunUntilIdle();
55   }
56
57   void InitializeWithConfig(const VideoDecoderConfig& config) {
58     InitializeWithConfigWithResult(config, true);
59   }
60
61   void Reinitialize() {
62     InitializeWithConfig(TestVideoConfig::Large(VideoCodec::kVP9));
63   }
64
65   void Reset() {
66     decoder_->Reset(NewExpectedClosure());
67     base::RunLoop().RunUntilIdle();
68   }
69
70   void Destroy() {
71     decoder_.reset();
72     base::RunLoop().RunUntilIdle();
73   }
74
75   // Sets up expectations and actions to put VpxVideoDecoder in an active
76   // decoding state.
77   void ExpectDecodingState() {
78     EXPECT_TRUE(DecodeSingleFrame(i_frame_buffer_).is_ok());
79     ASSERT_EQ(1U, output_frames_.size());
80   }
81
82   // Sets up expectations and actions to put VpxVideoDecoder in an end
83   // of stream state.
84   void ExpectEndOfStreamState() {
85     EXPECT_TRUE(DecodeSingleFrame(DecoderBuffer::CreateEOSBuffer()).is_ok());
86     ASSERT_FALSE(output_frames_.empty());
87   }
88
89   using InputBuffers = std::vector<scoped_refptr<DecoderBuffer>>;
90   using OutputFrames = std::vector<scoped_refptr<VideoFrame>>;
91
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();
97          ++iter) {
98       DecoderStatus status = Decode(*iter);
99       switch (status.code()) {
100         case DecoderStatus::Codes::kOk:
101           break;
102         case DecoderStatus::Codes::kAborted:
103           NOTREACHED();
104           [[fallthrough]];
105         default:
106           DCHECK(output_frames_.empty());
107           return status;
108       }
109     }
110     return DecoderStatus::Codes::kOk;
111   }
112
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());
121
122     return DecodeMultipleFrames(input_buffers);
123   }
124
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) {
130     Initialize();
131     scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(test_file_name);
132
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());
137
138     DecoderStatus status = DecodeMultipleFrames(input_buffers);
139
140     EXPECT_TRUE(status.is_ok());
141     ASSERT_EQ(2U, output_frames_.size());
142
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());
152   }
153
154   DecoderStatus Decode(scoped_refptr<DecoderBuffer> buffer) {
155     DecoderStatus status;
156     EXPECT_CALL(*this, DecodeDone(_)).WillOnce(testing::SaveArg<0>(&status));
157
158     decoder_->Decode(std::move(buffer),
159                      base::BindOnce(&VpxVideoDecoderTest::DecodeDone,
160                                     base::Unretained(this)));
161     base::RunLoop().RunUntilIdle();
162
163     return status;
164   }
165
166   void FrameReady(scoped_refptr<VideoFrame> frame) {
167     DCHECK(!frame->metadata().end_of_stream);
168     output_frames_.push_back(std::move(frame));
169   }
170
171   MOCK_METHOD1(DecodeDone, void(DecoderStatus));
172
173   base::test::TaskEnvironment task_env_;
174   std::unique_ptr<VideoDecoder> decoder_;
175
176   scoped_refptr<DecoderBuffer> i_frame_buffer_;
177   OutputFrames output_frames_;
178 };
179
180 TEST_F(VpxVideoDecoderTest, Initialize_Normal) {
181   Initialize();
182 }
183
184 TEST_F(VpxVideoDecoderTest, Reinitialize_AfterReset) {
185   Initialize();
186   ExpectDecodingState();
187   Reset();
188   Reinitialize();
189 }
190
191 TEST_F(VpxVideoDecoderTest, DecodeFrame_Normal) {
192   Initialize();
193
194   // Simulate decoding a single frame.
195   EXPECT_TRUE(DecodeSingleFrame(i_frame_buffer_).is_ok());
196   ASSERT_EQ(1U, output_frames_.size());
197 }
198
199 TEST_F(VpxVideoDecoderTest, DecodeFrame_OOM) {
200   Initialize();
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());
205 }
206
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));
211 }
212
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));
218 }
219
220 // Test resetting when decoder has initialized but not decoded.
221 TEST_F(VpxVideoDecoderTest, Reset_Initialized) {
222   Initialize();
223   Reset();
224 }
225
226 // Test resetting when decoder has decoded single frame.
227 TEST_F(VpxVideoDecoderTest, Reset_Decoding) {
228   Initialize();
229   ExpectDecodingState();
230   Reset();
231 }
232
233 // Test resetting when decoder has hit end of stream.
234 TEST_F(VpxVideoDecoderTest, Reset_EndOfStream) {
235   Initialize();
236   ExpectDecodingState();
237   ExpectEndOfStreamState();
238   Reset();
239 }
240
241 // Test destruction when decoder has initialized but not decoded.
242 TEST_F(VpxVideoDecoderTest, Destroy_Initialized) {
243   Initialize();
244   Destroy();
245 }
246
247 // Test destruction when decoder has decoded single frame.
248 TEST_F(VpxVideoDecoderTest, Destroy_Decoding) {
249   Initialize();
250   ExpectDecodingState();
251   Destroy();
252 }
253
254 // Test destruction when decoder has hit end of stream.
255 TEST_F(VpxVideoDecoderTest, Destroy_EndOfStream) {
256   Initialize();
257   ExpectDecodingState();
258   ExpectEndOfStreamState();
259   Destroy();
260 }
261
262 TEST_F(VpxVideoDecoderTest, SimpleFrameReuse) {
263   Initialize();
264   Decode(i_frame_buffer_);
265
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();
270
271   // Clear frame reference to return the frame to the pool.
272   frame = nullptr;
273
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));
279
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_);
283
284   ASSERT_EQ(2u, output_frames_.size());
285   EXPECT_EQ(old_y_data, output_frames_.back()->data(VideoFrame::kYPlane));
286 }
287
288 TEST_F(VpxVideoDecoderTest, SimpleFormatChange) {
289   scoped_refptr<DecoderBuffer> large_frame =
290       ReadTestDataFile("vp9-I-frame-1280x720");
291
292   Initialize();
293   Decode(i_frame_buffer_);
294   Decode(i_frame_buffer_);
295   output_frames_.clear();
296   base::RunLoop().RunUntilIdle();
297   Decode(large_frame);
298 }
299
300 TEST_F(VpxVideoDecoderTest, FrameValidAfterPoolDestruction) {
301   Initialize();
302   Decode(i_frame_buffer_);
303   Destroy();
304
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));
310 }
311
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.
319   Initialize();
320
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());
326
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())
333       break;
334   }
335
336   ASSERT_EQ(output_frames_.size(), 26u);
337
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];
341
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));
348
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;
354   Destroy();
355
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));
359 }
360 #endif  // !defined(LIBVPX_NO_HIGH_BIT_DEPTH) && !defined(ARCH_CPU_ARM_FAMILY)
361
362 }  // namespace media