| 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 94c0b3664a5f693730c56aafa15500881644ba68..942d7709ae91261de13c91d4bf982100771701bf 100644
|
| --- a/content/common/gpu/media/video_decode_accelerator_unittest.cc
|
| +++ b/content/common/gpu/media/video_decode_accelerator_unittest.cc
|
| @@ -325,6 +325,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,
|
| @@ -340,7 +342,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();
|
|
|
| @@ -375,7 +378,10 @@ class GLRenderingVDAClient
|
|
|
| void SetState(ClientState new_state);
|
| void FinishInitialization();
|
| + void ReturnTexture(int32_t picture_buffer_id);
|
| void ReturnPicture(int32_t picture_buffer_id);
|
| + void CallReusePicture(int32_t picture_buffer_id);
|
| + void FinishFlush();
|
|
|
| // Delete the associated decoder helper.
|
| void DeleteDecoder();
|
| @@ -417,6 +423,7 @@ class GLRenderingVDAClient
|
| int num_queued_fragments_;
|
| int num_decoded_frames_;
|
| int num_done_bitstream_buffers_;
|
| + int num_pictures_at_decoder_;
|
| base::TimeTicks initialize_done_ticks_;
|
| media::VideoCodecProfile profile_;
|
| int fake_decoder_;
|
| @@ -431,6 +438,7 @@ 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_;
|
|
|
| // A map of the textures that are currently active for the decoder, i.e.,
|
| // have been created via AssignPictureBuffers() and not dismissed via
|
| @@ -479,7 +487,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),
|
| @@ -497,12 +506,14 @@ GLRenderingVDAClient::GLRenderingVDAClient(
|
| num_queued_fragments_(0),
|
| num_decoded_frames_(0),
|
| num_done_bitstream_buffers_(0),
|
| + num_pictures_at_decoder_(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),
|
| weak_this_factory_(this) {
|
| LOG_ASSERT(num_in_flight_decodes > 0);
|
| @@ -529,10 +540,20 @@ void GLRenderingVDAClient::CreateAndStartDecoder() {
|
| LOG_ASSERT(decoder_deleted());
|
| LOG_ASSERT(!decoder_.get());
|
|
|
| + VideoDecodeAccelerator::Config config(profile_);
|
| + config.output_mode =
|
| + (g_test_import
|
| + ? media::VideoDecodeAccelerator::Config::OutputMode::IMPORT
|
| + : media::VideoDecodeAccelerator::Config::OutputMode::ALLOCATE);
|
| + config.flush_mode =
|
| + (test_full_flush_ ? media::VideoDecodeAccelerator::Config::FlushMode::
|
| + RETURN_OUTPUT_BUFFERS
|
| + : media::VideoDecodeAccelerator::Config::FlushMode::
|
| + KEEP_OUTPUT_BUFFERS);
|
| if (fake_decoder_) {
|
| decoder_.reset(new FakeVideoDecodeAccelerator(
|
| frame_size_, base::Bind(&DoNothingReturnTrue)));
|
| - LOG_ASSERT(decoder_->Initialize(profile_, this));
|
| + LOG_ASSERT(decoder_->Initialize(config, this));
|
| } else {
|
| if (!vda_factory_) {
|
| vda_factory_ = GpuVideoDecodeAcceleratorFactoryImpl::Create(
|
| @@ -542,16 +563,14 @@ void GLRenderingVDAClient::CreateAndStartDecoder() {
|
| LOG_ASSERT(vda_factory_);
|
| }
|
|
|
| - VideoDecodeAccelerator::Config config(profile_);
|
| - if (g_test_import) {
|
| - config.output_mode =
|
| - media::VideoDecodeAccelerator::Config::OutputMode::IMPORT;
|
| - }
|
| gpu::GpuPreferences gpu_preferences;
|
| decoder_ = vda_factory_->CreateVDA(this, config, gpu_preferences);
|
| }
|
|
|
| LOG_ASSERT(decoder_) << "Failed creating a VDA";
|
| + weak_vda_ptr_factory_.reset(
|
| + new base::WeakPtrFactory<VideoDecodeAccelerator>(decoder_.get()));
|
| + weak_vda_ = weak_vda_ptr_factory_->GetWeakPtr();
|
|
|
| decoder_->TryToSetupDecodeOnSeparateThread(
|
| weak_this_, base::ThreadTaskRunnerHandle::Get());
|
| @@ -645,10 +664,14 @@ void GLRenderingVDAClient::ProvidePictureBuffers(
|
| decoder_->ImportBufferForPicture(buffer.id(), handles);
|
| }
|
| }
|
| +
|
| + num_pictures_at_decoder_ = buffers.size();
|
| }
|
|
|
| void GLRenderingVDAClient::DismissPictureBuffer(int32_t picture_buffer_id) {
|
| LOG_ASSERT(1U == active_textures_.erase(picture_buffer_id));
|
| + EXPECT_GT(num_pictures_at_decoder_, 0);
|
| + --num_pictures_at_decoder_;
|
| }
|
|
|
| void GLRenderingVDAClient::PictureReady(const media::Picture& picture) {
|
| @@ -658,6 +681,15 @@ void GLRenderingVDAClient::PictureReady(const media::Picture& picture) {
|
| if (decoder_deleted())
|
| return;
|
|
|
| + EXPECT_GT(num_pictures_at_decoder_, 0);
|
| + --num_pictures_at_decoder_;
|
| +
|
| + 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 +721,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 +733,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,13 +745,36 @@ void GLRenderingVDAClient::ReturnPicture(int32_t picture_buffer_id) {
|
| return;
|
| }
|
|
|
| + ReturnPicture(picture_buffer_id);
|
| +}
|
| +
|
| +void GLRenderingVDAClient::CallReusePicture(int32_t picture_buffer_id) {
|
| + if (state_ == CS_FLUSHED && test_full_flush_) {
|
| + // If we just got a notification from the VDA that it's flushed and are
|
| + // testing full flush, we want to have a chance to test that VDA really
|
| + // returned all buffers before NotifyFlushDone(). Delay returning the buffer
|
| + // so that we have a chance in FinishFlush() to test we got all the buffers.
|
| + base::MessageLoop::current()->PostTask(
|
| + FROM_HERE, base::Bind(&GLRenderingVDAClient::CallReusePicture,
|
| + weak_this_, picture_buffer_id));
|
| + return;
|
| + }
|
| +
|
| + if (weak_vda_)
|
| + weak_vda_->ReusePictureBuffer(picture_buffer_id);
|
| + ++num_pictures_at_decoder_;
|
| +}
|
| +
|
| +void GLRenderingVDAClient::ReturnPicture(int32_t picture_buffer_id) {
|
| if (num_decoded_frames_ > delay_reuse_after_frame_num_) {
|
| base::MessageLoop::current()->PostDelayedTask(
|
| - FROM_HERE, base::Bind(&VideoDecodeAccelerator::ReusePictureBuffer,
|
| - weak_vda_, picture_buffer_id),
|
| + FROM_HERE, base::Bind(&GLRenderingVDAClient::CallReusePicture,
|
| + weak_this_, picture_buffer_id),
|
| kReuseDelay);
|
| } else {
|
| - decoder_->ReusePictureBuffer(picture_buffer_id);
|
| + base::MessageLoop::current()->PostTask(
|
| + FROM_HERE, base::Bind(&GLRenderingVDAClient::CallReusePicture,
|
| + weak_this_, picture_buffer_id));
|
| }
|
| }
|
|
|
| @@ -745,11 +801,11 @@ void GLRenderingVDAClient::NotifyEndOfBitstreamBuffer(
|
| }
|
| }
|
|
|
| -void GLRenderingVDAClient::NotifyFlushDone() {
|
| - if (decoder_deleted())
|
| - return;
|
| +void GLRenderingVDAClient::FinishFlush() {
|
| + ASSERT_EQ(CS_FLUSHED, state_);
|
| + if (test_full_flush_)
|
| + EXPECT_EQ(0, num_pictures_at_decoder_);
|
|
|
| - SetState(CS_FLUSHED);
|
| --remaining_play_throughs_;
|
| DCHECK_GE(remaining_play_throughs_, 0);
|
| if (decoder_deleted())
|
| @@ -758,6 +814,27 @@ void GLRenderingVDAClient::NotifyFlushDone() {
|
| SetState(CS_RESETTING);
|
| }
|
|
|
| +void GLRenderingVDAClient::NotifyFlushDone() {
|
| + if (decoder_deleted())
|
| + return;
|
| +
|
| + ASSERT_EQ(CS_FLUSHING, state_);
|
| + SetState(CS_FLUSHED);
|
| +
|
| + // We may have already posted some ReusePictureBuffer() calls before we got
|
| + // here. If we are testing RETURN_OUTPUT_BUFFERS flush mode, make sure we
|
| + // don't execute them returning the buffers to VDA until we have a chance
|
| + // to verify the VDA really returned all the buffers before finishing flush.
|
| + // Otherwise, we don't care and can continue without holding off any pending
|
| + // ReusePictureBuffer() calls
|
| + if (test_full_flush_) {
|
| + base::MessageLoop::current()->PostTask(
|
| + FROM_HERE, base::Bind(&GLRenderingVDAClient::FinishFlush, weak_this_));
|
| + } else {
|
| + FinishFlush();
|
| + }
|
| +}
|
| +
|
| void GLRenderingVDAClient::NotifyResetDone() {
|
| if (decoder_deleted())
|
| return;
|
| @@ -1192,10 +1269,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
|
| @@ -1226,6 +1305,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();
|
| @@ -1284,7 +1364,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(
|
| @@ -1439,59 +1520,74 @@ TEST_P(VideoDecodeAcceleratorParamTest, TestSimpleDecode) {
|
| INSTANTIATE_TEST_CASE_P(
|
| ReplayAfterEOS, VideoDecodeAcceleratorParamTest,
|
| ::testing::Values(
|
| - MakeTuple(1, 1, 4, END_OF_STREAM_RESET, CS_RESET, false, false)));
|
| + 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)));
|
| + 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)));
|
| + 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,
|
| ::testing::Values(
|
| - MakeTuple(1, 1, 1, MID_STREAM_RESET, CS_RESET, false, false)));
|
| + 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, true)));
|
| +
|
|
|
| INSTANTIATE_TEST_CASE_P(
|
| 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,
|
| ::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, 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),
|
| + static_cast<ClientState>(-1), false, false, false),
|
| MakeTuple(1, 1, 1, END_OF_STREAM_RESET,
|
| - static_cast<ClientState>(-10), false, false),
|
| + static_cast<ClientState>(-10), false, false, false),
|
| MakeTuple(1, 1, 1, END_OF_STREAM_RESET,
|
| - static_cast<ClientState>(-100), false, false)));
|
| + static_cast<ClientState>(-100), false, false, false)));
|
|
|
| // Test that decoding various variation works with multiple in-flight decodes.
|
| INSTANTIATE_TEST_CASE_P(
|
| 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.
|
| @@ -1500,15 +1596,15 @@ INSTANTIATE_TEST_CASE_P(
|
| ::testing::Values(
|
| // +0 hack below to promote enum to int.
|
| MakeTuple(kMinSupportedNumConcurrentDecoders + 0, 1, 1,
|
| - END_OF_STREAM_RESET, CS_RESET, false, false),
|
| + END_OF_STREAM_RESET, CS_RESET, false, false, false),
|
| MakeTuple(kMinSupportedNumConcurrentDecoders + 1, 1, 1,
|
| - END_OF_STREAM_RESET, CS_RESET, false, false)));
|
| + END_OF_STREAM_RESET, CS_RESET, false, false, false)));
|
|
|
| // Thumbnailing test
|
| INSTANTIATE_TEST_CASE_P(
|
| 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.
|
| @@ -1538,7 +1634,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);
|
|
|