Commit 7e7f86b3 authored by Vasiliy Telezhnikov's avatar Vasiliy Telezhnikov Committed by Commit Bot

Fix ordering of GetFrameInfo requests

This CL adds requests queue to FrameInfoHelperImpl to make sure all
requests are ordered to keep VideoFrameFactoryImpl pipeline ordered.

Before this change VFFI would cache FrameInfo to avoid thread hops to
GPU thread and it was possible that some CreateVideoFrame requests will
be completed out-of-order.

After this change VFFI doesn't cache FrameInfo and always call
FrameInfoHelper. FrameInfoHelper does all necessary caching to avoid
unnecessary hops to GPU thread and guarantees that callbacks with
FrameInfo will come in order.

Change-Id: Iacb63cf3746991c911f1f0d5e3667db3dbd56c68
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2304092
Commit-Queue: Vasiliy Telezhnikov <vasilyt@chromium.org>
Reviewed-by: default avatarFrank Liberato <liberato@chromium.org>
Cr-Commit-Position: refs/heads/master@{#790127}
parent ee99ff7f
This diff is collapsed.
...@@ -6,12 +6,11 @@ ...@@ -6,12 +6,11 @@
#define MEDIA_GPU_ANDROID_FRAME_INFO_HELPER_H_ #define MEDIA_GPU_ANDROID_FRAME_INFO_HELPER_H_
#include "base/optional.h" #include "base/optional.h"
#include "base/threading/sequence_bound.h"
#include "media/gpu/android/codec_image.h"
#include "media/gpu/android/shared_image_video_provider.h" #include "media/gpu/android/shared_image_video_provider.h"
#include "media/gpu/media_gpu_export.h" #include "media/gpu/media_gpu_export.h"
namespace media { namespace media {
class CodecOutputBufferRenderer;
// Helper class to fetch YCbCrInfo for Vulkan from a CodecImage. // Helper class to fetch YCbCrInfo for Vulkan from a CodecImage.
class MEDIA_GPU_EXPORT FrameInfoHelper { class MEDIA_GPU_EXPORT FrameInfoHelper {
...@@ -29,12 +28,14 @@ class MEDIA_GPU_EXPORT FrameInfoHelper { ...@@ -29,12 +28,14 @@ class MEDIA_GPU_EXPORT FrameInfoHelper {
base::Optional<gpu::VulkanYCbCrInfo> ycbcr_info; base::Optional<gpu::VulkanYCbCrInfo> ycbcr_info;
}; };
static base::SequenceBound<FrameInfoHelper> Create( using FrameInfoReadyCB =
base::OnceCallback<void(std::unique_ptr<CodecOutputBufferRenderer>,
FrameInfo)>;
static std::unique_ptr<FrameInfoHelper> Create(
scoped_refptr<base::SequencedTaskRunner> gpu_task_runner, scoped_refptr<base::SequencedTaskRunner> gpu_task_runner,
SharedImageVideoProvider::GetStubCB get_stub_cb); SharedImageVideoProvider::GetStubCB get_stub_cb);
static std::unique_ptr<FrameInfoHelper> CreateForTesting();
virtual ~FrameInfoHelper() = default; virtual ~FrameInfoHelper() = default;
// Call |cb| with the FrameInfo. Will render |buffer_renderer| to the front // Call |cb| with the FrameInfo. Will render |buffer_renderer| to the front
...@@ -42,9 +43,11 @@ class MEDIA_GPU_EXPORT FrameInfoHelper { ...@@ -42,9 +43,11 @@ class MEDIA_GPU_EXPORT FrameInfoHelper {
// attempt to get YCbCrInfo and cache it. If all necessary info is cached the // attempt to get YCbCrInfo and cache it. If all necessary info is cached the
// call will leave buffer_renderer intact and it can be rendered later. // call will leave buffer_renderer intact and it can be rendered later.
// Rendering can fail for reasons. This function will make best efforts to // Rendering can fail for reasons. This function will make best efforts to
// fill FrameInfo which can be used to create VideoFrame, but shouldn't be // fill FrameInfo which can be used to create VideoFrame.
// cached by caller. Last parameter in |cb| is bool that indicates that info //
// is reliable. // Callbacks will be executed and on callers sequence and guaranteed to be
// called in order of GetFrameInfo calls. Callback can be called before this
// function returns if all necessary info is available right away.
// //
// While this API might seem to be out of its Vulkan mind, it's this // While this API might seem to be out of its Vulkan mind, it's this
// complicated to (a) prevent rendering frames out of order to the front // complicated to (a) prevent rendering frames out of order to the front
...@@ -52,9 +55,7 @@ class MEDIA_GPU_EXPORT FrameInfoHelper { ...@@ -52,9 +55,7 @@ class MEDIA_GPU_EXPORT FrameInfoHelper {
// can't get a YCbCrInfo from a CodecImage due to timeouts. // can't get a YCbCrInfo from a CodecImage due to timeouts.
virtual void GetFrameInfo( virtual void GetFrameInfo(
std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer, std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer,
base::OnceCallback<void(std::unique_ptr<CodecOutputBufferRenderer>, FrameInfoReadyCB callback) = 0;
FrameInfo,
bool)> cb) = 0;
protected: protected:
FrameInfoHelper() = default; FrameInfoHelper() = default;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "base/test/bind_test_util.h" #include "base/test/bind_test_util.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "gpu/command_buffer/service/mock_texture_owner.h" #include "gpu/command_buffer/service/mock_texture_owner.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -18,11 +19,19 @@ namespace { ...@@ -18,11 +19,19 @@ namespace {
constexpr gfx::Size kTestVisibleSize(100, 100); constexpr gfx::Size kTestVisibleSize(100, 100);
constexpr gfx::Size kTestVisibleSize2(110, 110); constexpr gfx::Size kTestVisibleSize2(110, 110);
constexpr gfx::Size kTestCodedSize(128, 128); constexpr gfx::Size kTestCodedSize(128, 128);
std::unique_ptr<FrameInfoHelper> CreateHelper() {
auto task_runner = base::ThreadTaskRunnerHandle::Get();
auto get_stub_cb =
base::Bind([]() -> gpu::CommandBufferStub* { return nullptr; });
return FrameInfoHelper::Create(std::move(task_runner),
std::move(get_stub_cb));
}
} // namespace } // namespace
class FrameInfoHelperTest : public testing::Test { class FrameInfoHelperTest : public testing::Test {
public: public:
FrameInfoHelperTest() : helper_(FrameInfoHelper::CreateForTesting()) {} FrameInfoHelperTest() : helper_(CreateHelper()) {}
protected: protected:
void GetFrameInfo( void GetFrameInfo(
...@@ -31,13 +40,13 @@ class FrameInfoHelperTest : public testing::Test { ...@@ -31,13 +40,13 @@ class FrameInfoHelperTest : public testing::Test {
bool called = false; bool called = false;
auto callback = base::BindLambdaForTesting( auto callback = base::BindLambdaForTesting(
[&](std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer, [&](std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer,
FrameInfoHelper::FrameInfo info, bool success) { FrameInfoHelper::FrameInfo info) {
ASSERT_EQ(buffer_renderer_raw, buffer_renderer.get()); ASSERT_EQ(buffer_renderer_raw, buffer_renderer.get());
called = true; called = true;
last_get_frame_info_succeeded_ = success;
last_frame_info_ = info; last_frame_info_ = info;
}); });
helper_->GetFrameInfo(std::move(buffer_renderer), callback); helper_->GetFrameInfo(std::move(buffer_renderer), callback);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(called); ASSERT_TRUE(called);
} }
...@@ -67,15 +76,12 @@ class FrameInfoHelperTest : public testing::Test { ...@@ -67,15 +76,12 @@ class FrameInfoHelperTest : public testing::Test {
base::test::SingleThreadTaskEnvironment task_environment_; base::test::SingleThreadTaskEnvironment task_environment_;
std::unique_ptr<FrameInfoHelper> helper_; std::unique_ptr<FrameInfoHelper> helper_;
bool last_get_frame_info_succeeded_ = false;
FrameInfoHelper::FrameInfo last_frame_info_; FrameInfoHelper::FrameInfo last_frame_info_;
}; };
TEST_F(FrameInfoHelperTest, NoBufferRenderer) { TEST_F(FrameInfoHelperTest, NoBufferRenderer) {
// If there is no buffer renderer we shouldn't crash and report that request // If there is no buffer renderer we shouldn't crash.
// failed.
GetFrameInfo(nullptr); GetFrameInfo(nullptr);
EXPECT_FALSE(last_get_frame_info_succeeded_);
} }
TEST_F(FrameInfoHelperTest, TextureOwner) { TEST_F(FrameInfoHelperTest, TextureOwner) {
...@@ -93,7 +99,6 @@ TEST_F(FrameInfoHelperTest, TextureOwner) { ...@@ -93,7 +99,6 @@ TEST_F(FrameInfoHelperTest, TextureOwner) {
// as failed. // as failed.
EXPECT_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _)).Times(0); EXPECT_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _)).Times(0);
GetFrameInfo(std::move(buffer1)); GetFrameInfo(std::move(buffer1));
EXPECT_FALSE(last_get_frame_info_succeeded_);
EXPECT_EQ(last_frame_info_.coded_size, kTestVisibleSize); EXPECT_EQ(last_frame_info_.coded_size, kTestVisibleSize);
Mock::VerifyAndClearExpectations(texture_owner.get()); Mock::VerifyAndClearExpectations(texture_owner.get());
...@@ -101,7 +106,6 @@ TEST_F(FrameInfoHelperTest, TextureOwner) { ...@@ -101,7 +106,6 @@ TEST_F(FrameInfoHelperTest, TextureOwner) {
// be called and result should be kTestCodedSize instead of kTestVisibleSize. // be called and result should be kTestCodedSize instead of kTestVisibleSize.
EXPECT_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _)).Times(1); EXPECT_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _)).Times(1);
GetFrameInfo(CreateBufferRenderer(kTestVisibleSize, texture_owner)); GetFrameInfo(CreateBufferRenderer(kTestVisibleSize, texture_owner));
EXPECT_TRUE(last_get_frame_info_succeeded_);
EXPECT_EQ(last_frame_info_.coded_size, kTestCodedSize); EXPECT_EQ(last_frame_info_.coded_size, kTestCodedSize);
Mock::VerifyAndClearExpectations(texture_owner.get()); Mock::VerifyAndClearExpectations(texture_owner.get());
...@@ -109,22 +113,102 @@ TEST_F(FrameInfoHelperTest, TextureOwner) { ...@@ -109,22 +113,102 @@ TEST_F(FrameInfoHelperTest, TextureOwner) {
// size. GetCodedSizeAndVisibleRect should not be called. // size. GetCodedSizeAndVisibleRect should not be called.
EXPECT_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _)).Times(0); EXPECT_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _)).Times(0);
GetFrameInfo(CreateBufferRenderer(kTestVisibleSize, texture_owner)); GetFrameInfo(CreateBufferRenderer(kTestVisibleSize, texture_owner));
EXPECT_TRUE(last_get_frame_info_succeeded_);
EXPECT_EQ(last_frame_info_.coded_size, kTestCodedSize); EXPECT_EQ(last_frame_info_.coded_size, kTestCodedSize);
Mock::VerifyAndClearExpectations(texture_owner.get()); Mock::VerifyAndClearExpectations(texture_owner.get());
// Verify that we render if the visible size changed. // Verify that we render if the visible size changed.
EXPECT_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _)).Times(1); EXPECT_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _)).Times(1);
GetFrameInfo(CreateBufferRenderer(kTestVisibleSize2, texture_owner)); GetFrameInfo(CreateBufferRenderer(kTestVisibleSize2, texture_owner));
EXPECT_TRUE(last_get_frame_info_succeeded_);
EXPECT_EQ(last_frame_info_.coded_size, kTestCodedSize); EXPECT_EQ(last_frame_info_.coded_size, kTestCodedSize);
} }
TEST_F(FrameInfoHelperTest, Overlay) { TEST_F(FrameInfoHelperTest, Overlay) {
// In overlay case we always use visible size. // In overlay case we always use visible size.
GetFrameInfo(CreateBufferRenderer(kTestVisibleSize, nullptr)); GetFrameInfo(CreateBufferRenderer(kTestVisibleSize, nullptr));
EXPECT_TRUE(last_get_frame_info_succeeded_);
EXPECT_EQ(last_frame_info_.coded_size, kTestVisibleSize); EXPECT_EQ(last_frame_info_.coded_size, kTestVisibleSize);
} }
TEST_F(FrameInfoHelperTest, SwitchBetweenOverlayAndTextureOwner) {
auto texture_owner = base::MakeRefCounted<NiceMock<gpu::MockTextureOwner>>(
0, nullptr, nullptr, true);
// Return CodedSize when GetCodedSizeAndVisibleRect is called.
ON_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _))
.WillByDefault(SetArgPointee<1>(kTestCodedSize));
// In overlay case we always use visible size.
GetFrameInfo(CreateBufferRenderer(kTestVisibleSize, nullptr));
EXPECT_EQ(last_frame_info_.coded_size, kTestVisibleSize);
// Verify that when we switch to TextureOwner we request new size.
EXPECT_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _)).Times(1);
GetFrameInfo(CreateBufferRenderer(kTestVisibleSize, texture_owner));
EXPECT_EQ(last_frame_info_.coded_size, kTestCodedSize);
Mock::VerifyAndClearExpectations(texture_owner.get());
// Switch back to overlay and verify that we falled back to visible size and
// didn't try to render image.
EXPECT_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _)).Times(0);
GetFrameInfo(CreateBufferRenderer(kTestVisibleSize, nullptr));
EXPECT_EQ(last_frame_info_.coded_size, kTestVisibleSize);
Mock::VerifyAndClearExpectations(texture_owner.get());
// Verify that when we switch to TextureOwner we use cached size.
EXPECT_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _)).Times(0);
GetFrameInfo(CreateBufferRenderer(kTestVisibleSize, texture_owner));
EXPECT_EQ(last_frame_info_.coded_size, kTestCodedSize);
Mock::VerifyAndClearExpectations(texture_owner.get());
// Switch back to overlay again.
EXPECT_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _)).Times(0);
GetFrameInfo(CreateBufferRenderer(kTestVisibleSize, nullptr));
EXPECT_EQ(last_frame_info_.coded_size, kTestVisibleSize);
Mock::VerifyAndClearExpectations(texture_owner.get());
// Verify that when we switch to TextureOwner with resize we render another
// frame.
EXPECT_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _)).Times(1);
GetFrameInfo(CreateBufferRenderer(kTestVisibleSize2, texture_owner));
EXPECT_EQ(last_frame_info_.coded_size, kTestCodedSize);
Mock::VerifyAndClearExpectations(texture_owner.get());
}
TEST_F(FrameInfoHelperTest, OrderingTest) {
auto texture_owner = base::MakeRefCounted<NiceMock<gpu::MockTextureOwner>>(
0, nullptr, nullptr, true);
// Return CodedSize when GetCodedSizeAndVisibleRect is called.
ON_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _))
.WillByDefault(SetArgPointee<1>(kTestCodedSize));
auto buffer_renderer = CreateBufferRenderer(kTestVisibleSize, texture_owner);
// Create first callback and request frame.
const auto* buffer_renderer_raw = buffer_renderer.get();
bool called = false;
auto callback = base::BindLambdaForTesting(
[&](std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer,
FrameInfoHelper::FrameInfo info) {
ASSERT_EQ(buffer_renderer_raw, buffer_renderer.get());
called = true;
last_frame_info_ = info;
});
helper_->GetFrameInfo(std::move(buffer_renderer), callback);
// Create run after callback.
bool run_after_called = false;
auto run_after_callback = base::BindLambdaForTesting(
[&](std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer,
FrameInfoHelper::FrameInfo info) {
ASSERT_EQ(buffer_renderer.get(), nullptr);
// Expect first callback was called before this.
EXPECT_TRUE(called);
run_after_called = true;
});
helper_->GetFrameInfo(nullptr, run_after_callback);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(called);
ASSERT_TRUE(run_after_called);
}
} // namespace media } // namespace media
...@@ -81,7 +81,7 @@ VideoFrameFactoryImpl::VideoFrameFactoryImpl( ...@@ -81,7 +81,7 @@ VideoFrameFactoryImpl::VideoFrameFactoryImpl(
const gpu::GpuPreferences& gpu_preferences, const gpu::GpuPreferences& gpu_preferences,
std::unique_ptr<SharedImageVideoProvider> image_provider, std::unique_ptr<SharedImageVideoProvider> image_provider,
std::unique_ptr<MaybeRenderEarlyManager> mre_manager, std::unique_ptr<MaybeRenderEarlyManager> mre_manager,
base::SequenceBound<FrameInfoHelper> frame_info_helper) std::unique_ptr<FrameInfoHelper> frame_info_helper)
: image_provider_(std::move(image_provider)), : image_provider_(std::move(image_provider)),
gpu_task_runner_(std::move(gpu_task_runner)), gpu_task_runner_(std::move(gpu_task_runner)),
enable_threaded_texture_mailboxes_( enable_threaded_texture_mailboxes_(
...@@ -113,10 +113,6 @@ void VideoFrameFactoryImpl::SetSurfaceBundle( ...@@ -113,10 +113,6 @@ void VideoFrameFactoryImpl::SetSurfaceBundle(
// changing the TextureOwner. This is temporary. See ImageSpec. // changing the TextureOwner. This is temporary. See ImageSpec.
image_spec_.generation_id++; image_spec_.generation_id++;
// Reset cached visible size as we might switched between overlay and texture
// owner mode.
visible_size_ = gfx::Size();
if (!surface_bundle) { if (!surface_bundle) {
// Clear everything, just so we're not holding a reference. // Clear everything, just so we're not holding a reference.
codec_buffer_wait_coordinator_ = nullptr; codec_buffer_wait_coordinator_ = nullptr;
...@@ -185,48 +181,20 @@ void VideoFrameFactoryImpl::CreateVideoFrame( ...@@ -185,48 +181,20 @@ void VideoFrameFactoryImpl::CreateVideoFrame(
void VideoFrameFactoryImpl::RequestImage( void VideoFrameFactoryImpl::RequestImage(
std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer, std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer,
ImageWithInfoReadyCB image_ready_cb) { ImageWithInfoReadyCB image_ready_cb) {
if (buffer_renderer && visible_size_ == buffer_renderer->size()) { auto info_cb =
auto cb = base::BindOnce(std::move(image_ready_cb),
std::move(buffer_renderer), frame_info_);
image_provider_->RequestImage(
std::move(cb), image_spec_,
codec_buffer_wait_coordinator_
? codec_buffer_wait_coordinator_->texture_owner()
: nullptr);
return;
}
// We need to reset size to make sure VFFI pipeline is still ordered.
// e.g: CreateVideoFrame is called with new size. We post task to GPU thread
// to get new frame info. While we wait CreateVideoFrame might be called with
// old size again and if we don't reset size here we will skip GPU hop and new
// frame will be created earlier than first one.
visible_size_ = gfx::Size();
auto info_cb = BindToCurrentLoop(
base::BindOnce(&VideoFrameFactoryImpl::CreateVideoFrame_OnFrameInfoReady, base::BindOnce(&VideoFrameFactoryImpl::CreateVideoFrame_OnFrameInfoReady,
weak_factory_.GetWeakPtr(), std::move(image_ready_cb), weak_factory_.GetWeakPtr(), std::move(image_ready_cb),
codec_buffer_wait_coordinator_)); codec_buffer_wait_coordinator_);
frame_info_helper_.Post(FROM_HERE, &FrameInfoHelper::GetFrameInfo, frame_info_helper_->GetFrameInfo(std::move(buffer_renderer),
std::move(buffer_renderer), std::move(info_cb)); std::move(info_cb));
} }
void VideoFrameFactoryImpl::CreateVideoFrame_OnFrameInfoReady( void VideoFrameFactoryImpl::CreateVideoFrame_OnFrameInfoReady(
ImageWithInfoReadyCB image_ready_cb, ImageWithInfoReadyCB image_ready_cb,
scoped_refptr<CodecBufferWaitCoordinator> codec_buffer_wait_coordinator, scoped_refptr<CodecBufferWaitCoordinator> codec_buffer_wait_coordinator,
std::unique_ptr<CodecOutputBufferRenderer> output_buffer_renderer, std::unique_ptr<CodecOutputBufferRenderer> output_buffer_renderer,
FrameInfoHelper::FrameInfo frame_info, FrameInfoHelper::FrameInfo frame_info) {
bool success) {
// To get frame info we need to render frame which might fail for variety of
// reason. FrameInfoHelper will provide best values we can proceed with, but
// we should not cache it and attempt to get info for next frame.
if (success) {
frame_info_ = frame_info;
visible_size_ = output_buffer_renderer->size();
}
// If we don't have output buffer here we can't rely on reply from // If we don't have output buffer here we can't rely on reply from
// FrameInfoHelper as there might be not cached value and we can't render // FrameInfoHelper as there might be not cached value and we can't render
// nothing. But in this case call comes from RunAfterPendingVideoFrames and we // nothing. But in this case call comes from RunAfterPendingVideoFrames and we
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "base/threading/sequence_bound.h"
#include "gpu/config/gpu_preferences.h" #include "gpu/config/gpu_preferences.h"
#include "media/base/video_frame.h" #include "media/base/video_frame.h"
#include "media/gpu/android/codec_buffer_wait_coordinator.h" #include "media/gpu/android/codec_buffer_wait_coordinator.h"
...@@ -52,7 +51,7 @@ class MEDIA_GPU_EXPORT VideoFrameFactoryImpl : public VideoFrameFactory { ...@@ -52,7 +51,7 @@ class MEDIA_GPU_EXPORT VideoFrameFactoryImpl : public VideoFrameFactory {
const gpu::GpuPreferences& gpu_preferences, const gpu::GpuPreferences& gpu_preferences,
std::unique_ptr<SharedImageVideoProvider> image_provider, std::unique_ptr<SharedImageVideoProvider> image_provider,
std::unique_ptr<MaybeRenderEarlyManager> mre_manager, std::unique_ptr<MaybeRenderEarlyManager> mre_manager,
base::SequenceBound<FrameInfoHelper> frame_info_helper); std::unique_ptr<FrameInfoHelper> frame_info_helper);
~VideoFrameFactoryImpl() override; ~VideoFrameFactoryImpl() override;
void Initialize(OverlayMode overlay_mode, InitCB init_cb) override; void Initialize(OverlayMode overlay_mode, InitCB init_cb) override;
...@@ -105,8 +104,7 @@ class MEDIA_GPU_EXPORT VideoFrameFactoryImpl : public VideoFrameFactory { ...@@ -105,8 +104,7 @@ class MEDIA_GPU_EXPORT VideoFrameFactoryImpl : public VideoFrameFactory {
ImageWithInfoReadyCB image_ready_cb, ImageWithInfoReadyCB image_ready_cb,
scoped_refptr<CodecBufferWaitCoordinator> codec_buffer_wait_coordinator, scoped_refptr<CodecBufferWaitCoordinator> codec_buffer_wait_coordinator,
std::unique_ptr<CodecOutputBufferRenderer> output_buffer_renderer, std::unique_ptr<CodecOutputBufferRenderer> output_buffer_renderer,
FrameInfoHelper::FrameInfo frame_info, FrameInfoHelper::FrameInfo frame_info);
bool success);
MaybeRenderEarlyManager* mre_manager() const { return mre_manager_.get(); } MaybeRenderEarlyManager* mre_manager() const { return mre_manager_.get(); }
...@@ -128,12 +126,8 @@ class MEDIA_GPU_EXPORT VideoFrameFactoryImpl : public VideoFrameFactory { ...@@ -128,12 +126,8 @@ class MEDIA_GPU_EXPORT VideoFrameFactoryImpl : public VideoFrameFactory {
std::unique_ptr<MaybeRenderEarlyManager> mre_manager_; std::unique_ptr<MaybeRenderEarlyManager> mre_manager_;
// Caches FrameInfo and visible size it was cached for. // Helper to get coded_size and optional Vulkan YCbCrInfo.
gfx::Size visible_size_; std::unique_ptr<FrameInfoHelper> frame_info_helper_;
FrameInfoHelper::FrameInfo frame_info_;
// Optional helper to get the Vulkan YCbCrInfo.
base::SequenceBound<FrameInfoHelper> frame_info_helper_;
// The current image spec that we'll use to request images. // The current image spec that we'll use to request images.
SharedImageVideoProvider::ImageSpec image_spec_; SharedImageVideoProvider::ImageSpec image_spec_;
......
...@@ -44,46 +44,14 @@ class MockMaybeRenderEarlyManager : public MaybeRenderEarlyManager { ...@@ -44,46 +44,14 @@ class MockMaybeRenderEarlyManager : public MaybeRenderEarlyManager {
class MockFrameInfoHelper : public FrameInfoHelper, class MockFrameInfoHelper : public FrameInfoHelper,
public DestructionObservable { public DestructionObservable {
public: public:
MockFrameInfoHelper(MockFrameInfoHelper** thiz) { *thiz = this; } void GetFrameInfo(std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer,
FrameInfoReadyCB cb) override {
void GetFrameInfo(
std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer,
base::OnceCallback<
void(std::unique_ptr<CodecOutputBufferRenderer>, FrameInfo, bool)> cb)
override {
MockGetFrameInfo(buffer_renderer.get());
cb_ = std::move(cb);
buffer_renderer_ = std::move(buffer_renderer);
if (run_callback_automatically_) {
RunWithYcbCrInfo(true);
base::RunLoop().RunUntilIdle();
}
}
void RunWithYcbCrInfo(bool success) {
DCHECK(buffer_renderer_);
FrameInfo info; FrameInfo info;
info.coded_size = buffer_renderer_->size(); info.coded_size = buffer_renderer->size();
info.visible_rect = gfx::Rect(info.coded_size); info.visible_rect = gfx::Rect(info.coded_size);
std::move(cb_).Run(std::move(buffer_renderer_), info, success); std::move(cb).Run(std::move(buffer_renderer), info);
}
void set_run_callback_automatically(bool run_callback_automatically) {
run_callback_automatically_ = run_callback_automatically;
} }
MOCK_METHOD1(MockGetFrameInfo,
void(CodecOutputBufferRenderer* buffer_renderer));
private:
bool run_callback_automatically_ = true;
base::OnceCallback<
void(std::unique_ptr<CodecOutputBufferRenderer>, FrameInfo, bool)>
cb_;
std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer_;
}; };
class VideoFrameFactoryImplTest : public testing::Test { class VideoFrameFactoryImplTest : public testing::Test {
...@@ -96,15 +64,11 @@ class VideoFrameFactoryImplTest : public testing::Test { ...@@ -96,15 +64,11 @@ class VideoFrameFactoryImplTest : public testing::Test {
auto mre_manager = std::make_unique<MockMaybeRenderEarlyManager>(); auto mre_manager = std::make_unique<MockMaybeRenderEarlyManager>();
mre_manager_raw_ = mre_manager.get(); mre_manager_raw_ = mre_manager.get();
auto ycbcr_helper = base::SequenceBound<MockFrameInfoHelper>( auto info_helper = std::make_unique<MockFrameInfoHelper>();
task_runner_, &ycbcr_helper_raw_);
base::RunLoop().RunUntilIdle(); // Init |ycbcr_helper_raw_|.
ycbcr_destruction_observer_ =
ycbcr_helper_raw_->CreateDestructionObserver();
impl_ = std::make_unique<VideoFrameFactoryImpl>( impl_ = std::make_unique<VideoFrameFactoryImpl>(
task_runner_, gpu_preferences_, std::move(image_provider), task_runner_, gpu_preferences_, std::move(image_provider),
std::move(mre_manager), std::move(ycbcr_helper)); std::move(mre_manager), std::move(info_helper));
auto texture_owner = base::MakeRefCounted<NiceMock<gpu::MockTextureOwner>>( auto texture_owner = base::MakeRefCounted<NiceMock<gpu::MockTextureOwner>>(
0, nullptr, nullptr, true); 0, nullptr, nullptr, true);
auto codec_buffer_wait_coordinator = auto codec_buffer_wait_coordinator =
...@@ -177,7 +141,6 @@ class VideoFrameFactoryImplTest : public testing::Test { ...@@ -177,7 +141,6 @@ class VideoFrameFactoryImplTest : public testing::Test {
// Sent to |impl_| by RequestVideoFrame.. // Sent to |impl_| by RequestVideoFrame..
base::MockCallback<VideoFrameFactory::OnceOutputCB> output_cb_; base::MockCallback<VideoFrameFactory::OnceOutputCB> output_cb_;
MockFrameInfoHelper* ycbcr_helper_raw_ = nullptr;
std::unique_ptr<DestructionObserver> ycbcr_destruction_observer_; std::unique_ptr<DestructionObserver> ycbcr_destruction_observer_;
gpu::GpuPreferences gpu_preferences_; gpu::GpuPreferences gpu_preferences_;
...@@ -272,75 +235,4 @@ TEST_F(VideoFrameFactoryImplTest, ...@@ -272,75 +235,4 @@ TEST_F(VideoFrameFactoryImplTest,
impl_ = nullptr; impl_ = nullptr;
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
} }
TEST_F(VideoFrameFactoryImplTest, DoesCallFrameInfoHelperIfVulkan) {
// We will be driving callback by ourselves in this test.
ycbcr_helper_raw_->set_run_callback_automatically(false);
// Expect call to get info for the first frame.
EXPECT_CALL(*ycbcr_helper_raw_, MockGetFrameInfo(_)).Times(1);
RequestVideoFrame();
// Provide info. It should send image request.
ycbcr_helper_raw_->RunWithYcbCrInfo(true);
base::RunLoop().RunUntilIdle();
testing::Mock::VerifyAndClearExpectations(ycbcr_helper_raw_);
// Fulfilling image request should provide video frame.
EXPECT_CALL(output_cb_, Run(_)).Times(1);
auto image_record = MakeImageRecord();
image_provider_raw_->ProvideOneRequestedImage(&image_record);
base::RunLoop().RunUntilIdle();
// Verify that no more calls happen, since we don't want thread hops on every
// frame. Note that multiple could be dispatched before now. It should still
// send along a VideoFrame, though.
EXPECT_CALL(*ycbcr_helper_raw_, MockGetFrameInfo(_)).Times(0);
EXPECT_CALL(output_cb_, Run(_)).Times(1);
RequestVideoFrame();
auto other_image_record = MakeImageRecord();
// If the helper hasn't been destroyed, then we don't expect it to be called.
image_provider_raw_->ProvideOneRequestedImage(&other_image_record);
base::RunLoop().RunUntilIdle();
}
TEST_F(VideoFrameFactoryImplTest, NullYCbCrInfoDoesntCrash) {
// We will be driving callback by ourselves in this test.
ycbcr_helper_raw_->set_run_callback_automatically(false);
// Expect call to get info for the first frame.
EXPECT_CALL(*ycbcr_helper_raw_, MockGetFrameInfo(_)).Times(1);
RequestVideoFrame();
// Provide info. It should send image request.
ycbcr_helper_raw_->RunWithYcbCrInfo(false);
base::RunLoop().RunUntilIdle();
testing::Mock::VerifyAndClearExpectations(ycbcr_helper_raw_);
// Fulfilling image request should provide video frame.
EXPECT_CALL(output_cb_, Run(_)).Times(1);
auto image_record = MakeImageRecord();
image_provider_raw_->ProvideOneRequestedImage(&image_record);
base::RunLoop().RunUntilIdle();
// Verify that we will get call to GetFrameInfo as previous one failed.
EXPECT_CALL(*ycbcr_helper_raw_, MockGetFrameInfo(_)).Times(1);
EXPECT_CALL(output_cb_, Run(_)).Times(1);
RequestVideoFrame();
ycbcr_helper_raw_->RunWithYcbCrInfo(true);
base::RunLoop().RunUntilIdle();
auto other_image_record = MakeImageRecord();
// If the helper hasn't been destroyed, then we don't expect it to be called.
image_provider_raw_->ProvideOneRequestedImage(&other_image_record);
base::RunLoop().RunUntilIdle();
}
} // 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