Roll src/third_party/WebKit eac3800:0237a66 (svn 202606:202607)
[chromium-blink-merge.git] / content / renderer / media / webmediaplayer_ms.cc
blobab7dd718b9c5a0628a94fa80e8d110b8567fd9ba
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
3 // found in the LICENSE file.
5 #include "content/renderer/media/webmediaplayer_ms.h"
7 #include <limits>
8 #include <string>
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/metrics/histogram.h"
14 #include "cc/blink/context_provider_web_context.h"
15 #include "cc/blink/web_layer_impl.h"
16 #include "cc/layers/video_frame_provider_client_impl.h"
17 #include "cc/layers/video_layer.h"
18 #include "content/public/renderer/media_stream_audio_renderer.h"
19 #include "content/public/renderer/media_stream_renderer_factory.h"
20 #include "content/public/renderer/render_view.h"
21 #include "content/public/renderer/video_frame_provider.h"
22 #include "content/renderer/render_frame_impl.h"
23 #include "content/renderer/render_thread_impl.h"
24 #include "gpu/blink/webgraphicscontext3d_impl.h"
25 #include "media/base/media_log.h"
26 #include "media/base/video_frame.h"
27 #include "media/base/video_rotation.h"
28 #include "media/base/video_util.h"
29 #include "media/blink/webmediaplayer_delegate.h"
30 #include "third_party/WebKit/public/platform/WebMediaPlayerClient.h"
31 #include "third_party/WebKit/public/platform/WebRect.h"
32 #include "third_party/WebKit/public/platform/WebSize.h"
33 #include "third_party/WebKit/public/platform/WebURL.h"
34 #include "third_party/WebKit/public/web/WebFrame.h"
35 #include "third_party/WebKit/public/web/WebView.h"
36 #include "third_party/skia/include/core/SkBitmap.h"
38 using blink::WebCanvas;
39 using blink::WebMediaPlayer;
40 using blink::WebRect;
41 using blink::WebSize;
43 namespace content {
45 namespace {
47 // This function copies |frame| to a new YV12 media::VideoFrame.
48 scoped_refptr<media::VideoFrame> CopyFrameToYV12(
49 const scoped_refptr<media::VideoFrame>& frame,
50 media::SkCanvasVideoRenderer* video_renderer) {
51 const scoped_refptr<media::VideoFrame> new_frame =
52 media::VideoFrame::CreateFrame(media::PIXEL_FORMAT_YV12,
53 frame->coded_size(), frame->visible_rect(),
54 frame->natural_size(), frame->timestamp());
56 if (frame->HasTextures()) {
57 DCHECK(frame->format() == media::PIXEL_FORMAT_ARGB ||
58 frame->format() == media::PIXEL_FORMAT_XRGB);
59 SkBitmap bitmap;
60 bitmap.allocN32Pixels(frame->visible_rect().width(),
61 frame->visible_rect().height());
62 SkCanvas canvas(bitmap);
64 cc::ContextProvider* const provider =
65 RenderThreadImpl::current()->SharedMainThreadContextProvider().get();
66 if (provider) {
67 const media::Context3D context_3d =
68 media::Context3D(provider->ContextGL(), provider->GrContext());
69 DCHECK(context_3d.gl);
70 video_renderer->Copy(frame.get(), &canvas, context_3d);
71 } else {
72 // GPU Process crashed.
73 bitmap.eraseColor(SK_ColorTRANSPARENT);
75 media::CopyRGBToVideoFrame(reinterpret_cast<uint8*>(bitmap.getPixels()),
76 bitmap.rowBytes(),
77 frame->visible_rect(),
78 new_frame.get());
79 } else {
80 DCHECK(frame->IsMappable());
81 DCHECK(frame->format() == media::PIXEL_FORMAT_YV12 ||
82 frame->format() == media::PIXEL_FORMAT_I420);
83 for (size_t i = 0; i < media::VideoFrame::NumPlanes(frame->format()); ++i) {
84 media::CopyPlane(i, frame->data(i), frame->stride(i),
85 frame->rows(i), new_frame.get());
88 return new_frame;
91 } // anonymous namespace
93 WebMediaPlayerMS::WebMediaPlayerMS(
94 blink::WebFrame* frame,
95 blink::WebMediaPlayerClient* client,
96 base::WeakPtr<media::WebMediaPlayerDelegate> delegate,
97 media::MediaLog* media_log,
98 scoped_ptr<MediaStreamRendererFactory> factory,
99 const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner)
100 : frame_(frame),
101 network_state_(WebMediaPlayer::NetworkStateEmpty),
102 ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
103 buffered_(static_cast<size_t>(0)),
104 volume_(1.0f),
105 client_(client),
106 delegate_(delegate),
107 paused_(true),
108 received_first_frame_(false),
109 media_log_(media_log),
110 renderer_factory_(factory.Pass()),
111 compositor_(new Compositor(compositor_task_runner)),
112 compositor_task_runner_(compositor_task_runner) {
113 DVLOG(1) << "WebMediaPlayerMS::ctor";
114 media_log_->AddEvent(
115 media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_CREATED));
118 WebMediaPlayerMS::~WebMediaPlayerMS() {
119 DVLOG(1) << "WebMediaPlayerMS::dtor";
120 DCHECK(thread_checker_.CalledOnValidThread());
122 compositor_task_runner_->DeleteSoon(FROM_HERE, compositor_.release());
124 GetClient()->setWebLayer(NULL);
126 if (video_frame_provider_.get())
127 video_frame_provider_->Stop();
129 if (audio_renderer_.get())
130 audio_renderer_->Stop();
132 media_log_->AddEvent(
133 media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
135 if (delegate_.get())
136 delegate_->PlayerGone(this);
139 void WebMediaPlayerMS::load(LoadType load_type,
140 const blink::WebURL& url,
141 CORSMode cors_mode) {
142 DVLOG(1) << "WebMediaPlayerMS::load";
143 DCHECK(thread_checker_.CalledOnValidThread());
145 // TODO(acolwell): Change this to DCHECK_EQ(load_type,
146 // LoadTypeMediaStream) once Blink-side changes land.
147 DCHECK_NE(load_type, LoadTypeMediaSource);
149 GURL gurl(url);
151 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
152 SetReadyState(WebMediaPlayer::ReadyStateHaveNothing);
153 media_log_->AddEvent(media_log_->CreateLoadEvent(url.spec()));
155 video_frame_provider_ = renderer_factory_->GetVideoFrameProvider(
156 url,
157 base::Bind(&WebMediaPlayerMS::OnSourceError, AsWeakPtr()),
158 base::Bind(&WebMediaPlayerMS::OnFrameAvailable, AsWeakPtr()));
160 RenderFrame* const frame = RenderFrame::FromWebFrame(frame_);
161 audio_renderer_ = renderer_factory_->GetAudioRenderer(
162 url,
163 frame->GetRoutingID());
165 if (!video_frame_provider_ && !audio_renderer_) {
166 SetNetworkState(WebMediaPlayer::NetworkStateNetworkError);
167 return;
170 if (audio_renderer_) {
171 audio_renderer_->SetVolume(volume_);
172 audio_renderer_->Start();
174 if (video_frame_provider_)
175 video_frame_provider_->Start();
176 if (audio_renderer_ && !video_frame_provider_) {
177 // This is audio-only mode.
178 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
179 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
183 void WebMediaPlayerMS::play() {
184 DVLOG(1) << "WebMediaPlayerMS::play";
185 DCHECK(thread_checker_.CalledOnValidThread());
187 if (paused_) {
188 if (video_frame_provider_.get())
189 video_frame_provider_->Play();
191 compositor_task_runner_->PostTask(
192 FROM_HERE, base::Bind(&WebMediaPlayerMS::Compositor::StartRendering,
193 base::Unretained(compositor_.get())));
195 if (audio_renderer_.get())
196 audio_renderer_->Play();
198 if (delegate_.get())
199 delegate_->DidPlay(this);
202 paused_ = false;
204 media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PLAY));
207 void WebMediaPlayerMS::pause() {
208 DVLOG(1) << "WebMediaPlayerMS::pause";
209 DCHECK(thread_checker_.CalledOnValidThread());
211 if (video_frame_provider_.get())
212 video_frame_provider_->Pause();
214 compositor_task_runner_->PostTask(
215 FROM_HERE, base::Bind(&WebMediaPlayerMS::Compositor::StopRendering,
216 base::Unretained(compositor_.get())));
217 compositor_->ReplaceCurrentFrameWithACopy(&video_renderer_);
219 if (!paused_) {
220 if (audio_renderer_.get())
221 audio_renderer_->Pause();
223 if (delegate_.get())
224 delegate_->DidPause(this);
227 paused_ = true;
229 media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PAUSE));
232 bool WebMediaPlayerMS::supportsSave() const {
233 DCHECK(thread_checker_.CalledOnValidThread());
234 return false;
237 void WebMediaPlayerMS::seek(double seconds) {
238 DCHECK(thread_checker_.CalledOnValidThread());
241 void WebMediaPlayerMS::setRate(double rate) {
242 DCHECK(thread_checker_.CalledOnValidThread());
245 void WebMediaPlayerMS::setVolume(double volume) {
246 DCHECK(thread_checker_.CalledOnValidThread());
247 DVLOG(1) << "WebMediaPlayerMS::setVolume(volume=" << volume << ")";
248 volume_ = volume;
249 if (audio_renderer_.get())
250 audio_renderer_->SetVolume(volume_);
253 void WebMediaPlayerMS::setSinkId(const blink::WebString& device_id,
254 media::WebSetSinkIdCB* web_callback) {
255 DCHECK(thread_checker_.CalledOnValidThread());
256 DVLOG(1) << __FUNCTION__;
257 media::SwitchOutputDeviceCB callback =
258 media::ConvertToSwitchOutputDeviceCB(web_callback);
259 if (audio_renderer_.get()) {
260 media::OutputDevice* output_device = audio_renderer_->GetOutputDevice();
261 if (output_device) {
262 const std::string device_id_str(device_id.utf8());
263 const url::Origin security_origin(
264 GURL(frame_->securityOrigin().toString().utf8()));
265 output_device->SwitchOutputDevice(device_id_str, security_origin,
266 callback);
267 return;
270 callback.Run(media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_INTERNAL);
273 void WebMediaPlayerMS::setPreload(WebMediaPlayer::Preload preload) {
274 DCHECK(thread_checker_.CalledOnValidThread());
277 bool WebMediaPlayerMS::hasVideo() const {
278 DCHECK(thread_checker_.CalledOnValidThread());
279 return (video_frame_provider_.get() != NULL);
282 bool WebMediaPlayerMS::hasAudio() const {
283 DCHECK(thread_checker_.CalledOnValidThread());
284 return (audio_renderer_.get() != NULL);
287 blink::WebSize WebMediaPlayerMS::naturalSize() const {
288 DCHECK(thread_checker_.CalledOnValidThread());
290 gfx::Size size = compositor_->GetCurrentSize();
292 DVLOG(3) << "WebMediaPlayerMS::naturalSize, " << size.ToString();
293 return blink::WebSize(size);
296 bool WebMediaPlayerMS::paused() const {
297 DCHECK(thread_checker_.CalledOnValidThread());
298 return paused_;
301 bool WebMediaPlayerMS::seeking() const {
302 DCHECK(thread_checker_.CalledOnValidThread());
303 return false;
306 double WebMediaPlayerMS::duration() const {
307 DCHECK(thread_checker_.CalledOnValidThread());
308 return std::numeric_limits<double>::infinity();
311 double WebMediaPlayerMS::currentTime() const {
312 DCHECK(thread_checker_.CalledOnValidThread());
313 base::TimeDelta current_time = compositor_->GetCurrentTime();
314 if (current_time.ToInternalValue() != 0) {
315 return current_time.InSecondsF();
316 } else if (audio_renderer_.get()) {
317 return audio_renderer_->GetCurrentRenderTime().InSecondsF();
319 return 0.0;
322 WebMediaPlayer::NetworkState WebMediaPlayerMS::networkState() const {
323 DCHECK(thread_checker_.CalledOnValidThread());
324 DVLOG(1) << "WebMediaPlayerMS::networkState, state:" << network_state_;
325 return network_state_;
328 WebMediaPlayer::ReadyState WebMediaPlayerMS::readyState() const {
329 DCHECK(thread_checker_.CalledOnValidThread());
330 DVLOG(1) << "WebMediaPlayerMS::readyState, state:" << ready_state_;
331 return ready_state_;
334 blink::WebTimeRanges WebMediaPlayerMS::buffered() const {
335 DCHECK(thread_checker_.CalledOnValidThread());
336 return buffered_;
339 blink::WebTimeRanges WebMediaPlayerMS::seekable() const {
340 DCHECK(thread_checker_.CalledOnValidThread());
341 return blink::WebTimeRanges();
344 bool WebMediaPlayerMS::didLoadingProgress() {
345 DCHECK(thread_checker_.CalledOnValidThread());
346 return true;
349 void WebMediaPlayerMS::paint(blink::WebCanvas* canvas,
350 const blink::WebRect& rect,
351 unsigned char alpha,
352 SkXfermode::Mode mode) {
353 DVLOG(3) << "WebMediaPlayerMS::paint";
354 DCHECK(thread_checker_.CalledOnValidThread());
356 scoped_refptr<media::VideoFrame> frame = compositor_->GetCurrentFrame();
358 media::Context3D context_3d;
359 if (frame.get() && frame->HasTextures()) {
360 cc::ContextProvider* provider =
361 RenderThreadImpl::current()->SharedMainThreadContextProvider().get();
362 // GPU Process crashed.
363 if (!provider)
364 return;
365 context_3d = media::Context3D(provider->ContextGL(), provider->GrContext());
366 DCHECK(context_3d.gl);
368 gfx::RectF dest_rect(rect.x, rect.y, rect.width, rect.height);
369 video_renderer_.Paint(frame, canvas, dest_rect, alpha, mode,
370 media::VIDEO_ROTATION_0, context_3d);
373 bool WebMediaPlayerMS::hasSingleSecurityOrigin() const {
374 DCHECK(thread_checker_.CalledOnValidThread());
375 return true;
378 bool WebMediaPlayerMS::didPassCORSAccessCheck() const {
379 DCHECK(thread_checker_.CalledOnValidThread());
380 return true;
383 double WebMediaPlayerMS::mediaTimeForTimeValue(double timeValue) const {
384 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF();
387 unsigned WebMediaPlayerMS::decodedFrameCount() const {
388 DCHECK(thread_checker_.CalledOnValidThread());
389 unsigned total_frame_count = compositor_->GetTotalFrameCount();
390 DVLOG(1) << "WebMediaPlayerMS::decodedFrameCount, " << total_frame_count;
391 return total_frame_count;
394 unsigned WebMediaPlayerMS::droppedFrameCount() const {
395 DCHECK(thread_checker_.CalledOnValidThread());
396 unsigned dropped_frame_count = compositor_->GetDroppedFrameCount();
397 DVLOG(1) << "WebMediaPlayerMS::droppedFrameCount, " << dropped_frame_count;
398 return dropped_frame_count;
401 unsigned WebMediaPlayerMS::audioDecodedByteCount() const {
402 DCHECK(thread_checker_.CalledOnValidThread());
403 NOTIMPLEMENTED();
404 return 0;
407 unsigned WebMediaPlayerMS::videoDecodedByteCount() const {
408 DCHECK(thread_checker_.CalledOnValidThread());
409 NOTIMPLEMENTED();
410 return 0;
413 bool WebMediaPlayerMS::copyVideoTextureToPlatformTexture(
414 blink::WebGraphicsContext3D* web_graphics_context,
415 unsigned int texture,
416 unsigned int internal_format,
417 unsigned int type,
418 bool premultiply_alpha,
419 bool flip_y) {
420 TRACE_EVENT0("media", "WebMediaPlayerMS:copyVideoTextureToPlatformTexture");
421 DCHECK(thread_checker_.CalledOnValidThread());
423 scoped_refptr<media::VideoFrame> video_frame = compositor_->GetCurrentFrame();
425 if (!video_frame.get() || video_frame->HasTextures() ||
426 media::VideoFrame::NumPlanes(video_frame->format()) != 1) {
427 return false;
430 // TODO(dshwang): need more elegant way to convert WebGraphicsContext3D to
431 // GLES2Interface.
432 gpu::gles2::GLES2Interface* const gl =
433 static_cast<gpu_blink::WebGraphicsContext3DImpl*>(web_graphics_context)
434 ->GetGLInterface();
435 media::SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
436 gl, video_frame.get(), texture, internal_format, type, premultiply_alpha,
437 flip_y);
438 return true;
441 void WebMediaPlayerMS::OnFrameAvailable(
442 const scoped_refptr<media::VideoFrame>& frame) {
443 DVLOG(3) << "WebMediaPlayerMS::OnFrameAvailable";
444 DCHECK(thread_checker_.CalledOnValidThread());
446 base::TimeTicks render_time;
447 if (!frame->metadata()->GetTimeTicks(
448 media::VideoFrameMetadata::REFERENCE_TIME, &render_time)) {
449 render_time = base::TimeTicks();
451 TRACE_EVENT1("webrtc", "WebMediaPlayerMS::OnFrameAvailable",
452 "Ideal Render Instant", render_time.ToInternalValue());
454 if (!received_first_frame_) {
455 received_first_frame_ = true;
456 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
457 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
459 if (video_frame_provider_.get()) {
460 video_weblayer_.reset(new cc_blink::WebLayerImpl(
461 cc::VideoLayer::Create(cc_blink::WebLayerImpl::LayerSettings(),
462 compositor_.get(), media::VIDEO_ROTATION_0)));
463 video_weblayer_->layer()->SetContentsOpaque(true);
464 video_weblayer_->SetContentsOpaqueIsFixed(true);
465 GetClient()->setWebLayer(video_weblayer_.get());
469 bool size_changed = compositor_->GetCurrentSize() != frame->natural_size();
471 compositor_->EnqueueFrame(frame);
473 if (size_changed)
474 GetClient()->sizeChanged();
477 void WebMediaPlayerMS::RepaintInternal() {
478 DVLOG(1) << "WebMediaPlayerMS::RepaintInternal";
479 DCHECK(thread_checker_.CalledOnValidThread());
480 GetClient()->repaint();
483 void WebMediaPlayerMS::OnSourceError() {
484 DVLOG(1) << "WebMediaPlayerMS::OnSourceError";
485 DCHECK(thread_checker_.CalledOnValidThread());
486 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
487 RepaintInternal();
490 void WebMediaPlayerMS::SetNetworkState(WebMediaPlayer::NetworkState state) {
491 DCHECK(thread_checker_.CalledOnValidThread());
492 network_state_ = state;
493 // Always notify to ensure client has the latest value.
494 GetClient()->networkStateChanged();
497 void WebMediaPlayerMS::SetReadyState(WebMediaPlayer::ReadyState state) {
498 DCHECK(thread_checker_.CalledOnValidThread());
499 ready_state_ = state;
500 // Always notify to ensure client has the latest value.
501 GetClient()->readyStateChanged();
504 blink::WebMediaPlayerClient* WebMediaPlayerMS::GetClient() {
505 DCHECK(thread_checker_.CalledOnValidThread());
506 DCHECK(client_);
507 return client_;
510 WebMediaPlayerMS::Compositor::Compositor(
511 const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner)
512 : compositor_task_runner_(compositor_task_runner),
513 video_frame_provider_client_(NULL),
514 current_frame_used_(false),
515 last_deadline_max_(base::TimeTicks()),
516 total_frame_count_(0),
517 dropped_frame_count_(0),
518 paused_(false) {}
520 WebMediaPlayerMS::Compositor::~Compositor() {
521 DCHECK(compositor_task_runner_->BelongsToCurrentThread());
522 if (video_frame_provider_client_)
523 video_frame_provider_client_->StopUsingProvider();
526 void WebMediaPlayerMS::Compositor::EnqueueFrame(
527 scoped_refptr<media::VideoFrame> const& frame) {
528 base::AutoLock auto_lock(current_frame_lock_);
529 ++total_frame_count_;
531 if (base::TimeTicks::Now() > last_deadline_max_) {
532 // TODO(qiangchen): This shows vsyncs stops rendering frames. A probable
533 // cause is that the tab is not in the front. But we still have to let
534 // old frames go. Call VRA::RemoveExpiredFrames.
538 if (!current_frame_used_) {
539 ++dropped_frame_count_;
542 // TODO(qiangchen): Instead of using one variable to hold one frame, use
543 // VideoRendererAlgorithm.
544 current_frame_ = frame;
545 current_frame_used_ = false;
548 bool WebMediaPlayerMS::Compositor::UpdateCurrentFrame(
549 base::TimeTicks deadline_min,
550 base::TimeTicks deadline_max) {
551 DCHECK(compositor_task_runner_->BelongsToCurrentThread());
552 base::AutoLock auto_lock(current_frame_lock_);
553 TRACE_EVENT_BEGIN2("webrtc", "WebMediaPlayerMS::UpdateCurrentFrame",
554 "Actual Render Begin", deadline_min.ToInternalValue(),
555 "Actual Render End", deadline_max.ToInternalValue());
556 last_deadline_max_ = deadline_max;
558 // TODO(dalecurtis): This should make use of the deadline interval to ensure
559 // the painted frame is correct for the given interval.
561 if (paused_)
562 return false;
565 base::TimeTicks render_time;
566 if (!current_frame_->metadata()->GetTimeTicks(
567 media::VideoFrameMetadata::REFERENCE_TIME, &render_time)) {
568 render_time = base::TimeTicks();
570 TRACE_EVENT_END1("webrtc", "WebMediaPlayerMS::UpdateCurrentFrame",
571 "Ideal Render Instant", render_time.ToInternalValue());
572 return !current_frame_used_;
575 bool WebMediaPlayerMS::Compositor::HasCurrentFrame() {
576 base::AutoLock auto_lock(current_frame_lock_);
577 return !!current_frame_.get();
580 scoped_refptr<media::VideoFrame>
581 WebMediaPlayerMS::Compositor::GetCurrentFrame() {
582 DVLOG(3) << "WebMediaPlayerMS::Compositor::GetCurrentFrame";
583 base::AutoLock auto_lock(current_frame_lock_);
584 if (!current_frame_.get())
585 return NULL;
586 return current_frame_;
589 void WebMediaPlayerMS::Compositor::PutCurrentFrame() {
590 DVLOG(3) << "WebMediaPlayerMS::PutCurrentFrame";
591 current_frame_used_ = true;
594 void WebMediaPlayerMS::Compositor::SetVideoFrameProviderClient(
595 cc::VideoFrameProvider::Client* client) {
596 DCHECK(compositor_task_runner_->BelongsToCurrentThread());
597 if (video_frame_provider_client_)
598 video_frame_provider_client_->StopUsingProvider();
600 video_frame_provider_client_ = client;
601 if (video_frame_provider_client_)
602 video_frame_provider_client_->StartRendering();
605 void WebMediaPlayerMS::Compositor::StartRendering() {
606 DCHECK(compositor_task_runner_->BelongsToCurrentThread());
607 paused_ = false;
608 if (video_frame_provider_client_)
609 video_frame_provider_client_->StartRendering();
612 void WebMediaPlayerMS::Compositor::StopRendering() {
613 DCHECK(compositor_task_runner_->BelongsToCurrentThread());
614 paused_ = true;
615 if (video_frame_provider_client_)
616 video_frame_provider_client_->StopRendering();
619 void WebMediaPlayerMS::Compositor::ReplaceCurrentFrameWithACopy(
620 media::SkCanvasVideoRenderer* renderer) {
621 base::AutoLock auto_lock(current_frame_lock_);
622 if (!current_frame_.get())
623 return;
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_, renderer);
632 current_frame_ = new_frame;
635 gfx::Size WebMediaPlayerMS::Compositor::GetCurrentSize() {
636 base::AutoLock auto_lock(current_frame_lock_);
637 return current_frame_.get() ? current_frame_->natural_size() : gfx::Size();
640 base::TimeDelta WebMediaPlayerMS::Compositor::GetCurrentTime() {
641 base::AutoLock auto_lock(current_frame_lock_);
642 return current_frame_.get() ? current_frame_->timestamp() : base::TimeDelta();
645 unsigned WebMediaPlayerMS::Compositor::GetTotalFrameCount() {
646 return total_frame_count_;
649 unsigned WebMediaPlayerMS::Compositor::GetDroppedFrameCount() {
650 return dropped_frame_count_;
652 } // namespace content