Revert "[M120 Migration]Fix for crash during chrome exit"
[platform/framework/web/chromium-efl.git] / media / filters / ffmpeg_video_decoder_unittest.cc
1 // Copyright 2012 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 <stdint.h>
6
7 #include <list>
8 #include <string>
9 #include <vector>
10
11 #include "base/functional/bind.h"
12 #include "base/functional/callback_helpers.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/run_loop.h"
15 #include "base/strings/string_util.h"
16 #include "base/test/gmock_callback_support.h"
17 #include "base/test/task_environment.h"
18 #include "media/base/decoder_buffer.h"
19 #include "media/base/limits.h"
20 #include "media/base/media_log.h"
21 #include "media/base/media_util.h"
22 #include "media/base/mock_filters.h"
23 #include "media/base/mock_media_log.h"
24 #include "media/base/test_data_util.h"
25 #include "media/base/test_helpers.h"
26 #include "media/base/video_decoder.h"
27 #include "media/base/video_frame.h"
28 #include "media/base/video_util.h"
29 #include "media/ffmpeg/ffmpeg_common.h"
30 #include "media/filters/ffmpeg_video_decoder.h"
31 #include "testing/gmock/include/gmock/gmock.h"
32
33 using ::testing::_;
34 using ::testing::AtLeast;
35 using ::testing::AtMost;
36 using ::testing::InSequence;
37 using ::testing::IsNull;
38 using ::testing::Return;
39 using ::testing::SaveArg;
40 using ::testing::StrictMock;
41
42 namespace media {
43
44 constexpr gfx::Size kCodedSize(320, 180);
45 constexpr gfx::Rect kVisibleRect(kCodedSize);
46 constexpr gfx::Size kNaturalSize = kCodedSize;
47
48 ACTION_P(ReturnBuffer, buffer) {
49   arg0.Run(buffer.get() ? DemuxerStream::kOk : DemuxerStream::kAborted, buffer);
50 }
51
52 MATCHER(ContainsFailedToSendLog, "") {
53   return CONTAINS_STRING(arg, "Failed to send");
54 }
55
56 MATCHER(ContainsFailedToDecode, "") {
57   return CONTAINS_STRING(arg, "failed to decode");
58 }
59
60 class FFmpegVideoDecoderTest : public testing::Test {
61  public:
62   FFmpegVideoDecoderTest()
63       : decoder_(std::make_unique<FFmpegVideoDecoder>(&media_log_)) {
64     // Initialize various test buffers.
65     frame_buffer_ = std::make_unique<uint8_t[]>(kCodedSize.GetArea());
66     end_of_stream_buffer_ = DecoderBuffer::CreateEOSBuffer();
67     i_frame_buffer_ = ReadTestDataFile("h264-320x180-frame-0");
68     corrupt_i_frame_buffer_ = ReadTestDataFile("h264-320x180-frame-0");
69     memset(corrupt_i_frame_buffer_->writable_data(), 0,
70            corrupt_i_frame_buffer_->data_size() / 2);
71   }
72
73   FFmpegVideoDecoderTest(const FFmpegVideoDecoderTest&) = delete;
74   FFmpegVideoDecoderTest& operator=(const FFmpegVideoDecoderTest&) = delete;
75
76   ~FFmpegVideoDecoderTest() override { Destroy(); }
77
78   void Initialize() {
79     InitializeWithConfig(TestVideoConfig::Normal(VideoCodec::kH264));
80   }
81
82   void InitializeWithConfigWithResult(const VideoDecoderConfig& config,
83                                       bool success) {
84     decoder_->Initialize(
85         config, false, nullptr,
86         base::BindOnce(
87             [](bool success, DecoderStatus status) {
88               EXPECT_EQ(status.is_ok(), success);
89             },
90             success),
91         base::BindRepeating(&FFmpegVideoDecoderTest::FrameReady,
92                             base::Unretained(this)),
93         base::NullCallback());
94     base::RunLoop().RunUntilIdle();
95   }
96
97   void InitializeWithConfig(const VideoDecoderConfig& config) {
98     InitializeWithConfigWithResult(config, true);
99   }
100
101   void Reinitialize() {
102     InitializeWithConfig(TestVideoConfig::Large(VideoCodec::kH264));
103   }
104
105   void Reset() {
106     decoder_->Reset(NewExpectedClosure());
107     base::RunLoop().RunUntilIdle();
108   }
109
110   void Destroy() {
111     decoder_.reset();
112     base::RunLoop().RunUntilIdle();
113   }
114
115   // Sets up expectations and actions to put FFmpegVideoDecoder in an active
116   // decoding state.
117   void EnterDecodingState() {
118     EXPECT_TRUE(DecodeSingleFrame(i_frame_buffer_).is_ok());
119     ASSERT_EQ(1U, output_frames_.size());
120   }
121
122   // Sets up expectations and actions to put FFmpegVideoDecoder in an end
123   // of stream state.
124   void EnterEndOfStreamState() {
125     EXPECT_TRUE(DecodeSingleFrame(end_of_stream_buffer_).is_ok());
126     ASSERT_FALSE(output_frames_.empty());
127   }
128
129   typedef std::vector<scoped_refptr<DecoderBuffer> > InputBuffers;
130   typedef std::vector<scoped_refptr<VideoFrame> > OutputFrames;
131
132   // Decodes all buffers in |input_buffers| and push all successfully decoded
133   // output frames into |output_frames|.
134   // Returns the last decode status returned by the decoder.
135   DecoderStatus DecodeMultipleFrames(const InputBuffers& input_buffers) {
136     for (auto iter = input_buffers.begin(); iter != input_buffers.end();
137          ++iter) {
138       DecoderStatus status = Decode(*iter);
139       switch (status.code()) {
140         case DecoderStatus::Codes::kOk:
141           break;
142         case DecoderStatus::Codes::kAborted:
143           NOTREACHED();
144           [[fallthrough]];
145         default:
146           DCHECK(output_frames_.empty());
147           return status;
148       }
149     }
150     return DecoderStatus::Codes::kOk;
151   }
152
153   // Decodes the single compressed frame in |buffer| and writes the
154   // uncompressed output to |video_frame|. This method works with single
155   // and multithreaded decoders. End of stream buffers are used to trigger
156   // the frame to be returned in the multithreaded decoder case.
157   DecoderStatus DecodeSingleFrame(scoped_refptr<DecoderBuffer> buffer) {
158     InputBuffers input_buffers;
159     input_buffers.push_back(buffer);
160     input_buffers.push_back(end_of_stream_buffer_);
161
162     return DecodeMultipleFrames(input_buffers);
163   }
164
165   // Decodes |i_frame_buffer_| and then decodes the data contained in
166   // the file named |test_file_name|. This function expects both buffers
167   // to decode to frames that are the same size.
168   void DecodeIFrameThenTestFile(const std::string& test_file_name,
169                                 int expected_width,
170                                 int expected_height,
171                                 size_t expected_frames = 2u) {
172     Initialize();
173     scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(test_file_name);
174
175     InputBuffers input_buffers;
176     input_buffers.push_back(i_frame_buffer_);
177     input_buffers.push_back(buffer);
178     input_buffers.push_back(end_of_stream_buffer_);
179
180     DecoderStatus status = DecodeMultipleFrames(input_buffers);
181
182     EXPECT_TRUE(status.is_ok());
183     ASSERT_EQ(expected_frames, output_frames_.size());
184
185     gfx::Size original_size = kVisibleRect.size();
186     EXPECT_EQ(original_size.width(),
187               output_frames_[0]->visible_rect().size().width());
188     EXPECT_EQ(original_size.height(),
189               output_frames_[0]->visible_rect().size().height());
190     EXPECT_EQ(expected_width,
191               output_frames_[1]->visible_rect().size().width());
192     EXPECT_EQ(expected_height,
193               output_frames_[1]->visible_rect().size().height());
194   }
195
196   DecoderStatus Decode(scoped_refptr<DecoderBuffer> buffer) {
197     DecoderStatus status;
198     EXPECT_CALL(*this, DecodeDone(_)).WillOnce(SaveArg<0>(&status));
199
200     decoder_->Decode(buffer, base::BindOnce(&FFmpegVideoDecoderTest::DecodeDone,
201                                             base::Unretained(this)));
202
203     base::RunLoop().RunUntilIdle();
204
205     return status;
206   }
207
208   void FrameReady(scoped_refptr<VideoFrame> frame) {
209     DCHECK(!frame->metadata().end_of_stream);
210     output_frames_.push_back(std::move(frame));
211   }
212
213   MOCK_METHOD1(DecodeDone, void(DecoderStatus));
214
215   StrictMock<MockMediaLog> media_log_;
216
217   base::test::SingleThreadTaskEnvironment task_environment_;
218   std::unique_ptr<FFmpegVideoDecoder> decoder_;
219
220   // Various buffers for testing.
221   std::unique_ptr<uint8_t[]> frame_buffer_;
222   scoped_refptr<DecoderBuffer> end_of_stream_buffer_;
223   scoped_refptr<DecoderBuffer> i_frame_buffer_;
224   scoped_refptr<DecoderBuffer> corrupt_i_frame_buffer_;
225
226   OutputFrames output_frames_;
227 };
228
229 TEST_F(FFmpegVideoDecoderTest, Initialize_Normal) {
230   Initialize();
231 }
232
233 TEST_F(FFmpegVideoDecoderTest, Initialize_OpenDecoderFails) {
234   // Specify Theora w/o extra data so that avcodec_open2() fails.
235   VideoDecoderConfig config(VideoCodec::kTheora, VIDEO_CODEC_PROFILE_UNKNOWN,
236                             VideoDecoderConfig::AlphaMode::kIsOpaque,
237                             VideoColorSpace(), kNoTransformation, kCodedSize,
238                             kVisibleRect, kNaturalSize, EmptyExtraData(),
239                             EncryptionScheme::kUnencrypted);
240   InitializeWithConfigWithResult(config, false);
241 }
242
243 TEST_F(FFmpegVideoDecoderTest, Reinitialize_Normal) {
244   Initialize();
245   Reinitialize();
246 }
247
248 TEST_F(FFmpegVideoDecoderTest, Reinitialize_AfterDecodeFrame) {
249   Initialize();
250   EnterDecodingState();
251   Reinitialize();
252 }
253
254 TEST_F(FFmpegVideoDecoderTest, Reinitialize_AfterReset) {
255   Initialize();
256   EnterDecodingState();
257   Reset();
258   Reinitialize();
259 }
260
261 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_Normal) {
262   Initialize();
263
264   // Simulate decoding a single frame.
265   EXPECT_TRUE(DecodeSingleFrame(i_frame_buffer_).is_ok());
266   ASSERT_EQ(1U, output_frames_.size());
267 }
268
269 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_OOM) {
270   Initialize();
271   decoder_->force_allocation_error_for_testing();
272   EXPECT_MEDIA_LOG(_);
273   EXPECT_FALSE(DecodeSingleFrame(i_frame_buffer_).is_ok());
274   EXPECT_TRUE(output_frames_.empty());
275 }
276
277 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_DecodeError) {
278   Initialize();
279
280   EXPECT_MEDIA_LOG(ContainsFailedToSendLog());
281
282   // The error is only raised on the second decode attempt, so we expect at
283   // least one successful decode but we don't expect valid frame to be decoded.
284   // During the second decode attempt an error is raised.
285   EXPECT_TRUE(Decode(corrupt_i_frame_buffer_).is_ok());
286   EXPECT_TRUE(output_frames_.empty());
287   EXPECT_THAT(Decode(i_frame_buffer_), IsDecodeErrorStatus());
288   EXPECT_TRUE(output_frames_.empty());
289
290   // After a decode error occurred, all following decodes will return
291   // DecoderStatus::Codes::kFailed.
292   EXPECT_THAT(Decode(i_frame_buffer_), IsDecodeErrorStatus());
293   EXPECT_TRUE(output_frames_.empty());
294 }
295
296 // A corrupt frame followed by an EOS buffer should raise a decode error.
297 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_DecodeErrorAtEndOfStream) {
298   Initialize();
299
300   EXPECT_MEDIA_LOG(ContainsFailedToDecode());
301
302   EXPECT_THAT(DecodeSingleFrame(corrupt_i_frame_buffer_),
303               IsDecodeErrorStatus());
304 }
305
306 // Decode |i_frame_buffer_| and then a smaller frame and verify the output size
307 // was adjusted.
308 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_Smaller) {
309   DecodeIFrameThenTestFile("red-green.h264", 80, 128, /*expected_frames=*/4);
310 }
311
312 // Decode |i_frame_buffer_| and then a larger frame and verify the output size
313 // was adjusted.
314 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_Larger) {
315   DecodeIFrameThenTestFile("bear-320x192-baseline-frame-0.h264", 320, 192);
316 }
317
318 // Test resetting when decoder has initialized but not decoded.
319 TEST_F(FFmpegVideoDecoderTest, Reset_Initialized) {
320   Initialize();
321   Reset();
322 }
323
324 // Test resetting when decoder has decoded single frame.
325 TEST_F(FFmpegVideoDecoderTest, Reset_Decoding) {
326   Initialize();
327   EnterDecodingState();
328   Reset();
329 }
330
331 // Test resetting when decoder has hit end of stream.
332 TEST_F(FFmpegVideoDecoderTest, Reset_EndOfStream) {
333   Initialize();
334   EnterDecodingState();
335   EnterEndOfStreamState();
336   Reset();
337 }
338
339 // Test destruction when decoder has initialized but not decoded.
340 TEST_F(FFmpegVideoDecoderTest, Destroy_Initialized) {
341   Initialize();
342   Destroy();
343 }
344
345 // Test destruction when decoder has decoded single frame.
346 TEST_F(FFmpegVideoDecoderTest, Destroy_Decoding) {
347   Initialize();
348   EnterDecodingState();
349   Destroy();
350 }
351
352 // Test destruction when decoder has hit end of stream.
353 TEST_F(FFmpegVideoDecoderTest, Destroy_EndOfStream) {
354   Initialize();
355   EnterDecodingState();
356   EnterEndOfStreamState();
357   Destroy();
358 }
359
360 }  // namespace media