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

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: Make |render_frame_suspended_| android specific. 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"
11 #include "content/public/common/content_features.h" 12 #include "content/public/common/content_features.h"
13 #include "content/public/renderer/render_thread.h"
12 #include "media/base/bind_to_current_loop.h" 14 #include "media/base/bind_to_current_loop.h"
13 #include "media/base/video_frame.h" 15 #include "media/base/video_frame.h"
14 #include "media/base/video_frame_metadata.h" 16 #include "media/base/video_frame_metadata.h"
15 #include "media/base/video_util.h" 17 #include "media/base/video_util.h"
16 #include "media/renderers/gpu_video_accelerator_factories.h" 18 #include "media/renderers/gpu_video_accelerator_factories.h"
19 #include "media/video/gpu_memory_buffer_video_frame_pool.h"
17 20
18 const int kMinFrameSize = 2; 21 const int kMinFrameSize = 2;
19 22
20 namespace content { 23 namespace content {
21 24
25 // FrameDelivererOnCompositor is responsible for delivering frames received on
26 // OnVideoFrame() to |repaint_cb_| on compositor thread.
27 //
28 // It is created on main thread, but methods should be called and class should
29 // be destructed on compositor thread.
30 class MediaStreamVideoRendererSink::FrameDelivererOnCompositor {
31 public:
32 FrameDelivererOnCompositor(
33 const RepaintCB repaint_cb,
34 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
35 const scoped_refptr<base::TaskRunner>& worker_task_runner,
36 media::GpuVideoAcceleratorFactories* gpu_factories)
37 : repaint_cb_(repaint_cb),
38 state_(STOPPED),
39 frame_size_(kMinFrameSize, kMinFrameSize),
40 media_task_runner_(media_task_runner),
41 weak_factory_for_compositor_(this) {
42 compositor_thread_checker_.DetachFromThread();
43 if (gpu_factories &&
44 gpu_factories->ShouldUseGpuMemoryBuffersForVideoFrames() &&
45 base::FeatureList::IsEnabled(
46 features::kWebRtcUseGpuMemoryBufferVideoFrames)) {
47 gpu_memory_buffer_pool_.reset(new media::GpuMemoryBufferVideoFramePool(
48 media_task_runner, worker_task_runner, gpu_factories));
49 }
50 }
51 ~FrameDelivererOnCompositor() {
52 DCHECK(compositor_thread_checker_.CalledOnValidThread());
53
54 if (gpu_memory_buffer_pool_) {
55 media_task_runner_->DeleteSoon(FROM_HERE,
56 gpu_memory_buffer_pool_.release());
57 }
58 }
59
60 void OnVideoFrame(const scoped_refptr<media::VideoFrame>& frame,
61 base::TimeTicks current_time) {
62 DCHECK(compositor_thread_checker_.CalledOnValidThread());
63 DCHECK(frame);
64
65 if (state_ != STARTED)
66 return;
67
68 if (!gpu_memory_buffer_pool_) {
69 FrameReady(frame);
70 return;
71 }
72 // |gpu_memory_buffer_pool_| deletion is going to be posted to
73 // |media_task_runner_|. base::Unretained() usage is fine since
74 // |gpu_memory_buffer_pool_| outlives the task.
75 media_task_runner_->PostTask(
76 FROM_HERE,
77 base::Bind(
78 &media::GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame,
79 base::Unretained(gpu_memory_buffer_pool_.get()), frame,
80 media::BindToCurrentLoop(base::Bind(
81 &FrameDelivererOnCompositor::FrameReady, GetWeakPtr()))));
82 }
83
84 void FrameReady(const scoped_refptr<media::VideoFrame>& frame) {
85 DCHECK(compositor_thread_checker_.CalledOnValidThread());
86 DCHECK(frame);
87
88 frame_size_ = frame->natural_size();
89 TRACE_EVENT_INSTANT1(
90 "webrtc",
91 "MediaStreamVideoRendererSink::FrameDelivererOnCompositor::FrameReady",
92 TRACE_EVENT_SCOPE_THREAD, "timestamp",
93 frame->timestamp().InMilliseconds());
94 repaint_cb_.Run(frame);
95 }
96
97 void RenderSignalingFrame() {
98 DCHECK(compositor_thread_checker_.CalledOnValidThread());
99 // This is necessary to make sure audio can play if the video tag src is
100 // a MediaStream video track that has been rejected or ended.
101 // It also ensure that the renderer don't hold a reference to a real video
102 // frame if no more frames are provided. This is since there might be a
103 // finite number of available buffers. E.g, video that
104 // originates from a video camera.
105 scoped_refptr<media::VideoFrame> video_frame =
106 media::VideoFrame::CreateBlackFrame(
107 (state_ == STOPPED) ? gfx::Size(kMinFrameSize, kMinFrameSize)
108 : frame_size_);
109 video_frame->metadata()->SetBoolean(
110 media::VideoFrameMetadata::END_OF_STREAM, true);
111 video_frame->metadata()->SetTimeTicks(
112 media::VideoFrameMetadata::REFERENCE_TIME, base::TimeTicks::Now());
113 FrameReady(video_frame);
114 }
115
116 void Start() {
117 DCHECK(compositor_thread_checker_.CalledOnValidThread());
118 DCHECK_EQ(state_, STOPPED);
119 state_ = STARTED;
120 }
121
122 void Stop() {
123 DCHECK(compositor_thread_checker_.CalledOnValidThread());
124 DCHECK(state_ == STARTED || state_ == PAUSED);
125 state_ = STOPPED;
126 }
127
128 void Resume() {
129 DCHECK(compositor_thread_checker_.CalledOnValidThread());
130 if (state_ == PAUSED)
131 state_ = STARTED;
132 }
133
134 void Pause() {
135 DCHECK(compositor_thread_checker_.CalledOnValidThread());
136 if (state_ == STARTED)
137 state_ = PAUSED;
138 }
139
140 base::WeakPtr<FrameDelivererOnCompositor> GetWeakPtr() {
141 return weak_factory_for_compositor_.GetWeakPtr();
142 }
143
144 private:
145 friend class MediaStreamVideoRendererSink;
146
147 void SetGpuMemoryBufferVideoForTesting(
148 media::GpuMemoryBufferVideoFramePool* gpu_memory_buffer_pool) {
149 DCHECK(compositor_thread_checker_.CalledOnValidThread());
150 gpu_memory_buffer_pool_.reset(gpu_memory_buffer_pool);
151 }
152
153 const RepaintCB repaint_cb_;
154 State state_;
155 gfx::Size frame_size_;
156
157 // Pool of GpuMemoryBuffers and resources used to create hardware frames.
158 std::unique_ptr<media::GpuMemoryBufferVideoFramePool> gpu_memory_buffer_pool_;
159 const scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
160
161 // Used for DCHECKs to ensure method calls executed in the correct thread.
perkj_chrome 2016/11/09 15:27:13 s/ calls are executed ... on the correct
emircan 2016/11/11 22:27:19 Done.
162 base::ThreadChecker compositor_thread_checker_;
163
164 base::WeakPtrFactory<FrameDelivererOnCompositor> weak_factory_for_compositor_;
165
166 DISALLOW_COPY_AND_ASSIGN(FrameDelivererOnCompositor);
167 };
168
169 // FrameReceiverOnIO is responsible for trampolining frames from IO thread to
170 // compositor thread by posting a task on |deliverer_|'s OnFrame() method.
171 //
172 // It is created on main thread, but methods should be called and class should
173 // be destructed on IO thread.
174 class MediaStreamVideoRendererSink::FrameReceiverOnIO {
qiangchen 2016/11/09 23:23:48 Is it possible to remove this class? I mean just i
emircan 2016/11/11 22:27:19 I think that would make the ownership and threadin
qiangchen 2016/11/15 00:04:53 Acknowledged.
175 public:
176 FrameReceiverOnIO(
177 const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner,
178 const base::WeakPtr<FrameDelivererOnCompositor>& deliverer)
179 : compositor_task_runner_(compositor_task_runner),
180 deliverer_(deliverer),
181 weak_factory_for_io_(this) {
182 io_thread_checker_.DetachFromThread();
183 }
184 ~FrameReceiverOnIO() { DCHECK(io_thread_checker_.CalledOnValidThread()); }
185
186 void OnVideoFrame(const scoped_refptr<media::VideoFrame>& frame,
187 base::TimeTicks current_time) {
188 DCHECK(io_thread_checker_.CalledOnValidThread());
189 compositor_task_runner_->PostTask(
190 FROM_HERE, base::Bind(&MediaStreamVideoRendererSink::
191 FrameDelivererOnCompositor::OnVideoFrame,
192 deliverer_, frame, current_time));
193 }
194
195 base::WeakPtr<FrameReceiverOnIO> GetWeakPtr() {
196 return weak_factory_for_io_.GetWeakPtr();
197 }
198
199 private:
200 const scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
201 const base::WeakPtr<FrameDelivererOnCompositor> deliverer_;
202
203 // Used for DCHECKs to ensure method calls executed in the correct thread.
204 base::ThreadChecker io_thread_checker_;
205
206 base::WeakPtrFactory<FrameReceiverOnIO> weak_factory_for_io_;
207
208 DISALLOW_COPY_AND_ASSIGN(FrameReceiverOnIO);
209 };
210
22 MediaStreamVideoRendererSink::MediaStreamVideoRendererSink( 211 MediaStreamVideoRendererSink::MediaStreamVideoRendererSink(
23 const blink::WebMediaStreamTrack& video_track, 212 const blink::WebMediaStreamTrack& video_track,
24 const base::Closure& error_cb, 213 const base::Closure& error_cb,
25 const RepaintCB& repaint_cb, 214 const RepaintCB& repaint_cb,
215 const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner,
26 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, 216 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
27 const scoped_refptr<base::TaskRunner>& worker_task_runner, 217 const scoped_refptr<base::TaskRunner>& worker_task_runner,
28 media::GpuVideoAcceleratorFactories* gpu_factories) 218 media::GpuVideoAcceleratorFactories* gpu_factories)
29 : error_cb_(error_cb), 219 : 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), 220 video_track_(video_track),
35 media_task_runner_(media_task_runner), 221 frame_deliverer_(
36 weak_factory_(this) { 222 new MediaStreamVideoRendererSink::FrameDelivererOnCompositor(
37 if (gpu_factories && 223 repaint_cb,
38 gpu_factories->ShouldUseGpuMemoryBuffersForVideoFrames() && 224 media_task_runner,
39 base::FeatureList::IsEnabled( 225 worker_task_runner,
40 features::kWebRtcUseGpuMemoryBufferVideoFrames)) { 226 gpu_factories)),
41 gpu_memory_buffer_pool_.reset(new media::GpuMemoryBufferVideoFramePool( 227 compositor_task_runner_(compositor_task_runner) {}
42 media_task_runner, worker_task_runner, gpu_factories));
43 }
44 }
45 228
46 MediaStreamVideoRendererSink::~MediaStreamVideoRendererSink() { 229 MediaStreamVideoRendererSink::~MediaStreamVideoRendererSink() {
47 if (gpu_memory_buffer_pool_) { 230 compositor_task_runner_->DeleteSoon(FROM_HERE, frame_deliverer_.release());
48 media_task_runner_->DeleteSoon(FROM_HERE,
49 gpu_memory_buffer_pool_.release());
50 }
51 } 231 }
52 232
53 void MediaStreamVideoRendererSink::Start() { 233 void MediaStreamVideoRendererSink::Start() {
54 DCHECK(task_runner_->BelongsToCurrentThread()); 234 DCHECK(main_thread_checker_.CalledOnValidThread());
55 DCHECK_EQ(state_, STOPPED); 235
56 236 compositor_task_runner_->PostTask(
237 FROM_HERE, base::Bind(&FrameDelivererOnCompositor::Start,
238 frame_deliverer_->GetWeakPtr()));
239
240 frame_receiver_.reset(new MediaStreamVideoRendererSink::FrameReceiverOnIO(
241 compositor_task_runner_, frame_deliverer_->GetWeakPtr()));
57 MediaStreamVideoSink::ConnectToTrack( 242 MediaStreamVideoSink::ConnectToTrack(
58 video_track_, media::BindToCurrentLoop( 243 video_track_, base::Bind(&FrameReceiverOnIO::OnVideoFrame,
59 base::Bind(&MediaStreamVideoRendererSink::OnVideoFrame, 244 frame_receiver_->GetWeakPtr()),
60 weak_factory_.GetWeakPtr())),
61 // Local display video rendering is considered a secure link. 245 // Local display video rendering is considered a secure link.
62 true); 246 true);
63 state_ = STARTED;
64 247
65 if (video_track_.source().getReadyState() == 248 if (video_track_.source().getReadyState() ==
66 blink::WebMediaStreamSource::ReadyStateEnded || 249 blink::WebMediaStreamSource::ReadyStateEnded ||
67 !video_track_.isEnabled()) { 250 !video_track_.isEnabled()) {
68 RenderSignalingFrame(); 251 compositor_task_runner_->PostTask(
252 FROM_HERE, base::Bind(&FrameDelivererOnCompositor::RenderSignalingFrame,
253 frame_deliverer_->GetWeakPtr()));
69 } 254 }
70 } 255 }
71 256
72 void MediaStreamVideoRendererSink::Stop() { 257 void MediaStreamVideoRendererSink::Stop() {
73 DCHECK(task_runner_->BelongsToCurrentThread()); 258 DCHECK(main_thread_checker_.CalledOnValidThread());
74 DCHECK(state_ == STARTED || state_ == PAUSED); 259
75 MediaStreamVideoSink::DisconnectFromTrack(); 260 MediaStreamVideoSink::DisconnectFromTrack();
76 weak_factory_.InvalidateWeakPtrs(); 261 if (frame_receiver_) {
77 state_ = STOPPED; 262 RenderThread* const render_thread = RenderThread::Get();
78 frame_size_.set_width(kMinFrameSize); 263 if (render_thread) {
79 frame_size_.set_height(kMinFrameSize); 264 render_thread->GetIOTaskRunner()->DeleteSoon(FROM_HERE,
265 frame_receiver_.release());
266 }
267 }
268 compositor_task_runner_->PostTask(
269 FROM_HERE, base::Bind(&FrameDelivererOnCompositor::Stop,
270 frame_deliverer_->GetWeakPtr()));
80 } 271 }
81 272
82 void MediaStreamVideoRendererSink::Resume() { 273 void MediaStreamVideoRendererSink::Resume() {
83 DCHECK(task_runner_->BelongsToCurrentThread()); 274 DCHECK(main_thread_checker_.CalledOnValidThread());
84 if (state_ == PAUSED) 275 compositor_task_runner_->PostTask(
85 state_ = STARTED; 276 FROM_HERE, base::Bind(&FrameDelivererOnCompositor::Resume,
277 frame_deliverer_->GetWeakPtr()));
86 } 278 }
87 279
88 void MediaStreamVideoRendererSink::Pause() { 280 void MediaStreamVideoRendererSink::Pause() {
89 DCHECK(task_runner_->BelongsToCurrentThread()); 281 DCHECK(main_thread_checker_.CalledOnValidThread());
90 if (state_ == STARTED) 282 compositor_task_runner_->PostTask(
91 state_ = PAUSED; 283 FROM_HERE, base::Bind(&FrameDelivererOnCompositor::Pause,
284 frame_deliverer_->GetWeakPtr()));
285 }
286
287 MediaStreamVideoRendererSink::State
288 MediaStreamVideoRendererSink::GetStateForTesting() {
289 DCHECK(main_thread_checker_.CalledOnValidThread());
290 return frame_deliverer_->state_;
291 }
292
293 void MediaStreamVideoRendererSink::OnVideoFrameForTesting(
perkj_chrome 2016/11/09 15:27:13 please remove. Is it possible to create a fake vid
emircan 2016/11/11 22:27:19 This is how test have been injecting the frames be
perkj_chrome 2016/11/14 15:19:55 thanks
294 const scoped_refptr<media::VideoFrame>& frame,
295 base::TimeTicks current_time) {
296 DCHECK(main_thread_checker_.CalledOnValidThread());
297 compositor_task_runner_->PostTask(
298 FROM_HERE,
299 base::Bind(&FrameDelivererOnCompositor::OnVideoFrame,
300 frame_deliverer_->GetWeakPtr(), frame, current_time));
92 } 301 }
93 302
94 void MediaStreamVideoRendererSink::SetGpuMemoryBufferVideoForTesting( 303 void MediaStreamVideoRendererSink::SetGpuMemoryBufferVideoForTesting(
95 media::GpuMemoryBufferVideoFramePool* gpu_memory_buffer_pool) { 304 media::GpuMemoryBufferVideoFramePool* gpu_memory_buffer_pool) {
96 gpu_memory_buffer_pool_.reset(gpu_memory_buffer_pool); 305 DCHECK(main_thread_checker_.CalledOnValidThread());
306 compositor_task_runner_->PostTask(
307 FROM_HERE,
308 base::Bind(&FrameDelivererOnCompositor::SetGpuMemoryBufferVideoForTesting,
309 frame_deliverer_->GetWeakPtr(), gpu_memory_buffer_pool));
97 } 310 }
98 311
99 void MediaStreamVideoRendererSink::OnReadyStateChanged( 312 void MediaStreamVideoRendererSink::OnReadyStateChanged(
100 blink::WebMediaStreamSource::ReadyState state) { 313 blink::WebMediaStreamSource::ReadyState state) {
101 DCHECK(task_runner_->BelongsToCurrentThread()); 314 DCHECK(main_thread_checker_.CalledOnValidThread());
102 if (state == blink::WebMediaStreamSource::ReadyStateEnded) 315 if (state == blink::WebMediaStreamSource::ReadyStateEnded) {
103 RenderSignalingFrame(); 316 compositor_task_runner_->PostTask(
104 } 317 FROM_HERE, base::Bind(&FrameDelivererOnCompositor::RenderSignalingFrame,
105 318 frame_deliverer_->GetWeakPtr()));
106 void MediaStreamVideoRendererSink::OnVideoFrame( 319 }
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 } 320 }
159 321
160 } // namespace content 322 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698