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