diff options
author | watk <watk@chromium.org> | 2016-02-17 18:22:19 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-02-18 02:23:19 +0000 |
commit | dee516f91d460baf825f25503063a898ec3aaf3a (patch) | |
tree | 6ddd13c49f5b3548c28771377dff49a325f5b302 /content/browser/media | |
parent | 8fb3a4aee13f5299f4fb27d879b1fd1f07a5ae15 (diff) | |
download | chromium_src-dee516f91d460baf825f25503063a898ec3aaf3a.zip chromium_src-dee516f91d460baf825f25503063a898ec3aaf3a.tar.gz chromium_src-dee516f91d460baf825f25503063a898ec3aaf3a.tar.bz2 |
Enable Android SurfaceView fullscreen video with WMPI
This CL enables SurfaceView fullscreen video with the unified media pipeline
in cases where we use the AVDA deferred rendering strategy today.
* There's a new media interface called SurfaceManager with two methods:
CreateFullscreenSurface() and NaturalSizeChanged().
* SurfaceManager is implemented by RendererSurfaceViewManager, which is a
RenderFrameObserver, and BrowserSurfaceViewManager, which is created for
each RenderFrame by MediaWebContentsObserverAndroid.
* BrowserSurfaceViewManager creates a ContentVideoView in response to a
CreateFullscreenSurface message, and registers it in a surface map that the
decoder can look up in the GPU process.
* WMPI interacts with SurfaceManager on behalf of the decoder. It passes
GpuVideoDecoder a callback for requesting surfaces which it calls before
initializing VDAs.
* In response to the callback, if the player is in fullscreen WMPI will pass
the request to the SurfaceManager which will return the surface id to GVD. If
the player is not in fullscreen WMPI will return a null surface id.
* When GVD gets a surface id back it completes its initialization by calling
VDA::Initialize with the surface id and the VDA will render to the given
surface.
* WMPI records that it got a surface request callback so that it knows that
future fullscreen transitions will require a restart of the decoder in order
to switch surfaces.
* A future CL will allow us to switch the surface dynamically without
requiring a restart.
BUG=533630
Review URL: https://codereview.chromium.org/1655083002
Cr-Commit-Position: refs/heads/master@{#376068}
Diffstat (limited to 'content/browser/media')
4 files changed, 189 insertions, 4 deletions
diff --git a/content/browser/media/android/browser_surface_view_manager.cc b/content/browser/media/android/browser_surface_view_manager.cc new file mode 100644 index 0000000..f171a16 --- /dev/null +++ b/content/browser/media/android/browser_surface_view_manager.cc @@ -0,0 +1,86 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/media/android/browser_surface_view_manager.h" + +#include "content/browser/android/child_process_launcher_android.h" +#include "content/browser/android/content_view_core_impl.h" +#include "content/browser/gpu/gpu_surface_tracker.h" +#include "content/browser/web_contents/web_contents_impl.h" +#include "content/common/media/surface_view_manager_messages_android.h" +#include "content/public/browser/render_frame_host.h" +#include "media/base/surface_manager.h" +#include "ui/gfx/geometry/size.h" + +namespace content { + +BrowserSurfaceViewManager::BrowserSurfaceViewManager( + RenderFrameHost* render_frame_host) + : render_frame_host_(render_frame_host), + surface_id_(media::SurfaceManager::kNoSurfaceID) {} + +BrowserSurfaceViewManager::~BrowserSurfaceViewManager() {} + +void BrowserSurfaceViewManager::SetVideoSurface( + gfx::ScopedJavaSurface surface) { + if (surface.IsEmpty()) { + DCHECK_NE(surface_id_, media::SurfaceManager::kNoSurfaceID); + GpuSurfaceTracker::Get()->RemoveSurface(surface_id_); + UnregisterViewSurface(surface_id_); + surface_id_ = media::SurfaceManager::kNoSurfaceID; + } else { + // We mainly use the surface tracker to allocate a surface id for us. The + // lookup will go through the Android specific path and get the java + // surface directly, so there's no need to add a valid native widget here. + surface_id_ = GpuSurfaceTracker::Get()->AddSurfaceForNativeWidget( + gfx::kNullAcceleratedWidget); + RegisterViewSurface(surface_id_, surface.j_surface().obj()); + SendSurfaceID(surface_id_); + } +} + +void BrowserSurfaceViewManager::DidExitFullscreen(bool release_media_player) { + DVLOG(3) << __FUNCTION__; + content_video_view_.reset(); +} + +void BrowserSurfaceViewManager::OnCreateFullscreenSurface( + const gfx::Size& video_natural_size) { + // It's valid to get this call if we already own the fullscreen view. We just + // return the existing surface id. + if (content_video_view_) { + // Send the surface now if we have it. Otherwise it will be returned by + // |SetVideoSurface|. + if (surface_id_ != media::SurfaceManager::kNoSurfaceID) { + SendSurfaceID(surface_id_); + OnNaturalSizeChanged(video_natural_size); + return; + } + } + + // If we don't own the fullscreen view, but one exists, it means another + // WebContents has it. Ignore this request and return a null surface id. + if (ContentVideoView::GetInstance()) { + SendSurfaceID(media::SurfaceManager::kNoSurfaceID); + return; + } + + ContentViewCore* cvc = ContentViewCore::FromWebContents( + WebContents::FromRenderFrameHost(render_frame_host_)); + content_video_view_.reset(new ContentVideoView(this, cvc)); + OnNaturalSizeChanged(video_natural_size); +} + +void BrowserSurfaceViewManager::OnNaturalSizeChanged(const gfx::Size& size) { + if (content_video_view_) + content_video_view_->OnVideoSizeChanged(size.width(), size.height()); +} + +bool BrowserSurfaceViewManager::SendSurfaceID(int surface_id) { + return render_frame_host_->Send( + new SurfaceViewManagerMsg_FullscreenSurfaceCreated( + render_frame_host_->GetRoutingID(), surface_id)); +} + +} // namespace content diff --git a/content/browser/media/android/browser_surface_view_manager.h b/content/browser/media/android/browser_surface_view_manager.h new file mode 100644 index 0000000..df6b2594 --- /dev/null +++ b/content/browser/media/android/browser_surface_view_manager.h @@ -0,0 +1,53 @@ +// Copyright 2016 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 CONTENT_BROWSER_MEDIA_ANDROID_BROWSER_SURFACE_VIEW_MANAGER_H_ +#define CONTENT_BROWSER_MEDIA_ANDROID_BROWSER_SURFACE_VIEW_MANAGER_H_ + +#include <stdint.h> + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "content/browser/android/content_video_view.h" +#include "content/common/content_export.h" +#include "ui/gfx/geometry/size.h" + +namespace content { + +class RenderFrameHost; + +// BrowserSurfaceViewManager creates and owns a ContentVideoView on behalf of +// a fullscreen media player. Its SurfaceView is registered so that a decoder +// in the GPU process can look it up and render to it. +class CONTENT_EXPORT BrowserSurfaceViewManager + : public ContentVideoView::Client { + public: + explicit BrowserSurfaceViewManager(RenderFrameHost* render_frame_host); + ~BrowserSurfaceViewManager(); + + // ContentVideoView::Client overrides. + void SetVideoSurface(gfx::ScopedJavaSurface surface) override; + void DidExitFullscreen(bool release_media_player) override; + + void OnCreateFullscreenSurface(const gfx::Size& video_natural_size); + void OnNaturalSizeChanged(const gfx::Size& size); + + private: + // Send a message to return the surface id to the caller. + bool SendSurfaceID(int surface_id); + + RenderFrameHost* const render_frame_host_; + + // The surface id of the ContentVideoView surface. + int surface_id_; + + // The fullscreen view that contains a SurfaceView. + scoped_ptr<ContentVideoView> content_video_view_; + + DISALLOW_COPY_AND_ASSIGN(BrowserSurfaceViewManager); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_MEDIA_ANDROID_BROWSER_SURFACE_VIEW_MANAGER_H_ diff --git a/content/browser/media/android/media_web_contents_observer_android.cc b/content/browser/media/android/media_web_contents_observer_android.cc index 29f4b18..819c6b4 100644 --- a/content/browser/media/android/media_web_contents_observer_android.cc +++ b/content/browser/media/android/media_web_contents_observer_android.cc @@ -6,6 +6,7 @@ #include "content/browser/media/android/browser_media_player_manager.h" #include "content/browser/media/android/browser_media_session_manager.h" +#include "content/browser/media/android/browser_surface_view_manager.h" #include "content/browser/media/android/media_session.h" #include "content/browser/media/android/media_session_controller.h" #include "content/browser/media/android/media_session_observer.h" @@ -14,6 +15,7 @@ #include "content/common/media/media_player_delegate_messages.h" #include "content/common/media/media_player_messages_android.h" #include "content/common/media/media_session_messages_android.h" +#include "content/common/media/surface_view_manager_messages_android.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "ipc/ipc_message_macros.h" @@ -67,6 +69,19 @@ MediaWebContentsObserverAndroid::GetMediaSessionManager( return manager; } +BrowserSurfaceViewManager* +MediaWebContentsObserverAndroid::GetSurfaceViewManager( + RenderFrameHost* render_frame_host) { + auto it = surface_view_managers_.find(render_frame_host); + if (it != surface_view_managers_.end()) + return it->second; + + BrowserSurfaceViewManager* manager = + new BrowserSurfaceViewManager(render_frame_host); + surface_view_managers_.set(render_frame_host, make_scoped_ptr(manager)); + return manager; +} + void MediaWebContentsObserverAndroid::SuspendAllMediaPlayers() { web_contents()->ForEachFrame( base::Bind(&SuspendAllMediaPlayersInRenderFrame)); @@ -109,6 +124,7 @@ void MediaWebContentsObserverAndroid::RenderFrameDeleted( // detaching CDMs from media players yet. See http://crbug.com/330324 media_player_managers_.erase(render_frame_host); media_session_managers_.erase(render_frame_host); + surface_view_managers_.erase(render_frame_host); // TODO(xhwang): Currently MediaWebContentsObserver, BrowserMediaPlayerManager // and BrowserCdmManager all run on browser UI thread. So this call is okay. @@ -140,6 +156,9 @@ bool MediaWebContentsObserverAndroid::OnMessageReceived( if (OnMediaSessionMessageReceived(msg, render_frame_host)) return true; + if (OnSurfaceViewManagerMessageReceived(msg, render_frame_host)) + return true; + return false; } @@ -238,6 +257,22 @@ bool MediaWebContentsObserverAndroid::OnMediaSessionMessageReceived( return handled; } +bool MediaWebContentsObserverAndroid::OnSurfaceViewManagerMessageReceived( + const IPC::Message& msg, + RenderFrameHost* render_frame_host) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(MediaWebContentsObserverAndroid, msg) + IPC_MESSAGE_FORWARD(SurfaceViewManagerHostMsg_CreateFullscreenSurface, + GetSurfaceViewManager(render_frame_host), + BrowserSurfaceViewManager::OnCreateFullscreenSurface) + IPC_MESSAGE_FORWARD(SurfaceViewManagerHostMsg_NaturalSizeChanged, + GetSurfaceViewManager(render_frame_host), + BrowserSurfaceViewManager::OnNaturalSizeChanged) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + void MediaWebContentsObserverAndroid::OnSetCdm( RenderFrameHost* render_frame_host, int player_id, diff --git a/content/browser/media/android/media_web_contents_observer_android.h b/content/browser/media/android/media_web_contents_observer_android.h index 63b17da..e8e3650 100644 --- a/content/browser/media/android/media_web_contents_observer_android.h +++ b/content/browser/media/android/media_web_contents_observer_android.h @@ -18,6 +18,7 @@ namespace content { class BrowserCdmManager; class BrowserMediaPlayerManager; class BrowserMediaSessionManager; +class BrowserSurfaceViewManager; class MediaSessionController; // This class adds Android specific extensions to the MediaWebContentsObserver. @@ -31,13 +32,15 @@ class CONTENT_EXPORT MediaWebContentsObserverAndroid static MediaWebContentsObserverAndroid* FromWebContents( WebContents* web_contents); - // Gets the media player or media session manager associated with the given - // |render_frame_host| respectively. Creates a new one if it doesn't exist. - // The caller doesn't own the returned pointer. + // Gets one of the managers associated with the given |render_frame_host|. + // Creates a new one if it doesn't exist. The caller doesn't own the + // returned pointer. BrowserMediaPlayerManager* GetMediaPlayerManager( RenderFrameHost* render_frame_host); BrowserMediaSessionManager* GetMediaSessionManager( RenderFrameHost* render_frame_host); + BrowserSurfaceViewManager* GetSurfaceViewManager( + RenderFrameHost* render_frame_host); // Called by the WebContents when a tab has been closed but may still be // available for "undo" -- indicates that all media players (even audio only @@ -59,7 +62,7 @@ class CONTENT_EXPORT MediaWebContentsObserverAndroid void OnFrameInfoUpdated(); #endif // defined(VIDEO_HOLE) - // MediaWebContentsObserverAndroid overrides. + // MediaWebContentsObserver overrides. void RenderFrameDeleted(RenderFrameHost* render_frame_host) override; bool OnMessageReceived(const IPC::Message& message, RenderFrameHost* render_frame_host) override; @@ -91,6 +94,9 @@ class CONTENT_EXPORT MediaWebContentsObserverAndroid bool OnMediaSessionMessageReceived(const IPC::Message& message, RenderFrameHost* render_frame_host); + bool OnSurfaceViewManagerMessageReceived(const IPC::Message& message, + RenderFrameHost* render_frame_host); + void OnSetCdm(RenderFrameHost* render_frame_host, int player_id, int cdm_id); // Map from RenderFrameHost* to BrowserMediaPlayerManager. @@ -110,6 +116,11 @@ class CONTENT_EXPORT MediaWebContentsObserverAndroid std::map<MediaPlayerId, scoped_ptr<MediaSessionController>>; MediaSessionMap media_session_map_; + using SurfaceViewManagerMap = + base::ScopedPtrHashMap<RenderFrameHost*, + scoped_ptr<BrowserSurfaceViewManager>>; + SurfaceViewManagerMap surface_view_managers_; + DISALLOW_COPY_AND_ASSIGN(MediaWebContentsObserverAndroid); }; |