diff options
author | ycheo@chromium.org <ycheo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-21 16:08:20 +0000 |
---|---|---|
committer | ycheo@chromium.org <ycheo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-21 16:08:20 +0000 |
commit | 8b4efe95a07d17eb46c86c9a55b0878b6838f01f (patch) | |
tree | 7e0603ea1c5805f2e05bad7c00b3eac878362c5f | |
parent | 578d5dae5655184ce0abed013a103e6d9e9875d2 (diff) | |
download | chromium_src-8b4efe95a07d17eb46c86c9a55b0878b6838f01f.zip chromium_src-8b4efe95a07d17eb46c86c9a55b0878b6838f01f.tar.gz chromium_src-8b4efe95a07d17eb46c86c9a55b0878b6838f01f.tar.bz2 |
Enable the embedded L1/EME support in WebView.
- Add ExternalVideoSurfaceContainer which handles the external surface for the hole punching in WebView.
- Refactor the callbacks of ContentViewClient on the hole-punching to make them have the single purpose per each function.
BUG=329447
Review URL: https://codereview.chromium.org/132233042
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@252571 0039d316-1c4b-4281-b951-d872f2087c98
17 files changed, 553 insertions, 118 deletions
diff --git a/android_webview/java/src/org/chromium/android_webview/ExternalVideoSurfaceContainer.java b/android_webview/java/src/org/chromium/android_webview/ExternalVideoSurfaceContainer.java new file mode 100644 index 0000000..7bc1e11 --- /dev/null +++ b/android_webview/java/src/org/chromium/android_webview/ExternalVideoSurfaceContainer.java @@ -0,0 +1,259 @@ +// Copyright 2014 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. + +package org.chromium.android_webview; + +import android.content.Context; +import android.graphics.Canvas; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.ViewGroup; + +import org.chromium.base.CalledByNative; +import org.chromium.base.JNINamespace; +import org.chromium.content.browser.ContentViewCore; +import org.chromium.content.browser.RenderCoordinates; + +import java.lang.ref.WeakReference; + +/** + * This is a container for external video surfaces. + * The object is owned by the native peer and it is owned by WebContents. + * + * The expected behavior of the media player on the video hole punching is as follows. + * 1) If it requests the surface, it will call requestExternalVideoSurface(). + * When the resolution of the video is changed, it'll call requestExternalVideoSurface(). + * 2) Whenever the size or the position of the video element is changed, it'll notify through + * onExternalVideoSurfacePositionChanged(). + * 3) Whenever the page that contains the video element is scrolled or zoomed, + * onFrameInfoUpdated() will be called. + * 4) Usually steps 1) ~ 3) are repeated during the playback. + * 5) If the player no longer needs the surface any more, it'll call + * releaseExternalVideoSurface(). + * + * Please contact ycheo@chromium.org or wonsik@chromium.org if you have any + * questions or issues for this class. + */ +@JNINamespace("android_webview") +public class ExternalVideoSurfaceContainer implements SurfaceHolder.Callback { + private static final int INVALID_PLAYER_ID = -1; + + // Because WebView does hole-punching by itself, instead, the hole-punching logic + // in SurfaceView can clear out some web elements like media control or subtitle. + // So we need to disable its hole-punching logic. + private static class NoPunchingSurfaceView extends SurfaceView { + public NoPunchingSurfaceView(Context context) { + super(context); + } + // SurfaceView.dispatchDraw implementation punches a hole in the view hierarchy. + // Disable this by making this a no-op. + @Override + protected void dispatchDraw(Canvas canvas) {} + } + + // There can be at most 1 external video surface for now. + // If there are the multiple requests for the surface, then the second video will + // kick the first one off. + // To support the mulitple video surfaces seems impractical, because z-order between + // the multiple SurfaceViews is non-deterministic. + private static WeakReference<ExternalVideoSurfaceContainer> sActiveContainer = + new WeakReference<ExternalVideoSurfaceContainer>(null); + + private final int mNativeExternalVideoSurfaceContainer; + private final ContentViewCore mContentViewCore; + private int mPlayerId = INVALID_PLAYER_ID; + private SurfaceView mSurfaceView; + + // The absolute CSS coordinates of the video element. + private float mLeft; + private float mTop; + private float mRight; + private float mBottom; + + // The physical location/size of the external video surface in pixels. + private int mX; + private int mY; + private int mWidth; + private int mHeight; + + @CalledByNative + private static ExternalVideoSurfaceContainer create( + int nativeExternalVideoSurfaceContainer, ContentViewCore contentViewCore) { + return new ExternalVideoSurfaceContainer( + nativeExternalVideoSurfaceContainer, contentViewCore); + } + + private ExternalVideoSurfaceContainer( + int nativeExternalVideoSurfaceContainer, ContentViewCore contentViewCore) { + assert contentViewCore != null; + mNativeExternalVideoSurfaceContainer = nativeExternalVideoSurfaceContainer; + mContentViewCore = contentViewCore; + initializeCurrentPositionOfSurfaceView(); + } + + /** + * Called when a media player wants to request an external video surface. + * @param playerId The ID of the media player. + */ + @CalledByNative + private void requestExternalVideoSurface(int playerId) { + if (mPlayerId == playerId) return; + + if (mPlayerId == INVALID_PLAYER_ID) { + setActiveContainer(this); + } + + mPlayerId = playerId; + initializeCurrentPositionOfSurfaceView(); + + createSurfaceView(); + } + + /** + * Called when a media player wants to release an external video surface. + * @param playerId The ID of the media player. + */ + @CalledByNative + private void releaseExternalVideoSurface(int playerId) { + if (mPlayerId != playerId) return; + + releaseIfActiveContainer(this); + + mPlayerId = INVALID_PLAYER_ID; + } + + @CalledByNative + private void destroy() { + releaseExternalVideoSurface(mPlayerId); + } + + private void initializeCurrentPositionOfSurfaceView() { + mX = Integer.MIN_VALUE; + mY = Integer.MIN_VALUE; + mWidth = 0; + mHeight = 0; + } + + private static void setActiveContainer(ExternalVideoSurfaceContainer container) { + ExternalVideoSurfaceContainer activeContainer = sActiveContainer.get(); + if (activeContainer != null) { + activeContainer.removeSurfaceView(); + } + sActiveContainer = new WeakReference<ExternalVideoSurfaceContainer>(container); + } + + private static void releaseIfActiveContainer(ExternalVideoSurfaceContainer container) { + ExternalVideoSurfaceContainer activeContainer = sActiveContainer.get(); + if (activeContainer == container) { + setActiveContainer(null); + } + } + + private void createSurfaceView() { + mSurfaceView = new NoPunchingSurfaceView(mContentViewCore.getContext()); + mSurfaceView.getHolder().addCallback(this); + // SurfaceHoder.surfaceCreated() will be called after the SurfaceView is attached to + // the Window and becomes visible. + mContentViewCore.getContainerView().addView(mSurfaceView); + } + + private void removeSurfaceView() { + // SurfaceHoder.surfaceDestroyed() will be called in ViewGroup.removeView() + // as soon as the SurfaceView is detached from the Window. + mContentViewCore.getContainerView().removeView(mSurfaceView); + mSurfaceView = null; + } + + /** + * Called when the position of the video element which uses the external + * video surface is changed. + * @param playerId The ID of the media player. + * @param left The absolute CSS X coordinate of the left side of the video element. + * @param top The absolute CSS Y coordinate of the top side of the video element. + * @param right The absolute CSS X coordinate of the right side of the video element. + * @param bottom The absolute CSS Y coordinate of the bottom side of the video element. + */ + @CalledByNative + private void onExternalVideoSurfacePositionChanged( + int playerId, float left, float top, float right, float bottom) { + if (mPlayerId != playerId) return; + + mLeft = left; + mTop = top; + mRight = right; + mBottom = bottom; + + layOutSurfaceView(); + } + + /** + * Called when the page that contains the video element is scrolled or zoomed. + */ + @CalledByNative + private void onFrameInfoUpdated() { + if (mPlayerId == INVALID_PLAYER_ID) return; + + layOutSurfaceView(); + } + + private void layOutSurfaceView() { + RenderCoordinates renderCoordinates = mContentViewCore.getRenderCoordinates(); + RenderCoordinates.NormalizedPoint topLeft = renderCoordinates.createNormalizedPoint(); + RenderCoordinates.NormalizedPoint bottomRight = renderCoordinates.createNormalizedPoint(); + topLeft.setAbsoluteCss(mLeft, mTop); + bottomRight.setAbsoluteCss(mRight, mBottom); + float top = topLeft.getYPix(); + float left = topLeft.getXPix(); + float bottom = bottomRight.getYPix(); + float right = bottomRight.getXPix(); + + int x = Math.round(left + renderCoordinates.getScrollXPix()); + int y = Math.round(top + renderCoordinates.getScrollYPix()); + int width = Math.round(right - left); + int height = Math.round(bottom - top); + if (mX == x && mY == y && mWidth == width && mHeight == height) return; + mX = x; + mY = y; + mWidth = width; + mHeight = height; + + mSurfaceView.setX(x); + mSurfaceView.setY(y); + ViewGroup.LayoutParams layoutParams = mSurfaceView.getLayoutParams(); + layoutParams.width = width; + layoutParams.height = height; + mSurfaceView.requestLayout(); + } + + // SurfaceHolder.Callback methods. + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {} + + @Override + // surfaceCreated() callback can be called regardless of requestExternalVideoSurface, + // if the activity comes back from the background and becomes visible. + public void surfaceCreated(SurfaceHolder holder) { + if (mPlayerId != INVALID_PLAYER_ID) { + nativeSurfaceCreated( + mNativeExternalVideoSurfaceContainer, mPlayerId, holder.getSurface()); + } + } + + // surfaceDestroyed() callback can be called regardless of releaseExternalVideoSurface, + // if the activity moves to the backgound and becomes invisible. + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + if (mPlayerId != INVALID_PLAYER_ID) { + nativeSurfaceDestroyed(mNativeExternalVideoSurfaceContainer, mPlayerId); + } + } + + private native void nativeSurfaceCreated( + long nativeExternalVideoSurfaceContainerImpl, int playerId, Surface surface); + + private native void nativeSurfaceDestroyed( + long nativeExternalVideoSurfaceContainerImpl, int playerId); +} + diff --git a/android_webview/lib/DEPS b/android_webview/lib/DEPS index 8460d68..4442017 100644 --- a/android_webview/lib/DEPS +++ b/android_webview/lib/DEPS @@ -2,4 +2,5 @@ include_rules = [ "+cc/base/switches.h", "+components", # For jni registers. "+content/public", + "+media/base/media_switches.h", # For media command line switches. ] diff --git a/android_webview/lib/main/aw_main_delegate.cc b/android_webview/lib/main/aw_main_delegate.cc index c3186ae..8f8d387 100644 --- a/android_webview/lib/main/aw_main_delegate.cc +++ b/android_webview/lib/main/aw_main_delegate.cc @@ -26,6 +26,7 @@ #include "content/public/common/content_switches.h" #include "gpu/command_buffer/client/gl_in_process_context.h" #include "gpu/command_buffer/service/in_process_command_buffer.h" +#include "media/base/media_switches.h" #include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h" namespace android_webview { @@ -80,6 +81,11 @@ bool AwMainDelegate::BasicStartupComplete(int* exit_code) { // Disable WebRTC. cl->AppendSwitch(switches::kDisableWebRTC); +#if defined(VIDEO_HOLE) + // Support EME/L1 with hole-punching. + cl->AppendSwitch(switches::kMediaDrmEnableNonCompositing); +#endif + return false; } diff --git a/android_webview/native/android_webview_jni_registrar.cc b/android_webview/native/android_webview_jni_registrar.cc index 2a425b3..24241d7 100644 --- a/android_webview/native/android_webview_jni_registrar.cc +++ b/android_webview/native/android_webview_jni_registrar.cc @@ -19,6 +19,7 @@ #include "android_webview/native/aw_settings.h" #include "android_webview/native/aw_web_contents_delegate.h" #include "android_webview/native/cookie_manager.h" +#include "android_webview/native/external_video_surface_container_impl.h" #include "android_webview/native/input_stream_impl.h" #include "android_webview/native/intercepted_request_data_impl.h" #include "android_webview/native/java_browser_view_renderer_helper.h" @@ -45,6 +46,9 @@ static base::android::RegistrationMethod kWebViewRegisteredMethods[] = { { "AwResource", AwResource::RegisterAwResource }, { "AwWebContentsDelegate", RegisterAwWebContentsDelegate }, { "CookieManager", RegisterCookieManager }, +#if defined(VIDEO_HOLE) + { "ExternalVideoSurfaceContainer", RegisterExternalVideoSurfaceContainer }, +#endif { "InterceptedRequestDataImpl", RegisterInterceptedRequestData }, { "InputStream", RegisterInputStream }, { "JavaBrowserViewRendererHelper", RegisterJavaBrowserViewRendererHelper }, diff --git a/android_webview/native/external_video_surface_container_impl.cc b/android_webview/native/external_video_surface_container_impl.cc new file mode 100644 index 0000000..351b3ca --- /dev/null +++ b/android_webview/native/external_video_surface_container_impl.cc @@ -0,0 +1,112 @@ +// Copyright 2014 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 "android_webview/native/external_video_surface_container_impl.h" + +#include "base/android/jni_android.h" +#include "content/public/browser/android/content_view_core.h" +#include "jni/ExternalVideoSurfaceContainer_jni.h" +#include "ui/gfx/rect_f.h" + +using android_webview::ExternalVideoSurfaceContainerImpl; +using base::android::AttachCurrentThread; +using content::ContentViewCore; + +DEFINE_WEB_CONTENTS_USER_DATA_KEY(ExternalVideoSurfaceContainerImpl); + +namespace content { + +// static +void ExternalVideoSurfaceContainer::CreateForWebContents( + WebContents* web_contents) { + WebContentsUserData<ExternalVideoSurfaceContainerImpl>::CreateForWebContents( + web_contents); +} + +// static +ExternalVideoSurfaceContainer* ExternalVideoSurfaceContainer::FromWebContents( + WebContents* web_contents) { + return WebContentsUserData<ExternalVideoSurfaceContainerImpl>:: + FromWebContents(web_contents); +} + +} // namespace content + +namespace android_webview { + +ExternalVideoSurfaceContainerImpl::ExternalVideoSurfaceContainerImpl( + content::WebContents* web_contents) { + ContentViewCore* cvc = ContentViewCore::FromWebContents(web_contents); + if (cvc) { + JNIEnv* env = AttachCurrentThread(); + jobject_.Reset( + Java_ExternalVideoSurfaceContainer_create( + env, reinterpret_cast<intptr_t>(this), cvc->GetJavaObject().obj())); + } +} + +ExternalVideoSurfaceContainerImpl::~ExternalVideoSurfaceContainerImpl() { + JNIEnv* env = AttachCurrentThread(); + Java_ExternalVideoSurfaceContainer_destroy(env, jobject_.obj()); + jobject_.Reset(); +} + +void ExternalVideoSurfaceContainerImpl::RequestExternalVideoSurface( + int player_id, + const SurfaceCreatedCB& surface_created_cb, + const SurfaceDestroyedCB& surface_destroyed_cb) { + surface_created_cb_ = surface_created_cb; + surface_destroyed_cb_ = surface_destroyed_cb; + + JNIEnv* env = AttachCurrentThread(); + Java_ExternalVideoSurfaceContainer_requestExternalVideoSurface( + env, jobject_.obj(), static_cast<jint>(player_id)); +} + +void ExternalVideoSurfaceContainerImpl::ReleaseExternalVideoSurface( + int player_id) { + JNIEnv* env = AttachCurrentThread(); + Java_ExternalVideoSurfaceContainer_releaseExternalVideoSurface( + env, jobject_.obj(), static_cast<jint>(player_id)); + + surface_created_cb_.Reset(); + surface_destroyed_cb_.Reset(); +} + +void ExternalVideoSurfaceContainerImpl::OnFrameInfoUpdated() { + JNIEnv* env = AttachCurrentThread(); + Java_ExternalVideoSurfaceContainer_onFrameInfoUpdated(env, jobject_.obj()); +} + +void ExternalVideoSurfaceContainerImpl::OnExternalVideoSurfacePositionChanged( + int player_id, const gfx::RectF& rect) { + JNIEnv* env = AttachCurrentThread(); + Java_ExternalVideoSurfaceContainer_onExternalVideoSurfacePositionChanged( + env, + jobject_.obj(), + static_cast<jint>(player_id), + static_cast<jfloat>(rect.x()), + static_cast<jfloat>(rect.y()), + static_cast<jfloat>(rect.x() + rect.width()), + static_cast<jfloat>(rect.y() + rect.height())); +} + +// Methods called from Java. +void ExternalVideoSurfaceContainerImpl::SurfaceCreated( + JNIEnv* env, jobject obj, jint player_id, jobject jsurface) { + if (!surface_created_cb_.is_null()) + surface_created_cb_.Run(static_cast<int>(player_id), jsurface); +} + +void ExternalVideoSurfaceContainerImpl::SurfaceDestroyed( + JNIEnv* env, jobject obj, jint player_id) { + if (!surface_destroyed_cb_.is_null()) + surface_destroyed_cb_.Run(static_cast<int>(player_id)); +} + +bool RegisterExternalVideoSurfaceContainer(JNIEnv* env) { + return RegisterNativesImpl(env) >= 0; +} + +} // namespace android_webview diff --git a/android_webview/native/external_video_surface_container_impl.h b/android_webview/native/external_video_surface_container_impl.h new file mode 100644 index 0000000..c5d9f07 --- /dev/null +++ b/android_webview/native/external_video_surface_container_impl.h @@ -0,0 +1,57 @@ +// Copyright 2014 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 ANDROID_WEBVIEW_NATIVE_EXTERNAL_VIDEO_SURFACE_CONTAINER_IMPL_H_ +#define ANDROID_WEBVIEW_NATIVE_EXTERNAL_VIDEO_SURFACE_CONTAINER_IMPL_H_ + +#include <jni.h> + +#include "base/android/scoped_java_ref.h" +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "content/public/browser/android/external_video_surface_container.h" +#include "content/public/browser/web_contents_user_data.h" + +namespace android_webview { + +class ExternalVideoSurfaceContainerImpl + : public content::ExternalVideoSurfaceContainer, + public content::WebContentsUserData<ExternalVideoSurfaceContainerImpl> { + public: + typedef base::Callback<void(int, jobject)> SurfaceCreatedCB; + typedef base::Callback<void(int)> SurfaceDestroyedCB; + + ExternalVideoSurfaceContainerImpl(content::WebContents* contents); + + // ExternalVideoSurfaceContainer implementation. + virtual void RequestExternalVideoSurface( + int player_id, + const SurfaceCreatedCB& surface_created_cb, + const SurfaceDestroyedCB& surface_destroyed_cb) OVERRIDE; + virtual void ReleaseExternalVideoSurface(int player_id) OVERRIDE; + virtual void OnFrameInfoUpdated() OVERRIDE; + virtual void OnExternalVideoSurfacePositionChanged( + int player_id, const gfx::RectF& rect) OVERRIDE; + + // Methods called from Java. + void SurfaceCreated( + JNIEnv* env, jobject obj, jint player_id, jobject jsurface); + void SurfaceDestroyed(JNIEnv* env, jobject obj, jint player_id); + + private: + virtual ~ExternalVideoSurfaceContainerImpl(); + + base::android::ScopedJavaGlobalRef<jobject> jobject_; + + SurfaceCreatedCB surface_created_cb_; + SurfaceDestroyedCB surface_destroyed_cb_; + + DISALLOW_COPY_AND_ASSIGN(ExternalVideoSurfaceContainerImpl); +}; + +bool RegisterExternalVideoSurfaceContainer(JNIEnv* env); + +} // namespace android_webview + +#endif // ANDROID_WEBVIEW_NATIVE_EXTERNAL_VIDEO_SURFACE_CONTAINER_IMPL_H_ diff --git a/android_webview/native/webview_native.gyp b/android_webview/native/webview_native.gyp index 8acb8b9..bfacd3b 100644 --- a/android_webview/native/webview_native.gyp +++ b/android_webview/native/webview_native.gyp @@ -81,6 +81,14 @@ 'state_serializer.cc', 'state_serializer.h', ], + 'conditions': [ + ['video_hole==1', { + 'sources': [ + 'external_video_surface_container_impl.cc', + 'external_video_surface_container_impl.h', + ], + }], + ], }, { 'target_name': 'input_stream_android_jar_jni_headers', @@ -119,6 +127,7 @@ '../java/src/org/chromium/android_webview/AwResource.java', '../java/src/org/chromium/android_webview/AwSettings.java', '../java/src/org/chromium/android_webview/AwWebContentsDelegate.java', + '../java/src/org/chromium/android_webview/ExternalVideoSurfaceContainer.java', '../java/src/org/chromium/android_webview/InterceptedRequestData.java', '../java/src/org/chromium/android_webview/JavaBrowserViewRendererHelper.java', ], diff --git a/build/common.gypi b/build/common.gypi index 72e0e73..594b9a2 100644 --- a/build/common.gypi +++ b/build/common.gypi @@ -1278,6 +1278,9 @@ # Force disable libstdc++ debug mode. 'disable_glibcxx_debug%': 0, + # Set to 1 to compile with the hole punching for the protected video. + 'video_hole%': 0, + 'conditions': [ # The version of GCC in use, set later in platforms that use GCC and have # not explicitly chosen to build with clang. Currently, this means all @@ -2514,6 +2517,9 @@ '<(DEPTH)/chrome_elf/chrome_elf.gyp:chrome_redirects', ], }], + ['video_hole==1', { + 'defines': ['VIDEO_HOLE=1'], + }], ], # conditions for 'target_defaults' 'target_conditions': [ ['enable_wexit_time_destructors==1', { diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc index 2f120b4..89a1e5a 100644 --- a/content/browser/android/content_view_core_impl.cc +++ b/content/browser/android/content_view_core_impl.cc @@ -35,6 +35,7 @@ #include "content/common/input/web_input_event_traits.h" #include "content/common/input_messages.h" #include "content/common/view_messages.h" +#include "content/public/browser/android/external_video_surface_container.h" #include "content/public/browser/browser_accessibility_state.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/favicon_status.h" @@ -495,6 +496,12 @@ void ContentViewCoreImpl::UpdateFrameInfo( controls_offset.y(), content_offset.y(), overdraw_bottom_height); +#if defined(VIDEO_HOLE) + ExternalVideoSurfaceContainer* surface_container = + ExternalVideoSurfaceContainer::FromWebContents(web_contents_); + if (surface_container) + surface_container->OnFrameInfoUpdated(); +#endif // defined(VIDEO_HOLE) } void ContentViewCoreImpl::SetTitle(const base::string16& title) { @@ -744,25 +751,6 @@ ScopedJavaLocalRef<jobject> ContentViewCoreImpl::CreateTouchEventSynthesizer() { return Java_ContentViewCore_createTouchEventSynthesizer(env, obj.obj()); } -void ContentViewCoreImpl::NotifyExternalSurface( - int player_id, bool is_request, const gfx::RectF& rect) { - JNIEnv* env = AttachCurrentThread(); - - ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); - if (obj.is_null()) - return; - - Java_ContentViewCore_notifyExternalSurface( - env, - obj.obj(), - static_cast<jint>(player_id), - static_cast<jboolean>(is_request), - static_cast<jfloat>(rect.x()), - static_cast<jfloat>(rect.y()), - static_cast<jfloat>(rect.width()), - static_cast<jfloat>(rect.height())); -} - ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContentVideoViewClient() { JNIEnv* env = AttachCurrentThread(); @@ -1501,33 +1489,6 @@ jboolean ContentViewCoreImpl::IsShowingInterstitialPage(JNIEnv* env, return web_contents_->ShowingInterstitialPage(); } -void ContentViewCoreImpl::AttachExternalVideoSurface(JNIEnv* env, - jobject obj, - jint player_id, - jobject jsurface) { -#if defined(VIDEO_HOLE) - RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>( - web_contents_->GetRenderViewHost()); - if (rvhi && rvhi->media_player_manager()) { - rvhi->media_player_manager()->AttachExternalVideoSurface( - static_cast<int>(player_id), jsurface); - } -#endif // defined(VIDEO_HOLE) -} - -void ContentViewCoreImpl::DetachExternalVideoSurface(JNIEnv* env, - jobject obj, - jint player_id) { -#if defined(VIDEO_HOLE) - RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>( - web_contents_->GetRenderViewHost()); - if (rvhi && rvhi->media_player_manager()) { - rvhi->media_player_manager()->DetachExternalVideoSurface( - static_cast<int>(player_id)); - } -#endif // defined(VIDEO_HOLE) -} - jboolean ContentViewCoreImpl::IsRenderWidgetHostViewReady(JNIEnv* env, jobject obj) { RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid(); diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h index 9299f1c..80740f2 100644 --- a/content/browser/android/content_view_core_impl.h +++ b/content/browser/android/content_view_core_impl.h @@ -216,11 +216,6 @@ class ContentViewCoreImpl : public ContentViewCore, jint delegate); jboolean IsShowingInterstitialPage(JNIEnv* env, jobject obj); - void AttachExternalVideoSurface(JNIEnv* env, - jobject obj, - jint player_id, - jobject jsurface); - void DetachExternalVideoSurface(JNIEnv* env, jobject obj, jint player_id); void SetAccessibilityEnabled(JNIEnv* env, jobject obj, bool enabled); void SendActionAfterDoubleTapUma(JNIEnv* env, jobject obj, @@ -290,11 +285,6 @@ class ContentViewCoreImpl : public ContentViewCore, // testing/benchmarking purposes base::android::ScopedJavaLocalRef<jobject> CreateTouchEventSynthesizer(); - // Notifies the java object about the external surface, requesting for one if - // necessary. - void NotifyExternalSurface( - int player_id, bool is_request, const gfx::RectF& rect); - base::android::ScopedJavaLocalRef<jobject> GetContentVideoViewClient(); // Returns the context that the ContentViewCore was created with, it would diff --git a/content/browser/media/android/browser_media_player_manager.cc b/content/browser/media/android/browser_media_player_manager.cc index b3d62bc..5d457e4 100644 --- a/content/browser/media/android/browser_media_player_manager.cc +++ b/content/browser/media/android/browser_media_player_manager.cc @@ -12,6 +12,7 @@ #include "content/browser/web_contents/web_contents_view_android.h" #include "content/common/media/media_player_messages_android.h" #include "content/public/browser/android/content_view_core.h" +#include "content/public/browser/android/external_video_surface_container.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" @@ -326,7 +327,12 @@ void BrowserMediaPlayerManager::RequestMediaResources(int player_id) { } void BrowserMediaPlayerManager::ReleaseMediaResources(int player_id) { - // Nothing needs to be done. +#if defined(VIDEO_HOLE) + ExternalVideoSurfaceContainer* surface_container = + ExternalVideoSurfaceContainer::FromWebContents(web_contents_); + if (surface_container) + surface_container->ReleaseExternalVideoSurface(player_id); +#endif // defined(VIDEO_HOLE) } media::MediaResourceGetter* @@ -464,10 +470,23 @@ void BrowserMediaPlayerManager::OnNotifyExternalSurface( if (!web_contents_) return; - WebContentsViewAndroid* view = - static_cast<WebContentsViewAndroid*>(web_contents_->GetView()); - if (view) - view->NotifyExternalSurface(player_id, is_request, rect); + ExternalVideoSurfaceContainer::CreateForWebContents(web_contents_); + ExternalVideoSurfaceContainer* surface_container = + ExternalVideoSurfaceContainer::FromWebContents(web_contents_); + if (!surface_container) + return; + + if (is_request) { + // It's safe to use base::Unretained(this), because the callbacks will not + // be called after running ReleaseExternalVideoSurface(). + surface_container->RequestExternalVideoSurface( + player_id, + base::Bind(&BrowserMediaPlayerManager::AttachExternalVideoSurface, + base::Unretained(this)), + base::Bind(&BrowserMediaPlayerManager::DetachExternalVideoSurface, + base::Unretained(this))); + } + surface_container->OnExternalVideoSurfacePositionChanged(player_id, rect); } #endif // defined(VIDEO_HOLE) @@ -492,6 +511,12 @@ void BrowserMediaPlayerManager::OnEnterFullscreen(int player_id) { return; } +#if defined(VIDEO_HOLE) + ExternalVideoSurfaceContainer* surface_container = + ExternalVideoSurfaceContainer::FromWebContents(web_contents_); + if (surface_container) + surface_container->ReleaseExternalVideoSurface(player_id); +#endif // defined(VIDEO_HOLE) if (video_view_.get()) { fullscreen_player_id_ = player_id; video_view_->OpenVideo(); @@ -570,13 +595,6 @@ void BrowserMediaPlayerManager::OnReleaseResources(int player_id) { player->Release(); if (player_id == fullscreen_player_id_) fullscreen_player_is_released_ = true; - -#if defined(VIDEO_HOLE) - WebContentsViewAndroid* view = - static_cast<WebContentsViewAndroid*>(web_contents_->GetView()); - if (view) - view->NotifyExternalSurface(player_id, false, gfx::RectF()); -#endif // defined(VIDEO_HOLE) } void BrowserMediaPlayerManager::OnDestroyPlayer(int player_id) { diff --git a/content/browser/web_contents/web_contents_view_android.cc b/content/browser/web_contents/web_contents_view_android.cc index fc024b7..76408a6 100644 --- a/content/browser/web_contents/web_contents_view_android.cc +++ b/content/browser/web_contents/web_contents_view_android.cc @@ -54,14 +54,6 @@ void WebContentsViewAndroid::SetContentViewCore( } } -#if defined(VIDEO_HOLE) -void WebContentsViewAndroid::NotifyExternalSurface( - int player_id, bool is_request, const gfx::RectF& rect) { - if (content_view_core_) - content_view_core_->NotifyExternalSurface(player_id, is_request, rect); -} -#endif // defined(VIDEO_HOLE) - gfx::NativeView WebContentsViewAndroid::GetNativeView() const { return content_view_core_ ? content_view_core_->GetViewAndroid() : NULL; } diff --git a/content/browser/web_contents/web_contents_view_android.h b/content/browser/web_contents/web_contents_view_android.h index 3d043ec..aa2ef54 100644 --- a/content/browser/web_contents/web_contents_view_android.h +++ b/content/browser/web_contents/web_contents_view_android.h @@ -29,12 +29,6 @@ class WebContentsViewAndroid : public WebContentsViewPort, // by the UI frontend. void SetContentViewCore(ContentViewCoreImpl* content_view_core); -#if defined(VIDEO_HOLE) - void NotifyExternalSurface(int player_id, - bool is_request, - const gfx::RectF& rect); -#endif // defined(VIDEO_HOLE) - // WebContentsView implementation -------------------------------------------- virtual gfx::NativeView GetNativeView() const OVERRIDE; virtual gfx::NativeView GetContentNativeView() const OVERRIDE; diff --git a/content/content_browser.gypi b/content/content_browser.gypi index e97081d..f24002d 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -40,6 +40,7 @@ 'public/browser/android/content_view_layer_renderer.h', 'public/browser/android/devtools_auth.h', 'public/browser/android/download_controller_android.h', + 'public/browser/android/external_video_surface_container.h', 'public/browser/android/synchronous_compositor_client.h', 'public/browser/android/synchronous_compositor.cc', 'public/browser/android/synchronous_compositor.h', diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewClient.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewClient.java index f870651..5ae5dbb 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewClient.java +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewClient.java @@ -7,7 +7,6 @@ package org.chromium.content.browser; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; -import android.graphics.RectF; import android.util.Log; import android.view.ActionMode; import android.view.KeyEvent; @@ -161,12 +160,6 @@ public class ContentViewClient { } } - public void onExternalVideoSurfaceRequested(int playerId) { - } - - public void onGeometryChanged(int playerId, RectF rect) { - } - public ContentVideoViewClient getContentVideoViewClient() { return null; } diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java index 9dea1cf..71cb9cd 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java @@ -16,7 +16,6 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Rect; -import android.graphics.RectF; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -2553,9 +2552,6 @@ public class ContentViewCore if (mBrowserAccessibilityManager != null) { mBrowserAccessibilityManager.notifyFrameInfoInitialized(); } - - // Update geometry for external video surface. - getContentViewClient().onGeometryChanged(-1, null); } @CalledByNative @@ -3225,18 +3221,6 @@ public class ContentViewCore return new Rect(x, y, right, bottom); } - public void attachExternalVideoSurface(int playerId, Surface surface) { - if (mNativeContentViewCore != 0) { - nativeAttachExternalVideoSurface(mNativeContentViewCore, playerId, surface); - } - } - - public void detachExternalVideoSurface(int playerId) { - if (mNativeContentViewCore != 0) { - nativeDetachExternalVideoSurface(mNativeContentViewCore, playerId); - } - } - private boolean onAnimate(long frameTimeMicros) { if (mNativeContentViewCore == 0) return false; return nativeOnAnimate(mNativeContentViewCore, frameTimeMicros); @@ -3249,13 +3233,6 @@ public class ContentViewCore } } - @CalledByNative - private void notifyExternalSurface( - int playerId, boolean isRequest, float x, float y, float width, float height) { - if (isRequest) getContentViewClient().onExternalVideoSurfaceRequested(playerId); - getContentViewClient().onGeometryChanged(playerId, new RectF(x, y, x + width, y + height)); - } - public void extractSmartClipData(int x, int y, int width, int height) { if (mNativeContentViewCore != 0) { nativeExtractSmartClipData(mNativeContentViewCore, x, y, width, height); @@ -3465,12 +3442,6 @@ public class ContentViewCore private native void nativeShowImeIfNeeded(long nativeContentViewCoreImpl); - private native void nativeAttachExternalVideoSurface( - long nativeContentViewCoreImpl, int playerId, Surface surface); - - private native void nativeDetachExternalVideoSurface( - long nativeContentViewCoreImpl, int playerId); - private native void nativeSetAccessibilityEnabled( long nativeContentViewCoreImpl, boolean enabled); diff --git a/content/public/browser/android/external_video_surface_container.h b/content/public/browser/android/external_video_surface_container.h new file mode 100644 index 0000000..1b630e1 --- /dev/null +++ b/content/public/browser/android/external_video_surface_container.h @@ -0,0 +1,61 @@ +// Copyright 2014 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_PUBLIC_BROWSER_ANDROID_EXTERNAL_VIDEO_SURFACE_CONTAINER_H_ +#define CONTENT_PUBLIC_BROWSER_ANDROID_EXTERNAL_VIDEO_SURFACE_CONTAINER_H_ + +#include <jni.h> + +#include "base/callback.h" +#include "content/common/content_export.h" + +namespace gfx { +class RectF; +} + +namespace content { +class WebContents; + +// An interface used for managing the video surface for the hole punching. +class CONTENT_EXPORT ExternalVideoSurfaceContainer { + public: + typedef base::Callback<void(int, jobject)> SurfaceCreatedCB; + typedef base::Callback<void(int)> SurfaceDestroyedCB; + + // Creates an ExternalVideoSurfaceContainer, and attaches it to the given + // WebContents. If an instance is already attached, does nothing. + static void CreateForWebContents(WebContents* contents); + + // Returns the existing ExternalVideoSurfaceContainer attached to the given + // WebContents or NULL. + static ExternalVideoSurfaceContainer* FromWebContents(WebContents* contents); + + // Called when a media player wants to request an external video surface. + // Whenever the surface is created and visible, |surface_created_cb| will be + // called. And whenever it is destroyed or invisible, |surface_destroyed_cb| + // will be called. + virtual void RequestExternalVideoSurface( + int player_id, + const SurfaceCreatedCB& surface_created_cb, + const SurfaceDestroyedCB& surface_destroyed_cb) = 0; + + // Called when a media player wants to release an external video surface. + virtual void ReleaseExternalVideoSurface(int player_id) = 0; + + // Called when the position and size of the video element which uses + // the external video surface is changed. + // |rect| contains the new position and size in css pixels. + virtual void OnExternalVideoSurfacePositionChanged( + int player_id, const gfx::RectF& rect) = 0; + + // Called when the page that contains the video element is scrolled or zoomed. + virtual void OnFrameInfoUpdated() = 0; + + protected: + virtual ~ExternalVideoSurfaceContainer() {} +}; + +} // namespace content + +#endif // CONTENT_PUBLIC_BROWSER_ANDROID_EXTERNAL_VIDEO_SURFACE_CONTAINER_H_ |