| Index: media/gpu/android_video_decode_accelerator.cc
|
| diff --git a/media/gpu/android_video_decode_accelerator.cc b/media/gpu/android_video_decode_accelerator.cc
|
| index a3a358aec1054ffa05aa7ac33f0db28b9e173150..2f86be36baba65464c0a64a2052e0ba0c1159934 100644
|
| --- a/media/gpu/android_video_decode_accelerator.cc
|
| +++ b/media/gpu/android_video_decode_accelerator.cc
|
| @@ -34,8 +34,10 @@
|
| #include "media/base/media.h"
|
| #include "media/base/timestamp_constants.h"
|
| #include "media/base/video_decoder_config.h"
|
| +#include "media/gpu/avda_overlay_helper_impl.h"
|
| #include "media/gpu/avda_picture_buffer_manager.h"
|
| #include "media/gpu/content_video_view_overlay.h"
|
| +#include "media/gpu/content_video_view_overlay_factory.h"
|
| #include "media/gpu/shared_memory_region.h"
|
| #include "media/video/picture.h"
|
| #include "ui/gl/android/scoped_java_surface.h"
|
| @@ -109,12 +111,15 @@ constexpr base::TimeDelta IdleTimerTimeOut = base::TimeDelta::FromSeconds(1);
|
| // On low end devices (< KitKat is always low-end due to buggy MediaCodec),
|
| // defer the surface creation until the codec is actually used if we know no
|
| // software fallback exists.
|
| -bool ShouldDeferSurfaceCreation(AVDACodecAllocator* codec_allocator,
|
| - int surface_id,
|
| - VideoCodec codec) {
|
| - return surface_id == SurfaceManager::kNoSurfaceID && codec == kCodecH264 &&
|
| - codec_allocator->IsAnyRegisteredAVDA() &&
|
| - base::android::BuildInfo::GetInstance()->sdk_int() <= 18;
|
| +bool ShouldDeferSurfaceCreation(
|
| + AVDACodecAllocator* codec_allocator,
|
| + int surface_id,
|
| + VideoCodec codec,
|
| + const AndroidVideoDecodeAccelerator::PlatformConfig& platform_config) {
|
| + return platform_config.force_deferred_surface_creation ||
|
| + (surface_id == SurfaceManager::kNoSurfaceID && codec == kCodecH264 &&
|
| + codec_allocator->IsAnyRegisteredAVDA() &&
|
| + platform_config.sdk_int <= 18);
|
| }
|
|
|
| } // namespace
|
| @@ -226,13 +231,15 @@ AndroidVideoDecodeAccelerator::BitstreamRecord::~BitstreamRecord() {}
|
|
|
| AndroidVideoDecodeAccelerator::AndroidVideoDecodeAccelerator(
|
| AVDACodecAllocator* codec_allocator,
|
| + std::unique_ptr<AVDAOverlayHelper> overlay_helper,
|
| const MakeGLContextCurrentCallback& make_context_current_cb,
|
| - const GetGLES2DecoderCallback& get_gles2_decoder_cb)
|
| + const GetGLES2DecoderCallback& get_gles2_decoder_cb,
|
| + const PlatformConfig* optional_platform_config)
|
| : client_(nullptr),
|
| codec_allocator_(codec_allocator),
|
| make_context_current_cb_(make_context_current_cb),
|
| get_gles2_decoder_cb_(get_gles2_decoder_cb),
|
| - state_(WAITING_FOR_SURFACE),
|
| + state_(BEFORE_OVERLAY_INIT),
|
| picturebuffers_requested_(false),
|
| picture_buffer_manager_(this),
|
| media_drm_bridge_cdm_context_(nullptr),
|
| @@ -242,7 +249,17 @@ AndroidVideoDecodeAccelerator::AndroidVideoDecodeAccelerator(
|
| deferred_initialization_pending_(false),
|
| codec_needs_reset_(false),
|
| defer_surface_creation_(false),
|
| - weak_this_factory_(this) {}
|
| + overlay_helper_(std::move(overlay_helper)),
|
| + weak_this_factory_(this) {
|
| + if (optional_platform_config) {
|
| + platform_config_ = *optional_platform_config;
|
| + } else {
|
| + platform_config_.sdk_int =
|
| + base::android::BuildInfo::GetInstance()->sdk_int();
|
| + platform_config_.allow_setsurface =
|
| + MediaCodecUtil::IsSetOutputSurfaceSupported();
|
| + }
|
| +}
|
|
|
| AndroidVideoDecodeAccelerator::~AndroidVideoDecodeAccelerator() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| @@ -288,7 +305,6 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config,
|
| codec_config_->codec = VideoCodecProfileToVideoCodec(config.profile);
|
| codec_config_->initial_expected_coded_size =
|
| config.initial_expected_coded_size;
|
| - incoming_bundle_ = new AVDASurfaceBundle(config_.surface_id);
|
|
|
| if (codec_config_->codec != kCodecVP8 && codec_config_->codec != kCodecVP9 &&
|
| #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
|
| @@ -330,10 +346,11 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config,
|
|
|
| // If we're low on resources, we may decide to defer creation of the surface
|
| // until the codec is actually used.
|
| - if (ShouldDeferSurfaceCreation(codec_allocator_, surface_id(),
|
| - codec_config_->codec)) {
|
| + if (ShouldDeferSurfaceCreation(codec_allocator_, config_.surface_id,
|
| + codec_config_->codec, platform_config_)) {
|
| // We should never be here if a SurfaceView is required.
|
| - DCHECK_EQ(surface_id(), SurfaceManager::kNoSurfaceID);
|
| + // TODO(liberato): This really isn't true with AndroidOverlay.
|
| + DCHECK_EQ(config_.surface_id, SurfaceManager::kNoSurfaceID);
|
| defer_surface_creation_ = true;
|
| }
|
|
|
| @@ -352,82 +369,97 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config,
|
| }
|
| InitializeCdm();
|
| } else {
|
| - StartSurfaceCreation();
|
| + StartOverlayHelper();
|
| }
|
|
|
| // Fail / complete / defer initialization.
|
| return state_ != ERROR;
|
| }
|
|
|
| -void AndroidVideoDecodeAccelerator::StartSurfaceCreation() {
|
| - // We might be called during Initialize, during deferred initialization, or
|
| - // 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.
|
| +void AndroidVideoDecodeAccelerator::StartOverlayHelper() {
|
| + DCHECK_EQ(state_, BEFORE_OVERLAY_INIT);
|
|
|
| - // 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
|
| - // decode to save resources, though, we're signaling success now. If we're
|
| - // wrong, then decoding might fail when we might have been able to use a
|
| - // fallback renderer in WMPI if we failed init.
|
| + // If we're trying to defer surface creation, then don't notify the helper
|
| + // that it may start getting surfaces yet. We'll do that later.
|
| if (defer_surface_creation_) {
|
| if (deferred_initialization_pending_)
|
| NotifyInitializationSucceeded();
|
| -
|
| return;
|
| }
|
|
|
| - 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>(
|
| - incoming_bundle_->surface_id, overlay_config);
|
| - // We have to wait for some other AVDA instance to free up the surface.
|
| - // 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;
|
| + // Handle the sync path, which must use SurfaceTexture anyway. Note that we
|
| + // check both |during_initialize_| and |deferred_initialization_pending_|,
|
| + // since we might get here during deferred surface creation. In that case,
|
| + // Decode will call us (after clearing |defer_surface_creation_|), but
|
| + // deferred init will have already been signaled optimistically as success.
|
| + //
|
| + // Also note that we might choose to defer surface creation for the sync path,
|
| + // which won't get here. We'll exit above, successfully, during init, and
|
| + // will fall through to the below when Decode calls us back. That's okay.
|
| + // We only handle this case specially since |overlay_helper_| is allowed to
|
| + // post callbacks to us. Here, we guarantee that the sync case is actually
|
| + // resolved synchronously. The only exception will be if we need to defer
|
| + // surface creation for other reasons, in which case the sync path with just
|
| + // signal success optimistically.
|
| + if (during_initialize_ && !deferred_initialization_pending_) {
|
| + DCHECK_EQ(config_.surface_id, SurfaceManager::kNoSurfaceID);
|
| + OnTransitionToOrFromOverlay(nullptr);
|
| return;
|
| }
|
|
|
| - // We're creating a SurfaceTexture.
|
| - InitializePictureBufferManager();
|
| + // If we have a surface, then notify |overlay_helper_| about it.
|
| + std::unique_ptr<AndroidOverlayFactory> factory;
|
| + if (config_.surface_id != SurfaceManager::kNoSurfaceID) {
|
| + factory =
|
| + base::MakeUnique<ContentVideoViewOverlayFactory>(config_.surface_id);
|
| + }
|
| +
|
| + // Notify |overlay_helper_| that we've started. This guarantees that we'll
|
| + // get a callback. It might not be a synchronous callback, but we're not in
|
| + // the synchronous case. It will be soon, though. For pre-M, we rely on the
|
| + // fact that |overlay_helper_| won't tell us to use a SurfaceTexture while
|
| + // waiting for an overlay to become ready, for example.
|
| + overlay_helper_->Startup(
|
| + base::Bind(&AndroidVideoDecodeAccelerator::OnTransitionToOrFromOverlay,
|
| + GetWeakPtr()),
|
| + base::Bind(&AndroidVideoDecodeAccelerator::OnTransitionToOrFromOverlay,
|
| + GetWeakPtr(), nullptr),
|
| + base::Bind(&AndroidVideoDecodeAccelerator::OnStopUsingOverlayImmediately,
|
| + GetWeakPtr()),
|
| + std::move(factory));
|
| }
|
|
|
| -void AndroidVideoDecodeAccelerator::OnOverlayReady(AndroidOverlay* overlay) {
|
| - DCHECK(!defer_surface_creation_);
|
| - DCHECK_EQ(state_, WAITING_FOR_SURFACE);
|
| - DCHECK(incoming_bundle_);
|
| +void AndroidVideoDecodeAccelerator::OnTransitionToOrFromOverlay(
|
| + std::unique_ptr<AndroidOverlay> overlay) {
|
| + // If we're waiting for a surface (e.g., during startup), then proceed
|
| + // immediately. Otherwise, wait for Dequeue to handle it. This can probably
|
| + // be merged with UpdateSurface.
|
| + if (state_ == BEFORE_OVERLAY_INIT) {
|
| + DCHECK(!incoming_overlay_);
|
| + incoming_bundle_ = new AVDASurfaceBundle(std::move(overlay));
|
| + InitializePictureBufferManager();
|
| + return;
|
| + }
|
|
|
| - InitializePictureBufferManager();
|
| -}
|
| + // If, for some reason, |overlay_helper_| decides that we really should
|
| + // change our output surface pre-M, ignore it. For example, if the
|
| + // compositor tells us that it can't use an overlay, well, there's not much
|
| + // that we can do here unless we start falling forward to keyframes.
|
| + if (!platform_config_.allow_setsurface)
|
| + return;
|
|
|
| -void AndroidVideoDecodeAccelerator::OnOverlayFailed(AndroidOverlay* overlay) {
|
| - NOTIFY_ERROR(PLATFORM_FAILURE, "Surface is not available");
|
| + // If we're using a SurfaceTexture and are told to switch to one, then just
|
| + // do nothing. |overlay_helper_| doesn't really know if we've switched to
|
| + // SurfaceTexture or not. Note that it can't ask us to switch to the same
|
| + // overlay we're using, since it's unique_ptr.
|
| + if (!overlay && codec_config_->surface_bundle &&
|
| + !codec_config_->surface_bundle->overlay) {
|
| + // Also stop transitioning to an overlay, if we were doing so.
|
| + incoming_overlay_.reset();
|
| + return;
|
| + }
|
| +
|
| + incoming_overlay_ = std::move(overlay);
|
| }
|
|
|
| void AndroidVideoDecodeAccelerator::InitializePictureBufferManager() {
|
| @@ -473,7 +505,7 @@ void AndroidVideoDecodeAccelerator::InitializePictureBufferManager() {
|
| } else {
|
| // We've switched surfaces, so replace |surface_bundle|.
|
| codec_config_->surface_bundle = incoming_bundle_;
|
| - // We could be in WAITING_FOR_SURFACE, but we're not anymore.
|
| + // We could be in BEFORE_OVERLAY_INIT, but we're not anymore.
|
| state_ = NO_ERROR;
|
| }
|
| incoming_bundle_ = nullptr;
|
| @@ -498,7 +530,7 @@ void AndroidVideoDecodeAccelerator::InitializePictureBufferManager() {
|
| // Initialize(), and the client must not want deferred init. Note that having
|
| // |deferred_initialization_pending_| false by itself isn't enough; if we're
|
| // deferring surface creation, then we'll finish deferred init before asking
|
| - // for the surface. We'll be called via ::Decode.
|
| + // for the surface. We'll be called via Decode.
|
| if (during_initialize_ && !deferred_initialization_pending_) {
|
| ConfigureMediaCodecSynchronously();
|
| return;
|
| @@ -512,7 +544,7 @@ void AndroidVideoDecodeAccelerator::DoIOTask(bool start_timer) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| TRACE_EVENT0("media", "AVDA::DoIOTask");
|
| if (state_ == ERROR || state_ == WAITING_FOR_CODEC ||
|
| - state_ == SURFACE_DESTROYED || state_ == WAITING_FOR_SURFACE) {
|
| + state_ == SURFACE_DESTROYED || state_ == BEFORE_OVERLAY_INIT) {
|
| return;
|
| }
|
|
|
| @@ -532,7 +564,7 @@ bool AndroidVideoDecodeAccelerator::QueueInput() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| TRACE_EVENT0("media", "AVDA::QueueInput");
|
| if (state_ == ERROR || state_ == WAITING_FOR_CODEC ||
|
| - state_ == WAITING_FOR_KEY || state_ == WAITING_FOR_SURFACE) {
|
| + state_ == WAITING_FOR_KEY || state_ == BEFORE_OVERLAY_INIT) {
|
| return false;
|
| }
|
| if (bitstreams_notified_in_advance_.size() > kMaxBitstreamsNotifiedInAdvance)
|
| @@ -648,7 +680,7 @@ bool AndroidVideoDecodeAccelerator::QueueInput() {
|
| base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| FROM_HERE,
|
| base::Bind(&AndroidVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer,
|
| - weak_this_factory_.GetWeakPtr(), bitstream_buffer.id()));
|
| + GetWeakPtr(), bitstream_buffer.id()));
|
| bitstreams_notified_in_advance_.push_back(bitstream_buffer.id());
|
|
|
| if (status != MEDIA_CODEC_OK) {
|
| @@ -663,7 +695,7 @@ bool AndroidVideoDecodeAccelerator::DequeueOutput() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| TRACE_EVENT0("media", "AVDA::DequeueOutput");
|
| if (state_ == ERROR || state_ == WAITING_FOR_CODEC ||
|
| - state_ == WAITING_FOR_SURFACE) {
|
| + state_ == BEFORE_OVERLAY_INIT) {
|
| return false;
|
| }
|
| // If we're draining for reset or destroy, then we don't need picture buffers
|
| @@ -684,14 +716,14 @@ bool AndroidVideoDecodeAccelerator::DequeueOutput() {
|
| // If we're waiting to switch surfaces pause output release until we have all
|
| // picture buffers returned. This is so we can ensure the right flags are set
|
| // on the picture buffers returned to the client.
|
| - if (pending_surface_id_) {
|
| + if (incoming_overlay_) {
|
| if (picture_buffer_manager_.HasUnrenderedPictures())
|
| return false;
|
| if (!UpdateSurface())
|
| return false;
|
| - // If we can't allocate the incoming surface yet, then stop here.
|
| - if (state_ != NO_ERROR)
|
| - return false;
|
| +
|
| + // UpdateSurface should fail if we've transitioned to the error state.
|
| + DCHECK(state_ == NO_ERROR);
|
| }
|
|
|
| bool eos = false;
|
| @@ -752,7 +784,7 @@ bool AndroidVideoDecodeAccelerator::DequeueOutput() {
|
| base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| FROM_HERE,
|
| base::Bind(&AndroidVideoDecodeAccelerator::RequestPictureBuffers,
|
| - weak_this_factory_.GetWeakPtr()));
|
| + GetWeakPtr()));
|
| return false;
|
| }
|
|
|
| @@ -884,12 +916,11 @@ void AndroidVideoDecodeAccelerator::Decode(
|
|
|
| // If we deferred getting a surface, then start getting one now.
|
| if (defer_surface_creation_) {
|
| - // This is a little strange in that we're not really waiting for a surface
|
| - // yet -- we haven't requested one. We're still in WAITING_FOR_SURFACE as
|
| - // the initial state set during construction.
|
| - DCHECK_EQ(state_, WAITING_FOR_SURFACE);
|
| + // We should still be in BEFORE_OVERLAY_INIT, since we've deferred doing it
|
| + // until now.
|
| + DCHECK_EQ(state_, BEFORE_OVERLAY_INIT);
|
| defer_surface_creation_ = false;
|
| - StartSurfaceCreation();
|
| + StartOverlayHelper();
|
| if (state_ == ERROR) {
|
| DLOG(ERROR) << "Failed deferred surface and MediaCodec initialization.";
|
| return;
|
| @@ -918,7 +949,7 @@ void AndroidVideoDecodeAccelerator::Decode(
|
| base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| FROM_HERE,
|
| base::Bind(&AndroidVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer,
|
| - weak_this_factory_.GetWeakPtr(), bitstream_buffer.id()));
|
| + GetWeakPtr(), bitstream_buffer.id()));
|
| }
|
| }
|
|
|
| @@ -997,12 +1028,11 @@ void AndroidVideoDecodeAccelerator::Flush() {
|
|
|
| void AndroidVideoDecodeAccelerator::ConfigureMediaCodecAsynchronously() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(!media_codec_);
|
|
|
| DCHECK_NE(state_, WAITING_FOR_CODEC);
|
| state_ = WAITING_FOR_CODEC;
|
|
|
| - ReleaseCodec();
|
| -
|
| base::Optional<TaskType> task_type =
|
| codec_allocator_->TaskTypeForAllocation();
|
| if (!task_type) {
|
| @@ -1020,8 +1050,7 @@ void AndroidVideoDecodeAccelerator::ConfigureMediaCodecAsynchronously() {
|
| }
|
|
|
| codec_config_->task_type = task_type.value();
|
| - codec_allocator_->CreateMediaCodecAsync(weak_this_factory_.GetWeakPtr(),
|
| - codec_config_);
|
| + codec_allocator_->CreateMediaCodecAsync(GetWeakPtr(), codec_config_);
|
| }
|
|
|
| void AndroidVideoDecodeAccelerator::ConfigureMediaCodecSynchronously() {
|
| @@ -1040,7 +1069,7 @@ void AndroidVideoDecodeAccelerator::ConfigureMediaCodecSynchronously() {
|
|
|
| codec_config_->task_type = task_type.value();
|
| std::unique_ptr<MediaCodecBridge> media_codec =
|
| - AVDACodecAllocator::GetInstance()->CreateMediaCodecSync(codec_config_);
|
| + codec_allocator_->CreateMediaCodecSync(codec_config_);
|
| // Note that |media_codec| might be null, which will NotifyError.
|
| OnCodecConfigured(std::move(media_codec));
|
| }
|
| @@ -1052,22 +1081,23 @@ void AndroidVideoDecodeAccelerator::OnCodecConfigured(
|
| // If we are supposed to notify that initialization is complete, then do so
|
| // before returning. Otherwise, this is a reconfiguration.
|
|
|
| + DCHECK(!media_codec_);
|
| + media_codec_ = std::move(media_codec);
|
| +
|
| // If |state_| changed to SURFACE_DESTROYED while we were configuring a codec,
|
| // then the codec is already invalid so we return early and drop it.
|
| - // TODO(liberato): We're going to drop the codec when |media_codec| goes out
|
| - // of scope, on this thread. We really should post it to the proper thread
|
| - // to avoid potentially hanging.
|
| if (state_ == SURFACE_DESTROYED) {
|
| if (deferred_initialization_pending_) {
|
| // Losing the output surface is not considered an error state, so notify
|
| - // success. The client will destroy this soon.
|
| + // success. The client will destroy |this| soon.
|
| NotifyInitializationSucceeded();
|
| }
|
| +
|
| + // Post it to the right thread.
|
| + ReleaseCodecAndBundle();
|
| return;
|
| }
|
|
|
| - DCHECK(!media_codec_);
|
| - media_codec_ = std::move(media_codec);
|
| picture_buffer_manager_.CodecChanged(media_codec_.get());
|
| if (!media_codec_) {
|
| NOTIFY_ERROR(PLATFORM_FAILURE, "Failed to create MediaCodec");
|
| @@ -1134,18 +1164,18 @@ void AndroidVideoDecodeAccelerator::OnDrainCompleted() {
|
| ResetCodecState();
|
| base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| FROM_HERE, base::Bind(&AndroidVideoDecodeAccelerator::NotifyFlushDone,
|
| - weak_this_factory_.GetWeakPtr()));
|
| + GetWeakPtr()));
|
| break;
|
| case DRAIN_FOR_RESET:
|
| ResetCodecState();
|
| base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| FROM_HERE, base::Bind(&AndroidVideoDecodeAccelerator::NotifyResetDone,
|
| - weak_this_factory_.GetWeakPtr()));
|
| + GetWeakPtr()));
|
| break;
|
| case DRAIN_FOR_DESTROY:
|
| base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| FROM_HERE, base::Bind(&AndroidVideoDecodeAccelerator::ActualDestroy,
|
| - weak_this_factory_.GetWeakPtr()));
|
| + GetWeakPtr()));
|
| break;
|
| }
|
| drain_type_.reset();
|
| @@ -1157,10 +1187,10 @@ void AndroidVideoDecodeAccelerator::ResetCodecState() {
|
| // If there is already a reset in flight, then that counts. This can really
|
| // only happen if somebody calls Reset.
|
| // If the surface is destroyed or we're in an error state there's nothing to
|
| - // do. Note that WAITING_FOR_SURFACE implies that we have no codec, but it's
|
| + // do. Note that BEFORE_OVERLAY_INIT implies that we have no codec, but it's
|
| // included for completeness.
|
| if (state_ == WAITING_FOR_CODEC || state_ == SURFACE_DESTROYED ||
|
| - state_ == WAITING_FOR_SURFACE || state_ == ERROR || !media_codec_) {
|
| + state_ == BEFORE_OVERLAY_INIT || state_ == ERROR || !media_codec_) {
|
| return;
|
| }
|
|
|
| @@ -1193,10 +1223,11 @@ 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
|
| + // Release the codec, retain the bundle, and allocate a new codec. It will
|
| + // not wait for the old one to finish up with the bundle, 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.
|
| + ReleaseCodec();
|
| ConfigureMediaCodecAsynchronously();
|
| }
|
| }
|
| @@ -1209,10 +1240,10 @@ void AndroidVideoDecodeAccelerator::Reset() {
|
| if (defer_surface_creation_) {
|
| DCHECK(!media_codec_);
|
| DCHECK(pending_bitstream_records_.empty());
|
| - DCHECK_EQ(state_, WAITING_FOR_SURFACE);
|
| + DCHECK_EQ(state_, BEFORE_OVERLAY_INIT);
|
| base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| FROM_HERE, base::Bind(&AndroidVideoDecodeAccelerator::NotifyResetDone,
|
| - weak_this_factory_.GetWeakPtr()));
|
| + GetWeakPtr()));
|
| return;
|
| }
|
|
|
| @@ -1225,7 +1256,7 @@ void AndroidVideoDecodeAccelerator::Reset() {
|
| base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| FROM_HERE,
|
| base::Bind(&AndroidVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer,
|
| - weak_this_factory_.GetWeakPtr(), bitstream_buffer_id));
|
| + GetWeakPtr(), bitstream_buffer_id));
|
| }
|
| }
|
| TRACE_COUNTER1("media", "AVDA::PendingBitstreamBufferCount", 0);
|
| @@ -1239,15 +1270,20 @@ void AndroidVideoDecodeAccelerator::SetSurface(int32_t surface_id) {
|
| DVLOG(1) << __func__;
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| - if (surface_id == this->surface_id()) {
|
| - pending_surface_id_.reset();
|
| + // It's possible that we'll receive a SetSurface before initializing the
|
| + // overlay helper. For example, if we defer surface creation, then we'll
|
| + // signal success to WMPI before initializing it. WMPI is free to change the
|
| + // surface. In this case, just pretend that |surface_id| is the initial one.
|
| + if (state_ == BEFORE_OVERLAY_INIT) {
|
| + config_.surface_id = surface_id;
|
| return;
|
| }
|
|
|
| - // Surface changes never take effect immediately, they will be handled during
|
| - // DequeOutput() once we get to a good switch point or immediately during an
|
| - // OnSurfaceDestroyed() call.
|
| - pending_surface_id_ = surface_id;
|
| + std::unique_ptr<AndroidOverlayFactory> factory;
|
| + if (surface_id != SurfaceManager::kNoSurfaceID)
|
| + factory = base::MakeUnique<ContentVideoViewOverlayFactory>(surface_id);
|
| +
|
| + overlay_helper_->OnOverlayFactory(std::move(factory));
|
| }
|
|
|
| void AndroidVideoDecodeAccelerator::Destroy() {
|
| @@ -1271,7 +1307,7 @@ void AndroidVideoDecodeAccelerator::ActualDestroy() {
|
| // our weak refs.
|
| weak_this_factory_.InvalidateWeakPtrs();
|
| GetManager()->StopTimer(this);
|
| - ReleaseCodec();
|
| + ReleaseCodecAndBundle();
|
|
|
| delete this;
|
| }
|
| @@ -1291,10 +1327,10 @@ AndroidVideoDecodeAccelerator::GetGlDecoder() const {
|
| return get_gles2_decoder_cb_.Run();
|
| }
|
|
|
| -void AndroidVideoDecodeAccelerator::OnSurfaceDestroyed(
|
| +void AndroidVideoDecodeAccelerator::OnStopUsingOverlayImmediately(
|
| AndroidOverlay* overlay) {
|
| DVLOG(1) << __func__;
|
| - TRACE_EVENT0("media", "AVDA::OnSurfaceDestroyed");
|
| + TRACE_EVENT0("media", "AVDA::OnStopUsingOverlayImmediately");
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| // We cannot get here if we're before surface allocation, since we transition
|
| @@ -1302,28 +1338,62 @@ void AndroidVideoDecodeAccelerator::OnSurfaceDestroyed(
|
| // posting. If we do ever lose the surface before starting codec allocation,
|
| // then we could just update the config to use a SurfaceTexture and return
|
| // without changing state.
|
| - DCHECK_NE(state_, WAITING_FOR_SURFACE);
|
| + DCHECK_NE(state_, BEFORE_OVERLAY_INIT);
|
| +
|
| + // If we're transitioning to |overlay|, then just stop here. We're not also
|
| + // using the overlay if we're transitioning to it.
|
| + if (incoming_overlay_ && incoming_overlay_->get() == overlay) {
|
| + incoming_overlay_.reset();
|
| + return;
|
| + }
|
| +
|
| + // If we have no codec, or if our current config doesn't refer to |overlay|,
|
| + // then do nothing. |overlay| might be for some overlay that's waiting for
|
| + // codec destruction on some other thread.
|
| + if (!codec_config_->surface_bundle ||
|
| + codec_config_->surface_bundle->overlay.get() != overlay) {
|
| + return;
|
| + }
|
| +
|
| + // If we have a codec, or if codec allocation is in flight, then it's using an
|
| + // overlay that was destroyed.
|
| + if (state_ == WAITING_FOR_CODEC) {
|
| + // What we should do here is to set |incoming_overlay_| to nullptr, to start
|
| + // a transistion to SurfaceTexture. OnCodecConfigured could notice that
|
| + // there's an incoming overlay, and then immediately transition the codec /
|
| + // drop and re-allocate the codec using it. However, for CVV, that won't
|
| + // work, since CVV-based overlays block the main thread waiting for the
|
| + // overlay to be dropped, so OnCodecConfigured won't run. For DS, it's the
|
| + // right thing.
|
| + // So, for now, we just fail, and let OnCodecConfigured drop the codec.
|
| + // Note that this case really can only happen on pre-M anyway, unless it's
|
| + // during initial construction. This will result in the overlay being
|
| + // destroyed after timeout, since OnCodecConfigured can't run until the
|
| + // synchronous CVV destruction quits.
|
| + state_ = SURFACE_DESTROYED;
|
| + return;
|
| + }
|
|
|
| // If the API is available avoid having to restart the decoder in order to
|
| // leave fullscreen. If we don't clear the surface immediately during this
|
| // callback, the MediaCodec will throw an error as the surface is destroyed.
|
| - if (base::android::BuildInfo::GetInstance()->sdk_int() >= 23) {
|
| + if (platform_config_.allow_setsurface) {
|
| // Since we can't wait for a transition, we must invalidate all outstanding
|
| // picture buffers to avoid putting the GL system in a broken state.
|
| picture_buffer_manager_.ReleaseCodecBuffers(output_picture_buffers_);
|
|
|
| - // Switch away from the surface being destroyed to a surface texture.
|
| - DCHECK_NE(surface_id(), SurfaceManager::kNoSurfaceID);
|
| + // If we aren't transitioning to some other surface, then transition to a
|
| + // SurfaceTexture. Remember that, if |incoming_overlay_| is an overlay,
|
| + // then it's already ready and can be transitioned to immediately. We were
|
| + // just waiting for codec buffers to come back, but we just dropped them.
|
| + // Note that we want |incoming_overlay_| to has_value(), but that value
|
| + // should be a nullptr to indicate that we should switch to SurfaceTexture.
|
| + if (!incoming_overlay_)
|
| + incoming_overlay_ = std::unique_ptr<AndroidOverlay>();
|
|
|
| - // The leaving fullscreen notification may come in before this point.
|
| - if (pending_surface_id_)
|
| - DCHECK_EQ(pending_surface_id_.value(), SurfaceManager::kNoSurfaceID);
|
| -
|
| - pending_surface_id_ = SurfaceManager::kNoSurfaceID;
|
| UpdateSurface();
|
| // Switching to a SurfaceTexture should never need to wait. If it does,
|
| // then the codec might still be using the destroyed surface, which is bad.
|
| - DCHECK_NE(state_, WAITING_FOR_SURFACE);
|
| return;
|
| }
|
|
|
| @@ -1331,7 +1401,7 @@ void AndroidVideoDecodeAccelerator::OnSurfaceDestroyed(
|
| // when configuration completes and it notices that |state_| has changed to
|
| // SURFACE_DESTROYED.
|
| state_ = SURFACE_DESTROYED;
|
| - ReleaseCodec();
|
| + ReleaseCodecAndBundle();
|
|
|
| // If we're draining, signal completion now because the drain can no longer
|
| // proceed.
|
| @@ -1365,14 +1435,14 @@ void AndroidVideoDecodeAccelerator::InitializeCdm() {
|
| // called.
|
| // TODO(xhwang): Remove |cdm_unset_cb| after it's not used on all platforms.
|
| cdm_registration_id_ = media_drm_bridge_cdm_context_->RegisterPlayer(
|
| - BindToCurrentLoop(base::Bind(&AndroidVideoDecodeAccelerator::OnKeyAdded,
|
| - weak_this_factory_.GetWeakPtr())),
|
| + BindToCurrentLoop(
|
| + base::Bind(&AndroidVideoDecodeAccelerator::OnKeyAdded, GetWeakPtr())),
|
| base::Bind(&base::DoNothing));
|
|
|
| // Deferred initialization will continue in OnMediaCryptoReady().
|
| - media_drm_bridge_cdm_context_->SetMediaCryptoReadyCB(BindToCurrentLoop(
|
| - base::Bind(&AndroidVideoDecodeAccelerator::OnMediaCryptoReady,
|
| - weak_this_factory_.GetWeakPtr())));
|
| + media_drm_bridge_cdm_context_->SetMediaCryptoReadyCB(
|
| + BindToCurrentLoop(base::Bind(
|
| + &AndroidVideoDecodeAccelerator::OnMediaCryptoReady, GetWeakPtr())));
|
| #endif // !defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS)
|
| }
|
|
|
| @@ -1400,7 +1470,7 @@ void AndroidVideoDecodeAccelerator::OnMediaCryptoReady(
|
| codec_config_->needs_protected_surface = needs_protected_surface;
|
|
|
| // After receiving |media_crypto_| we can start with surface creation.
|
| - StartSurfaceCreation();
|
| + StartOverlayHelper();
|
| }
|
|
|
| void AndroidVideoDecodeAccelerator::OnKeyAdded() {
|
| @@ -1590,21 +1660,17 @@ bool AndroidVideoDecodeAccelerator::IsMediaCodecSoftwareDecodingForbidden()
|
| }
|
|
|
| bool AndroidVideoDecodeAccelerator::UpdateSurface() {
|
| - DCHECK(pending_surface_id_);
|
| - DCHECK_NE(surface_id(), pending_surface_id_.value());
|
| - DCHECK(surface_id() == SurfaceManager::kNoSurfaceID ||
|
| - pending_surface_id_.value() == SurfaceManager::kNoSurfaceID);
|
| -
|
| - const int new_surface_id = pending_surface_id_.value();
|
| - pending_surface_id_.reset();
|
| + DCHECK(incoming_overlay_);
|
|
|
| // Start surface creation. Note that if we're called via surfaceDestroyed,
|
| // then this must complete synchronously or it will DCHECK. Otherwise, we
|
| // might still be using the destroyed surface. We don't enforce this, but
|
| // it's worth remembering that there are cases where it's required.
|
| // Note that we don't re-use |surface_bundle|, since the codec is using it!
|
| - incoming_bundle_ = new AVDASurfaceBundle(new_surface_id);
|
| - StartSurfaceCreation();
|
| + incoming_bundle_ =
|
| + new AVDASurfaceBundle(std::move(incoming_overlay_.value()));
|
| + incoming_overlay_.reset();
|
| + InitializePictureBufferManager();
|
| if (state_ == ERROR) {
|
| // This might be called from OnSurfaceDestroyed(), so we have to release the
|
| // MediaCodec if we failed to switch the surface. We reset the surface ID
|
| @@ -1613,17 +1679,22 @@ bool AndroidVideoDecodeAccelerator::UpdateSurface() {
|
| // works. If it could fail after getting a codec, then this assumption
|
| // wouldn't be necessarily true anymore.
|
| // Also note that we might not have switched surfaces yet, which is also bad
|
| - // for OnSurfaceDestroyed, because of WAITING_FOR_SURFACE. Shouldn't
|
| + // for OnSurfaceDestroyed, because of BEFORE_OVERLAY_INIT. Shouldn't
|
| // happen with SurfaceTexture, and OnSurfaceDestroyed checks for it. In
|
| // either case, we definitely should not still have an incoming bundle; it
|
| // should have been dropped.
|
| DCHECK(!incoming_bundle_);
|
| - ReleaseCodec();
|
| + ReleaseCodecAndBundle();
|
| }
|
|
|
| return state_ != ERROR;
|
| }
|
|
|
| +base::WeakPtr<AndroidVideoDecodeAccelerator>
|
| +AndroidVideoDecodeAccelerator::GetWeakPtr() {
|
| + return weak_this_factory_.GetWeakPtr();
|
| +}
|
| +
|
| void AndroidVideoDecodeAccelerator::ReleaseCodec() {
|
| if (!media_codec_)
|
| return;
|
| @@ -1634,4 +1705,9 @@ void AndroidVideoDecodeAccelerator::ReleaseCodec() {
|
| codec_config_->surface_bundle);
|
| }
|
|
|
| +void AndroidVideoDecodeAccelerator::ReleaseCodecAndBundle() {
|
| + ReleaseCodec();
|
| + codec_config_->surface_bundle = nullptr;
|
| +}
|
| +
|
| } // namespace media
|
|
|