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

Side by Side Diff: content/renderer/media/media_stream_video_renderer_sink.cc

Issue 2472273002: Move passing of WebRTC rendering frames from main thread to compositor thread (Closed)
Patch Set: perkj@ 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/media/media_stream_video_renderer_sink.h" 5 #include "content/renderer/media/media_stream_video_renderer_sink.h"
6 6
7 #include "base/feature_list.h" 7 #include "base/feature_list.h"
8 #include "base/memory/weak_ptr.h"
8 #include "base/single_thread_task_runner.h" 9 #include "base/single_thread_task_runner.h"
9 #include "base/threading/thread_task_runner_handle.h" 10 #include "base/threading/thread_task_runner_handle.h"
10 #include "base/trace_event/trace_event.h" 11 #include "base/trace_event/trace_event.h"
12 #include "content/child/child_process.h"
11 #include "content/public/common/content_features.h" 13 #include "content/public/common/content_features.h"
14 #include "content/public/renderer/render_thread.h"
12 #include "media/base/bind_to_current_loop.h" 15 #include "media/base/bind_to_current_loop.h"
13 #include "media/base/video_frame.h" 16 #include "media/base/video_frame.h"
14 #include "media/base/video_frame_metadata.h" 17 #include "media/base/video_frame_metadata.h"
15 #include "media/base/video_util.h" 18 #include "media/base/video_util.h"
16 #include "media/renderers/gpu_video_accelerator_factories.h" 19 #include "media/renderers/gpu_video_accelerator_factories.h"
20 #include "media/video/gpu_memory_buffer_video_frame_pool.h"
17 21
18 const int kMinFrameSize = 2; 22 const int kMinFrameSize = 2;
19 23
20 namespace content { 24 namespace content {
21 25
26 // FrameDelivererOnCompositor is responsible for delivering frames received on
27 // OnVideoFrame() to |repaint_cb_| on compositor thread.
28 //
29 // It is created on main thread, but methods should be called and class should
30 // be destructed on compositor thread.
31 class MediaStreamVideoRendererSink::FrameDelivererOnCompositor {
DaleCurtis 2016/11/15 00:30:16 Generally we describe where a class runs by it's v
emircan 2016/11/15 19:54:01 Done.
32 public:
33 FrameDelivererOnCompositor(
34 const RepaintCB repaint_cb,
DaleCurtis 2016/11/15 00:30:15 const&
emircan 2016/11/15 19:54:01 Done.
35 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
DaleCurtis 2016/11/15 00:30:16 New classes should pass scoped_refptr by value.
emircan 2016/11/15 19:54:01 Done.
36 const scoped_refptr<base::TaskRunner>& worker_task_runner,
37 media::GpuVideoAcceleratorFactories* gpu_factories)
38 : repaint_cb_(repaint_cb),
39 state_(STOPPED),
40 frame_size_(kMinFrameSize, kMinFrameSize),
41 media_task_runner_(media_task_runner),
42 weak_factory_for_compositor_(this) {
DaleCurtis 2016/11/15 00:30:16 There's only one, so not really any reason to call
emircan 2016/11/15 19:54:01 Done.
43 compositor_thread_checker_.DetachFromThread();
44 if (gpu_factories &&
45 gpu_factories->ShouldUseGpuMemoryBuffersForVideoFrames() &&
46 base::FeatureList::IsEnabled(
47 features::kWebRtcUseGpuMemoryBufferVideoFrames)) {
48 gpu_memory_buffer_pool_.reset(new media::GpuMemoryBufferVideoFramePool(
49 media_task_runner, worker_task_runner, gpu_factories));
50 }
51 }
52 ~FrameDelivererOnCompositor() {
DaleCurtis 2016/11/15 00:30:16 Add blank line.
emircan 2016/11/15 19:54:01 Done.
53 DCHECK(compositor_thread_checker_.CalledOnValidThread());
54
55 if (gpu_memory_buffer_pool_) {
56 media_task_runner_->DeleteSoon(FROM_HERE,
57 gpu_memory_buffer_pool_.release());
58 }
59 }
60
61 void OnVideoFrame(const scoped_refptr<media::VideoFrame>& frame,
62 base::TimeTicks /*current_time*/) {
63 DCHECK(compositor_thread_checker_.CalledOnValidThread());
64 DCHECK(frame);
65 TRACE_EVENT_INSTANT1("webrtc",
66 "MediaStreamVideoRendererSink::"
67 "FrameDelivererOnCompositor::OnVideoFrame",
68 TRACE_EVENT_SCOPE_THREAD, "timestamp",
69 frame->timestamp().InMilliseconds());
70
71 if (state_ != STARTED)
72 return;
73 frame_size_ = frame->natural_size();
DaleCurtis 2016/11/15 00:30:16 Isn't this going to get out of sync with what's ac
emircan 2016/11/15 19:54:01 Moving it to after copy.
74
75 if (!gpu_memory_buffer_pool_) {
76 repaint_cb_.Run(frame);
77 return;
78 }
79
80 // |gpu_memory_buffer_pool_| deletion is going to be posted to
81 // |media_task_runner_|. base::Unretained() usage is fine since
82 // |gpu_memory_buffer_pool_| outlives the task.
83 media_task_runner_->PostTask(
84 FROM_HERE,
85 base::Bind(
86 &media::GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame,
87 base::Unretained(gpu_memory_buffer_pool_.get()), frame,
88 media::BindToCurrentLoop(base::Bind(
89 &FrameDelivererOnCompositor::FrameReady, GetWeakPtr()))));
90 }
91
92 void FrameReady(const scoped_refptr<media::VideoFrame>& frame) {
DaleCurtis 2016/11/15 00:30:16 Sequeneces of Start/Stop/Start are going to result
emircan 2016/11/15 19:54:01 I would say that is OK and consistent, considering
DaleCurtis 2016/11/15 20:29:03 Seems fine, but defer to qiangchen@.
93 DCHECK(compositor_thread_checker_.CalledOnValidThread());
94 DCHECK(frame);
95 TRACE_EVENT_INSTANT1(
96 "webrtc",
97 "MediaStreamVideoRendererSink::FrameDelivererOnCompositor::FrameReady",
98 TRACE_EVENT_SCOPE_THREAD, "timestamp",
99 frame->timestamp().InMilliseconds());
100
101 if (state_ != STARTED)
102 return;
103 repaint_cb_.Run(frame);
104 }
105
106 void RenderSignalingFrame() {
DaleCurtis 2016/11/15 00:30:16 RenderEndOfStream?
emircan 2016/11/15 19:54:01 Done.
107 DCHECK(compositor_thread_checker_.CalledOnValidThread());
108 // This is necessary to make sure audio can play if the video tag src is a
109 // MediaStream video track that has been rejected or ended. It also ensure
110 // that the renderer doesn't hold a reference to a real video frame if no
111 // more frames are provided. This is since there might be a finite number
112 // of available buffers. E.g, video that originates from a video camera.
113 scoped_refptr<media::VideoFrame> video_frame =
114 media::VideoFrame::CreateBlackFrame(
115 (state_ == STOPPED) ? gfx::Size(kMinFrameSize, kMinFrameSize)
DaleCurtis 2016/11/15 00:30:16 No unnecessary parens.
emircan 2016/11/15 19:54:01 Done.
116 : frame_size_);
117 video_frame->metadata()->SetBoolean(
118 media::VideoFrameMetadata::END_OF_STREAM, true);
119 video_frame->metadata()->SetTimeTicks(
120 media::VideoFrameMetadata::REFERENCE_TIME, base::TimeTicks::Now());
121 OnVideoFrame(video_frame, base::TimeTicks());
122 }
123
124 void Start() {
125 DCHECK(compositor_thread_checker_.CalledOnValidThread());
126 DCHECK_EQ(state_, STOPPED);
127 state_ = STARTED;
128 }
129
130 void Stop() {
131 DCHECK(compositor_thread_checker_.CalledOnValidThread());
132 DCHECK(state_ == STARTED || state_ == PAUSED);
DaleCurtis 2016/11/15 00:30:16 for multiple DCHECKs() like this add a <<state_ t
emircan 2016/11/15 19:54:01 Done.
133 state_ = STOPPED;
134 }
135
136 void Resume() {
137 DCHECK(compositor_thread_checker_.CalledOnValidThread());
138 if (state_ == PAUSED)
DaleCurtis 2016/11/15 00:30:15 Instead of conditionals can these be DCHECKs() ?
emircan 2016/11/15 19:54:01 I am not sure. Running "play(); play();" on JS wou
DaleCurtis 2016/11/15 20:29:03 Does calling play() play() not already have an exi
emircan 2016/11/16 00:52:24 It actually does, "load(); play();" causes the pro
139 state_ = STARTED;
140 }
141
142 void Pause() {
143 DCHECK(compositor_thread_checker_.CalledOnValidThread());
144 if (state_ == STARTED)
DaleCurtis 2016/11/15 00:30:16 Ditto?
emircan 2016/11/15 19:54:01 Same as above, "pause(); pause();" would crash if
145 state_ = PAUSED;
146 }
147
148 base::WeakPtr<FrameDelivererOnCompositor> GetWeakPtr() {
DaleCurtis 2016/11/15 00:30:15 This is a bit confusingly named since we also have
emircan 2016/11/15 19:54:01 I switched to AsWeakPtr().
149 return weak_factory_for_compositor_.GetWeakPtr();
150 }
151
152 private:
153 friend class MediaStreamVideoRendererSink;
154
155 void SetGpuMemoryBufferVideoForTesting(
156 media::GpuMemoryBufferVideoFramePool* gpu_memory_buffer_pool) {
157 DCHECK(compositor_thread_checker_.CalledOnValidThread());
158 gpu_memory_buffer_pool_.reset(gpu_memory_buffer_pool);
159 }
160
161 const RepaintCB repaint_cb_;
162 State state_;
163 gfx::Size frame_size_;
164
165 // Pool of GpuMemoryBuffers and resources used to create hardware frames.
166 std::unique_ptr<media::GpuMemoryBufferVideoFramePool> gpu_memory_buffer_pool_;
167 const scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
168
169 // Used for DCHECKs to ensure method calls are executed on the correct thread.
170 base::ThreadChecker compositor_thread_checker_;
171
172 base::WeakPtrFactory<FrameDelivererOnCompositor> weak_factory_for_compositor_;
173
174 DISALLOW_COPY_AND_ASSIGN(FrameDelivererOnCompositor);
175 };
176
177 // FrameReceiverOnIO is responsible for trampolining frames from IO thread to
DaleCurtis 2016/11/15 00:30:16 Ditto on naming.
emircan 2016/11/15 19:54:01 Done.
178 // the compositor thread by posting a task on |deliverer_|'s OnFrame() method.
179 //
180 // It is created on main thread, but methods should be called and class should
181 // be destructed on the IO thread.
182 class MediaStreamVideoRendererSink::FrameReceiverOnIO {
183 public:
184 FrameReceiverOnIO(
185 const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner,
186 const base::WeakPtr<FrameDelivererOnCompositor>& deliverer)
187 : compositor_task_runner_(compositor_task_runner),
188 deliverer_(deliverer),
189 weak_factory_for_io_(this) {
DaleCurtis 2016/11/15 00:30:16 Ditto on SupportsWeakPtr.
emircan 2016/11/15 19:54:01 Done.
190 io_thread_checker_.DetachFromThread();
191 }
192 ~FrameReceiverOnIO() { DCHECK(io_thread_checker_.CalledOnValidThread()); }
193
194 void OnVideoFrame(const scoped_refptr<media::VideoFrame>& frame,
195 base::TimeTicks current_time) {
196 DCHECK(io_thread_checker_.CalledOnValidThread());
197 compositor_task_runner_->PostTask(
198 FROM_HERE, base::Bind(&MediaStreamVideoRendererSink::
199 FrameDelivererOnCompositor::OnVideoFrame,
200 deliverer_, frame, current_time));
201 }
202
203 base::WeakPtr<FrameReceiverOnIO> GetWeakPtr() {
204 return weak_factory_for_io_.GetWeakPtr();
205 }
206
207 private:
208 const scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
209 const base::WeakPtr<FrameDelivererOnCompositor> deliverer_;
210
211 // Used for DCHECKs to ensure method calls executed in the correct thread.
212 base::ThreadChecker io_thread_checker_;
213
214 base::WeakPtrFactory<FrameReceiverOnIO> weak_factory_for_io_;
215
216 DISALLOW_COPY_AND_ASSIGN(FrameReceiverOnIO);
217 };
218
22 MediaStreamVideoRendererSink::MediaStreamVideoRendererSink( 219 MediaStreamVideoRendererSink::MediaStreamVideoRendererSink(
23 const blink::WebMediaStreamTrack& video_track, 220 const blink::WebMediaStreamTrack& video_track,
24 const base::Closure& error_cb, 221 const base::Closure& error_cb,
25 const RepaintCB& repaint_cb, 222 const RepaintCB& repaint_cb,
223 const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner,
26 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, 224 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
27 const scoped_refptr<base::TaskRunner>& worker_task_runner, 225 const scoped_refptr<base::TaskRunner>& worker_task_runner,
28 media::GpuVideoAcceleratorFactories* gpu_factories) 226 media::GpuVideoAcceleratorFactories* gpu_factories)
29 : error_cb_(error_cb), 227 : error_cb_(error_cb),
30 repaint_cb_(repaint_cb),
31 task_runner_(base::ThreadTaskRunnerHandle::Get()),
32 state_(STOPPED),
33 frame_size_(kMinFrameSize, kMinFrameSize),
34 video_track_(video_track), 228 video_track_(video_track),
35 media_task_runner_(media_task_runner), 229 frame_deliverer_(
36 weak_factory_(this) { 230 new MediaStreamVideoRendererSink::FrameDelivererOnCompositor(
37 if (gpu_factories && 231 repaint_cb,
38 gpu_factories->ShouldUseGpuMemoryBuffersForVideoFrames() && 232 media_task_runner,
39 base::FeatureList::IsEnabled( 233 worker_task_runner,
40 features::kWebRtcUseGpuMemoryBufferVideoFrames)) { 234 gpu_factories)),
41 gpu_memory_buffer_pool_.reset(new media::GpuMemoryBufferVideoFramePool( 235 compositor_task_runner_(compositor_task_runner) {}
42 media_task_runner, worker_task_runner, gpu_factories));
43 }
44 }
45 236
46 MediaStreamVideoRendererSink::~MediaStreamVideoRendererSink() { 237 MediaStreamVideoRendererSink::~MediaStreamVideoRendererSink() {
47 if (gpu_memory_buffer_pool_) { 238 compositor_task_runner_->DeleteSoon(FROM_HERE, frame_deliverer_.release());
48 media_task_runner_->DeleteSoon(FROM_HERE,
49 gpu_memory_buffer_pool_.release());
50 }
51 } 239 }
52 240
53 void MediaStreamVideoRendererSink::Start() { 241 void MediaStreamVideoRendererSink::Start() {
54 DCHECK(task_runner_->BelongsToCurrentThread()); 242 DCHECK(main_thread_checker_.CalledOnValidThread());
55 DCHECK_EQ(state_, STOPPED); 243
56 244 compositor_task_runner_->PostTask(
245 FROM_HERE, base::Bind(&FrameDelivererOnCompositor::Start,
246 frame_deliverer_->GetWeakPtr()));
DaleCurtis 2016/11/15 00:30:16 You can't vend WeakPtr's for the compositor from t
emircan 2016/11/15 19:54:01 I am confused by what you said. WeakPtrs must be d
DaleCurtis 2016/11/15 20:29:03 If you create the weak ptr on a different thread t
247
248 frame_receiver_.reset(new MediaStreamVideoRendererSink::FrameReceiverOnIO(
249 compositor_task_runner_, frame_deliverer_->GetWeakPtr()));
57 MediaStreamVideoSink::ConnectToTrack( 250 MediaStreamVideoSink::ConnectToTrack(
58 video_track_, media::BindToCurrentLoop( 251 video_track_, base::Bind(&FrameReceiverOnIO::OnVideoFrame,
59 base::Bind(&MediaStreamVideoRendererSink::OnVideoFrame, 252 frame_receiver_->GetWeakPtr()),
60 weak_factory_.GetWeakPtr())),
61 // Local display video rendering is considered a secure link. 253 // Local display video rendering is considered a secure link.
62 true); 254 true);
63 state_ = STARTED;
64 255
65 if (video_track_.source().getReadyState() == 256 if (video_track_.source().getReadyState() ==
66 blink::WebMediaStreamSource::ReadyStateEnded || 257 blink::WebMediaStreamSource::ReadyStateEnded ||
67 !video_track_.isEnabled()) { 258 !video_track_.isEnabled()) {
68 RenderSignalingFrame(); 259 compositor_task_runner_->PostTask(
260 FROM_HERE, base::Bind(&FrameDelivererOnCompositor::RenderSignalingFrame,
261 frame_deliverer_->GetWeakPtr()));
69 } 262 }
70 } 263 }
71 264
72 void MediaStreamVideoRendererSink::Stop() { 265 void MediaStreamVideoRendererSink::Stop() {
73 DCHECK(task_runner_->BelongsToCurrentThread()); 266 DCHECK(main_thread_checker_.CalledOnValidThread());
74 DCHECK(state_ == STARTED || state_ == PAUSED); 267
75 MediaStreamVideoSink::DisconnectFromTrack(); 268 MediaStreamVideoSink::DisconnectFromTrack();
76 weak_factory_.InvalidateWeakPtrs(); 269 if (frame_receiver_) {
77 state_ = STOPPED; 270 ChildProcess::current()->io_task_runner()->DeleteSoon(
78 frame_size_.set_width(kMinFrameSize); 271 FROM_HERE, frame_receiver_.release());
79 frame_size_.set_height(kMinFrameSize); 272 }
273 compositor_task_runner_->PostTask(
274 FROM_HERE, base::Bind(&FrameDelivererOnCompositor::Stop,
275 frame_deliverer_->GetWeakPtr()));
80 } 276 }
81 277
82 void MediaStreamVideoRendererSink::Resume() { 278 void MediaStreamVideoRendererSink::Resume() {
83 DCHECK(task_runner_->BelongsToCurrentThread()); 279 DCHECK(main_thread_checker_.CalledOnValidThread());
84 if (state_ == PAUSED) 280 compositor_task_runner_->PostTask(
85 state_ = STARTED; 281 FROM_HERE, base::Bind(&FrameDelivererOnCompositor::Resume,
282 frame_deliverer_->GetWeakPtr()));
86 } 283 }
87 284
88 void MediaStreamVideoRendererSink::Pause() { 285 void MediaStreamVideoRendererSink::Pause() {
89 DCHECK(task_runner_->BelongsToCurrentThread()); 286 DCHECK(main_thread_checker_.CalledOnValidThread());
90 if (state_ == STARTED) 287 compositor_task_runner_->PostTask(
91 state_ = PAUSED; 288 FROM_HERE, base::Bind(&FrameDelivererOnCompositor::Pause,
289 frame_deliverer_->GetWeakPtr()));
290 }
291
292 MediaStreamVideoRendererSink::State
293 MediaStreamVideoRendererSink::GetStateForTesting() {
294 DCHECK(main_thread_checker_.CalledOnValidThread());
295 return frame_deliverer_->state_;
92 } 296 }
93 297
94 void MediaStreamVideoRendererSink::SetGpuMemoryBufferVideoForTesting( 298 void MediaStreamVideoRendererSink::SetGpuMemoryBufferVideoForTesting(
95 media::GpuMemoryBufferVideoFramePool* gpu_memory_buffer_pool) { 299 media::GpuMemoryBufferVideoFramePool* gpu_memory_buffer_pool) {
96 gpu_memory_buffer_pool_.reset(gpu_memory_buffer_pool); 300 DCHECK(main_thread_checker_.CalledOnValidThread());
301 compositor_task_runner_->PostTask(
302 FROM_HERE,
303 base::Bind(&FrameDelivererOnCompositor::SetGpuMemoryBufferVideoForTesting,
304 frame_deliverer_->GetWeakPtr(), gpu_memory_buffer_pool));
97 } 305 }
98 306
99 void MediaStreamVideoRendererSink::OnReadyStateChanged( 307 void MediaStreamVideoRendererSink::OnReadyStateChanged(
100 blink::WebMediaStreamSource::ReadyState state) { 308 blink::WebMediaStreamSource::ReadyState state) {
101 DCHECK(task_runner_->BelongsToCurrentThread()); 309 DCHECK(main_thread_checker_.CalledOnValidThread());
102 if (state == blink::WebMediaStreamSource::ReadyStateEnded) 310 if (state == blink::WebMediaStreamSource::ReadyStateEnded) {
103 RenderSignalingFrame(); 311 compositor_task_runner_->PostTask(
104 } 312 FROM_HERE, base::Bind(&FrameDelivererOnCompositor::RenderSignalingFrame,
105 313 frame_deliverer_->GetWeakPtr()));
106 void MediaStreamVideoRendererSink::OnVideoFrame( 314 }
107 const scoped_refptr<media::VideoFrame>& frame,
108 base::TimeTicks estimated_capture_time) {
109 DCHECK(task_runner_->BelongsToCurrentThread());
110 DCHECK(frame);
111 if (state_ != STARTED)
112 return;
113
114 if (!gpu_memory_buffer_pool_) {
115 FrameReady(frame);
116 return;
117 }
118
119 // |gpu_memory_buffer_pool_| deletion is going to be posted to
120 // |media_task_runner_|. base::Unretained() usage is fine since
121 // |gpu_memory_buffer_pool_| outlives the task.
122 media_task_runner_->PostTask(
123 FROM_HERE,
124 base::Bind(
125 &media::GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame,
126 base::Unretained(gpu_memory_buffer_pool_.get()), frame,
127 media::BindToCurrentLoop(
128 base::Bind(&MediaStreamVideoRendererSink::FrameReady,
129 weak_factory_.GetWeakPtr()))));
130 }
131
132 void MediaStreamVideoRendererSink::FrameReady(
133 const scoped_refptr<media::VideoFrame>& frame) {
134 DCHECK(task_runner_->BelongsToCurrentThread());
135 DCHECK(frame);
136
137 frame_size_ = frame->natural_size();
138 TRACE_EVENT_INSTANT1("media_stream_video_renderer_sink", "FrameReady",
139 TRACE_EVENT_SCOPE_THREAD, "timestamp",
140 frame->timestamp().InMilliseconds());
141 repaint_cb_.Run(frame);
142 }
143
144 void MediaStreamVideoRendererSink::RenderSignalingFrame() {
145 // This is necessary to make sure audio can play if the video tag src is
146 // a MediaStream video track that has been rejected or ended.
147 // It also ensure that the renderer don't hold a reference to a real video
148 // frame if no more frames are provided. This is since there might be a
149 // finite number of available buffers. E.g, video that
150 // originates from a video camera.
151 scoped_refptr<media::VideoFrame> video_frame =
152 media::VideoFrame::CreateBlackFrame(frame_size_);
153 video_frame->metadata()->SetBoolean(media::VideoFrameMetadata::END_OF_STREAM,
154 true);
155 video_frame->metadata()->SetTimeTicks(
156 media::VideoFrameMetadata::REFERENCE_TIME, base::TimeTicks::Now());
157 OnVideoFrame(video_frame, base::TimeTicks());
158 } 315 }
159 316
160 } // namespace content 317 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698