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; |
} |