Commit 31e2e42a authored by Dan Sanders's avatar Dan Sanders Committed by Commit Bot

[media] Support parent thread decode in VdaVideoDecoder.

Bug: 522298
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I48b205e7b20cf512e953d5992be6ed507add688b
Reviewed-on: https://chromium-review.googlesource.com/1217716Reviewed-by: default avatarFrank Liberato <liberato@chromium.org>
Commit-Queue: Dan Sanders <sandersd@chromium.org>
Cr-Commit-Position: refs/heads/master@{#590479}
parent 2d79a618
...@@ -318,11 +318,13 @@ void VdaVideoDecoder::InitializeOnGpuThread() { ...@@ -318,11 +318,13 @@ void VdaVideoDecoder::InitializeOnGpuThread() {
return; return;
} }
// TODO(sandersd): TryToSetupDecodeOnSeparateThread().
gpu_weak_vda_factory_.reset( gpu_weak_vda_factory_.reset(
new base::WeakPtrFactory<VideoDecodeAccelerator>(vda_.get())); new base::WeakPtrFactory<VideoDecodeAccelerator>(vda_.get()));
gpu_weak_vda_ = gpu_weak_vda_factory_->GetWeakPtr(); gpu_weak_vda_ = gpu_weak_vda_factory_->GetWeakPtr();
vda_initialized_ = true; vda_initialized_ = true;
decode_on_parent_thread_ = vda_->TryToSetupDecodeOnSeparateThread(
parent_weak_this_, parent_task_runner_);
parent_task_runner_->PostTask(FROM_HERE, parent_task_runner_->PostTask(FROM_HERE,
base::BindOnce(&VdaVideoDecoder::InitializeDone, base::BindOnce(&VdaVideoDecoder::InitializeDone,
...@@ -374,6 +376,11 @@ void VdaVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer, ...@@ -374,6 +376,11 @@ void VdaVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
timestamps_.Put(bitstream_buffer_id, buffer->timestamp()); timestamps_.Put(bitstream_buffer_id, buffer->timestamp());
decode_cbs_[bitstream_buffer_id] = decode_cb; decode_cbs_[bitstream_buffer_id] = decode_cb;
if (decode_on_parent_thread_) {
vda_->Decode(std::move(buffer), bitstream_buffer_id);
return;
}
gpu_task_runner_->PostTask( gpu_task_runner_->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce(&VdaVideoDecoder::DecodeOnGpuThread, gpu_weak_this_, base::BindOnce(&VdaVideoDecoder::DecodeOnGpuThread, gpu_weak_this_,
......
...@@ -187,16 +187,17 @@ class VdaVideoDecoder : public VideoDecoder, ...@@ -187,16 +187,17 @@ class VdaVideoDecoder : public VideoDecoder,
// large enough to account for any amount of frame reordering. // large enough to account for any amount of frame reordering.
base::MRUCache<int32_t, base::TimeDelta> timestamps_; base::MRUCache<int32_t, base::TimeDelta> timestamps_;
//
// GPU thread state.
//
std::unique_ptr<VideoDecodeAccelerator> vda_;
bool vda_initialized_ = false;
// //
// Shared state. // Shared state.
// //
// Only read on GPU thread during initialization, which is mutually exclusive
// with writes on the parent thread.
VideoDecoderConfig config_; VideoDecoderConfig config_;
// Only written on the GPU thread during initialization, which is mutually
// exclusive with reads on the parent thread.
std::unique_ptr<VideoDecodeAccelerator> vda_;
bool vda_initialized_ = false;
bool decode_on_parent_thread_ = false;
// //
// Weak pointers, prefixed by bound thread. // Weak pointers, prefixed by bound thread.
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "base/test/mock_callback.h" #include "base/test/mock_callback.h"
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
#include "base/threading/thread.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "gpu/command_buffer/common/sync_token.h" #include "gpu/command_buffer/common/sync_token.h"
#include "media/base/decode_status.h" #include "media/base/decode_status.h"
...@@ -92,13 +93,16 @@ VideoDecodeAccelerator::Capabilities GetCapabilities() { ...@@ -92,13 +93,16 @@ VideoDecodeAccelerator::Capabilities GetCapabilities() {
} // namespace } // namespace
class VdaVideoDecoderTest : public testing::Test { // Parameterized by |decode_on_parent_thread|.
class VdaVideoDecoderTest : public testing::TestWithParam<bool> {
public: public:
explicit VdaVideoDecoderTest() { explicit VdaVideoDecoderTest() : gpu_thread_("GPU Thread") {
// TODO(sandersd): Use a separate thread for the GPU task runner. gpu_thread_.Start();
scoped_refptr<base::SingleThreadTaskRunner> task_runner = scoped_refptr<base::SingleThreadTaskRunner> parent_task_runner =
environment_.GetMainThreadTaskRunner(); environment_.GetMainThreadTaskRunner();
cbh_ = base::MakeRefCounted<FakeCommandBufferHelper>(task_runner); scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner =
gpu_thread_.task_runner();
cbh_ = base::MakeRefCounted<FakeCommandBufferHelper>(gpu_task_runner);
// |owned_vda_| exists to delete |vda_| when |this| is destructed. Ownership // |owned_vda_| exists to delete |vda_| when |this| is destructed. Ownership
// is passed to |vdavd_| by CreateVda(), but |vda_| remains to be used for // is passed to |vdavd_| by CreateVda(), but |vda_| remains to be used for
...@@ -110,7 +114,8 @@ class VdaVideoDecoderTest : public testing::Test { ...@@ -110,7 +114,8 @@ class VdaVideoDecoderTest : public testing::Test {
EXPECT_CALL(*vda_, Destroy()); EXPECT_CALL(*vda_, Destroy());
vdavd_.reset(new VdaVideoDecoder( vdavd_.reset(new VdaVideoDecoder(
task_runner, task_runner, media_log_.Clone(), gfx::ColorSpace(), parent_task_runner, gpu_task_runner, media_log_.Clone(),
gfx::ColorSpace(),
base::BindOnce(&VdaVideoDecoderTest::CreatePictureBufferManager, base::BindOnce(&VdaVideoDecoderTest::CreatePictureBufferManager,
base::Unretained(this)), base::Unretained(this)),
base::BindOnce(&VdaVideoDecoderTest::CreateCommandBufferHelper, base::BindOnce(&VdaVideoDecoderTest::CreateCommandBufferHelper,
...@@ -124,73 +129,140 @@ class VdaVideoDecoderTest : public testing::Test { ...@@ -124,73 +129,140 @@ class VdaVideoDecoderTest : public testing::Test {
~VdaVideoDecoderTest() override { ~VdaVideoDecoderTest() override {
// Drop ownership of anything that may have an async destruction process, // Drop ownership of anything that may have an async destruction process,
// then allow destruction to complete. // then allow destruction to complete.
cbh_->StubLost(); gpu_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&FakeCommandBufferHelper::StubLost, cbh_));
cbh_ = nullptr; cbh_ = nullptr;
owned_vda_ = nullptr; owned_vda_ = nullptr;
pbm_ = nullptr; pbm_ = nullptr;
vdavd_ = nullptr; vdavd_ = nullptr;
environment_.RunUntilIdle(); RunUntilIdle();
} }
protected: protected:
void RunUntilIdle() {
// FlushForTesting() only runs tasks that have already been posted.
// TODO(sandersd): Find a more reliable way to run all tasks.
gpu_thread_.FlushForTesting();
gpu_thread_.FlushForTesting();
environment_.RunUntilIdle();
}
void InitializeWithConfig(const VideoDecoderConfig& config) { void InitializeWithConfig(const VideoDecoderConfig& config) {
vdavd_->Initialize(config, false, nullptr, init_cb_.Get(), output_cb_.Get(), vdavd_->Initialize(config, false, nullptr, init_cb_.Get(), output_cb_.Get(),
waiting_cb_.Get()); waiting_cb_.Get());
} }
void Initialize() { void Initialize() {
EXPECT_CALL(*vda_, Initialize(_, vdavd_.get())).WillOnce(Return(true));
EXPECT_CALL(*vda_, TryToSetupDecodeOnSeparateThread(_, _))
.WillOnce(Return(GetParam()));
EXPECT_CALL(init_cb_, Run(true));
InitializeWithConfig(VideoDecoderConfig( InitializeWithConfig(VideoDecoderConfig(
kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420, kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420,
COLOR_SPACE_HD_REC709, VIDEO_ROTATION_0, gfx::Size(1920, 1088), COLOR_SPACE_HD_REC709, VIDEO_ROTATION_0, gfx::Size(1920, 1088),
gfx::Rect(1920, 1080), gfx::Size(1920, 1080), EmptyExtraData(), gfx::Rect(1920, 1080), gfx::Size(1920, 1080), EmptyExtraData(),
Unencrypted())); Unencrypted()));
RunUntilIdle();
EXPECT_CALL(*vda_, Initialize(_, vdavd_.get())).WillOnce(Return(true));
EXPECT_CALL(init_cb_, Run(true));
environment_.RunUntilIdle();
} }
int32_t ProvidePictureBuffer() { int32_t ProvidePictureBuffer() {
std::vector<PictureBuffer> picture_buffers; std::vector<PictureBuffer> picture_buffers;
client_->ProvidePictureBuffers(1, PIXEL_FORMAT_XRGB, 1,
gfx::Size(1920, 1088), GL_TEXTURE_2D);
EXPECT_CALL(*vda_, AssignPictureBuffers(_)) EXPECT_CALL(*vda_, AssignPictureBuffers(_))
.WillOnce(SaveArg<0>(&picture_buffers)); .WillOnce(SaveArg<0>(&picture_buffers));
environment_.RunUntilIdle(); gpu_thread_.task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&VideoDecodeAccelerator::Client::ProvidePictureBuffers,
base::Unretained(client_), 1, PIXEL_FORMAT_XRGB, 1,
gfx::Size(1920, 1088), GL_TEXTURE_2D));
RunUntilIdle();
DCHECK_EQ(picture_buffers.size(), 1U); DCHECK_EQ(picture_buffers.size(), 1U);
return picture_buffers[0].id(); return picture_buffers[0].id();
} }
int32_t Decode(base::TimeDelta timestamp) { int32_t Decode(base::TimeDelta timestamp) {
int32_t bitstream_id = 0; int32_t bitstream_id = 0;
vdavd_->Decode(CreateDecoderBuffer(timestamp), decode_cb_.Get());
EXPECT_CALL(*vda_, Decode(_, _)).WillOnce(SaveArg<1>(&bitstream_id)); EXPECT_CALL(*vda_, Decode(_, _)).WillOnce(SaveArg<1>(&bitstream_id));
environment_.RunUntilIdle(); vdavd_->Decode(CreateDecoderBuffer(timestamp), decode_cb_.Get());
RunUntilIdle();
return bitstream_id; return bitstream_id;
} }
void NotifyEndOfBitstreamBuffer(int32_t bitstream_id) { void NotifyEndOfBitstreamBuffer(int32_t bitstream_id) {
// Expectation must go before the call because NotifyEndOfBitstreamBuffer()
// implements the same-thread optimization.
EXPECT_CALL(decode_cb_, Run(DecodeStatus::OK)); EXPECT_CALL(decode_cb_, Run(DecodeStatus::OK));
client_->NotifyEndOfBitstreamBuffer(bitstream_id); if (GetParam()) {
environment_.RunUntilIdle(); // TODO(sandersd): The VDA could notify on either thread. Test both.
client_->NotifyEndOfBitstreamBuffer(bitstream_id);
} else {
gpu_thread_.task_runner()->PostTask(
FROM_HERE,
base::BindOnce(
&VideoDecodeAccelerator::Client::NotifyEndOfBitstreamBuffer,
base::Unretained(client_), bitstream_id));
}
RunUntilIdle();
} }
scoped_refptr<VideoFrame> PictureReady(int32_t bitstream_buffer_id, scoped_refptr<VideoFrame> PictureReady(
int32_t picture_buffer_id) { int32_t bitstream_buffer_id,
// Expectation must go before the call because PictureReady() implements the int32_t picture_buffer_id,
// same-thread optimization. gfx::Rect visible_rect = gfx::Rect(1920, 1080)) {
scoped_refptr<VideoFrame> frame; scoped_refptr<VideoFrame> frame;
Picture picture(picture_buffer_id, bitstream_buffer_id, visible_rect,
gfx::ColorSpace::CreateSRGB(), true);
EXPECT_CALL(output_cb_, Run(_)).WillOnce(SaveArg<0>(&frame)); EXPECT_CALL(output_cb_, Run(_)).WillOnce(SaveArg<0>(&frame));
client_->PictureReady(Picture(picture_buffer_id, bitstream_buffer_id, if (GetParam()) {
gfx::Rect(1920, 1080), // TODO(sandersd): The first time a picture is output, VDAs will do so on
gfx::ColorSpace::CreateSRGB(), true)); // the GPU thread (because GpuVideoDecodeAccelerator required that). Test
environment_.RunUntilIdle(); // both.
client_->PictureReady(picture);
} else {
gpu_thread_.task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&VideoDecodeAccelerator::Client::PictureReady,
base::Unretained(client_), picture));
}
RunUntilIdle();
return frame; return frame;
} }
void DismissPictureBuffer(int32_t picture_buffer_id) {
gpu_thread_.task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&VideoDecodeAccelerator::Client::DismissPictureBuffer,
base::Unretained(client_), picture_buffer_id));
RunUntilIdle();
}
void NotifyFlushDone() {
gpu_thread_.task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&VideoDecodeAccelerator::Client::NotifyFlushDone,
base::Unretained(client_)));
RunUntilIdle();
}
void NotifyResetDone() {
gpu_thread_.task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&VideoDecodeAccelerator::Client::NotifyResetDone,
base::Unretained(client_)));
RunUntilIdle();
}
void NotifyError(VideoDecodeAccelerator::Error error) {
gpu_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&VideoDecodeAccelerator::Client::NotifyError,
base::Unretained(client_), error));
RunUntilIdle();
}
void ReleaseSyncToken(gpu::SyncToken sync_token) {
gpu_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&FakeCommandBufferHelper::ReleaseSyncToken,
cbh_, sync_token));
RunUntilIdle();
}
// TODO(sandersd): This exact code is also used in // TODO(sandersd): This exact code is also used in
// PictureBufferManagerImplTest. Share the implementation. // PictureBufferManagerImplTest. Share the implementation.
gpu::SyncToken GenerateSyncToken(scoped_refptr<VideoFrame> video_frame) { gpu::SyncToken GenerateSyncToken(scoped_refptr<VideoFrame> video_frame) {
...@@ -225,6 +297,7 @@ class VdaVideoDecoderTest : public testing::Test { ...@@ -225,6 +297,7 @@ class VdaVideoDecoderTest : public testing::Test {
} }
base::test::ScopedTaskEnvironment environment_; base::test::ScopedTaskEnvironment environment_;
base::Thread gpu_thread_;
testing::NiceMock<MockMediaLog> media_log_; testing::NiceMock<MockMediaLog> media_log_;
testing::StrictMock<base::MockCallback<VideoDecoder::InitCB>> init_cb_; testing::StrictMock<base::MockCallback<VideoDecoder::InitCB>> init_cb_;
...@@ -247,79 +320,75 @@ class VdaVideoDecoderTest : public testing::Test { ...@@ -247,79 +320,75 @@ class VdaVideoDecoderTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(VdaVideoDecoderTest); DISALLOW_COPY_AND_ASSIGN(VdaVideoDecoderTest);
}; };
TEST_F(VdaVideoDecoderTest, CreateAndDestroy) {} TEST_P(VdaVideoDecoderTest, CreateAndDestroy) {}
TEST_F(VdaVideoDecoderTest, Initialize) { TEST_P(VdaVideoDecoderTest, Initialize) {
Initialize(); Initialize();
} }
TEST_F(VdaVideoDecoderTest, Initialize_UnsupportedSize) { TEST_P(VdaVideoDecoderTest, Initialize_UnsupportedSize) {
InitializeWithConfig(VideoDecoderConfig( InitializeWithConfig(VideoDecoderConfig(
kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420, COLOR_SPACE_SD_REC601, kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420, COLOR_SPACE_SD_REC601,
VIDEO_ROTATION_0, gfx::Size(320, 240), gfx::Rect(320, 240), VIDEO_ROTATION_0, gfx::Size(320, 240), gfx::Rect(320, 240),
gfx::Size(320, 240), EmptyExtraData(), Unencrypted())); gfx::Size(320, 240), EmptyExtraData(), Unencrypted()));
EXPECT_CALL(init_cb_, Run(false)); EXPECT_CALL(init_cb_, Run(false));
environment_.RunUntilIdle(); RunUntilIdle();
} }
TEST_F(VdaVideoDecoderTest, Initialize_UnsupportedCodec) { TEST_P(VdaVideoDecoderTest, Initialize_UnsupportedCodec) {
InitializeWithConfig(VideoDecoderConfig( InitializeWithConfig(VideoDecoderConfig(
kCodecH264, H264PROFILE_BASELINE, PIXEL_FORMAT_I420, kCodecH264, H264PROFILE_BASELINE, PIXEL_FORMAT_I420,
COLOR_SPACE_HD_REC709, VIDEO_ROTATION_0, gfx::Size(1920, 1088), COLOR_SPACE_HD_REC709, VIDEO_ROTATION_0, gfx::Size(1920, 1088),
gfx::Rect(1920, 1080), gfx::Size(1920, 1080), EmptyExtraData(), gfx::Rect(1920, 1080), gfx::Size(1920, 1080), EmptyExtraData(),
Unencrypted())); Unencrypted()));
EXPECT_CALL(init_cb_, Run(false)); EXPECT_CALL(init_cb_, Run(false));
environment_.RunUntilIdle(); RunUntilIdle();
} }
TEST_F(VdaVideoDecoderTest, Initialize_RejectedByVda) { TEST_P(VdaVideoDecoderTest, Initialize_RejectedByVda) {
EXPECT_CALL(*vda_, Initialize(_, vdavd_.get())).WillOnce(Return(false));
InitializeWithConfig(VideoDecoderConfig( InitializeWithConfig(VideoDecoderConfig(
kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420, COLOR_SPACE_HD_REC709, kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420, COLOR_SPACE_HD_REC709,
VIDEO_ROTATION_0, gfx::Size(1920, 1088), gfx::Rect(1920, 1080), VIDEO_ROTATION_0, gfx::Size(1920, 1088), gfx::Rect(1920, 1080),
gfx::Size(1920, 1080), EmptyExtraData(), Unencrypted())); gfx::Size(1920, 1080), EmptyExtraData(), Unencrypted()));
EXPECT_CALL(*vda_, Initialize(_, vdavd_.get())).WillOnce(Return(false));
EXPECT_CALL(init_cb_, Run(false)); EXPECT_CALL(init_cb_, Run(false));
environment_.RunUntilIdle(); RunUntilIdle();
} }
TEST_F(VdaVideoDecoderTest, ProvideAndDismissPictureBuffer) { TEST_P(VdaVideoDecoderTest, ProvideAndDismissPictureBuffer) {
Initialize(); Initialize();
int32_t id = ProvidePictureBuffer(); int32_t id = ProvidePictureBuffer();
client_->DismissPictureBuffer(id); DismissPictureBuffer(id);
environment_.RunUntilIdle();
} }
TEST_F(VdaVideoDecoderTest, Decode) { TEST_P(VdaVideoDecoderTest, Decode) {
Initialize(); Initialize();
int32_t bitstream_id = Decode(base::TimeDelta()); int32_t bitstream_id = Decode(base::TimeDelta());
NotifyEndOfBitstreamBuffer(bitstream_id); NotifyEndOfBitstreamBuffer(bitstream_id);
} }
TEST_F(VdaVideoDecoderTest, Decode_Reset) { TEST_P(VdaVideoDecoderTest, Decode_Reset) {
Initialize(); Initialize();
Decode(base::TimeDelta()); Decode(base::TimeDelta());
vdavd_->Reset(reset_cb_.Get());
EXPECT_CALL(*vda_, Reset()); EXPECT_CALL(*vda_, Reset());
environment_.RunUntilIdle(); vdavd_->Reset(reset_cb_.Get());
RunUntilIdle();
client_->NotifyResetDone();
EXPECT_CALL(decode_cb_, Run(DecodeStatus::ABORTED)); EXPECT_CALL(decode_cb_, Run(DecodeStatus::ABORTED));
EXPECT_CALL(reset_cb_, Run()); EXPECT_CALL(reset_cb_, Run());
environment_.RunUntilIdle(); NotifyResetDone();
} }
TEST_F(VdaVideoDecoderTest, Decode_NotifyError) { TEST_P(VdaVideoDecoderTest, Decode_NotifyError) {
Initialize(); Initialize();
Decode(base::TimeDelta()); Decode(base::TimeDelta());
client_->NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE);
EXPECT_CALL(decode_cb_, Run(DecodeStatus::DECODE_ERROR)); EXPECT_CALL(decode_cb_, Run(DecodeStatus::DECODE_ERROR));
environment_.RunUntilIdle(); NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE);
} }
TEST_F(VdaVideoDecoderTest, Decode_OutputAndReuse) { TEST_P(VdaVideoDecoderTest, Decode_OutputAndReuse) {
Initialize(); Initialize();
int32_t bitstream_id = Decode(base::TimeDelta()); int32_t bitstream_id = Decode(base::TimeDelta());
NotifyEndOfBitstreamBuffer(bitstream_id); NotifyEndOfBitstreamBuffer(bitstream_id);
...@@ -330,44 +399,42 @@ TEST_F(VdaVideoDecoderTest, Decode_OutputAndReuse) { ...@@ -330,44 +399,42 @@ TEST_F(VdaVideoDecoderTest, Decode_OutputAndReuse) {
// Dropping the frame triggers reuse, which will wait on the SyncPoint. // Dropping the frame triggers reuse, which will wait on the SyncPoint.
gpu::SyncToken sync_token = GenerateSyncToken(frame); gpu::SyncToken sync_token = GenerateSyncToken(frame);
frame = nullptr; frame = nullptr;
environment_.RunUntilIdle(); RunUntilIdle();
// But the VDA won't be notified until the SyncPoint wait completes. // But the VDA won't be notified until the SyncPoint wait completes.
EXPECT_CALL(*vda_, ReusePictureBuffer(picture_buffer_id)); EXPECT_CALL(*vda_, ReusePictureBuffer(picture_buffer_id));
cbh_->ReleaseSyncToken(sync_token); ReleaseSyncToken(sync_token);
environment_.RunUntilIdle();
} }
TEST_F(VdaVideoDecoderTest, Decode_OutputAndDismiss) { TEST_P(VdaVideoDecoderTest, Decode_OutputAndDismiss) {
Initialize(); Initialize();
int32_t bitstream_id = Decode(base::TimeDelta()); int32_t bitstream_id = Decode(base::TimeDelta());
NotifyEndOfBitstreamBuffer(bitstream_id); NotifyEndOfBitstreamBuffer(bitstream_id);
int32_t picture_buffer_id = ProvidePictureBuffer(); int32_t picture_buffer_id = ProvidePictureBuffer();
scoped_refptr<VideoFrame> frame = scoped_refptr<VideoFrame> frame =
PictureReady(bitstream_id, picture_buffer_id); PictureReady(bitstream_id, picture_buffer_id);
DismissPictureBuffer(picture_buffer_id);
client_->DismissPictureBuffer(picture_buffer_id);
environment_.RunUntilIdle();
// Dropping the frame still requires a SyncPoint to wait on. // Dropping the frame still requires a SyncPoint to wait on.
gpu::SyncToken sync_token = GenerateSyncToken(frame); gpu::SyncToken sync_token = GenerateSyncToken(frame);
frame = nullptr; frame = nullptr;
environment_.RunUntilIdle(); RunUntilIdle();
// But the VDA should not be notified when it completes. // But the VDA should not be notified when it completes.
cbh_->ReleaseSyncToken(sync_token); ReleaseSyncToken(sync_token);
environment_.RunUntilIdle();
} }
TEST_F(VdaVideoDecoderTest, Decode_Output_MaintainsAspect) { TEST_P(VdaVideoDecoderTest, Decode_Output_MaintainsAspect) {
// Initialize with a config that has a 2:1 pixel aspect ratio. // Initialize with a config that has a 2:1 pixel aspect ratio.
EXPECT_CALL(*vda_, Initialize(_, vdavd_.get())).WillOnce(Return(true));
EXPECT_CALL(*vda_, TryToSetupDecodeOnSeparateThread(_, _))
.WillOnce(Return(GetParam()));
InitializeWithConfig(VideoDecoderConfig( InitializeWithConfig(VideoDecoderConfig(
kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420, COLOR_SPACE_HD_REC709, kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420, COLOR_SPACE_HD_REC709,
VIDEO_ROTATION_0, gfx::Size(640, 480), gfx::Rect(640, 480), VIDEO_ROTATION_0, gfx::Size(640, 480), gfx::Rect(640, 480),
gfx::Size(1280, 480), EmptyExtraData(), Unencrypted())); gfx::Size(1280, 480), EmptyExtraData(), Unencrypted()));
EXPECT_CALL(*vda_, Initialize(_, vdavd_.get())).WillOnce(Return(true));
EXPECT_CALL(init_cb_, Run(true)); EXPECT_CALL(init_cb_, Run(true));
environment_.RunUntilIdle(); RunUntilIdle();
// Assign a picture buffer that has size 1920x1088. // Assign a picture buffer that has size 1920x1088.
int32_t picture_buffer_id = ProvidePictureBuffer(); int32_t picture_buffer_id = ProvidePictureBuffer();
...@@ -376,12 +443,8 @@ TEST_F(VdaVideoDecoderTest, Decode_Output_MaintainsAspect) { ...@@ -376,12 +443,8 @@ TEST_F(VdaVideoDecoderTest, Decode_Output_MaintainsAspect) {
int32_t bitstream_id = Decode(base::TimeDelta()); int32_t bitstream_id = Decode(base::TimeDelta());
NotifyEndOfBitstreamBuffer(bitstream_id); NotifyEndOfBitstreamBuffer(bitstream_id);
scoped_refptr<VideoFrame> frame; scoped_refptr<VideoFrame> frame =
EXPECT_CALL(output_cb_, Run(_)).WillOnce(SaveArg<0>(&frame)); PictureReady(bitstream_id, picture_buffer_id, gfx::Rect(320, 240));
client_->PictureReady(Picture(picture_buffer_id, bitstream_id,
gfx::Rect(320, 240),
gfx::ColorSpace::CreateSRGB(), true));
environment_.RunUntilIdle();
// The frame should have |natural_size| 640x240 (pixel aspect ratio // The frame should have |natural_size| 640x240 (pixel aspect ratio
// preserved). // preserved).
...@@ -391,15 +454,18 @@ TEST_F(VdaVideoDecoderTest, Decode_Output_MaintainsAspect) { ...@@ -391,15 +454,18 @@ TEST_F(VdaVideoDecoderTest, Decode_Output_MaintainsAspect) {
EXPECT_EQ(frame->visible_rect(), gfx::Rect(320, 240)); EXPECT_EQ(frame->visible_rect(), gfx::Rect(320, 240));
} }
TEST_F(VdaVideoDecoderTest, Flush) { TEST_P(VdaVideoDecoderTest, Flush) {
Initialize(); Initialize();
vdavd_->Decode(DecoderBuffer::CreateEOSBuffer(), decode_cb_.Get());
EXPECT_CALL(*vda_, Flush()); EXPECT_CALL(*vda_, Flush());
environment_.RunUntilIdle(); vdavd_->Decode(DecoderBuffer::CreateEOSBuffer(), decode_cb_.Get());
RunUntilIdle();
client_->NotifyFlushDone();
EXPECT_CALL(decode_cb_, Run(DecodeStatus::OK)); EXPECT_CALL(decode_cb_, Run(DecodeStatus::OK));
environment_.RunUntilIdle(); NotifyFlushDone();
} }
INSTANTIATE_TEST_CASE_P(VdaVideoDecoder,
VdaVideoDecoderTest,
::testing::Values(false, true));
} // namespace media } // namespace media
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment