| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "media/gpu/content_video_view_overlay_allocator.h" |
| |
| #include "media/gpu/avda_codec_allocator.h" |
| |
| namespace media { |
| |
| // static |
| ContentVideoViewOverlayAllocator* |
| ContentVideoViewOverlayAllocator::GetInstance() { |
| static ContentVideoViewOverlayAllocator* allocator = |
| new ContentVideoViewOverlayAllocator(); |
| return allocator; |
| } |
| |
| ContentVideoViewOverlayAllocator::ContentVideoViewOverlayAllocator() |
| : allocator_(AVDACodecAllocator::GetInstance()) {} |
| |
| ContentVideoViewOverlayAllocator::~ContentVideoViewOverlayAllocator() {} |
| |
| bool ContentVideoViewOverlayAllocator::AllocateSurface(Client* client) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| const int32_t surface_id = client->GetSurfaceId(); |
| DVLOG(1) << __func__ << ": " << surface_id; |
| DCHECK_NE(surface_id, SurfaceManager::kNoSurfaceID); |
| |
| // If it's not owned or being released, |client| now owns it. |
| // Note: it's owned until it's released, since AVDACodecAllocator does that. |
| // It keeps the bundle around (and also the overlay that's the current owner) |
| // until the codec is done with it. That's required to use AndroidOverlay. |
| // So, we don't need to check for 'being released'; the owner is good enough. |
| auto it = surface_owners_.find(surface_id); |
| if (it == surface_owners_.end()) { |
| OwnerRecord record; |
| record.owner = client; |
| surface_owners_.insert(OwnerMap::value_type(surface_id, record)); |
| return true; |
| } |
| |
| // Otherwise |client| replaces the previous waiter (if any). |
| OwnerRecord& record = it->second; |
| if (record.waiter) |
| record.waiter->OnSurfaceAvailable(false); |
| record.waiter = client; |
| return false; |
| } |
| |
| void ContentVideoViewOverlayAllocator::DeallocateSurface(Client* client) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| const int32_t surface_id = client->GetSurfaceId(); |
| DCHECK_NE(surface_id, SurfaceManager::kNoSurfaceID); |
| |
| // If we time out waiting for the surface to be destroyed, then we might have |
| // already removed |surface_id|. If it's now trying to deallocate, then |
| // maybe we just weren't patient enough, or mediaserver restarted. |
| auto it = surface_owners_.find(surface_id); |
| if (it == surface_owners_.end()) |
| return; |
| |
| OwnerRecord& record = it->second; |
| if (record.owner == client) |
| record.owner = nullptr; |
| else if (record.waiter == client) |
| record.waiter = nullptr; |
| |
| // Promote the waiter if possible. |
| if (record.waiter && !record.owner) { |
| record.owner = record.waiter; |
| record.waiter = nullptr; |
| record.owner->OnSurfaceAvailable(true); |
| return; |
| } |
| |
| // Remove the record if it's now unused. |
| if (!record.owner && !record.waiter) |
| surface_owners_.erase(it); |
| } |
| |
| // During surface teardown we have to handle the following cases. |
| // 1) No AVDA has acquired the surface, or the surface has already been |
| // completely released. |
| // This case is easy -- there's no owner or waiter, and we can return. |
| // |
| // 2) A MediaCodec is currently being configured with the surface on another |
| // thread. Whether an AVDA owns the surface or has already deallocated it, |
| // the MediaCodec should be dropped when configuration completes. |
| // In this case, we'll find an owner. We'll notify it about the destruction. |
| // Note that AVDA doesn't handle this case correctly right now, since it |
| // doesn't know the state of codec creation on the codec thread. This is |
| // only a problem because CVV has the 'wait on main thread' semantics. |
| // |
| // 3) An AVDA owns the surface and it responds to OnSurfaceDestroyed() by: |
| // a) Replacing the destroyed surface by calling MediaCodec#setSurface(). |
| // b) Releasing the MediaCodec it's attached to. |
| // In case a, the surface will be destroyed during OnSurfaceDestroyed. |
| // In case b, we'll have to wait for the release to complete. |
| // |
| // 4) No AVDA owns the surface, but the MediaCodec it's attached to is currently |
| // being destroyed on another thread. |
| // This is the same as 3b. |
| void ContentVideoViewOverlayAllocator::OnSurfaceDestroyed(int32_t surface_id) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| DVLOG(1) << __func__ << ": " << surface_id; |
| |
| // If it isn't currently owned, then we're done. Rememeber that the overlay |
| // must outlive any user of it (MediaCodec!), and currently AVDACodecAllocator |
| // is responsible for making sure that happens for AVDA. |
| auto it = surface_owners_.find(surface_id); |
| if (it == surface_owners_.end()) |
| return; |
| |
| // Notify the owner and waiter (if any). |
| OwnerRecord& record = it->second; |
| if (record.waiter) { |
| record.waiter->OnSurfaceAvailable(false); |
| record.waiter = nullptr; |
| } |
| |
| DCHECK(record.owner); |
| |
| // |record| could be removed by the callback, if it deallocates the surface. |
| record.owner->OnSurfaceDestroyed(); |
| |
| // If owner deallocated the surface, then we don't need to wait. Note that |
| // the owner might have been deleted in that case. Since CVVOverlay only |
| // deallocates the surface during destruction, it's a safe bet. |
| it = surface_owners_.find(surface_id); |
| if (it == surface_owners_.end()) |
| return; |
| |
| // The surface is still in use, but should have been posted to another thread |
| // for destruction. Note that this isn't technically required for overlays |
| // in general, but CVV requires it. All of the pending release stuff should |
| // be moved here, or to custom deleters of CVVOverlay. However, in the |
| // interest of not changing too much at once, we let AVDACodecAllocator |
| // handle it. Since we're deprecating CVVOverlay anyway, all of this can be |
| // removed eventually. |
| // If the wait fails, then clean up |surface_owners_| anyway, since the codec |
| // release is probably hung up. |
| if (!allocator_->WaitForPendingRelease(record.owner)) |
| surface_owners_.erase(it); |
| } |
| |
| } // namespace media |