Chromium Code Reviews| 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 ccc9f0b90a657923fe19d20cb65b51a1f26af782..e6528c3bbe4020d87dadbec8f1b55fdfe5e21d0e 100644 |
| --- a/media/gpu/android_video_decode_accelerator.cc |
| +++ b/media/gpu/android_video_decode_accelerator.cc |
| @@ -169,7 +169,7 @@ class AVDAManager { |
| // is assumed to be on the way out, so we fail its allocation request. |
| bool AllocateSurface(int surface_id, AndroidVideoDecodeAccelerator* avda) { |
| // Nobody has to wait for no surface. |
| - if (surface_id == AndroidVideoDecodeAccelerator::Config::kNoSurfaceID) |
| + if (surface_id == SurfaceManager::kNoSurfaceID) |
| return true; |
| auto iter = surface_waiter_map_.find(surface_id); |
| @@ -225,8 +225,7 @@ class AVDAManager { |
| // defer the surface creation until the codec is actually used if we know no |
| // software fallback exists. |
| bool ShouldDeferSurfaceCreation(int surface_id, VideoCodec codec) { |
| - return surface_id == AndroidVideoDecodeAccelerator::Config::kNoSurfaceID && |
| - codec == kCodecH264 && |
| + return surface_id == SurfaceManager::kNoSurfaceID && codec == kCodecH264 && |
| g_avda_codec_allocator.Get().IsAnyRegisteredAVDA() && |
| (base::android::BuildInfo::GetInstance()->sdk_int() <= 18 || |
| base::SysInfo::IsLowEndDevice()); |
| @@ -309,6 +308,7 @@ AndroidVideoDecodeAccelerator::AndroidVideoDecodeAccelerator( |
| get_gles2_decoder_cb_(get_gles2_decoder_cb), |
| state_(NO_ERROR), |
| picturebuffers_requested_(false), |
| + picture_buffer_manager_(this), |
| drain_type_(DRAIN_TYPE_NONE), |
| media_drm_bridge_cdm_context_(nullptr), |
| cdm_registration_id_(0), |
| @@ -318,6 +318,7 @@ AndroidVideoDecodeAccelerator::AndroidVideoDecodeAccelerator( |
| deferred_initialization_pending_(false), |
| codec_needs_reset_(false), |
| defer_surface_creation_(false), |
| + surface_id_(SurfaceManager::kNoSurfaceID), |
| weak_this_factory_(this) {} |
| AndroidVideoDecodeAccelerator::~AndroidVideoDecodeAccelerator() { |
| @@ -396,15 +397,21 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config, |
| return false; |
| } |
| + // If SetSurface() was called before initialize, pick up the surface. |
| + if (pending_surface_id_) { |
| + surface_id_ = pending_surface_id_.value(); |
| + pending_surface_id_.reset(); |
| + } |
| + |
| // If we're low on resources, we may decide to defer creation of the surface |
| // until the codec is actually used. |
| - if (g_avda_manager.Get().ShouldDeferSurfaceCreation(config_.surface_id, |
| + if (g_avda_manager.Get().ShouldDeferSurfaceCreation(surface_id_, |
| codec_config_->codec_)) { |
| DCHECK(!deferred_initialization_pending_); |
| // We should never be here if a SurfaceView is required. |
| - DCHECK_EQ(config_.surface_id, Config::kNoSurfaceID); |
| - DCHECK(g_avda_manager.Get().AllocateSurface(config_.surface_id, this)); |
| + DCHECK_EQ(surface_id_, SurfaceManager::kNoSurfaceID); |
| + DCHECK(g_avda_manager.Get().AllocateSurface(surface_id_, this)); |
| defer_surface_creation_ = true; |
| NotifyInitializationComplete(true); |
| @@ -419,7 +426,7 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config, |
| return false; |
| } |
| - if (g_avda_manager.Get().AllocateSurface(config_.surface_id, this)) { |
| + if (g_avda_manager.Get().AllocateSurface(surface_id_, this)) { |
| // We have successfully owned the surface, so finish initialization now. |
| return InitializePictureBufferManager(); |
| } |
| @@ -445,8 +452,7 @@ bool AndroidVideoDecodeAccelerator::InitializePictureBufferManager() { |
| return false; |
| } |
| - codec_config_->surface_ = |
| - picture_buffer_manager_.Initialize(this, config_.surface_id); |
| + codec_config_->surface_ = picture_buffer_manager_.Initialize(surface_id_); |
| if (codec_config_->surface_.IsEmpty()) |
| return false; |
| @@ -653,6 +659,20 @@ bool AndroidVideoDecodeAccelerator::DequeueOutput() { |
| return false; |
| } |
| + // 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_) { |
| + DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), 23); |
| + if (picture_buffer_manager_.ArePicturesOutstanding()) |
| + return false; |
| + surface_id_ = pending_surface_id_.value(); |
| + codec_config_->surface_ = |
| + picture_buffer_manager_.Initialize(pending_surface_id_.value()); |
| + media_codec_->SetSurface(codec_config_->surface_.j_surface().obj()); |
| + pending_surface_id_.reset(); |
| + } |
| + |
| bool eos = false; |
| base::TimeDelta presentation_timestamp; |
| int32_t buf_index = 0; |
| @@ -1240,6 +1260,16 @@ void AndroidVideoDecodeAccelerator::Reset() { |
| } |
| } |
| +void AndroidVideoDecodeAccelerator::SetSurface(int32_t surface_id) { |
| + if (surface_id == surface_id_) |
| + return; |
| + |
| + // Surface changes never take affect immediately, they will be handled during |
| + // DequeOutput() once we get to a good switch point or immediately during an |
| + // OnDestroyingSurface() call. |
| + pending_surface_id_ = surface_id; |
| +} |
| + |
| void AndroidVideoDecodeAccelerator::Destroy() { |
| DVLOG(1) << __FUNCTION__; |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| @@ -1273,7 +1303,7 @@ void AndroidVideoDecodeAccelerator::ActualDestroy() { |
| // 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. |
| - g_avda_manager.Get().DeallocateSurface(config_.surface_id, this); |
| + g_avda_manager.Get().DeallocateSurface(surface_id_, this); |
| // Note that async codec construction might still be in progress. In that |
| // case, the codec will be deleted when it completes once we invalidate all |
| @@ -1307,9 +1337,35 @@ void AndroidVideoDecodeAccelerator::OnDestroyingSurface(int surface_id) { |
| TRACE_EVENT0("media", "AVDA::OnDestroyingSurface"); |
| DVLOG(1) << __FUNCTION__ << " surface_id: " << surface_id; |
| - if (surface_id != config_.surface_id) |
| + if (surface_id != surface_id_) |
| return; |
| + // If the API is available avoid having to restart the decoder in order to |
| + // leave full screen. 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) { |
| + // 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. |
|
liberato (no reviews please)
2016/11/03 20:51:04
we can almost un-overlay these things in the overl
|
| + picture_buffer_manager_.ReleaseCodecBuffers(output_picture_buffers_); |
| + |
| + // Switch away from the surface being destroyed to a surface texture. |
| + DCHECK_NE(surface_id_, SurfaceManager::kNoSurfaceID); |
| + |
| + // The leaving full screen notification may come in before this point, so |
| + // clear it if necessary. |
| + if (pending_surface_id_) { |
|
liberato (no reviews please)
2016/11/03 20:51:04
if it comes in later, then we might already be usi
DaleCurtis
2016/11/04 01:07:22
This case is already handled in SetSurface and her
|
| + DCHECK_EQ(pending_surface_id_.value(), SurfaceManager::kNoSurfaceID); |
| + pending_surface_id_.reset(); |
| + } |
| + |
| + surface_id_ = SurfaceManager::kNoSurfaceID; |
| + codec_config_->surface_ = |
| + picture_buffer_manager_.Initialize(SurfaceManager::kNoSurfaceID); |
| + if (media_codec_) |
| + media_codec_->SetSurface(codec_config_->surface_.j_surface().obj()); |
| + return; |
| + } |
| + |
| // If we're currently asynchronously configuring a codec, it will be destroyed |
| // when configuration completes and it notices that |state_| has changed to |
| // SURFACE_DESTROYED. |