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

Unified Diff: media/gpu/android_video_decode_accelerator.cc

Issue 2692863011: Add ContentVideoViewOverlay to AVDA. (Closed)
Patch Set: keep |overlay| longer in UpdateSurface, comments Created 3 years, 10 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
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 c9ee3d432e6a8f39e7954fcd99542bdfda81761d..b33e2b20bed15d2eed797c9759b9d44a158d2256 100644
--- a/media/gpu/android_video_decode_accelerator.cc
+++ b/media/gpu/android_video_decode_accelerator.cc
@@ -35,6 +35,7 @@
#include "media/base/timestamp_constants.h"
#include "media/base/video_decoder_config.h"
#include "media/gpu/avda_picture_buffer_manager.h"
+#include "media/gpu/content_video_view_overlay.h"
#include "media/gpu/shared_memory_region.h"
#include "media/video/picture.h"
#include "ui/gl/android/scoped_java_surface.h"
@@ -364,6 +365,12 @@ void AndroidVideoDecodeAccelerator::StartSurfaceCreation() {
// We might be called during Initialize, during deferred initialization, or
// afterwards (::Decode, for deferred surface init, UpdateSurface).
+ // Whoever calls us should release any overlay we had.
+ DCHECK(!codec_config_->overlay);
+ // Note that we don't enforce that for any SurfaceTexture or its Surface,
liberato (no reviews please) 2017/02/17 18:34:38 watk: do you agree with this reasoning? i believe
watk 2017/02/17 22:40:36 I don't know to be honest. I'm pretty confused :(
liberato (no reviews please) 2017/03/07 21:30:25 i think that this is now okay, since surface bundl
+ // since there might be a codec that's using them. They'll get cleared
+ // later, in InitializePictureBufferManager.
+
// If surface creation is deferred, then do nothing except signal that init
// is complete, if needed. We might still fail to get a surface or codec,
// which would normally be an init error. Since we're deferring init until a
@@ -377,7 +384,20 @@ void AndroidVideoDecodeAccelerator::StartSurfaceCreation() {
return;
}
- if (!codec_allocator_->AllocateSurface(this, config_.surface_id)) {
+ if (config_.surface_id != SurfaceManager::kNoSurfaceID) {
+ // Create the overlay. Note that it will never call us back immedaitely.
watk 2017/02/17 22:40:36 immediately
liberato (no reviews please) 2017/03/07 21:30:25 Done.
+ // It will post when the surface is available.
+ AndroidOverlay::Config overlay_config;
+ // We use weak ptrs here since |overlay| can outlive us, if we send it for
+ // async codec config.
+ overlay_config.ready_cb =
+ base::Bind(&AndroidVideoDecodeAccelerator::OnSurfaceAvailable,
+ weak_this_factory_.GetWeakPtr());
+ overlay_config.destroyed_cb =
+ base::Bind(&AndroidVideoDecodeAccelerator::OnSurfaceDestroyed,
+ weak_this_factory_.GetWeakPtr());
+ codec_config_->overlay = base::MakeUnique<ContentVideoViewOverlay>(
+ codec_allocator_, config_.surface_id, overlay_config);
// We have to wait for some other AVDA instance to free up the surface.
// OnSurfaceAvailable will be called when it's available.
// Note that if we aren't deferring init, then we'll signal success, and
@@ -387,18 +407,18 @@ void AndroidVideoDecodeAccelerator::StartSurfaceCreation() {
return;
}
- // We now own the surface, so finish initialization.
+ // We're creating a SurfaceTexture.
InitializePictureBufferManager();
}
-void AndroidVideoDecodeAccelerator::OnSurfaceAvailable(bool success) {
+void AndroidVideoDecodeAccelerator::OnSurfaceAvailable() {
DCHECK(!defer_surface_creation_);
DCHECK_EQ(state_, WAITING_FOR_SURFACE);
- if (!success) {
- NOTIFY_ERROR(PLATFORM_FAILURE, "Surface is not available");
- return;
- }
+ // TODO(liberato): We could short-circuit the AndroidOverlay callback to call
watk 2017/02/17 22:40:36 Remove TODO? I don't think we need a comment here
liberato (no reviews please) 2017/03/07 21:30:25 Done.
+ // InitializePictureBufferManager, but it's somewhat clearer this way. We
+ // also get to keep the WAITING_FOR_SURFACE DCHECK, whcih isn't always true
+ // in InitializePictureBufferManager.
InitializePictureBufferManager();
}
@@ -412,21 +432,30 @@ void AndroidVideoDecodeAccelerator::InitializePictureBufferManager() {
return;
}
- codec_config_->surface =
- picture_buffer_manager_.Initialize(config_.surface_id);
- codec_config_->surface_texture = picture_buffer_manager_.surface_texture();
- if (codec_config_->surface.IsEmpty()) {
- NOTIFY_ERROR(PLATFORM_FAILURE, "Codec surface is empty");
- return;
+ // TODO(liberato): it doesn't make sense anymore for the PictureBufferManager
+ // to create the surface texture.
+ if (codec_config_->overlay) {
+ picture_buffer_manager_.InitializeForOverlay();
+ // Note that we might want to do this after SetSurface, or on return, or
liberato (no reviews please) 2017/02/17 18:34:38 hrm, this also exists in the current code. i'm pr
watk 2017/02/17 22:40:36 Yeah +1 to already exists.
liberato (no reviews please) 2017/03/07 21:30:25 surface bundle should fix this.
+ // something like that. There might still be a MediaCodec that's using
+ // them now. Perhaps put them into local vars?
+ codec_config_->surface_texture_surface = gl::ScopedJavaSurface();
+ codec_config_->surface_texture = nullptr;
watk 2017/02/17 22:40:36 This seems broken? Before this change. I think it
liberato (no reviews please) 2017/03/07 21:30:25 it did this before, too. it used to be that AVDA:
+ } else {
+ codec_config_->surface_texture_surface =
+ picture_buffer_manager_.InitializeForSurfaceTexture();
+ codec_config_->surface_texture = picture_buffer_manager_.surface_texture();
}
- // If we have a media codec, then setSurface. If that doesn't work, then we
+ // If we have a media codec, then SetSurface. If that doesn't work, then we
// do not try to allocate a new codec; we might not be at a keyframe, etc.
// If we get here with a codec, then we must setSurface.
if (media_codec_) {
// TODO(liberato): fail on api check?
- if (!media_codec_->SetSurface(codec_config_->surface.j_surface().obj())) {
+ if (!media_codec_->SetSurface(codec_config_->j_surface().obj())) {
NOTIFY_ERROR(PLATFORM_FAILURE, "MediaCodec failed to switch surfaces.");
+ } else {
+ state_ = NO_ERROR;
}
return;
}
@@ -950,7 +979,7 @@ void AndroidVideoDecodeAccelerator::ConfigureMediaCodecAsynchronously() {
codec_allocator_->TaskTypeForAllocation();
if (!task_type) {
// If there is no free thread, then just fail.
- OnCodecConfigured(nullptr);
+ OnCodecConfigured(nullptr, nullptr);
return;
}
@@ -958,7 +987,7 @@ void AndroidVideoDecodeAccelerator::ConfigureMediaCodecAsynchronously() {
// instead of using the software decoders provided by MediaCodec.
if (task_type == TaskType::SW_CODEC &&
IsMediaCodecSoftwareDecodingForbidden()) {
- OnCodecConfigured(nullptr);
+ OnCodecConfigured(nullptr, nullptr);
return;
}
@@ -977,7 +1006,7 @@ void AndroidVideoDecodeAccelerator::ConfigureMediaCodecSynchronously() {
codec_allocator_->TaskTypeForAllocation();
if (!task_type) {
// If there is no free thread, then just fail.
- OnCodecConfigured(nullptr);
+ OnCodecConfigured(nullptr, nullptr);
return;
}
@@ -985,13 +1014,17 @@ void AndroidVideoDecodeAccelerator::ConfigureMediaCodecSynchronously() {
std::unique_ptr<VideoCodecBridge> media_codec =
codec_allocator_->CreateMediaCodecSync(codec_config_);
// Note that |media_codec| might be null, which will NotifyError.
- OnCodecConfigured(std::move(media_codec));
+ OnCodecConfigured(codec_config_, std::move(media_codec));
}
void AndroidVideoDecodeAccelerator::OnCodecConfigured(
+ scoped_refptr<CodecConfig> codec_config,
std::unique_ptr<VideoCodecBridge> media_codec) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(state_ == WAITING_FOR_CODEC || state_ == SURFACE_DESTROYED);
+ // We don't use |codec_config|. It's present only in case the callback
+ // fails, so that |overlay| will be dropped on the right thread if it's the
+ // last reference.
// If we are supposed to notify that initialization is complete, then do so
// before returning. Otherwise, this is a reconfiguration.
@@ -1136,6 +1169,10 @@ void AndroidVideoDecodeAccelerator::ResetCodecState() {
} else {
DVLOG(3) << __func__ << " Deleting the MediaCodec and creating a new one.";
GetManager()->StopTimer(this);
+ // Note that this will release the codec, then allocate a new one. It will
+ // not wait for the old one to finish up with the surface, which is bad.
+ // It works (usually) because it ends up allocating the codec on the same
+ // thread as is used to release the old one, so it's serialized anyway.
ConfigureMediaCodecAsynchronously();
}
}
@@ -1212,9 +1249,8 @@ void AndroidVideoDecodeAccelerator::ActualDestroy() {
GetManager()->StopTimer(this);
ReleaseCodec();
- // 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.
- codec_allocator_->DeallocateSurface(this, config_.surface_id);
+ // If we own |surface_id|, then we'll delete it when |codec_config_| goes
+ // out of scope. That might be after an in-progress async config completes.
// Hop the SurfaceTexture release call through the task runner used last time
// we released a codec. This ensures that we release the surface texture after
@@ -1252,12 +1288,13 @@ void AndroidVideoDecodeAccelerator::OnSurfaceDestroyed() {
TRACE_EVENT0("media", "AVDA::OnSurfaceDestroyed");
DCHECK(thread_checker_.CalledOnValidThread());
- // We cannot get here if we're before surface allocation, since we transition
- // to WAITING_FOR_CODEC (or NO_ERROR, if sync) when we get the surface without
- // posting. If we do ever lose the surface before starting codec allocation,
- // then we could just update the config to use a SurfaceTexture and return
- // without changing state.
- DCHECK_NE(state_, WAITING_FOR_SURFACE);
+ // If we're notified that the overlay is destroyed while we're waiting for a
+ // surface from it, then we could just switch back to SurfaceTexture. For
+ // now, we just fail.
+ if (state_ == WAITING_FOR_SURFACE) {
+ NOTIFY_ERROR(PLATFORM_FAILURE, "Surface is not available");
+ 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
@@ -1558,6 +1595,12 @@ bool AndroidVideoDecodeAccelerator::UpdateSurface() {
// then this must complete synchronously or it will DCHECK. Otherwise, we
// might still be using the destroyed surface. We don't enforce this, but
// it's worth remembering that there are cases where it's required.
+
+ // Regardless of whether we succeed, we will no longer own the previous
+ // surface, if any, when we return. |previous_overlay| will be dropped then.
+ std::unique_ptr<AndroidOverlay> previous_overlay =
+ std::move(codec_config_->overlay);
+
config_.surface_id = new_surface_id;
StartSurfaceCreation();
if (state_ == ERROR) {
@@ -1572,12 +1615,12 @@ bool AndroidVideoDecodeAccelerator::UpdateSurface() {
// happen with SurfaceTexture, and OnSurfaceDestroyed checks for it.
config_.surface_id = previous_surface_id;
ReleaseCodec();
- codec_allocator_->DeallocateSurface(this, new_surface_id);
+ // For CVV, this is the right thing to do, since dropping |overlay| doesn't
+ // really destroy the surface. However, for DS, we'll want to post it in
+ // ReleaseCodec in this case since the codec is still using it.
+ codec_config_->overlay = nullptr;
}
- // Regardless of whether we succeeded, we no longer own the previous surface.
- codec_allocator_->DeallocateSurface(this, previous_surface_id);
-
return state_ != ERROR;
}

Powered by Google App Engine
This is Rietveld 408576698