// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/media/webmediaplayer_ms.h"
#include <limits>
#include "base/bind.h"
#include "base/callback.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
#include "cc/layers/video_layer.h"
#include "content/renderer/media/media_stream_audio_renderer.h"
#include "content/renderer/media/media_stream_client.h"
#include "content/renderer/media/video_frame_provider.h"
#include "content/renderer/media/webmediaplayer_delegate.h"
#include "content/renderer/media/webmediaplayer_util.h"
#include "media/base/media_log.h"
#include "media/base/video_frame.h"
#include "third_party/WebKit/public/platform/WebMediaPlayerClient.h"
#include "third_party/WebKit/public/platform/WebRect.h"
#include "third_party/WebKit/public/platform/WebSize.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebView.h"
#include "webkit/renderer/compositor_bindings/web_layer_impl.h"
using blink::WebCanvas;
using blink::WebMediaPlayer;
using blink::WebRect;
using blink::WebSize;
namespace content {
WebMediaPlayerMS::WebMediaPlayerMS(
blink::WebFrame* frame,
blink::WebMediaPlayerClient* client,
base::WeakPtr<WebMediaPlayerDelegate> delegate,
MediaStreamClient* media_stream_client,
media::MediaLog* media_log)
: frame_(frame),
network_state_(WebMediaPlayer::NetworkStateEmpty),
ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
buffered_(static_cast<size_t>(1)),
client_(client),
delegate_(delegate),
media_stream_client_(media_stream_client),
paused_(true),
current_frame_used_(false),
pending_repaint_(false),
video_frame_provider_client_(NULL),
received_first_frame_(false),
sequence_started_(false),
total_frame_count_(0),
dropped_frame_count_(0),
media_log_(media_log) {
DVLOG(1) << "WebMediaPlayerMS::ctor";
DCHECK(media_stream_client);
media_log_->AddEvent(
media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_CREATED));
}
WebMediaPlayerMS::~WebMediaPlayerMS() {
DVLOG(1) << "WebMediaPlayerMS::dtor";
DCHECK(thread_checker_.CalledOnValidThread());
SetVideoFrameProviderClient(NULL);
GetClient()->setWebLayer(NULL);
if (video_frame_provider_.get())
video_frame_provider_->Stop();
if (audio_renderer_.get())
audio_renderer_->Stop();
media_log_->AddEvent(
media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
if (delegate_.get())
delegate_->PlayerGone(this);
}
void WebMediaPlayerMS::load(LoadType load_type,
const blink::WebURL& url,
CORSMode cors_mode) {
DVLOG(1) << "WebMediaPlayerMS::load";
DCHECK(thread_checker_.CalledOnValidThread());
// TODO(acolwell): Change this to DCHECK_EQ(load_type,
// LoadTypeMediaStream) once Blink-side changes land.
DCHECK_NE(load_type, LoadTypeMediaSource);
GURL gurl(url);
setVolume(GetClient()->volume());
SetNetworkState(WebMediaPlayer::NetworkStateLoading);
SetReadyState(WebMediaPlayer::ReadyStateHaveNothing);
media_log_->AddEvent(media_log_->CreateLoadEvent(url.spec()));
// Check if this url is media stream.
video_frame_provider_ = media_stream_client_->GetVideoFrameProvider(
url,
base::Bind(&WebMediaPlayerMS::OnSourceError, AsWeakPtr()),
base::Bind(&WebMediaPlayerMS::OnFrameAvailable, AsWeakPtr()));
audio_renderer_ = media_stream_client_->GetAudioRenderer(url);
if (video_frame_provider_.get() || audio_renderer_.get()) {
GetClient()->setOpaque(true);
if (audio_renderer_.get())
audio_renderer_->Start();
if (video_frame_provider_.get()) {
video_frame_provider_->Start();
} else {
// This is audio-only mode.
DCHECK(audio_renderer_.get());
SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
}
} else {
SetNetworkState(WebMediaPlayer::NetworkStateNetworkError);
}
}
void WebMediaPlayerMS::play() {
DVLOG(1) << "WebMediaPlayerMS::play";
DCHECK(thread_checker_.CalledOnValidThread());
if (paused_) {
if (video_frame_provider_.get())
video_frame_provider_->Play();
if (audio_renderer_.get())
audio_renderer_->Play();
if (delegate_.get())
delegate_->DidPlay(this);
}
paused_ = false;
media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PLAY));
}
void WebMediaPlayerMS::pause() {
DVLOG(1) << "WebMediaPlayerMS::pause";
DCHECK(thread_checker_.CalledOnValidThread());
if (video_frame_provider_.get())
video_frame_provider_->Pause();
if (!paused_) {
if (audio_renderer_.get())
audio_renderer_->Pause();
if (delegate_.get())
delegate_->DidPause(this);
}
paused_ = true;
media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PAUSE));
}
bool WebMediaPlayerMS::supportsFullscreen() const {
DCHECK(thread_checker_.CalledOnValidThread());
return true;
}
bool WebMediaPlayerMS::supportsSave() const {
DCHECK(thread_checker_.CalledOnValidThread());
return false;
}
void WebMediaPlayerMS::seek(double seconds) {
DCHECK(thread_checker_.CalledOnValidThread());
}
void WebMediaPlayerMS::setRate(double rate) {
DCHECK(thread_checker_.CalledOnValidThread());
}
void WebMediaPlayerMS::setVolume(double volume) {
DCHECK(thread_checker_.CalledOnValidThread());
if (!audio_renderer_.get())
return;
DVLOG(1) << "WebMediaPlayerMS::setVolume(volume=" << volume << ")";
audio_renderer_->SetVolume(volume);
}
void WebMediaPlayerMS::setPreload(WebMediaPlayer::Preload preload) {
DCHECK(thread_checker_.CalledOnValidThread());
}
bool WebMediaPlayerMS::hasVideo() const {
DCHECK(thread_checker_.CalledOnValidThread());
return (video_frame_provider_.get() != NULL);
}
bool WebMediaPlayerMS::hasAudio() const {
DCHECK(thread_checker_.CalledOnValidThread());
return (audio_renderer_.get() != NULL);
}
blink::WebSize WebMediaPlayerMS::naturalSize() const {
DCHECK(thread_checker_.CalledOnValidThread());
gfx::Size size;
if (current_frame_.get())
size = current_frame_->natural_size();
DVLOG(3) << "WebMediaPlayerMS::naturalSize, " << size.ToString();
return blink::WebSize(size);
}
bool WebMediaPlayerMS::paused() const {
DCHECK(thread_checker_.CalledOnValidThread());
return paused_;
}
bool WebMediaPlayerMS::seeking() const {
DCHECK(thread_checker_.CalledOnValidThread());
return false;
}
double WebMediaPlayerMS::duration() const {
DCHECK(thread_checker_.CalledOnValidThread());
return std::numeric_limits<double>::infinity();
}
double WebMediaPlayerMS::currentTime() const {
DCHECK(thread_checker_.CalledOnValidThread());
if (current_frame_.get()) {
return current_frame_->GetTimestamp().InSecondsF();
} else if (audio_renderer_.get()) {
return audio_renderer_->GetCurrentRenderTime().InSecondsF();
}
return 0.0;
}
WebMediaPlayer::NetworkState WebMediaPlayerMS::networkState() const {
DCHECK(thread_checker_.CalledOnValidThread());
DVLOG(1) << "WebMediaPlayerMS::networkState, state:" << network_state_;
return network_state_;
}
WebMediaPlayer::ReadyState WebMediaPlayerMS::readyState() const {
DCHECK(thread_checker_.CalledOnValidThread());
DVLOG(1) << "WebMediaPlayerMS::readyState, state:" << ready_state_;
return ready_state_;
}
const blink::WebTimeRanges& WebMediaPlayerMS::buffered() {
DCHECK(thread_checker_.CalledOnValidThread());
return buffered_;
}
double WebMediaPlayerMS::maxTimeSeekable() const {
DCHECK(thread_checker_.CalledOnValidThread());
return 0.0;
}
bool WebMediaPlayerMS::didLoadingProgress() const {
DCHECK(thread_checker_.CalledOnValidThread());
return true;
}
void WebMediaPlayerMS::paint(WebCanvas* canvas,
const WebRect& rect,
unsigned char alpha) {
DVLOG(3) << "WebMediaPlayerMS::paint";
DCHECK(thread_checker_.CalledOnValidThread());
gfx::RectF dest_rect(rect.x, rect.y, rect.width, rect.height);
video_renderer_.Paint(current_frame_.get(), canvas, dest_rect, alpha);
{
base::AutoLock auto_lock(current_frame_lock_);
if (current_frame_.get())
current_frame_used_ = true;
}
}
bool WebMediaPlayerMS::hasSingleSecurityOrigin() const {
DCHECK(thread_checker_.CalledOnValidThread());
return true;
}
bool WebMediaPlayerMS::didPassCORSAccessCheck() const {
DCHECK(thread_checker_.CalledOnValidThread());
return true;
}
double WebMediaPlayerMS::mediaTimeForTimeValue(double timeValue) const {
return ConvertSecondsToTimestamp(timeValue).InSecondsF();
}
unsigned WebMediaPlayerMS::decodedFrameCount() const {
DCHECK(thread_checker_.CalledOnValidThread());
DVLOG(1) << "WebMediaPlayerMS::decodedFrameCount, " << total_frame_count_;
return total_frame_count_;
}
unsigned WebMediaPlayerMS::droppedFrameCount() const {
DCHECK(thread_checker_.CalledOnValidThread());
DVLOG(1) << "WebMediaPlayerMS::droppedFrameCount, " << dropped_frame_count_;
return dropped_frame_count_;
}
unsigned WebMediaPlayerMS::audioDecodedByteCount() const {
DCHECK(thread_checker_.CalledOnValidThread());
NOTIMPLEMENTED();
return 0;
}
unsigned WebMediaPlayerMS::videoDecodedByteCount() const {
DCHECK(thread_checker_.CalledOnValidThread());
NOTIMPLEMENTED();
return 0;
}
void WebMediaPlayerMS::SetVideoFrameProviderClient(
cc::VideoFrameProvider::Client* client) {
// This is called from both the main renderer thread and the compositor
// thread (when the main thread is blocked).
if (video_frame_provider_client_)
video_frame_provider_client_->StopUsingProvider();
video_frame_provider_client_ = client;
}
scoped_refptr<media::VideoFrame> WebMediaPlayerMS::GetCurrentFrame() {
DVLOG(3) << "WebMediaPlayerMS::GetCurrentFrame";
base::AutoLock auto_lock(current_frame_lock_);
DCHECK(!pending_repaint_);
if (!current_frame_.get())
return NULL;
pending_repaint_ = true;
current_frame_used_ = true;
return current_frame_;
}
void WebMediaPlayerMS::PutCurrentFrame(
const scoped_refptr<media::VideoFrame>& frame) {
DVLOG(3) << "WebMediaPlayerMS::PutCurrentFrame";
DCHECK(pending_repaint_);
pending_repaint_ = false;
}
void WebMediaPlayerMS::OnFrameAvailable(
const scoped_refptr<media::VideoFrame>& frame) {
DVLOG(3) << "WebMediaPlayerMS::OnFrameAvailable";
DCHECK(thread_checker_.CalledOnValidThread());
++total_frame_count_;
if (!received_first_frame_) {
received_first_frame_ = true;
{
base::AutoLock auto_lock(current_frame_lock_);
DCHECK(!current_frame_used_);
current_frame_ = frame;
}
SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
GetClient()->sizeChanged();
if (video_frame_provider_.get() && GetClient()->needsWebLayerForVideo()) {
video_weblayer_.reset(
new webkit::WebLayerImpl(cc::VideoLayer::Create(this)));
GetClient()->setWebLayer(video_weblayer_.get());
}
}
// Do not update |current_frame_| when paused.
if (paused_)
return;
if (!sequence_started_) {
sequence_started_ = true;
start_time_ = frame->GetTimestamp();
}
bool size_changed = !current_frame_.get() ||
current_frame_->natural_size() != frame->natural_size();
{
base::AutoLock auto_lock(current_frame_lock_);
if (!current_frame_used_ && current_frame_.get())
++dropped_frame_count_;
current_frame_ = frame;
current_frame_->SetTimestamp(frame->GetTimestamp() - start_time_);
current_frame_used_ = false;
}
if (size_changed)
GetClient()->sizeChanged();
GetClient()->repaint();
}
void WebMediaPlayerMS::RepaintInternal() {
DVLOG(1) << "WebMediaPlayerMS::RepaintInternal";
DCHECK(thread_checker_.CalledOnValidThread());
GetClient()->repaint();
}
void WebMediaPlayerMS::OnSourceError() {
DVLOG(1) << "WebMediaPlayerMS::OnSourceError";
DCHECK(thread_checker_.CalledOnValidThread());
SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
RepaintInternal();
}
void WebMediaPlayerMS::SetNetworkState(WebMediaPlayer::NetworkState state) {
DCHECK(thread_checker_.CalledOnValidThread());
network_state_ = state;
// Always notify to ensure client has the latest value.
GetClient()->networkStateChanged();
}
void WebMediaPlayerMS::SetReadyState(WebMediaPlayer::ReadyState state) {
DCHECK(thread_checker_.CalledOnValidThread());
ready_state_ = state;
// Always notify to ensure client has the latest value.
GetClient()->readyStateChanged();
}
blink::WebMediaPlayerClient* WebMediaPlayerMS::GetClient() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(client_);
return client_;
}
} // namespace content