diff options
author | qinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-19 20:28:52 +0000 |
---|---|---|
committer | qinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-19 20:28:52 +0000 |
commit | 780fc824225e958594b4b0334f3d6d2dbc5ebf4e (patch) | |
tree | 4bba0c50e65162524bdc2860356d89002b74e0c6 /webkit/media | |
parent | afd2b9217c8384fb4ee3113964659775c9aea60d (diff) | |
download | chromium_src-780fc824225e958594b4b0334f3d6d2dbc5ebf4e.zip chromium_src-780fc824225e958594b4b0334f3d6d2dbc5ebf4e.tar.gz chromium_src-780fc824225e958594b4b0334f3d6d2dbc5ebf4e.tar.bz2 |
Move android mediaplayer from render process to browser process.
Due to UID isolation for security reasons, the render process can no longer have permissions to access internet.
Since Android mediaplayer requires internet permission to work, it has to be moved to the browser process to resolve this.
Here are the changes included in this patch:
1. Make WebMediaPlayerAndroid a common base class for WebMediaPlayerImplAndroid and WebMediaPlayerInProcessAndroid.
WebMediaPlayerImplAndroid places the android mediaplayer in the brower process, this will be used for future chrome on android releases.
WebMediaPlayerInProcessAndroid still places the android mediaplayer in the render process, this is being used for Layout tests. We will deprecate this later.
2.Added a commandline flag kMediaPlayerInRenderProcess to
allow switching between these 2 modes
3.MediaPlayerBridge now takes over all the logics originally in WebMediaPlayerAndroid. This is to shield WMPA from knowing the internal state of the mediaplayer.
BUG=
Review URL: https://chromiumcodereview.appspot.com/10919075
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@157596 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/media')
-rw-r--r-- | webkit/media/android/media_player_bridge_manager_impl.cc | 64 | ||||
-rw-r--r-- | webkit/media/android/media_player_bridge_manager_impl.h | 41 | ||||
-rw-r--r-- | webkit/media/android/webmediaplayer_android.cc | 310 | ||||
-rw-r--r-- | webkit/media/android/webmediaplayer_android.h | 177 | ||||
-rw-r--r-- | webkit/media/android/webmediaplayer_impl_android.cc | 83 | ||||
-rw-r--r-- | webkit/media/android/webmediaplayer_impl_android.h | 79 | ||||
-rw-r--r-- | webkit/media/android/webmediaplayer_in_process_android.cc | 177 | ||||
-rw-r--r-- | webkit/media/android/webmediaplayer_in_process_android.h | 117 | ||||
-rw-r--r-- | webkit/media/android/webmediaplayer_manager_android.cc | 42 | ||||
-rw-r--r-- | webkit/media/android/webmediaplayer_manager_android.h | 19 | ||||
-rw-r--r-- | webkit/media/android/webmediaplayer_proxy_android.cc | 55 | ||||
-rw-r--r-- | webkit/media/android/webmediaplayer_proxy_android.h | 70 | ||||
-rw-r--r-- | webkit/media/webkit_media.gypi | 6 |
13 files changed, 752 insertions, 488 deletions
diff --git a/webkit/media/android/media_player_bridge_manager_impl.cc b/webkit/media/android/media_player_bridge_manager_impl.cc new file mode 100644 index 0000000..acadb2d --- /dev/null +++ b/webkit/media/android/media_player_bridge_manager_impl.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/media_player_bridge_manager_impl.h" + +#include "media/base/android/media_player_bridge.h" + +namespace webkit_media { + +MediaPlayerBridgeManagerImpl::MediaPlayerBridgeManagerImpl( + int threshold) + : active_player_threshold_(threshold) { +} + +MediaPlayerBridgeManagerImpl::~MediaPlayerBridgeManagerImpl() {} + +void MediaPlayerBridgeManagerImpl::RequestMediaResources( + media::MediaPlayerBridge* player) { + if (!player) + return; + + int num_active_player = 0; + std::vector<media::MediaPlayerBridge*>::iterator it; + for (it = players_.begin(); it != players_.end(); ++it) { + // The player is already active, ignore it. + if ((*it) == player) + return; + + num_active_player++; + } + + if (num_active_player < active_player_threshold_) { + players_.push_back(player); + return; + } + + // Get a list of the players to free. + std::vector<media::MediaPlayerBridge*> players_to_release; + for (it = players_.begin(); it != players_.end(); ++it) { + if ((*it)->prepared() && !(*it)->IsPlaying()) + players_to_release.push_back(*it); + } + + // Calling release() will result in a call to ReleaseMediaResources(), so + // the player will be removed from |players_|. + for (it = players_to_release.begin(); it != players_to_release.end(); ++it) + (*it)->Release(); + + players_.push_back(player); +} + +void MediaPlayerBridgeManagerImpl::ReleaseMediaResources( + media::MediaPlayerBridge* player) { + for (std::vector<media::MediaPlayerBridge*>::iterator it = players_.begin(); + it != players_.end(); ++it) { + if ((*it) == player) { + players_.erase(it); + return; + } + } +} + +} // namespace webkit_media diff --git a/webkit/media/android/media_player_bridge_manager_impl.h b/webkit/media/android/media_player_bridge_manager_impl.h new file mode 100644 index 0000000..d3ca426 --- /dev/null +++ b/webkit/media/android/media_player_bridge_manager_impl.h @@ -0,0 +1,41 @@ +// 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_MEDIA_PLAYER_BRIDGE_MANAGER_IMPL_H_ +#define WEBKIT_MEDIA_ANDROID_MEDIA_PLAYER_BRIDGE_MANAGER_IMPL_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "media/base/android/media_player_bridge_manager.h" + +namespace webkit_media { + +// Class for managing active MediaPlayerBridge objects if they are created +// in render process. +class MediaPlayerBridgeManagerImpl : public media::MediaPlayerBridgeManager { + public: + // The manager will start to reclaim unused resources when the number of + // active MediaPlayerBridge objects reaches |threshold|. + explicit MediaPlayerBridgeManagerImpl(int threshold); + virtual ~MediaPlayerBridgeManagerImpl(); + + // media::MediaPlayerBridgeManager implementations. + virtual void RequestMediaResources(media::MediaPlayerBridge* player) OVERRIDE; + virtual void ReleaseMediaResources(media::MediaPlayerBridge* player) OVERRIDE; + + private: + // An array of active MediaPlayerBridge objects. + std::vector<media::MediaPlayerBridge*> players_; + + // Threshold before we start to reclaim unused media resources. + int active_player_threshold_; + + DISALLOW_COPY_AND_ASSIGN(MediaPlayerBridgeManagerImpl); +}; + +} // namespace webkit_media + +#endif // WEBKIT_MEDIA_ANDROID_MEDIA_PLAYER_BRIDGE_MANAGER_IMPL_H_ diff --git a/webkit/media/android/webmediaplayer_android.cc b/webkit/media/android/webmediaplayer_android.cc index 8032a8c..fae25d6 100644 --- a/webkit/media/android/webmediaplayer_android.cc +++ b/webkit/media/android/webmediaplayer_android.cc @@ -4,86 +4,49 @@ #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/WebDocument.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.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/stream_texture_factory_android.h" #include "webkit/media/android/webmediaplayer_manager_android.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; +static const uint32 kGLTextureExternalOES = 0x8D65; + 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; - -// TODO(qinmin): Figure out where we should define this more appropriately -static const uint32 kGLTextureExternalOES = 0x8D65; 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( - WebKit::WebFrame* frame, - WebMediaPlayerClient* client, - WebKit::WebCookieJar* cookie_jar, - webkit_media::WebMediaPlayerManagerAndroid* manager, - webkit_media::StreamTextureFactory* factory) - : frame_(frame), - client_(client), + WebKit::WebMediaPlayerClient* client, + WebMediaPlayerManagerAndroid* manager, + StreamTextureFactory* factory) + : client_(client), buffered_(1u), video_frame_(new WebVideoFrameImpl(VideoFrame::CreateEmptyFrame())), main_loop_(MessageLoop::current()), - proxy_(new WebMediaPlayerProxyAndroid(main_loop_->message_loop_proxy(), - AsWeakPtr())), - prepared_(false), - duration_(0), pending_seek_(0), seeking_(false), - playback_completed_(false), did_loading_progress_(false), - cookie_jar_(cookie_jar), manager_(manager), - pending_play_event_(false), network_state_(WebMediaPlayer::NetworkStateEmpty), ready_state_(WebMediaPlayer::ReadyStateHaveNothing), - texture_id_(0), - stream_id_(0), + is_playing_(false), needs_establish_peer_(true), stream_texture_factory_(factory) { main_loop_->AddDestructionObserver(this); if (manager_) player_id_ = manager_->RegisterMediaPlayer(this); + if (stream_texture_factory_.get()) { stream_texture_proxy_.reset(stream_texture_factory_->CreateProxy()); stream_id_ = stream_texture_factory_->CreateStreamTexture(&texture_id_); @@ -91,50 +54,23 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid( } WebMediaPlayerAndroid::~WebMediaPlayerAndroid() { - if (manager_) - manager_->UnregisterMediaPlayer(player_id_); - if (stream_id_) stream_texture_factory_->DestroyStreamTexture(texture_id_); + if (manager_) + manager_->UnregisterMediaPlayer(player_id_); + if (main_loop_) main_loop_->RemoveDestructionObserver(this); } -void WebMediaPlayerAndroid::InitIncognito(bool incognito_mode) { - incognito_mode_ = incognito_mode; -} - void WebMediaPlayerAndroid::load(const WebURL& url, CORSMode cors_mode) { if (cors_mode != CORSModeUnspecified) NOTIMPLEMENTED() << "No CORS support"; url_ = url; - UpdateNetworkState(WebMediaPlayer::NetworkStateLoading); - UpdateReadyState(WebMediaPlayer::ReadyStateHaveNothing); - - // 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::ReadyStateHaveMetadata); - UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); + InitializeMediaPlayer(url_); } void WebMediaPlayerAndroid::cancelLoad() { @@ -142,42 +78,23 @@ void WebMediaPlayerAndroid::cancelLoad() { } void WebMediaPlayerAndroid::play() { - if (media_player_.get()) { - if (!prepared_) - pending_play_event_ = true; - else - PlayInternal(); - } else { - pending_play_event_ = true; - InitializeMediaPlayer(); - } + if (hasVideo() && needs_establish_peer_) + EstablishSurfaceTexturePeer(); + + PlayInternal(); + is_playing_ = true; } 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; - } + PauseInternal(); + is_playing_ = false; } void WebMediaPlayerAndroid::seek(float seconds) { - // Record the time to seek when OnMediaPrepared() is called. pending_seek_ = seconds; + seeking_ = true; - // Reset |playback_completed_| so that we return the correct current time. - playback_completed_ = false; - - if (media_player_.get()) { - if (prepared_) - SeekInternal(seconds); - } else { - InitializeMediaPlayer(); - } + SeekInternal(ConvertSecondsToTimestamp(seconds)); } bool WebMediaPlayerAndroid::supportsFullscreen() const { @@ -198,8 +115,7 @@ void WebMediaPlayerAndroid::setRate(float rate) { } void WebMediaPlayerAndroid::setVolume(float volume) { - if (media_player_.get()) - media_player_->SetVolume(volume, volume); + NOTIMPLEMENTED(); } void WebMediaPlayerAndroid::setVisible(bool visible) { @@ -213,6 +129,10 @@ bool WebMediaPlayerAndroid::totalBytesKnown() { } bool WebMediaPlayerAndroid::hasVideo() const { + // If we have obtained video size information before, use it. + if (!natural_size_.isEmpty()) + return true; + // TODO(qinmin): need a better method to determine whether the current media // content contains video. Android does not provide any function to do // this. @@ -221,16 +141,12 @@ bool WebMediaPlayerAndroid::hasVideo() const { // 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(); + 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; } bool WebMediaPlayerAndroid::hasAudio() const { @@ -239,9 +155,7 @@ bool WebMediaPlayerAndroid::hasAudio() const { } bool WebMediaPlayerAndroid::paused() const { - if (!prepared_) - return !pending_play_event_; - return !media_player_->IsPlaying(); + return !is_playing_; } bool WebMediaPlayerAndroid::seeking() const { @@ -249,23 +163,15 @@ bool WebMediaPlayerAndroid::seeking() const { } float WebMediaPlayerAndroid::duration() const { - return duration_; + return static_cast<float>(duration_.InSecondsF()); } float WebMediaPlayerAndroid::currentTime() const { // If the player is pending for a seek, return the seek time. - if (!prepared_ || seeking()) + if (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()); + return GetCurrentTimeInternal(); } int WebMediaPlayerAndroid::dataRate() const { @@ -307,8 +213,7 @@ unsigned long long WebMediaPlayerAndroid::totalBytes() const { return 0; } -void WebMediaPlayerAndroid::setSize(const WebSize& size) { - texture_size_ = size; +void WebMediaPlayerAndroid::setSize(const WebKit::WebSize& size) { } void WebMediaPlayerAndroid::paint(WebKit::WebCanvas* canvas, @@ -325,8 +230,7 @@ bool WebMediaPlayerAndroid::didPassCORSAccessCheck() const { return false; } -WebMediaPlayer::MovieLoadType - WebMediaPlayerAndroid::movieLoadType() const { +WebMediaPlayer::MovieLoadType WebMediaPlayerAndroid::movieLoadType() const { // Deprecated. // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. return WebMediaPlayer::MovieLoadTypeUnknown; @@ -356,17 +260,7 @@ unsigned WebMediaPlayerAndroid::videoDecodedByteCount() const { 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(); - +void WebMediaPlayerAndroid::OnMediaPrepared(base::TimeDelta duration) { if (url_.SchemeIs("file")) UpdateNetworkState(WebMediaPlayer::NetworkStateLoaded); @@ -379,30 +273,20 @@ void WebMediaPlayerAndroid::OnMediaPrepared() { UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); } - 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(); - } + // In we have skipped loading, we have to update webkit about the new + // duration. + if (duration_ != duration) { + duration_ = duration; + 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; + // 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. + OnTimeUpdate(duration_); client_->timeChanged(); } @@ -411,9 +295,11 @@ void WebMediaPlayerAndroid::OnBufferingUpdate(int percentage) { did_loading_progress_ = true; } -void WebMediaPlayerAndroid::OnSeekComplete() { +void WebMediaPlayerAndroid::OnSeekComplete(base::TimeDelta current_time) { seeking_ = false; + OnTimeUpdate(current_time); + UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); client_->timeChanged(); @@ -441,10 +327,6 @@ void WebMediaPlayerAndroid::OnMediaError(int error_type) { client_->repaint(); } -void WebMediaPlayerAndroid::OnMediaInfo(int info_type) { - NOTIMPLEMENTED(); -} - void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) { if (natural_size_.width == width && natural_size_.height == height) return; @@ -471,84 +353,39 @@ void WebMediaPlayerAndroid::UpdateReadyState( client_->readyStateChanged(); } +void WebMediaPlayerAndroid::OnPlayerReleased() { + needs_establish_peer_ = true; +} + void WebMediaPlayerAndroid::ReleaseMediaResources() { // Pause the media player first. pause(); client_->playbackStateChanged(); - if (media_player_.get()) { - // Save the current media player status. - pending_seek_ = currentTime(); - duration_ = duration(); - - media_player_.reset(); - needs_establish_peer_ = true; - } - prepared_ = false; -} - -bool WebMediaPlayerAndroid::IsInitialized() const { - return (media_player_ != NULL); -} - -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 first_party_url(frame_->document().firstPartyForCookies()); - cookies = UTF16ToUTF8(cookie_jar_->cookies(url_, first_party_url)); - } - media_player_->SetDataSource(url_.spec(), cookies, incognito_mode_); - - if (manager_) - manager_->RequestMediaResources(player_id_); - - 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_)); + ReleaseResourcesInternal(); + OnPlayerReleased(); } -void WebMediaPlayerAndroid::PlayInternal() { - CHECK(prepared_); +void WebMediaPlayerAndroid::WillDestroyCurrentMessageLoop() { + Destroy(); - if (hasVideo() && stream_texture_factory_.get()) { - if (needs_establish_peer_) { - stream_texture_factory_->EstablishPeer(stream_id_, player_id_); - needs_establish_peer_ = false; - } + if (stream_id_) { + stream_texture_factory_->DestroyStreamTexture(texture_id_); + stream_id_ = 0; } - if (paused()) - media_player_->Start(base::Bind( - &WebMediaPlayerProxyAndroid::PlaybackCompleteCallback, proxy_)); -} - -void WebMediaPlayerAndroid::PauseInternal() { - CHECK(prepared_); - media_player_->Pause(); -} + video_frame_.reset(new WebVideoFrameImpl(VideoFrame::CreateEmptyFrame())); -void WebMediaPlayerAndroid::SeekInternal(float seconds) { - CHECK(prepared_); - seeking_ = true; - media_player_->SeekTo(ConvertSecondsToTimestamp(seconds), base::Bind( - &WebMediaPlayerProxyAndroid::SeekCompleteCallback, proxy_)); -} + if (manager_) + manager_->UnregisterMediaPlayer(player_id_); -void WebMediaPlayerAndroid::WillDestroyCurrentMessageLoop() { manager_ = NULL; main_loop_ = NULL; } WebVideoFrame* WebMediaPlayerAndroid::getCurrentFrame() { - if (!stream_texture_proxy_->IsInitialized() && stream_id_) { + if (stream_texture_proxy_.get() && !stream_texture_proxy_->IsInitialized() + && stream_id_) { stream_texture_proxy_->Initialize( stream_id_, video_frame_->width(), video_frame_->height()); } @@ -560,11 +397,20 @@ void WebMediaPlayerAndroid::putCurrentFrame( WebVideoFrame* web_video_frame) { } -// This gets called both on compositor and main thread. void WebMediaPlayerAndroid::setStreamTextureClient( WebKit::WebStreamTextureClient* client) { if (stream_texture_proxy_.get()) stream_texture_proxy_->SetClient(client); } +void WebMediaPlayerAndroid::EstablishSurfaceTexturePeer() { + if (stream_texture_factory_.get() && stream_id_) + stream_texture_factory_->EstablishPeer(stream_id_, player_id_); + needs_establish_peer_ = false; +} + +void WebMediaPlayerAndroid::UpdatePlayingState(bool is_playing) { + is_playing_ = is_playing; +} + } // namespace webkit_media diff --git a/webkit/media/android/webmediaplayer_android.h b/webkit/media/android/webmediaplayer_android.h index 3bcfd3e..9869e30 100644 --- a/webkit/media/android/webmediaplayer_android.h +++ b/webkit/media/android/webmediaplayer_android.h @@ -10,46 +10,24 @@ #include "base/basictypes.h" #include "base/message_loop.h" #include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" +#include "base/time.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayer.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebVideoFrame.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; -class WebFrame; -} - -namespace media { -class MediaPlayerBridge; -} namespace webkit_media { class StreamTextureFactory; class StreamTextureProxy; class WebMediaPlayerManagerAndroid; -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 MessageLoop::DestructionObserver, - public base::SupportsWeakPtr<WebMediaPlayerAndroid> { - public: - WebMediaPlayerAndroid(WebKit::WebFrame* frame, - WebKit::WebMediaPlayerClient* client, - WebKit::WebCookieJar* cookie_jar, - webkit_media::WebMediaPlayerManagerAndroid* manager, - webkit_media::StreamTextureFactory* factory); - virtual ~WebMediaPlayerAndroid(); - - // Set |incognito_mode_| to true if in incognito mode. - static void InitIncognito(bool incognito_mode); +// An abstract class that serves as the common base class for implementing +// WebKit::WebMediaPlayer on Android. +class WebMediaPlayerAndroid + : public WebKit::WebMediaPlayer, + public MessageLoop::DestructionObserver { + public: // Resource loading. virtual void load(const WebKit::WebURL& url, CORSMode cors_mode); virtual void cancelLoad(); @@ -113,111 +91,117 @@ class WebMediaPlayerAndroid : // compositor thread. virtual WebKit::WebVideoFrame* getCurrentFrame(); virtual void putCurrentFrame(WebKit::WebVideoFrame*); - virtual void setStreamTextureClient( - WebKit::WebStreamTextureClient* client); + + // This gets called both on compositor and main thread to set the callback + // target when a frame is produced. + virtual void setStreamTextureClient(WebKit::WebStreamTextureClient* client); // 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); - - // This function is called by WebMediaPlayerManagerAndroid to pause the video - // and release |media_player_| and its surface texture when we switch tabs. + virtual void OnMediaPrepared(base::TimeDelta duration); + virtual void OnPlaybackComplete(); + virtual void OnBufferingUpdate(int percentage); + virtual void OnSeekComplete(base::TimeDelta current_time); + virtual void OnMediaError(int error_type); + virtual void OnVideoSizeChanged(int width, int height); + + // Called to update the current time. + virtual void OnTimeUpdate(base::TimeDelta current_time) = 0; + + // Called when the player is released. + virtual void OnPlayerReleased(); + + // This function is called by the WebMediaPlayerManagerAndroid to pause the + // video and release the media player and surface texture when we switch tabs. // However, the actual GlTexture is not released to keep the video screenshot. - void ReleaseMediaResources(); + virtual void ReleaseMediaResources(); - // Whether |media_player_| has been initialized. - bool IsInitialized() const; + // Method to set the surface for video. + virtual void SetVideoSurface(jobject j_surface) = 0; // Method inherited from DestructionObserver. virtual void WillDestroyCurrentMessageLoop() OVERRIDE; - 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(); + protected: + // Construct a WebMediaPlayerAndroid object with reference to the + // client, manager and stream texture factory. + WebMediaPlayerAndroid(WebKit::WebMediaPlayerClient* client, + WebMediaPlayerManagerAndroid* manager, + StreamTextureFactory* factory); + virtual ~WebMediaPlayerAndroid(); - // Functions that implements media player control. - void PlayInternal(); - void PauseInternal(); - void SeekInternal(float seconds); + // Helper method to update the playing state. + virtual void UpdatePlayingState(bool is_playing_); // Helper methods for posting task for setting states and update WebKit. - void UpdateNetworkState(WebKit::WebMediaPlayer::NetworkState state); - void UpdateReadyState(WebKit::WebMediaPlayer::ReadyState state); + virtual void UpdateNetworkState(WebKit::WebMediaPlayer::NetworkState state); + virtual void UpdateReadyState(WebKit::WebMediaPlayer::ReadyState state); + + // Helper method to reestablish the surface texture peer for android + // mediaplayer. + virtual void EstablishSurfaceTexturePeer(); + + // Method to be implemented by child classes. + // Initialize the media player bridge object. + virtual void InitializeMediaPlayer(GURL url) = 0; - // whether the current process is incognito mode - static bool incognito_mode_; + // Inform the media player to start playing. + virtual void PlayInternal() = 0; - WebKit::WebFrame* frame_; + // Inform the media player to pause. + virtual void PauseInternal() = 0; + // Inform the media player to seek to a particular position. + virtual void SeekInternal(base::TimeDelta time) = 0; + + // Get the current time from the media player. + virtual float GetCurrentTimeInternal() const = 0; + + // Release the Android Media player. + virtual void ReleaseResourcesInternal() = 0; + + // Cleaning up all remaining resources as this object is about to get deleted. + virtual void Destroy() = 0; + + WebKit::WebMediaPlayerClient* client() { return client_; } + + int player_id() { return player_id_; } + + private: 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_; - // Message loops for main renderer thread. + // Message loop for main renderer thread. MessageLoop* main_loop_; - // 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_; + base::TimeDelta 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. + // The time android media player is trying to seek. float pending_seek_; // Internal seek state. bool seeking_; - // Whether playback has completed. - float playback_completed_; - // Whether loading has progressed since the last call to didLoadingProgress. mutable bool did_loading_progress_; - // Pointer to the cookie jar to get the cookie for the media url. - WebKit::WebCookieJar* cookie_jar_; + // Manager for managing this object. + WebMediaPlayerManagerAndroid* manager_; - // Manager for managing this media player. - webkit_media::WebMediaPlayerManagerAndroid* manager_; - - // Player ID assigned by the media player manager. + // Player ID assigned by the |manager_|. int player_id_; - // 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_; @@ -228,15 +212,18 @@ class WebMediaPlayerAndroid : // Stream texture ID allocated to the video. unsigned int stream_id_; - // Whether |media_player_| needs to re-establish the surface texture peer. + // Whether the mediaplayer is playing. + bool is_playing_; + + // Whether media player needs to re-establish the surface texture peer. bool needs_establish_peer_; // Object for allocating stream textures. - scoped_ptr<webkit_media::StreamTextureFactory> stream_texture_factory_; + scoped_ptr<StreamTextureFactory> stream_texture_factory_; // Object for calling back the compositor thread to repaint the video when a // frame available. It should be initialized on the compositor thread. - scoped_ptr<webkit_media::StreamTextureProxy> stream_texture_proxy_; + scoped_ptr<StreamTextureProxy> stream_texture_proxy_; DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerAndroid); }; diff --git a/webkit/media/android/webmediaplayer_impl_android.cc b/webkit/media/android/webmediaplayer_impl_android.cc new file mode 100644 index 0000000..e38d1f2 --- /dev/null +++ b/webkit/media/android/webmediaplayer_impl_android.cc @@ -0,0 +1,83 @@ +// 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_impl_android.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "media/base/android/media_player_bridge.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerClient.h" +#include "webkit/media/android/stream_texture_factory_android.h" +#include "webkit/media/android/webmediaplayer_manager_android.h" +#include "webkit/media/android/webmediaplayer_proxy_android.h" + +using WebKit::WebMediaPlayerClient; +using WebKit::WebMediaPlayer; + +namespace webkit_media { + +WebMediaPlayerImplAndroid::WebMediaPlayerImplAndroid( + WebKit::WebFrame* frame, + WebMediaPlayerClient* client, + WebMediaPlayerManagerAndroid* manager, + WebMediaPlayerProxyAndroid* proxy, + StreamTextureFactory* factory) + : WebMediaPlayerAndroid(client, manager, factory), + frame_(frame), + proxy_(proxy), + current_time_(0) { +} + +WebMediaPlayerImplAndroid::~WebMediaPlayerImplAndroid() { + Destroy(); +} + +void WebMediaPlayerImplAndroid::InitializeMediaPlayer(GURL url) { + GURL first_party_url = frame_->document().firstPartyForCookies(); + if (proxy_) { + proxy_->Initialize(player_id(), url.spec(), first_party_url.spec()); + } + + UpdateNetworkState(WebMediaPlayer::NetworkStateLoading); + UpdateReadyState(WebMediaPlayer::ReadyStateHaveNothing); +} + +void WebMediaPlayerImplAndroid::PlayInternal() { + if (paused() && proxy_) + proxy_->Start(player_id()); +} + +void WebMediaPlayerImplAndroid::PauseInternal() { + if (proxy_) + proxy_->Pause(player_id()); +} + +void WebMediaPlayerImplAndroid::SeekInternal(base::TimeDelta time) { + if (proxy_) + proxy_->Seek(player_id(), time); +} + +float WebMediaPlayerImplAndroid::GetCurrentTimeInternal() const { + return current_time_; +} + +void WebMediaPlayerImplAndroid::ReleaseResourcesInternal() { + if (proxy_) + proxy_->ReleaseResources(player_id()); +} + +void WebMediaPlayerImplAndroid::OnTimeUpdate(base::TimeDelta current_time) { + current_time_ = static_cast<float>(current_time.InSecondsF()); +} + +void WebMediaPlayerImplAndroid::Destroy() { + proxy_->DestroyPlayer(player_id()); + proxy_ = NULL; +} + +void WebMediaPlayerImplAndroid::SetVideoSurface(jobject j_surface) {} + +} // namespace webkit_media diff --git a/webkit/media/android/webmediaplayer_impl_android.h b/webkit/media/android/webmediaplayer_impl_android.h new file mode 100644 index 0000000..20a87e1 --- /dev/null +++ b/webkit/media/android/webmediaplayer_impl_android.h @@ -0,0 +1,79 @@ +// 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_IMPL_ANDROID_H_ +#define WEBKIT_MEDIA_ANDROID_WEBMEDIAPLAYER_IMPL_ANDROID_H_ + +#include <string> + +#include <jni.h> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayer.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebVideoFrame.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURL.h" +#include "webkit/media/android/webmediaplayer_android.h" + +namespace WebKit { +class WebFrame; +} + +namespace webkit_media { + +class StreamTextureFactory; +class WebMediaPlayerManagerAndroid; +class WebMediaPlayerProxyAndroid; + +// This class implements WebKit::WebMediaPlayer by keeping the android +// media player in the browser process. It listens to all the status changes +// sent from the browser process and sends playback controls to the media +// player. +class WebMediaPlayerImplAndroid : public WebMediaPlayerAndroid { + public: + // Construct a WebMediaPlayerImplAndroid object. This class communicates + // with the MediaPlayerBridge object in the browser process through + // |proxy|. + // TODO(qinmin): |frame| argument is used to determine whether the current + // player can enter fullscreen. + WebMediaPlayerImplAndroid(WebKit::WebFrame* frame, + WebKit::WebMediaPlayerClient* client, + WebMediaPlayerManagerAndroid* manager, + WebMediaPlayerProxyAndroid* proxy, + StreamTextureFactory* factory); + virtual ~WebMediaPlayerImplAndroid(); + + // WebMediaPlayerAndroid implementation. + virtual void OnTimeUpdate(base::TimeDelta current_time) OVERRIDE; + virtual void SetVideoSurface(jobject j_surface) OVERRIDE; + + private: + // Methods inherited from WebMediaPlayerAndroid. + virtual void InitializeMediaPlayer(GURL url) OVERRIDE; + virtual void PlayInternal() OVERRIDE; + virtual void PauseInternal() OVERRIDE; + virtual void SeekInternal(base::TimeDelta time) OVERRIDE; + virtual float GetCurrentTimeInternal() const OVERRIDE; + virtual void ReleaseResourcesInternal() OVERRIDE; + virtual void Destroy() OVERRIDE; + + WebKit::WebFrame* const 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. + WebMediaPlayerProxyAndroid* proxy_; + + // The current playing time. Because the mediaplayer is in the browser + // process, it will regularly update the |current_time_| by calling + // OnTimeUpdate(). + float current_time_; + + DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerImplAndroid); +}; + +} // namespace webkit_media + +#endif // WEBKIT_MEDIA_ANDROID_WEBMEDIAPLAYER_IMPL_ANDROID_H_ diff --git a/webkit/media/android/webmediaplayer_in_process_android.cc b/webkit/media/android/webmediaplayer_in_process_android.cc new file mode 100644 index 0000000..aea5a05 --- /dev/null +++ b/webkit/media/android/webmediaplayer_in_process_android.cc @@ -0,0 +1,177 @@ +// 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_in_process_android.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "base/utf_string_conversions.h" +#include "media/base/android/media_player_bridge.h" +#include "media/base/android/media_player_bridge_manager.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerClient.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCookieJar.h" +#include "webkit/media/android/stream_texture_factory_android.h" +#include "webkit/media/android/webmediaplayer_manager_android.h" + +using WebKit::WebMediaPlayerClient; +using WebKit::WebMediaPlayer; +using WebKit::WebURL; +using media::MediaPlayerBridge; + +namespace webkit_media { + +InProcessCookieGetter::InProcessCookieGetter(WebKit::WebCookieJar* cookie_jar) + : cookie_jar_(cookie_jar) { +} + +InProcessCookieGetter::~InProcessCookieGetter() {} + +void InProcessCookieGetter::GetCookies( + const std::string& url, + const std::string& first_party_for_cookies, + const GetCookieCB& callback) { + std::string cookies; + if (cookie_jar_ != NULL) { + cookies = UTF16ToUTF8( + cookie_jar_->cookies(GURL(url), GURL(first_party_for_cookies))); + } + callback.Run(cookies); +} + +WebMediaPlayerInProcessAndroid::WebMediaPlayerInProcessAndroid( + WebKit::WebFrame* frame, + WebMediaPlayerClient* client, + WebKit::WebCookieJar* cookie_jar, + WebMediaPlayerManagerAndroid* manager, + media::MediaPlayerBridgeManager* resource_manager, + StreamTextureFactory* factory, + bool disable_media_history_logging) + : WebMediaPlayerAndroid(client, manager, factory), + frame_(frame), + playback_completed_(false), + cookie_jar_(cookie_jar), + resource_manager_(resource_manager), + disable_history_logging_(disable_media_history_logging) { +} + +WebMediaPlayerInProcessAndroid::~WebMediaPlayerInProcessAndroid() {} + +void WebMediaPlayerInProcessAndroid::PlayInternal() { + if (paused()) + media_player_->Start(); +} + +void WebMediaPlayerInProcessAndroid::PauseInternal() { + if (!paused()) + media_player_->Pause(); +} + +void WebMediaPlayerInProcessAndroid::SeekInternal(base::TimeDelta time) { + playback_completed_ = false; + media_player_->SeekTo(time); +} + +bool WebMediaPlayerInProcessAndroid::paused() const { + return !media_player_->IsPlaying(); +} + +float WebMediaPlayerInProcessAndroid::GetCurrentTimeInternal() const { + // 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. + if (playback_completed_) + return duration(); + return static_cast<float>(media_player_->GetCurrentTime().InSecondsF()); +} + +void WebMediaPlayerInProcessAndroid::ReleaseResourcesInternal() { + media_player_->Release(); +} + +void WebMediaPlayerInProcessAndroid::MediaPreparedCallback( + int player_id, base::TimeDelta duration) { + OnMediaPrepared(duration); +} + +void WebMediaPlayerInProcessAndroid::PlaybackCompleteCallback(int player_id) { + // Set the current time equal to duration to let webkit know that play back + // is completed. + playback_completed_ = true; + client()->timeChanged(); +} + +void WebMediaPlayerInProcessAndroid::SeekCompleteCallback( + int player_id, base::TimeDelta current_time) { + OnSeekComplete(current_time); +} + +void WebMediaPlayerInProcessAndroid::MediaErrorCallback(int player_id, + int error_type) { + OnMediaError(error_type); +} + +void WebMediaPlayerInProcessAndroid::VideoSizeChangedCallback( + int player_id, int width, int height) { + OnVideoSizeChanged(width, height); +} + +void WebMediaPlayerInProcessAndroid::BufferingUpdateCallback( + int player_id, int percent) { + OnBufferingUpdate(percent); +} + +void WebMediaPlayerInProcessAndroid::SetVideoSurface(jobject j_surface) { + media_player_->SetVideoSurface(j_surface); +} + +void WebMediaPlayerInProcessAndroid::InitializeMediaPlayer(GURL url) { + GURL first_party_url = frame_->document().firstPartyForCookies(); + media_player_.reset(new MediaPlayerBridge( + player_id(), url.spec(), first_party_url.spec(), + new InProcessCookieGetter(cookie_jar_), + disable_history_logging_, + resource_manager_, + base::Bind(&WebMediaPlayerInProcessAndroid::MediaErrorCallback, + base::Unretained(this)), + base::Bind(&WebMediaPlayerInProcessAndroid::VideoSizeChangedCallback, + base::Unretained(this)), + base::Bind(&WebMediaPlayerInProcessAndroid::BufferingUpdateCallback, + base::Unretained(this)), + base::Bind(&WebMediaPlayerInProcessAndroid::MediaPreparedCallback, + base::Unretained(this)), + base::Bind(&WebMediaPlayerInProcessAndroid::PlaybackCompleteCallback, + base::Unretained(this)), + base::Bind(&WebMediaPlayerInProcessAndroid::SeekCompleteCallback, + base::Unretained(this)), + base::Bind(&WebMediaPlayerInProcessAndroid::TimeUpdateCallback, + base::Unretained(this)))); + + UpdateNetworkState(WebMediaPlayer::NetworkStateLoading); + UpdateReadyState(WebMediaPlayer::ReadyStateHaveNothing); + + // Calling Prepare() 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")) { + media_player_->Prepare(); + return; + } + + // Pretend everything has been loaded so that webkit can + // still call play() and seek(). + UpdateReadyState(WebMediaPlayer::ReadyStateHaveMetadata); + UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); +} + +void WebMediaPlayerInProcessAndroid::OnTimeUpdate( + base::TimeDelta current_time) {} + +void WebMediaPlayerInProcessAndroid::Destroy() {} + +} // namespace webkit_media diff --git a/webkit/media/android/webmediaplayer_in_process_android.h b/webkit/media/android/webmediaplayer_in_process_android.h new file mode 100644 index 0000000..bfd37c2 --- /dev/null +++ b/webkit/media/android/webmediaplayer_in_process_android.h @@ -0,0 +1,117 @@ +// 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_IN_PROCESS_ANDROID_H_ +#define WEBKIT_MEDIA_ANDROID_WEBMEDIAPLAYER_IN_PROCESS_ANDROID_H_ + +#include <string> + +#include <jni.h> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "media/base/android/cookie_getter.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayer.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebVideoFrame.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURL.h" +#include "webkit/media/android/webmediaplayer_android.h" + +namespace WebKit { +class WebCookieJar; +class WebFrame; +} + +namespace media { +class MediaPlayerBridge; +class MediaPlayerBridgeManager; +} + +namespace webkit_media { + +class StreamTextureFactory; +class WebMediaPlayerManagerAndroid; + +// Class for retrieving the cookies from WebCookieJar. +class InProcessCookieGetter : public media::CookieGetter { + public: + // Construct an InProcessCookieGetter object from a WebCookieJar. + explicit InProcessCookieGetter(WebKit::WebCookieJar* cookie_jar); + virtual ~InProcessCookieGetter(); + + // media::CookieGetter implementation. + virtual void GetCookies(const std::string& url, + const std::string& first_party_for_cookies, + const GetCookieCB& callback) OVERRIDE; + +private: + WebKit::WebCookieJar* cookie_jar_; + DISALLOW_COPY_AND_ASSIGN(InProcessCookieGetter); +}; + +// This class implements WebKit::WebMediaPlayer by keeping the android +// mediaplayer in the render process. This mode is being deprecated +// as mediaplayer is going to be moved to the browser process. +class WebMediaPlayerInProcessAndroid : public WebMediaPlayerAndroid { + public: + // Construct a WebMediaPlayerInProcessAndroid object. + WebMediaPlayerInProcessAndroid( + WebKit::WebFrame* frame, + WebKit::WebMediaPlayerClient* client, + WebKit::WebCookieJar* cookie_jar, + WebMediaPlayerManagerAndroid* manager, + media::MediaPlayerBridgeManager* resource_manager, + StreamTextureFactory* factory, + bool disable_media_history_logging); + virtual ~WebMediaPlayerInProcessAndroid(); + + // Getters of playback state. + virtual bool paused() const; + + // Callbacks from media::MediaPlayerBridge to WebMediaPlayerInProcessAndroid. + void MediaErrorCallback(int player_id, int error_type); + void VideoSizeChangedCallback(int player_id, int width, int height); + void BufferingUpdateCallback(int player_id, int percent); + void PlaybackCompleteCallback(int player_id); + void SeekCompleteCallback(int player_id, base::TimeDelta current_time); + void MediaPreparedCallback(int player_id, base::TimeDelta duration); + void TimeUpdateCallback(int player_id, base::TimeDelta current_time) {} + + // WebMediaPlayerAndroid implementation. + virtual void SetVideoSurface(jobject j_surface) OVERRIDE; + virtual void OnTimeUpdate(base::TimeDelta current_time) OVERRIDE; + + private: + // Methods inherited from WebMediaPlayerAndroid. + virtual void InitializeMediaPlayer(GURL url) OVERRIDE; + virtual void PlayInternal() OVERRIDE; + virtual void PauseInternal() OVERRIDE; + virtual void SeekInternal(base::TimeDelta time) OVERRIDE; + virtual float GetCurrentTimeInternal() const OVERRIDE; + virtual void ReleaseResourcesInternal() OVERRIDE; + virtual void Destroy() OVERRIDE; + + WebKit::WebFrame* const frame_; + + // Bridge to the android media player. + scoped_ptr<media::MediaPlayerBridge> media_player_; + + // Whether playback has completed. + float playback_completed_; + + // Pointer to the cookie jar to get the cookie for the media url. + WebKit::WebCookieJar* cookie_jar_; + + // Manager for managing all the hardware player resources. + media::MediaPlayerBridgeManager* resource_manager_; + + // Whether we should disable history logging. + bool disable_history_logging_; + + DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerInProcessAndroid); +}; + +} // namespace webkit_media + +#endif // WEBKIT_MEDIA_ANDROID_WEBMEDIAPLAYER_IN_PROCESS_ANDROID_H_ diff --git a/webkit/media/android/webmediaplayer_manager_android.cc b/webkit/media/android/webmediaplayer_manager_android.cc index 4d2ae88..f93854d 100644 --- a/webkit/media/android/webmediaplayer_manager_android.cc +++ b/webkit/media/android/webmediaplayer_manager_android.cc @@ -6,10 +6,6 @@ #include "webkit/media/android/webmediaplayer_android.h" -// Threshold on the number of media players per renderer before we start -// attempting to release inactive media players. -static const int kMediaPlayerThreshold = 2; - namespace webkit_media { WebMediaPlayerManagerAndroid::WebMediaPlayerManagerAndroid() @@ -27,37 +23,9 @@ int WebMediaPlayerManagerAndroid::RegisterMediaPlayer( } void WebMediaPlayerManagerAndroid::UnregisterMediaPlayer(int player_id) { - std::map<int32, WebMediaPlayerAndroid*>::iterator iter = - media_players_.find(player_id); - DCHECK(iter != media_players_.end()); - media_players_.erase(player_id); } -void WebMediaPlayerManagerAndroid::RequestMediaResources(int player_id) { - std::map<int32, WebMediaPlayerAndroid*>::iterator iter = - media_players_.find(player_id); - DCHECK(iter != media_players_.end()); - - if ((iter->second)->IsInitialized()) - return; - - // Release active players that are paused. Because we only release paused - // players, the number of running players could go beyond the limit. - // TODO(qinmin): we should use LRU to release the oldest player if we are - // reaching hardware limit. - if (GetActivePlayerCount() < kMediaPlayerThreshold) - return; - - std::map<int32, WebMediaPlayerAndroid*>::iterator player_it; - for (player_it = media_players_.begin(); - player_it != media_players_.end(); ++player_it) { - WebMediaPlayerAndroid* player = player_it->second; - if (player->IsInitialized() && player->paused()) - player->ReleaseMediaResources(); - } -} - void WebMediaPlayerManagerAndroid::ReleaseMediaResources() { std::map<int32, WebMediaPlayerAndroid*>::iterator player_it; for (player_it = media_players_.begin(); @@ -66,16 +34,6 @@ void WebMediaPlayerManagerAndroid::ReleaseMediaResources() { } } -int32 WebMediaPlayerManagerAndroid::GetActivePlayerCount() { - int32 count = 0; - std::map<int32, WebMediaPlayerAndroid*>::iterator iter; - for (iter = media_players_.begin(); iter != media_players_.end(); ++iter) { - if ((iter->second)->IsInitialized()) - count++; - } - return count; -} - WebMediaPlayerAndroid* WebMediaPlayerManagerAndroid::GetMediaPlayer( int player_id) { std::map<int32, WebMediaPlayerAndroid*>::iterator iter = diff --git a/webkit/media/android/webmediaplayer_manager_android.h b/webkit/media/android/webmediaplayer_manager_android.h index ab29303..29482b7 100644 --- a/webkit/media/android/webmediaplayer_manager_android.h +++ b/webkit/media/android/webmediaplayer_manager_android.h @@ -5,7 +5,6 @@ #ifndef WEBKIT_MEDIA_ANDROID_WEBMEDIAPLAYER_MANAGER_ANDROID_H_ #define WEBKIT_MEDIA_ANDROID_WEBMEDIAPLAYER_MANAGER_ANDROID_H_ -#include <jni.h> #include <map> #include "base/basictypes.h" @@ -14,34 +13,24 @@ namespace webkit_media { class WebMediaPlayerAndroid; -// Class for managing all the WebMediaPlayerAndroid objects in a renderer -// process. +// Class for managing all the WebMediaPlayerAndroid objects in the same +// RenderView. class WebMediaPlayerManagerAndroid { public: WebMediaPlayerManagerAndroid(); - ~WebMediaPlayerManagerAndroid(); + virtual ~WebMediaPlayerManagerAndroid(); // Register and unregister a WebMediaPlayerAndroid object. int RegisterMediaPlayer(WebMediaPlayerAndroid* player); void UnregisterMediaPlayer(int player_id); - // Called when a mediaplayer starts to decode media. If the number - // of active decoders hits the limit, release some resources. - // TODO(qinmin): we need to classify between video and audio decoders. - // Audio decoders are inexpensive. And css animations often come with - // lots of small audio files. - void RequestMediaResources(int player_id); - - // Release all the media resources on the renderer process. + // Release all the media resources managed by this object. void ReleaseMediaResources(); // Get the pointer to WebMediaPlayerAndroid given the |player_id|. WebMediaPlayerAndroid* GetMediaPlayer(int player_id); private: - // Get the number of active players. - int32 GetActivePlayerCount(); - // Info for all available WebMediaPlayerAndroid on a page; kept so that // we can enumerate them to send updates about tab focus and visibily. std::map<int32, WebMediaPlayerAndroid*> media_players_; diff --git a/webkit/media/android/webmediaplayer_proxy_android.cc b/webkit/media/android/webmediaplayer_proxy_android.cc index 677a665..d09bf22 100644 --- a/webkit/media/android/webmediaplayer_proxy_android.cc +++ b/webkit/media/android/webmediaplayer_proxy_android.cc @@ -4,61 +4,8 @@ #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_)); -} +WebMediaPlayerProxyAndroid::~WebMediaPlayerProxyAndroid() {}; } // namespace webkit_media diff --git a/webkit/media/android/webmediaplayer_proxy_android.h b/webkit/media/android/webmediaplayer_proxy_android.h index 2b491ff..aeabe78 100644 --- a/webkit/media/android/webmediaplayer_proxy_android.h +++ b/webkit/media/android/webmediaplayer_proxy_android.h @@ -5,68 +5,38 @@ #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" +#include <string> -namespace base { -class MessageLoopProxy; -} +#include "base/time.h" 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> { +// An interface to facilitate the IPC between the browser side +// android::MediaPlayer and the WebMediaPlayerImplAndroid in the renderer +// process. +// Implementation is provided by content::WebMediaPlayerProxyImplAndroid. +class 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(); + // Initialize a MediaPlayerBridge object in browser process + virtual void Initialize(int player_id, const std::string& url, + const std::string& first_party_for_cookies) = 0; - // Notify |webmediaplayer_| that seek has completed. - void SeekCompleteTask(); + // Start the player. + virtual void Start(int player_id) = 0; - // Notify |webmediaplayer_| that media has been prepared successfully. - void MediaPreparedTask(); + // Pause the player. + virtual void Pause(int player_id) = 0; - // The render message loop where WebKit lives. - scoped_refptr<base::MessageLoopProxy> render_loop_; + // Perform seek on the player. + virtual void Seek(int player_id, base::TimeDelta time) = 0; - // The WebMediaPlayerAndroid object all the callbacks should be send to. - base::WeakPtr<WebMediaPlayerAndroid> webmediaplayer_; + // Release resources for the player. + virtual void ReleaseResources(int player_id) = 0; - DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerProxyAndroid); + // Destroy the player in the browser process + virtual void DestroyPlayer(int player_id) = 0; }; } // namespace webkit_media diff --git a/webkit/media/webkit_media.gypi b/webkit/media/webkit_media.gypi index db08992..77bb53f 100644 --- a/webkit/media/webkit_media.gypi +++ b/webkit/media/webkit_media.gypi @@ -18,9 +18,15 @@ 'android/audio_decoder_android.cc', 'android/media_metadata_android.cc', 'android/media_metadata_android.h', + 'android/media_player_bridge_manager_impl.cc', + 'android/media_player_bridge_manager_impl.h', 'android/stream_texture_factory_android.h', 'android/webmediaplayer_android.cc', 'android/webmediaplayer_android.h', + 'android/webmediaplayer_impl_android.cc', + 'android/webmediaplayer_impl_android.h', + 'android/webmediaplayer_in_process_android.cc', + 'android/webmediaplayer_in_process_android.h', 'android/webmediaplayer_manager_android.cc', 'android/webmediaplayer_manager_android.h', 'android/webmediaplayer_proxy_android.cc', |