Commit 1f31a184 authored by Emircan Uysaler's avatar Emircan Uysaler Committed by Commit Bot

Stop using GpuMemoryBufferVideoFramePool when WebMediaPlayerMS is hidden

This CL adds calls to track when WebMediaPlayerMS is hidden or shown, so
that in the time period we can skip creating GMB backed frames. For that
time period, frames aren't going to be displayed, so copying them to GMBs
is extra work which should be avoided.

Bug: 653200
Change-Id: I67e55c7f1150b434d82321ac90a08c7c3e3e6336
Reviewed-on: https://chromium-review.googlesource.com/954339Reviewed-by: default avatarDaniele Castagna <dcastagna@chromium.org>
Reviewed-by: default avatarDan Sanders <sandersd@chromium.org>
Commit-Queue: Emircan Uysaler <emircan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#542950}
parent e2a9160b
...@@ -72,6 +72,7 @@ class WebMediaPlayerMS::FrameDeliverer { ...@@ -72,6 +72,7 @@ class WebMediaPlayerMS::FrameDeliverer {
player_(player), player_(player),
enqueue_frame_cb_(enqueue_frame_cb), enqueue_frame_cb_(enqueue_frame_cb),
media_task_runner_(media_task_runner), media_task_runner_(media_task_runner),
weak_factory_for_pool_(this),
weak_factory_(this) { weak_factory_(this) {
io_thread_checker_.DetachFromThread(); io_thread_checker_.DetachFromThread();
...@@ -87,6 +88,7 @@ class WebMediaPlayerMS::FrameDeliverer { ...@@ -87,6 +88,7 @@ class WebMediaPlayerMS::FrameDeliverer {
~FrameDeliverer() { ~FrameDeliverer() {
DCHECK(io_thread_checker_.CalledOnValidThread()); DCHECK(io_thread_checker_.CalledOnValidThread());
if (gpu_memory_buffer_pool_) { if (gpu_memory_buffer_pool_) {
gpu_memory_buffer_pool_->Abort();
media_task_runner_->DeleteSoon(FROM_HERE, media_task_runner_->DeleteSoon(FROM_HERE,
gpu_memory_buffer_pool_.release()); gpu_memory_buffer_pool_.release());
} }
...@@ -95,6 +97,7 @@ class WebMediaPlayerMS::FrameDeliverer { ...@@ -95,6 +97,7 @@ class WebMediaPlayerMS::FrameDeliverer {
void OnVideoFrame(scoped_refptr<media::VideoFrame> frame) { void OnVideoFrame(scoped_refptr<media::VideoFrame> frame) {
DCHECK(io_thread_checker_.CalledOnValidThread()); DCHECK(io_thread_checker_.CalledOnValidThread());
// On Android, stop passing frames.
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
if (render_frame_suspended_) if (render_frame_suspended_)
return; return;
...@@ -105,6 +108,20 @@ class WebMediaPlayerMS::FrameDeliverer { ...@@ -105,6 +108,20 @@ class WebMediaPlayerMS::FrameDeliverer {
return; return;
} }
// If |render_frame_suspended_|, we can keep passing the frames to keep the
// latest frame in compositor up to date. However, creating GMB backed
// frames is unnecessary, because the frames are not going to be shown for
// the time period.
if (render_frame_suspended_) {
FrameReady(frame);
// If there are any existing MaybeCreateHardwareFrame() calls, we do not
// want those frames to be placed after the current one, so just drop
// them.
gpu_memory_buffer_pool_->Abort();
weak_factory_for_pool_.InvalidateWeakPtrs();
return;
}
// |gpu_memory_buffer_pool_| deletion is going to be posted to // |gpu_memory_buffer_pool_| deletion is going to be posted to
// |media_task_runner_|. base::Unretained() usage is fine since // |media_task_runner_|. base::Unretained() usage is fine since
// |gpu_memory_buffer_pool_| outlives the task. // |gpu_memory_buffer_pool_| outlives the task.
...@@ -113,8 +130,9 @@ class WebMediaPlayerMS::FrameDeliverer { ...@@ -113,8 +130,9 @@ class WebMediaPlayerMS::FrameDeliverer {
base::BindOnce( base::BindOnce(
&media::GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame, &media::GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame,
base::Unretained(gpu_memory_buffer_pool_.get()), frame, base::Unretained(gpu_memory_buffer_pool_.get()), frame,
media::BindToCurrentLoop(base::BindRepeating( media::BindToCurrentLoop(
&FrameDeliverer::FrameReady, weak_factory_.GetWeakPtr())))); base::BindOnce(&FrameDeliverer::FrameReady,
weak_factory_for_pool_.GetWeakPtr()))));
} }
void FrameReady(const scoped_refptr<media::VideoFrame>& frame) { void FrameReady(const scoped_refptr<media::VideoFrame>& frame) {
...@@ -159,12 +177,10 @@ class WebMediaPlayerMS::FrameDeliverer { ...@@ -159,12 +177,10 @@ class WebMediaPlayerMS::FrameDeliverer {
enqueue_frame_cb_.Run(frame); enqueue_frame_cb_.Run(frame);
} }
#if defined(OS_ANDROID)
void SetRenderFrameSuspended(bool render_frame_suspended) { void SetRenderFrameSuspended(bool render_frame_suspended) {
DCHECK(io_thread_checker_.CalledOnValidThread()); DCHECK(io_thread_checker_.CalledOnValidThread());
render_frame_suspended_ = render_frame_suspended; render_frame_suspended_ = render_frame_suspended;
} }
#endif // defined(OS_ANDROID)
MediaStreamVideoRenderer::RepaintCB GetRepaintCallback() { MediaStreamVideoRenderer::RepaintCB GetRepaintCallback() {
return base::Bind(&FrameDeliverer::OnVideoFrame, return base::Bind(&FrameDeliverer::OnVideoFrame,
...@@ -177,10 +193,7 @@ class WebMediaPlayerMS::FrameDeliverer { ...@@ -177,10 +193,7 @@ class WebMediaPlayerMS::FrameDeliverer {
bool last_frame_opaque_; bool last_frame_opaque_;
media::VideoRotation last_frame_rotation_; media::VideoRotation last_frame_rotation_;
bool received_first_frame_; bool received_first_frame_;
#if defined(OS_ANDROID)
bool render_frame_suspended_ = false; bool render_frame_suspended_ = false;
#endif // defined(OS_ANDROID)
const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
const base::WeakPtr<WebMediaPlayerMS> player_; const base::WeakPtr<WebMediaPlayerMS> player_;
...@@ -193,6 +206,7 @@ class WebMediaPlayerMS::FrameDeliverer { ...@@ -193,6 +206,7 @@ class WebMediaPlayerMS::FrameDeliverer {
// Used for DCHECKs to ensure method calls are executed on the correct thread. // Used for DCHECKs to ensure method calls are executed on the correct thread.
base::ThreadChecker io_thread_checker_; base::ThreadChecker io_thread_checker_;
base::WeakPtrFactory<FrameDeliverer> weak_factory_for_pool_;
base::WeakPtrFactory<FrameDeliverer> weak_factory_; base::WeakPtrFactory<FrameDeliverer> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FrameDeliverer); DISALLOW_COPY_AND_ASSIGN(FrameDeliverer);
...@@ -736,27 +750,28 @@ size_t WebMediaPlayerMS::VideoDecodedByteCount() const { ...@@ -736,27 +750,28 @@ size_t WebMediaPlayerMS::VideoDecodedByteCount() const {
} }
void WebMediaPlayerMS::OnFrameHidden() { void WebMediaPlayerMS::OnFrameHidden() {
#if defined(OS_ANDROID)
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
// This method is called when the RenderFrame is sent to background or
// Method called when the RenderFrame is sent to background and suspended // suspended. During undoable tab closures OnHidden() may be called back to
// (android). Substitute the displayed VideoFrame with a copy to avoid // back, so we can't rely on |render_frame_suspended_| being false here.
// holding on to it unnecessarily.
//
// During undoable tab closures OnHidden() may be called back to back, so we
// can't rely on |render_frame_suspended_| being false here.
if (frame_deliverer_) { if (frame_deliverer_) {
io_task_runner_->PostTask( io_task_runner_->PostTask(
FROM_HERE, base::Bind(&FrameDeliverer::SetRenderFrameSuspended, FROM_HERE, base::Bind(&FrameDeliverer::SetRenderFrameSuspended,
base::Unretained(frame_deliverer_.get()), true)); base::Unretained(frame_deliverer_.get()), true));
} }
// On Android, substitute the displayed VideoFrame with a copy to avoid holding
// onto it unnecessarily.
#if defined(OS_ANDROID)
if (!paused_) if (!paused_)
compositor_->ReplaceCurrentFrameWithACopy(); compositor_->ReplaceCurrentFrameWithACopy();
#endif // defined(OS_ANDROID) #endif // defined(OS_ANDROID)
} }
void WebMediaPlayerMS::OnFrameClosed() { void WebMediaPlayerMS::OnFrameClosed() {
DCHECK(thread_checker_.CalledOnValidThread());
// On Android, pause the video completely for this time period.
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
if (!paused_) { if (!paused_) {
Pause(); Pause();
...@@ -764,17 +779,16 @@ void WebMediaPlayerMS::OnFrameClosed() { ...@@ -764,17 +779,16 @@ void WebMediaPlayerMS::OnFrameClosed() {
} }
delegate_->PlayerGone(delegate_id_); delegate_->PlayerGone(delegate_id_);
#endif // defined(OS_ANDROID)
if (frame_deliverer_) { if (frame_deliverer_) {
io_task_runner_->PostTask( io_task_runner_->PostTask(
FROM_HERE, base::Bind(&FrameDeliverer::SetRenderFrameSuspended, FROM_HERE, base::Bind(&FrameDeliverer::SetRenderFrameSuspended,
base::Unretained(frame_deliverer_.get()), true)); base::Unretained(frame_deliverer_.get()), true));
} }
#endif // defined(OS_ANDROID)
} }
void WebMediaPlayerMS::OnFrameShown() { void WebMediaPlayerMS::OnFrameShown() {
#if defined(OS_ANDROID)
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
if (frame_deliverer_) { if (frame_deliverer_) {
...@@ -783,7 +797,9 @@ void WebMediaPlayerMS::OnFrameShown() { ...@@ -783,7 +797,9 @@ void WebMediaPlayerMS::OnFrameShown() {
base::Unretained(frame_deliverer_.get()), false)); base::Unretained(frame_deliverer_.get()), false));
} }
// Resume playback on visibility. play() clears |should_play_upon_shown_|. // On Android, resume playback on visibility. play() clears
// |should_play_upon_shown_|.
#if defined(OS_ANDROID)
if (should_play_upon_shown_) if (should_play_upon_shown_)
Play(); Play();
#endif // defined(OS_ANDROID) #endif // defined(OS_ANDROID)
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "build/build_config.h"
#include "content/public/renderer/media_stream_renderer_factory.h" #include "content/public/renderer/media_stream_renderer_factory.h"
#include "content/renderer/media/stream/webmediaplayer_ms.h" #include "content/renderer/media/stream/webmediaplayer_ms.h"
#include "content/renderer/media/stream/webmediaplayer_ms_compositor.h" #include "content/renderer/media/stream/webmediaplayer_ms_compositor.h"
...@@ -1091,6 +1092,65 @@ TEST_F(WebMediaPlayerMSTest, CreateHardwareFrames) { ...@@ -1091,6 +1092,65 @@ TEST_F(WebMediaPlayerMSTest, CreateHardwareFrames) {
EXPECT_CALL(*this, DoStopRendering()); EXPECT_CALL(*this, DoStopRendering());
} }
#if !defined(OS_ANDROID)
// Tests that GpuMemoryBufferVideoFramePool is not called when page is hidden.
TEST_F(WebMediaPlayerMSTest, StopsCreatingHardwareFramesWhenHiddenOrClosed) {
MockMediaStreamVideoRenderer* provider = LoadAndGetFrameProvider(true);
SetGpuMemoryBufferVideoForTesting();
const int kTestBrake = static_cast<int>(FrameType::TEST_BRAKE);
static int tokens[] = {0, kTestBrake};
std::vector<int> timestamps(tokens, tokens + sizeof(tokens) / sizeof(int));
provider->QueueFrames(timestamps);
EXPECT_CALL(*this, DoSetWebLayer(true));
EXPECT_CALL(*this, DoStartRendering());
EXPECT_CALL(*this, DoReadyStateChanged(
blink::WebMediaPlayer::kReadyStateHaveMetadata));
EXPECT_CALL(*this, DoReadyStateChanged(
blink::WebMediaPlayer::kReadyStateHaveEnoughData));
EXPECT_CALL(*this,
CheckSizeChanged(gfx::Size(kStandardWidth, kStandardHeight)));
message_loop_controller_.RunAndWaitForStatus(
media::PipelineStatus::PIPELINE_OK);
ASSERT_EQ(1u, frame_ready_cbs_.size());
frame_ready_cbs_.clear();
// Hidden should stop passing frames to GpuMemoryBufferVideoFramePool.
player_->OnFrameHidden();
provider->QueueFrames(timestamps, false);
message_loop_controller_.RunAndWaitForStatus(
media::PipelineStatus::PIPELINE_OK);
ASSERT_EQ(0u, frame_ready_cbs_.size());
// Shown should resume passing frames to GpuMemoryBufferVideoFramePool.
player_->OnFrameShown();
provider->QueueFrames(timestamps, false);
message_loop_controller_.RunAndWaitForStatus(
media::PipelineStatus::PIPELINE_OK);
ASSERT_EQ(1u, frame_ready_cbs_.size());
frame_ready_cbs_.clear();
// Hidden should stop passing frames to GpuMemoryBufferVideoFramePool.
player_->OnFrameClosed();
provider->QueueFrames(timestamps, false);
message_loop_controller_.RunAndWaitForStatus(
media::PipelineStatus::PIPELINE_OK);
ASSERT_EQ(0u, frame_ready_cbs_.size());
// Shown should resume passing frames to GpuMemoryBufferVideoFramePool.
player_->OnFrameShown();
provider->QueueFrames(timestamps, false);
message_loop_controller_.RunAndWaitForStatus(
media::PipelineStatus::PIPELINE_OK);
ASSERT_EQ(1u, frame_ready_cbs_.size());
testing::Mock::VerifyAndClearExpectations(this);
EXPECT_CALL(*this, DoSetWebLayer(false));
EXPECT_CALL(*this, DoStopRendering());
}
#endif // !defined(OS_ANDROID)
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
TEST_F(WebMediaPlayerMSTest, HiddenPlayerTests) { TEST_F(WebMediaPlayerMSTest, HiddenPlayerTests) {
LoadAndGetFrameProvider(true); LoadAndGetFrameProvider(true);
......
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