1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 <string> 6 #include <vector> 7 8 #include "base/bind.h" 9 #include "base/callback_helpers.h" 10 #include "base/memory/singleton.h" 11 #include "base/message_loop/message_loop.h" 12 #include "base/strings/string_util.h" 13 #include "media/base/decoder_buffer.h" 14 #include "media/base/gmock_callback_support.h" 15 #include "media/base/limits.h" 16 #include "media/base/mock_filters.h" 17 #include "media/base/test_data_util.h" 18 #include "media/base/test_helpers.h" 19 #include "media/base/video_decoder.h" 20 #include "media/base/video_frame.h" 21 #include "media/base/video_util.h" 22 #include "media/ffmpeg/ffmpeg_common.h" 23 #include "media/filters/ffmpeg_glue.h" 24 #include "media/filters/ffmpeg_video_decoder.h" 25 #include "testing/gmock/include/gmock/gmock.h" 26 27 using ::testing::_; 28 using ::testing::AtLeast; 29 using ::testing::InSequence; 30 using ::testing::IsNull; 31 using ::testing::Return; 32 using ::testing::SaveArg; 33 using ::testing::StrictMock; 34 35 namespace media { 36 37 static const VideoFrame::Format kVideoFormat = VideoFrame::YV12; 38 static const gfx::Size kCodedSize(320, 240); 39 static const gfx::Rect kVisibleRect(320, 240); 40 static const gfx::Size kNaturalSize(320, 240); 41 42 ACTION_P(ReturnBuffer, buffer) { 43 arg0.Run(buffer.get() ? DemuxerStream::kOk : DemuxerStream::kAborted, buffer); 44 } 45 46 class FFmpegVideoDecoderTest : public testing::Test { 47 public: 48 FFmpegVideoDecoderTest() 49 : decoder_(new FFmpegVideoDecoder(message_loop_.message_loop_proxy())), 50 decode_cb_(base::Bind(&FFmpegVideoDecoderTest::FrameReady, 51 base::Unretained(this))) { 52 FFmpegGlue::InitializeFFmpeg(); 53 54 // Initialize various test buffers. 55 frame_buffer_.reset(new uint8[kCodedSize.GetArea()]); 56 end_of_stream_buffer_ = DecoderBuffer::CreateEOSBuffer(); 57 i_frame_buffer_ = ReadTestDataFile("vp8-I-frame-320x240"); 58 corrupt_i_frame_buffer_ = ReadTestDataFile("vp8-corrupt-I-frame"); 59 } 60 61 virtual ~FFmpegVideoDecoderTest() { 62 Stop(); 63 } 64 65 void Initialize() { 66 InitializeWithConfig(TestVideoConfig::Normal()); 67 } 68 69 void InitializeWithConfigAndStatus(const VideoDecoderConfig& config, 70 PipelineStatus status) { 71 decoder_->Initialize(config, NewExpectedStatusCB(status)); 72 message_loop_.RunUntilIdle(); 73 } 74 75 void InitializeWithConfig(const VideoDecoderConfig& config) { 76 InitializeWithConfigAndStatus(config, PIPELINE_OK); 77 } 78 79 void Reinitialize() { 80 InitializeWithConfig(TestVideoConfig::Large()); 81 } 82 83 void Reset() { 84 decoder_->Reset(NewExpectedClosure()); 85 message_loop_.RunUntilIdle(); 86 } 87 88 void Stop() { 89 decoder_->Stop(NewExpectedClosure()); 90 message_loop_.RunUntilIdle(); 91 } 92 93 // Sets up expectations and actions to put FFmpegVideoDecoder in an active 94 // decoding state. 95 void EnterDecodingState() { 96 VideoDecoder::Status status; 97 scoped_refptr<VideoFrame> video_frame; 98 DecodeSingleFrame(i_frame_buffer_, &status, &video_frame); 99 100 EXPECT_EQ(VideoDecoder::kOk, status); 101 ASSERT_TRUE(video_frame.get()); 102 EXPECT_FALSE(video_frame->end_of_stream()); 103 } 104 105 // Sets up expectations and actions to put FFmpegVideoDecoder in an end 106 // of stream state. 107 void EnterEndOfStreamState() { 108 VideoDecoder::Status status; 109 scoped_refptr<VideoFrame> video_frame; 110 DecodeSingleFrame(end_of_stream_buffer_, &status, &video_frame); 111 EXPECT_EQ(VideoDecoder::kOk, status); 112 ASSERT_TRUE(video_frame.get()); 113 EXPECT_TRUE(video_frame->end_of_stream()); 114 } 115 116 typedef std::vector<scoped_refptr<DecoderBuffer> > InputBuffers; 117 typedef std::vector<scoped_refptr<VideoFrame> > OutputFrames; 118 119 // Decodes all buffers in |input_buffers| and push all successfully decoded 120 // output frames (excluding EOS frames) into |output_frames|. 121 // Returns the last decode status returned by the decoder. 122 VideoDecoder::Status DecodeMultipleFrames(const InputBuffers& input_buffers, 123 OutputFrames* output_frames) { 124 InputBuffers::const_iterator input_iter = input_buffers.begin(); 125 126 for (;;) { 127 // Prepare input buffer. 128 scoped_refptr<DecoderBuffer> buffer; 129 if (input_iter != input_buffers.end()) { 130 buffer = *input_iter; 131 ++input_iter; 132 } else { 133 buffer = end_of_stream_buffer_; 134 } 135 136 VideoDecoder::Status status; 137 scoped_refptr<VideoFrame> frame; 138 Decode(buffer, &status, &frame); 139 140 switch (status) { 141 case VideoDecoder::kOk: 142 DCHECK(frame); 143 if (!frame->end_of_stream()) { 144 output_frames->push_back(frame); 145 continue; 146 } else { // EOS 147 return status; 148 } 149 case VideoDecoder::kNotEnoughData: 150 DCHECK(!frame); 151 continue; 152 case VideoDecoder::kDecodeError: 153 case VideoDecoder::kDecryptError: 154 DCHECK(!frame); 155 return status; 156 } 157 } 158 } 159 160 // Decodes the single compressed frame in |buffer| and writes the 161 // uncompressed output to |video_frame|. This method works with single 162 // and multithreaded decoders. End of stream buffers are used to trigger 163 // the frame to be returned in the multithreaded decoder case. 164 void DecodeSingleFrame(const scoped_refptr<DecoderBuffer>& buffer, 165 VideoDecoder::Status* status, 166 scoped_refptr<VideoFrame>* video_frame) { 167 InputBuffers input_buffers; 168 input_buffers.push_back(buffer); 169 170 OutputFrames output_frames; 171 *status = DecodeMultipleFrames(input_buffers, &output_frames); 172 173 if (*status != VideoDecoder::kOk) 174 return; 175 176 ASSERT_LE(output_frames.size(), 1U); 177 if (output_frames.size() == 1U) 178 *video_frame = output_frames[0]; 179 else 180 *video_frame = VideoFrame::CreateEOSFrame(); 181 } 182 183 // Decodes |i_frame_buffer_| and then decodes the data contained in 184 // the file named |test_file_name|. This function expects both buffers 185 // to decode to frames that are the same size. 186 void DecodeIFrameThenTestFile(const std::string& test_file_name, 187 int expected_width, 188 int expected_height) { 189 Initialize(); 190 scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(test_file_name); 191 192 InputBuffers input_buffers; 193 input_buffers.push_back(i_frame_buffer_); 194 input_buffers.push_back(buffer); 195 196 OutputFrames output_frames; 197 VideoDecoder::Status status = 198 DecodeMultipleFrames(input_buffers, &output_frames); 199 200 EXPECT_EQ(VideoDecoder::kOk, status); 201 ASSERT_EQ(2U, output_frames.size()); 202 203 gfx::Size original_size = kVisibleRect.size(); 204 EXPECT_EQ(original_size.width(), 205 output_frames[0]->visible_rect().size().width()); 206 EXPECT_EQ(original_size.height(), 207 output_frames[0]->visible_rect().size().height()); 208 EXPECT_EQ(expected_width, 209 output_frames[1]->visible_rect().size().width()); 210 EXPECT_EQ(expected_height, 211 output_frames[1]->visible_rect().size().height()); 212 } 213 214 void Decode(const scoped_refptr<DecoderBuffer>& buffer, 215 VideoDecoder::Status* status, 216 scoped_refptr<VideoFrame>* video_frame) { 217 EXPECT_CALL(*this, FrameReady(_, _)) 218 .WillOnce(DoAll(SaveArg<0>(status), SaveArg<1>(video_frame))); 219 220 decoder_->Decode(buffer, decode_cb_); 221 222 message_loop_.RunUntilIdle(); 223 } 224 225 MOCK_METHOD2(FrameReady, void(VideoDecoder::Status, 226 const scoped_refptr<VideoFrame>&)); 227 228 base::MessageLoop message_loop_; 229 scoped_ptr<FFmpegVideoDecoder> decoder_; 230 231 VideoDecoder::DecodeCB decode_cb_; 232 233 // Various buffers for testing. 234 scoped_ptr<uint8_t[]> frame_buffer_; 235 scoped_refptr<DecoderBuffer> end_of_stream_buffer_; 236 scoped_refptr<DecoderBuffer> i_frame_buffer_; 237 scoped_refptr<DecoderBuffer> corrupt_i_frame_buffer_; 238 239 private: 240 DISALLOW_COPY_AND_ASSIGN(FFmpegVideoDecoderTest); 241 }; 242 243 TEST_F(FFmpegVideoDecoderTest, Initialize_Normal) { 244 Initialize(); 245 } 246 247 TEST_F(FFmpegVideoDecoderTest, Initialize_UnsupportedDecoder) { 248 // Test avcodec_find_decoder() returning NULL. 249 InitializeWithConfigAndStatus(TestVideoConfig::Invalid(), 250 DECODER_ERROR_NOT_SUPPORTED); 251 } 252 253 TEST_F(FFmpegVideoDecoderTest, Initialize_UnsupportedPixelFormat) { 254 // Ensure decoder handles unsupported pixel formats without crashing. 255 VideoDecoderConfig config(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN, 256 VideoFrame::UNKNOWN, 257 kCodedSize, kVisibleRect, kNaturalSize, 258 NULL, 0, false); 259 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED); 260 } 261 262 TEST_F(FFmpegVideoDecoderTest, Initialize_OpenDecoderFails) { 263 // Specify Theora w/o extra data so that avcodec_open2() fails. 264 VideoDecoderConfig config(kCodecTheora, VIDEO_CODEC_PROFILE_UNKNOWN, 265 kVideoFormat, 266 kCodedSize, kVisibleRect, kNaturalSize, 267 NULL, 0, false); 268 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED); 269 } 270 271 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioNumeratorZero) { 272 gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 0, 1); 273 VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN, 274 kVideoFormat, 275 kCodedSize, kVisibleRect, natural_size, 276 NULL, 0, false); 277 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED); 278 } 279 280 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioDenominatorZero) { 281 gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 1, 0); 282 VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN, 283 kVideoFormat, 284 kCodedSize, kVisibleRect, natural_size, 285 NULL, 0, false); 286 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED); 287 } 288 289 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioNumeratorNegative) { 290 gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), -1, 1); 291 VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN, 292 kVideoFormat, 293 kCodedSize, kVisibleRect, natural_size, 294 NULL, 0, false); 295 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED); 296 } 297 298 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioDenominatorNegative) { 299 gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 1, -1); 300 VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN, 301 kVideoFormat, 302 kCodedSize, kVisibleRect, natural_size, 303 NULL, 0, false); 304 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED); 305 } 306 307 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioNumeratorTooLarge) { 308 int width = kVisibleRect.size().width(); 309 int num = ceil(static_cast<double>(limits::kMaxDimension + 1) / width); 310 gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), num, 1); 311 VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN, 312 kVideoFormat, 313 kCodedSize, kVisibleRect, natural_size, 314 NULL, 0, false); 315 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED); 316 } 317 318 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioDenominatorTooLarge) { 319 int den = kVisibleRect.size().width() + 1; 320 gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 1, den); 321 VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN, 322 kVideoFormat, 323 kCodedSize, kVisibleRect, natural_size, 324 NULL, 0, false); 325 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED); 326 } 327 328 TEST_F(FFmpegVideoDecoderTest, Reinitialize_Normal) { 329 Initialize(); 330 Reinitialize(); 331 } 332 333 TEST_F(FFmpegVideoDecoderTest, Reinitialize_Failure) { 334 Initialize(); 335 InitializeWithConfigAndStatus(TestVideoConfig::Invalid(), 336 DECODER_ERROR_NOT_SUPPORTED); 337 } 338 339 TEST_F(FFmpegVideoDecoderTest, Reinitialize_AfterDecodeFrame) { 340 Initialize(); 341 EnterDecodingState(); 342 Reinitialize(); 343 } 344 345 TEST_F(FFmpegVideoDecoderTest, Reinitialize_AfterReset) { 346 Initialize(); 347 EnterDecodingState(); 348 Reset(); 349 Reinitialize(); 350 } 351 352 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_Normal) { 353 Initialize(); 354 355 // Simulate decoding a single frame. 356 VideoDecoder::Status status; 357 scoped_refptr<VideoFrame> video_frame; 358 DecodeSingleFrame(i_frame_buffer_, &status, &video_frame); 359 360 EXPECT_EQ(VideoDecoder::kOk, status); 361 ASSERT_TRUE(video_frame.get()); 362 EXPECT_FALSE(video_frame->end_of_stream()); 363 } 364 365 // Verify current behavior for 0 byte frames. FFmpeg simply ignores 366 // the 0 byte frames. 367 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_0ByteFrame) { 368 Initialize(); 369 370 scoped_refptr<DecoderBuffer> zero_byte_buffer = new DecoderBuffer(0); 371 372 InputBuffers input_buffers; 373 input_buffers.push_back(i_frame_buffer_); 374 input_buffers.push_back(zero_byte_buffer); 375 input_buffers.push_back(i_frame_buffer_); 376 377 OutputFrames output_frames; 378 VideoDecoder::Status status = 379 DecodeMultipleFrames(input_buffers, &output_frames); 380 381 EXPECT_EQ(VideoDecoder::kOk, status); 382 ASSERT_EQ(2U, output_frames.size()); 383 384 EXPECT_FALSE(output_frames[0]->end_of_stream()); 385 EXPECT_FALSE(output_frames[1]->end_of_stream()); 386 } 387 388 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_DecodeError) { 389 Initialize(); 390 391 VideoDecoder::Status status; 392 scoped_refptr<VideoFrame> frame; 393 394 // The error is only raised on the second decode attempt, so we expect at 395 // least one successful decode but we don't expect valid frame to be decoded. 396 // During the second decode attempt an error is raised. 397 Decode(corrupt_i_frame_buffer_, &status, &frame); 398 DCHECK(!frame); 399 DCHECK_EQ(VideoDecoder::kNotEnoughData, status); 400 Decode(i_frame_buffer_, &status, &frame); 401 DCHECK(!frame); 402 DCHECK_EQ(VideoDecoder::kDecodeError, status); 403 404 // After a decode error occurred, all following decodes will return 405 // kDecodeError. 406 Decode(i_frame_buffer_, &status, &frame); 407 DCHECK(!frame); 408 DCHECK_EQ(VideoDecoder::kDecodeError, status); 409 } 410 411 // Multi-threaded decoders have different behavior than single-threaded 412 // decoders at the end of the stream. Multithreaded decoders hide errors 413 // that happen on the last |codec_context_->thread_count| frames to avoid 414 // prematurely signalling EOS. This test just exposes that behavior so we can 415 // detect if it changes. 416 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_DecodeErrorAtEndOfStream) { 417 Initialize(); 418 419 VideoDecoder::Status status; 420 scoped_refptr<VideoFrame> video_frame; 421 DecodeSingleFrame(corrupt_i_frame_buffer_, &status, &video_frame); 422 423 EXPECT_EQ(VideoDecoder::kOk, status); 424 ASSERT_TRUE(video_frame.get()); 425 EXPECT_TRUE(video_frame->end_of_stream()); 426 } 427 428 // Decode |i_frame_buffer_| and then a frame with a larger width and verify 429 // the output size was adjusted. 430 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_LargerWidth) { 431 DecodeIFrameThenTestFile("vp8-I-frame-640x240", 640, 240); 432 } 433 434 // Decode |i_frame_buffer_| and then a frame with a smaller width and verify 435 // the output size was adjusted. 436 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_SmallerWidth) { 437 DecodeIFrameThenTestFile("vp8-I-frame-160x240", 160, 240); 438 } 439 440 // Decode |i_frame_buffer_| and then a frame with a larger height and verify 441 // the output size was adjusted. 442 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_LargerHeight) { 443 DecodeIFrameThenTestFile("vp8-I-frame-320x480", 320, 480); 444 } 445 446 // Decode |i_frame_buffer_| and then a frame with a smaller height and verify 447 // the output size was adjusted. 448 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_SmallerHeight) { 449 DecodeIFrameThenTestFile("vp8-I-frame-320x120", 320, 120); 450 } 451 452 // Test resetting when decoder has initialized but not decoded. 453 TEST_F(FFmpegVideoDecoderTest, Reset_Initialized) { 454 Initialize(); 455 Reset(); 456 } 457 458 // Test resetting when decoder has decoded single frame. 459 TEST_F(FFmpegVideoDecoderTest, Reset_Decoding) { 460 Initialize(); 461 EnterDecodingState(); 462 Reset(); 463 } 464 465 // Test resetting when decoder has hit end of stream. 466 TEST_F(FFmpegVideoDecoderTest, Reset_EndOfStream) { 467 Initialize(); 468 EnterDecodingState(); 469 EnterEndOfStreamState(); 470 Reset(); 471 } 472 473 // Test stopping when decoder has initialized but not decoded. 474 TEST_F(FFmpegVideoDecoderTest, Stop_Initialized) { 475 Initialize(); 476 Stop(); 477 } 478 479 // Test stopping when decoder has decoded single frame. 480 TEST_F(FFmpegVideoDecoderTest, Stop_Decoding) { 481 Initialize(); 482 EnterDecodingState(); 483 Stop(); 484 } 485 486 // Test stopping when decoder has hit end of stream. 487 TEST_F(FFmpegVideoDecoderTest, Stop_EndOfStream) { 488 Initialize(); 489 EnterDecodingState(); 490 EnterEndOfStreamState(); 491 Stop(); 492 } 493 494 } // namespace media 495