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/renderer/media/media_stream_audio_renderer.h"
15 #include "content/renderer/media/media_stream_client.h"
16 #include "content/renderer/media/video_frame_provider.h"
17 #include "content/renderer/media/webmediaplayer_delegate.h"
18 #include "content/renderer/media/webmediaplayer_util.h"
19 #include "content/renderer/render_frame_impl.h"
20 #include "media/base/media_log.h"
21 #include "media/base/video_frame.h"
22 #include "third_party/WebKit/public/platform/WebMediaPlayerClient.h"
23 #include "third_party/WebKit/public/platform/WebRect.h"
24 #include "third_party/WebKit/public/platform/WebSize.h"
25 #include "third_party/WebKit/public/platform/WebURL.h"
26 #include "third_party/WebKit/public/web/WebFrame.h"
27 #include "third_party/WebKit/public/web/WebView.h"
28 #include "webkit/renderer/compositor_bindings/web_layer_impl.h"
30 using blink::WebCanvas
;
31 using blink::WebMediaPlayer
;
37 WebMediaPlayerMS::WebMediaPlayerMS(
38 blink::WebFrame
* frame
,
39 blink::WebMediaPlayerClient
* client
,
40 base::WeakPtr
<WebMediaPlayerDelegate
> delegate
,
41 MediaStreamClient
* media_stream_client
,
42 media::MediaLog
* media_log
)
44 network_state_(WebMediaPlayer::NetworkStateEmpty
),
45 ready_state_(WebMediaPlayer::ReadyStateHaveNothing
),
46 buffered_(static_cast<size_t>(1)),
49 media_stream_client_(media_stream_client
),
51 current_frame_used_(false),
52 pending_repaint_(false),
53 video_frame_provider_client_(NULL
),
54 received_first_frame_(false),
55 sequence_started_(false),
56 total_frame_count_(0),
57 dropped_frame_count_(0),
58 media_log_(media_log
) {
59 DVLOG(1) << "WebMediaPlayerMS::ctor";
60 DCHECK(media_stream_client
);
62 media_log_
->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_CREATED
));
65 WebMediaPlayerMS::~WebMediaPlayerMS() {
66 DVLOG(1) << "WebMediaPlayerMS::dtor";
67 DCHECK(thread_checker_
.CalledOnValidThread());
69 SetVideoFrameProviderClient(NULL
);
70 GetClient()->setWebLayer(NULL
);
72 if (video_frame_provider_
.get())
73 video_frame_provider_
->Stop();
75 if (audio_renderer_
.get())
76 audio_renderer_
->Stop();
79 media_log_
->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_DESTROYED
));
82 delegate_
->PlayerGone(this);
85 void WebMediaPlayerMS::load(LoadType load_type
,
86 const blink::WebURL
& url
,
88 DVLOG(1) << "WebMediaPlayerMS::load";
89 DCHECK(thread_checker_
.CalledOnValidThread());
91 // TODO(acolwell): Change this to DCHECK_EQ(load_type,
92 // LoadTypeMediaStream) once Blink-side changes land.
93 DCHECK_NE(load_type
, LoadTypeMediaSource
);
97 setVolume(GetClient()->volume());
98 SetNetworkState(WebMediaPlayer::NetworkStateLoading
);
99 SetReadyState(WebMediaPlayer::ReadyStateHaveNothing
);
100 media_log_
->AddEvent(media_log_
->CreateLoadEvent(url
.spec()));
102 // Check if this url is media stream.
103 video_frame_provider_
= media_stream_client_
->GetVideoFrameProvider(
105 base::Bind(&WebMediaPlayerMS::OnSourceError
, AsWeakPtr()),
106 base::Bind(&WebMediaPlayerMS::OnFrameAvailable
, AsWeakPtr()));
108 audio_renderer_
= media_stream_client_
->GetAudioRenderer(
110 RenderFrame::FromWebFrame(frame_
)->GetRoutingID());
112 if (video_frame_provider_
.get() || audio_renderer_
.get()) {
113 GetClient()->setOpaque(true);
114 if (audio_renderer_
.get())
115 audio_renderer_
->Start();
117 if (video_frame_provider_
.get()) {
118 video_frame_provider_
->Start();
120 // This is audio-only mode.
121 DCHECK(audio_renderer_
.get());
122 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata
);
123 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData
);
126 SetNetworkState(WebMediaPlayer::NetworkStateNetworkError
);
130 void WebMediaPlayerMS::play() {
131 DVLOG(1) << "WebMediaPlayerMS::play";
132 DCHECK(thread_checker_
.CalledOnValidThread());
135 if (video_frame_provider_
.get())
136 video_frame_provider_
->Play();
138 if (audio_renderer_
.get())
139 audio_renderer_
->Play();
142 delegate_
->DidPlay(this);
147 media_log_
->AddEvent(media_log_
->CreateEvent(media::MediaLogEvent::PLAY
));
150 void WebMediaPlayerMS::pause() {
151 DVLOG(1) << "WebMediaPlayerMS::pause";
152 DCHECK(thread_checker_
.CalledOnValidThread());
154 if (video_frame_provider_
.get())
155 video_frame_provider_
->Pause();
158 if (audio_renderer_
.get())
159 audio_renderer_
->Pause();
162 delegate_
->DidPause(this);
167 media_log_
->AddEvent(media_log_
->CreateEvent(media::MediaLogEvent::PAUSE
));
170 bool WebMediaPlayerMS::supportsSave() const {
171 DCHECK(thread_checker_
.CalledOnValidThread());
175 void WebMediaPlayerMS::seek(double seconds
) {
176 DCHECK(thread_checker_
.CalledOnValidThread());
179 void WebMediaPlayerMS::setRate(double rate
) {
180 DCHECK(thread_checker_
.CalledOnValidThread());
183 void WebMediaPlayerMS::setVolume(double volume
) {
184 DCHECK(thread_checker_
.CalledOnValidThread());
185 if (!audio_renderer_
.get())
187 DVLOG(1) << "WebMediaPlayerMS::setVolume(volume=" << volume
<< ")";
188 audio_renderer_
->SetVolume(volume
);
191 void WebMediaPlayerMS::setPreload(WebMediaPlayer::Preload preload
) {
192 DCHECK(thread_checker_
.CalledOnValidThread());
195 bool WebMediaPlayerMS::hasVideo() const {
196 DCHECK(thread_checker_
.CalledOnValidThread());
197 return (video_frame_provider_
.get() != NULL
);
200 bool WebMediaPlayerMS::hasAudio() const {
201 DCHECK(thread_checker_
.CalledOnValidThread());
202 return (audio_renderer_
.get() != NULL
);
205 blink::WebSize
WebMediaPlayerMS::naturalSize() const {
206 DCHECK(thread_checker_
.CalledOnValidThread());
209 if (current_frame_
.get())
210 size
= current_frame_
->natural_size();
211 DVLOG(3) << "WebMediaPlayerMS::naturalSize, " << size
.ToString();
212 return blink::WebSize(size
);
215 bool WebMediaPlayerMS::paused() const {
216 DCHECK(thread_checker_
.CalledOnValidThread());
220 bool WebMediaPlayerMS::seeking() const {
221 DCHECK(thread_checker_
.CalledOnValidThread());
225 double WebMediaPlayerMS::duration() const {
226 DCHECK(thread_checker_
.CalledOnValidThread());
227 return std::numeric_limits
<double>::infinity();
230 double WebMediaPlayerMS::currentTime() const {
231 DCHECK(thread_checker_
.CalledOnValidThread());
232 if (current_frame_
.get()) {
233 return current_frame_
->GetTimestamp().InSecondsF();
234 } else if (audio_renderer_
.get()) {
235 return audio_renderer_
->GetCurrentRenderTime().InSecondsF();
240 WebMediaPlayer::NetworkState
WebMediaPlayerMS::networkState() const {
241 DCHECK(thread_checker_
.CalledOnValidThread());
242 DVLOG(1) << "WebMediaPlayerMS::networkState, state:" << network_state_
;
243 return network_state_
;
246 WebMediaPlayer::ReadyState
WebMediaPlayerMS::readyState() const {
247 DCHECK(thread_checker_
.CalledOnValidThread());
248 DVLOG(1) << "WebMediaPlayerMS::readyState, state:" << ready_state_
;
252 const blink::WebTimeRanges
& WebMediaPlayerMS::buffered() {
253 DCHECK(thread_checker_
.CalledOnValidThread());
257 double WebMediaPlayerMS::maxTimeSeekable() const {
258 DCHECK(thread_checker_
.CalledOnValidThread());
262 bool WebMediaPlayerMS::didLoadingProgress() const {
263 DCHECK(thread_checker_
.CalledOnValidThread());
267 void WebMediaPlayerMS::paint(WebCanvas
* canvas
,
269 unsigned char alpha
) {
270 DVLOG(3) << "WebMediaPlayerMS::paint";
271 DCHECK(thread_checker_
.CalledOnValidThread());
273 gfx::RectF
dest_rect(rect
.x
, rect
.y
, rect
.width
, rect
.height
);
274 video_renderer_
.Paint(current_frame_
.get(), canvas
, dest_rect
, alpha
);
277 base::AutoLock
auto_lock(current_frame_lock_
);
278 if (current_frame_
.get())
279 current_frame_used_
= true;
283 bool WebMediaPlayerMS::hasSingleSecurityOrigin() const {
284 DCHECK(thread_checker_
.CalledOnValidThread());
288 bool WebMediaPlayerMS::didPassCORSAccessCheck() const {
289 DCHECK(thread_checker_
.CalledOnValidThread());
293 double WebMediaPlayerMS::mediaTimeForTimeValue(double timeValue
) const {
294 return ConvertSecondsToTimestamp(timeValue
).InSecondsF();
297 unsigned WebMediaPlayerMS::decodedFrameCount() const {
298 DCHECK(thread_checker_
.CalledOnValidThread());
299 DVLOG(1) << "WebMediaPlayerMS::decodedFrameCount, " << total_frame_count_
;
300 return total_frame_count_
;
303 unsigned WebMediaPlayerMS::droppedFrameCount() const {
304 DCHECK(thread_checker_
.CalledOnValidThread());
305 DVLOG(1) << "WebMediaPlayerMS::droppedFrameCount, " << dropped_frame_count_
;
306 return dropped_frame_count_
;
309 unsigned WebMediaPlayerMS::audioDecodedByteCount() const {
310 DCHECK(thread_checker_
.CalledOnValidThread());
315 unsigned WebMediaPlayerMS::videoDecodedByteCount() const {
316 DCHECK(thread_checker_
.CalledOnValidThread());
321 void WebMediaPlayerMS::SetVideoFrameProviderClient(
322 cc::VideoFrameProvider::Client
* client
) {
323 // This is called from both the main renderer thread and the compositor
324 // thread (when the main thread is blocked).
325 if (video_frame_provider_client_
)
326 video_frame_provider_client_
->StopUsingProvider();
327 video_frame_provider_client_
= client
;
330 scoped_refptr
<media::VideoFrame
> WebMediaPlayerMS::GetCurrentFrame() {
331 DVLOG(3) << "WebMediaPlayerMS::GetCurrentFrame";
332 base::AutoLock
auto_lock(current_frame_lock_
);
333 DCHECK(!pending_repaint_
);
334 if (!current_frame_
.get())
336 pending_repaint_
= true;
337 current_frame_used_
= true;
338 return current_frame_
;
341 void WebMediaPlayerMS::PutCurrentFrame(
342 const scoped_refptr
<media::VideoFrame
>& frame
) {
343 DVLOG(3) << "WebMediaPlayerMS::PutCurrentFrame";
344 DCHECK(pending_repaint_
);
345 pending_repaint_
= false;
348 void WebMediaPlayerMS::OnFrameAvailable(
349 const scoped_refptr
<media::VideoFrame
>& frame
) {
350 DVLOG(3) << "WebMediaPlayerMS::OnFrameAvailable";
351 DCHECK(thread_checker_
.CalledOnValidThread());
352 ++total_frame_count_
;
353 if (!received_first_frame_
) {
354 received_first_frame_
= true;
356 base::AutoLock
auto_lock(current_frame_lock_
);
357 DCHECK(!current_frame_used_
);
358 current_frame_
= frame
;
360 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata
);
361 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData
);
362 GetClient()->sizeChanged();
364 if (video_frame_provider_
.get() && GetClient()->needsWebLayerForVideo()) {
365 video_weblayer_
.reset(
366 new webkit::WebLayerImpl(cc::VideoLayer::Create(this)));
367 GetClient()->setWebLayer(video_weblayer_
.get());
371 // Do not update |current_frame_| when paused.
375 if (!sequence_started_
) {
376 sequence_started_
= true;
377 start_time_
= frame
->GetTimestamp();
379 bool size_changed
= !current_frame_
.get() ||
380 current_frame_
->natural_size() != frame
->natural_size();
383 base::AutoLock
auto_lock(current_frame_lock_
);
384 if (!current_frame_used_
&& current_frame_
.get())
385 ++dropped_frame_count_
;
386 current_frame_
= frame
;
387 current_frame_
->SetTimestamp(frame
->GetTimestamp() - start_time_
);
388 current_frame_used_
= false;
392 GetClient()->sizeChanged();
394 GetClient()->repaint();
397 void WebMediaPlayerMS::RepaintInternal() {
398 DVLOG(1) << "WebMediaPlayerMS::RepaintInternal";
399 DCHECK(thread_checker_
.CalledOnValidThread());
400 GetClient()->repaint();
403 void WebMediaPlayerMS::OnSourceError() {
404 DVLOG(1) << "WebMediaPlayerMS::OnSourceError";
405 DCHECK(thread_checker_
.CalledOnValidThread());
406 SetNetworkState(WebMediaPlayer::NetworkStateFormatError
);
410 void WebMediaPlayerMS::SetNetworkState(WebMediaPlayer::NetworkState state
) {
411 DCHECK(thread_checker_
.CalledOnValidThread());
412 network_state_
= state
;
413 // Always notify to ensure client has the latest value.
414 GetClient()->networkStateChanged();
417 void WebMediaPlayerMS::SetReadyState(WebMediaPlayer::ReadyState state
) {
418 DCHECK(thread_checker_
.CalledOnValidThread());
419 ready_state_
= state
;
420 // Always notify to ensure client has the latest value.
421 GetClient()->readyStateChanged();
424 blink::WebMediaPlayerClient
* WebMediaPlayerMS::GetClient() {
425 DCHECK(thread_checker_
.CalledOnValidThread());
430 } // namespace content