| Index: media/gpu/android_video_decode_accelerator_unittest.cc
|
| diff --git a/media/gpu/android_video_decode_accelerator_unittest.cc b/media/gpu/android_video_decode_accelerator_unittest.cc
|
| index f8c2aa85a6614e7578cbbc588266463f8f41aece..0f76a2f4da5542bbfc63e2544be54665e418c5b3 100644
|
| --- a/media/gpu/android_video_decode_accelerator_unittest.cc
|
| +++ b/media/gpu/android_video_decode_accelerator_unittest.cc
|
| @@ -11,24 +11,33 @@
|
| #include "base/android/jni_android.h"
|
| #include "base/bind.h"
|
| #include "base/logging.h"
|
| +#include "base/memory/ptr_util.h"
|
| +#include "base/memory/weak_ptr.h"
|
| #include "base/message_loop/message_loop.h"
|
| #include "base/run_loop.h"
|
| #include "base/threading/thread_task_runner_handle.h"
|
| #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
|
| #include "media/base/android/media_codec_util.h"
|
| #include "media/base/android/media_jni_registrar.h"
|
| +#include "media/base/android/mock_android_overlay.h"
|
| +#include "media/base/android/mock_media_codec_bridge.h"
|
| #include "media/gpu/android_video_decode_accelerator.h"
|
| #include "media/gpu/avda_codec_allocator.h"
|
| +#include "media/gpu/avda_overlay_helper.h"
|
| #include "media/video/picture.h"
|
| #include "media/video/video_decode_accelerator.h"
|
| #include "testing/gmock/include/gmock/gmock.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
| +#include "ui/gl/android/surface_texture.h"
|
| #include "ui/gl/gl_context.h"
|
| #include "ui/gl/gl_surface.h"
|
| #include "ui/gl/init/gl_factory.h"
|
|
|
| using ::testing::_;
|
| using ::testing::NiceMock;
|
| +using ::testing::NotNull;
|
| +using ::testing::Return;
|
| +using ::testing::StrictMock;
|
|
|
| namespace media {
|
| namespace {
|
| @@ -48,43 +57,240 @@ base::WeakPtr<gpu::gles2::GLES2Decoder> GetGLES2Decoder(
|
| return decoder;
|
| }
|
|
|
| -ACTION(PostNullCodec) {
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(&media::AVDACodecAllocatorClient::OnCodecConfigured,
|
| - arg0, nullptr));
|
| -}
|
| -
|
| } // namespace
|
|
|
| -class MockVDAClient : public VideoDecodeAccelerator::Client {
|
| +class AndroidVideoDecodeAcceleratorTest : public testing::Test {
|
| public:
|
| - MOCK_METHOD1(NotifyInitializationComplete, void(bool));
|
| - MOCK_METHOD5(
|
| - ProvidePictureBuffers,
|
| - void(uint32_t, VideoPixelFormat, uint32_t, const gfx::Size&, uint32_t));
|
| - MOCK_METHOD1(DismissPictureBuffer, void(int32_t));
|
| - MOCK_METHOD1(PictureReady, void(const Picture&));
|
| - MOCK_METHOD1(NotifyEndOfBitstreamBuffer, void(int32_t));
|
| - MOCK_METHOD0(NotifyFlushDone, void());
|
| - MOCK_METHOD0(NotifyResetDone, void());
|
| - MOCK_METHOD1(NotifyError, void(VideoDecodeAccelerator::Error));
|
| -};
|
| + class MockVDAClient : public VideoDecodeAccelerator::Client {
|
| + public:
|
| + MockVDAClient() {}
|
|
|
| -class MockCodecAllocator : public AVDACodecAllocator {
|
| - public:
|
| - MOCK_METHOD2(CreateMediaCodecAsync,
|
| - void(base::WeakPtr<AVDACodecAllocatorClient>,
|
| - scoped_refptr<CodecConfig>));
|
| -};
|
| + MOCK_METHOD1(NotifyInitializationComplete, void(bool));
|
| + MOCK_METHOD5(
|
| + ProvidePictureBuffers,
|
| + void(uint32_t, VideoPixelFormat, uint32_t, const gfx::Size&, uint32_t));
|
| + MOCK_METHOD1(DismissPictureBuffer, void(int32_t));
|
| + MOCK_METHOD1(PictureReady, void(const Picture&));
|
| + MOCK_METHOD1(NotifyEndOfBitstreamBuffer, void(int32_t));
|
| + MOCK_METHOD0(NotifyFlushDone, void());
|
| + MOCK_METHOD0(NotifyResetDone, void());
|
| + MOCK_METHOD1(NotifyError, void(VideoDecodeAccelerator::Error));
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(MockVDAClient);
|
| + };
|
| +
|
| + // Codec allocator that lets you count calls on Mock* methods, and also
|
| + // lets you answer the codec.
|
| + class FakeCodecAllocator : public StrictMock<AVDACodecAllocator> {
|
| + public:
|
| + FakeCodecAllocator() {}
|
| +
|
| + // These are called with some parameters of the codec config by our
|
| + // implementatin of their respective functions. This allows tests to set
|
| + // expectations on them.
|
| + MOCK_METHOD2(MockCreateMediaCodecSync,
|
| + void(AndroidOverlay*, gl::SurfaceTexture*));
|
| + MOCK_METHOD2(MockCreateMediaCodecAsync,
|
| + void(AndroidOverlay*, gl::SurfaceTexture*));
|
| +
|
| + // Note that this doesn't exactly match the signature, since unique_ptr
|
| + // doesn't work. plus, we expand |surface_bundle| a bit to make it more
|
| + // convenient to set expectations.
|
| + MOCK_METHOD3(MockReleaseMediaCodec,
|
| + void(MediaCodecBridge*, AndroidOverlay*, gl::SurfaceTexture*));
|
| +
|
| + std::unique_ptr<MediaCodecBridge> CreateMediaCodecSync(
|
| + scoped_refptr<CodecConfig> codec_config) override {
|
| + MockCreateMediaCodecSync(
|
| + codec_config->surface_bundle->overlay.get(),
|
| + codec_config->surface_bundle->surface_texture.get());
|
| +
|
| + CopyCodecAllocParams(codec_config);
|
| +
|
| + std::unique_ptr<MockMediaCodecBridge> codec;
|
| + if (allow_sync_creation)
|
| + codec = base::MakeUnique<MockMediaCodecBridge>();
|
| +
|
| + if (codec)
|
| + most_recent_codec_ = codec->GetWeakPtr();
|
| + else
|
| + most_recent_codec_ = nullptr;
|
| +
|
| + return std::move(codec);
|
| + }
|
| +
|
| + void CreateMediaCodecAsync(base::WeakPtr<AVDACodecAllocatorClient> client,
|
| + scoped_refptr<CodecConfig> config) override {
|
| + // Clear |most_recent_codec_| until somebody calls Provide*CodecAsync().
|
| + most_recent_codec_ = nullptr;
|
| + CopyCodecAllocParams(config);
|
| + client_ = client;
|
| +
|
| + MockCreateMediaCodecAsync(most_recent_overlay(),
|
| + most_recent_surface_texture());
|
| + }
|
| +
|
| + void ReleaseMediaCodec(
|
| + std::unique_ptr<MediaCodecBridge> media_codec,
|
| + TaskType task_type,
|
| + const scoped_refptr<AVDASurfaceBundle>& surface_bundle) override {
|
| + MockReleaseMediaCodec(media_codec.get(), surface_bundle->overlay.get(),
|
| + surface_bundle->surface_texture.get());
|
| + }
|
| +
|
| + // Provide AVDA with a mock codec.
|
| + void ProvideMockCodecAsync() {
|
| + // If AVDA hasn't requested a codec, then get mad.
|
| + ASSERT_TRUE(client_);
|
| + if (!client_)
|
| + return;
|
| +
|
| + std::unique_ptr<MockMediaCodecBridge> codec =
|
| + base::MakeUnique<MockMediaCodecBridge>();
|
| + most_recent_codec_ = codec->GetWeakPtr();
|
| + client_->OnCodecConfigured(std::move(codec));
|
| + }
|
| +
|
| + // Provide AVDA will a null codec.
|
| + void ProvideNullCodecAsync() {
|
| + // If AVDA hasn't requested a codec, then get mad.
|
| + ASSERT_TRUE(client_);
|
| + if (!client_)
|
| + return;
|
| +
|
| + most_recent_codec_ = nullptr;
|
| + client_->OnCodecConfigured(nullptr);
|
| + }
|
| +
|
| + // Return the most recent bundle that we've received for codec allocation.
|
| + scoped_refptr<AVDASurfaceBundle> most_recent_bundle() {
|
| + return most_recent_bundle_;
|
| + }
|
| +
|
| + // Return the most recent codec that we provided, or null if it has been
|
| + // freed already.
|
| + MockMediaCodecBridge* most_recent_codec() {
|
| + return most_recent_codec_.get();
|
| + }
|
| +
|
| + // Return the most recent overlay / etc. that we were given during codec
|
| + // allocation (sync or async).
|
| + AndroidOverlay* most_recent_overlay() { return most_recent_overlay_; }
|
| + gl::SurfaceTexture* most_recent_surface_texture() {
|
| + return most_recent_surface_texture_;
|
| + }
|
| +
|
| + // Most recent codec that we've created via CreateMockCodec, since we have
|
| + // to assign ownership.
|
| + base::WeakPtr<MockMediaCodecBridge> most_recent_codec_;
|
| +
|
| + // Most recent surface bundle that we've gotten during codec allocation.
|
| + // This should be the same as |config_->surface_bundle| initially, but AVDA
|
| + // might change it.
|
| + scoped_refptr<AVDASurfaceBundle> most_recent_bundle_;
|
| +
|
| + // Most recent overlay provided during codec allocation.
|
| + AndroidOverlay* most_recent_overlay_ = nullptr;
|
| +
|
| + // Most recent surface texture provided during codec allocation.
|
| + gl::SurfaceTexture* most_recent_surface_texture_ = nullptr;
|
| +
|
| + // Should a call to CreateMediaCodecSync succeed?
|
| + bool allow_sync_creation = true;
|
| +
|
| + private:
|
| + // Copy |config| and all of the parameters we care about. We don't leave
|
| + // them all in config, since AVDA could change them at any time.
|
| + void CopyCodecAllocParams(scoped_refptr<CodecConfig> config) {
|
| + config_ = config;
|
| + most_recent_bundle_ = config->surface_bundle;
|
| + most_recent_overlay_ = config->surface_bundle->overlay.get();
|
| +
|
| + most_recent_surface_texture_ =
|
| + config->surface_bundle->surface_texture.get();
|
| + }
|
| +
|
| + base::WeakPtr<AVDACodecAllocatorClient> client_;
|
| + scoped_refptr<CodecConfig> config_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(FakeCodecAllocator);
|
| + };
|
| +
|
| + // Overlay helper that calls mocked functions to allow counting calls, but
|
| + // also records arguments. Note that gmock can't mock out unique_ptrs
|
| + // anyway, so we can't mock AVDAOverlayHelper directly.
|
| + class FakeOverlayHelper : public StrictMock<AVDAOverlayHelper> {
|
| + public:
|
| + FakeOverlayHelper() : weak_factory_(this) {}
|
| +
|
| + // These are called by the real functions. You may set expectations on
|
| + // them if you like.
|
| + MOCK_METHOD0(MockStartup, void());
|
| + MOCK_METHOD0(MockOnOverlayFactory, void());
|
| +
|
| + base::WeakPtr<FakeOverlayHelper> GetWeakPtr() {
|
| + return weak_factory_.GetWeakPtr();
|
| + }
|
| +
|
| + void Startup(
|
| + const UseOverlayCB& use_overlay_cb,
|
| + const UseSurfaceTextureCB& use_surface_texture_cb,
|
| + const StopUsingOverlayImmediatelyCB& stop_immediately_cb,
|
| + std::unique_ptr<AndroidOverlayFactory> initial_factory) override {
|
| + MockStartup();
|
| +
|
| + factory_ = std::move(initial_factory);
|
| + use_overlay_cb_ = use_overlay_cb;
|
| + use_surface_texture_cb_ = use_surface_texture_cb;
|
| + stop_immediately_cb_ = stop_immediately_cb;
|
| + }
|
| +
|
| + void OnOverlayFactory(
|
| + std::unique_ptr<AndroidOverlayFactory> factory) override {
|
| + MockOnOverlayFactory();
|
| + factory_ = std::move(factory);
|
| + }
|
| +
|
| + // Notify AVDA to use a surface texture.
|
| + void ProvideSurfaceTexture() {
|
| + use_surface_texture_cb_.Run();
|
| + base::RunLoop().RunUntilIdle();
|
| + }
|
| +
|
| + void ProvideOverlay(std::unique_ptr<AndroidOverlay> overlay) {
|
| + use_overlay_cb_.Run(std::move(overlay));
|
| + base::RunLoop().RunUntilIdle();
|
| + }
|
| +
|
| + void StopImmediately(AndroidOverlay* overlay) {
|
| + stop_immediately_cb_.Run(overlay);
|
| + base::RunLoop().RunUntilIdle();
|
| + }
|
| +
|
| + UseOverlayCB use_overlay_cb_;
|
| + UseSurfaceTextureCB use_surface_texture_cb_;
|
| + StopUsingOverlayImmediatelyCB stop_immediately_cb_;
|
| +
|
| + std::unique_ptr<AndroidOverlayFactory> factory_;
|
| +
|
| + base::WeakPtrFactory<FakeOverlayHelper> weak_factory_;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(FakeOverlayHelper);
|
| + };
|
| +
|
| + // We pick this profile since it's always supported.
|
| + AndroidVideoDecodeAcceleratorTest() : config_(H264PROFILE_BASELINE) {}
|
|
|
| -class AndroidVideoDecodeAcceleratorTest : public testing::Test {
|
| - public:
|
| ~AndroidVideoDecodeAcceleratorTest() override {}
|
|
|
| void SetUp() override {
|
| JNIEnv* env = base::android::AttachCurrentThread();
|
| RegisterJni(env);
|
|
|
| + main_task_runner_ = base::ThreadTaskRunnerHandle::Get();
|
| +
|
| gl::init::ShutdownGL();
|
| ASSERT_TRUE(gl::init::InitializeGLOneOff());
|
| surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size(16, 16));
|
| @@ -92,59 +298,426 @@ class AndroidVideoDecodeAcceleratorTest : public testing::Test {
|
| gl::GLContextAttribs());
|
| context_->MakeCurrent(surface_.get());
|
|
|
| - vda_.reset(new AndroidVideoDecodeAccelerator(
|
| - &codec_allocator_, base::Bind(&MakeContextCurrent),
|
| - base::Bind(&GetGLES2Decoder, gl_decoder_.AsWeakPtr())));
|
| + helper_that_is_usually_null_ = base::MakeUnique<FakeOverlayHelper>();
|
| + helper_ = helper_that_is_usually_null_->GetWeakPtr();
|
| +
|
| + platform_config_.sdk_int = base::android::SDK_VERSION_MARSHMALLOW;
|
| + platform_config_.allow_setsurface = true;
|
| + platform_config_.force_deferred_surface_creation = false;
|
| +
|
| + // By default, allow deferred init.
|
| + config_.is_deferred_initialization_allowed = true;
|
| + }
|
| +
|
| + // Create and initialize AVDA with |config_|, and return the result.
|
| + bool InitializeAVDA() {
|
| + // Because VDA has a custom deleter, we must assign it to |vda_| carefully.
|
| + AndroidVideoDecodeAccelerator* avda = new AndroidVideoDecodeAccelerator(
|
| + &codec_allocator_, std::move(helper_that_is_usually_null_),
|
| + base::Bind(&MakeContextCurrent),
|
| + base::Bind(&GetGLES2Decoder, gl_decoder_.AsWeakPtr()),
|
| + &platform_config_);
|
| + avda_ = avda->GetWeakPtr();
|
| + vda_.reset(avda);
|
| +
|
| + bool result = vda_->Initialize(config_, &client_);
|
| + base::RunLoop().RunUntilIdle();
|
| + return result;
|
| + }
|
| +
|
| + // Initialize |vda_|, providing a new surface for it. You may get the surface
|
| + // by asking |codec_allocator_|.
|
| + void InitializeAVDAWithOverlay() {
|
| + EXPECT_CALL(*helper_, MockStartup());
|
| +
|
| + config_.surface_id = 123;
|
| + ASSERT_TRUE(InitializeAVDA());
|
| + base::RunLoop().RunUntilIdle();
|
| + ASSERT_TRUE(helper_->factory_ != nullptr);
|
| +
|
| + // Have the factory provide an overlay, and verify that codec creation is
|
| + // provided with that overlay.
|
| + std::unique_ptr<MockAndroidOverlay> overlay =
|
| + base::MakeUnique<MockAndroidOverlay>();
|
| + // Set the expectations first, since ProvideOverlay might cause callbacks.
|
| + EXPECT_CALL(codec_allocator_,
|
| + MockCreateMediaCodecAsync(overlay.get(), nullptr));
|
| + helper_->ProvideOverlay(std::move(overlay));
|
| +
|
| + // Provide the codec so that we can check if it's freed properly.
|
| + EXPECT_CALL(client_, NotifyInitializationComplete(true));
|
| + codec_allocator_.ProvideMockCodecAsync();
|
| + base::RunLoop().RunUntilIdle();
|
| + }
|
| +
|
| + void InitializeAVDAWithSurfaceTexture() {
|
| + EXPECT_CALL(*helper_, MockStartup());
|
| +
|
| + ASSERT_TRUE(InitializeAVDA());
|
| + base::RunLoop().RunUntilIdle();
|
| + // We do not expect a factory, since we are using SurfaceTexture.
|
| + ASSERT_TRUE(helper_->factory_ == nullptr);
|
| +
|
| + // Set the expectations first, since ProvideOverlay might cause callbacks.
|
| + EXPECT_CALL(codec_allocator_,
|
| + MockCreateMediaCodecAsync(nullptr, NotNull()));
|
| + helper_->ProvideSurfaceTexture();
|
| +
|
| + // Provide the codec so that we can check if it's freed properly.
|
| + EXPECT_CALL(client_, NotifyInitializationComplete(true));
|
| + codec_allocator_.ProvideMockCodecAsync();
|
| + base::RunLoop().RunUntilIdle();
|
| + }
|
| +
|
| + // Set whether HasUnrendereredPictureBuffers will return true or false.
|
| + // TODO(liberato): We can't actually do this yet. It turns out to be okay,
|
| + // because AVDA doesn't actually SetSurface before DequeueOutput. It could do
|
| + // so, though, if there aren't unrendered buffers. Should AVDA ever start
|
| + // switching surfaces immediately upon receiving them, rather than waiting for
|
| + // DequeueOutput, then we'll want to be able to indicate that it has
|
| + // unrendered pictures to prevent that behavior.
|
| + void SetHasUnrenderedPictureBuffers(bool flag) {}
|
| +
|
| + // Tell |avda_| to switch surfaces to its incoming surface. This is a method
|
| + // since we're a friend of AVDA, and the tests are subclasses. It's also
|
| + // somewhat hacky, but much less hacky than trying to run it via a timer.
|
| + void LetAVDAUpdateSurface() {
|
| + SetHasUnrenderedPictureBuffers(false);
|
| + avda_->DequeueOutput();
|
| }
|
|
|
| base::MessageLoop message_loop_;
|
| scoped_refptr<gl::GLSurface> surface_;
|
| scoped_refptr<gl::GLContext> context_;
|
| + scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
|
| NiceMock<gpu::gles2::MockGLES2Decoder> gl_decoder_;
|
| - NiceMock<MockVDAClient> client_;
|
| - NiceMock<MockCodecAllocator> codec_allocator_;
|
| + StrictMock<MockVDAClient> client_;
|
| + FakeCodecAllocator codec_allocator_;
|
| + VideoDecodeAccelerator::Config config_;
|
| +
|
| + AndroidVideoDecodeAccelerator::PlatformConfig platform_config_;
|
| +
|
| + // We maintain a weak ref to this since AVDA owns it.
|
| + base::WeakPtr<FakeOverlayHelper> helper_;
|
|
|
| // This must be a unique pointer to a VDA, not an AVDA, to ensure the
|
| // the default_delete specialization that calls Destroy() will be used.
|
| std::unique_ptr<VideoDecodeAccelerator> vda_;
|
| +
|
| + // Weak ptr to |vda_| as an AVDA.
|
| + base::WeakPtr<AndroidVideoDecodeAccelerator> avda_;
|
| +
|
| + private:
|
| + // This is the object that |helper_| points to, or nullptr once we assign
|
| + // ownership to AVDA.
|
| + std::unique_ptr<FakeOverlayHelper> helper_that_is_usually_null_;
|
| };
|
|
|
| TEST_F(AndroidVideoDecodeAcceleratorTest, ConfigureUnsupportedCodec) {
|
| SKIP_IF_MEDIACODEC_IS_NOT_AVAILABLE();
|
|
|
| - ASSERT_FALSE(vda_->Initialize(
|
| - VideoDecodeAccelerator::Config(VIDEO_CODEC_PROFILE_UNKNOWN), &client_));
|
| + config_ = VideoDecodeAccelerator::Config(VIDEO_CODEC_PROFILE_UNKNOWN);
|
| + ASSERT_FALSE(InitializeAVDA());
|
| }
|
|
|
| -TEST_F(AndroidVideoDecodeAcceleratorTest, ConfigureSupportedCodec) {
|
| +TEST_F(AndroidVideoDecodeAcceleratorTest,
|
| + ConfigureSupportedCodecSynchronously) {
|
| SKIP_IF_MEDIACODEC_IS_NOT_AVAILABLE();
|
|
|
| - // H264 is always supported by AVDA.
|
| - ASSERT_TRUE(vda_->Initialize(
|
| - VideoDecodeAccelerator::Config(H264PROFILE_BASELINE), &client_));
|
| + config_.is_deferred_initialization_allowed = false;
|
| +
|
| + EXPECT_CALL(codec_allocator_, MockCreateMediaCodecSync(nullptr, NotNull()));
|
| + ASSERT_TRUE(InitializeAVDA());
|
| }
|
|
|
| -TEST_F(AndroidVideoDecodeAcceleratorTest, FailingToCreateACodecIsAnError) {
|
| - EXPECT_CALL(codec_allocator_, CreateMediaCodecAsync(_, _))
|
| - .WillOnce(PostNullCodec());
|
| +TEST_F(AndroidVideoDecodeAcceleratorTest, FailingToCreateACodecSyncIsAnError) {
|
| + // Failuew to create a codec during sync init should cause Initialize to fail.
|
| + SKIP_IF_MEDIACODEC_IS_NOT_AVAILABLE();
|
| +
|
| + config_.is_deferred_initialization_allowed = false;
|
| + codec_allocator_.allow_sync_creation = false;
|
| +
|
| + EXPECT_CALL(codec_allocator_, MockCreateMediaCodecSync(nullptr, NotNull()));
|
| + ASSERT_FALSE(InitializeAVDA());
|
| +}
|
| +
|
| +TEST_F(AndroidVideoDecodeAcceleratorTest, FailingToCreateACodecAsyncIsAnError) {
|
| + // Verify that a null codec signals error for async init when it doesn't get a
|
| + // mediacodec instance.
|
| + //
|
| + // Also assert that there's only one call to CreateMediaCodecAsync. And since
|
| + // it replies with a null codec, AVDA will be in an error state when it shuts
|
| + // down. Since we know that it's constructed before we destroy the VDA, we
|
| + // verify that AVDA doens't create codecs during destruction.
|
| + SKIP_IF_MEDIACODEC_IS_NOT_AVAILABLE();
|
| +
|
| + // Note that if we somehow end up deferring surface creation, then this would
|
| + // no longer be expected to fail. It would signal success before asking for a
|
| + // surface or codec.
|
| + EXPECT_CALL(*helper_, MockStartup());
|
| + EXPECT_CALL(codec_allocator_, MockCreateMediaCodecAsync(_, NotNull()));
|
| EXPECT_CALL(client_, NotifyInitializationComplete(false));
|
|
|
| - VideoDecodeAccelerator::Config config(H264PROFILE_BASELINE);
|
| - config.is_deferred_initialization_allowed = true;
|
| - vda_->Initialize(config, &client_);
|
| + ASSERT_TRUE(InitializeAVDA());
|
| + helper_->ProvideSurfaceTexture();
|
| + codec_allocator_.ProvideNullCodecAsync();
|
| +
|
| + // Make sure that codec allocation has happened before destroying the VDA.
|
| + testing::Mock::VerifyAndClearExpectations(&codec_allocator_);
|
| +
|
| + vda_ = nullptr;
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +TEST_F(AndroidVideoDecodeAcceleratorTest,
|
| + LowEndDevicesSucceedInitWithoutASurface) {
|
| + // If AVDA decides that we should defer surface creation, then it should
|
| + // signal success before we provide a surface. It should still ask for a
|
| + // surface, though.
|
| + SKIP_IF_MEDIACODEC_IS_NOT_AVAILABLE();
|
| +
|
| + // It would be nicer if we didn't just force this on, since we might do so
|
| + // in a state that AVDA isn't supposed to handle (e.g., if we give it a
|
| + // surface, then it would never decide to defer surface creation).
|
| + platform_config_.force_deferred_surface_creation = true;
|
| + config_.surface_id = SurfaceManager::kNoSurfaceID;
|
| +
|
| + EXPECT_CALL(*helper_, MockStartup()).Times(0);
|
| + EXPECT_CALL(client_, NotifyInitializationComplete(true));
|
| +
|
| + InitializeAVDA();
|
| +}
|
| +
|
| +TEST_F(AndroidVideoDecodeAcceleratorTest, WillStartHelperImmediately) {
|
| + // AVDA should initialize |helper_| immediately if it's not waiting for a Cdm.
|
| + // It should provide a null factory, since |config_| defaults to
|
| + // SurfaceTexture. We also expect that AVDA will not create a codec before it
|
| + // gets a surface, nor will it signal deferred init success to us.
|
| + SKIP_IF_MEDIACODEC_IS_NOT_AVAILABLE();
|
| +
|
| + EXPECT_CALL(*helper_, MockStartup());
|
| + EXPECT_CALL(codec_allocator_, MockCreateMediaCodecAsync(_, NotNull()))
|
| + .Times(0);
|
| + EXPECT_CALL(client_, NotifyInitializationComplete(_)).Times(0);
|
| +
|
| + InitializeAVDA();
|
| + ASSERT_TRUE(helper_->factory_ == nullptr);
|
| +}
|
| +
|
| +TEST_F(AndroidVideoDecodeAcceleratorTest,
|
| + AsyncInitWithSurfaceTextureAndDelete) {
|
| + // When configuring with a SurfaceTexture and deferred init, we should be
|
| + // asked for a codec, and be notified of init success if we provide one. When
|
| + // AVDA is destroyed, it should release the codec and surface texture.
|
| + SKIP_IF_MEDIACODEC_IS_NOT_AVAILABLE();
|
| +
|
| + InitializeAVDAWithSurfaceTexture();
|
| +
|
| + // Delete the VDA, and make sure that it tries to free the codec and the right
|
| + // surface texture.
|
| + EXPECT_CALL(
|
| + codec_allocator_,
|
| + MockReleaseMediaCodec(codec_allocator_.most_recent_codec(),
|
| + codec_allocator_.most_recent_overlay(),
|
| + codec_allocator_.most_recent_surface_texture()));
|
| + vda_ = nullptr;
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +TEST_F(AndroidVideoDecodeAcceleratorTest, AsyncInitWithSurfaceAndDelete) {
|
| + // When |config_| specifies a surface, we should be given a factory during
|
| + // startup for it. When |helper_| provides an overlay, the codec should be
|
| + // allocated using it. Shutdown should provide the overlay when releasing the
|
| + // media codec.
|
| + SKIP_IF_MEDIACODEC_IS_NOT_AVAILABLE();
|
| +
|
| + InitializeAVDAWithOverlay();
|
| +
|
| + // Delete the VDA, and make sure that it tries to free the codec and the
|
| + // overlay that it provided to us.
|
| + EXPECT_CALL(
|
| + codec_allocator_,
|
| + MockReleaseMediaCodec(codec_allocator_.most_recent_codec(),
|
| + codec_allocator_.most_recent_overlay(),
|
| + codec_allocator_.most_recent_surface_texture()));
|
| + vda_ = nullptr;
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +TEST_F(AndroidVideoDecodeAcceleratorTest,
|
| + SwitchesToSurfaceTextureWhenSurfaceDestroyed) {
|
| + // Provide a surface, and a codec, then destroy the surface. AVDA should use
|
| + // SetSurface to switch to SurfaceTexture.
|
| + SKIP_IF_MEDIACODEC_IS_NOT_AVAILABLE();
|
| +
|
| + InitializeAVDAWithOverlay();
|
| +
|
| + // It would be nice if we knew that this was a surface texture. As it is, we
|
| + // just destroy the VDA and expect that we're provided with one. Hopefully,
|
| + // AVDA is actually calling SetSurface properly.
|
| + EXPECT_CALL(*codec_allocator_.most_recent_codec(), SetSurface(_))
|
| + .WillOnce(Return(true));
|
| + helper_->StopImmediately(codec_allocator_.most_recent_overlay());
|
| +
|
| + EXPECT_CALL(codec_allocator_,
|
| + MockReleaseMediaCodec(codec_allocator_.most_recent_codec(),
|
| + nullptr, NotNull()));
|
| + vda_ = nullptr;
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +TEST_F(AndroidVideoDecodeAcceleratorTest, SwitchesToSurfaceTextureEventually) {
|
| + // Provide a surface, and a codec, then request that AVDA switches to a
|
| + // surface texture. Verify that it does.
|
| + SKIP_IF_MEDIACODEC_IS_NOT_AVAILABLE();
|
| +
|
| + InitializeAVDAWithOverlay();
|
| +
|
| + EXPECT_CALL(*codec_allocator_.most_recent_codec(), SetSurface(_))
|
| + .WillOnce(Return(true));
|
| +
|
| + // Note that it's okay if |avda_| switches before ProvideSurfaceTexture
|
| + // returns, since it has no queued output anyway.
|
| + helper_->ProvideSurfaceTexture();
|
| + LetAVDAUpdateSurface();
|
| +
|
| + // Verify that we're now using some surface texture.
|
| + EXPECT_CALL(codec_allocator_,
|
| + MockReleaseMediaCodec(codec_allocator_.most_recent_codec(),
|
| + nullptr, NotNull()));
|
| + vda_ = nullptr;
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +TEST_F(AndroidVideoDecodeAcceleratorTest,
|
| + SetSurfaceFailureDoesntSwitchSurfaces) {
|
| + // Initialize AVDA with a surface, then request that AVDA switches to a
|
| + // surface texture. When it tries to UpdateSurface, pretend to fail. AVDA
|
| + // should notify error, and also release the original surface.
|
| + SKIP_IF_MEDIACODEC_IS_NOT_AVAILABLE();
|
| +
|
| + InitializeAVDAWithOverlay();
|
| +
|
| + EXPECT_CALL(*codec_allocator_.most_recent_codec(), SetSurface(_))
|
| + .WillOnce(Return(false));
|
| + EXPECT_CALL(client_,
|
| + NotifyError(AndroidVideoDecodeAccelerator::PLATFORM_FAILURE))
|
| + .Times(1);
|
| + helper_->ProvideSurfaceTexture();
|
| +
|
| + // Verify that we're still using an overlay.
|
| + EXPECT_CALL(codec_allocator_,
|
| + MockReleaseMediaCodec(codec_allocator_.most_recent_codec(),
|
| + NotNull(), nullptr));
|
| +
|
| + // Also destroy the VDA to be sure that it cleans up the codec. It can do so
|
| + // earlier if it wants to, but isn't required to.
|
| + LetAVDAUpdateSurface();
|
| + vda_ = nullptr;
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +TEST_F(AndroidVideoDecodeAcceleratorTest,
|
| + SwitchToSurfaceAndBackBeforeSetSurface) {
|
| + // Ask AVDA to switch from ST to overlay, then back to ST before it has a
|
| + // chance to do the first switch. It should simply drop the overlay.
|
| + SKIP_IF_MEDIACODEC_IS_NOT_AVAILABLE();
|
| +
|
| + InitializeAVDAWithSurfaceTexture();
|
| +
|
| + // Don't let AVDA switch immediately, else it could choose to SetSurface when
|
| + // it first gets the overlay.
|
| + SetHasUnrenderedPictureBuffers(true);
|
| + EXPECT_CALL(*codec_allocator_.most_recent_codec(), SetSurface(_)).Times(0);
|
| + std::unique_ptr<MockAndroidOverlay> overlay =
|
| + base::MakeUnique<MockAndroidOverlay>();
|
| + // Make sure that the overlay is not destroyed too soon.
|
| + std::unique_ptr<MockAndroidOverlay::DestructionObserver> observer =
|
| + overlay->CreateDestructionObserver();
|
| +
|
| + helper_->ProvideOverlay(std::move(overlay));
|
| +
|
| + // Now it is okay to drop the overlay.
|
| + EXPECT_CALL(*observer, OnOverlayDestroyed());
|
| +
|
| + // While the incoming surface is pending, switch back to SurfaceTexture.
|
| + helper_->ProvideSurfaceTexture();
|
| +
|
| + // Cleanup should free the the original SurfaceTexture. It would probably be
|
| + // fine to free a new one, but that seems like a waste of resources. So, we
|
| + // enforce that it should elide the switch entirely.
|
| + EXPECT_CALL(
|
| + codec_allocator_,
|
| + MockReleaseMediaCodec(codec_allocator_.most_recent_codec(), nullptr,
|
| + codec_allocator_.most_recent_surface_texture()));
|
| + LetAVDAUpdateSurface();
|
| + vda_ = nullptr;
|
| base::RunLoop().RunUntilIdle();
|
| }
|
|
|
| -TEST_F(AndroidVideoDecodeAcceleratorTest, NoCodecsAreCreatedDuringDestruction) {
|
| - // Assert that there's only one call to CreateMediaCodecAsync. And since it
|
| - // replies with a null codec, AVDA will be in an error state when it shuts
|
| - // down.
|
| - EXPECT_CALL(codec_allocator_, CreateMediaCodecAsync(_, _))
|
| - .WillOnce(PostNullCodec());
|
| +TEST_F(AndroidVideoDecodeAcceleratorTest,
|
| + ChangingOutputSurfaceVoluntarilyWithoutSetSurfaceIsIgnored) {
|
| + // If we ask AVDA to change to SurfaceTexture should be ignored on platforms
|
| + // that don't support SetSurface (pre-M or blacklisted). It should also
|
| + // ignore SurfaceTexture => overlay, but we don't check that.
|
| + //
|
| + // Also note that there are other probably reasonable things to do (like
|
| + // signal an error), but we want to be sure that it doesn't try to SetSurface.
|
| + // We also want to be sure that, if it doesn't signal an error, that it also
|
| + // doesn't get confused about which surface is in use. So, we assume that it
|
| + // doesn't signal an error, and we check that it releases the right surface
|
| + // with the codec.
|
| + EXPECT_CALL(client_, NotifyError(_)).Times(0);
|
| +
|
| + platform_config_.allow_setsurface = false;
|
| + InitializeAVDAWithOverlay();
|
| + EXPECT_CALL(*codec_allocator_.most_recent_codec(), SetSurface(_)).Times(0);
|
| +
|
| + // This should not switch to SurfaceTexture.
|
| + helper_->ProvideSurfaceTexture();
|
| + LetAVDAUpdateSurface();
|
| +
|
| + // It should free an overlay with the codec.
|
| + EXPECT_CALL(
|
| + codec_allocator_,
|
| + MockReleaseMediaCodec(codec_allocator_.most_recent_codec(),
|
| + codec_allocator_.most_recent_overlay(), nullptr));
|
| + vda_ = nullptr;
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +TEST_F(AndroidVideoDecodeAcceleratorTest,
|
| + OnSurfaceDestroyedWithoutSetSurfaceFreesTheCodec) {
|
| + // If AVDA receives OnSurfaceDestroyed without support for SetSurface, then it
|
| + // should free the codec.
|
| + platform_config_.allow_setsurface = false;
|
| + InitializeAVDAWithOverlay();
|
| + EXPECT_CALL(*codec_allocator_.most_recent_codec(), SetSurface(_)).Times(0);
|
| +
|
| + // This should free the codec.
|
| + EXPECT_CALL(
|
| + codec_allocator_,
|
| + MockReleaseMediaCodec(codec_allocator_.most_recent_codec(),
|
| + codec_allocator_.most_recent_overlay(), nullptr));
|
| + helper_->StopImmediately(codec_allocator_.most_recent_overlay());
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + // Verify that the codec has been released, since |vda_| will be destroyed
|
| + // soon. The expectations must be met before that.
|
| + testing::Mock::VerifyAndClearExpectations(&codec_allocator_);
|
| +}
|
| +
|
| +TEST_F(AndroidVideoDecodeAcceleratorTest,
|
| + MultipleSurfaceTextureCallbacksAreIgnored) {
|
| + // Ask AVDA to switch to ST when it's already using ST, nothing should happen.
|
| + SKIP_IF_MEDIACODEC_IS_NOT_AVAILABLE();
|
| +
|
| + InitializeAVDAWithSurfaceTexture();
|
| +
|
| + // This should do nothing.
|
| + EXPECT_CALL(*codec_allocator_.most_recent_codec(), SetSurface(_)).Times(0);
|
| + helper_->ProvideSurfaceTexture();
|
|
|
| - VideoDecodeAccelerator::Config config(H264PROFILE_BASELINE);
|
| - config.is_deferred_initialization_allowed = true;
|
| - vda_->Initialize(config, &client_);
|
| base::RunLoop().RunUntilIdle();
|
| }
|
|
|
|
|