Chromium Code Reviews| 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; |
| } |