Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(83)

Unified Diff: content/renderer/media/webmediaplayer_ms.cc

Issue 2472273002: Move passing of WebRTC rendering frames from main thread to compositor thread (Closed)
Patch Set: wez@ comments. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/renderer/media/webmediaplayer_ms.cc
diff --git a/content/renderer/media/webmediaplayer_ms.cc b/content/renderer/media/webmediaplayer_ms.cc
index 7d8f77ecc76a90d2fe46b022377d59f59a0dfd8c..7ecee9a793bf506343742b4d1d2687e68042b51d 100644
--- a/content/renderer/media/webmediaplayer_ms.cc
+++ b/content/renderer/media/webmediaplayer_ms.cc
@@ -11,6 +11,7 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "cc/blink/web_layer_impl.h"
#include "cc/layers/video_frame_provider_client_impl.h"
@@ -23,6 +24,7 @@
#include "content/renderer/media/webmediaplayer_ms_compositor.h"
#include "content/renderer/render_frame_impl.h"
#include "content/renderer/render_thread_impl.h"
+#include "media/base/bind_to_current_loop.h"
#include "media/base/media_content_type.h"
#include "media/base/media_log.h"
#include "media/base/video_frame.h"
@@ -36,6 +38,96 @@
namespace content {
+// FrameDeliverer is responsible for delivering frames received on
+// compositor thread by calling of EnqueueFrame() method of |compositor_|.
+//
+// It is created on main thread, but methods should be called and class should
+// be destructed on compositor thread.
+class WebMediaPlayerMS::FrameDeliverer
+ : public base::SupportsWeakPtr<FrameDeliverer> {
+ public:
+ typedef base::Callback<void(scoped_refptr<media::VideoFrame>)>
+ EnqueueFrameCallback;
+
+ FrameDeliverer(const base::WeakPtr<WebMediaPlayerMS>& player,
+ const EnqueueFrameCallback& enqueue_frame_cb)
+ : last_frame_opaque_(true),
+ received_first_frame_(false),
+ main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ player_(player),
+ enqueue_frame_cb_(enqueue_frame_cb) {
+ compositor_thread_checker_.DetachFromThread();
+ }
+
+ ~FrameDeliverer() {
+ DCHECK(compositor_thread_checker_.CalledOnValidThread());
+ }
+
+ void OnVideoFrame(scoped_refptr<media::VideoFrame> frame) {
+ DCHECK(compositor_thread_checker_.CalledOnValidThread());
+
+#if defined(OS_ANDROID)
+ if (render_frame_suspended_)
+ return;
+#endif // defined(OS_ANDROID)
+
+ base::TimeTicks render_time;
+ if (frame->metadata()->GetTimeTicks(
+ media::VideoFrameMetadata::REFERENCE_TIME, &render_time)) {
+ TRACE_EVENT1("webrtc", "WebMediaPlayerMS::OnFrameAvailable",
+ "Ideal Render Instant", render_time.ToInternalValue());
+ } else {
+ TRACE_EVENT0("webrtc", "WebMediaPlayerMS::OnFrameAvailable");
+ }
+ const bool is_opaque = media::IsOpaque(frame->format());
+
+ if (!received_first_frame_) {
+ received_first_frame_ = true;
+ last_frame_opaque_ = is_opaque;
+ media::VideoRotation video_rotation;
+ ignore_result(frame->metadata()->GetRotation(
+ media::VideoFrameMetadata::ROTATION, &video_rotation));
+ main_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&WebMediaPlayerMS::OnFirstFrameReceived,
+ player_, video_rotation, is_opaque));
+ }
+
+ if (last_frame_opaque_ != is_opaque) {
+ last_frame_opaque_ = is_opaque;
+ main_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&WebMediaPlayerMS::OnOpacityChanged, player_, is_opaque));
+ }
+
+ enqueue_frame_cb_.Run(frame);
+ }
+
+#if defined(OS_ANDROID)
+ void SetRenderFrameSuspended(bool render_frame_suspended) {
+ DCHECK(compositor_thread_checker_.CalledOnValidThread());
+ render_frame_suspended_ = render_frame_suspended;
+ }
+#endif // defined(OS_ANDROID)
+
+ private:
+ bool last_frame_opaque_;
+ 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_;
+ const EnqueueFrameCallback enqueue_frame_cb_;
+
+ // Used for DCHECKs to ensure method calls executed on the correct thread,
+ // i.e. compositor thread.
+ base::ThreadChecker compositor_thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(FrameDeliverer);
+};
+
WebMediaPlayerMS::WebMediaPlayerMS(
blink::WebFrame* frame,
blink::WebMediaPlayerClient* client,
@@ -55,10 +147,7 @@ WebMediaPlayerMS::WebMediaPlayerMS(
client_(client),
delegate_(delegate),
delegate_id_(0),
- last_frame_opaque_(true),
paused_(true),
- render_frame_suspended_(false),
- received_first_frame_(false),
video_rotation_(media::VIDEO_ROTATION_0),
media_log_(media_log),
renderer_factory_(std::move(factory)),
@@ -90,6 +179,10 @@ WebMediaPlayerMS::~WebMediaPlayerMS() {
get_client()->setWebLayer(nullptr);
if (video_weblayer_)
static_cast<cc::VideoLayer*>(video_weblayer_->layer())->StopUsingProvider();
+
+ if (frame_deliverer_)
+ compositor_task_runner_->DeleteSoon(FROM_HERE, frame_deliverer_.release());
+
if (compositor_)
compositor_task_runner_->DeleteSoon(FROM_HERE, compositor_.release());
@@ -129,10 +222,17 @@ void WebMediaPlayerMS::load(LoadType load_type,
web_stream.isNull() ? std::string() : web_stream.id().utf8();
media_log_->AddEvent(media_log_->CreateLoadEvent(stream_id));
+ // base::Unretained usage is safe here because |compositor_| is destroyed
+ // after |frame_deliverer_|.
+ frame_deliverer_.reset(new WebMediaPlayerMS::FrameDeliverer(
+ AsWeakPtr(), base::Bind(&WebMediaPlayerMSCompositor::EnqueueFrame,
+ base::Unretained(compositor_.get()))));
video_frame_provider_ = renderer_factory_->GetVideoRenderer(
- web_stream, base::Bind(&WebMediaPlayerMS::OnSourceError, AsWeakPtr()),
- base::Bind(&WebMediaPlayerMS::OnFrameAvailable, AsWeakPtr()),
- media_task_runner_, worker_task_runner_, gpu_factories_);
+ web_stream, media::BindToCurrentLoop(base::Bind(
+ &WebMediaPlayerMS::OnSourceError, AsWeakPtr())),
+ base::Bind(&FrameDeliverer::OnVideoFrame, frame_deliverer_->AsWeakPtr()),
DaleCurtis 2016/11/17 02:18:51 Can you just have the frame deliverer return a cal
emircan 2016/11/17 19:43:46 Done. I removed base::SupportsWeakPtr<FrameDeliver
+ compositor_task_runner_, media_task_runner_, worker_task_runner_,
+ gpu_factories_);
RenderFrame* const frame = RenderFrame::FromWebFrame(frame_);
@@ -402,8 +502,12 @@ void WebMediaPlayerMS::OnHidden() {
//
// 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_) {
+ compositor_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&FrameDeliverer::SetRenderFrameSuspended,
+ base::Unretained(frame_deliverer_.get()), true));
+ }
- render_frame_suspended_ = true;
if (!paused_)
compositor_->ReplaceCurrentFrameWithACopy();
#endif // defined(OS_ANDROID)
@@ -413,7 +517,11 @@ void WebMediaPlayerMS::OnShown() {
#if defined(OS_ANDROID)
DCHECK(thread_checker_.CalledOnValidThread());
- render_frame_suspended_ = false;
+ if (frame_deliverer_) {
+ compositor_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&FrameDeliverer::SetRenderFrameSuspended,
+ base::Unretained(frame_deliverer_.get()), false));
+ }
// Resume playback on visibility. play() clears |should_play_upon_shown_|.
if (should_play_upon_shown_)
@@ -434,8 +542,12 @@ bool WebMediaPlayerMS::OnSuspendRequested(bool must_suspend) {
if (delegate_)
delegate_->PlayerGone(delegate_id_);
- render_frame_suspended_ = true;
-#endif
+ if (frame_deliverer_) {
+ compositor_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&FrameDeliverer::SetRenderFrameSuspended,
+ base::Unretained(frame_deliverer_.get()), true));
+ }
+#endif // defined(OS_ANDROID)
return true;
}
@@ -482,50 +594,26 @@ bool WebMediaPlayerMS::copyVideoTextureToPlatformTexture(
premultiply_alpha, flip_y);
}
-void WebMediaPlayerMS::OnFrameAvailable(
- const scoped_refptr<media::VideoFrame>& frame) {
- DVLOG(3) << __func__;
+void WebMediaPlayerMS::OnFirstFrameReceived(media::VideoRotation video_rotation,
+ bool is_opaque) {
+ DVLOG(1) << __func__;
DCHECK(thread_checker_.CalledOnValidThread());
+ video_rotation_ = video_rotation;
+ SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
+ SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
- if (render_frame_suspended_)
- return;
-
- base::TimeTicks render_time;
- if (frame->metadata()->GetTimeTicks(media::VideoFrameMetadata::REFERENCE_TIME,
- &render_time)) {
- TRACE_EVENT1("webrtc", "WebMediaPlayerMS::OnFrameAvailable",
- "Ideal Render Instant", render_time.ToInternalValue());
- } else {
- TRACE_EVENT0("webrtc", "WebMediaPlayerMS::OnFrameAvailable");
- }
- const bool is_opaque = media::IsOpaque(frame->format());
-
- if (!received_first_frame_) {
- received_first_frame_ = true;
- last_frame_opaque_ = is_opaque;
- SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
- SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
-
- if (video_frame_provider_.get()) {
- ignore_result(frame->metadata()->GetRotation(
- media::VideoFrameMetadata::ROTATION, &video_rotation_));
-
- video_weblayer_.reset(new cc_blink::WebLayerImpl(
- cc::VideoLayer::Create(compositor_.get(), video_rotation_)));
- video_weblayer_->layer()->SetContentsOpaque(is_opaque);
- video_weblayer_->SetContentsOpaqueIsFixed(true);
- get_client()->setWebLayer(video_weblayer_.get());
- }
- }
+ video_weblayer_.reset(new cc_blink::WebLayerImpl(
+ cc::VideoLayer::Create(compositor_.get(), video_rotation_)));
+ video_weblayer_->layer()->SetContentsOpaque(is_opaque);
+ video_weblayer_->SetContentsOpaqueIsFixed(true);
+ get_client()->setWebLayer(video_weblayer_.get());
+}
- // Only configure opacity on changes, since marking it as transparent is
- // expensive, see https://crbug.com/647886.
- if (video_weblayer_ && last_frame_opaque_ != is_opaque) {
- last_frame_opaque_ = is_opaque;
- video_weblayer_->layer()->SetContentsOpaque(is_opaque);
- }
+void WebMediaPlayerMS::OnOpacityChanged(bool is_opaque) {
+ DVLOG(1) << __func__;
+ DCHECK(thread_checker_.CalledOnValidThread());
- compositor_->EnqueueFrame(frame);
+ video_weblayer_->layer()->SetContentsOpaque(is_opaque);
}
void WebMediaPlayerMS::RepaintInternal() {

Powered by Google App Engine
This is Rietveld 408576698