| Index: content/common/gpu/media/android_video_decode_accelerator.cc
|
| diff --git a/content/common/gpu/media/android_video_decode_accelerator.cc b/content/common/gpu/media/android_video_decode_accelerator.cc
|
| index 3942a80ff3b4b27e042912b7853cfaac8cdc1702..64653a63f3d31204021d8df068405252729ac206 100644
|
| --- a/content/common/gpu/media/android_video_decode_accelerator.cc
|
| +++ b/content/common/gpu/media/android_video_decode_accelerator.cc
|
| @@ -127,15 +127,22 @@ class AndroidVideoDecodeAccelerator::OnFrameAvailableHandler
|
| public:
|
| // We do not retain ownership of |owner|. It must remain valid until
|
| // after ClearOwner() is called. This will register with
|
| - // |surface_texture| to receive OnFrameAvailable callbacks.
|
| + // |surface_texture| to receive OnFrameAvailable callbacks. If
|
| + // |use_separate_thread| is true, then we'll request that the callback happens
|
| + // on a thread that is dedicated to SurfaceTexture callbacks.
|
| OnFrameAvailableHandler(
|
| AndroidVideoDecodeAccelerator* owner,
|
| - const scoped_refptr<gfx::SurfaceTexture>& surface_texture)
|
| + const scoped_refptr<gfx::SurfaceTexture>& surface_texture,
|
| + bool use_separate_thread)
|
| : owner_(owner) {
|
| // Note that the callback owns a strong ref to us.
|
| - surface_texture->SetFrameAvailableCallbackOnAnyThread(
|
| - base::Bind(&OnFrameAvailableHandler::OnFrameAvailable,
|
| - scoped_refptr<OnFrameAvailableHandler>(this)));
|
| + base::Closure cb = base::Bind(&OnFrameAvailableHandler::OnFrameAvailable,
|
| + scoped_refptr<OnFrameAvailableHandler>(this));
|
| +
|
| + if (use_separate_thread)
|
| + surface_texture->SetFrameAvailableCallbackOnSeparateThread(cb);
|
| + else
|
| + surface_texture->SetFrameAvailableCallbackOnAnyThread(cb);
|
| }
|
|
|
| // Forget about our owner, which is required before one deletes it.
|
| @@ -257,7 +264,14 @@ AndroidVideoDecodeAccelerator::AndroidVideoDecodeAccelerator(
|
| if (UseDeferredRenderingStrategy()) {
|
| // TODO(liberato, watk): Figure out what we want to do about zero copy for
|
| // fullscreen external SurfaceView in WebView. http://crbug.com/582170.
|
| - DCHECK(!gl_decoder_->GetContextGroup()->mailbox_manager()->UsesSync());
|
| +
|
| + // Make sure that we're making a copy in sync mode, to verify that our
|
| + // guess about whether we're in sync mode in NeedsBrowserCopy is correct.
|
| + // Also make sure that, if we're in sync mode, that we're using a threaded
|
| + // callback so that it doesn't deadlock with the main thread.
|
| + DCHECK(!gl_decoder_->GetContextGroup()->mailbox_manager()->UsesSync() ||
|
| + (DeferredStrategyNeedsBrowserCopy() && IsCallbackThreadable()));
|
| +
|
| DVLOG(1) << __FUNCTION__ << ", using deferred rendering strategy.";
|
| strategy_.reset(new AndroidDeferredRenderingBackingStrategy(this));
|
| } else {
|
| @@ -335,8 +349,14 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config,
|
| scoped_refptr<gfx::SurfaceTexture> surface_texture =
|
| strategy_->GetSurfaceTexture();
|
| if (surface_texture) {
|
| + // The deferred strategy requires threading the callback if we're using
|
| + // the sync compositor.
|
| + bool use_separate_thread =
|
| + gl_decoder_->GetContextGroup()->mailbox_manager()->UsesSync() &&
|
| + UseDeferredRenderingStrategy();
|
| + DCHECK(!use_separate_thread || IsCallbackThreadable());
|
| on_frame_available_handler_ =
|
| - new OnFrameAvailableHandler(this, surface_texture);
|
| + new OnFrameAvailableHandler(this, surface_texture, use_separate_thread);
|
| }
|
|
|
| // For encrypted streams we postpone configuration until MediaCrypto is
|
| @@ -1102,10 +1122,37 @@ void AndroidVideoDecodeAccelerator::ManageTimer(bool did_work) {
|
|
|
| // static
|
| bool AndroidVideoDecodeAccelerator::UseDeferredRenderingStrategy() {
|
| - const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
|
| // TODO(liberato, watk): Figure out what we want to do about zero copy for
|
| // fullscreen external SurfaceView in WebView. http://crbug.com/582170.
|
| - return !cmd_line->HasSwitch(switches::kEnableThreadedTextureMailboxes);
|
| + // If we are at API 21, we can use this any time. Otherwise, we cannot use
|
| + // it for webview, since we cannot set the callback thread, causing a
|
| + // deadlock with the compositor.
|
| + return IsCallbackThreadable() || !DeferredStrategyNeedsBrowserCopy();
|
| +}
|
| +
|
| +// static
|
| +bool AndroidVideoDecodeAccelerator::DeferredStrategyNeedsBrowserCopy() {
|
| + // If we're using the synchronous mailbox mechanism and the deferred
|
| + // rendering strategy, then we need to force a copy before sending to
|
| + // the browser compositor.
|
| + // The copy is required because SurfaceTexture client textures can't be
|
| + // shared across unrelated GL contexts. By deferring the copy until the
|
| + // frame is sent to the browser compositor, we can limit the number of
|
| + // outstanding copies to be ~2, regardless of how many the pipeline wants
|
| + // for better playback.
|
| + // In practice, all of that means "WebView requires a copy".
|
| +
|
| + // We'd really like to check
|
| + // gl_decoder_->GetContextGroup()->mailbox_manager()->UsesSync() here, but
|
| + // we're called too early in start-up for that to be set properly.
|
| + // Instead, we use this switch and verify it later.
|
| + const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
|
| + return cmd_line->HasSwitch(switches::kEnableThreadedTextureMailboxes);
|
| +}
|
| +
|
| +// static
|
| +bool AndroidVideoDecodeAccelerator::IsCallbackThreadable() {
|
| + return base::android::BuildInfo::GetInstance()->sdk_int() >= 21;
|
| }
|
|
|
| // static
|
| @@ -1146,6 +1193,9 @@ AndroidVideoDecodeAccelerator::GetCapabilities() {
|
| NEEDS_ALL_PICTURE_BUFFERS_TO_DECODE |
|
| media::VideoDecodeAccelerator::Capabilities::
|
| SUPPORTS_EXTERNAL_OUTPUT_SURFACE;
|
| + if (DeferredStrategyNeedsBrowserCopy())
|
| + capabilities.flags |=
|
| + media::VideoDecodeAccelerator::Capabilities::COPY_REQUIRED;
|
| }
|
|
|
| return capabilities;
|
|
|