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