blob: 643e38309ec0d8bafef71992ddb20c0763621357 [file] [log] [blame]
// 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/android/codec_image_group.h"
#include "base/sequenced_task_runner.h"
#include "media/gpu/android/avda_surface_bundle.h"
namespace media {
CodecImageGroup::CodecImageGroup(
scoped_refptr<base::SequencedTaskRunner> task_runner,
scoped_refptr<AVDASurfaceBundle> surface_bundle)
: surface_bundle_(std::move(surface_bundle)), weak_this_factory_(this) {
// If the surface bundle has an overlay, then register for destruction
// callbacks. We thread-hop to the right thread, which means that we might
// find out about destruction asynchronously. Remember that the wp will be
// cleared on |task_runner|.
if (surface_bundle_->overlay) {
surface_bundle_->overlay->AddSurfaceDestroyedCallback(base::BindOnce(
[](scoped_refptr<base::SequencedTaskRunner> task_runner,
base::OnceCallback<void(AndroidOverlay*)> cb,
AndroidOverlay* overlay) -> void {
task_runner->PostTask(FROM_HERE,
base::BindOnce(std::move(cb), overlay));
},
std::move(task_runner),
base::BindOnce(&CodecImageGroup::OnSurfaceDestroyed,
weak_this_factory_.GetWeakPtr())));
}
// TODO(liberato): if there's no overlay, should we clear |surface_bundle_|?
// be sure not to call SurfaceDestroyed if !surface_bundle_ in that case when
// adding a new image.
}
CodecImageGroup::~CodecImageGroup() {}
void CodecImageGroup::SetDestructionCb(
CodecImage::DestructionCb destruction_cb) {
destruction_cb_ = std::move(destruction_cb);
}
void CodecImageGroup::AddCodecImage(CodecImage* image) {
// If somebody adds an image after the surface has been destroyed, fail the
// image immediately. This can happen due to thread hopping.
if (!surface_bundle_) {
image->ReleaseCodecBuffer();
return;
}
images_.insert(image);
// Bind a strong ref to |this| so that the callback will prevent us from being
// destroyed until the CodecImage is destroyed.
image->SetDestructionCb(
base::BindRepeating(&CodecImageGroup::OnCodecImageDestroyed,
scoped_refptr<CodecImageGroup>(this)));
}
void CodecImageGroup::OnCodecImageDestroyed(CodecImage* image) {
images_.erase(image);
if (destruction_cb_)
destruction_cb_.Run(image);
}
void CodecImageGroup::OnSurfaceDestroyed(AndroidOverlay* overlay) {
// Release any codec buffer, so that the image doesn't try to render to the
// overlay. If it already did, that's fine.
for (CodecImage* image : images_)
image->ReleaseCodecBuffer();
// While this might cause |surface_bundle_| to be deleted, it's okay because
// it's a RefCountedDeleteOnSequence.
surface_bundle_ = nullptr;
}
} // namespace media