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 526146156f8b64b473e3b66fa7f4237cf75d648a..40836c7f2070c8e13d89e9b5ae2a5f48baf5290b 100644 |
--- a/media/gpu/android_video_decode_accelerator.cc |
+++ b/media/gpu/android_video_decode_accelerator.cc |
@@ -249,6 +249,65 @@ class AVDATimerManager { |
return construction_thread_.task_runner(); |
} |
+ // |owner| would like to use |surface_id|. If it is not busy, then mark it |
watk
2016/05/18 20:38:18
No "owner" any more
liberato (no reviews please)
2016/05/18 21:13:13
Done.
|
+ // as busy and return true. If it is busy, then replace any existing waiter, |
+ // make |owner| the current waiter, and return false. Any existing waiter |
+ // is assumed to be on the way out, so we fail its allocation request. |
+ bool AllocateSurface(int surface_id, AndroidVideoDecodeAccelerator* avda) { |
+ SurfaceWaiterMap::iterator iter = surface_waiter_map_.find(surface_id); |
+ |
+ // Nobody has to wait for no surface. |
DaleCurtis
2016/05/18 17:59:11
Move above find?
liberato (no reviews please)
2016/05/18 18:49:39
Done.
|
+ if (surface_id == AndroidVideoDecodeAccelerator::Config::kNoSurfaceID) |
+ return true; |
+ |
+ if (iter == surface_waiter_map_.end()) { |
+ // SurfaceView isn't allocated. Succeed. |
+ surface_waiter_map_[surface_id].owner = avda; |
+ surface_waiter_map_[surface_id].waiter = nullptr; |
+ return true; |
+ } |
+ |
+ // SurfaceView is already allocated. |
+ |
+ if (iter->second.waiter != nullptr) { |
DaleCurtis
2016/05/18 17:59:11
Can you explain this design choice? I.e. why would
liberato (no reviews please)
2016/05/18 18:49:39
because WMPI maintains at most one AVDA instance.
DaleCurtis
2016/05/18 18:55:49
Hmm, what about other WMPI instances?
liberato (no reviews please)
2016/05/18 19:51:18
|surface_id_| will not be the same if the surface
|
+ // Some other AVDA is waiting. |avda| will replace it, so notify it |
+ // that it will fail. |
+ iter->second.waiter->OnSurfaceAvailable(false); |
+ iter->second.waiter = nullptr; |
+ } |
+ |
+ // |avda| is now waiting. |
+ iter->second.waiter = avda; |
+ return false; |
+ } |
+ |
+ // Clear any waiting request for |surface_id| by |avda|. It is okay if |
+ // |waiter| is not waiting and/or isn't the owner of |surface_id|. |
+ void DeallocateSurface(int surface_id, AndroidVideoDecodeAccelerator* avda) { |
+ SurfaceWaiterMap::iterator iter = surface_waiter_map_.find(surface_id); |
+ if (iter == surface_waiter_map_.end()) |
DaleCurtis
2016/05/18 17:59:11
Should this dcheck?
liberato (no reviews please)
2016/05/18 18:49:39
no. this way, one simply calls Deallocate uncondi
|
+ return; |
+ |
+ // If |avda| was waiting, then remove it without OnSurfaceAvailable. |
+ if (iter->second.waiter == avda) |
+ iter->second.waiter = nullptr; |
+ |
+ // If |avda| is the owner, then let the next owner have it. |
+ if (iter->second.owner == avda) { |
DaleCurtis
2016/05/18 17:59:11
Use early returns instead.
liberato (no reviews please)
2016/05/18 18:49:39
Done.
|
+ if (AndroidVideoDecodeAccelerator* waiter = iter->second.waiter) { |
+ // Promote |waiter| to be the owner. |
+ iter->second.owner = waiter; |
+ iter->second.waiter = nullptr; |
+ waiter->OnSurfaceAvailable(true); |
+ } else { |
+ // No waiter -- remove the record and return since |iter| is |
+ // no longer valid. |
+ surface_waiter_map_.erase(iter); |
+ return; |
+ } |
+ } |
+ } |
+ |
private: |
friend struct base::DefaultLazyInstanceTraits<AVDATimerManager>; |
@@ -280,6 +339,15 @@ class AVDATimerManager { |
// All AVDA instances that might like to use the construction thread. |
std::set<AndroidVideoDecodeAccelerator*> thread_avda_instances_; |
+ // [surface id] = accelerator that owns the surface, or nullptr. |
watk
2016/05/18 20:38:18
Comment seems out of date/wrong place
liberato (no reviews please)
2016/05/18 21:13:13
Done.
|
+ struct OwnerRecord { |
+ OwnerRecord() : owner(nullptr), waiter(nullptr) {} |
DaleCurtis
2016/05/18 17:59:11
Constructor prevents this from being a POD type. I
liberato (no reviews please)
2016/05/18 18:49:39
hrm, i just tried brace-or-equal but that doesn't
DaleCurtis
2016/05/18 18:55:49
Dropping the constructor and not using = nullptr o
liberato (no reviews please)
2016/05/18 19:51:17
i switched to "= nullptr" in the most recent CL.
|
+ AndroidVideoDecodeAccelerator* owner; |
+ AndroidVideoDecodeAccelerator* waiter; |
+ }; |
+ using SurfaceWaiterMap = std::map<int, OwnerRecord>; |
+ SurfaceWaiterMap surface_waiter_map_; |
+ |
// Since we can't delete while iterating when using a set, defer erasure until |
// after iteration complete. |
bool timer_running_ = false; |
@@ -318,6 +386,7 @@ AndroidVideoDecodeAccelerator::AndroidVideoDecodeAccelerator( |
error_sequence_token_(0), |
defer_errors_(false), |
deferred_initialization_pending_(false), |
+ cdm_id_(0), |
surface_id_(media::VideoDecodeAccelerator::Config::kNoSurfaceID), |
weak_this_factory_(this) {} |
@@ -359,6 +428,7 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config, |
codec_config_->initial_expected_coded_size_ = |
config.initial_expected_coded_size; |
is_encrypted_ = config.is_encrypted; |
+ cdm_id_ = config.cdm_id; |
// We signalled that we support deferred initialization, so see if the client |
// does also. |
@@ -415,6 +485,33 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config, |
} |
surface_id_ = config.surface_id; |
+ if (g_avda_timer.Pointer()->AllocateSurface(surface_id_, this)) { |
+ // We have succesfully owned the surface, so finish initialization now. |
+ return InitializeStrategy(); |
+ } |
+ |
+ // We have to wait for some other AVDA instance to free up the surface. |
+ // OnSurfaceAvailable will be called when it's available. |
+ return true; |
+} |
+ |
+void AndroidVideoDecodeAccelerator::OnSurfaceAvailable(bool success) { |
+ DCHECK(deferred_initialization_pending_); |
+ |
+ if (!success) { |
+ // Surface isn't available and/or we're being destroyed. |
+ NotifyInitializationComplete(false); |
+ deferred_initialization_pending_ = false; |
+ return; |
+ } |
+ |
+ if (!InitializeStrategy()) { |
watk
2016/05/18 20:38:18
Could merge this block into the above with a || if
liberato (no reviews please)
2016/05/18 21:13:13
Done.
|
+ NotifyInitializationComplete(false); |
+ deferred_initialization_pending_ = false; |
+ } |
+} |
+ |
+bool AndroidVideoDecodeAccelerator::InitializeStrategy() { |
codec_config_->surface_ = strategy_->Initialize(surface_id_); |
if (codec_config_->surface_.IsEmpty()) { |
LOG(ERROR) << "Failed to initialize the backing strategy. The returned " |
@@ -445,7 +542,7 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config, |
// If we are encrypted, then we aren't able to create the codec yet. |
if (is_encrypted_) { |
- InitializeCdm(config.cdm_id); |
+ InitializeCdm(); |
return true; |
} |
@@ -455,7 +552,11 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config, |
} |
// If the client doesn't support deferred initialization (WebRTC), then we |
- // should complete it now and return a meaningful result. |
+ // should complete it now and return a meaningful result. Note that it would |
+ // be nice if we didn't have to worry about starting codec configuration at |
+ // all (::Initialize or the wrapper can do it), but then they have to remember |
+ // not to start codec config if we have to wait for the cdm. It's somewhat |
+ // clearer for us to handle both cases. |
return ConfigureMediaCodecSynchronously(); |
} |
@@ -1204,6 +1305,10 @@ void AndroidVideoDecodeAccelerator::ActualDestroy() { |
on_destroying_surface_cb_); |
} |
+ // 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_timer.Pointer()->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 |
// our weak refs. |
@@ -1296,15 +1401,16 @@ void AndroidVideoDecodeAccelerator::PostError( |
state_ = ERROR; |
} |
-void AndroidVideoDecodeAccelerator::InitializeCdm(int cdm_id) { |
- DVLOG(2) << __FUNCTION__ << ": " << cdm_id; |
+void AndroidVideoDecodeAccelerator::InitializeCdm() { |
+ DVLOG(2) << __FUNCTION__ << ": " << cdm_id_; |
#if !defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) |
NOTIMPLEMENTED(); |
NotifyInitializationComplete(false); |
#else |
// Store the CDM to hold a reference to it. |
- cdm_for_reference_holding_only_ = media::MojoCdmService::LegacyGetCdm(cdm_id); |
+ cdm_for_reference_holding_only_ = |
+ media::MojoCdmService::LegacyGetCdm(cdm_id_); |
DCHECK(cdm_for_reference_holding_only_); |
// On Android platform the CdmContext must be a MediaDrmBridgeCdmContext. |