media/gpu/test: Add new VDA test for multiple queued buffer decode requests.
This CL adds a test that requests multiple bitstream buffer decodes, without
waiting for the result of the previous decode operation.
TEST=ran new VDA tests on nocturne
BUG=879065
Change-Id: I72352206ae56e9a3e4f62f87271c978bbad7bfee
Reviewed-on: https://chromium-review.googlesource.com/c/1419560
Commit-Queue: David Staessens <dstaessens@chromium.org>
Reviewed-by: Alexandre Courbot <acourbot@chromium.org>
Cr-Commit-Position: refs/heads/master@{#624723}
diff --git a/media/gpu/test/video_player/video_decoder_client.cc b/media/gpu/test/video_player/video_decoder_client.cc
index 6e3e1f6..b07e3f65 100644
--- a/media/gpu/test/video_player/video_decoder_client.cc
+++ b/media/gpu/test/video_player/video_decoder_client.cc
@@ -25,12 +25,14 @@
VideoDecoderClient::VideoDecoderClient(
const VideoPlayer::EventCallback& event_cb,
FrameRenderer* renderer,
- const std::vector<VideoFrameProcessor*>& frame_processors)
+ const std::vector<VideoFrameProcessor*>& frame_processors,
+ const VideoDecoderClientConfig& config)
: event_cb_(event_cb),
frame_renderer_(renderer),
frame_processors_(frame_processors),
decoder_client_thread_("VDAClientDecoderThread"),
decoder_client_state_(VideoDecoderClientState::kUninitialized),
+ decoder_client_config_(config),
weak_this_factory_(this) {
DETACH_FROM_SEQUENCE(decoder_client_sequence_checker_);
weak_this_ = weak_this_factory_.GetWeakPtr();
@@ -45,9 +47,10 @@
std::unique_ptr<VideoDecoderClient> VideoDecoderClient::Create(
const VideoPlayer::EventCallback& event_cb,
FrameRenderer* frame_renderer,
- const std::vector<VideoFrameProcessor*>& frame_processors) {
- auto decoder_client = base::WrapUnique(
- new VideoDecoderClient(event_cb, frame_renderer, frame_processors));
+ const std::vector<VideoFrameProcessor*>& frame_processors,
+ const VideoDecoderClientConfig& config) {
+ auto decoder_client = base::WrapUnique(new VideoDecoderClient(
+ event_cb, frame_renderer, frame_processors, config));
if (!decoder_client->Initialize()) {
return nullptr;
}
@@ -198,20 +201,17 @@
DCHECK_NE(VideoDecoderClientState::kIdle, decoder_client_state_);
DVLOGF(4);
- // Queue the next fragment to be decoded. Flush when we reached the end of the
- // stream.
- if (encoded_data_helper_->ReachEndOfStream()) {
- decoder_client_thread_.task_runner()->PostTask(
- FROM_HERE, base::BindOnce(&VideoDecoderClient::FlushTask, weak_this_));
- } else {
- decoder_client_thread_.task_runner()->PostTask(
- FROM_HERE, base::BindOnce(&VideoDecoderClient::DecodeNextFragmentTask,
- weak_this_));
- }
+ num_outstanding_decode_requests_--;
+
+ // Queue the next fragment to be decoded.
+ decoder_client_thread_.task_runner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&VideoDecoderClient::DecodeNextFragmentTask, weak_this_));
}
void VideoDecoderClient::NotifyFlushDone() {
DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_client_sequence_checker_);
+ DCHECK_EQ(0u, num_outstanding_decode_requests_);
decoder_client_state_ = VideoDecoderClientState::kIdle;
event_cb_.Run(VideoPlayerEvent::kFlushDone);
@@ -219,6 +219,7 @@
void VideoDecoderClient::NotifyResetDone() {
DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_client_sequence_checker_);
+ DCHECK_EQ(0u, num_outstanding_decode_requests_);
// We finished resetting to a different point in the stream, so we should
// update the frame index. Currently only resetting to the start of the stream
@@ -303,6 +304,7 @@
void VideoDecoderClient::DestroyDecoderTask(base::WaitableEvent* done) {
DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_client_sequence_checker_);
DCHECK_EQ(VideoDecoderClientState::kIdle, decoder_client_state_);
+ DCHECK_EQ(0u, num_outstanding_decode_requests_);
DVLOGF(4);
// Invalidate all scheduled tasks.
@@ -328,8 +330,10 @@
if (decoder_client_state_ != VideoDecoderClientState::kDecoding)
return;
+ // Flush immediately when we reached the end of the stream. This changes the
+ // state to kFlushing so further decode tasks will be aborted.
if (encoded_data_helper_->ReachEndOfStream()) {
- LOG(ERROR) << "End of stream reached";
+ FlushTask();
return;
}
@@ -354,6 +358,7 @@
DVLOGF(4) << "Bitstream buffer id: " << bitstream_buffer_id;
decoder_->Decode(bitstream_buffer);
+ num_outstanding_decode_requests_++;
}
void VideoDecoderClient::PlayTask() {
@@ -364,11 +369,13 @@
// called e.g. while flushing, the behavior is undefined.
ASSERT_EQ(decoder_client_state_, VideoDecoderClientState::kIdle);
- // Start decoding the first fragment. While in the decoding state new
+ // Start decoding the first fragments. While in the decoding state new
// fragments will automatically be fed to the decoder, when the decoder
- // notifies us it reached the end of the current bitstream.
+ // notifies us it reached the end of a bitstream buffer.
decoder_client_state_ = VideoDecoderClientState::kDecoding;
- DecodeNextFragmentTask();
+ for (size_t i = 0; i < decoder_client_config_.max_outstanding_decode_requests;
+ ++i)
+ DecodeNextFragmentTask();
}
void VideoDecoderClient::FlushTask() {
diff --git a/media/gpu/test/video_player/video_decoder_client.h b/media/gpu/test/video_player/video_decoder_client.h
index 6ec7d8e..a694024 100644
--- a/media/gpu/test/video_player/video_decoder_client.h
+++ b/media/gpu/test/video_player/video_decoder_client.h
@@ -27,6 +27,13 @@
class FrameRenderer;
class VideoFrameProcessor;
+// Video decoder client configuration.
+struct VideoDecoderClientConfig {
+ // The maximum number of bitstream buffer decodes that can be requested
+ // without waiting for the result of the previous decode requests.
+ size_t max_outstanding_decode_requests = 1;
+};
+
// The video decoder client is responsible for the communication between the
// video player and the video decoder. It also communicates with the frame
// renderer and other components. The video decoder client can only have one
@@ -49,7 +56,8 @@
static std::unique_ptr<VideoDecoderClient> Create(
const VideoPlayer::EventCallback& event_cb,
FrameRenderer* frame_renderer,
- const std::vector<VideoFrameProcessor*>& frame_processors);
+ const std::vector<VideoFrameProcessor*>& frame_processors,
+ const VideoDecoderClientConfig& config);
// Create a decoder with specified |config| and video |stream|. The video
// will not be owned by the decoder client, the caller should guarantee it
@@ -81,7 +89,8 @@
VideoDecoderClient(const VideoPlayer::EventCallback& event_cb,
FrameRenderer* renderer,
- const std::vector<VideoFrameProcessor*>& frame_processors);
+ const std::vector<VideoFrameProcessor*>& frame_processors,
+ const VideoDecoderClientConfig& config);
bool Initialize();
void Destroy();
@@ -141,6 +150,10 @@
// Index of the frame that's currently being decoded.
size_t current_frame_index_ = 0;
+ // The current number of outgoing bitstream buffers decode requests.
+ size_t num_outstanding_decode_requests_ = 0;
+ // Video decoder client configuration.
+ const VideoDecoderClientConfig decoder_client_config_;
// TODO(dstaessens@) Replace with StreamParser.
std::unique_ptr<media::test::EncodedDataHelper> encoded_data_helper_;
diff --git a/media/gpu/test/video_player/video_player.cc b/media/gpu/test/video_player/video_player.cc
index bfbd514..481d4e0 100644
--- a/media/gpu/test/video_player/video_player.cc
+++ b/media/gpu/test/video_player/video_player.cc
@@ -32,16 +32,18 @@
std::unique_ptr<VideoPlayer> VideoPlayer::Create(
const Video* video,
FrameRenderer* frame_renderer,
- const std::vector<VideoFrameProcessor*>& frame_processors) {
+ const std::vector<VideoFrameProcessor*>& frame_processors,
+ const VideoDecoderClientConfig& config) {
auto video_player = base::WrapUnique(new VideoPlayer());
- video_player->Initialize(video, frame_renderer, frame_processors);
+ video_player->Initialize(video, frame_renderer, frame_processors, config);
return video_player;
}
void VideoPlayer::Initialize(
const Video* video,
FrameRenderer* frame_renderer,
- const std::vector<VideoFrameProcessor*>& frame_processors) {
+ const std::vector<VideoFrameProcessor*>& frame_processors,
+ const VideoDecoderClientConfig& config) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(video_player_state_, VideoPlayerState::kUninitialized);
DCHECK(frame_renderer && video);
@@ -50,8 +52,8 @@
EventCallback event_cb =
base::BindRepeating(&VideoPlayer::NotifyEvent, base::Unretained(this));
- decoder_client_ =
- VideoDecoderClient::Create(event_cb, frame_renderer, frame_processors);
+ decoder_client_ = VideoDecoderClient::Create(event_cb, frame_renderer,
+ frame_processors, config);
CHECK(decoder_client_) << "Failed to create decoder client";
// Create a decoder for the specified video. We'll always use import mode as
diff --git a/media/gpu/test/video_player/video_player.h b/media/gpu/test/video_player/video_player.h
index c6cc240..5c9df26e 100644
--- a/media/gpu/test/video_player/video_player.h
+++ b/media/gpu/test/video_player/video_player.h
@@ -21,6 +21,7 @@
class FrameRenderer;
class Video;
class VideoDecoderClient;
+struct VideoDecoderClientConfig;
class VideoFrameProcessor;
// Default timeout used when waiting for events.
@@ -57,7 +58,8 @@
static std::unique_ptr<VideoPlayer> Create(
const Video* video,
FrameRenderer* frame_renderer,
- const std::vector<VideoFrameProcessor*>& frame_processors);
+ const std::vector<VideoFrameProcessor*>& frame_processors,
+ const VideoDecoderClientConfig& config);
void Play();
void Stop();
@@ -99,7 +101,8 @@
void Initialize(const Video* video,
FrameRenderer* frame_renderer,
- const std::vector<VideoFrameProcessor*>& frame_processors);
+ const std::vector<VideoFrameProcessor*>& frame_processors,
+ const VideoDecoderClientConfig& config);
void Destroy();
// Notify the client an event has occurred (e.g. frame decoded).
diff --git a/media/gpu/video_decode_accelerator_tests.cc b/media/gpu/video_decode_accelerator_tests.cc
index 76354ad..398efdac 100644
--- a/media/gpu/video_decode_accelerator_tests.cc
+++ b/media/gpu/video_decode_accelerator_tests.cc
@@ -12,6 +12,7 @@
#include "media/gpu/test/video_player/frame_renderer_dummy.h"
#include "media/gpu/test/video_player/video.h"
#include "media/gpu/test/video_player/video_collection.h"
+#include "media/gpu/test/video_player/video_decoder_client.h"
#include "media/gpu/test/video_player/video_player.h"
#include "mojo/core/embedder/embedder.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -75,11 +76,13 @@
// Video decode test class. Performs setup and teardown for each single test.
class VideoDecoderTest : public ::testing::Test {
public:
- std::unique_ptr<VideoPlayer> CreateVideoPlayer(const Video* video) {
+ std::unique_ptr<VideoPlayer> CreateVideoPlayer(
+ const Video* video,
+ const VideoDecoderClientConfig& config = VideoDecoderClientConfig()) {
frame_validator_ =
media::test::VideoFrameValidator::Create(video->FrameChecksums());
return VideoPlayer::Create(video, g_env->dummy_frame_renderer_.get(),
- {frame_validator_.get()});
+ {frame_validator_.get()}, config);
}
protected:
@@ -211,6 +214,21 @@
EXPECT_EQ(0u, frame_validator_->GetMismatchedFramesCount());
}
+// Play video from start to end. Multiple buffer decodes will be queued in the
+// decoder, without waiting for the result of the previous decode requests.
+TEST_F(VideoDecoderTest, FlushAtEndOfStream_MultipleOutstandingDecodes) {
+ VideoDecoderClientConfig config;
+ config.max_outstanding_decode_requests = 5;
+ auto tvp = CreateVideoPlayer(g_env->video_, config);
+
+ tvp->Play();
+ EXPECT_TRUE(tvp->WaitForFlushDone());
+
+ EXPECT_EQ(tvp->GetFlushDoneCount(), 1u);
+ EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->video_->NumFrames());
+ EXPECT_EQ(0u, frame_validator_->GetMismatchedFramesCount());
+}
+
} // namespace test
} // namespace media