#include "content/renderer/media/android/stream_texture_factory.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/task/single_thread_task_runner.h"
#include "gpu/ipc/client/client_shared_image_interface.h"
#include "gpu/ipc/client/gpu_channel_host.h"
#include "gpu/ipc/common/gpu_channel.mojom.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
#include "ui/gfx/geometry/size.h"
namespace content {
StreamTextureProxy::StreamTextureProxy(std::unique_ptr<StreamTextureHost> host)
: host_(std::move(host)) {}
StreamTextureProxy::~StreamTextureProxy() {}
void StreamTextureProxy::Release() {
ClearReceivedFrameCB();
ClearCreateVideoFrameCB();
if (!task_runner_.get() || task_runner_->BelongsToCurrentThread() ||
!task_runner_->DeleteSoon(FROM_HERE, this)) {
delete this;
}
}
void StreamTextureProxy::ClearReceivedFrameCB() {
base::AutoLock lock(lock_);
received_frame_cb_.Reset();
}
void StreamTextureProxy::ClearCreateVideoFrameCB() {
base::AutoLock lock(lock_);
create_video_frame_cb_.Reset();
}
void StreamTextureProxy::BindToTaskRunner(
const base::RepeatingClosure& received_frame_cb,
const CreateVideoFrameCB& create_video_frame_cb,
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
DCHECK(task_runner.get());
{
base::AutoLock lock(lock_);
DCHECK(!task_runner_.get() || (task_runner.get() == task_runner_.get()));
task_runner_ = task_runner;
received_frame_cb_ = received_frame_cb;
create_video_frame_cb_ = create_video_frame_cb;
}
if (task_runner->BelongsToCurrentThread()) {
BindOnThread();
return;
}
task_runner->PostTask(FROM_HERE,
base::BindOnce(&StreamTextureProxy::BindOnThread,
base::Unretained(this)));
}
void StreamTextureProxy::BindOnThread() {
host_->BindToCurrentThread(this);
}
void StreamTextureProxy::OnFrameAvailable() {
base::AutoLock lock(lock_);
if (!received_frame_cb_.is_null())
received_frame_cb_.Run();
}
void StreamTextureProxy::OnFrameWithInfoAvailable(
const gpu::Mailbox& mailbox,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
const absl::optional<gpu::VulkanYCbCrInfo>& ycbcr_info) {
base::AutoLock lock(lock_);
if (!create_video_frame_cb_.is_null())
create_video_frame_cb_.Run(mailbox, coded_size, visible_rect, ycbcr_info);
if (!received_frame_cb_.is_null())
received_frame_cb_.Run();
}
void StreamTextureProxy::ForwardStreamTextureForSurfaceRequest(
const base::UnguessableToken& request_token) {
base::AutoLock lock(lock_);
if (!task_runner_)
return;
if (!task_runner_->BelongsToCurrentThread()) {
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&StreamTextureProxy::ForwardStreamTextureForSurfaceRequest,
base::Unretained(this), request_token));
return;
}
host_->ForwardStreamTextureForSurfaceRequest(request_token);
}
void StreamTextureProxy::UpdateRotatedVisibleSize(const gfx::Size& size) {
base::AutoLock lock(lock_);
if (!task_runner_)
return;
if (!task_runner_->BelongsToCurrentThread()) {
task_runner_->PostTask(
FROM_HERE, base::BindOnce(&StreamTextureProxy::UpdateRotatedVisibleSize,
base::Unretained(this), size));
return;
}
host_->UpdateRotatedVisibleSize(size);
}
scoped_refptr<StreamTextureFactory> StreamTextureFactory::Create(
scoped_refptr<gpu::GpuChannelHost> channel) {
return new StreamTextureFactory(std::move(channel));
}
StreamTextureFactory::StreamTextureFactory(
scoped_refptr<gpu::GpuChannelHost> channel)
: channel_(std::move(channel)) {
DCHECK(channel_);
}
StreamTextureFactory::~StreamTextureFactory() = default;
ScopedStreamTextureProxy StreamTextureFactory::CreateProxy() {
int32_t stream_id = channel_->GenerateRouteID();
bool succeeded = false;
mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync;
mojo::PendingAssociatedRemote<gpu::mojom::StreamTexture> remote;
channel_->GetGpuChannel().CreateStreamTexture(
stream_id, remote.InitWithNewEndpointAndPassReceiver(), &succeeded);
if (!succeeded) {
DLOG(ERROR) << "CreateStreamTexture failed";
return ScopedStreamTextureProxy();
}
return ScopedStreamTextureProxy(
new StreamTextureProxy(std::make_unique<StreamTextureHost>(
channel_, stream_id, std::move(remote))));
}
bool StreamTextureFactory::IsLost() const {
return channel_->IsLost();
}
gpu::SharedImageInterface* StreamTextureFactory::SharedImageInterface() {
if (shared_image_interface_)
return shared_image_interface_.get();
shared_image_interface_ = channel_->CreateClientSharedImageInterface();
DCHECK(shared_image_interface_);
return shared_image_interface_.get();
}
}