Chromium Code Reviews| Index: media/filters/video_frame_stream_unittest.cc |
| diff --git a/media/filters/video_frame_stream_unittest.cc b/media/filters/video_frame_stream_unittest.cc |
| index 247b25eacc6a3f5b190536b5b5bb3b15b016f737..36fe7071ee72fab89d05991dceabd5362a361524 100644 |
| --- a/media/filters/video_frame_stream_unittest.cc |
| +++ b/media/filters/video_frame_stream_unittest.cc |
| @@ -188,12 +188,6 @@ class VideoFrameStreamTest |
| pending_read_ = false; |
| } |
| - void FrameReadyHoldDemuxer(VideoFrameStream::Status status, |
| - const scoped_refptr<VideoFrame>& frame) { |
| - FrameReady(status, frame); |
| - |
| - } |
| - |
| void OnReset() { |
| DCHECK(!pending_read_); |
| DCHECK(pending_reset_); |
| @@ -410,7 +404,7 @@ TEST_P(VideoFrameStreamTest, Initialization) { |
| Initialize(); |
| } |
| -TEST_P(VideoFrameStreamTest, DecoderInitializationFails) { |
| +TEST_P(VideoFrameStreamTest, AllDecoderInitializationFails) { |
| decoder1_->SimulateFailureToInit(); |
| decoder2_->SimulateFailureToInit(); |
| decoder3_->SimulateFailureToInit(); |
| @@ -418,6 +412,13 @@ TEST_P(VideoFrameStreamTest, DecoderInitializationFails) { |
| EXPECT_FALSE(is_initialized_); |
| } |
| +TEST_P(VideoFrameStreamTest, PartialDecoderInitializationFails) { |
| + decoder1_->SimulateFailureToInit(); |
| + decoder2_->SimulateFailureToInit(); |
| + Initialize(); |
| + EXPECT_TRUE(is_initialized_); |
| +} |
| + |
| TEST_P(VideoFrameStreamTest, ReadOneFrame) { |
| Initialize(); |
| Read(); |
| @@ -747,18 +748,207 @@ TEST_P(VideoFrameStreamTest, Destroy_AfterRead_AfterReset) { |
| Reset(); |
| } |
| -TEST_P(VideoFrameStreamTest, DecoderErrorWhenReading) { |
| +TEST_P(VideoFrameStreamTest, FallbackDecoder_SelectedOnInitialDecodeError) { |
| + Initialize(); |
| + decoder1_->SimulateError(); |
| + ReadOneFrame(); |
| + |
| + // |video_frame_stream_| should have fallen back to |decoder2_|. |
| + ASSERT_FALSE(pending_read_); |
| + ASSERT_EQ(VideoFrameStream::OK, last_read_status_); |
| + |
| + // Can't check |decoder1_| right now, it might have been destroyed already. |
| + ASSERT_GT(decoder2_->total_bytes_decoded(), 0); |
| + |
| + // Verify no frame was dropped. |
| + ReadAllFrames(); |
| +} |
| + |
| +TEST_P(VideoFrameStreamTest, |
| + FallbackDecoder_SelectedOnInitialDecodeError_Twice) { |
| + Initialize(); |
| + decoder1_->SimulateError(); |
| + decoder2_->HoldNextInit(); |
| + ReadOneFrame(); |
| + |
| + decoder2_->SatisfyInit(); |
| + decoder2_->SimulateError(); |
| + message_loop_.RunUntilIdle(); |
| + |
| + // |video_frame_stream_| should have fallen back to |decoder3_|. |
| + ASSERT_FALSE(pending_read_); |
| + ASSERT_EQ(VideoFrameStream::OK, last_read_status_); |
| + |
| + // Can't check |decoder1_| or |decoder2_| right now, they might have been |
| + // destroyed already. |
| + ASSERT_GT(decoder3_->total_bytes_decoded(), 0); |
| + |
| + // Verify no frame was dropped. |
| + ReadAllFrames(); |
| +} |
| + |
| +TEST_P(VideoFrameStreamTest, FallbackDecoder_ConfigChangeClearsPendingBuffers) { |
| + // Test case is only interesting if the decoder can receive a config change |
| + // before returning its first frame. |
| + if (GetParam().decoding_delay < kNumBuffersInOneConfig) |
| + return; |
| + |
| + Initialize(); |
| + EnterPendingState(DEMUXER_READ_CONFIG_CHANGE); |
| + ASSERT_GT(video_frame_stream_->get_pending_buffers_size_for_testing(), 0); |
| + |
| + SatisfyPendingCallback(DEMUXER_READ_CONFIG_CHANGE); |
| + ASSERT_EQ(video_frame_stream_->get_pending_buffers_size_for_testing(), 0); |
| + EXPECT_FALSE(pending_read_); |
| +} |
| + |
| +TEST_P(VideoFrameStreamTest, FallbackDecoder_PendingBuffersIsFilledAndCleared) { |
| + // Test applies only when there is a decoder delay, and the decoder will not |
| + // receive a config change before outputing its first frame. Parallel decoding |
| + // is also disabled in this test case, for readability and simplicity of the |
| + // unit test. |
| + if (GetParam().decoding_delay == 0 || |
| + GetParam().decoding_delay > kNumBuffersInOneConfig || |
| + GetParam().parallel_decoding > 1) |
| + return; |
|
DaleCurtis
2016/04/15 01:19:17
Multiline if needs {}
tguilbert
2016/04/15 20:45:52
Done.
|
| + Initialize(); |
| + |
| + // Block on demuxer read and decoder decode so we can step through. |
| + demuxer_stream_->HoldNextRead(); |
| + decoder1_->HoldDecode(); |
| + ReadOneFrame(); |
| + |
| + int demuxer_reads_satisfied = 0; |
| + // Send back and requests buffers until the next one would fill the decoder |
| + // delay. |
| + while (demuxer_reads_satisfied < GetParam().decoding_delay - 1) { |
| + // Send a buffer back. |
| + demuxer_stream_->SatisfyReadAndHoldNext(); |
| + message_loop_.RunUntilIdle(); |
| + ++demuxer_reads_satisfied; |
| + |
| + // Decode one buffer. |
| + decoder1_->SatisfySingleDecode(); |
| + message_loop_.RunUntilIdle(); |
| + EXPECT_TRUE(pending_read_); |
| + EXPECT_EQ(demuxer_reads_satisfied, |
| + video_frame_stream_->get_pending_buffers_size_for_testing()); |
| + // No fallback buffers should be queued up yet. |
| + EXPECT_EQ(0, video_frame_stream_->get_fallback_buffers_size_for_testing()); |
| + } |
| + |
| + // Hold the init before triggering the error, to verify internal state. |
| + demuxer_stream_->SatisfyReadAndHoldNext(); |
| + ++demuxer_reads_satisfied; |
| + decoder2_->HoldNextInit(); |
| + decoder1_->SimulateError(); |
| + message_loop_.RunUntilIdle(); |
| + |
| + EXPECT_TRUE(pending_read_); |
| + EXPECT_EQ(demuxer_reads_satisfied, |
| + video_frame_stream_->get_pending_buffers_size_for_testing()); |
| + |
| + decoder2_->SatisfyInit(); |
| + decoder2_->HoldDecode(); |
| + message_loop_.RunUntilIdle(); |
| + |
| + // Make sure the pending buffers have been transfered to fallback buffers. |
| + // One call to Decode() during the initialization process, so we expect one |
| + // buffer to already have been consumed from the fallback buffers and appended |
| + // to the pending buffers. |
| + EXPECT_EQ(demuxer_reads_satisfied - 1, |
| + video_frame_stream_->get_fallback_buffers_size_for_testing()); |
| + EXPECT_EQ(1, video_frame_stream_->get_pending_buffers_size_for_testing()); |
| + |
| + decoder2_->SatisfyDecode(); |
| + message_loop_.RunUntilIdle(); |
| + |
| + // Make sure all buffers consumed by |decoder2_| have come from the fallback |
| + // buffers, and have been re-appended to the pending buffers. |
| + EXPECT_EQ(0, video_frame_stream_->get_fallback_buffers_size_for_testing()); |
| + EXPECT_EQ(demuxer_reads_satisfied, |
| + video_frame_stream_->get_pending_buffers_size_for_testing()); |
| + EXPECT_EQ(video_frame_stream_->get_previous_decoder_for_testing(), decoder1_); |
| + EXPECT_TRUE(pending_read_); |
| + |
| + // Give the decoder one more buffer, enough to release a frame. |
| + demuxer_stream_->SatisfyReadAndHoldNext(); |
| + message_loop_.RunUntilIdle(); |
| + |
| + // New buffers should not have been added after the frame was released. |
| + EXPECT_EQ(video_frame_stream_->get_pending_buffers_size_for_testing(), 0); |
| + EXPECT_FALSE(pending_read_); |
| + |
| + demuxer_stream_->SatisfyRead(); |
| + |
| + // Confirm no frames were dropped. |
| + ReadAllFrames(); |
| +} |
| + |
| +TEST_P(VideoFrameStreamTest, FallbackDecoder_SelectedOnDecodeThenInitErrors) { |
| Initialize(); |
| - EnterPendingState(DECODER_DECODE); |
| decoder1_->SimulateError(); |
| + decoder2_->SimulateFailureToInit(); |
| + ReadOneFrame(); |
| + |
| + // |video_frame_stream_| should have fallen back to |decoder3_| |
| + ASSERT_FALSE(pending_read_); |
| + ASSERT_EQ(VideoFrameStream::OK, last_read_status_); |
| + |
| + // Can't check |decoder1_| or |decoder2_| right now, they might have been |
| + // destroyed already. |
| + ASSERT_GT(decoder3_->total_bytes_decoded(), 0); |
| + |
| + // Verify no frame was dropped. |
| + ReadAllFrames(); |
| +} |
| + |
| +TEST_P(VideoFrameStreamTest, FallbackDecoder_SelectedOnInitThenDecodeErrors) { |
| + decoder1_->SimulateFailureToInit(); |
| + decoder2_->HoldDecode(); |
| + Initialize(); |
| + ReadOneFrame(); |
| + decoder2_->SimulateError(); |
| message_loop_.RunUntilIdle(); |
| + |
| + // |video_frame_stream_| should have fallen back to |decoder3_| |
| ASSERT_FALSE(pending_read_); |
| + ASSERT_EQ(VideoFrameStream::OK, last_read_status_); |
| + |
| + // Can't check |decoder1_| or |decoder2_| right now, they might have been |
| + // destroyed already. |
| + ASSERT_GT(decoder3_->total_bytes_decoded(), 0); |
| + |
| + // Verify no frame was dropped. |
| + ReadAllFrames(); |
| +} |
| + |
| +TEST_P(VideoFrameStreamTest, |
| + FallbackDecoder_NotSelectedOnMidstreamDecodeError) { |
| + Initialize(); |
| + ReadOneFrame(); |
| + |
| + // Successfully received a frame. |
| + EXPECT_FALSE(pending_read_); |
| + ASSERT_GT(decoder1_->total_bytes_decoded(), 0); |
| + |
| + decoder1_->SimulateError(); |
| + |
| + // The error must surface from Read() as DECODE_ERROR. |
| + while (last_read_status_ == VideoFrameStream::OK) { |
| + ReadOneFrame(); |
| + message_loop_.RunUntilIdle(); |
| + EXPECT_FALSE(pending_read_); |
| + } |
| + |
| + // Verify the error was surfaced, rather than falling back to |decoder2_|. |
| + EXPECT_FALSE(pending_read_); |
| + ASSERT_EQ(decoder2_->total_bytes_decoded(), 0); |
| ASSERT_EQ(VideoFrameStream::DECODE_ERROR, last_read_status_); |
| } |
| TEST_P(VideoFrameStreamTest, DecoderErrorWhenNotReading) { |
| Initialize(); |
| - |
| decoder1_->HoldDecode(); |
| ReadOneFrame(); |
| EXPECT_TRUE(pending_read_); |
| @@ -784,8 +974,13 @@ TEST_P(VideoFrameStreamTest, DecoderErrorWhenNotReading) { |
| TEST_P(VideoFrameStreamTest, FallbackDecoderSelectedOnFailureToReinitialize) { |
| Initialize(); |
| decoder1_->SimulateFailureToInit(); |
| + // Holding decode, because large decoder delays might cause us to get rid of |
| + // |previous_decoder_| before we are in a pending state again. |
| + decoder2_->HoldDecode(); |
| ReadUntilDecoderReinitialized(decoder1_); |
| ASSERT_TRUE(video_frame_stream_->get_previous_decoder_for_testing()); |
| + decoder2_->SatisfyDecode(); |
| + message_loop_.RunUntilIdle(); |
| ReadAllFrames(); |
| ASSERT_FALSE(video_frame_stream_->get_previous_decoder_for_testing()); |
| } |