diff options
-rw-r--r-- | content/renderer/render_view_impl.cc | 15 | ||||
-rw-r--r-- | content/renderer/render_view_impl.h | 17 | ||||
-rw-r--r-- | media/base/android/media_player_bridge.cc | 1 | ||||
-rw-r--r-- | webkit/media/android/stream_texture_factory_android.h | 56 | ||||
-rw-r--r-- | webkit/media/android/webmediaplayer_android.cc | 95 | ||||
-rw-r--r-- | webkit/media/android/webmediaplayer_android.h | 48 | ||||
-rw-r--r-- | webkit/media/android/webmediaplayer_manager_android.cc | 50 | ||||
-rw-r--r-- | webkit/media/android/webmediaplayer_manager_android.h | 53 | ||||
-rw-r--r-- | webkit/media/webkit_media.gypi | 3 |
9 files changed, 324 insertions, 14 deletions
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index f37da15..b8cf211 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc @@ -188,6 +188,7 @@ #if defined(OS_ANDROID) #include "webkit/media/android/webmediaplayer_android.h" +#include "webkit/media/android/webmediaplayer_manager_android.h" #elif defined(OS_WIN) // TODO(port): these files are currently Windows only because they concern: // * theming @@ -611,6 +612,11 @@ RenderViewImpl::RenderViewImpl( new TextInputClientObserver(this); #endif // defined(OS_MACOSX) +#if defined(OS_ANDROID) + media_player_manager_.reset( + new webkit_media::WebMediaPlayerManagerAndroid()); +#endif + // The next group of objects all implement RenderViewObserver, so are deleted // along with the RenderView automatically. devtools_agent_ = new DevToolsAgent(this); @@ -2302,8 +2308,10 @@ WebMediaPlayer* RenderViewImpl::createMediaPlayer( RenderViewObserver, observers_, WillCreateMediaPlayer(frame, client)); #if defined(OS_ANDROID) + // TODO(qinmin): upstream the implementation of StreamTextureFactoryImpl + // to replace the NULL param here. return new webkit_media::WebMediaPlayerAndroid( - client, cookieJar(frame)); + frame, client, cookieJar(frame), media_player_manager_.get(), NULL); #endif media::MessageLoopFactory* message_loop_factory = @@ -5040,6 +5048,11 @@ void RenderViewImpl::DidHandleTouchEvent(const WebTouchEvent& event) { void RenderViewImpl::OnWasHidden() { RenderWidget::OnWasHidden(); +#if defined(OS_ANDROID) + // Inform WebMediaPlayerManagerAndroid to release all media player resources. + media_player_manager_->ReleaseMediaResources(); +#endif + if (webview()) { webview()->settings()->setMinimumTimerInterval( webkit_glue::kBackgroundTabTimerInterval); diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h index 64d4f39..9d8fdb7 100644 --- a/content/renderer/render_view_impl.h +++ b/content/renderer/render_view_impl.h @@ -122,6 +122,12 @@ class ImageResourceFetcher; class ResourceFetcher; } +#if defined(OS_ANDROID) +namespace webkit_media { +class WebMediaPlayerManagerAndroid; +} +#endif + namespace WebKit { class WebApplicationCacheHost; class WebApplicationCacheHostClient; @@ -244,6 +250,12 @@ class RenderViewImpl : public RenderWidget, return mouse_lock_dispatcher_; } +#if defined(OS_ANDROID) + webkit_media::WebMediaPlayerManagerAndroid* media_player_manager() { + return media_player_manager_.get(); + } +#endif + WebKit::WebPeerConnectionHandler* CreatePeerConnectionHandler( WebKit::WebPeerConnectionHandlerClient* client); WebKit::WebPeerConnection00Handler* CreatePeerConnectionHandlerJsep( @@ -1365,6 +1377,11 @@ class RenderViewImpl : public RenderWidget, // Wraps the |webwidget_| as a MouseLockDispatcher::LockTarget interface. scoped_ptr<MouseLockDispatcher::LockTarget> webwidget_mouse_lock_target_; +#if defined(OS_ANDROID) + // The media player manager for managing all the media players on this view. + scoped_ptr<webkit_media::WebMediaPlayerManagerAndroid> media_player_manager_; +#endif + // Plugins ------------------------------------------------------------------- // All the currently active plugin delegates for this RenderView; kept so diff --git a/media/base/android/media_player_bridge.cc b/media/base/android/media_player_bridge.cc index a494777..44d13b6 100644 --- a/media/base/android/media_player_bridge.cc +++ b/media/base/android/media_player_bridge.cc @@ -76,6 +76,7 @@ MediaPlayerBridge::MediaPlayerBridge() { } MediaPlayerBridge::~MediaPlayerBridge() { + SetVideoSurface(NULL); CallVoidMethod("release"); } diff --git a/webkit/media/android/stream_texture_factory_android.h b/webkit/media/android/stream_texture_factory_android.h new file mode 100644 index 0000000..9ef4e4d --- /dev/null +++ b/webkit/media/android/stream_texture_factory_android.h @@ -0,0 +1,56 @@ +// 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_STREAM_TEXTURE_FACTORY_ANDROID_H_ +#define WEBKIT_MEDIA_ANDROID_STREAM_TEXTURE_FACTORY_ANDROID_H_ +#pragma once + +namespace WebKit { +class WebStreamTextureClient; +} + +namespace webkit_media { + +// The proxy class for the gpu thread to notify the compositor thread +// when a new video frame is available. +class StreamTextureProxy { + public: + virtual ~StreamTextureProxy() {} + + // Initialize the the stream_id, texture width and height. This should + // be called on the compositor thread. + virtual bool Initialize(int stream_id, int width, int height) = 0; + + virtual bool IsInitialized() = 0; + + // Setting the target for callback when a frame is available. This function + // could be called on both the main thread and the compositor thread. + virtual void SetClient(WebKit::WebStreamTextureClient* client) = 0; +}; + + +// Factory class for managing the stream texture. +class StreamTextureFactory { + public: + virtual ~StreamTextureFactory() {} + + // Create the StreamTextureProxy object. + virtual StreamTextureProxy* CreateProxy() = 0; + + // Send an IPC message to the browser process to request a java surface + // object for the given stream_id. After the the surface is created, + // it will be passed back to the WebMediaPlayerAndroid object identified by + // the player_id. + virtual void EstablishPeer(int stream_id, int player_id) = 0; + + // Create the streamTexture and return the stream Id and set the texture id. + virtual unsigned CreateStreamTexture(unsigned* texture_id) = 0; + + // Destroy the streamTexture for the given texture Id. + virtual void DestroyStreamTexture(unsigned texture_id) = 0; +}; + +} // namespace webkit_media + +#endif // WEBKIT_MEDIA_ANDROID_STREAM_TEXTURE_FACTORY_ANDROID_H_ diff --git a/webkit/media/android/webmediaplayer_android.cc b/webkit/media/android/webmediaplayer_android.cc index 1b99ebb..faaadaf 100644 --- a/webkit/media/android/webmediaplayer_android.cc +++ b/webkit/media/android/webmediaplayer_android.cc @@ -13,10 +13,14 @@ #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" @@ -33,6 +37,9 @@ 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 @@ -47,9 +54,13 @@ static const float kTemporaryDuration = 100.0f; bool WebMediaPlayerAndroid::incognito_mode_ = false; WebMediaPlayerAndroid::WebMediaPlayerAndroid( + WebKit::WebFrame* frame, WebMediaPlayerClient* client, - WebKit::WebCookieJar* cookie_jar) - : client_(client), + WebKit::WebCookieJar* cookie_jar, + webkit_media::WebMediaPlayerManagerAndroid* manager, + webkit_media::StreamTextureFactory* factory) + : frame_(frame), + client_(client), buffered_(1u), video_frame_(new WebVideoFrameImpl(VideoFrame::CreateEmptyFrame())), proxy_(new WebMediaPlayerProxyAndroid(base::MessageLoopProxy::current(), @@ -62,16 +73,25 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid( buffered_bytes_(0), did_loading_progress_(false), cookie_jar_(cookie_jar), + manager_(manager), pending_play_event_(false), network_state_(WebMediaPlayer::NetworkStateEmpty), - ready_state_(WebMediaPlayer::ReadyStateHaveNothing) { - video_frame_.reset(new WebVideoFrameImpl(VideoFrame::CreateEmptyFrame())); + ready_state_(WebMediaPlayer::ReadyStateHaveNothing), + texture_id_(0), + stream_id_(0), + needs_establish_peer_(true), + stream_texture_factory_(factory) { + player_id_ = manager_->RegisterMediaPlayer(this); + if (stream_texture_factory_.get()) + stream_texture_proxy_.reset(stream_texture_factory_->CreateProxy()); } WebMediaPlayerAndroid::~WebMediaPlayerAndroid() { if (media_player_.get()) { media_player_->Stop(); } + + manager_->UnregisterMediaPlayer(player_id_); } void WebMediaPlayerAndroid::InitIncognito(bool incognito_mode) { @@ -437,9 +457,20 @@ void WebMediaPlayerAndroid::UpdateReadyState( client_->readyStateChanged(); } -void WebMediaPlayerAndroid::SetVideoSurface(jobject j_surface) { - if (media_player_.get()) - media_player_->SetVideoSurface(j_surface); +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; } void WebMediaPlayerAndroid::InitializeMediaPlayer() { @@ -450,8 +481,8 @@ void WebMediaPlayerAndroid::InitializeMediaPlayer() { std::string cookies; if (cookie_jar_ != NULL) { - WebURL url(url_); - cookies = UTF16ToUTF8(cookie_jar_->cookies(url, url)); + WebURL first_party_url(frame_->document().firstPartyForCookies()); + cookies = UTF16ToUTF8(cookie_jar_->cookies(url_, first_party_url)); } media_player_->SetDataSource(url_.spec(), cookies, incognito_mode_); @@ -466,6 +497,16 @@ void WebMediaPlayerAndroid::InitializeMediaPlayer() { void WebMediaPlayerAndroid::PlayInternal() { CHECK(prepared_); + if (hasVideo() && stream_texture_factory_.get()) { + if (!stream_id_) + CreateStreamTexture(); + + if (needs_establish_peer_) { + stream_texture_factory_->EstablishPeer(stream_id_, player_id_); + needs_establish_peer_ = false; + } + } + if (paused()) media_player_->Start(base::Bind( &WebMediaPlayerProxyAndroid::PlaybackCompleteCallback, proxy_)); @@ -483,7 +524,36 @@ void WebMediaPlayerAndroid::SeekInternal(float seconds) { &WebMediaPlayerProxyAndroid::SeekCompleteCallback, proxy_)); } +void WebMediaPlayerAndroid::CreateStreamTexture() { + DCHECK(!stream_id_); + DCHECK(!texture_id_); + stream_id_ = stream_texture_factory_->CreateStreamTexture(&texture_id_); + if (texture_id_) + video_frame_.reset(new WebVideoFrameImpl(VideoFrame::WrapNativeTexture( + texture_id_, + kGLTextureExternalOES, + texture_size_.width, + texture_size_.height, + base::TimeDelta(), + base::TimeDelta(), + base::Bind(&WebMediaPlayerAndroid::DestroyStreamTexture, + base::Unretained(this))))); +} + +void WebMediaPlayerAndroid::DestroyStreamTexture() { + DCHECK(stream_id_); + DCHECK(texture_id_); + stream_texture_factory_->DestroyStreamTexture(texture_id_); + texture_id_ = 0; + stream_id_ = 0; +} + WebVideoFrame* WebMediaPlayerAndroid::getCurrentFrame() { + if (!stream_texture_proxy_->IsInitialized() && stream_id_) { + stream_texture_proxy_->Initialize( + stream_id_, video_frame_->width(), video_frame_->height()); + } + return video_frame_.get(); } @@ -491,4 +561,11 @@ 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); +} + } // namespace webkit_media diff --git a/webkit/media/android/webmediaplayer_android.h b/webkit/media/android/webmediaplayer_android.h index c8935fa..b948d362 100644 --- a/webkit/media/android/webmediaplayer_android.h +++ b/webkit/media/android/webmediaplayer_android.h @@ -4,6 +4,7 @@ #ifndef WEBKIT_MEDIA_ANDROID_WEBMEDIAPLAYER_ANDROID_H_ #define WEBKIT_MEDIA_ANDROID_WEBMEDIAPLAYER_ANDROID_H_ +#pragma once #include <jni.h> @@ -18,6 +19,7 @@ namespace WebKit { class WebCookieJar; +class WebFrame; } namespace media { @@ -26,6 +28,9 @@ class MediaPlayerBridge; namespace webkit_media { +class StreamTextureFactory; +class StreamTextureProxy; +class WebMediaPlayerManagerAndroid; class WebMediaPlayerProxyAndroid; // This class serves as the android implementation of WebKit::WebMediaPlayer. @@ -35,8 +40,11 @@ class WebMediaPlayerAndroid : public WebKit::WebMediaPlayer, public base::SupportsWeakPtr<WebMediaPlayerAndroid> { public: - WebMediaPlayerAndroid(WebKit::WebMediaPlayerClient* client, - WebKit::WebCookieJar* cookie_jar); + 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. @@ -105,6 +113,8 @@ class WebMediaPlayerAndroid : // compositor thread. virtual WebKit::WebVideoFrame* getCurrentFrame(); virtual void putCurrentFrame(WebKit::WebVideoFrame*); + virtual void setStreamTextureClient( + WebKit::WebStreamTextureClient* client); // Media player callback handlers. void OnMediaPrepared(); @@ -115,8 +125,10 @@ class WebMediaPlayerAndroid : 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); + // This function is called by WebMediaPlayerManagerAndroid to pause the video + // and release |media_player_| and its surface texture when we switch tabs. + // However, the actual GlTexture is not released to keep the video screenshot. + void ReleaseMediaResources(); private: // Create a media player to load the |url_| and prepare for playback. @@ -134,9 +146,15 @@ class WebMediaPlayerAndroid : void UpdateNetworkState(WebKit::WebMediaPlayer::NetworkState state); void UpdateReadyState(WebKit::WebMediaPlayer::ReadyState state); + // Methods for creation and deletion of stream texture. + void CreateStreamTexture(); + void DestroyStreamTexture(); + // whether the current process is incognito mode static bool incognito_mode_; + WebKit::WebFrame* frame_; + WebKit::WebMediaPlayerClient* const client_; // Save the list of buffered time ranges. @@ -188,6 +206,12 @@ class WebMediaPlayerAndroid : // Pointer to the cookie jar to get the cookie for the media url. WebKit::WebCookieJar* cookie_jar_; + // Manager for managing this media player. + webkit_media::WebMediaPlayerManagerAndroid* manager_; + + // Player ID assigned by the media player manager. + int player_id_; + // Whether the user has clicked the play button while media player // is preparing. bool pending_play_event_; @@ -196,6 +220,22 @@ class WebMediaPlayerAndroid : WebKit::WebMediaPlayer::NetworkState network_state_; WebKit::WebMediaPlayer::ReadyState ready_state_; + // GL texture ID allocated to the video. + unsigned int texture_id_; + + // Stream texture ID allocated to the video. + unsigned int stream_id_; + + // 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_; + + // 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_; + DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerAndroid); }; diff --git a/webkit/media/android/webmediaplayer_manager_android.cc b/webkit/media/android/webmediaplayer_manager_android.cc new file mode 100644 index 0000000..93c9733 --- /dev/null +++ b/webkit/media/android/webmediaplayer_manager_android.cc @@ -0,0 +1,50 @@ +// 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_manager_android.h" + +#include "webkit/media/android/webmediaplayer_android.h" + +namespace webkit_media { + +WebMediaPlayerManagerAndroid::WebMediaPlayerManagerAndroid() + : next_media_player_id_(0) { +} + +WebMediaPlayerManagerAndroid::~WebMediaPlayerManagerAndroid() {} + +int WebMediaPlayerManagerAndroid::RegisterMediaPlayer( + WebMediaPlayerAndroid* player) { + MediaPlayerInfo info; + info.player = player; + media_players_[next_media_player_id_] = info; + return next_media_player_id_++; +} + +void WebMediaPlayerManagerAndroid::UnregisterMediaPlayer(int player_id) { + std::map<int32, MediaPlayerInfo>::iterator iter = + media_players_.find(player_id); + DCHECK(iter != media_players_.end()); + + media_players_.erase(player_id); +} + +void WebMediaPlayerManagerAndroid::ReleaseMediaResources() { + std::map<int32, MediaPlayerInfo>::iterator player_it; + for (player_it = media_players_.begin(); + player_it != media_players_.end(); ++player_it) { + (player_it->second).player->ReleaseMediaResources(); + } +} + +WebMediaPlayerAndroid* WebMediaPlayerManagerAndroid::GetMediaPlayer( + int player_id) { + std::map<int32, MediaPlayerInfo>::iterator iter = + media_players_.find(player_id); + if (iter != media_players_.end()) + return (iter->second).player; + return NULL; +} + +} // namespace webkit_media diff --git a/webkit/media/android/webmediaplayer_manager_android.h b/webkit/media/android/webmediaplayer_manager_android.h new file mode 100644 index 0000000..e8a046a --- /dev/null +++ b/webkit/media/android/webmediaplayer_manager_android.h @@ -0,0 +1,53 @@ +// 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_MANAGER_ANDROID_H_ +#define WEBKIT_MEDIA_ANDROID_WEBMEDIAPLAYER_MANAGER_ANDROID_H_ +#pragma once + +#include <jni.h> +#include <map> + +#include "base/basictypes.h" + +namespace webkit_media { + +class WebMediaPlayerAndroid; + +// Class for managing all the WebMediaPlayerAndroid objects in a renderer +// process. +class WebMediaPlayerManagerAndroid { + public: + WebMediaPlayerManagerAndroid(); + ~WebMediaPlayerManagerAndroid(); + + // Register and unregister a WebMediaPlayerAndroid object. + int RegisterMediaPlayer(WebMediaPlayerAndroid* player); + void UnregisterMediaPlayer(int player_id); + + // Release all the media resources on the renderer process. + void ReleaseMediaResources(); + + // Get the pointer to WebMediaPlayerAndroid given the |player_id|. + WebMediaPlayerAndroid* GetMediaPlayer(int player_id); + + private: + // Information needed to manage WebMediaPlayerAndroid. + // TODO(qinmin): more informations will be added here for resource management. + struct MediaPlayerInfo { + webkit_media::WebMediaPlayerAndroid* player; + }; + + // 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, MediaPlayerInfo> media_players_; + + int32 next_media_player_id_; + + DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerManagerAndroid); +}; + +} // namespace webkit_media + +#endif // WEBKIT_MEDIA_ANDROID_WEBMEDIAPLAYER_MANAGER_ANDROID_H_ diff --git a/webkit/media/webkit_media.gypi b/webkit/media/webkit_media.gypi index ad6c642..111b5ef 100644 --- a/webkit/media/webkit_media.gypi +++ b/webkit/media/webkit_media.gypi @@ -15,8 +15,11 @@ ], 'sources': [ 'android/audio_decoder_android.cc', + 'android/stream_texture_factory_android.h', 'android/webmediaplayer_android.cc', 'android/webmediaplayer_android.h', + 'android/webmediaplayer_manager_android.cc', + 'android/webmediaplayer_manager_android.h', 'android/webmediaplayer_proxy_android.cc', 'android/webmediaplayer_proxy_android.h', 'active_loader.cc', |