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. |