Commit c3089ac9 authored by Emircan Uysaler's avatar Emircan Uysaler Committed by Commit Bot

Reland "Stop using GpuMemoryBufferVideoFramePool when WebMediaPlayerMS is hidden"

This is a reland of 1f31a184

Original change's description:
> 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/954339
> Reviewed-by: Daniele Castagna <dcastagna@chromium.org>
> Reviewed-by: Dan Sanders <sandersd@chromium.org>
> Commit-Queue: Emircan Uysaler <emircan@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#542950}

Bug: 653200
TBR: sandersd@chromium.org, dcastagna@chromium.org
Change-Id: I277eca14cac19e80b4b00dae75188842d7b49c97
Reviewed-on: https://chromium-review.googlesource.com/963581Reviewed-by: default avatarEmircan Uysaler <emircan@chromium.org>
Commit-Queue: Emircan Uysaler <emircan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#543241}
parent 1de17bc9
......@@ -72,6 +72,7 @@ class WebMediaPlayerMS::FrameDeliverer {
player_(player),
enqueue_frame_cb_(enqueue_frame_cb),
media_task_runner_(media_task_runner),
weak_factory_for_pool_(this),
weak_factory_(this) {
io_thread_checker_.DetachFromThread();
......@@ -87,6 +88,7 @@ class WebMediaPlayerMS::FrameDeliverer {
~FrameDeliverer() {
DCHECK(io_thread_checker_.CalledOnValidThread());
if (gpu_memory_buffer_pool_) {
gpu_memory_buffer_pool_->Abort();
media_task_runner_->DeleteSoon(FROM_HERE,
gpu_memory_buffer_pool_.release());
}
......@@ -95,6 +97,7 @@ class WebMediaPlayerMS::FrameDeliverer {
void OnVideoFrame(scoped_refptr<media::VideoFrame> frame) {
DCHECK(io_thread_checker_.CalledOnValidThread());
// On Android, stop passing frames.
#if defined(OS_ANDROID)
if (render_frame_suspended_)
return;
......@@ -105,6 +108,20 @@ class WebMediaPlayerMS::FrameDeliverer {
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
// |media_task_runner_|. base::Unretained() usage is fine since
// |gpu_memory_buffer_pool_| outlives the task.
......@@ -113,8 +130,9 @@ class WebMediaPlayerMS::FrameDeliverer {
base::BindOnce(
&media::GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame,
base::Unretained(gpu_memory_buffer_pool_.get()), frame,
media::BindToCurrentLoop(base::BindRepeating(
&FrameDeliverer::FrameReady, weak_factory_.GetWeakPtr()))));
media::BindToCurrentLoop(
base::BindOnce(&FrameDeliverer::FrameReady,
weak_factory_for_pool_.GetWeakPtr()))));
}
void FrameReady(const scoped_refptr<media::VideoFrame>& frame) {
......@@ -159,12 +177,10 @@ class WebMediaPlayerMS::FrameDeliverer {
enqueue_frame_cb_.Run(frame);
}
#if defined(OS_ANDROID)
void SetRenderFrameSuspended(bool render_frame_suspended) {
DCHECK(io_thread_checker_.CalledOnValidThread());
render_frame_suspended_ = render_frame_suspended;
}
#endif // defined(OS_ANDROID)
MediaStreamVideoRenderer::RepaintCB GetRepaintCallback() {
return base::Bind(&FrameDeliverer::OnVideoFrame,
......@@ -177,10 +193,7 @@ class WebMediaPlayerMS::FrameDeliverer {
bool last_frame_opaque_;
media::VideoRotation last_frame_rotation_;
bool received_first_frame_;
#if defined(OS_ANDROID)
bool render_frame_suspended_ = false;
#endif // defined(OS_ANDROID)
const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
const base::WeakPtr<WebMediaPlayerMS> player_;
......@@ -193,6 +206,7 @@ class WebMediaPlayerMS::FrameDeliverer {
// Used for DCHECKs to ensure method calls are executed on the correct thread.
base::ThreadChecker io_thread_checker_;
base::WeakPtrFactory<FrameDeliverer> weak_factory_for_pool_;
base::WeakPtrFactory<FrameDeliverer> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FrameDeliverer);
......@@ -736,27 +750,28 @@ size_t WebMediaPlayerMS::VideoDecodedByteCount() const {
}
void WebMediaPlayerMS::OnFrameHidden() {
#if defined(OS_ANDROID)
DCHECK(thread_checker_.CalledOnValidThread());
// Method called when the RenderFrame is sent to background and suspended
// (android). Substitute the displayed VideoFrame with a copy to avoid
// 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.
// This method is called when the RenderFrame is sent to background or
// suspended. 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_) {
io_task_runner_->PostTask(
FROM_HERE, base::Bind(&FrameDeliverer::SetRenderFrameSuspended,
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_)
compositor_->ReplaceCurrentFrameWithACopy();
#endif // defined(OS_ANDROID)
}
void WebMediaPlayerMS::OnFrameClosed() {
DCHECK(thread_checker_.CalledOnValidThread());
// On Android, pause the video completely for this time period.
#if defined(OS_ANDROID)
if (!paused_) {
Pause();
......@@ -764,17 +779,16 @@ void WebMediaPlayerMS::OnFrameClosed() {
}
delegate_->PlayerGone(delegate_id_);
#endif // defined(OS_ANDROID)
if (frame_deliverer_) {
io_task_runner_->PostTask(
FROM_HERE, base::Bind(&FrameDeliverer::SetRenderFrameSuspended,
base::Unretained(frame_deliverer_.get()), true));
}
#endif // defined(OS_ANDROID)
}
void WebMediaPlayerMS::OnFrameShown() {
#if defined(OS_ANDROID)
DCHECK(thread_checker_.CalledOnValidThread());
if (frame_deliverer_) {
......@@ -783,7 +797,9 @@ void WebMediaPlayerMS::OnFrameShown() {
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_)
Play();
#endif // defined(OS_ANDROID)
......
......@@ -8,6 +8,7 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "build/build_config.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_compositor.h"
......@@ -1091,6 +1092,67 @@ TEST_F(WebMediaPlayerMSTest, CreateHardwareFrames) {
EXPECT_CALL(*this, DoStopRendering());
}
// Hidden and closed trigger different events on Android and this test doesn't
// cover that, see HiddenPlayerTests for specifics.
#if !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
// 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)
TEST_F(WebMediaPlayerMSTest, HiddenPlayerTests) {
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