OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <string> | 5 #include <string> |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
10 #include "base/memory/singleton.h" | 10 #include "base/memory/singleton.h" |
(...skipping 21 matching lines...) Expand all Loading... |
32 using ::testing::StrictMock; | 32 using ::testing::StrictMock; |
33 | 33 |
34 namespace media { | 34 namespace media { |
35 | 35 |
36 static const VideoFrame::Format kVideoFormat = VideoFrame::YV12; | 36 static const VideoFrame::Format kVideoFormat = VideoFrame::YV12; |
37 static const gfx::Size kCodedSize(320, 240); | 37 static const gfx::Size kCodedSize(320, 240); |
38 static const gfx::Rect kVisibleRect(320, 240); | 38 static const gfx::Rect kVisibleRect(320, 240); |
39 static const gfx::Size kNaturalSize(320, 240); | 39 static const gfx::Size kNaturalSize(320, 240); |
40 | 40 |
41 ACTION_P(ReturnBuffer, buffer) { | 41 ACTION_P(ReturnBuffer, buffer) { |
42 arg0.Run(buffer ? DemuxerStream::kOk : DemuxerStream::kAborted, buffer); | 42 arg0.Run(buffer.get() ? DemuxerStream::kOk : DemuxerStream::kAborted, buffer); |
43 } | 43 } |
44 | 44 |
45 class FFmpegVideoDecoderTest : public testing::Test { | 45 class FFmpegVideoDecoderTest : public testing::Test { |
46 public: | 46 public: |
47 FFmpegVideoDecoderTest() | 47 FFmpegVideoDecoderTest() |
48 : decoder_(new FFmpegVideoDecoder(message_loop_.message_loop_proxy())), | 48 : decoder_(new FFmpegVideoDecoder(message_loop_.message_loop_proxy())), |
49 demuxer_(new StrictMock<MockDemuxerStream>(DemuxerStream::VIDEO)), | 49 demuxer_(new StrictMock<MockDemuxerStream>(DemuxerStream::VIDEO)), |
50 read_cb_(base::Bind(&FFmpegVideoDecoderTest::FrameReady, | 50 read_cb_(base::Bind(&FFmpegVideoDecoderTest::FrameReady, |
51 base::Unretained(this))) { | 51 base::Unretained(this))) { |
52 FFmpegGlue::InitializeFFmpeg(); | 52 FFmpegGlue::InitializeFFmpeg(); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 } | 95 } |
96 | 96 |
97 // Sets up expectations and actions to put FFmpegVideoDecoder in an active | 97 // Sets up expectations and actions to put FFmpegVideoDecoder in an active |
98 // decoding state. | 98 // decoding state. |
99 void EnterDecodingState() { | 99 void EnterDecodingState() { |
100 VideoDecoder::Status status; | 100 VideoDecoder::Status status; |
101 scoped_refptr<VideoFrame> video_frame; | 101 scoped_refptr<VideoFrame> video_frame; |
102 DecodeSingleFrame(i_frame_buffer_, &status, &video_frame); | 102 DecodeSingleFrame(i_frame_buffer_, &status, &video_frame); |
103 | 103 |
104 EXPECT_EQ(VideoDecoder::kOk, status); | 104 EXPECT_EQ(VideoDecoder::kOk, status); |
105 ASSERT_TRUE(video_frame); | 105 ASSERT_TRUE(video_frame.get()); |
106 EXPECT_FALSE(video_frame->IsEndOfStream()); | 106 EXPECT_FALSE(video_frame->IsEndOfStream()); |
107 } | 107 } |
108 | 108 |
109 // Sets up expectations and actions to put FFmpegVideoDecoder in an end | 109 // Sets up expectations and actions to put FFmpegVideoDecoder in an end |
110 // of stream state. | 110 // of stream state. |
111 void EnterEndOfStreamState() { | 111 void EnterEndOfStreamState() { |
112 scoped_refptr<VideoFrame> video_frame; | 112 scoped_refptr<VideoFrame> video_frame; |
113 VideoDecoder::Status status; | 113 VideoDecoder::Status status; |
114 Read(&status, &video_frame); | 114 Read(&status, &video_frame); |
115 EXPECT_EQ(VideoDecoder::kOk, status); | 115 EXPECT_EQ(VideoDecoder::kOk, status); |
116 ASSERT_TRUE(video_frame); | 116 ASSERT_TRUE(video_frame.get()); |
117 EXPECT_TRUE(video_frame->IsEndOfStream()); | 117 EXPECT_TRUE(video_frame->IsEndOfStream()); |
118 } | 118 } |
119 | 119 |
120 // Decodes the single compressed frame in |buffer| and writes the | 120 // Decodes the single compressed frame in |buffer| and writes the |
121 // uncompressed output to |video_frame|. This method works with single | 121 // uncompressed output to |video_frame|. This method works with single |
122 // and multithreaded decoders. End of stream buffers are used to trigger | 122 // and multithreaded decoders. End of stream buffers are used to trigger |
123 // the frame to be returned in the multithreaded decoder case. | 123 // the frame to be returned in the multithreaded decoder case. |
124 void DecodeSingleFrame(const scoped_refptr<DecoderBuffer>& buffer, | 124 void DecodeSingleFrame(const scoped_refptr<DecoderBuffer>& buffer, |
125 VideoDecoder::Status* status, | 125 VideoDecoder::Status* status, |
126 scoped_refptr<VideoFrame>* video_frame) { | 126 scoped_refptr<VideoFrame>* video_frame) { |
(...skipping 28 matching lines...) Expand all Loading... |
155 | 155 |
156 EXPECT_CALL(statistics_cb_, OnStatistics(_)) | 156 EXPECT_CALL(statistics_cb_, OnStatistics(_)) |
157 .Times(2); | 157 .Times(2); |
158 | 158 |
159 Read(&status_a, &video_frame_a); | 159 Read(&status_a, &video_frame_a); |
160 Read(&status_b, &video_frame_b); | 160 Read(&status_b, &video_frame_b); |
161 | 161 |
162 gfx::Size original_size = kVisibleRect.size(); | 162 gfx::Size original_size = kVisibleRect.size(); |
163 EXPECT_EQ(VideoDecoder::kOk, status_a); | 163 EXPECT_EQ(VideoDecoder::kOk, status_a); |
164 EXPECT_EQ(VideoDecoder::kOk, status_b); | 164 EXPECT_EQ(VideoDecoder::kOk, status_b); |
165 ASSERT_TRUE(video_frame_a); | 165 ASSERT_TRUE(video_frame_a.get()); |
166 ASSERT_TRUE(video_frame_b); | 166 ASSERT_TRUE(video_frame_b.get()); |
167 EXPECT_EQ(original_size.width(), | 167 EXPECT_EQ(original_size.width(), |
168 video_frame_a->visible_rect().size().width()); | 168 video_frame_a->visible_rect().size().width()); |
169 EXPECT_EQ(original_size.height(), | 169 EXPECT_EQ(original_size.height(), |
170 video_frame_a->visible_rect().size().height()); | 170 video_frame_a->visible_rect().size().height()); |
171 EXPECT_EQ(expected_width, video_frame_b->visible_rect().size().width()); | 171 EXPECT_EQ(expected_width, video_frame_b->visible_rect().size().width()); |
172 EXPECT_EQ(expected_height, video_frame_b->visible_rect().size().height()); | 172 EXPECT_EQ(expected_height, video_frame_b->visible_rect().size().height()); |
173 } | 173 } |
174 | 174 |
175 void Read(VideoDecoder::Status* status, | 175 void Read(VideoDecoder::Status* status, |
176 scoped_refptr<VideoFrame>* video_frame) { | 176 scoped_refptr<VideoFrame>* video_frame) { |
177 EXPECT_CALL(*this, FrameReady(_, _)) | 177 EXPECT_CALL(*this, FrameReady(_, _)) |
178 .WillOnce(DoAll(SaveArg<0>(status), SaveArg<1>(video_frame))); | 178 .WillOnce(DoAll(SaveArg<0>(status), SaveArg<1>(video_frame))); |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
313 | 313 |
314 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_Normal) { | 314 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_Normal) { |
315 Initialize(); | 315 Initialize(); |
316 | 316 |
317 // Simulate decoding a single frame. | 317 // Simulate decoding a single frame. |
318 VideoDecoder::Status status; | 318 VideoDecoder::Status status; |
319 scoped_refptr<VideoFrame> video_frame; | 319 scoped_refptr<VideoFrame> video_frame; |
320 DecodeSingleFrame(i_frame_buffer_, &status, &video_frame); | 320 DecodeSingleFrame(i_frame_buffer_, &status, &video_frame); |
321 | 321 |
322 EXPECT_EQ(VideoDecoder::kOk, status); | 322 EXPECT_EQ(VideoDecoder::kOk, status); |
323 ASSERT_TRUE(video_frame); | 323 ASSERT_TRUE(video_frame.get()); |
324 EXPECT_FALSE(video_frame->IsEndOfStream()); | 324 EXPECT_FALSE(video_frame->IsEndOfStream()); |
325 } | 325 } |
326 | 326 |
327 // Verify current behavior for 0 byte frames. FFmpeg simply ignores | 327 // Verify current behavior for 0 byte frames. FFmpeg simply ignores |
328 // the 0 byte frames. | 328 // the 0 byte frames. |
329 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_0ByteFrame) { | 329 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_0ByteFrame) { |
330 Initialize(); | 330 Initialize(); |
331 | 331 |
332 scoped_refptr<DecoderBuffer> zero_byte_buffer = new DecoderBuffer(0); | 332 scoped_refptr<DecoderBuffer> zero_byte_buffer = new DecoderBuffer(0); |
333 | 333 |
(...skipping 14 matching lines...) Expand all Loading... |
348 .Times(2); | 348 .Times(2); |
349 | 349 |
350 Read(&status_a, &video_frame_a); | 350 Read(&status_a, &video_frame_a); |
351 Read(&status_b, &video_frame_b); | 351 Read(&status_b, &video_frame_b); |
352 Read(&status_c, &video_frame_c); | 352 Read(&status_c, &video_frame_c); |
353 | 353 |
354 EXPECT_EQ(VideoDecoder::kOk, status_a); | 354 EXPECT_EQ(VideoDecoder::kOk, status_a); |
355 EXPECT_EQ(VideoDecoder::kOk, status_b); | 355 EXPECT_EQ(VideoDecoder::kOk, status_b); |
356 EXPECT_EQ(VideoDecoder::kOk, status_c); | 356 EXPECT_EQ(VideoDecoder::kOk, status_c); |
357 | 357 |
358 ASSERT_TRUE(video_frame_a); | 358 ASSERT_TRUE(video_frame_a.get()); |
359 ASSERT_TRUE(video_frame_b); | 359 ASSERT_TRUE(video_frame_b.get()); |
360 ASSERT_TRUE(video_frame_c); | 360 ASSERT_TRUE(video_frame_c.get()); |
361 | 361 |
362 EXPECT_FALSE(video_frame_a->IsEndOfStream()); | 362 EXPECT_FALSE(video_frame_a->IsEndOfStream()); |
363 EXPECT_FALSE(video_frame_b->IsEndOfStream()); | 363 EXPECT_FALSE(video_frame_b->IsEndOfStream()); |
364 EXPECT_TRUE(video_frame_c->IsEndOfStream()); | 364 EXPECT_TRUE(video_frame_c->IsEndOfStream()); |
365 } | 365 } |
366 | 366 |
367 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_DecodeError) { | 367 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_DecodeError) { |
368 Initialize(); | 368 Initialize(); |
369 | 369 |
370 EXPECT_CALL(*demuxer_, Read(_)) | 370 EXPECT_CALL(*demuxer_, Read(_)) |
371 .WillOnce(ReturnBuffer(corrupt_i_frame_buffer_)) | 371 .WillOnce(ReturnBuffer(corrupt_i_frame_buffer_)) |
372 .WillRepeatedly(ReturnBuffer(i_frame_buffer_)); | 372 .WillRepeatedly(ReturnBuffer(i_frame_buffer_)); |
373 | 373 |
374 // The error is only raised on the second decode attempt, so we expect at | 374 // The error is only raised on the second decode attempt, so we expect at |
375 // least one successful decode but we don't expect FrameReady() to be | 375 // least one successful decode but we don't expect FrameReady() to be |
376 // executed as an error is raised instead. | 376 // executed as an error is raised instead. |
377 EXPECT_CALL(statistics_cb_, OnStatistics(_)); | 377 EXPECT_CALL(statistics_cb_, OnStatistics(_)); |
378 | 378 |
379 // Our read should still get satisfied with end of stream frame during an | 379 // Our read should still get satisfied with end of stream frame during an |
380 // error. | 380 // error. |
381 VideoDecoder::Status status; | 381 VideoDecoder::Status status; |
382 scoped_refptr<VideoFrame> video_frame; | 382 scoped_refptr<VideoFrame> video_frame; |
383 Read(&status, &video_frame); | 383 Read(&status, &video_frame); |
384 EXPECT_EQ(VideoDecoder::kDecodeError, status); | 384 EXPECT_EQ(VideoDecoder::kDecodeError, status); |
385 EXPECT_FALSE(video_frame); | 385 EXPECT_FALSE(video_frame.get()); |
386 | 386 |
387 // After a decode error occurred, all following read will return kDecodeError. | 387 // After a decode error occurred, all following read will return kDecodeError. |
388 Read(&status, &video_frame); | 388 Read(&status, &video_frame); |
389 EXPECT_EQ(VideoDecoder::kDecodeError, status); | 389 EXPECT_EQ(VideoDecoder::kDecodeError, status); |
390 EXPECT_FALSE(video_frame); | 390 EXPECT_FALSE(video_frame.get()); |
391 } | 391 } |
392 | 392 |
393 // Multi-threaded decoders have different behavior than single-threaded | 393 // Multi-threaded decoders have different behavior than single-threaded |
394 // decoders at the end of the stream. Multithreaded decoders hide errors | 394 // decoders at the end of the stream. Multithreaded decoders hide errors |
395 // that happen on the last |codec_context_->thread_count| frames to avoid | 395 // that happen on the last |codec_context_->thread_count| frames to avoid |
396 // prematurely signalling EOS. This test just exposes that behavior so we can | 396 // prematurely signalling EOS. This test just exposes that behavior so we can |
397 // detect if it changes. | 397 // detect if it changes. |
398 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_DecodeErrorAtEndOfStream) { | 398 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_DecodeErrorAtEndOfStream) { |
399 Initialize(); | 399 Initialize(); |
400 | 400 |
401 VideoDecoder::Status status; | 401 VideoDecoder::Status status; |
402 scoped_refptr<VideoFrame> video_frame; | 402 scoped_refptr<VideoFrame> video_frame; |
403 DecodeSingleFrame(corrupt_i_frame_buffer_, &status, &video_frame); | 403 DecodeSingleFrame(corrupt_i_frame_buffer_, &status, &video_frame); |
404 | 404 |
405 EXPECT_EQ(VideoDecoder::kOk, status); | 405 EXPECT_EQ(VideoDecoder::kOk, status); |
406 ASSERT_TRUE(video_frame); | 406 ASSERT_TRUE(video_frame.get()); |
407 EXPECT_TRUE(video_frame->IsEndOfStream()); | 407 EXPECT_TRUE(video_frame->IsEndOfStream()); |
408 } | 408 } |
409 | 409 |
410 // Decode |i_frame_buffer_| and then a frame with a larger width and verify | 410 // Decode |i_frame_buffer_| and then a frame with a larger width and verify |
411 // the output size was adjusted. | 411 // the output size was adjusted. |
412 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_LargerWidth) { | 412 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_LargerWidth) { |
413 DecodeIFrameThenTestFile("vp8-I-frame-640x240", 640, 240); | 413 DecodeIFrameThenTestFile("vp8-I-frame-640x240", 640, 240); |
414 } | 414 } |
415 | 415 |
416 // Decode |i_frame_buffer_| and then a frame with a smaller width and verify | 416 // Decode |i_frame_buffer_| and then a frame with a smaller width and verify |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
516 | 516 |
517 EXPECT_CALL(*demuxer_, Read(_)) | 517 EXPECT_CALL(*demuxer_, Read(_)) |
518 .WillOnce(ReturnBuffer(scoped_refptr<DecoderBuffer>())); | 518 .WillOnce(ReturnBuffer(scoped_refptr<DecoderBuffer>())); |
519 | 519 |
520 VideoDecoder::Status status; | 520 VideoDecoder::Status status; |
521 scoped_refptr<VideoFrame> video_frame; | 521 scoped_refptr<VideoFrame> video_frame; |
522 | 522 |
523 Read(&status, &video_frame); | 523 Read(&status, &video_frame); |
524 | 524 |
525 EXPECT_EQ(VideoDecoder::kOk, status); | 525 EXPECT_EQ(VideoDecoder::kOk, status); |
526 EXPECT_FALSE(video_frame); | 526 EXPECT_FALSE(video_frame.get()); |
527 } | 527 } |
528 | 528 |
529 // Test aborted read on the demuxer stream during pending reset. | 529 // Test aborted read on the demuxer stream during pending reset. |
530 TEST_F(FFmpegVideoDecoderTest, DemuxerRead_AbortedDuringReset) { | 530 TEST_F(FFmpegVideoDecoderTest, DemuxerRead_AbortedDuringReset) { |
531 Initialize(); | 531 Initialize(); |
532 | 532 |
533 // Request a read on the decoder and ensure the demuxer has been called. | 533 // Request a read on the decoder and ensure the demuxer has been called. |
534 DemuxerStream::ReadCB read_cb; | 534 DemuxerStream::ReadCB read_cb; |
535 EXPECT_CALL(*demuxer_, Read(_)) | 535 EXPECT_CALL(*demuxer_, Read(_)) |
536 .WillOnce(SaveArg<0>(&read_cb)); | 536 .WillOnce(SaveArg<0>(&read_cb)); |
537 decoder_->Read(read_cb_); | 537 decoder_->Read(read_cb_); |
538 ASSERT_FALSE(read_cb.is_null()); | 538 ASSERT_FALSE(read_cb.is_null()); |
539 | 539 |
540 // Reset while there is still an outstanding read on the demuxer. | 540 // Reset while there is still an outstanding read on the demuxer. |
541 Reset(); | 541 Reset(); |
542 | 542 |
543 // Signal an aborted demuxer read: a NULL video frame should be returned. | 543 // Signal an aborted demuxer read: a NULL video frame should be returned. |
544 EXPECT_CALL(*this, FrameReady(VideoDecoder::kOk, IsNull())); | 544 EXPECT_CALL(*this, FrameReady(VideoDecoder::kOk, IsNull())); |
545 read_cb.Run(DemuxerStream::kAborted, NULL); | 545 read_cb.Run(DemuxerStream::kAborted, NULL); |
546 message_loop_.RunUntilIdle(); | 546 message_loop_.RunUntilIdle(); |
547 } | 547 } |
548 | 548 |
549 } // namespace media | 549 } // namespace media |
OLD | NEW |