Roll src/third_party/WebKit a452221:9ff6d11 (svn 202117:202119)
[chromium-blink-merge.git] / content / renderer / media / webmediaplayer_ms.cc
blobfe89d6f618235770b306d8a2f2a8640ce036c567
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>
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/metrics/histogram.h"
13 #include "cc/blink/context_provider_web_context.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"
17 #include "content/public/renderer/media_stream_audio_renderer.h"
18 #include "content/public/renderer/media_stream_renderer_factory.h"
19 #include "content/public/renderer/render_view.h"
20 #include "content/public/renderer/video_frame_provider.h"
21 #include "content/renderer/render_frame_impl.h"
22 #include "content/renderer/render_thread_impl.h"
23 #include "gpu/blink/webgraphicscontext3d_impl.h"
24 #include "media/base/media_log.h"
25 #include "media/base/video_frame.h"
26 #include "media/base/video_rotation.h"
27 #include "media/base/video_util.h"
28 #include "media/blink/webmediaplayer_delegate.h"
29 #include "third_party/WebKit/public/platform/WebMediaPlayerClient.h"
30 #include "third_party/WebKit/public/platform/WebRect.h"
31 #include "third_party/WebKit/public/platform/WebSize.h"
32 #include "third_party/WebKit/public/platform/WebURL.h"
33 #include "third_party/WebKit/public/web/WebFrame.h"
34 #include "third_party/WebKit/public/web/WebView.h"
35 #include "third_party/skia/include/core/SkBitmap.h"
37 using blink::WebCanvas;
38 using blink::WebMediaPlayer;
39 using blink::WebRect;
40 using blink::WebSize;
42 namespace content {
44 namespace {
46 // This function copies |frame| to a new YV12 media::VideoFrame.
47 scoped_refptr<media::VideoFrame> CopyFrameToYV12(
48 const scoped_refptr<media::VideoFrame>& frame,
49 media::SkCanvasVideoRenderer* video_renderer) {
50 const scoped_refptr<media::VideoFrame> new_frame =
51 media::VideoFrame::CreateFrame(media::PIXEL_FORMAT_YV12,
52 frame->coded_size(), frame->visible_rect(),
53 frame->natural_size(), frame->timestamp());
55 if (frame->HasTextures()) {
56 DCHECK(frame->format() == media::PIXEL_FORMAT_ARGB ||
57 frame->format() == media::PIXEL_FORMAT_XRGB);
58 SkBitmap bitmap;
59 bitmap.allocN32Pixels(frame->visible_rect().width(),
60 frame->visible_rect().height());
61 SkCanvas canvas(bitmap);
63 cc::ContextProvider* const provider =
64 RenderThreadImpl::current()->SharedMainThreadContextProvider().get();
65 if (provider) {
66 const media::Context3D context_3d =
67 media::Context3D(provider->ContextGL(), provider->GrContext());
68 DCHECK(context_3d.gl);
69 video_renderer->Copy(frame.get(), &canvas, context_3d);
70 } else {
71 // GPU Process crashed.
72 bitmap.eraseColor(SK_ColorTRANSPARENT);
74 media::CopyRGBToVideoFrame(reinterpret_cast<uint8*>(bitmap.getPixels()),
75 bitmap.rowBytes(),
76 frame->visible_rect(),
77 new_frame.get());
78 } else {
79 DCHECK(frame->IsMappable());
80 DCHECK(frame->format() == media::PIXEL_FORMAT_YV12 ||
81 frame->format() == media::PIXEL_FORMAT_I420);
82 for (size_t i = 0; i < media::VideoFrame::NumPlanes(frame->format()); ++i) {
83 media::CopyPlane(i, frame->data(i), frame->stride(i),
84 frame->rows(i), new_frame.get());
87 return new_frame;
90 } // anonymous namespace
92 WebMediaPlayerMS::WebMediaPlayerMS(
93 blink::WebFrame* frame,
94 blink::WebMediaPlayerClient* client,
95 base::WeakPtr<media::WebMediaPlayerDelegate> delegate,
96 media::MediaLog* media_log,
97 scoped_ptr<MediaStreamRendererFactory> factory,
98 const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner)
99 : frame_(frame),
100 network_state_(WebMediaPlayer::NetworkStateEmpty),
101 ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
102 buffered_(static_cast<size_t>(0)),
103 volume_(1.0f),
104 client_(client),
105 delegate_(delegate),
106 paused_(true),
107 received_first_frame_(false),
108 media_log_(media_log),
109 renderer_factory_(factory.Pass()),
110 compositor_(new Compositor(compositor_task_runner)),
111 compositor_task_runner_(compositor_task_runner) {
112 DVLOG(1) << "WebMediaPlayerMS::ctor";
113 media_log_->AddEvent(
114 media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_CREATED));
117 WebMediaPlayerMS::~WebMediaPlayerMS() {
118 DVLOG(1) << "WebMediaPlayerMS::dtor";
119 DCHECK(thread_checker_.CalledOnValidThread());
121 compositor_task_runner_->DeleteSoon(FROM_HERE, compositor_.release());
123 GetClient()->setWebLayer(NULL);
125 if (video_frame_provider_.get())
126 video_frame_provider_->Stop();
128 if (audio_renderer_.get())
129 audio_renderer_->Stop();
131 media_log_->AddEvent(
132 media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
134 if (delegate_.get())
135 delegate_->PlayerGone(this);
138 void WebMediaPlayerMS::load(LoadType load_type,
139 const blink::WebURL& url,
140 CORSMode cors_mode) {
141 DVLOG(1) << "WebMediaPlayerMS::load";
142 DCHECK(thread_checker_.CalledOnValidThread());
144 // TODO(acolwell): Change this to DCHECK_EQ(load_type,
145 // LoadTypeMediaStream) once Blink-side changes land.
146 DCHECK_NE(load_type, LoadTypeMediaSource);
148 GURL gurl(url);
150 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
151 SetReadyState(WebMediaPlayer::ReadyStateHaveNothing);
152 media_log_->AddEvent(media_log_->CreateLoadEvent(url.spec()));
154 video_frame_provider_ = renderer_factory_->GetVideoFrameProvider(
155 url,
156 base::Bind(&WebMediaPlayerMS::OnSourceError, AsWeakPtr()),
157 base::Bind(&WebMediaPlayerMS::OnFrameAvailable, AsWeakPtr()));
159 RenderFrame* const frame = RenderFrame::FromWebFrame(frame_);
160 audio_renderer_ = renderer_factory_->GetAudioRenderer(
161 url,
162 frame->GetRoutingID());
164 if (!video_frame_provider_ && !audio_renderer_) {
165 SetNetworkState(WebMediaPlayer::NetworkStateNetworkError);
166 return;
169 if (audio_renderer_) {
170 audio_renderer_->SetVolume(volume_);
171 audio_renderer_->Start();
173 if (video_frame_provider_)
174 video_frame_provider_->Start();
175 if (audio_renderer_ && !video_frame_provider_) {
176 // This is audio-only mode.
177 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
178 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
182 void WebMediaPlayerMS::play() {
183 DVLOG(1) << "WebMediaPlayerMS::play";
184 DCHECK(thread_checker_.CalledOnValidThread());
186 if (paused_) {
187 if (video_frame_provider_.get())
188 video_frame_provider_->Play();
190 compositor_task_runner_->PostTask(
191 FROM_HERE, base::Bind(&WebMediaPlayerMS::Compositor::StartRendering,
192 base::Unretained(compositor_.get())));
194 if (audio_renderer_.get())
195 audio_renderer_->Play();
197 if (delegate_.get())
198 delegate_->DidPlay(this);
201 paused_ = false;
203 media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PLAY));
206 void WebMediaPlayerMS::pause() {
207 DVLOG(1) << "WebMediaPlayerMS::pause";
208 DCHECK(thread_checker_.CalledOnValidThread());
210 if (video_frame_provider_.get())
211 video_frame_provider_->Pause();
213 compositor_task_runner_->PostTask(
214 FROM_HERE, base::Bind(&WebMediaPlayerMS::Compositor::StopRendering,
215 base::Unretained(compositor_.get())));
216 compositor_->ReplaceCurrentFrameWithACopy(&video_renderer_);
218 if (!paused_) {
219 if (audio_renderer_.get())
220 audio_renderer_->Pause();
222 if (delegate_.get())
223 delegate_->DidPause(this);
226 paused_ = true;
228 media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PAUSE));
231 bool WebMediaPlayerMS::supportsSave() const {
232 DCHECK(thread_checker_.CalledOnValidThread());
233 return false;
236 void WebMediaPlayerMS::seek(double seconds) {
237 DCHECK(thread_checker_.CalledOnValidThread());
240 void WebMediaPlayerMS::setRate(double rate) {
241 DCHECK(thread_checker_.CalledOnValidThread());
244 void WebMediaPlayerMS::setVolume(double volume) {
245 DCHECK(thread_checker_.CalledOnValidThread());
246 DVLOG(1) << "WebMediaPlayerMS::setVolume(volume=" << volume << ")";
247 volume_ = volume;
248 if (audio_renderer_.get())
249 audio_renderer_->SetVolume(volume_);
252 void WebMediaPlayerMS::setSinkId(const blink::WebString& device_id,
253 media::WebSetSinkIdCB* web_callback) {
254 DCHECK(thread_checker_.CalledOnValidThread());
255 DVLOG(1) << __FUNCTION__;
256 media::SwitchOutputDeviceCB callback =
257 media::ConvertToSwitchOutputDeviceCB(web_callback);
258 if (audio_renderer_.get()) {
259 media::OutputDevice* output_device = audio_renderer_->GetOutputDevice();
260 if (output_device) {
261 const std::string device_id_str(device_id.utf8());
262 const GURL security_origin(frame_->securityOrigin().toString().utf8());
263 output_device->SwitchOutputDevice(device_id_str, security_origin,
264 callback);
265 return;
268 callback.Run(media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_SUPPORTED);
271 void WebMediaPlayerMS::setPreload(WebMediaPlayer::Preload preload) {
272 DCHECK(thread_checker_.CalledOnValidThread());
275 bool WebMediaPlayerMS::hasVideo() const {
276 DCHECK(thread_checker_.CalledOnValidThread());
277 return (video_frame_provider_.get() != NULL);
280 bool WebMediaPlayerMS::hasAudio() const {
281 DCHECK(thread_checker_.CalledOnValidThread());
282 return (audio_renderer_.get() != NULL);
285 blink::WebSize WebMediaPlayerMS::naturalSize() const {
286 DCHECK(thread_checker_.CalledOnValidThread());
288 gfx::Size size = compositor_->GetCurrentSize();
290 DVLOG(3) << "WebMediaPlayerMS::naturalSize, " << size.ToString();
291 return blink::WebSize(size);
294 bool WebMediaPlayerMS::paused() const {
295 DCHECK(thread_checker_.CalledOnValidThread());
296 return paused_;
299 bool WebMediaPlayerMS::seeking() const {
300 DCHECK(thread_checker_.CalledOnValidThread());
301 return false;
304 double WebMediaPlayerMS::duration() const {
305 DCHECK(thread_checker_.CalledOnValidThread());
306 return std::numeric_limits<double>::infinity();
309 double WebMediaPlayerMS::currentTime() const {
310 DCHECK(thread_checker_.CalledOnValidThread());
311 base::TimeDelta current_time = compositor_->GetCurrentTime();
312 if (current_time.ToInternalValue() != 0) {
313 return current_time.InSecondsF();
314 } else if (audio_renderer_.get()) {
315 return audio_renderer_->GetCurrentRenderTime().InSecondsF();
317 return 0.0;
320 WebMediaPlayer::NetworkState WebMediaPlayerMS::networkState() const {
321 DCHECK(thread_checker_.CalledOnValidThread());
322 DVLOG(1) << "WebMediaPlayerMS::networkState, state:" << network_state_;
323 return network_state_;
326 WebMediaPlayer::ReadyState WebMediaPlayerMS::readyState() const {
327 DCHECK(thread_checker_.CalledOnValidThread());
328 DVLOG(1) << "WebMediaPlayerMS::readyState, state:" << ready_state_;
329 return ready_state_;
332 blink::WebTimeRanges WebMediaPlayerMS::buffered() const {
333 DCHECK(thread_checker_.CalledOnValidThread());
334 return buffered_;
337 blink::WebTimeRanges WebMediaPlayerMS::seekable() const {
338 DCHECK(thread_checker_.CalledOnValidThread());
339 return blink::WebTimeRanges();
342 bool WebMediaPlayerMS::didLoadingProgress() {
343 DCHECK(thread_checker_.CalledOnValidThread());
344 return true;
347 void WebMediaPlayerMS::paint(blink::WebCanvas* canvas,
348 const blink::WebRect& rect,
349 unsigned char alpha,
350 SkXfermode::Mode mode) {
351 DVLOG(3) << "WebMediaPlayerMS::paint";
352 DCHECK(thread_checker_.CalledOnValidThread());
354 scoped_refptr<media::VideoFrame> frame = compositor_->GetCurrentFrame();
356 media::Context3D context_3d;
357 if (frame.get() && frame->HasTextures()) {
358 cc::ContextProvider* provider =
359 RenderThreadImpl::current()->SharedMainThreadContextProvider().get();
360 // GPU Process crashed.
361 if (!provider)
362 return;
363 context_3d = media::Context3D(provider->ContextGL(), provider->GrContext());
364 DCHECK(context_3d.gl);
366 gfx::RectF dest_rect(rect.x, rect.y, rect.width, rect.height);
367 video_renderer_.Paint(frame, canvas, dest_rect, alpha, mode,
368 media::VIDEO_ROTATION_0, context_3d);
371 bool WebMediaPlayerMS::hasSingleSecurityOrigin() const {
372 DCHECK(thread_checker_.CalledOnValidThread());
373 return true;
376 bool WebMediaPlayerMS::didPassCORSAccessCheck() const {
377 DCHECK(thread_checker_.CalledOnValidThread());
378 return true;
381 double WebMediaPlayerMS::mediaTimeForTimeValue(double timeValue) const {
382 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF();
385 unsigned WebMediaPlayerMS::decodedFrameCount() const {
386 DCHECK(thread_checker_.CalledOnValidThread());
387 unsigned total_frame_count = compositor_->GetTotalFrameCount();
388 DVLOG(1) << "WebMediaPlayerMS::decodedFrameCount, " << total_frame_count;
389 return total_frame_count;
392 unsigned WebMediaPlayerMS::droppedFrameCount() const {
393 DCHECK(thread_checker_.CalledOnValidThread());
394 unsigned dropped_frame_count = compositor_->GetDroppedFrameCount();
395 DVLOG(1) << "WebMediaPlayerMS::droppedFrameCount, " << dropped_frame_count;
396 return dropped_frame_count;
399 unsigned WebMediaPlayerMS::audioDecodedByteCount() const {
400 DCHECK(thread_checker_.CalledOnValidThread());
401 NOTIMPLEMENTED();
402 return 0;
405 unsigned WebMediaPlayerMS::videoDecodedByteCount() const {
406 DCHECK(thread_checker_.CalledOnValidThread());
407 NOTIMPLEMENTED();
408 return 0;
411 bool WebMediaPlayerMS::copyVideoTextureToPlatformTexture(
412 blink::WebGraphicsContext3D* web_graphics_context,
413 unsigned int texture,
414 unsigned int internal_format,
415 unsigned int type,
416 bool premultiply_alpha,
417 bool flip_y) {
418 TRACE_EVENT0("media", "WebMediaPlayerMS:copyVideoTextureToPlatformTexture");
419 DCHECK(thread_checker_.CalledOnValidThread());
421 scoped_refptr<media::VideoFrame> video_frame = compositor_->GetCurrentFrame();
423 if (!video_frame.get() || video_frame->HasTextures() ||
424 media::VideoFrame::NumPlanes(video_frame->format()) != 1) {
425 return false;
428 // TODO(dshwang): need more elegant way to convert WebGraphicsContext3D to
429 // GLES2Interface.
430 gpu::gles2::GLES2Interface* const gl =
431 static_cast<gpu_blink::WebGraphicsContext3DImpl*>(web_graphics_context)
432 ->GetGLInterface();
433 media::SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
434 gl, video_frame.get(), texture, internal_format, type, premultiply_alpha,
435 flip_y);
436 return true;
439 void WebMediaPlayerMS::OnFrameAvailable(
440 const scoped_refptr<media::VideoFrame>& frame) {
441 DVLOG(3) << "WebMediaPlayerMS::OnFrameAvailable";
442 DCHECK(thread_checker_.CalledOnValidThread());
444 base::TimeTicks render_time;
445 if (!frame->metadata()->GetTimeTicks(
446 media::VideoFrameMetadata::REFERENCE_TIME, &render_time)) {
447 render_time = base::TimeTicks();
449 TRACE_EVENT1("webrtc", "WebMediaPlayerMS::OnFrameAvailable",
450 "Ideal Render Instant", render_time.ToInternalValue());
452 if (!received_first_frame_) {
453 received_first_frame_ = true;
454 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
455 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
457 if (video_frame_provider_.get()) {
458 video_weblayer_.reset(new cc_blink::WebLayerImpl(
459 cc::VideoLayer::Create(cc_blink::WebLayerImpl::LayerSettings(),
460 compositor_.get(), media::VIDEO_ROTATION_0)));
461 video_weblayer_->layer()->SetContentsOpaque(true);
462 video_weblayer_->SetContentsOpaqueIsFixed(true);
463 GetClient()->setWebLayer(video_weblayer_.get());
467 bool size_changed = compositor_->GetCurrentSize() != frame->natural_size();
469 compositor_->EnqueueFrame(frame);
471 if (size_changed)
472 GetClient()->sizeChanged();
475 void WebMediaPlayerMS::RepaintInternal() {
476 DVLOG(1) << "WebMediaPlayerMS::RepaintInternal";
477 DCHECK(thread_checker_.CalledOnValidThread());
478 GetClient()->repaint();
481 void WebMediaPlayerMS::OnSourceError() {
482 DVLOG(1) << "WebMediaPlayerMS::OnSourceError";
483 DCHECK(thread_checker_.CalledOnValidThread());
484 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
485 RepaintInternal();
488 void WebMediaPlayerMS::SetNetworkState(WebMediaPlayer::NetworkState state) {
489 DCHECK(thread_checker_.CalledOnValidThread());
490 network_state_ = state;
491 // Always notify to ensure client has the latest value.
492 GetClient()->networkStateChanged();
495 void WebMediaPlayerMS::SetReadyState(WebMediaPlayer::ReadyState state) {
496 DCHECK(thread_checker_.CalledOnValidThread());
497 ready_state_ = state;
498 // Always notify to ensure client has the latest value.
499 GetClient()->readyStateChanged();
502 blink::WebMediaPlayerClient* WebMediaPlayerMS::GetClient() {
503 DCHECK(thread_checker_.CalledOnValidThread());
504 DCHECK(client_);
505 return client_;
508 WebMediaPlayerMS::Compositor::Compositor(
509 const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner)
510 : compositor_task_runner_(compositor_task_runner),
511 video_frame_provider_client_(NULL),
512 current_frame_used_(false),
513 last_deadline_max_(base::TimeTicks()),
514 total_frame_count_(0),
515 dropped_frame_count_(0),
516 paused_(false) {}
518 WebMediaPlayerMS::Compositor::~Compositor() {
519 DCHECK(compositor_task_runner_->BelongsToCurrentThread());
520 if (video_frame_provider_client_)
521 video_frame_provider_client_->StopUsingProvider();
524 void WebMediaPlayerMS::Compositor::EnqueueFrame(
525 scoped_refptr<media::VideoFrame> const& frame) {
526 base::AutoLock auto_lock(current_frame_lock_);
527 ++total_frame_count_;
529 if (base::TimeTicks::Now() > last_deadline_max_) {
530 // TODO(qiangchen): This shows vsyncs stops rendering frames. A probable
531 // cause is that the tab is not in the front. But we still have to let
532 // old frames go. Call VRA::RemoveExpiredFrames.
536 if (!current_frame_used_) {
537 ++dropped_frame_count_;
540 // TODO(qiangchen): Instead of using one variable to hold one frame, use
541 // VideoRendererAlgorithm.
542 current_frame_ = frame;
543 current_frame_used_ = false;
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;
556 // TODO(dalecurtis): This should make use of the deadline interval to ensure
557 // the painted frame is correct for the given interval.
559 if (paused_)
560 return false;
563 base::TimeTicks render_time;
564 if (!current_frame_->metadata()->GetTimeTicks(
565 media::VideoFrameMetadata::REFERENCE_TIME, &render_time)) {
566 render_time = base::TimeTicks();
568 TRACE_EVENT_END1("webrtc", "WebMediaPlayerMS::UpdateCurrentFrame",
569 "Ideal Render Instant", render_time.ToInternalValue());
570 return !current_frame_used_;
573 bool WebMediaPlayerMS::Compositor::HasCurrentFrame() {
574 base::AutoLock auto_lock(current_frame_lock_);
575 return !!current_frame_.get();
578 scoped_refptr<media::VideoFrame>
579 WebMediaPlayerMS::Compositor::GetCurrentFrame() {
580 DVLOG(3) << "WebMediaPlayerMS::Compositor::GetCurrentFrame";
581 base::AutoLock auto_lock(current_frame_lock_);
582 if (!current_frame_.get())
583 return NULL;
584 return current_frame_;
587 void WebMediaPlayerMS::Compositor::PutCurrentFrame() {
588 DVLOG(3) << "WebMediaPlayerMS::PutCurrentFrame";
589 current_frame_used_ = true;
592 void WebMediaPlayerMS::Compositor::SetVideoFrameProviderClient(
593 cc::VideoFrameProvider::Client* client) {
594 DCHECK(compositor_task_runner_->BelongsToCurrentThread());
595 if (video_frame_provider_client_)
596 video_frame_provider_client_->StopUsingProvider();
598 video_frame_provider_client_ = client;
599 if (video_frame_provider_client_)
600 video_frame_provider_client_->StartRendering();
603 void WebMediaPlayerMS::Compositor::StartRendering() {
604 DCHECK(compositor_task_runner_->BelongsToCurrentThread());
605 paused_ = false;
606 if (video_frame_provider_client_)
607 video_frame_provider_client_->StartRendering();
610 void WebMediaPlayerMS::Compositor::StopRendering() {
611 DCHECK(compositor_task_runner_->BelongsToCurrentThread());
612 paused_ = true;
613 if (video_frame_provider_client_)
614 video_frame_provider_client_->StopRendering();
617 void WebMediaPlayerMS::Compositor::ReplaceCurrentFrameWithACopy(
618 media::SkCanvasVideoRenderer* renderer) {
619 base::AutoLock auto_lock(current_frame_lock_);
620 if (!current_frame_.get())
621 return;
623 // Copy the frame so that rendering can show the last received frame.
624 // The original frame must not be referenced when the player is paused since
625 // there might be a finite number of available buffers. E.g, video that
626 // originates from a video camera.
627 scoped_refptr<media::VideoFrame> new_frame =
628 CopyFrameToYV12(current_frame_, renderer);
630 current_frame_ = new_frame;
633 gfx::Size WebMediaPlayerMS::Compositor::GetCurrentSize() {
634 base::AutoLock auto_lock(current_frame_lock_);
635 return current_frame_.get() ? current_frame_->natural_size() : gfx::Size();
638 base::TimeDelta WebMediaPlayerMS::Compositor::GetCurrentTime() {
639 base::AutoLock auto_lock(current_frame_lock_);
640 return current_frame_.get() ? current_frame_->timestamp() : base::TimeDelta();
643 unsigned WebMediaPlayerMS::Compositor::GetTotalFrameCount() {
644 return total_frame_count_;
647 unsigned WebMediaPlayerMS::Compositor::GetDroppedFrameCount() {
648 return dropped_frame_count_;
650 } // namespace content