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

Unified Diff: media/gpu/android_video_decode_accelerator.cc

Issue 2461073002: Use MediaCodec.setOutputSurface() for fullscreen transitions on M. (Closed)
Patch Set: Address comments. 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
« no previous file with comments | « media/gpu/android_video_decode_accelerator.h ('k') | media/gpu/avda_codec_image.h » ('j') | 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 11adbd8189c59bc4f157815a5828ce9f55d11f23..3bec30326f5dc36493da0e8e4ba7865c61b7bc9c 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());
@@ -319,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() {
@@ -397,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);
@@ -420,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();
}
@@ -446,8 +452,7 @@ bool AndroidVideoDecodeAccelerator::InitializePictureBufferManager() {
return false;
}
- codec_config_->surface_ =
- picture_buffer_manager_.Initialize(config_.surface_id);
+ codec_config_->surface_ = picture_buffer_manager_.Initialize(surface_id_);
if (codec_config_->surface_.IsEmpty())
return false;
@@ -654,6 +659,16 @@ 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_) {
+ if (picture_buffer_manager_.HasUnrenderedPictures())
+ return false;
+ if (!UpdateSurface())
+ return false;
+ }
+
bool eos = false;
base::TimeDelta presentation_timestamp;
int32_t buf_index = 0;
@@ -884,10 +899,14 @@ void AndroidVideoDecodeAccelerator::DecodeBuffer(
void AndroidVideoDecodeAccelerator::RequestPictureBuffers() {
if (client_) {
- client_->ProvidePictureBuffers(
- kNumPictureBuffers, PIXEL_FORMAT_UNKNOWN, 1,
- picture_buffer_manager_.GetPictureBufferSize(),
- picture_buffer_manager_.GetTextureTarget());
+ // Allocate a picture buffer that is the actual frame size. Note that it
+ // will be an external texture anyway, so it doesn't allocate an image of
+ // that size. It's important to get the coded size right, so that
+ // VideoLayerImpl doesn't try to scale the texture when building the quad
+ // for it.
+ client_->ProvidePictureBuffers(kNumPictureBuffers, PIXEL_FORMAT_UNKNOWN, 1,
+ size_,
+ AVDAPictureBufferManager::kTextureTarget);
}
}
@@ -907,13 +926,7 @@ void AndroidVideoDecodeAccelerator::AssignPictureBuffers(
<< "Failed to make GL context current for Assign, continuing.";
for (size_t i = 0; i < buffers.size(); ++i) {
- if (buffers[i].size() != picture_buffer_manager_.GetPictureBufferSize()) {
- POST_ERROR(INVALID_ARGUMENT,
- "Invalid picture buffer size assigned. Wanted "
- << size_.ToString() << ", but got "
- << buffers[i].size().ToString());
- return;
- }
+ DCHECK(buffers[i].size() == size_);
int32_t id = buffers[i].id();
output_picture_buffers_.insert(std::make_pair(id, buffers[i]));
free_picture_ids_.push(id);
@@ -1241,6 +1254,18 @@ void AndroidVideoDecodeAccelerator::Reset() {
}
}
+void AndroidVideoDecodeAccelerator::SetSurface(int32_t surface_id) {
+ if (surface_id == surface_id_) {
+ pending_surface_id_.reset();
+ return;
+ }
+
+ // Surface changes never take effect 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());
@@ -1274,7 +1299,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
@@ -1308,8 +1333,28 @@ 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 fullscreen. 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.
+ 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 fullscreen notification may come in before this point.
+ if (pending_surface_id_)
+ DCHECK_EQ(pending_surface_id_.value(), SurfaceManager::kNoSurfaceID);
+
+ pending_surface_id_ = SurfaceManager::kNoSurfaceID;
+ UpdateSurface();
return;
+ }
// If we're currently asynchronously configuring a codec, it will be destroyed
// when configuration completes and it notices that |state_| has changed to
@@ -1584,4 +1629,35 @@ bool AndroidVideoDecodeAccelerator::IsMediaCodecSoftwareDecodingForbidden()
codec_config_->codec_ == kCodecVP9);
}
+bool AndroidVideoDecodeAccelerator::UpdateSurface() {
+ DCHECK(pending_surface_id_);
+ DCHECK_NE(surface_id_, pending_surface_id_.value());
+
+ // Ensure the current context is active when switching surfaces; we may need
+ // to create a new texture.
+ if (!make_context_current_cb_.Run()) {
+ POST_ERROR(PLATFORM_FAILURE,
+ "Failed to make this decoder's GL context current when "
+ "switching surfaces.");
+ return false;
+ }
+
+ surface_id_ = pending_surface_id_.value();
+ codec_config_->surface_ =
+ picture_buffer_manager_.Initialize(pending_surface_id_.value());
+ if (codec_config_->surface_.IsEmpty()) {
+ POST_ERROR(PLATFORM_FAILURE, "An error occurred while switching surfaces.");
+ return false;
+ }
+
+ if (media_codec_ &&
+ !media_codec_->SetSurface(codec_config_->surface_.j_surface().obj())) {
+ POST_ERROR(PLATFORM_FAILURE, "MediaCodec failed to switch surfaces.");
+ return false;
+ }
+
+ pending_surface_id_.reset();
+ return true;
+}
+
} // namespace media
« no previous file with comments | « media/gpu/android_video_decode_accelerator.h ('k') | media/gpu/avda_codec_image.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698