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"
10 #include "base/callback.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/metrics/histogram.h"
13 #include "cc/blink/web_layer_impl.h"
14 #include "cc/layers/video_layer.h"
15 #include "content/public/renderer/render_view.h"
16 #include "content/renderer/media/media_stream_audio_renderer.h"
17 #include "content/renderer/media/media_stream_renderer_factory.h"
18 #include "content/renderer/media/video_frame_provider.h"
19 #include "content/renderer/media/webmediaplayer_delegate.h"
20 #include "content/renderer/media/webmediaplayer_util.h"
21 #include "content/renderer/render_frame_impl.h"
22 #include "media/base/media_log.h"
23 #include "media/base/video_frame.h"
24 #include "media/base/video_rotation.h"
25 #include "media/base/video_util.h"
26 #include "third_party/WebKit/public/platform/WebMediaPlayerClient.h"
27 #include "third_party/WebKit/public/platform/WebRect.h"
28 #include "third_party/WebKit/public/platform/WebSize.h"
29 #include "third_party/WebKit/public/platform/WebURL.h"
30 #include "third_party/WebKit/public/web/WebFrame.h"
31 #include "third_party/WebKit/public/web/WebView.h"
32 #include "third_party/skia/include/core/SkBitmap.h"
34 using blink::WebCanvas
;
35 using blink::WebMediaPlayer
;
41 // This function copies a YV12 or NATIVE_TEXTURE to a new YV12
43 scoped_refptr
<media::VideoFrame
> CopyFrameToYV12(
44 const scoped_refptr
<media::VideoFrame
>& frame
) {
45 DCHECK(frame
->format() == media::VideoFrame::YV12
||
46 frame
->format() == media::VideoFrame::I420
||
47 frame
->format() == media::VideoFrame::NATIVE_TEXTURE
);
48 scoped_refptr
<media::VideoFrame
> new_frame
=
49 media::VideoFrame::CreateFrame(media::VideoFrame::YV12
,
51 frame
->visible_rect(),
52 frame
->natural_size(),
55 if (frame
->format() == media::VideoFrame::NATIVE_TEXTURE
) {
57 bitmap
.allocN32Pixels(frame
->visible_rect().width(),
58 frame
->visible_rect().height());
59 frame
->ReadPixelsFromNativeTexture(bitmap
);
61 media::CopyRGBToVideoFrame(
62 reinterpret_cast<uint8
*>(bitmap
.getPixels()),
64 frame
->visible_rect(),
67 size_t number_of_planes
=
68 media::VideoFrame::NumPlanes(frame
->format());
69 for (size_t i
= 0; i
< number_of_planes
; ++i
) {
70 media::CopyPlane(i
, frame
->data(i
), frame
->stride(i
),
71 frame
->rows(i
), new_frame
.get());
77 } // anonymous namespace
81 WebMediaPlayerMS::WebMediaPlayerMS(
82 blink::WebFrame
* frame
,
83 blink::WebMediaPlayerClient
* client
,
84 base::WeakPtr
<WebMediaPlayerDelegate
> delegate
,
85 media::MediaLog
* media_log
,
86 scoped_ptr
<MediaStreamRendererFactory
> factory
)
88 network_state_(WebMediaPlayer::NetworkStateEmpty
),
89 ready_state_(WebMediaPlayer::ReadyStateHaveNothing
),
90 buffered_(static_cast<size_t>(1)),
95 current_frame_used_(false),
96 pending_repaint_(false),
97 video_frame_provider_client_(NULL
),
98 received_first_frame_(false),
99 total_frame_count_(0),
100 dropped_frame_count_(0),
101 media_log_(media_log
),
102 renderer_factory_(factory
.Pass()) {
103 DVLOG(1) << "WebMediaPlayerMS::ctor";
104 media_log_
->AddEvent(
105 media_log_
->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_CREATED
));
108 WebMediaPlayerMS::~WebMediaPlayerMS() {
109 DVLOG(1) << "WebMediaPlayerMS::dtor";
110 DCHECK(thread_checker_
.CalledOnValidThread());
112 SetVideoFrameProviderClient(NULL
);
113 GetClient()->setWebLayer(NULL
);
115 if (video_frame_provider_
.get())
116 video_frame_provider_
->Stop();
118 if (audio_renderer_
.get())
119 audio_renderer_
->Stop();
121 media_log_
->AddEvent(
122 media_log_
->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_DESTROYED
));
125 delegate_
->PlayerGone(this);
128 void WebMediaPlayerMS::load(LoadType load_type
,
129 const blink::WebURL
& url
,
130 CORSMode cors_mode
) {
131 DVLOG(1) << "WebMediaPlayerMS::load";
132 DCHECK(thread_checker_
.CalledOnValidThread());
134 // TODO(acolwell): Change this to DCHECK_EQ(load_type,
135 // LoadTypeMediaStream) once Blink-side changes land.
136 DCHECK_NE(load_type
, LoadTypeMediaSource
);
140 SetNetworkState(WebMediaPlayer::NetworkStateLoading
);
141 SetReadyState(WebMediaPlayer::ReadyStateHaveNothing
);
142 media_log_
->AddEvent(media_log_
->CreateLoadEvent(url
.spec()));
144 video_frame_provider_
= renderer_factory_
->GetVideoFrameProvider(
146 base::Bind(&WebMediaPlayerMS::OnSourceError
, AsWeakPtr()),
147 base::Bind(&WebMediaPlayerMS::OnFrameAvailable
, AsWeakPtr()));
149 RenderFrame
* frame
= RenderFrame::FromWebFrame(frame_
);
150 audio_renderer_
= renderer_factory_
->GetAudioRenderer(
152 frame
->GetRenderView()->GetRoutingID(),
153 frame
->GetRoutingID());
155 if (video_frame_provider_
.get() || audio_renderer_
.get()) {
156 if (audio_renderer_
.get()) {
157 audio_renderer_
->SetVolume(volume_
);
158 audio_renderer_
->Start();
161 if (video_frame_provider_
.get()) {
162 video_frame_provider_
->Start();
164 // This is audio-only mode.
165 DCHECK(audio_renderer_
.get());
166 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata
);
167 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData
);
170 SetNetworkState(WebMediaPlayer::NetworkStateNetworkError
);
174 void WebMediaPlayerMS::play() {
175 DVLOG(1) << "WebMediaPlayerMS::play";
176 DCHECK(thread_checker_
.CalledOnValidThread());
179 if (video_frame_provider_
.get())
180 video_frame_provider_
->Play();
182 if (audio_renderer_
.get())
183 audio_renderer_
->Play();
186 delegate_
->DidPlay(this);
191 media_log_
->AddEvent(media_log_
->CreateEvent(media::MediaLogEvent::PLAY
));
194 void WebMediaPlayerMS::pause() {
195 DVLOG(1) << "WebMediaPlayerMS::pause";
196 DCHECK(thread_checker_
.CalledOnValidThread());
198 if (video_frame_provider_
.get())
199 video_frame_provider_
->Pause();
202 if (audio_renderer_
.get())
203 audio_renderer_
->Pause();
206 delegate_
->DidPause(this);
211 media_log_
->AddEvent(media_log_
->CreateEvent(media::MediaLogEvent::PAUSE
));
213 if (!current_frame_
.get())
216 // Copy the frame so that rendering can show the last received frame.
217 // The original frame must not be referenced when the player is paused since
218 // there might be a finite number of available buffers. E.g, video that
219 // originates from a video camera.
220 scoped_refptr
<media::VideoFrame
> new_frame
= CopyFrameToYV12(current_frame_
);
221 base::AutoLock
auto_lock(current_frame_lock_
);
222 current_frame_
= new_frame
;
225 bool WebMediaPlayerMS::supportsSave() const {
226 DCHECK(thread_checker_
.CalledOnValidThread());
230 void WebMediaPlayerMS::seek(double seconds
) {
231 DCHECK(thread_checker_
.CalledOnValidThread());
234 void WebMediaPlayerMS::setRate(double rate
) {
235 DCHECK(thread_checker_
.CalledOnValidThread());
238 void WebMediaPlayerMS::setVolume(double volume
) {
239 DCHECK(thread_checker_
.CalledOnValidThread());
240 DVLOG(1) << "WebMediaPlayerMS::setVolume(volume=" << volume
<< ")";
242 if (audio_renderer_
.get())
243 audio_renderer_
->SetVolume(volume_
);
246 void WebMediaPlayerMS::setPreload(WebMediaPlayer::Preload preload
) {
247 DCHECK(thread_checker_
.CalledOnValidThread());
250 bool WebMediaPlayerMS::hasVideo() const {
251 DCHECK(thread_checker_
.CalledOnValidThread());
252 return (video_frame_provider_
.get() != NULL
);
255 bool WebMediaPlayerMS::hasAudio() const {
256 DCHECK(thread_checker_
.CalledOnValidThread());
257 return (audio_renderer_
.get() != NULL
);
260 blink::WebSize
WebMediaPlayerMS::naturalSize() const {
261 DCHECK(thread_checker_
.CalledOnValidThread());
264 if (current_frame_
.get())
265 size
= current_frame_
->natural_size();
266 DVLOG(3) << "WebMediaPlayerMS::naturalSize, " << size
.ToString();
267 return blink::WebSize(size
);
270 bool WebMediaPlayerMS::paused() const {
271 DCHECK(thread_checker_
.CalledOnValidThread());
275 bool WebMediaPlayerMS::seeking() const {
276 DCHECK(thread_checker_
.CalledOnValidThread());
280 double WebMediaPlayerMS::duration() const {
281 DCHECK(thread_checker_
.CalledOnValidThread());
282 return std::numeric_limits
<double>::infinity();
285 double WebMediaPlayerMS::currentTime() const {
286 DCHECK(thread_checker_
.CalledOnValidThread());
287 if (current_time_
.ToInternalValue() != 0) {
288 return current_time_
.InSecondsF();
289 } else if (audio_renderer_
.get()) {
290 return audio_renderer_
->GetCurrentRenderTime().InSecondsF();
295 WebMediaPlayer::NetworkState
WebMediaPlayerMS::networkState() const {
296 DCHECK(thread_checker_
.CalledOnValidThread());
297 DVLOG(1) << "WebMediaPlayerMS::networkState, state:" << network_state_
;
298 return network_state_
;
301 WebMediaPlayer::ReadyState
WebMediaPlayerMS::readyState() const {
302 DCHECK(thread_checker_
.CalledOnValidThread());
303 DVLOG(1) << "WebMediaPlayerMS::readyState, state:" << ready_state_
;
307 blink::WebTimeRanges
WebMediaPlayerMS::buffered() const {
308 DCHECK(thread_checker_
.CalledOnValidThread());
312 double WebMediaPlayerMS::maxTimeSeekable() const {
313 DCHECK(thread_checker_
.CalledOnValidThread());
317 bool WebMediaPlayerMS::didLoadingProgress() {
318 DCHECK(thread_checker_
.CalledOnValidThread());
322 void WebMediaPlayerMS::paint(blink::WebCanvas
* canvas
,
323 const blink::WebRect
& rect
,
324 unsigned char alpha
) {
325 paint(canvas
, rect
, alpha
, SkXfermode::kSrcOver_Mode
);
328 void WebMediaPlayerMS::paint(blink::WebCanvas
* canvas
,
329 const blink::WebRect
& rect
,
331 SkXfermode::Mode mode
) {
332 DVLOG(3) << "WebMediaPlayerMS::paint";
333 DCHECK(thread_checker_
.CalledOnValidThread());
335 gfx::RectF
dest_rect(rect
.x
, rect
.y
, rect
.width
, rect
.height
);
336 video_renderer_
.Paint(current_frame_
.get(),
341 media::VIDEO_ROTATION_0
);
344 base::AutoLock
auto_lock(current_frame_lock_
);
345 if (current_frame_
.get())
346 current_frame_used_
= true;
350 bool WebMediaPlayerMS::hasSingleSecurityOrigin() const {
351 DCHECK(thread_checker_
.CalledOnValidThread());
355 bool WebMediaPlayerMS::didPassCORSAccessCheck() const {
356 DCHECK(thread_checker_
.CalledOnValidThread());
360 double WebMediaPlayerMS::mediaTimeForTimeValue(double timeValue
) const {
361 return ConvertSecondsToTimestamp(timeValue
).InSecondsF();
364 unsigned WebMediaPlayerMS::decodedFrameCount() const {
365 DCHECK(thread_checker_
.CalledOnValidThread());
366 DVLOG(1) << "WebMediaPlayerMS::decodedFrameCount, " << total_frame_count_
;
367 return total_frame_count_
;
370 unsigned WebMediaPlayerMS::droppedFrameCount() const {
371 DCHECK(thread_checker_
.CalledOnValidThread());
372 DVLOG(1) << "WebMediaPlayerMS::droppedFrameCount, " << dropped_frame_count_
;
373 return dropped_frame_count_
;
376 unsigned WebMediaPlayerMS::audioDecodedByteCount() const {
377 DCHECK(thread_checker_
.CalledOnValidThread());
382 unsigned WebMediaPlayerMS::videoDecodedByteCount() const {
383 DCHECK(thread_checker_
.CalledOnValidThread());
388 void WebMediaPlayerMS::SetVideoFrameProviderClient(
389 cc::VideoFrameProvider::Client
* client
) {
390 // This is called from both the main renderer thread and the compositor
391 // thread (when the main thread is blocked).
392 if (video_frame_provider_client_
)
393 video_frame_provider_client_
->StopUsingProvider();
394 video_frame_provider_client_
= client
;
397 scoped_refptr
<media::VideoFrame
> WebMediaPlayerMS::GetCurrentFrame() {
398 DVLOG(3) << "WebMediaPlayerMS::GetCurrentFrame";
399 base::AutoLock
auto_lock(current_frame_lock_
);
400 DCHECK(!pending_repaint_
);
401 if (!current_frame_
.get())
403 pending_repaint_
= true;
404 current_frame_used_
= true;
405 return current_frame_
;
408 void WebMediaPlayerMS::PutCurrentFrame(
409 const scoped_refptr
<media::VideoFrame
>& frame
) {
410 DVLOG(3) << "WebMediaPlayerMS::PutCurrentFrame";
411 DCHECK(pending_repaint_
);
412 pending_repaint_
= false;
415 void WebMediaPlayerMS::OnFrameAvailable(
416 const scoped_refptr
<media::VideoFrame
>& frame
) {
417 DVLOG(3) << "WebMediaPlayerMS::OnFrameAvailable";
418 DCHECK(thread_checker_
.CalledOnValidThread());
419 ++total_frame_count_
;
420 if (!received_first_frame_
) {
421 received_first_frame_
= true;
423 base::AutoLock
auto_lock(current_frame_lock_
);
424 DCHECK(!current_frame_used_
);
425 current_frame_
= frame
;
427 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata
);
428 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData
);
429 GetClient()->sizeChanged();
431 if (video_frame_provider_
.get()) {
432 video_weblayer_
.reset(new cc_blink::WebLayerImpl(
433 cc::VideoLayer::Create(this, media::VIDEO_ROTATION_0
)));
434 video_weblayer_
->setOpaque(true);
435 GetClient()->setWebLayer(video_weblayer_
.get());
439 // Do not update |current_frame_| when paused.
443 bool size_changed
= !current_frame_
.get() ||
444 current_frame_
->natural_size() != frame
->natural_size();
447 base::AutoLock
auto_lock(current_frame_lock_
);
448 if (!current_frame_used_
&& current_frame_
.get())
449 ++dropped_frame_count_
;
450 current_frame_
= frame
;
451 current_time_
= frame
->timestamp();
452 current_frame_used_
= false;
456 GetClient()->sizeChanged();
458 GetClient()->repaint();
461 void WebMediaPlayerMS::RepaintInternal() {
462 DVLOG(1) << "WebMediaPlayerMS::RepaintInternal";
463 DCHECK(thread_checker_
.CalledOnValidThread());
464 GetClient()->repaint();
467 void WebMediaPlayerMS::OnSourceError() {
468 DVLOG(1) << "WebMediaPlayerMS::OnSourceError";
469 DCHECK(thread_checker_
.CalledOnValidThread());
470 SetNetworkState(WebMediaPlayer::NetworkStateFormatError
);
474 void WebMediaPlayerMS::SetNetworkState(WebMediaPlayer::NetworkState state
) {
475 DCHECK(thread_checker_
.CalledOnValidThread());
476 network_state_
= state
;
477 // Always notify to ensure client has the latest value.
478 GetClient()->networkStateChanged();
481 void WebMediaPlayerMS::SetReadyState(WebMediaPlayer::ReadyState state
) {
482 DCHECK(thread_checker_
.CalledOnValidThread());
483 ready_state_
= state
;
484 // Always notify to ensure client has the latest value.
485 GetClient()->readyStateChanged();
488 blink::WebMediaPlayerClient
* WebMediaPlayerMS::GetClient() {
489 DCHECK(thread_checker_
.CalledOnValidThread());
494 } // namespace content