OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/webmediaplayer_ms.h" | 5 #include "content/renderer/media/webmediaplayer_ms.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback.h" | 10 #include "base/callback.h" |
11 #include "base/message_loop/message_loop.h" | 11 #include "base/message_loop/message_loop.h" |
12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
13 #include "cc/blink/context_provider_web_context.h" | 13 #include "cc/blink/context_provider_web_context.h" |
14 #include "cc/blink/web_layer_impl.h" | 14 #include "cc/blink/web_layer_impl.h" |
| 15 #include "cc/layers/video_frame_provider_client_impl.h" |
15 #include "cc/layers/video_layer.h" | 16 #include "cc/layers/video_layer.h" |
16 #include "content/public/renderer/media_stream_audio_renderer.h" | 17 #include "content/public/renderer/media_stream_audio_renderer.h" |
17 #include "content/public/renderer/media_stream_renderer_factory.h" | 18 #include "content/public/renderer/media_stream_renderer_factory.h" |
18 #include "content/public/renderer/render_view.h" | 19 #include "content/public/renderer/render_view.h" |
19 #include "content/public/renderer/video_frame_provider.h" | 20 #include "content/public/renderer/video_frame_provider.h" |
20 #include "content/renderer/render_frame_impl.h" | 21 #include "content/renderer/render_frame_impl.h" |
21 #include "content/renderer/render_thread_impl.h" | 22 #include "content/renderer/render_thread_impl.h" |
22 #include "gpu/blink/webgraphicscontext3d_impl.h" | 23 #include "gpu/blink/webgraphicscontext3d_impl.h" |
23 #include "media/base/media_log.h" | 24 #include "media/base/media_log.h" |
24 #include "media/base/video_frame.h" | 25 #include "media/base/video_frame.h" |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 return new_frame; | 86 return new_frame; |
86 } | 87 } |
87 | 88 |
88 } // anonymous namespace | 89 } // anonymous namespace |
89 | 90 |
90 WebMediaPlayerMS::WebMediaPlayerMS( | 91 WebMediaPlayerMS::WebMediaPlayerMS( |
91 blink::WebFrame* frame, | 92 blink::WebFrame* frame, |
92 blink::WebMediaPlayerClient* client, | 93 blink::WebMediaPlayerClient* client, |
93 base::WeakPtr<media::WebMediaPlayerDelegate> delegate, | 94 base::WeakPtr<media::WebMediaPlayerDelegate> delegate, |
94 media::MediaLog* media_log, | 95 media::MediaLog* media_log, |
95 scoped_ptr<MediaStreamRendererFactory> factory) | 96 scoped_ptr<MediaStreamRendererFactory> factory, |
| 97 const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner) |
96 : frame_(frame), | 98 : frame_(frame), |
97 network_state_(WebMediaPlayer::NetworkStateEmpty), | 99 network_state_(WebMediaPlayer::NetworkStateEmpty), |
98 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), | 100 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), |
99 buffered_(static_cast<size_t>(0)), | 101 buffered_(static_cast<size_t>(0)), |
100 volume_(1.0f), | 102 volume_(1.0f), |
101 client_(client), | 103 client_(client), |
102 delegate_(delegate), | 104 delegate_(delegate), |
103 paused_(true), | 105 paused_(true), |
104 current_frame_used_(false), | |
105 video_frame_provider_client_(NULL), | |
106 received_first_frame_(false), | 106 received_first_frame_(false), |
107 total_frame_count_(0), | |
108 dropped_frame_count_(0), | |
109 media_log_(media_log), | 107 media_log_(media_log), |
110 renderer_factory_(factory.Pass()) { | 108 renderer_factory_(factory.Pass()), |
| 109 compositor_(new Compositor(compositor_task_runner)), |
| 110 compositor_task_runner_(compositor_task_runner) { |
111 DVLOG(1) << "WebMediaPlayerMS::ctor"; | 111 DVLOG(1) << "WebMediaPlayerMS::ctor"; |
112 media_log_->AddEvent( | 112 media_log_->AddEvent( |
113 media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_CREATED)); | 113 media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_CREATED)); |
114 } | 114 } |
115 | 115 |
116 WebMediaPlayerMS::~WebMediaPlayerMS() { | 116 WebMediaPlayerMS::~WebMediaPlayerMS() { |
117 DVLOG(1) << "WebMediaPlayerMS::dtor"; | 117 DVLOG(1) << "WebMediaPlayerMS::dtor"; |
118 DCHECK(thread_checker_.CalledOnValidThread()); | 118 DCHECK(thread_checker_.CalledOnValidThread()); |
119 | 119 |
120 SetVideoFrameProviderClient(NULL); | 120 compositor_task_runner_->DeleteSoon(FROM_HERE, compositor_.release()); |
| 121 |
121 GetClient()->setWebLayer(NULL); | 122 GetClient()->setWebLayer(NULL); |
122 | 123 |
123 if (video_frame_provider_.get()) | 124 if (video_frame_provider_.get()) |
124 video_frame_provider_->Stop(); | 125 video_frame_provider_->Stop(); |
125 | 126 |
126 if (audio_renderer_.get()) | 127 if (audio_renderer_.get()) |
127 audio_renderer_->Stop(); | 128 audio_renderer_->Stop(); |
128 | 129 |
129 media_log_->AddEvent( | 130 media_log_->AddEvent( |
130 media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_DESTROYED)); | 131 media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_DESTROYED)); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
179 } | 180 } |
180 | 181 |
181 void WebMediaPlayerMS::play() { | 182 void WebMediaPlayerMS::play() { |
182 DVLOG(1) << "WebMediaPlayerMS::play"; | 183 DVLOG(1) << "WebMediaPlayerMS::play"; |
183 DCHECK(thread_checker_.CalledOnValidThread()); | 184 DCHECK(thread_checker_.CalledOnValidThread()); |
184 | 185 |
185 if (paused_) { | 186 if (paused_) { |
186 if (video_frame_provider_.get()) | 187 if (video_frame_provider_.get()) |
187 video_frame_provider_->Play(); | 188 video_frame_provider_->Play(); |
188 | 189 |
| 190 compositor_task_runner_->PostTask( |
| 191 FROM_HERE, base::Bind(&WebMediaPlayerMS::Compositor::StartRendering, |
| 192 base::Unretained(compositor_.get()))); |
| 193 |
189 if (audio_renderer_.get()) | 194 if (audio_renderer_.get()) |
190 audio_renderer_->Play(); | 195 audio_renderer_->Play(); |
191 | 196 |
192 if (delegate_.get()) | 197 if (delegate_.get()) |
193 delegate_->DidPlay(this); | 198 delegate_->DidPlay(this); |
194 } | 199 } |
195 | 200 |
196 paused_ = false; | 201 paused_ = false; |
197 | 202 |
198 media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PLAY)); | 203 media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PLAY)); |
199 } | 204 } |
200 | 205 |
201 void WebMediaPlayerMS::pause() { | 206 void WebMediaPlayerMS::pause() { |
202 DVLOG(1) << "WebMediaPlayerMS::pause"; | 207 DVLOG(1) << "WebMediaPlayerMS::pause"; |
203 DCHECK(thread_checker_.CalledOnValidThread()); | 208 DCHECK(thread_checker_.CalledOnValidThread()); |
204 | 209 |
205 if (video_frame_provider_.get()) | 210 if (video_frame_provider_.get()) |
206 video_frame_provider_->Pause(); | 211 video_frame_provider_->Pause(); |
207 | 212 |
| 213 compositor_task_runner_->PostTask( |
| 214 FROM_HERE, base::Bind(&WebMediaPlayerMS::Compositor::StopRendering, |
| 215 base::Unretained(compositor_.get()))); |
| 216 |
208 if (!paused_) { | 217 if (!paused_) { |
209 if (audio_renderer_.get()) | 218 if (audio_renderer_.get()) |
210 audio_renderer_->Pause(); | 219 audio_renderer_->Pause(); |
211 | 220 |
212 if (delegate_.get()) | 221 if (delegate_.get()) |
213 delegate_->DidPause(this); | 222 delegate_->DidPause(this); |
214 } | 223 } |
215 | 224 |
216 paused_ = true; | 225 paused_ = true; |
217 | 226 |
218 media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PAUSE)); | 227 media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PAUSE)); |
219 | |
220 if (!current_frame_.get()) | |
221 return; | |
222 | |
223 // Copy the frame so that rendering can show the last received frame. | |
224 // The original frame must not be referenced when the player is paused since | |
225 // there might be a finite number of available buffers. E.g, video that | |
226 // originates from a video camera. | |
227 scoped_refptr<media::VideoFrame> new_frame = | |
228 CopyFrameToYV12(current_frame_, &video_renderer_); | |
229 | |
230 base::AutoLock auto_lock(current_frame_lock_); | |
231 current_frame_ = new_frame; | |
232 } | 228 } |
233 | 229 |
234 bool WebMediaPlayerMS::supportsSave() const { | 230 bool WebMediaPlayerMS::supportsSave() const { |
235 DCHECK(thread_checker_.CalledOnValidThread()); | 231 DCHECK(thread_checker_.CalledOnValidThread()); |
236 return false; | 232 return false; |
237 } | 233 } |
238 | 234 |
239 void WebMediaPlayerMS::seek(double seconds) { | 235 void WebMediaPlayerMS::seek(double seconds) { |
240 DCHECK(thread_checker_.CalledOnValidThread()); | 236 DCHECK(thread_checker_.CalledOnValidThread()); |
241 } | 237 } |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
281 } | 277 } |
282 | 278 |
283 bool WebMediaPlayerMS::hasAudio() const { | 279 bool WebMediaPlayerMS::hasAudio() const { |
284 DCHECK(thread_checker_.CalledOnValidThread()); | 280 DCHECK(thread_checker_.CalledOnValidThread()); |
285 return (audio_renderer_.get() != NULL); | 281 return (audio_renderer_.get() != NULL); |
286 } | 282 } |
287 | 283 |
288 blink::WebSize WebMediaPlayerMS::naturalSize() const { | 284 blink::WebSize WebMediaPlayerMS::naturalSize() const { |
289 DCHECK(thread_checker_.CalledOnValidThread()); | 285 DCHECK(thread_checker_.CalledOnValidThread()); |
290 | 286 |
291 gfx::Size size; | 287 gfx::Size size = compositor_->GetCurrentSize(); |
292 if (current_frame_.get()) | 288 |
293 size = current_frame_->natural_size(); | |
294 DVLOG(3) << "WebMediaPlayerMS::naturalSize, " << size.ToString(); | 289 DVLOG(3) << "WebMediaPlayerMS::naturalSize, " << size.ToString(); |
295 return blink::WebSize(size); | 290 return blink::WebSize(size); |
296 } | 291 } |
297 | 292 |
298 bool WebMediaPlayerMS::paused() const { | 293 bool WebMediaPlayerMS::paused() const { |
299 DCHECK(thread_checker_.CalledOnValidThread()); | 294 DCHECK(thread_checker_.CalledOnValidThread()); |
300 return paused_; | 295 return paused_; |
301 } | 296 } |
302 | 297 |
303 bool WebMediaPlayerMS::seeking() const { | 298 bool WebMediaPlayerMS::seeking() const { |
304 DCHECK(thread_checker_.CalledOnValidThread()); | 299 DCHECK(thread_checker_.CalledOnValidThread()); |
305 return false; | 300 return false; |
306 } | 301 } |
307 | 302 |
308 double WebMediaPlayerMS::duration() const { | 303 double WebMediaPlayerMS::duration() const { |
309 DCHECK(thread_checker_.CalledOnValidThread()); | 304 DCHECK(thread_checker_.CalledOnValidThread()); |
310 return std::numeric_limits<double>::infinity(); | 305 return std::numeric_limits<double>::infinity(); |
311 } | 306 } |
312 | 307 |
313 double WebMediaPlayerMS::currentTime() const { | 308 double WebMediaPlayerMS::currentTime() const { |
314 DCHECK(thread_checker_.CalledOnValidThread()); | 309 DCHECK(thread_checker_.CalledOnValidThread()); |
315 if (current_time_.ToInternalValue() != 0) { | 310 base::TimeDelta current_time = compositor_->GetCurrentTime(); |
316 return current_time_.InSecondsF(); | 311 if (current_time.ToInternalValue() != 0) { |
| 312 return current_time.InSecondsF(); |
317 } else if (audio_renderer_.get()) { | 313 } else if (audio_renderer_.get()) { |
318 return audio_renderer_->GetCurrentRenderTime().InSecondsF(); | 314 return audio_renderer_->GetCurrentRenderTime().InSecondsF(); |
319 } | 315 } |
320 return 0.0; | 316 return 0.0; |
321 } | 317 } |
322 | 318 |
323 WebMediaPlayer::NetworkState WebMediaPlayerMS::networkState() const { | 319 WebMediaPlayer::NetworkState WebMediaPlayerMS::networkState() const { |
324 DCHECK(thread_checker_.CalledOnValidThread()); | 320 DCHECK(thread_checker_.CalledOnValidThread()); |
325 DVLOG(1) << "WebMediaPlayerMS::networkState, state:" << network_state_; | 321 DVLOG(1) << "WebMediaPlayerMS::networkState, state:" << network_state_; |
326 return network_state_; | 322 return network_state_; |
(...skipping 20 matching lines...) Expand all Loading... |
347 return true; | 343 return true; |
348 } | 344 } |
349 | 345 |
350 void WebMediaPlayerMS::paint(blink::WebCanvas* canvas, | 346 void WebMediaPlayerMS::paint(blink::WebCanvas* canvas, |
351 const blink::WebRect& rect, | 347 const blink::WebRect& rect, |
352 unsigned char alpha, | 348 unsigned char alpha, |
353 SkXfermode::Mode mode) { | 349 SkXfermode::Mode mode) { |
354 DVLOG(3) << "WebMediaPlayerMS::paint"; | 350 DVLOG(3) << "WebMediaPlayerMS::paint"; |
355 DCHECK(thread_checker_.CalledOnValidThread()); | 351 DCHECK(thread_checker_.CalledOnValidThread()); |
356 | 352 |
| 353 scoped_refptr<media::VideoFrame> frame = compositor_->GetCurrentFrame(); |
| 354 |
357 media::Context3D context_3d; | 355 media::Context3D context_3d; |
358 if (current_frame_.get() && current_frame_->HasTextures()) { | 356 if (frame.get() && frame->HasTextures()) { |
359 cc::ContextProvider* provider = | 357 cc::ContextProvider* provider = |
360 RenderThreadImpl::current()->SharedMainThreadContextProvider().get(); | 358 RenderThreadImpl::current()->SharedMainThreadContextProvider().get(); |
361 // GPU Process crashed. | 359 // GPU Process crashed. |
362 if (!provider) | 360 if (!provider) |
363 return; | 361 return; |
364 context_3d = media::Context3D(provider->ContextGL(), provider->GrContext()); | 362 context_3d = media::Context3D(provider->ContextGL(), provider->GrContext()); |
365 DCHECK(context_3d.gl); | 363 DCHECK(context_3d.gl); |
366 } | 364 } |
367 gfx::RectF dest_rect(rect.x, rect.y, rect.width, rect.height); | 365 gfx::RectF dest_rect(rect.x, rect.y, rect.width, rect.height); |
368 video_renderer_.Paint(current_frame_, canvas, dest_rect, alpha, mode, | 366 video_renderer_.Paint(frame, canvas, dest_rect, alpha, mode, |
369 media::VIDEO_ROTATION_0, context_3d); | 367 media::VIDEO_ROTATION_0, context_3d); |
370 | |
371 { | |
372 base::AutoLock auto_lock(current_frame_lock_); | |
373 if (current_frame_.get()) | |
374 current_frame_used_ = true; | |
375 } | |
376 } | 368 } |
377 | 369 |
378 bool WebMediaPlayerMS::hasSingleSecurityOrigin() const { | 370 bool WebMediaPlayerMS::hasSingleSecurityOrigin() const { |
379 DCHECK(thread_checker_.CalledOnValidThread()); | 371 DCHECK(thread_checker_.CalledOnValidThread()); |
380 return true; | 372 return true; |
381 } | 373 } |
382 | 374 |
383 bool WebMediaPlayerMS::didPassCORSAccessCheck() const { | 375 bool WebMediaPlayerMS::didPassCORSAccessCheck() const { |
384 DCHECK(thread_checker_.CalledOnValidThread()); | 376 DCHECK(thread_checker_.CalledOnValidThread()); |
385 return true; | 377 return true; |
386 } | 378 } |
387 | 379 |
388 double WebMediaPlayerMS::mediaTimeForTimeValue(double timeValue) const { | 380 double WebMediaPlayerMS::mediaTimeForTimeValue(double timeValue) const { |
389 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF(); | 381 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF(); |
390 } | 382 } |
391 | 383 |
392 unsigned WebMediaPlayerMS::decodedFrameCount() const { | 384 unsigned WebMediaPlayerMS::decodedFrameCount() const { |
393 DCHECK(thread_checker_.CalledOnValidThread()); | 385 DCHECK(thread_checker_.CalledOnValidThread()); |
394 DVLOG(1) << "WebMediaPlayerMS::decodedFrameCount, " << total_frame_count_; | 386 unsigned total_frame_count = compositor_->GetTotalFrameCount(); |
395 return total_frame_count_; | 387 DVLOG(1) << "WebMediaPlayerMS::decodedFrameCount, " << total_frame_count; |
| 388 return total_frame_count; |
396 } | 389 } |
397 | 390 |
398 unsigned WebMediaPlayerMS::droppedFrameCount() const { | 391 unsigned WebMediaPlayerMS::droppedFrameCount() const { |
399 DCHECK(thread_checker_.CalledOnValidThread()); | 392 DCHECK(thread_checker_.CalledOnValidThread()); |
400 DVLOG(1) << "WebMediaPlayerMS::droppedFrameCount, " << dropped_frame_count_; | 393 unsigned dropped_frame_count = compositor_->GetDroppedFrameCount(); |
401 return dropped_frame_count_; | 394 DVLOG(1) << "WebMediaPlayerMS::droppedFrameCount, " << dropped_frame_count; |
| 395 return dropped_frame_count; |
402 } | 396 } |
403 | 397 |
404 unsigned WebMediaPlayerMS::audioDecodedByteCount() const { | 398 unsigned WebMediaPlayerMS::audioDecodedByteCount() const { |
405 DCHECK(thread_checker_.CalledOnValidThread()); | 399 DCHECK(thread_checker_.CalledOnValidThread()); |
406 NOTIMPLEMENTED(); | 400 NOTIMPLEMENTED(); |
407 return 0; | 401 return 0; |
408 } | 402 } |
409 | 403 |
410 unsigned WebMediaPlayerMS::videoDecodedByteCount() const { | 404 unsigned WebMediaPlayerMS::videoDecodedByteCount() const { |
411 DCHECK(thread_checker_.CalledOnValidThread()); | 405 DCHECK(thread_checker_.CalledOnValidThread()); |
412 NOTIMPLEMENTED(); | 406 NOTIMPLEMENTED(); |
413 return 0; | 407 return 0; |
414 } | 408 } |
415 | 409 |
416 bool WebMediaPlayerMS::copyVideoTextureToPlatformTexture( | 410 bool WebMediaPlayerMS::copyVideoTextureToPlatformTexture( |
417 blink::WebGraphicsContext3D* web_graphics_context, | 411 blink::WebGraphicsContext3D* web_graphics_context, |
418 unsigned int texture, | 412 unsigned int texture, |
419 unsigned int internal_format, | 413 unsigned int internal_format, |
420 unsigned int type, | 414 unsigned int type, |
421 bool premultiply_alpha, | 415 bool premultiply_alpha, |
422 bool flip_y) { | 416 bool flip_y) { |
423 TRACE_EVENT0("media", "WebMediaPlayerMS:copyVideoTextureToPlatformTexture"); | 417 TRACE_EVENT0("media", "WebMediaPlayerMS:copyVideoTextureToPlatformTexture"); |
424 DCHECK(thread_checker_.CalledOnValidThread()); | 418 DCHECK(thread_checker_.CalledOnValidThread()); |
425 | 419 |
426 scoped_refptr<media::VideoFrame> video_frame; | 420 scoped_refptr<media::VideoFrame> video_frame = compositor_->GetCurrentFrame(); |
427 { | |
428 base::AutoLock auto_lock(current_frame_lock_); | |
429 video_frame = current_frame_; | |
430 } | |
431 | 421 |
432 if (!video_frame.get() || video_frame->HasTextures() || | 422 if (!video_frame.get() || video_frame->HasTextures() || |
433 media::VideoFrame::NumPlanes(video_frame->format()) != 1) { | 423 media::VideoFrame::NumPlanes(video_frame->format()) != 1) { |
434 return false; | 424 return false; |
435 } | 425 } |
436 | 426 |
437 // TODO(dshwang): need more elegant way to convert WebGraphicsContext3D to | 427 // TODO(dshwang): need more elegant way to convert WebGraphicsContext3D to |
438 // GLES2Interface. | 428 // GLES2Interface. |
439 gpu::gles2::GLES2Interface* gl = | 429 gpu::gles2::GLES2Interface* gl = |
440 static_cast<gpu_blink::WebGraphicsContext3DImpl*>(web_graphics_context) | 430 static_cast<gpu_blink::WebGraphicsContext3DImpl*>(web_graphics_context) |
441 ->GetGLInterface(); | 431 ->GetGLInterface(); |
442 media::SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( | 432 media::SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( |
443 gl, video_frame.get(), texture, internal_format, type, premultiply_alpha, | 433 gl, video_frame.get(), texture, internal_format, type, premultiply_alpha, |
444 flip_y); | 434 flip_y); |
445 return true; | 435 return true; |
446 } | 436 } |
447 | 437 |
448 void WebMediaPlayerMS::SetVideoFrameProviderClient( | |
449 cc::VideoFrameProvider::Client* client) { | |
450 // This is called from both the main renderer thread and the compositor | |
451 // thread (when the main thread is blocked). | |
452 if (video_frame_provider_client_) | |
453 video_frame_provider_client_->StopUsingProvider(); | |
454 video_frame_provider_client_ = client; | |
455 } | |
456 | |
457 bool WebMediaPlayerMS::UpdateCurrentFrame(base::TimeTicks deadline_min, | |
458 base::TimeTicks deadline_max) { | |
459 // TODO(dalecurtis): This should make use of the deadline interval to ensure | |
460 // the painted frame is correct for the given interval. | |
461 NOTREACHED(); | |
462 return false; | |
463 } | |
464 | |
465 bool WebMediaPlayerMS::HasCurrentFrame() { | |
466 base::AutoLock auto_lock(current_frame_lock_); | |
467 return current_frame_; | |
468 } | |
469 | |
470 scoped_refptr<media::VideoFrame> WebMediaPlayerMS::GetCurrentFrame() { | |
471 DVLOG(3) << "WebMediaPlayerMS::GetCurrentFrame"; | |
472 base::AutoLock auto_lock(current_frame_lock_); | |
473 if (!current_frame_.get()) | |
474 return NULL; | |
475 current_frame_used_ = true; | |
476 return current_frame_; | |
477 } | |
478 | |
479 void WebMediaPlayerMS::PutCurrentFrame() { | |
480 DVLOG(3) << "WebMediaPlayerMS::PutCurrentFrame"; | |
481 } | |
482 | |
483 void WebMediaPlayerMS::OnFrameAvailable( | 438 void WebMediaPlayerMS::OnFrameAvailable( |
484 const scoped_refptr<media::VideoFrame>& frame) { | 439 const scoped_refptr<media::VideoFrame>& frame) { |
485 DVLOG(3) << "WebMediaPlayerMS::OnFrameAvailable"; | 440 DVLOG(3) << "WebMediaPlayerMS::OnFrameAvailable"; |
486 DCHECK(thread_checker_.CalledOnValidThread()); | 441 DCHECK(thread_checker_.CalledOnValidThread()); |
487 ++total_frame_count_; | 442 |
| 443 base::TimeTicks render_time; |
| 444 if (!frame->metadata()->GetTimeTicks( |
| 445 media::VideoFrameMetadata::REFERENCE_TIME, &render_time)) { |
| 446 render_time = base::TimeTicks(); |
| 447 } |
| 448 TRACE_EVENT1("webrtc", "WebMediaPlayerMS::OnFrameAvailable", |
| 449 "Ideal Render Instant", render_time.ToInternalValue()); |
| 450 |
488 if (!received_first_frame_) { | 451 if (!received_first_frame_) { |
489 received_first_frame_ = true; | 452 received_first_frame_ = true; |
490 { | |
491 base::AutoLock auto_lock(current_frame_lock_); | |
492 DCHECK(!current_frame_used_); | |
493 current_frame_ = frame; | |
494 } | |
495 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); | 453 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); |
496 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); | 454 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); |
497 GetClient()->sizeChanged(); | |
498 | 455 |
499 if (video_frame_provider_.get()) { | 456 if (video_frame_provider_.get()) { |
500 video_weblayer_.reset(new cc_blink::WebLayerImpl( | 457 video_weblayer_.reset(new cc_blink::WebLayerImpl( |
501 cc::VideoLayer::Create(cc_blink::WebLayerImpl::LayerSettings(), this, | 458 cc::VideoLayer::Create(cc_blink::WebLayerImpl::LayerSettings(), |
502 media::VIDEO_ROTATION_0))); | 459 compositor_.get(), media::VIDEO_ROTATION_0))); |
503 video_weblayer_->setOpaque(true); | 460 video_weblayer_->setOpaque(true); |
504 GetClient()->setWebLayer(video_weblayer_.get()); | 461 GetClient()->setWebLayer(video_weblayer_.get()); |
505 } | 462 } |
506 } | 463 } |
507 | 464 |
508 // Do not update |current_frame_| when paused. | 465 bool size_changed = compositor_->GetCurrentSize() != frame->natural_size(); |
509 if (paused_) | |
510 return; | |
511 | 466 |
512 bool size_changed = !current_frame_.get() || | 467 compositor_->EnqueueFrame(frame); |
513 current_frame_->natural_size() != frame->natural_size(); | |
514 | |
515 { | |
516 base::AutoLock auto_lock(current_frame_lock_); | |
517 if (!current_frame_used_ && current_frame_.get()) | |
518 ++dropped_frame_count_; | |
519 current_frame_ = frame; | |
520 current_time_ = frame->timestamp(); | |
521 current_frame_used_ = false; | |
522 } | |
523 | 468 |
524 if (size_changed) | 469 if (size_changed) |
525 GetClient()->sizeChanged(); | 470 GetClient()->sizeChanged(); |
526 | |
527 GetClient()->repaint(); | |
528 } | 471 } |
529 | 472 |
530 void WebMediaPlayerMS::RepaintInternal() { | 473 void WebMediaPlayerMS::RepaintInternal() { |
531 DVLOG(1) << "WebMediaPlayerMS::RepaintInternal"; | 474 DVLOG(1) << "WebMediaPlayerMS::RepaintInternal"; |
532 DCHECK(thread_checker_.CalledOnValidThread()); | 475 DCHECK(thread_checker_.CalledOnValidThread()); |
533 GetClient()->repaint(); | 476 GetClient()->repaint(); |
534 } | 477 } |
535 | 478 |
536 void WebMediaPlayerMS::OnSourceError() { | 479 void WebMediaPlayerMS::OnSourceError() { |
537 DVLOG(1) << "WebMediaPlayerMS::OnSourceError"; | 480 DVLOG(1) << "WebMediaPlayerMS::OnSourceError"; |
(...skipping 15 matching lines...) Expand all Loading... |
553 // Always notify to ensure client has the latest value. | 496 // Always notify to ensure client has the latest value. |
554 GetClient()->readyStateChanged(); | 497 GetClient()->readyStateChanged(); |
555 } | 498 } |
556 | 499 |
557 blink::WebMediaPlayerClient* WebMediaPlayerMS::GetClient() { | 500 blink::WebMediaPlayerClient* WebMediaPlayerMS::GetClient() { |
558 DCHECK(thread_checker_.CalledOnValidThread()); | 501 DCHECK(thread_checker_.CalledOnValidThread()); |
559 DCHECK(client_); | 502 DCHECK(client_); |
560 return client_; | 503 return client_; |
561 } | 504 } |
562 | 505 |
| 506 WebMediaPlayerMS::Compositor::Compositor( |
| 507 const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner) |
| 508 : compositor_task_runner_(compositor_task_runner), |
| 509 video_frame_provider_client_(NULL), |
| 510 current_frame_used_(false), |
| 511 last_deadline_max_(base::TimeTicks()), |
| 512 total_frame_count_(0), |
| 513 dropped_frame_count_(0), |
| 514 paused_(false) {} |
| 515 |
| 516 WebMediaPlayerMS::Compositor::~Compositor() { |
| 517 DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| 518 if (video_frame_provider_client_) |
| 519 video_frame_provider_client_->StopUsingProvider(); |
| 520 } |
| 521 |
| 522 void WebMediaPlayerMS::Compositor::EnqueueFrame( |
| 523 scoped_refptr<media::VideoFrame> const& frame) { |
| 524 base::AutoLock auto_lock(current_frame_lock_); |
| 525 ++total_frame_count_; |
| 526 |
| 527 if (base::TimeTicks::Now() > last_deadline_max_) { |
| 528 // TODO(qiangchen): This shows vsyncs stops rendering frames. A probable |
| 529 // cause is that the tab is not in the front. But we still have to let |
| 530 // old frames go. Call VRA::RemoveExpiredFrames. |
| 531 current_frame_ = frame; |
| 532 } |
| 533 |
| 534 if (staging_frame_.get() != current_frame_.get()) { |
| 535 // This shows the staging_frame_ nevers get updated into current_frame_, and |
| 536 // now we are going to overwrite it. The frame should be counted as dropped. |
| 537 ++dropped_frame_count_; |
| 538 } |
| 539 |
| 540 // TODO(qiangchen): Instead of using one variable to hold one frame, use |
| 541 // VideoRendererAlgorithm. |
| 542 staging_frame_ = frame; |
| 543 } |
| 544 |
| 545 bool WebMediaPlayerMS::Compositor::UpdateCurrentFrame( |
| 546 base::TimeTicks deadline_min, |
| 547 base::TimeTicks deadline_max) { |
| 548 DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| 549 base::AutoLock auto_lock(current_frame_lock_); |
| 550 TRACE_EVENT_BEGIN2("webrtc", "WebMediaPlayerMS::UpdateCurrentFrame", |
| 551 "Actual Render Begin", deadline_min.ToInternalValue(), |
| 552 "Actual Render End", deadline_max.ToInternalValue()); |
| 553 last_deadline_max_ = deadline_max; |
| 554 |
| 555 // TODO(dalecurtis): This should make use of the deadline interval to ensure |
| 556 // the painted frame is correct for the given interval. |
| 557 |
| 558 if (paused_) |
| 559 return false; |
| 560 |
| 561 if (current_frame_.get() != staging_frame_.get()) { |
| 562 if (!current_frame_used_) |
| 563 ++dropped_frame_count_; |
| 564 current_frame_ = staging_frame_; |
| 565 current_frame_used_ = false; |
| 566 } |
| 567 |
| 568 base::TimeTicks render_time; |
| 569 if (!current_frame_->metadata()->GetTimeTicks( |
| 570 media::VideoFrameMetadata::REFERENCE_TIME, &render_time)) { |
| 571 render_time = base::TimeTicks(); |
| 572 } |
| 573 TRACE_EVENT_END1("webrtc", "WebMediaPlayerMS::UpdateCurrentFrame", |
| 574 "Ideal Render Instant", render_time.ToInternalValue()); |
| 575 return !current_frame_used_; |
| 576 } |
| 577 |
| 578 bool WebMediaPlayerMS::Compositor::HasCurrentFrame() { |
| 579 base::AutoLock auto_lock(current_frame_lock_); |
| 580 return !!current_frame_.get(); |
| 581 } |
| 582 |
| 583 scoped_refptr<media::VideoFrame> |
| 584 WebMediaPlayerMS::Compositor::GetCurrentFrame() { |
| 585 DVLOG(3) << "WebMediaPlayerMS::Compositor::GetCurrentFrame"; |
| 586 base::AutoLock auto_lock(current_frame_lock_); |
| 587 if (!current_frame_.get()) |
| 588 return NULL; |
| 589 return current_frame_; |
| 590 } |
| 591 |
| 592 void WebMediaPlayerMS::Compositor::PutCurrentFrame() { |
| 593 DVLOG(3) << "WebMediaPlayerMS::PutCurrentFrame"; |
| 594 current_frame_used_ = true; |
| 595 } |
| 596 |
| 597 void WebMediaPlayerMS::Compositor::SetVideoFrameProviderClient( |
| 598 cc::VideoFrameProvider::Client* client) { |
| 599 DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| 600 if (video_frame_provider_client_) |
| 601 video_frame_provider_client_->StopUsingProvider(); |
| 602 |
| 603 video_frame_provider_client_ = client; |
| 604 if (video_frame_provider_client_) |
| 605 video_frame_provider_client_->StartRendering(); |
| 606 } |
| 607 |
| 608 void WebMediaPlayerMS::Compositor::StartRendering() { |
| 609 DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| 610 paused_ = false; |
| 611 if (video_frame_provider_client_) |
| 612 video_frame_provider_client_->StartRendering(); |
| 613 } |
| 614 |
| 615 void WebMediaPlayerMS::Compositor::StopRendering() { |
| 616 DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| 617 paused_ = true; |
| 618 if (video_frame_provider_client_) |
| 619 video_frame_provider_client_->StopRendering(); |
| 620 |
| 621 base::AutoLock auto_lock(current_frame_lock_); |
| 622 if (!current_frame_.get()) |
| 623 return; |
| 624 |
| 625 // Copy the frame so that rendering can show the last received frame. |
| 626 // The original frame must not be referenced when the player is paused since |
| 627 // there might be a finite number of available buffers. E.g, video that |
| 628 // originates from a video camera. |
| 629 scoped_refptr<media::VideoFrame> new_frame = |
| 630 CopyFrameToYV12(current_frame_, &video_renderer_); |
| 631 |
| 632 current_frame_ = new_frame; |
| 633 } |
| 634 |
| 635 gfx::Size WebMediaPlayerMS::Compositor::GetCurrentSize() { |
| 636 base::AutoLock auto_lock(current_frame_lock_); |
| 637 return staging_frame_.get() ? staging_frame_->natural_size() : gfx::Size(); |
| 638 } |
| 639 |
| 640 base::TimeDelta WebMediaPlayerMS::Compositor::GetCurrentTime() { |
| 641 base::AutoLock auto_lock(current_frame_lock_); |
| 642 return staging_frame_.get() ? staging_frame_->timestamp() : base::TimeDelta(); |
| 643 } |
| 644 |
| 645 unsigned WebMediaPlayerMS::Compositor::GetTotalFrameCount() { |
| 646 return total_frame_count_; |
| 647 } |
| 648 |
| 649 unsigned WebMediaPlayerMS::Compositor::GetDroppedFrameCount() { |
| 650 return dropped_frame_count_; |
| 651 } |
563 } // namespace content | 652 } // namespace content |
OLD | NEW |