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

Unified Diff: media/gpu/android_video_decode_accelerator.cc

Issue 2461073002: Use MediaCodec.setOutputSurface() for fullscreen transitions on M. (Closed)
Patch Set: Simplify APIs. Created 4 years, 1 month 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
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.

Powered by Google App Engine
This is Rietveld 408576698