summaryrefslogtreecommitdiffstats
path: root/webkit
diff options
context:
space:
mode:
authorqinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-25 20:33:15 +0000
committerqinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-25 20:33:15 +0000
commite45912efc8d9a4b15320f73436474856d74d6628 (patch)
tree2907312ab9ebe273c943e80c422e4410dff0b9c4 /webkit
parentb880b2d83257b51630ea95a5f5874dc393729f57 (diff)
downloadchromium_src-e45912efc8d9a4b15320f73436474856d74d6628.zip
chromium_src-e45912efc8d9a4b15320f73436474856d74d6628.tar.gz
chromium_src-e45912efc8d9a4b15320f73436474856d74d6628.tar.bz2
Upstream WebMediaPlayerAndroid as WebKit::WebMediaPlayer implementation on android.
I've seperated the WebMediaPlayerAndroid into several changes so that each change will be easier to understand. This is the first change in the series. It implements the basic functionalities needed for WebMediaPlayer on android. Here are the things that are missing and will be addressed in future changes: 1. Only audio is working after this change (for video, you can only hear audio now). Video will be in the next change. 2. Fullscreen implementation is missing in this change, it will come after the video change. BUG= TEST= Review URL: http://codereview.chromium.org/10073016 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@133971 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r--webkit/media/android/webmediaplayer_android.cc486
-rw-r--r--webkit/media/android/webmediaplayer_android.h200
-rw-r--r--webkit/media/android/webmediaplayer_proxy_android.cc64
-rw-r--r--webkit/media/android/webmediaplayer_proxy_android.h74
-rw-r--r--webkit/media/webkit_media.gypi15
-rw-r--r--webkit/media/webmediaplayer_impl.cc20
-rw-r--r--webkit/media/webmediaplayer_util.cc26
-rw-r--r--webkit/media/webmediaplayer_util.h20
8 files changed, 885 insertions, 20 deletions
diff --git a/webkit/media/android/webmediaplayer_android.cc b/webkit/media/android/webmediaplayer_android.cc
new file mode 100644
index 0000000..4966d0a
--- /dev/null
+++ b/webkit/media/android/webmediaplayer_android.cc
@@ -0,0 +1,486 @@
+// Copyright (c) 2012 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 "webkit/media/android/webmediaplayer_android.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/utf_string_conversions.h"
+#include "media/base/android/media_player_bridge.h"
+#include "net/base/mime_util.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerClient.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCookieJar.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h"
+#include "webkit/media/android/webmediaplayer_proxy_android.h"
+#include "webkit/media/webmediaplayer_util.h"
+#include "webkit/media/webvideoframe_impl.h"
+
+using WebKit::WebCanvas;
+using WebKit::WebMediaPlayerClient;
+using WebKit::WebMediaPlayer;
+using WebKit::WebRect;
+using WebKit::WebSize;
+using WebKit::WebTimeRanges;
+using WebKit::WebURL;
+using WebKit::WebVideoFrame;
+using media::MediaPlayerBridge;
+using media::VideoFrame;
+using webkit_media::WebVideoFrameImpl;
+
+namespace webkit_media {
+
+// Because we create the media player lazily on android, the duration of the
+// media is initially unknown to us. This makes the user unable to perform
+// seek. To solve this problem, we use a temporary duration of 100 seconds when
+// the duration is unknown. And we scale the seek position later when duration
+// is available.
+// TODO(qinmin): create a thread and use android MediaMetadataRetriever
+// class to extract the duration.
+static const float kTemporaryDuration = 100.0f;
+
+bool WebMediaPlayerAndroid::incognito_mode_ = false;
+
+WebMediaPlayerAndroid::WebMediaPlayerAndroid(
+ WebMediaPlayerClient* client,
+ WebKit::WebCookieJar* cookie_jar)
+ : client_(client),
+ buffered_(1u),
+ video_frame_(new WebVideoFrameImpl(VideoFrame::CreateEmptyFrame())),
+ proxy_(new WebMediaPlayerProxyAndroid(base::MessageLoopProxy::current(),
+ AsWeakPtr())),
+ prepared_(false),
+ duration_(0),
+ pending_seek_(0),
+ seeking_(false),
+ playback_completed_(false),
+ buffered_bytes_(0),
+ cookie_jar_(cookie_jar),
+ pending_play_event_(false),
+ network_state_(WebMediaPlayer::Empty),
+ ready_state_(WebMediaPlayer::HaveNothing) {
+ video_frame_.reset(new WebVideoFrameImpl(VideoFrame::CreateEmptyFrame()));
+}
+
+WebMediaPlayerAndroid::~WebMediaPlayerAndroid() {
+ if (media_player_.get()) {
+ media_player_->Stop();
+ }
+}
+
+void WebMediaPlayerAndroid::InitIncognito(bool incognito_mode) {
+ incognito_mode_ = incognito_mode;
+}
+
+void WebMediaPlayerAndroid::load(const WebURL& url) {
+ url_ = url;
+
+ UpdateNetworkState(WebMediaPlayer::Loading);
+ UpdateReadyState(WebMediaPlayer::HaveNothing);
+
+ // Calling InitializeMediaPlayer() will cause android mediaplayer to start
+ // buffering and decoding the data. On mobile devices, this costs a lot of
+ // data usage and could even introduce performance issues. So we don't
+ // initialize the player unless it is a local file. We will start loading
+ // the media only when play/seek/fullsceen button is clicked.
+ if (url_.SchemeIs("file")) {
+ InitializeMediaPlayer();
+ return;
+ }
+
+ // TODO(qinmin): we need a method to calculate the duration of the media.
+ // Android does not provide any function to do that.
+ // Set the initial duration value to kTemporaryDuration so that user can
+ // touch the seek bar to perform seek. We will scale the seek position later
+ // when we got the actual duration.
+ duration_ = kTemporaryDuration;
+
+ // Pretend everything has been loaded so that webkit can
+ // still call play() and seek().
+ UpdateReadyState(WebMediaPlayer::HaveMetadata);
+ UpdateReadyState(WebMediaPlayer::HaveEnoughData);
+}
+
+void WebMediaPlayerAndroid::cancelLoad() {
+ NOTIMPLEMENTED();
+}
+
+void WebMediaPlayerAndroid::play() {
+ if (media_player_.get()) {
+ if (!prepared_)
+ pending_play_event_ = true;
+ else
+ PlayInternal();
+ } else {
+ pending_play_event_ = true;
+ InitializeMediaPlayer();
+ }
+}
+
+void WebMediaPlayerAndroid::pause() {
+ if (media_player_.get()) {
+ if (!prepared_)
+ pending_play_event_ = false;
+ else
+ PauseInternal();
+ } else {
+ // We don't need to load media if pause() is called.
+ pending_play_event_ = false;
+ }
+}
+
+void WebMediaPlayerAndroid::seek(float seconds) {
+ // Record the time to seek when OnMediaPrepared() is called.
+ pending_seek_ = seconds;
+
+ // Reset |playback_completed_| so that we return the correct current time.
+ playback_completed_ = false;
+
+ if (media_player_.get()) {
+ if (prepared_)
+ SeekInternal(seconds);
+ } else {
+ InitializeMediaPlayer();
+ }
+}
+
+bool WebMediaPlayerAndroid::supportsFullscreen() const {
+ return true;
+}
+
+bool WebMediaPlayerAndroid::supportsSave() const {
+ return false;
+}
+
+void WebMediaPlayerAndroid::setEndTime(float seconds) {
+ // Deprecated.
+ // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used.
+}
+
+void WebMediaPlayerAndroid::setRate(float rate) {
+ NOTIMPLEMENTED();
+}
+
+void WebMediaPlayerAndroid::setVolume(float volume) {
+ if (media_player_.get())
+ media_player_->SetVolume(volume, volume);
+}
+
+void WebMediaPlayerAndroid::setVisible(bool visible) {
+ // Deprecated.
+ // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used.
+}
+
+bool WebMediaPlayerAndroid::totalBytesKnown() {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool WebMediaPlayerAndroid::hasVideo() const {
+ // TODO(qinmin): need a better method to determine whether the current media
+ // content contains video. Android does not provide any function to do
+ // this.
+ // We don't know whether the current media content has video unless
+ // the player is prepared. If the player is not prepared, we fall back
+ // to the mime-type. There may be no mime-type on a redirect URL.
+ // In that case, we conservatively assume it contains video so that
+ // enterfullscreen call will not fail.
+ if (!prepared_) {
+ if (!url_.has_path())
+ return false;
+ std::string mime;
+ if(!net::GetMimeTypeFromFile(FilePath(url_.path()), &mime))
+ return true;
+ return mime.find("audio/") == std::string::npos;
+ }
+
+ return !natural_size_.isEmpty();
+}
+
+bool WebMediaPlayerAndroid::hasAudio() const {
+ // TODO(hclam): Query status of audio and return the actual value.
+ return true;
+}
+
+bool WebMediaPlayerAndroid::paused() const {
+ if (!prepared_)
+ return !pending_play_event_;
+ return !media_player_->IsPlaying();
+}
+
+bool WebMediaPlayerAndroid::seeking() const {
+ return seeking_;
+}
+
+float WebMediaPlayerAndroid::duration() const {
+ return duration_;
+}
+
+float WebMediaPlayerAndroid::currentTime() const {
+ // If the player is pending for a seek, return the seek time.
+ if (!prepared_ || seeking())
+ return pending_seek_;
+
+ // When playback is about to finish, android media player often stops
+ // at a time which is smaller than the duration. This makes webkit never
+ // know that the playback has finished. To solve this, we set the
+ // current time to media duration when OnPlaybackComplete() get called.
+ // And return the greater of the two values so that the current
+ // time is most updated.
+ if (playback_completed_)
+ return duration();
+ return static_cast<float>(media_player_->GetCurrentTime().InSecondsF());
+}
+
+int WebMediaPlayerAndroid::dataRate() const {
+ // Deprecated.
+ // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used.
+ return 0;
+}
+
+WebSize WebMediaPlayerAndroid::naturalSize() const {
+ return natural_size_;
+}
+
+WebMediaPlayer::NetworkState WebMediaPlayerAndroid::networkState() const {
+ return network_state_;
+}
+
+WebMediaPlayer::ReadyState WebMediaPlayerAndroid::readyState() const {
+ return ready_state_;
+}
+
+const WebTimeRanges& WebMediaPlayerAndroid::buffered() {
+ return buffered_;
+}
+
+float WebMediaPlayerAndroid::maxTimeSeekable() const {
+ // TODO(hclam): If this stream is not seekable this should return 0.
+ return duration();
+}
+
+unsigned long long WebMediaPlayerAndroid::bytesLoaded() const {
+ return buffered_bytes_;
+}
+
+unsigned long long WebMediaPlayerAndroid::totalBytes() const {
+ // Deprecated.
+ // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used.
+ return 0;
+}
+
+void WebMediaPlayerAndroid::setSize(const WebSize& size) {
+ texture_size_ = size;
+}
+
+void WebMediaPlayerAndroid::paint(WebKit::WebCanvas* canvas,
+ const WebKit::WebRect& rect,
+ uint8_t alpha) {
+ NOTIMPLEMENTED();
+}
+
+bool WebMediaPlayerAndroid::hasSingleSecurityOrigin() const {
+ return false;
+}
+
+WebMediaPlayer::MovieLoadType
+ WebMediaPlayerAndroid::movieLoadType() const {
+ // Deprecated.
+ // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used.
+ return WebMediaPlayer::Unknown;
+}
+
+float WebMediaPlayerAndroid::mediaTimeForTimeValue(float timeValue) const {
+ return ConvertSecondsToTimestamp(timeValue).InSecondsF();
+}
+
+unsigned WebMediaPlayerAndroid::decodedFrameCount() const {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+unsigned WebMediaPlayerAndroid::droppedFrameCount() const {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+unsigned WebMediaPlayerAndroid::audioDecodedByteCount() const {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+unsigned WebMediaPlayerAndroid::videoDecodedByteCount() const {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+void WebMediaPlayerAndroid::OnMediaPrepared() {
+ if (!media_player_.get())
+ return;
+
+ prepared_ = true;
+
+ // Update the media duration first so that webkit will get the correct
+ // duration when UpdateReadyState is called.
+ float dur = duration_;
+ duration_ = media_player_->GetDuration().InSecondsF();
+
+ if (url_.SchemeIs("file"))
+ UpdateNetworkState(WebMediaPlayer::Loaded);
+
+ if (ready_state_ != WebMediaPlayer::HaveEnoughData) {
+ UpdateReadyState(WebMediaPlayer::HaveMetadata);
+ UpdateReadyState(WebMediaPlayer::HaveEnoughData);
+ } else {
+ // If the status is already set to HaveEnoughData, set it again to make sure
+ // that Videolayerchromium will get created.
+ UpdateReadyState(WebMediaPlayer::HaveEnoughData);
+ }
+
+ if (!url_.SchemeIs("file")) {
+ // In we have skipped loading, the duration was preset to
+ // kTemporaryDuration. We have to update webkit about the new duration.
+ if (duration_ != dur) {
+ // Scale the |pending_seek_| according to the new duration.
+ pending_seek_ = pending_seek_ * duration_ / kTemporaryDuration;
+ client_->durationChanged();
+ }
+ }
+
+ // If media player was recovered from a saved state, consume all the pending
+ // events.
+ seek(pending_seek_);
+
+ if (pending_play_event_)
+ PlayInternal();
+
+ pending_play_event_ = false;
+}
+
+void WebMediaPlayerAndroid::OnPlaybackComplete() {
+ // Set the current time equal to duration to let webkit know that play back
+ // is completed.
+ playback_completed_ = true;
+ client_->timeChanged();
+}
+
+void WebMediaPlayerAndroid::OnBufferingUpdate(int percentage) {
+ buffered_[0].end = duration() * percentage / 100;
+ // Implement a trick here to fake progress event, as WebKit checks
+ // consecutive bytesLoaded() to see if any progress made.
+ // See HTMLMediaElement::progressEventTimerFired.
+ // TODO(qinmin): need a method to calculate the buffered bytes.
+ buffered_bytes_++;
+}
+
+void WebMediaPlayerAndroid::OnSeekComplete() {
+ seeking_ = false;
+
+ UpdateReadyState(WebMediaPlayer::HaveEnoughData);
+
+ client_->timeChanged();
+}
+
+void WebMediaPlayerAndroid::OnMediaError(int error_type) {
+ switch (error_type) {
+ case MediaPlayerBridge::MEDIA_ERROR_UNKNOWN:
+ // When playing an bogus URL or bad file we fire a MEDIA_ERROR_UNKNOWN.
+ // As WebKit uses FormatError to indicate an error for bogus URL or bad
+ // file we default a MEDIA_ERROR_UNKNOWN to FormatError.
+ UpdateNetworkState(WebMediaPlayer::FormatError);
+ break;
+ case MediaPlayerBridge::MEDIA_ERROR_SERVER_DIED:
+ // TODO(zhenghao): Media server died. In this case, the application must
+ // release the MediaPlayer object and instantiate a new one.
+ UpdateNetworkState(WebMediaPlayer::DecodeError);
+ break;
+ case MediaPlayerBridge::MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
+ UpdateNetworkState(WebMediaPlayer::FormatError);
+ break;
+ case MediaPlayerBridge::MEDIA_ERROR_INVALID_CODE:
+ break;
+ }
+ client_->repaint();
+}
+
+void WebMediaPlayerAndroid::OnMediaInfo(int info_type) {
+ NOTIMPLEMENTED();
+}
+
+void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) {
+ natural_size_.width = width;
+ natural_size_.height = height;
+}
+
+void WebMediaPlayerAndroid::UpdateNetworkState(
+ WebMediaPlayer::NetworkState state) {
+ network_state_ = state;
+ client_->networkStateChanged();
+}
+
+void WebMediaPlayerAndroid::UpdateReadyState(
+ WebMediaPlayer::ReadyState state) {
+ ready_state_ = state;
+ client_->readyStateChanged();
+}
+
+void WebMediaPlayerAndroid::SetVideoSurface(jobject j_surface) {
+ if (media_player_.get())
+ media_player_->SetVideoSurface(j_surface);
+}
+
+void WebMediaPlayerAndroid::InitializeMediaPlayer() {
+ CHECK(!media_player_.get());
+ prepared_ = false;
+ media_player_.reset(new MediaPlayerBridge());
+ media_player_->SetStayAwakeWhilePlaying();
+
+ std::string cookies;
+ if (cookie_jar_ != NULL) {
+ WebURL url(url_);
+ cookies = UTF16ToUTF8(cookie_jar_->cookies(url, url));
+ }
+ media_player_->SetDataSource(url_.spec(), cookies, incognito_mode_);
+
+ media_player_->Prepare(
+ base::Bind(&WebMediaPlayerProxyAndroid::MediaInfoCallback, proxy_),
+ base::Bind(&WebMediaPlayerProxyAndroid::MediaErrorCallback, proxy_),
+ base::Bind(&WebMediaPlayerProxyAndroid::VideoSizeChangedCallback, proxy_),
+ base::Bind(&WebMediaPlayerProxyAndroid::BufferingUpdateCallback, proxy_),
+ base::Bind(&WebMediaPlayerProxyAndroid::MediaPreparedCallback, proxy_));
+}
+
+void WebMediaPlayerAndroid::PlayInternal() {
+ CHECK(prepared_);
+
+ if (paused())
+ media_player_->Start(base::Bind(
+ &WebMediaPlayerProxyAndroid::PlaybackCompleteCallback, proxy_));
+}
+
+void WebMediaPlayerAndroid::PauseInternal() {
+ CHECK(prepared_);
+ media_player_->Pause();
+}
+
+void WebMediaPlayerAndroid::SeekInternal(float seconds) {
+ CHECK(prepared_);
+ seeking_ = true;
+ media_player_->SeekTo(ConvertSecondsToTimestamp(seconds), base::Bind(
+ &WebMediaPlayerProxyAndroid::SeekCompleteCallback, proxy_));
+}
+
+WebVideoFrame* WebMediaPlayerAndroid::getCurrentFrame() {
+ return video_frame_.get();
+}
+
+void WebMediaPlayerAndroid::putCurrentFrame(
+ WebVideoFrame* web_video_frame) {
+}
+
+} // namespace webkit_media
diff --git a/webkit/media/android/webmediaplayer_android.h b/webkit/media/android/webmediaplayer_android.h
new file mode 100644
index 0000000..61ee5d1
--- /dev/null
+++ b/webkit/media/android/webmediaplayer_android.h
@@ -0,0 +1,200 @@
+// Copyright (c) 2012 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.
+
+#ifndef WEBKIT_MEDIA_ANDROID_WEBMEDIAPLAYER_ANDROID_H_
+#define WEBKIT_MEDIA_ANDROID_WEBMEDIAPLAYER_ANDROID_H_
+
+#include <jni.h>
+
+#include "base/basictypes.h"
+#include "base/message_loop_proxy.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayer.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURL.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebVideoFrame.h"
+
+namespace WebKit {
+class WebCookieJar;
+}
+
+namespace media {
+class MediaPlayerBridge;
+}
+
+namespace webkit_media {
+
+class WebMediaPlayerProxyAndroid;
+
+// This class serves as the android implementation of WebKit::WebMediaPlayer.
+// It implements all the playback functions by forwarding calls to android
+// media player, and reports player state changes to the webkit.
+class WebMediaPlayerAndroid :
+ public WebKit::WebMediaPlayer,
+ public base::SupportsWeakPtr<WebMediaPlayerAndroid> {
+ public:
+ WebMediaPlayerAndroid(WebKit::WebMediaPlayerClient* client,
+ WebKit::WebCookieJar* cookie_jar);
+ virtual ~WebMediaPlayerAndroid() OVERRIDE;
+
+ // Set |incognito_mode_| to true if in incognito mode.
+ static void InitIncognito(bool incognito_mode);
+
+ // Resource loading.
+ virtual void load(const WebKit::WebURL& url) OVERRIDE;
+ virtual void cancelLoad() OVERRIDE;
+
+ // Playback controls.
+ virtual void play() OVERRIDE;
+ virtual void pause() OVERRIDE;
+ virtual void seek(float seconds) OVERRIDE;
+ virtual bool supportsFullscreen() const OVERRIDE;
+ virtual bool supportsSave() const OVERRIDE;
+ virtual void setEndTime(float seconds) OVERRIDE;
+ virtual void setRate(float rate) OVERRIDE;
+ virtual void setVolume(float volume) OVERRIDE;
+ virtual void setVisible(bool visible) OVERRIDE;
+ virtual bool totalBytesKnown() OVERRIDE;
+ virtual const WebKit::WebTimeRanges& buffered() OVERRIDE;
+ virtual float maxTimeSeekable() const OVERRIDE;
+
+ // Methods for painting.
+ virtual void setSize(const WebKit::WebSize& size) OVERRIDE;
+ virtual void paint(WebKit::WebCanvas* canvas,
+ const WebKit::WebRect& rect,
+ uint8_t alpha) OVERRIDE;
+
+ // True if the loaded media has a playable video/audio track.
+ virtual bool hasVideo() const OVERRIDE;
+ virtual bool hasAudio() const OVERRIDE;
+
+ // Dimensions of the video.
+ virtual WebKit::WebSize naturalSize() const OVERRIDE;
+
+ // Getters of playback state.
+ virtual bool paused() const OVERRIDE;
+ virtual bool seeking() const OVERRIDE;
+ virtual float duration() const OVERRIDE;
+ virtual float currentTime() const OVERRIDE;
+
+ // Get rate of loading the resource.
+ virtual int32 dataRate() const OVERRIDE;
+
+ virtual unsigned long long bytesLoaded() const OVERRIDE;
+ virtual unsigned long long totalBytes() const OVERRIDE;
+
+ // Internal states of loading and network.
+ virtual WebKit::WebMediaPlayer::NetworkState networkState() const OVERRIDE;
+ virtual WebKit::WebMediaPlayer::ReadyState readyState() const OVERRIDE;
+
+ virtual bool hasSingleSecurityOrigin() const OVERRIDE;
+ virtual WebKit::WebMediaPlayer::MovieLoadType movieLoadType() const OVERRIDE;
+
+ virtual float mediaTimeForTimeValue(float timeValue) const OVERRIDE;
+
+ // Provide statistics.
+ virtual unsigned decodedFrameCount() const OVERRIDE;
+ virtual unsigned droppedFrameCount() const OVERRIDE;
+ virtual unsigned audioDecodedByteCount() const OVERRIDE;
+ virtual unsigned videoDecodedByteCount() const OVERRIDE;
+
+ // Methods called from VideoLayerChromium. These methods are running on the
+ // compositor thread.
+ virtual WebKit::WebVideoFrame* getCurrentFrame() OVERRIDE;
+ virtual void putCurrentFrame(WebKit::WebVideoFrame*) OVERRIDE;
+
+ // Media player callback handlers.
+ void OnMediaPrepared();
+ void OnPlaybackComplete();
+ void OnBufferingUpdate(int percentage);
+ void OnSeekComplete();
+ void OnMediaError(int error_type);
+ void OnMediaInfo(int info_type);
+ void OnVideoSizeChanged(int width, int height);
+
+ // Method to set the video surface for android media player.
+ void SetVideoSurface(jobject j_surface);
+
+ private:
+ // Create a media player to load the |url_| and prepare for playback.
+ // Because of limited decoding resources on mobile devices, idle media players
+ // could get released. In that case, we call this function to get a new media
+ // player when needed.
+ void InitializeMediaPlayer();
+
+ // Functions that implements media player control.
+ void PlayInternal();
+ void PauseInternal();
+ void SeekInternal(float seconds);
+
+ // Helper methods for posting task for setting states and update WebKit.
+ void UpdateNetworkState(WebKit::WebMediaPlayer::NetworkState state);
+ void UpdateReadyState(WebKit::WebMediaPlayer::ReadyState state);
+
+ // whether the current process is incognito mode
+ static bool incognito_mode_;
+
+ WebKit::WebMediaPlayerClient* const client_;
+
+ // Save the list of buffered time ranges.
+ WebKit::WebTimeRanges buffered_;
+
+ // Bridge to the android media player.
+ scoped_ptr<media::MediaPlayerBridge> media_player_;
+
+ // Size of the media element.
+ WebKit::WebSize texture_size_;
+
+ // Size of the video.
+ WebKit::WebSize natural_size_;
+
+ // The video frame object used for renderering by WebKit.
+ scoped_ptr<WebKit::WebVideoFrame> video_frame_;
+
+ // Proxy object that delegates method calls on Render Thread.
+ // This object is created on the Render Thread and is only called in the
+ // destructor.
+ scoped_refptr<WebMediaPlayerProxyAndroid> proxy_;
+
+ // If this is set to true, prepare of the media player is done.
+ bool prepared_;
+
+ // URL of the media file to be fetched.
+ GURL url_;
+
+ // Media duration.
+ float duration_;
+
+ // When switching tabs, we release the media player. This variable keeps
+ // track of the current playback time so that a seek will be performed
+ // next time the media player gets recreated.
+ float pending_seek_;
+
+ // Internal seek state.
+ bool seeking_;
+
+ // Whether playback has completed.
+ float playback_completed_;
+
+ // Fake it by self increasing on every OnBufferingUpdate event.
+ int64 buffered_bytes_;
+
+ // Pointer to the cookie jar to get the cookie for the media url.
+ WebKit::WebCookieJar* cookie_jar_;
+
+ // Whether the user has clicked the play button while media player
+ // is preparing.
+ bool pending_play_event_;
+
+ // Current player states.
+ WebKit::WebMediaPlayer::NetworkState network_state_;
+ WebKit::WebMediaPlayer::ReadyState ready_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerAndroid);
+};
+
+} // namespace webkit_media
+
+#endif // WEBKIT_MEDIA_ANDROID_WEBMEDIAPLAYER_ANDROID_H_
diff --git a/webkit/media/android/webmediaplayer_proxy_android.cc b/webkit/media/android/webmediaplayer_proxy_android.cc
new file mode 100644
index 0000000..677a665
--- /dev/null
+++ b/webkit/media/android/webmediaplayer_proxy_android.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2012 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 "webkit/media/android/webmediaplayer_proxy_android.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "webkit/media/android/webmediaplayer_android.h"
+
+namespace webkit_media {
+
+WebMediaPlayerProxyAndroid::WebMediaPlayerProxyAndroid(
+ const scoped_refptr<base::MessageLoopProxy>& render_loop,
+ base::WeakPtr<WebMediaPlayerAndroid> webmediaplayer)
+ : render_loop_(render_loop),
+ webmediaplayer_(webmediaplayer) {
+ DCHECK(render_loop_);
+ DCHECK(webmediaplayer_);
+}
+
+WebMediaPlayerProxyAndroid::~WebMediaPlayerProxyAndroid() {
+}
+
+void WebMediaPlayerProxyAndroid::MediaErrorCallback(int error_type) {
+ render_loop_->PostTask(FROM_HERE, base::Bind(
+ &WebMediaPlayerAndroid::OnMediaError, webmediaplayer_, error_type));
+}
+
+void WebMediaPlayerProxyAndroid::MediaInfoCallback(int info_type) {
+ render_loop_->PostTask(FROM_HERE, base::Bind(
+ &WebMediaPlayerAndroid::OnMediaInfo, webmediaplayer_, info_type));
+}
+
+void WebMediaPlayerProxyAndroid::VideoSizeChangedCallback(
+ int width, int height) {
+ render_loop_->PostTask(FROM_HERE, base::Bind(
+ &WebMediaPlayerAndroid::OnVideoSizeChanged, webmediaplayer_,
+ width, height));
+}
+
+void WebMediaPlayerProxyAndroid::BufferingUpdateCallback(int percent) {
+ render_loop_->PostTask(FROM_HERE, base::Bind(
+ &WebMediaPlayerAndroid::OnBufferingUpdate, webmediaplayer_, percent));
+}
+
+void WebMediaPlayerProxyAndroid::PlaybackCompleteCallback() {
+ render_loop_->PostTask(FROM_HERE, base::Bind(
+ &WebMediaPlayerAndroid::OnPlaybackComplete, webmediaplayer_));
+}
+
+void WebMediaPlayerProxyAndroid::SeekCompleteCallback() {
+ render_loop_->PostTask(FROM_HERE, base::Bind(
+ &WebMediaPlayerAndroid::OnSeekComplete, webmediaplayer_));
+}
+
+void WebMediaPlayerProxyAndroid::MediaPreparedCallback() {
+ render_loop_->PostTask(FROM_HERE, base::Bind(
+ &WebMediaPlayerAndroid::OnMediaPrepared, webmediaplayer_));
+}
+
+} // namespace webkit_media
diff --git a/webkit/media/android/webmediaplayer_proxy_android.h b/webkit/media/android/webmediaplayer_proxy_android.h
new file mode 100644
index 0000000..2b491ff
--- /dev/null
+++ b/webkit/media/android/webmediaplayer_proxy_android.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2012 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.
+
+#ifndef WEBKIT_MEDIA_ANDROID_WEBMEDIAPLAYER_PROXY_ANDROID_H_
+#define WEBKIT_MEDIA_ANDROID_WEBMEDIAPLAYER_PROXY_ANDROID_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+
+namespace base {
+class MessageLoopProxy;
+}
+
+namespace webkit_media {
+
+class WebMediaPlayerAndroid;
+
+// Acts as a thread proxy between media::MediaPlayerBridge and
+// WebMediaPlayerAndroid so that callbacks are posted onto the render thread.
+class WebMediaPlayerProxyAndroid
+ : public base::RefCountedThreadSafe<WebMediaPlayerProxyAndroid> {
+ public:
+ WebMediaPlayerProxyAndroid(
+ const scoped_refptr<base::MessageLoopProxy>& render_loop,
+ base::WeakPtr<WebMediaPlayerAndroid> webmediaplayer);
+
+ // Callbacks from media::MediaPlayerBridge to WebMediaPlayerAndroid.
+ void MediaErrorCallback(int error_type);
+ void MediaInfoCallback(int info_type);
+ void VideoSizeChangedCallback(int width, int height);
+ void BufferingUpdateCallback(int percent);
+ void PlaybackCompleteCallback();
+ void SeekCompleteCallback();
+ void MediaPreparedCallback();
+
+ private:
+ friend class base::RefCountedThreadSafe<WebMediaPlayerProxyAndroid>;
+ virtual ~WebMediaPlayerProxyAndroid();
+
+ // Notify |webmediaplayer_| that an error has occured.
+ void MediaErrorTask(int error_type);
+
+ // Notify |webmediaplayer_| that some info has been received from
+ // media::MediaPlayerBridge.
+ void MediaInfoTask(int info_type);
+
+ // Notify |webmediaplayer_| that the video size has changed.
+ void VideoSizeChangedTask(int width, int height);
+
+ // Notify |webmediaplayer_| that an update in buffering has occured.
+ void BufferingUpdateTask(int percent);
+
+ // Notify |webmediaplayer_| that playback has completed.
+ void PlaybackCompleteTask();
+
+ // Notify |webmediaplayer_| that seek has completed.
+ void SeekCompleteTask();
+
+ // Notify |webmediaplayer_| that media has been prepared successfully.
+ void MediaPreparedTask();
+
+ // The render message loop where WebKit lives.
+ scoped_refptr<base::MessageLoopProxy> render_loop_;
+
+ // The WebMediaPlayerAndroid object all the callbacks should be send to.
+ base::WeakPtr<WebMediaPlayerAndroid> webmediaplayer_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerProxyAndroid);
+};
+
+} // namespace webkit_media
+
+#endif // WEBKIT_MEDIA_ANDROID_WEBMEDIAPLAYER_PROXY_ANDROID_H_
diff --git a/webkit/media/webkit_media.gypi b/webkit/media/webkit_media.gypi
index 879a423..be71b66 100644
--- a/webkit/media/webkit_media.gypi
+++ b/webkit/media/webkit_media.gypi
@@ -15,6 +15,10 @@
],
'sources': [
'android/audio_decoder_android.cc',
+ 'android/webmediaplayer_android.cc',
+ 'android/webmediaplayer_android.h',
+ 'android/webmediaplayer_proxy_android.cc',
+ 'android/webmediaplayer_proxy_android.h',
'active_loader.cc',
'active_loader.h',
'audio_decoder.cc',
@@ -36,6 +40,8 @@
'webmediaplayer_impl.h',
'webmediaplayer_proxy.cc',
'webmediaplayer_proxy.h',
+ 'webmediaplayer_util.cc',
+ 'webmediaplayer_util.h',
'webvideoframe_impl.cc',
'webvideoframe_impl.h',
],
@@ -45,12 +51,19 @@
'<(DEPTH)/webkit/support/setup_third_party.gyp:third_party_headers',
],
}],
- ['OS=="android"', {
+ ['OS == "android"', {
'sources!': [
'audio_decoder.cc',
'webmediaplayer_impl.cc',
'webmediaplayer_impl.h',
],
+ 'dependencies': [
+ '<(DEPTH)/media/media.gyp:player_android',
+ ],
+ }, { # OS != "android"'
+ 'sources/': [
+ ['exclude', '^android/'],
+ ],
}],
],
},
diff --git a/webkit/media/webmediaplayer_impl.cc b/webkit/media/webmediaplayer_impl.cc
index 77b86c2..2f2e22b 100644
--- a/webkit/media/webmediaplayer_impl.cc
+++ b/webkit/media/webmediaplayer_impl.cc
@@ -35,6 +35,7 @@
#include "webkit/media/key_systems.h"
#include "webkit/media/webmediaplayer_delegate.h"
#include "webkit/media/webmediaplayer_proxy.h"
+#include "webkit/media/webmediaplayer_util.h"
#include "webkit/media/webvideoframe_impl.h"
using WebKit::WebCanvas;
@@ -76,25 +77,6 @@ const int kPlayerExtraMemory = 1024 * 1024;
const float kMinRate = 0.0625f;
const float kMaxRate = 16.0f;
-// Platform independent method for converting and rounding floating point
-// seconds to an int64 timestamp.
-//
-// Refer to https://bugs.webkit.org/show_bug.cgi?id=52697 for details.
-base::TimeDelta ConvertSecondsToTimestamp(float seconds) {
- float microseconds = seconds * base::Time::kMicrosecondsPerSecond;
- float integer = ceilf(microseconds);
- float difference = integer - microseconds;
-
- // Round down if difference is large enough.
- if ((microseconds > 0 && difference > 0.5f) ||
- (microseconds <= 0 && difference >= 0.5f)) {
- integer -= 1.0f;
- }
-
- // Now we can safely cast to int64 microseconds.
- return base::TimeDelta::FromMicroseconds(static_cast<int64>(integer));
-}
-
} // namespace
namespace webkit_media {
diff --git a/webkit/media/webmediaplayer_util.cc b/webkit/media/webmediaplayer_util.cc
new file mode 100644
index 0000000..e2d5ef8
--- /dev/null
+++ b/webkit/media/webmediaplayer_util.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 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 "webkit/media/webmediaplayer_util.h"
+
+#include <math.h>
+
+namespace webkit_media {
+
+base::TimeDelta ConvertSecondsToTimestamp(float seconds) {
+ float microseconds = seconds * base::Time::kMicrosecondsPerSecond;
+ float integer = ceilf(microseconds);
+ float difference = integer - microseconds;
+
+ // Round down if difference is large enough.
+ if ((microseconds > 0 && difference > 0.5f) ||
+ (microseconds <= 0 && difference >= 0.5f)) {
+ integer -= 1.0f;
+ }
+
+ // Now we can safely cast to int64 microseconds.
+ return base::TimeDelta::FromMicroseconds(static_cast<int64>(integer));
+}
+
+} // namespace webkit_media
diff --git a/webkit/media/webmediaplayer_util.h b/webkit/media/webmediaplayer_util.h
new file mode 100644
index 0000000..8225354
--- /dev/null
+++ b/webkit/media/webmediaplayer_util.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 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.
+
+#ifndef WEBKIT_MEDIA_WEBMEDIAPLAYER_UTIL_H_
+#define WEBKIT_MEDIA_WEBMEDIAPLAYER_UTIL_H_
+
+#include "base/time.h"
+
+namespace webkit_media {
+
+// Platform independent method for converting and rounding floating point
+// seconds to an int64 timestamp.
+//
+// Refer to https://bugs.webkit.org/show_bug.cgi?id=52697 for details.
+base::TimeDelta ConvertSecondsToTimestamp(float seconds);
+
+} // namespace webkit_media
+
+#endif // WEBKIT_MEDIA_WEBMEDIAPLAYER_UTIL_H_