Commit c58e8f82 authored by liberato's avatar liberato Committed by Commit bot

Add ContentVideoViewOverlay to AVDA.

Wrap usage of ContentVideoView in an AndroidOverlay interface.  This
doesn't change the functionality, but starts to move AVDA towards
using AndroidOverlays rather than hard-coding CVV.

Much of Allocate/DeallocateSurface could be moved from
AVDACodecAllocator to ContentVideoViewOverlay.  However, to keep the
size of this change small, it isn't yet.

There shouldn't be any functional difference with this CL.

BUG=667950

CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel

Review-Url: https://codereview.chromium.org/2692863011
Cr-Commit-Position: refs/heads/master@{#456135}
parent 7da56993
......@@ -16,6 +16,8 @@ if (is_android) {
sources = [
"android_cdm_factory.cc",
"android_cdm_factory.h",
"android_overlay.cc",
"android_overlay.h",
"media_client_android.cc",
"media_client_android.h",
"media_codec_bridge.h",
......
// Copyright 2017 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 "media/base/android/android_overlay.h"
namespace media {
AndroidOverlay::Config::Config() = default;
AndroidOverlay::Config::Config(const AndroidOverlay::Config&) = default;
AndroidOverlay::Config::~Config() = default;
} // namespace media
// Copyright 2017 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 MEDIA_BASE_ANDROID_ANDROID_OVERLAY_H_
#define MEDIA_BASE_ANDROID_ANDROID_OVERLAY_H_
#include "base/android/scoped_java_ref.h"
#include "base/callback.h"
#include "base/macros.h"
#include "media/base/media_export.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gl/android/scoped_java_surface.h"
namespace media {
// Client interface to an AndroidOverlay. Once constructed, you can expect to
// receive either a call to ReadyCB or a call to FailedCB to indicate whether
// the overlay is ready, or isn't going to be ready. If one does get ReadyCB,
// then one may GetJavaSurface() to retrieve the java Surface object. One
// will get DestroyedCB eventually after ReadyCB, assuming that one doesn't
// delete the overlay before that.
// When DestroyedCB arrives, you should stop using the Android Surface and
// delete the AndroidOverlay instance. Currently, the exact contract depends
// on the concrete implementation. Once ContentVideoView is deprecated, it will
// be: it is not guaranteed that any AndroidOverlay instances will operate until
// the destroyed instance is deleted. This must happen on the thread that was
// used to create it. It does not have to happen immediately, or before the
// callback returns.
// With CVV, one must still delete the overlay on the main thread, and it
// doesn't have to happen before this returns. However, one must signal the
// CVV onSurfaceDestroyed handler on some thread before returning from the
// callback. AVDACodecAllocator::ReleaseMediaCodec handles signaling. The
// fundamental difference is that CVV blocks the UI thread in the browser, which
// makes it unsafe to let the gpu main thread proceed without risk of deadlock
// AndroidOverlay isn't technically supposed to do that.
class MEDIA_EXPORT AndroidOverlay {
public:
// Called when the overlay is ready for use, via |GetJavaSurface()|.
using ReadyCB = base::Callback<void()>;
// Called when overlay has failed before |ReadyCB| is called. Will not be
// called after ReadyCB. It will be the last callback for the overlay.
using FailedCB = base::Callback<void()>;
// Called when the overlay has been destroyed. This will not be called unless
// ReadyCB has been called. It will be the last callback for the overlay.
using DestroyedCB = base::Callback<void()>;
// Configuration used to create an overlay.
struct Config {
public:
Config();
Config(const Config&);
~Config();
gfx::Rect rect;
ReadyCB ready_cb;
FailedCB failed_cb;
DestroyedCB destroyed_cb;
};
virtual ~AndroidOverlay() {}
// Schedules a relayout of this overlay. If called before the client is
// notified that the surface is created, then the call will be ignored.
virtual void ScheduleLayout(const gfx::Rect& rect) = 0;
// May be called during / after ReadyCB and before DestroyedCB.
virtual const base::android::JavaRef<jobject>& GetJavaSurface() const = 0;
protected:
AndroidOverlay() {}
DISALLOW_COPY_AND_ASSIGN(AndroidOverlay);
};
} // namespace media
#endif // MEDIA_BASE_ANDROID_ANDROID_OVERLAY_H_
......@@ -189,6 +189,8 @@ component("gpu") {
"avda_state_provider.h",
"avda_surface_bundle.cc",
"avda_surface_bundle.h",
"content_video_view_overlay.cc",
"content_video_view_overlay.h",
"surface_texture_gl_owner.cc",
"surface_texture_gl_owner.h",
]
......
......@@ -35,6 +35,7 @@
#include "media/base/timestamp_constants.h"
#include "media/base/video_decoder_config.h"
#include "media/gpu/avda_picture_buffer_manager.h"
#include "media/gpu/content_video_view_overlay.h"
#include "media/gpu/shared_memory_region.h"
#include "media/video/picture.h"
#include "ui/gl/android/scoped_java_surface.h"
......@@ -364,6 +365,13 @@ void AndroidVideoDecodeAccelerator::StartSurfaceCreation() {
// afterwards (::Decode, for deferred surface init, UpdateSurface).
DCHECK(incoming_bundle_);
// We should not yet have an overlay.
DCHECK(!incoming_bundle_->overlay);
// Note that we don't enforce that for any SurfaceTexture or its Surface,
// since there might be a codec that's using them. They'll get cleared
// later, in InitializePictureBufferManager.
// If surface creation is deferred, then do nothing except signal that init
// is complete, if needed. We might still fail to get a surface or codec,
// which would normally be an init error. Since we're deferring init until a
......@@ -377,34 +385,52 @@ void AndroidVideoDecodeAccelerator::StartSurfaceCreation() {
return;
}
if (!codec_allocator_->AllocateSurface(this, incoming_bundle_->surface_id)) {
if (incoming_bundle_->surface_id != SurfaceManager::kNoSurfaceID) {
// Create the overlay. Note that it will never call us back immediately.
// It will post when the surface is available.
AndroidOverlay::Config overlay_config;
// We use weak ptrs here since |overlay| can outlive us, if we send it for
// async codec config.
overlay_config.ready_cb =
base::Bind(&AndroidVideoDecodeAccelerator::OnOverlayReady,
weak_this_factory_.GetWeakPtr());
overlay_config.failed_cb =
base::Bind(&AndroidVideoDecodeAccelerator::OnOverlayFailed,
weak_this_factory_.GetWeakPtr());
overlay_config.destroyed_cb =
base::Bind(&AndroidVideoDecodeAccelerator::OnSurfaceDestroyed,
weak_this_factory_.GetWeakPtr());
// TODO(liberato): make |surface_id| the overlay config token. If we're
// using CVV, then we'll need a CVV factory impl that understands it.
incoming_bundle_->overlay = base::MakeUnique<ContentVideoViewOverlay>(
codec_allocator_, incoming_bundle_->surface_id, overlay_config);
// We have to wait for some other AVDA instance to free up the surface.
// OnSurfaceAvailable will be called when it's available.
// OnOverlayReady will be called when it's available.
// Note that if we aren't deferring init, then we'll signal success, and
// if we fail later then it will fail decoding instead. However, since
// nobody that provides a SurfaceView requires sync init, it doesn't matter.
// Also remember that ContentVideoViewOverlay will not call OnOverlayReady
// before it returns.
state_ = WAITING_FOR_SURFACE;
return;
}
// We now own the surface, so finish initialization.
// We're creating a SurfaceTexture.
InitializePictureBufferManager();
}
void AndroidVideoDecodeAccelerator::OnSurfaceAvailable(bool success) {
void AndroidVideoDecodeAccelerator::OnOverlayReady() {
DCHECK(!defer_surface_creation_);
DCHECK_EQ(state_, WAITING_FOR_SURFACE);
DCHECK(incoming_bundle_);
if (!success) {
NOTIFY_ERROR(PLATFORM_FAILURE, "Surface is not available");
incoming_bundle_ = nullptr;
return;
}
InitializePictureBufferManager();
}
void AndroidVideoDecodeAccelerator::OnOverlayFailed() {
NOTIFY_ERROR(PLATFORM_FAILURE, "Surface is not available");
}
void AndroidVideoDecodeAccelerator::InitializePictureBufferManager() {
DCHECK(!defer_surface_creation_);
DCHECK(incoming_bundle_);
......@@ -412,18 +438,29 @@ void AndroidVideoDecodeAccelerator::InitializePictureBufferManager() {
if (!make_context_current_cb_.Run()) {
NOTIFY_ERROR(PLATFORM_FAILURE,
"Failed to make this decoder's GL context current");
incoming_bundle_ = nullptr;
return;
}
// Move |incoming_bundle_| to |codec_config_|. Our caller must set up an
// incoming bundle properly, since we don't want to accidentally overwrite
// |surface_bundle| for a codec that's being released elsewhere.
incoming_bundle_->surface = picture_buffer_manager_.Initialize(surface_id());
incoming_bundle_->surface_texture = picture_buffer_manager_.surface_texture();
if (incoming_bundle_->surface.IsEmpty()) {
NOTIFY_ERROR(PLATFORM_FAILURE, "Codec surface is empty");
incoming_bundle_ = nullptr;
return;
// TODO(liberato): it doesn't make sense anymore for the PictureBufferManager
// to create the surface texture. We can probably make an overlay impl out
// of it, and provide the surface texture to |picture_buffer_manager_|.
if (incoming_bundle_->overlay) {
picture_buffer_manager_.InitializeForOverlay();
} else {
incoming_bundle_->surface_texture_surface =
picture_buffer_manager_.InitializeForSurfaceTexture();
incoming_bundle_->surface_texture =
picture_buffer_manager_.surface_texture();
if (!incoming_bundle_->surface_texture) {
NOTIFY_ERROR(PLATFORM_FAILURE, "Could not allocate surface texture");
incoming_bundle_ = nullptr;
return;
}
}
// If we have a media codec, then SetSurface. If that doesn't work, then we
......@@ -431,8 +468,7 @@ void AndroidVideoDecodeAccelerator::InitializePictureBufferManager() {
// If we get here with a codec, then we must setSurface.
if (media_codec_) {
// TODO(liberato): fail on api check?
if (!media_codec_->SetSurface(
incoming_bundle_->surface.j_surface().obj())) {
if (!media_codec_->SetSurface(incoming_bundle_->j_surface().obj())) {
NOTIFY_ERROR(PLATFORM_FAILURE, "MediaCodec failed to switch surfaces.");
// We're not going to use |incoming_bundle_|.
} else {
......@@ -655,7 +691,7 @@ bool AndroidVideoDecodeAccelerator::DequeueOutput() {
if (!UpdateSurface())
return false;
// If we can't allocate the incoming surface yet, then stop here.
if (state_ == WAITING_FOR_SURFACE)
if (state_ != NO_ERROR)
return false;
}
......@@ -1014,7 +1050,6 @@ void AndroidVideoDecodeAccelerator::OnCodecConfigured(
std::unique_ptr<MediaCodecBridge> media_codec) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(state_ == WAITING_FOR_CODEC || state_ == SURFACE_DESTROYED);
// If we are supposed to notify that initialization is complete, then do so
// before returning. Otherwise, this is a reconfiguration.
......@@ -1158,6 +1193,10 @@ void AndroidVideoDecodeAccelerator::ResetCodecState() {
} else {
DVLOG(3) << __func__ << " Deleting the MediaCodec and creating a new one.";
GetManager()->StopTimer(this);
// Note that this will release the codec, then allocate a new one. It will
// not wait for the old one to finish up with the surface, which is bad.
// It works (usually) because it ends up allocating the codec on the same
// thread as is used to release the old one, so it's serialized anyway.
ConfigureMediaCodecAsynchronously();
}
}
......@@ -1234,10 +1273,6 @@ void AndroidVideoDecodeAccelerator::ActualDestroy() {
GetManager()->StopTimer(this);
ReleaseCodec();
// We no longer care about |surface_id|, in case we did before. It's okay
// if we have no surface and/or weren't the owner or a waiter.
codec_allocator_->DeallocateSurface(this, surface_id());
delete this;
}
......@@ -1559,7 +1594,6 @@ bool AndroidVideoDecodeAccelerator::UpdateSurface() {
DCHECK(surface_id() == SurfaceManager::kNoSurfaceID ||
pending_surface_id_.value() == SurfaceManager::kNoSurfaceID);
const int previous_surface_id = surface_id();
const int new_surface_id = pending_surface_id_.value();
pending_surface_id_.reset();
......@@ -1584,19 +1618,7 @@ bool AndroidVideoDecodeAccelerator::UpdateSurface() {
// should have been dropped.
DCHECK(!incoming_bundle_);
ReleaseCodec();
// We no longer own the new surface.
codec_allocator_->DeallocateSurface(this, new_surface_id);
}
// Regardless of whether we succeeded, we no longer own the previous surface.
// This is the only case where we start a new incoming bundle, and we maintain
// the property that |incoming_bundle_| is the one that we own, as documented
// for surface_id().
// It would be nice if the outgoing surface bundle did this.
// TODO(liberato): It could, but the CVV implementation of AndroidOverlay
// will do it too when the bundle holding it is dropped. We'll do it this way
// until then, just to minimize changes.
codec_allocator_->DeallocateSurface(this, previous_surface_id);
}
return state_ != ERROR;
}
......
......@@ -76,8 +76,6 @@ class MEDIA_GPU_EXPORT AndroidVideoDecodeAccelerator
void NotifyError(Error error) override;
// AVDACodecAllocatorClient implementation:
void OnSurfaceAvailable(bool success) override;
void OnSurfaceDestroyed() override;
void OnCodecConfigured(
std::unique_ptr<MediaCodecBridge> media_codec) override;
......@@ -112,14 +110,23 @@ class MEDIA_GPU_EXPORT AndroidVideoDecodeAccelerator
// Entry point for configuring / reconfiguring a codec with a new surface.
// Start surface creation by trying to allocate the surface id. Will either
// InitializePictureBufferManager if the surface is available immediately, or
// will wait for OnSurfaceAvailable to do it. This will transition |state_|
// will wait for OnOverlayReady to do it. This will transition |state_|
// to WAITING_FOR_SURFACE or WAITING_FOR_CODEC, as needed (or NO_ERROR if it
// gets the surface and the codec without waiting).
// Note that this requires that you create a new |incoming_bundle_| with the
// appropriate surface id.
void StartSurfaceCreation();
// Initialize of the picture buffer manager to use the current surface, once
// Called by AndroidOverlay when a surface becomes available.
void OnOverlayReady();
// Called by AndroidOverlay when the overlay will not call OnOverlayReady.
void OnOverlayFailed();
// Called by AndroidOverlay when a surface is lost.
void OnSurfaceDestroyed();
// Initializes the picture buffer manager to use the current surface, once
// it is available. This is not normally called directly, but rather via
// StartSurfaceCreation. If we have a media codec already, then this will
// attempt to setSurface the new surface. Otherwise, it will start codec
......@@ -148,11 +155,6 @@ class MEDIA_GPU_EXPORT AndroidVideoDecodeAccelerator
// concern with modifying |codec_config_| after this returns.
void ConfigureMediaCodecSynchronously();
// Instantiate a media codec using |codec_config|.
// This may be called on any thread.
static std::unique_ptr<MediaCodecBridge> ConfigureMediaCodecOnAnyThread(
scoped_refptr<CodecConfig> codec_config);
// Sends the decoded frame specified by |codec_buffer_index| to the client.
void SendDecodedFrameToClient(int32_t codec_buffer_index,
int32_t bitstream_id);
......
......@@ -142,7 +142,7 @@ scoped_refptr<base::SingleThreadTaskRunner> AVDACodecAllocator::TaskRunnerFor(
return threads_[task_type]->thread.task_runner();
}
bool AVDACodecAllocator::AllocateSurface(AVDACodecAllocatorClient* client,
bool AVDACodecAllocator::AllocateSurface(AVDASurfaceAllocatorClient* client,
int surface_id) {
DVLOG(1) << __func__ << ": " << surface_id;
DCHECK(thread_checker_.CalledOnValidThread());
......@@ -165,7 +165,7 @@ bool AVDACodecAllocator::AllocateSurface(AVDACodecAllocatorClient* client,
return false;
}
void AVDACodecAllocator::DeallocateSurface(AVDACodecAllocatorClient* client,
void AVDACodecAllocator::DeallocateSurface(AVDASurfaceAllocatorClient* client,
int surface_id) {
DCHECK(thread_checker_.CalledOnValidThread());
if (surface_id == SurfaceManager::kNoSurfaceID ||
......@@ -254,7 +254,7 @@ std::unique_ptr<MediaCodecBridge> AVDACodecAllocator::CreateMediaCodecSync(
MediaCodecBridgeImpl::CreateVideoDecoder(
codec_config->codec, codec_config->needs_protected_surface,
codec_config->initial_expected_coded_size,
codec_config->surface_bundle->surface.j_surface().obj(), media_crypto,
codec_config->surface_bundle->j_surface().obj(), media_crypto,
codec_config->csd0, codec_config->csd1, true,
require_software_codec));
......
......@@ -19,6 +19,7 @@
#include "base/threading/thread_checker.h"
#include "base/time/tick_clock.h"
#include "base/trace_event/trace_event.h"
#include "media/base/android/android_overlay.h"
#include "media/base/android/media_codec_bridge_impl.h"
#include "media/base/android/media_drm_bridge_cdm_context.h"
#include "media/base/media.h"
......@@ -80,7 +81,7 @@ class CodecConfig : public base::RefCountedThreadSafe<CodecConfig> {
DISALLOW_COPY_AND_ASSIGN(CodecConfig);
};
class AVDACodecAllocatorClient {
class AVDASurfaceAllocatorClient {
public:
// Called when the requested SurfaceView becomes available after a call to
// AllocateSurface()
......@@ -92,6 +93,12 @@ class AVDACodecAllocatorClient {
// need to call DeallocateSurface();
virtual void OnSurfaceDestroyed() = 0;
protected:
~AVDASurfaceAllocatorClient() {}
};
class AVDACodecAllocatorClient {
public:
// Called on the main thread when a new MediaCodec is configured.
// |media_codec| will be null if configuration failed.
virtual void OnCodecConfigured(
......@@ -122,13 +129,13 @@ class MEDIA_GPU_EXPORT AVDACodecAllocator {
// Returns true if the caller now owns the surface, or false if someone else
// owns the surface. |client| will be notified when the surface is available
// via OnSurfaceAvailable().
bool AllocateSurface(AVDACodecAllocatorClient* client, int surface_id);
bool AllocateSurface(AVDASurfaceAllocatorClient* client, int surface_id);
// Relinquish ownership of the surface or stop waiting for it to be available.
// The caller must guarantee that when calling this the surface is either no
// longer attached to a MediaCodec, or the MediaCodec it was attached to is
// was released with ReleaseMediaCodec().
void DeallocateSurface(AVDACodecAllocatorClient* client, int surface_id);
void DeallocateSurface(AVDASurfaceAllocatorClient* client, int surface_id);
// Create and configure a MediaCodec synchronously.
std::unique_ptr<MediaCodecBridge> CreateMediaCodecSync(
......@@ -190,8 +197,8 @@ class MEDIA_GPU_EXPORT AVDACodecAllocator {
friend class AVDACodecAllocatorTest;
struct OwnerRecord {
AVDACodecAllocatorClient* owner = nullptr;
AVDACodecAllocatorClient* waiter = nullptr;
AVDASurfaceAllocatorClient* owner = nullptr;
AVDASurfaceAllocatorClient* waiter = nullptr;
};
class HangDetector : public base::MessageLoop::TaskObserver {
......
......@@ -42,7 +42,8 @@ void SignalImmediately(base::WaitableEvent* event) {
}
}
class MockClient : public AVDACodecAllocatorClient {
class MockClient : public AVDACodecAllocatorClient,
public AVDASurfaceAllocatorClient {
public:
MOCK_METHOD1(OnSurfaceAvailable, void(bool success));
MOCK_METHOD0(OnSurfaceDestroyed, void());
......
......@@ -16,11 +16,11 @@
#include "gpu/command_buffer/service/gl_stream_texture_image.h"
#include "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h"
#include "gpu/command_buffer/service/texture_manager.h"
#include "gpu/ipc/common/gpu_surface_lookup.h"
#include "gpu/ipc/service/gpu_channel.h"
#include "media/base/android/media_codec_bridge_impl.h"
#include "media/gpu/avda_codec_image.h"
#include "media/gpu/avda_shared_state.h"
#include "ui/gl/android/scoped_java_surface.h"
#include "ui/gl/android/surface_texture.h"
#include "ui/gl/egl_util.h"
#include "ui/gl/gl_bindings.h"
......@@ -47,7 +47,8 @@ scoped_refptr<SurfaceTextureGLOwner> CreateAttachedSurfaceTexture(
base::WeakPtr<gpu::gles2::GLES2Decoder> gl_decoder) {
scoped_refptr<SurfaceTextureGLOwner> surface_texture =
SurfaceTextureGLOwner::Create();
DCHECK(surface_texture);
if (!surface_texture)
return nullptr;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, surface_texture->texture_id());
......@@ -71,17 +72,21 @@ AVDAPictureBufferManager::AVDAPictureBufferManager(
AVDAPictureBufferManager::~AVDAPictureBufferManager() {}
gl::ScopedJavaSurface AVDAPictureBufferManager::Initialize(int surface_id) {
void AVDAPictureBufferManager::InitializeForOverlay() {
shared_state_ = new AVDASharedState();
surface_texture_ = nullptr;
}
// Acquire the SurfaceView surface if given a valid id.
if (surface_id != SurfaceManager::kNoSurfaceID)
return gpu::GpuSurfaceLookup::GetInstance()->AcquireJavaSurface(surface_id);
gl::ScopedJavaSurface AVDAPictureBufferManager::InitializeForSurfaceTexture() {
shared_state_ = new AVDASharedState();
surface_texture_ = nullptr;
// Otherwise create a SurfaceTexture.
// Create a SurfaceTexture.
surface_texture_ =
CreateAttachedSurfaceTexture(state_provider_->GetGlDecoder());
if (!surface_texture_)
return gl::ScopedJavaSurface();
shared_state_->SetSurfaceTexture(surface_texture_);
return gl::ScopedJavaSurface(surface_texture_.get());
}
......
......@@ -43,14 +43,21 @@ class MEDIA_GPU_EXPORT AVDAPictureBufferManager {
explicit AVDAPictureBufferManager(AVDAStateProvider* state_provider);
virtual ~AVDAPictureBufferManager();
// Must be called before anything else. If |surface_id| is |kNoSurfaceID|
// then a new SurfaceTexture will be returned. Otherwise, the corresponding
// SurfaceView will be returned.
// Call either InitializeForOverlay or InitializeForSurfaceTexture before
// anything else. InitializeForOverlay will set us up to render codec buffers
// at the approrpriate time for display, but will assume that consuming the
// resulting buffers is handled elsewhere (e.g., SurfaceFlinger).
//
// May be called multiple times to switch to a new |surface_id|. Picture
// buffers will be updated to use the new surface during the call to
// UseCodecBufferForPictureBuffer().
gl::ScopedJavaSurface Initialize(int surface_id);
// InitializeForSurfaceTexture will create a SurfaceTexture and return the
// surface for it. We will arrange to consume the buffers at the right time,
// in addition to releasing codec buffers for rendering.
//
// One may call these multiple times to change between overlay and ST.
//
// Picture buffers will be updated to reflect the new surface during the call
// to UseCodecBufferForPicture().
void InitializeForOverlay();
gl::ScopedJavaSurface InitializeForSurfaceTexture();
void Destroy(const PictureBufferMap& buffers);
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "media/gpu/avda_surface_bundle.h"
#include "media/base/android/android_overlay.h"
namespace media {
......@@ -11,7 +12,8 @@ AVDASurfaceBundle::AVDASurfaceBundle(int surface_id) : surface_id(surface_id) {}
AVDASurfaceBundle::~AVDASurfaceBundle() {
// Explicitly free the surface first, just to be sure that it's deleted before
// the SurfaceTexture is.
surface = gl::ScopedJavaSurface();
surface_texture_surface = gl::ScopedJavaSurface();
// Also release the back buffers. We might want to let the consumer do this
// after it has swapped the back buffer it wants, but we don't.
if (surface_texture)
......
......@@ -6,6 +6,7 @@
#define MEDIA_GPU_AVDA_SURFACE_BUNDLE_H_
#include "base/memory/ref_counted.h"
#include "media/base/android/android_overlay.h"
#include "media/base/surface_manager.h"
#include "ui/gl/android/scoped_java_surface.h"
#include "ui/gl/android/surface_texture.h"
......@@ -27,15 +28,36 @@ class AVDASurfaceBundle : public base::RefCountedThreadSafe<AVDASurfaceBundle> {
public:
explicit AVDASurfaceBundle(int surface_id);
// The surface that MediaCodec is configured to output to. This can be either
// a SurfaceTexture or other Surface provider.
// TODO(liberato): it would be nice if we had an abstraction that included
// SurfaceTexture and Overlay, but we don't right now.
const base::android::JavaRef<jobject>& j_surface() const {
if (overlay)
return overlay->GetJavaSurface();
else
return surface_texture_surface.j_surface();
}
int surface_id = SurfaceManager::kNoSurfaceID;
// The surface onto which the codec is writing.
gl::ScopedJavaSurface surface;
// TODO(liberato): this isn't true if we have an overlay. the overlay keeps
// the java surface.
// gl::ScopedJavaSurface surface;
// If |overlay| is non-null, then |overlay| owns |surface|.
std::unique_ptr<AndroidOverlay> overlay;
// The SurfaceTexture attached to |surface|, or nullptr if |surface| is
// SurfaceView backed.
scoped_refptr<gl::SurfaceTexture> surface_texture;
// If |surface_texture| is not null, then this is the surface for it.
// TODO(liberato): |surface| is the same thing, since overlays own their own
// surfaces anyway.
gl::ScopedJavaSurface surface_texture_surface;
private:
~AVDASurfaceBundle();
friend class base::RefCountedThreadSafe<AVDASurfaceBundle>;
......
// Copyright 2017 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 "media/gpu/content_video_view_overlay.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/threading/thread_task_runner_handle.h"
#include "gpu/ipc/common/gpu_surface_lookup.h"
namespace media {
ContentVideoViewOverlay::ContentVideoViewOverlay(
AVDACodecAllocator* codec_allocator,
int surface_id,
const AndroidOverlay::Config& config)
: codec_allocator_(codec_allocator),
surface_id_(surface_id),
config_(config),
weak_factory_(this) {
if (codec_allocator_->AllocateSurface(this, surface_id_)) {
// We have the surface -- post a callback to our OnSurfaceAvailable.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&ContentVideoViewOverlay::OnSurfaceAvailable,
weak_factory_.GetWeakPtr(), true));
}
}
ContentVideoViewOverlay::~ContentVideoViewOverlay() {
// Deallocate the surface. It's okay if we don't own it.
codec_allocator_->DeallocateSurface(this, surface_id_);
}
void ContentVideoViewOverlay::ScheduleLayout(const gfx::Rect& rect) {
NOTIMPLEMENTED();
}
const base::android::JavaRef<jobject>& ContentVideoViewOverlay::GetJavaSurface()
const {
return surface_.j_surface();
}
void ContentVideoViewOverlay::OnSurfaceAvailable(bool success) {
if (!success) {
// Notify that the surface won't be available.
config_.failed_cb.Run();
// |this| may be deleted.
return;
}
// Get the surface and notify our client.
surface_ =
gpu::GpuSurfaceLookup::GetInstance()->AcquireJavaSurface(surface_id_);
// If no surface was returned, then fail instead.
if (surface_.IsEmpty()) {
config_.failed_cb.Run();
// |this| may be deleted.
return;
}
config_.ready_cb.Run();
}
void ContentVideoViewOverlay::OnSurfaceDestroyed() {
config_.destroyed_cb.Run();
// |this| may be deleted, or deletion might be posted elsewhere.
}
} // namespace media
// Copyright 2017 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 MEDIA_GPU_CONTENT_VIDEO_VIEW_OVERLAY_H_
#define MEDIA_GPU_CONTENT_VIDEO_VIEW_OVERLAY_H_
#include "base/memory/weak_ptr.h"
#include "media/base/android/android_overlay.h"
#include "media/gpu/avda_codec_allocator.h"
#include "ui/gl/android/scoped_java_surface.h"
namespace media {
// TODO(liberato): most of Allocate/DeallocateSurface can be moved here, out
// of AVDACodecAllocator.
class ContentVideoViewOverlay : public AndroidOverlay,
public AVDASurfaceAllocatorClient {
public:
// |config| is ignored except for callbacks. Callbacks will not be called
// before this returns.
ContentVideoViewOverlay(AVDACodecAllocator* codec_allocator,
int surface_id,
const AndroidOverlay::Config& config);
~ContentVideoViewOverlay() override;
// ContentVideoView ignores this, unfortunately.
void ScheduleLayout(const gfx::Rect& rect) override;
const base::android::JavaRef<jobject>& GetJavaSurface() const override;
// AVDASurfaceAllocatorClient
void OnSurfaceAvailable(bool success) override;
void OnSurfaceDestroyed() override;
private:
AVDACodecAllocator* codec_allocator_;
int surface_id_;
AndroidOverlay::Config config_;
gl::ScopedJavaSurface surface_;
base::WeakPtrFactory<ContentVideoViewOverlay> weak_factory_;
};
} // namespace media
#endif // MEDIA_GPU_ANDROID_CONTENT_VIDEO_VIEW_OVERLAY_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment