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