chromium/media/gpu/test/video_decode_accelerator_tests.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <limits>
#include <memory>

#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/cpu.h"
#include "base/files/file_util.h"
#include "base/functional/callback_helpers.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/test/bind.h"
#include "base/test/launcher/unit_test_launcher.h"
#include "build/build_config.h"
#include "media/base/decoder_buffer.h"
#include "media/base/encryption_scheme.h"
#include "media/base/media_switches.h"
#include "media/base/media_util.h"
#include "media/base/test_data_util.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_transformation.h"
#include "media/filters/dav1d_video_decoder.h"
#include "media/gpu/test/video_bitstream.h"
#include "media/gpu/test/video_decode_accelerator_test_suite.h"
#include "media/gpu/test/video_frame_file_writer.h"
#include "media/gpu/test/video_frame_validator.h"
#include "media/gpu/test/video_player/decoder_listener.h"
#include "media/gpu/test/video_player/decoder_wrapper.h"
#include "media/gpu/test/video_player/frame_renderer_dummy.h"
#include "media/gpu/test/video_player/video_player_test_environment.h"
#include "media/gpu/test/video_test_helpers.h"
#include "media/media_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"

#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
#include "media/gpu/chromeos/video_decoder_pipeline.h"
#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)

#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
#include "media/gpu/chromeos/platform_video_frame_pool.h"
#endif  // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)

namespace media {
namespace test {

namespace {

media::test::VideoDecodeAcceleratorTestSuite* g_env;

// Video decode test class. Performs setup and teardown for each single test.
class VideoDecoderTest : public ::testing::Test {};

}  // namespace

#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
TEST_F(VideoDecoderTest, GetSupportedConfigs) {}
#endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)

// Test initializing the video decoder for the specified video. Initialization
// will be successful if the video decoder is capable of decoding the test
// video's configuration (e.g. codec and resolution). The test only verifies
// initialization and doesn't decode the video.
TEST_F(VideoDecoderTest, Initialize) {}

// Test video decoder simple re-initialization: Initialize, then without
// playing, re-initialize.
TEST_F(VideoDecoderTest, Reinitialize) {}

// Test video decoder simple re-initialization, then re-initialization after a
// successful play.
TEST_F(VideoDecoderTest, ReinitializeThenPlayThenInitialize) {}

// Create a video decoder and immediately destroy it without initializing. The
// video decoder will be automatically destroyed when the video player goes out
// of scope at the end of the test. The test will pass if no asserts or crashes
// are triggered upon destroying.
TEST_F(VideoDecoderTest, DestroyBeforeInitialize) {}

#if BUILDFLAG(USE_V4L2_CODEC)
// This test case calls Decode() a number of times and expect OK DecodeCBs. This
// test only makes sense for V4L2 (VA-API doesn't have an input queue).
TEST_F(VideoDecoderTest, Decode) {
  auto tvp = CreateDecoderListener(g_env->Video());

  tvp->Play();
  // We usually allocate at least 8 buffers for input queues.
  const size_t kNumDecodeBuffers = 8;
  EXPECT_TRUE(tvp->WaitForEvent(DecoderListener::Event::kDecoderBufferAccepted,
                                /*times=*/kNumDecodeBuffers));
}

// This test case sends all the frames and expects them to be accepted for
// decoding (as in, VideoDecoder::OutputCB should be called). Most of them
// should be decoded as well, but since this test doesn't exercise an
// End-of-Stream (a.k.a. "a flush"), some will likely be held onto by the
// VideoDecoder/driver as part of its decoding pipeline. We don't know how
// many (it depends also on the ImageProcessor, if any), so it's not a good
// idea to set expectations on the number of kFrameDecoded events.
TEST_F(VideoDecoderTest, AllDecoderBuffersAcceptedForDecoding) {
  auto tvp = CreateDecoderListener(g_env->Video());

  tvp->Play();
  EXPECT_TRUE(tvp->WaitForEvent(DecoderListener::Event::kDecoderBufferAccepted,
                                /*times=*/g_env->Video()->NumFrames()));

  // This is a hack to allow Qualcomm devices (e.g. trogdor) to flush the pipes
  // after the last resolution change event that comes out when running the
  // resolution_change_500frames.vp9.ivf sequence. It should be fixed but since
  // a new V4L2StatefulVideoDecoder backend is in the making, let's just leave
  // the hack. See b/294611425.
  base::PlatformThread::Sleep(base::Milliseconds(100));
}
#endif

// Play video from start to end. Wait for the kFlushDone event at the end of the
// stream, that notifies us all frames have been decoded.
TEST_F(VideoDecoderTest, FlushAtEndOfStream) {}

#if BUILDFLAG(USE_V4L2_CODEC)
// Flush the decoder somewhere mid-stream, then continue as normal. This is a
// contrived use case to exercise important V4L2 stateful areas.
TEST_F(VideoDecoderTest, DISABLED_FlushMidStream) {
  if (!base::FeatureList::IsEnabled(kV4L2FlatStatefulVideoDecoder)) {
    GTEST_SKIP();
  }

  auto tvp = CreateDecoderListener(g_env->Video());

  tvp->Play();
  const size_t flush_location_in_frames =
      std::min(static_cast<size_t>(10), g_env->Video()->NumFrames() / 2);
  EXPECT_TRUE(tvp->WaitForFrameDecoded(flush_location_in_frames));
  tvp->Flush();
  EXPECT_TRUE(tvp->WaitForFlushDone());
  // GetFrameDecodedCount() is likely larger than |flush_location_in_frames|
  // because there are likely submitted encoded chunks ready to be decoded at
  // the time of Flush().
  EXPECT_GE(tvp->GetFrameDecodedCount(), flush_location_in_frames);
  tvp->Play();
  EXPECT_TRUE(tvp->WaitForFlushDone());

  // Total flush count must be two: once mid-stream and once at the end.
  EXPECT_EQ(tvp->GetFlushDoneCount(), 2u);

  // The H264 bitstreams in our test set have B-frames; by Flush()ing carelessly
  // like we do here in this test, we're likely to lose needed references that
  // later B-frames will need. Those B-frames will be discarded.
  // TODO(mcasas): Flush at an IDR frame.
  const bool has_b_frames = g_env->Video()->Codec() == VideoCodec::kH264;
  if (!has_b_frames)
    EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->Video()->NumFrames());
  else
    EXPECT_LE(tvp->GetFrameDecodedCount(), g_env->Video()->NumFrames());
  EXPECT_TRUE(tvp->WaitForFrameProcessors());
}
#endif

// Flush the decoder immediately after initialization.
TEST_F(VideoDecoderTest, FlushAfterInitialize) {}

// Reset the decoder immediately after initialization.
TEST_F(VideoDecoderTest, ResetAfterInitialize) {}

// Reset the decoder when the middle of the stream is reached.
TEST_F(VideoDecoderTest, ResetMidStream) {}

// Reset the decoder when the end of the stream is reached.
TEST_F(VideoDecoderTest, ResetEndOfStream) {}

// Reset the decoder immediately when the end-of-stream flush starts, without
// waiting for a kFlushDone event.
TEST_F(VideoDecoderTest, ResetBeforeFlushDone) {}

// Reset the decoder immediately when encountering the first config info in a
// H.264/HEVC video stream. After resetting the video is played until the end.
TEST_F(VideoDecoderTest, ResetAfterFirstConfigInfo) {}

TEST_F(VideoDecoderTest, ResolutionChangeAbortedByReset) {}

// 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) {}

// Play multiple videos simultaneously from start to finish.
TEST_F(VideoDecoderTest, FlushAtEndOfStream_MultipleConcurrentDecodes) {}

TEST_F(VideoDecoderTest, InitializeWithNonSupportedConfig) {}

}  // namespace test
}  // namespace media

int main(int argc, char** argv) {}