Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(609)

Unified Diff: media/gpu/android_video_decode_accelerator.cc

Issue 1993833002: Serialize usage of SurfaceView between AVDA instances. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: cl feedback. Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/gpu/android_video_decode_accelerator.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..50fe2ebca4ece288bff98a1135b8baa2d94a0966 100644
--- a/media/gpu/android_video_decode_accelerator.cc
+++ b/media/gpu/android_video_decode_accelerator.cc
@@ -249,6 +249,64 @@ class AVDATimerManager {
return construction_thread_.task_runner();
}
+ // |avda| would like to use |surface_id|. If it is not busy, then mark it
+ // as busy and return true. If it is busy, then replace any existing waiter,
+ // make |avda| 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) {
+ // Nobody has to wait for no surface.
+ if (surface_id == AndroidVideoDecodeAccelerator::Config::kNoSurfaceID)
+ return true;
+
+ auto iter = surface_waiter_map_.find(surface_id);
+ if (iter == surface_waiter_map_.end()) {
+ // SurfaceView isn't allocated. Succeed.
+ surface_waiter_map_[surface_id].owner = avda;
+ return true;
+ }
+
+ // SurfaceView is already allocated.
+ if (iter->second.waiter) {
+ // 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())
+ 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 waiter have it.
+ if (iter->second.owner != avda)
+ return;
+
+ AndroidVideoDecodeAccelerator* waiter = iter->second.waiter;
+ if (!waiter) {
+ // No waiter -- remove the record and return explicitly since |iter| is
+ // no longer valid.
+ surface_waiter_map_.erase(iter);
+ return;
+ }
+
+ // Promote |waiter| to be the owner.
+ iter->second.owner = waiter;
+ iter->second.waiter = nullptr;
+ waiter->OnSurfaceAvailable(true);
+ }
+
private:
friend struct base::DefaultLazyInstanceTraits<AVDATimerManager>;
@@ -280,6 +338,14 @@ class AVDATimerManager {
// All AVDA instances that might like to use the construction thread.
std::set<AndroidVideoDecodeAccelerator*> thread_avda_instances_;
+ struct OwnerRecord {
+ AndroidVideoDecodeAccelerator* owner = nullptr;
+ AndroidVideoDecodeAccelerator* waiter = nullptr;
+ };
+ // [surface id] = OwnerRecord for that surface.
+ 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;
@@ -308,7 +374,6 @@ AndroidVideoDecodeAccelerator::AndroidVideoDecodeAccelerator(
: client_(NULL),
make_context_current_cb_(make_context_current_cb),
get_gles2_decoder_cb_(get_gles2_decoder_cb),
- is_encrypted_(false),
state_(NO_ERROR),
picturebuffers_requested_(false),
drain_type_(DRAIN_TYPE_NONE),
@@ -318,7 +383,6 @@ AndroidVideoDecodeAccelerator::AndroidVideoDecodeAccelerator(
error_sequence_token_(0),
defer_errors_(false),
deferred_initialization_pending_(false),
- surface_id_(media::VideoDecodeAccelerator::Config::kNoSurfaceID),
weak_this_factory_(this) {}
AndroidVideoDecodeAccelerator::~AndroidVideoDecodeAccelerator() {
@@ -354,17 +418,17 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config,
DCHECK(client);
client_ = client;
+ config_ = config;
codec_config_ = new CodecConfig();
codec_config_->codec_ = VideoCodecProfileToVideoCodec(config.profile);
codec_config_->initial_expected_coded_size_ =
config.initial_expected_coded_size;
- is_encrypted_ = config.is_encrypted;
// We signalled that we support deferred initialization, so see if the client
// does also.
deferred_initialization_pending_ = config.is_deferred_initialization_allowed;
- if (is_encrypted_ && !deferred_initialization_pending_) {
+ if (config_.is_encrypted && !deferred_initialization_pending_) {
DLOG(ERROR) << "Deferred initialization must be used for encrypted streams";
return false;
}
@@ -380,7 +444,7 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config,
// or if the stream is encrypted.
if ((codec_config_->codec_ == media::kCodecVP8 ||
codec_config_->codec_ == media::kCodecVP9) &&
- !is_encrypted_ &&
+ !config_.is_encrypted &&
media::VideoCodecBridge::IsKnownUnaccelerated(
codec_config_->codec_, media::MEDIA_CODEC_DECODER)) {
DVLOG(1) << "Initialization failed: "
@@ -414,8 +478,27 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config,
return false;
}
- surface_id_ = config.surface_id;
- codec_config_->surface_ = strategy_->Initialize(surface_id_);
+ if (g_avda_timer.Pointer()->AllocateSurface(config_.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 || !InitializeStrategy()) {
+ NotifyInitializationComplete(false);
+ deferred_initialization_pending_ = false;
+ }
+}
+
+bool AndroidVideoDecodeAccelerator::InitializeStrategy() {
+ codec_config_->surface_ = strategy_->Initialize(config_.surface_id);
if (codec_config_->surface_.IsEmpty()) {
LOG(ERROR) << "Failed to initialize the backing strategy. The returned "
"Java surface is empty.";
@@ -444,8 +527,8 @@ 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);
+ if (config_.is_encrypted) {
+ InitializeCdm();
return true;
}
@@ -455,7 +538,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 +1291,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(config_.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.
@@ -1262,7 +1353,7 @@ void AndroidVideoDecodeAccelerator::OnDestroyingSurface(int surface_id) {
TRACE_EVENT0("media", "AVDA::OnDestroyingSurface");
DVLOG(1) << __FUNCTION__ << " surface_id: " << surface_id;
- if (surface_id != surface_id_)
+ if (surface_id != config_.surface_id)
return;
// If we're currently asynchronously configuring a codec, it will be destroyed
@@ -1296,15 +1387,16 @@ void AndroidVideoDecodeAccelerator::PostError(
state_ = ERROR;
}
-void AndroidVideoDecodeAccelerator::InitializeCdm(int cdm_id) {
- DVLOG(2) << __FUNCTION__ << ": " << cdm_id;
+void AndroidVideoDecodeAccelerator::InitializeCdm() {
+ DVLOG(2) << __FUNCTION__ << ": " << config_.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(config_.cdm_id);
DCHECK(cdm_for_reference_holding_only_);
// On Android platform the CdmContext must be a MediaDrmBridgeCdmContext.
« no previous file with comments | « media/gpu/android_video_decode_accelerator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698