Chromium Code Reviews| Index: content/common/gpu/media/video_decode_accelerator_unittest.cc |
| diff --git a/content/common/gpu/media/video_decode_accelerator_unittest.cc b/content/common/gpu/media/video_decode_accelerator_unittest.cc |
| index 78ea8ba2c6d564e509b452686c0607a1b8d6ecff..2e84c4ed58c79b70559ff45180f9971a77d181b1 100644 |
| --- a/content/common/gpu/media/video_decode_accelerator_unittest.cc |
| +++ b/content/common/gpu/media/video_decode_accelerator_unittest.cc |
| @@ -312,6 +312,8 @@ class GLRenderingVDAClient |
| // will start delaying the call to ReusePictureBuffer() for kReuseDelay. |
| // |decode_calls_per_second| is the number of VDA::Decode calls per second. |
| // If |decode_calls_per_second| > 0, |num_in_flight_decodes| must be 1. |
| + // When |test_full_flush| is true, request the VDA to return all buffers it |
| + // owns on Flush(), and verify that. |
| GLRenderingVDAClient(size_t window_id, |
| RenderingHelper* rendering_helper, |
| ClientStateNotification<ClientState>* note, |
| @@ -327,7 +329,8 @@ class GLRenderingVDAClient |
| bool suppress_rendering, |
| int delay_reuse_after_frame_num, |
| int decode_calls_per_second, |
| - bool render_as_thumbnails); |
| + bool render_as_thumbnails, |
| + bool test_full_flush); |
| ~GLRenderingVDAClient() override; |
| void CreateAndStartDecoder(); |
| @@ -371,6 +374,7 @@ class GLRenderingVDAClient |
| void SetState(ClientState new_state); |
| void FinishInitialization(); |
| + void ReturnTexture(int32_t picture_buffer_id); |
| void ReturnPicture(int32_t picture_buffer_id); |
| // Delete the associated decoder helper. |
| @@ -411,6 +415,7 @@ class GLRenderingVDAClient |
| int num_queued_fragments_; |
| int num_decoded_frames_; |
| int num_done_bitstream_buffers_; |
| + int num_pictures_at_client_; |
| base::TimeTicks initialize_done_ticks_; |
| media::VideoCodecProfile profile_; |
| int fake_decoder_; |
| @@ -425,6 +430,8 @@ class GLRenderingVDAClient |
| // The number of VDA::Decode calls per second. This is to simulate webrtc. |
| int decode_calls_per_second_; |
| bool render_as_thumbnails_; |
| + bool test_full_flush_; |
| + std::list<int> delayed_picture_buffer_ids_to_return_; |
| // A map of the textures that are currently active for the decoder, i.e., |
| // have been created via AssignPictureBuffers() and not dismissed via |
| @@ -459,7 +466,8 @@ GLRenderingVDAClient::GLRenderingVDAClient( |
| bool suppress_rendering, |
| int delay_reuse_after_frame_num, |
| int decode_calls_per_second, |
| - bool render_as_thumbnails) |
| + bool render_as_thumbnails, |
| + bool test_full_flush) |
| : window_id_(window_id), |
| rendering_helper_(rendering_helper), |
| frame_size_(frame_width, frame_height), |
| @@ -477,12 +485,14 @@ GLRenderingVDAClient::GLRenderingVDAClient( |
| num_queued_fragments_(0), |
| num_decoded_frames_(0), |
| num_done_bitstream_buffers_(0), |
| + num_pictures_at_client_(0), |
| fake_decoder_(fake_decoder), |
| texture_target_(0), |
| suppress_rendering_(suppress_rendering), |
| delay_reuse_after_frame_num_(delay_reuse_after_frame_num), |
| decode_calls_per_second_(decode_calls_per_second), |
| render_as_thumbnails_(render_as_thumbnails), |
| + test_full_flush_(test_full_flush), |
| next_picture_buffer_id_(1) { |
| LOG_ASSERT(num_in_flight_decodes > 0); |
| LOG_ASSERT(num_play_throughs > 0); |
| @@ -649,6 +659,8 @@ void GLRenderingVDAClient::ProvidePictureBuffers( |
| void GLRenderingVDAClient::DismissPictureBuffer(int32_t picture_buffer_id) { |
| LOG_ASSERT(1U == active_textures_.erase(picture_buffer_id)); |
| + EXPECT_GT(num_pictures_at_client_, 0); |
| + --num_pictures_at_client_; |
| } |
| void GLRenderingVDAClient::PictureReady(const media::Picture& picture) { |
| @@ -658,6 +670,15 @@ void GLRenderingVDAClient::PictureReady(const media::Picture& picture) { |
| if (decoder_deleted()) |
| return; |
| + EXPECT_GT(num_pictures_at_client_, 0); |
| + --num_pictures_at_client_; |
| + |
| + if (picture.bitstream_buffer_id() == -1) { |
| + // The picture does not contain any decoded data, reuse it immediately. |
| + ReturnPicture(picture.picture_buffer_id()); |
| + return; |
| + } |
| + |
| base::TimeTicks now = base::TimeTicks::Now(); |
| frame_delivery_times_.push_back(now); |
| @@ -689,7 +710,7 @@ void GLRenderingVDAClient::PictureReady(const media::Picture& picture) { |
| scoped_refptr<VideoFrameTexture> video_frame = new VideoFrameTexture( |
| texture_target_, texture_it->second->texture_id(), |
| - base::Bind(&GLRenderingVDAClient::ReturnPicture, AsWeakPtr(), |
| + base::Bind(&GLRenderingVDAClient::ReturnTexture, AsWeakPtr(), |
| picture.picture_buffer_id())); |
| ASSERT_TRUE(pending_textures_.insert(*texture_it).second); |
| @@ -701,9 +722,10 @@ void GLRenderingVDAClient::PictureReady(const media::Picture& picture) { |
| } |
| } |
| -void GLRenderingVDAClient::ReturnPicture(int32_t picture_buffer_id) { |
| +void GLRenderingVDAClient::ReturnTexture(int32_t picture_buffer_id) { |
| if (decoder_deleted()) |
| return; |
| + |
| LOG_ASSERT(1U == pending_textures_.erase(picture_buffer_id)); |
| if (pending_textures_.empty() && state_ == CS_RESETTING) { |
| @@ -712,6 +734,15 @@ void GLRenderingVDAClient::ReturnPicture(int32_t picture_buffer_id) { |
| return; |
| } |
| + ReturnPicture(picture_buffer_id); |
| +} |
| + |
| +void GLRenderingVDAClient::ReturnPicture(int32_t picture_buffer_id) { |
| + if (test_full_flush_ && state_ == CS_FLUSHING) { |
| + delayed_picture_buffer_ids_to_return_.push_back(picture_buffer_id); |
| + return; |
| + } |
| + |
| if (num_decoded_frames_ > delay_reuse_after_frame_num_) { |
| base::MessageLoop::current()->PostDelayedTask( |
| FROM_HERE, |
| @@ -722,6 +753,8 @@ void GLRenderingVDAClient::ReturnPicture(int32_t picture_buffer_id) { |
| } else { |
| decoder_->ReusePictureBuffer(picture_buffer_id); |
| } |
| + |
| + ++num_pictures_at_client_; |
| } |
| void GLRenderingVDAClient::NotifyEndOfBitstreamBuffer( |
| @@ -739,7 +772,7 @@ void GLRenderingVDAClient::NotifyEndOfBitstreamBuffer( |
| // |outstanding_decodes_|. |decoder_| should be able to accept Flush() |
| // before it's done with outstanding decodes. (crbug.com/528183) |
| if (outstanding_decodes_ == 0) { |
| - decoder_->Flush(); |
| + decoder_->Flush(test_full_flush_); |
| SetState(CS_FLUSHING); |
| } |
| } else if (decode_calls_per_second_ == 0) { |
| @@ -752,6 +785,14 @@ void GLRenderingVDAClient::NotifyFlushDone() { |
| return; |
| SetState(CS_FLUSHED); |
| + |
| + if (test_full_flush_) { |
| + EXPECT_EQ(num_pictures_at_client_, 0); |
|
kcwu
2016/03/22 09:47:42
EXPECT_EQ(0, num_pictures_at_client_);
expected fi
|
| + for (auto& picture_buffer_id : delayed_picture_buffer_ids_to_return_) |
| + ReturnPicture(picture_buffer_id); |
| + delayed_picture_buffer_ids_to_return_.clear(); |
| + } |
| + |
| --remaining_play_throughs_; |
| DCHECK_GE(remaining_play_throughs_, 0); |
| if (decoder_deleted()) |
| @@ -1194,10 +1235,12 @@ void VideoDecodeAcceleratorTest::OutputLogFile( |
| // - delete_decoder_phase: see GLRenderingVDAClient ctor. |
| // - whether to test slow rendering by delaying ReusePictureBuffer(). |
| // - whether the video frames are rendered as thumbnails. |
| +// - whether to test VDA::Flush(true) |
| class VideoDecodeAcceleratorParamTest |
| : public VideoDecodeAcceleratorTest, |
| public ::testing::WithParamInterface< |
| - base::Tuple<int, int, int, ResetPoint, ClientState, bool, bool> > { |
| + base:: |
| + Tuple<int, int, int, ResetPoint, ClientState, bool, bool, bool>> { |
| }; |
| // Wait for |note| to report a state and if it's not |expected_state| then |
| @@ -1228,6 +1271,7 @@ TEST_P(VideoDecodeAcceleratorParamTest, TestSimpleDecode) { |
| const int delete_decoder_state = base::get<4>(GetParam()); |
| bool test_reuse_delay = base::get<5>(GetParam()); |
| const bool render_as_thumbnails = base::get<6>(GetParam()); |
| + const bool test_full_flush = base::get<7>(GetParam()); |
| if (test_video_files_.size() > 1) |
| num_concurrent_decoders = test_video_files_.size(); |
| @@ -1286,7 +1330,8 @@ TEST_P(VideoDecodeAcceleratorParamTest, TestSimpleDecode) { |
| suppress_rendering, |
| delay_after_frame_num, |
| 0, |
| - render_as_thumbnails); |
| + render_as_thumbnails, |
| + test_full_flush); |
| clients[index] = client; |
| helper_params.window_sizes.push_back( |
| @@ -1438,79 +1483,181 @@ TEST_P(VideoDecodeAcceleratorParamTest, TestSimpleDecode) { |
| }; |
| // Test that replay after EOS works fine. |
| -INSTANTIATE_TEST_CASE_P( |
| - ReplayAfterEOS, VideoDecodeAcceleratorParamTest, |
| - ::testing::Values( |
| - MakeTuple(1, 1, 4, END_OF_STREAM_RESET, CS_RESET, false, false))); |
| +INSTANTIATE_TEST_CASE_P(ReplayAfterEOS, |
| + VideoDecodeAcceleratorParamTest, |
| + ::testing::Values(MakeTuple(1, |
| + 1, |
| + 4, |
| + END_OF_STREAM_RESET, |
| + CS_RESET, |
| + false, |
| + false, |
| + false))); |
| // Test that Reset() before the first Decode() works fine. |
| -INSTANTIATE_TEST_CASE_P( |
| - ResetBeforeDecode, VideoDecodeAcceleratorParamTest, |
| - ::testing::Values( |
| - MakeTuple(1, 1, 1, START_OF_STREAM_RESET, CS_RESET, false, false))); |
| +INSTANTIATE_TEST_CASE_P(ResetBeforeDecode, |
| + VideoDecodeAcceleratorParamTest, |
| + ::testing::Values(MakeTuple(1, |
| + 1, |
| + 1, |
| + START_OF_STREAM_RESET, |
| + CS_RESET, |
| + false, |
| + false, |
| + false))); |
| // Test Reset() immediately after Decode() containing config info. |
| INSTANTIATE_TEST_CASE_P( |
| - ResetAfterFirstConfigInfo, VideoDecodeAcceleratorParamTest, |
| - ::testing::Values( |
| - MakeTuple( |
| - 1, 1, 1, RESET_AFTER_FIRST_CONFIG_INFO, CS_RESET, false, false))); |
| + ResetAfterFirstConfigInfo, |
| + VideoDecodeAcceleratorParamTest, |
| + ::testing::Values(MakeTuple(1, |
| + 1, |
| + 1, |
| + RESET_AFTER_FIRST_CONFIG_INFO, |
| + CS_RESET, |
| + false, |
| + false, |
| + false))); |
| // Test that Reset() mid-stream works fine and doesn't affect decoding even when |
| // Decode() calls are made during the reset. |
| INSTANTIATE_TEST_CASE_P( |
| - MidStreamReset, VideoDecodeAcceleratorParamTest, |
| + MidStreamReset, |
| + VideoDecodeAcceleratorParamTest, |
| + ::testing::Values( |
| + MakeTuple(1, 1, 1, MID_STREAM_RESET, CS_RESET, false, false, false))); |
| + |
| +// Test that the VDA returns all buffers to us on Flush(true). |
| +INSTANTIATE_TEST_CASE_P( |
| + FullFlush, |
| + VideoDecodeAcceleratorParamTest, |
| ::testing::Values( |
| - MakeTuple(1, 1, 1, MID_STREAM_RESET, CS_RESET, false, false))); |
| + MakeTuple(1, 1, 1, MID_STREAM_RESET, CS_RESET, false, false, true))); |
| INSTANTIATE_TEST_CASE_P( |
| - SlowRendering, VideoDecodeAcceleratorParamTest, |
| + SlowRendering, |
| + VideoDecodeAcceleratorParamTest, |
| ::testing::Values( |
| - MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET, true, false))); |
| + MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET, true, false, false))); |
| // Test that Destroy() mid-stream works fine (primarily this is testing that no |
| // crashes occur). |
| INSTANTIATE_TEST_CASE_P( |
| - TearDownTiming, VideoDecodeAcceleratorParamTest, |
| + TearDownTiming, |
| + VideoDecodeAcceleratorParamTest, |
| ::testing::Values( |
| - MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_DECODER_SET, false, false), |
| - MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_INITIALIZED, false, false), |
| - MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_FLUSHING, false, false), |
| - MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_FLUSHED, false, false), |
| - MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESETTING, false, false), |
| - MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false), |
| - MakeTuple(1, 1, 1, END_OF_STREAM_RESET, |
| - static_cast<ClientState>(-1), false, false), |
| - MakeTuple(1, 1, 1, END_OF_STREAM_RESET, |
| - static_cast<ClientState>(-10), false, false), |
| - MakeTuple(1, 1, 1, END_OF_STREAM_RESET, |
| - static_cast<ClientState>(-100), false, false))); |
| + MakeTuple(1, |
| + 1, |
| + 1, |
| + END_OF_STREAM_RESET, |
| + CS_DECODER_SET, |
| + false, |
| + false, |
| + false), |
| + MakeTuple(1, |
| + 1, |
| + 1, |
| + END_OF_STREAM_RESET, |
| + CS_INITIALIZED, |
| + false, |
| + false, |
| + false), |
| + MakeTuple(1, |
| + 1, |
| + 1, |
| + END_OF_STREAM_RESET, |
| + CS_FLUSHING, |
| + false, |
| + false, |
| + false), |
| + MakeTuple(1, |
| + 1, |
| + 1, |
| + END_OF_STREAM_RESET, |
| + CS_FLUSHED, |
| + false, |
| + false, |
| + false), |
| + MakeTuple(1, |
| + 1, |
| + 1, |
| + END_OF_STREAM_RESET, |
| + CS_RESETTING, |
| + false, |
| + false, |
| + false), |
| + MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false, false), |
| + MakeTuple(1, |
| + 1, |
| + 1, |
| + END_OF_STREAM_RESET, |
| + static_cast<ClientState>(-1), |
| + false, |
| + false, |
| + false), |
| + MakeTuple(1, |
| + 1, |
| + 1, |
| + END_OF_STREAM_RESET, |
| + static_cast<ClientState>(-10), |
| + false, |
| + false, |
| + false), |
| + MakeTuple(1, |
| + 1, |
| + 1, |
| + END_OF_STREAM_RESET, |
| + static_cast<ClientState>(-100), |
| + false, |
| + false, |
| + false))); |
| // Test that decoding various variation works with multiple in-flight decodes. |
| INSTANTIATE_TEST_CASE_P( |
| - DecodeVariations, VideoDecodeAcceleratorParamTest, |
| + DecodeVariations, |
| + VideoDecodeAcceleratorParamTest, |
| ::testing::Values( |
| - MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false), |
| - MakeTuple(1, 10, 1, END_OF_STREAM_RESET, CS_RESET, false, false), |
| + MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false, false), |
| + MakeTuple(1, 10, 1, END_OF_STREAM_RESET, CS_RESET, false, false, false), |
| // Tests queuing. |
| - MakeTuple(1, 15, 1, END_OF_STREAM_RESET, CS_RESET, false, false))); |
| + MakeTuple(1, |
| + 15, |
| + 1, |
| + END_OF_STREAM_RESET, |
| + CS_RESET, |
| + false, |
| + false, |
| + false))); |
| // Find out how many concurrent decoders can go before we exhaust system |
| // resources. |
| -INSTANTIATE_TEST_CASE_P( |
| - ResourceExhaustion, VideoDecodeAcceleratorParamTest, |
| - ::testing::Values( |
| - // +0 hack below to promote enum to int. |
| - MakeTuple(kMinSupportedNumConcurrentDecoders + 0, 1, 1, |
| - END_OF_STREAM_RESET, CS_RESET, false, false), |
| - MakeTuple(kMinSupportedNumConcurrentDecoders + 1, 1, 1, |
| - END_OF_STREAM_RESET, CS_RESET, false, false))); |
| +INSTANTIATE_TEST_CASE_P(ResourceExhaustion, |
| + VideoDecodeAcceleratorParamTest, |
| + ::testing::Values( |
| + // +0 hack below to promote enum to int. |
| + MakeTuple(kMinSupportedNumConcurrentDecoders + 0, |
| + 1, |
| + 1, |
| + END_OF_STREAM_RESET, |
| + CS_RESET, |
| + false, |
| + false, |
| + false), |
| + MakeTuple(kMinSupportedNumConcurrentDecoders + 1, |
| + 1, |
| + 1, |
| + END_OF_STREAM_RESET, |
| + CS_RESET, |
| + false, |
| + false, |
| + false))); |
| // Thumbnailing test |
| INSTANTIATE_TEST_CASE_P( |
| - Thumbnail, VideoDecodeAcceleratorParamTest, |
| + Thumbnail, |
| + VideoDecodeAcceleratorParamTest, |
| ::testing::Values( |
| - MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, true))); |
| + MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, true, false))); |
| // Measure the median of the decode time when VDA::Decode is called 30 times per |
| // second. |
| @@ -1540,7 +1687,8 @@ TEST_F(VideoDecodeAcceleratorTest, TestDecodeTimeMedian) { |
| true, |
| std::numeric_limits<int>::max(), |
| kWebRtcDecodeCallsPerSecond, |
| - false /* render_as_thumbnail */); |
| + false /* render_as_thumbnail */, |
| + false /* test_full_flush */); |
| helper_params.window_sizes.push_back( |
| gfx::Size(test_video_files_[0]->width, test_video_files_[0]->height)); |
| InitializeRenderingHelper(helper_params); |