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/layers/video_layer.h"
14 #include "content/public/renderer/render_view.h"
15 #include "content/renderer/media/media_stream_audio_renderer.h"
16 #include "content/renderer/media/media_stream_renderer_factory.h"
17 #include "content/renderer/media/video_frame_provider.h"
18 #include "content/renderer/media/webmediaplayer_delegate.h"
19 #include "content/renderer/media/webmediaplayer_util.h"
20 #include "content/renderer/render_frame_impl.h"
21 #include "media/base/media_log.h"
22 #include "media/base/video_frame.h"
23 #include "media/base/video_util.h"
24 #include "third_party/WebKit/public/platform/WebMediaPlayerClient.h"
25 #include "third_party/WebKit/public/platform/WebRect.h"
26 #include "third_party/WebKit/public/platform/WebSize.h"
27 #include "third_party/WebKit/public/platform/WebURL.h"
28 #include "third_party/WebKit/public/web/WebFrame.h"
29 #include "third_party/WebKit/public/web/WebView.h"
30 #include "third_party/skia/include/core/SkBitmap.h"
31 #include "webkit/renderer/compositor_bindings/web_layer_impl.h"
33 using blink::WebCanvas
;
34 using blink::WebMediaPlayer
;
40 // This function copies a YV12 or NATIVE_TEXTURE to a new YV12
42 scoped_refptr
<media::VideoFrame
> CopyFrameToYV12(
43 const scoped_refptr
<media::VideoFrame
>& frame
) {
44 DCHECK(frame
->format() == media::VideoFrame::YV12
||
45 frame
->format() == media::VideoFrame::I420
||
46 frame
->format() == media::VideoFrame::NATIVE_TEXTURE
);
47 scoped_refptr
<media::VideoFrame
> new_frame
=
48 media::VideoFrame::CreateFrame(media::VideoFrame::YV12
,
50 frame
->visible_rect(),
51 frame
->natural_size(),
54 if (frame
->format() == media::VideoFrame::NATIVE_TEXTURE
) {
56 bitmap
.allocN32Pixels(frame
->visible_rect().width(),
57 frame
->visible_rect().height());
58 frame
->ReadPixelsFromNativeTexture(bitmap
);
60 media::CopyRGBToVideoFrame(
61 reinterpret_cast<uint8
*>(bitmap
.getPixels()),
63 frame
->visible_rect(),
66 size_t number_of_planes
=
67 media::VideoFrame::NumPlanes(frame
->format());
68 for (size_t i
= 0; i
< number_of_planes
; ++i
) {
69 media::CopyPlane(i
, frame
->data(i
), frame
->stride(i
),
70 frame
->rows(i
), new_frame
.get());
76 } // anonymous namespace
80 WebMediaPlayerMS::WebMediaPlayerMS(
81 blink::WebFrame
* frame
,
82 blink::WebMediaPlayerClient
* client
,
83 base::WeakPtr
<WebMediaPlayerDelegate
> delegate
,
84 media::MediaLog
* media_log
,
85 scoped_ptr
<MediaStreamRendererFactory
> factory
)
87 network_state_(WebMediaPlayer::NetworkStateEmpty
),
88 ready_state_(WebMediaPlayer::ReadyStateHaveNothing
),
89 buffered_(static_cast<size_t>(1)),
93 current_frame_used_(false),
94 pending_repaint_(false),
95 video_frame_provider_client_(NULL
),
96 received_first_frame_(false),
97 total_frame_count_(0),
98 dropped_frame_count_(0),
99 media_log_(media_log
),
100 renderer_factory_(factory
.Pass()) {
101 DVLOG(1) << "WebMediaPlayerMS::ctor";
102 media_log_
->AddEvent(
103 media_log_
->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_CREATED
));
106 WebMediaPlayerMS::~WebMediaPlayerMS() {
107 DVLOG(1) << "WebMediaPlayerMS::dtor";
108 DCHECK(thread_checker_
.CalledOnValidThread());
110 SetVideoFrameProviderClient(NULL
);
111 GetClient()->setWebLayer(NULL
);
113 if (video_frame_provider_
.get())
114 video_frame_provider_
->Stop();
116 if (audio_renderer_
.get())
117 audio_renderer_
->Stop();
119 media_log_
->AddEvent(
120 media_log_
->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_DESTROYED
));
123 delegate_
->PlayerGone(this);
126 void WebMediaPlayerMS::load(LoadType load_type
,
127 const blink::WebURL
& url
,
128 CORSMode cors_mode
) {
129 DVLOG(1) << "WebMediaPlayerMS::load";
130 DCHECK(thread_checker_
.CalledOnValidThread());
132 // TODO(acolwell): Change this to DCHECK_EQ(load_type,
133 // LoadTypeMediaStream) once Blink-side changes land.
134 DCHECK_NE(load_type
, LoadTypeMediaSource
);
138 setVolume(GetClient()->volume());
139 SetNetworkState(WebMediaPlayer::NetworkStateLoading
);
140 SetReadyState(WebMediaPlayer::ReadyStateHaveNothing
);
141 media_log_
->AddEvent(media_log_
->CreateLoadEvent(url
.spec()));
143 video_frame_provider_
= renderer_factory_
->GetVideoFrameProvider(
145 base::Bind(&WebMediaPlayerMS::OnSourceError
, AsWeakPtr()),
146 base::Bind(&WebMediaPlayerMS::OnFrameAvailable
, AsWeakPtr()));
148 RenderFrame
* frame
= RenderFrame::FromWebFrame(frame_
);
149 audio_renderer_
= renderer_factory_
->GetAudioRenderer(
151 frame
->GetRenderView()->GetRoutingID(),
152 frame
->GetRoutingID());
154 if (video_frame_provider_
.get() || audio_renderer_
.get()) {
155 if (audio_renderer_
.get())
156 audio_renderer_
->Start();
158 if (video_frame_provider_
.get()) {
159 video_frame_provider_
->Start();
161 // This is audio-only mode.
162 DCHECK(audio_renderer_
.get());
163 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata
);
164 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData
);
167 SetNetworkState(WebMediaPlayer::NetworkStateNetworkError
);
171 void WebMediaPlayerMS::play() {
172 DVLOG(1) << "WebMediaPlayerMS::play";
173 DCHECK(thread_checker_
.CalledOnValidThread());
176 if (video_frame_provider_
.get())
177 video_frame_provider_
->Play();
179 if (audio_renderer_
.get())
180 audio_renderer_
->Play();
183 delegate_
->DidPlay(this);
188 media_log_
->AddEvent(media_log_
->CreateEvent(media::MediaLogEvent::PLAY
));
191 void WebMediaPlayerMS::pause() {
192 DVLOG(1) << "WebMediaPlayerMS::pause";
193 DCHECK(thread_checker_
.CalledOnValidThread());
195 if (video_frame_provider_
.get())
196 video_frame_provider_
->Pause();
199 if (audio_renderer_
.get())
200 audio_renderer_
->Pause();
203 delegate_
->DidPause(this);
208 media_log_
->AddEvent(media_log_
->CreateEvent(media::MediaLogEvent::PAUSE
));
213 // Copy the frame so that rendering can show the last received frame.
214 // The original frame must not be referenced when the player is paused since
215 // there might be a finite number of available buffers. E.g, video that
216 // originates from a video camera.
217 scoped_refptr
<media::VideoFrame
> new_frame
= CopyFrameToYV12(current_frame_
);
218 base::AutoLock
auto_lock(current_frame_lock_
);
219 current_frame_
= new_frame
;
222 bool WebMediaPlayerMS::supportsSave() const {
223 DCHECK(thread_checker_
.CalledOnValidThread());
227 void WebMediaPlayerMS::seek(double seconds
) {
228 DCHECK(thread_checker_
.CalledOnValidThread());
231 void WebMediaPlayerMS::setRate(double rate
) {
232 DCHECK(thread_checker_
.CalledOnValidThread());
235 void WebMediaPlayerMS::setVolume(double volume
) {
236 DCHECK(thread_checker_
.CalledOnValidThread());
237 if (!audio_renderer_
.get())
239 DVLOG(1) << "WebMediaPlayerMS::setVolume(volume=" << volume
<< ")";
240 audio_renderer_
->SetVolume(volume
);
243 void WebMediaPlayerMS::setPreload(WebMediaPlayer::Preload preload
) {
244 DCHECK(thread_checker_
.CalledOnValidThread());
247 bool WebMediaPlayerMS::hasVideo() const {
248 DCHECK(thread_checker_
.CalledOnValidThread());
249 return (video_frame_provider_
.get() != NULL
);
252 bool WebMediaPlayerMS::hasAudio() const {
253 DCHECK(thread_checker_
.CalledOnValidThread());
254 return (audio_renderer_
.get() != NULL
);
257 blink::WebSize
WebMediaPlayerMS::naturalSize() const {
258 DCHECK(thread_checker_
.CalledOnValidThread());
261 if (current_frame_
.get())
262 size
= current_frame_
->natural_size();
263 DVLOG(3) << "WebMediaPlayerMS::naturalSize, " << size
.ToString();
264 return blink::WebSize(size
);
267 bool WebMediaPlayerMS::paused() const {
268 DCHECK(thread_checker_
.CalledOnValidThread());
272 bool WebMediaPlayerMS::seeking() const {
273 DCHECK(thread_checker_
.CalledOnValidThread());
277 double WebMediaPlayerMS::duration() const {
278 DCHECK(thread_checker_
.CalledOnValidThread());
279 return std::numeric_limits
<double>::infinity();
282 double WebMediaPlayerMS::currentTime() const {
283 DCHECK(thread_checker_
.CalledOnValidThread());
284 if (current_time_
.ToInternalValue() != 0) {
285 return current_time_
.InSecondsF();
286 } else if (audio_renderer_
.get()) {
287 return audio_renderer_
->GetCurrentRenderTime().InSecondsF();
292 WebMediaPlayer::NetworkState
WebMediaPlayerMS::networkState() const {
293 DCHECK(thread_checker_
.CalledOnValidThread());
294 DVLOG(1) << "WebMediaPlayerMS::networkState, state:" << network_state_
;
295 return network_state_
;
298 WebMediaPlayer::ReadyState
WebMediaPlayerMS::readyState() const {
299 DCHECK(thread_checker_
.CalledOnValidThread());
300 DVLOG(1) << "WebMediaPlayerMS::readyState, state:" << ready_state_
;
304 blink::WebTimeRanges
WebMediaPlayerMS::buffered() const {
305 DCHECK(thread_checker_
.CalledOnValidThread());
309 double WebMediaPlayerMS::maxTimeSeekable() const {
310 DCHECK(thread_checker_
.CalledOnValidThread());
314 bool WebMediaPlayerMS::didLoadingProgress() {
315 DCHECK(thread_checker_
.CalledOnValidThread());
319 void WebMediaPlayerMS::paint(WebCanvas
* canvas
,
321 unsigned char alpha
) {
322 DVLOG(3) << "WebMediaPlayerMS::paint";
323 DCHECK(thread_checker_
.CalledOnValidThread());
325 gfx::RectF
dest_rect(rect
.x
, rect
.y
, rect
.width
, rect
.height
);
326 video_renderer_
.Paint(current_frame_
.get(), canvas
, dest_rect
, alpha
);
329 base::AutoLock
auto_lock(current_frame_lock_
);
330 if (current_frame_
.get())
331 current_frame_used_
= true;
335 bool WebMediaPlayerMS::hasSingleSecurityOrigin() const {
336 DCHECK(thread_checker_
.CalledOnValidThread());
340 bool WebMediaPlayerMS::didPassCORSAccessCheck() const {
341 DCHECK(thread_checker_
.CalledOnValidThread());
345 double WebMediaPlayerMS::mediaTimeForTimeValue(double timeValue
) const {
346 return ConvertSecondsToTimestamp(timeValue
).InSecondsF();
349 unsigned WebMediaPlayerMS::decodedFrameCount() const {
350 DCHECK(thread_checker_
.CalledOnValidThread());
351 DVLOG(1) << "WebMediaPlayerMS::decodedFrameCount, " << total_frame_count_
;
352 return total_frame_count_
;
355 unsigned WebMediaPlayerMS::droppedFrameCount() const {
356 DCHECK(thread_checker_
.CalledOnValidThread());
357 DVLOG(1) << "WebMediaPlayerMS::droppedFrameCount, " << dropped_frame_count_
;
358 return dropped_frame_count_
;
361 unsigned WebMediaPlayerMS::audioDecodedByteCount() const {
362 DCHECK(thread_checker_
.CalledOnValidThread());
367 unsigned WebMediaPlayerMS::videoDecodedByteCount() const {
368 DCHECK(thread_checker_
.CalledOnValidThread());
373 void WebMediaPlayerMS::SetVideoFrameProviderClient(
374 cc::VideoFrameProvider::Client
* client
) {
375 // This is called from both the main renderer thread and the compositor
376 // thread (when the main thread is blocked).
377 if (video_frame_provider_client_
)
378 video_frame_provider_client_
->StopUsingProvider();
379 video_frame_provider_client_
= client
;
382 scoped_refptr
<media::VideoFrame
> WebMediaPlayerMS::GetCurrentFrame() {
383 DVLOG(3) << "WebMediaPlayerMS::GetCurrentFrame";
384 base::AutoLock
auto_lock(current_frame_lock_
);
385 DCHECK(!pending_repaint_
);
386 if (!current_frame_
.get())
388 pending_repaint_
= true;
389 current_frame_used_
= true;
390 return current_frame_
;
393 void WebMediaPlayerMS::PutCurrentFrame(
394 const scoped_refptr
<media::VideoFrame
>& frame
) {
395 DVLOG(3) << "WebMediaPlayerMS::PutCurrentFrame";
396 DCHECK(pending_repaint_
);
397 pending_repaint_
= false;
400 void WebMediaPlayerMS::OnFrameAvailable(
401 const scoped_refptr
<media::VideoFrame
>& frame
) {
402 DVLOG(3) << "WebMediaPlayerMS::OnFrameAvailable";
403 DCHECK(thread_checker_
.CalledOnValidThread());
404 ++total_frame_count_
;
405 if (!received_first_frame_
) {
406 received_first_frame_
= true;
408 base::AutoLock
auto_lock(current_frame_lock_
);
409 DCHECK(!current_frame_used_
);
410 current_frame_
= frame
;
412 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata
);
413 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData
);
414 GetClient()->sizeChanged();
416 if (video_frame_provider_
) {
417 video_weblayer_
.reset(
418 new webkit::WebLayerImpl(cc::VideoLayer::Create(this)));
419 video_weblayer_
->setOpaque(true);
420 GetClient()->setWebLayer(video_weblayer_
.get());
424 // Do not update |current_frame_| when paused.
428 bool size_changed
= !current_frame_
.get() ||
429 current_frame_
->natural_size() != frame
->natural_size();
432 base::AutoLock
auto_lock(current_frame_lock_
);
433 if (!current_frame_used_
&& current_frame_
.get())
434 ++dropped_frame_count_
;
435 current_frame_
= frame
;
436 current_time_
= frame
->timestamp();
437 current_frame_used_
= false;
441 GetClient()->sizeChanged();
443 GetClient()->repaint();
446 void WebMediaPlayerMS::RepaintInternal() {
447 DVLOG(1) << "WebMediaPlayerMS::RepaintInternal";
448 DCHECK(thread_checker_
.CalledOnValidThread());
449 GetClient()->repaint();
452 void WebMediaPlayerMS::OnSourceError() {
453 DVLOG(1) << "WebMediaPlayerMS::OnSourceError";
454 DCHECK(thread_checker_
.CalledOnValidThread());
455 SetNetworkState(WebMediaPlayer::NetworkStateFormatError
);
459 void WebMediaPlayerMS::SetNetworkState(WebMediaPlayer::NetworkState state
) {
460 DCHECK(thread_checker_
.CalledOnValidThread());
461 network_state_
= state
;
462 // Always notify to ensure client has the latest value.
463 GetClient()->networkStateChanged();
466 void WebMediaPlayerMS::SetReadyState(WebMediaPlayer::ReadyState state
) {
467 DCHECK(thread_checker_
.CalledOnValidThread());
468 ready_state_
= state
;
469 // Always notify to ensure client has the latest value.
470 GetClient()->readyStateChanged();
473 blink::WebMediaPlayerClient
* WebMediaPlayerMS::GetClient() {
474 DCHECK(thread_checker_
.CalledOnValidThread());
479 } // namespace content