* Copyright (c) 2022-2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "content/renderer/media/ohos/native_texture_wrapper_impl.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/task/bind_post_task.h"
#include "cc/layers/video_frame_provider.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
namespace {
void OnReleaseVideoFrame(scoped_refptr<content::NativeTextureFactory> factories,
gpu::Mailbox mailbox,
const gpu::SyncToken& sync_token) {
gpu::SharedImageInterface* sii = factories->SharedImageInterface();
sii->DestroySharedImage(sync_token, mailbox);
sii->Flush();
}
}
namespace content {
NativeTextureWrapperImpl::NativeTextureWrapperImpl(
bool enable_texture_copy,
gl::ohos::TextureOwnerMode texture_owner_mode,
scoped_refptr<NativeTextureFactory> factory,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
: enable_texture_copy_(enable_texture_copy),
texture_owner_mode_(texture_owner_mode),
factory_(factory),
main_task_runner_(main_task_runner) {}
NativeTextureWrapperImpl::~NativeTextureWrapperImpl() {
DCHECK(main_task_runner_->BelongsToCurrentThread());
if (native_texture_proxy_)
native_texture_proxy_->ClearCreateVideoFrameCB();
SetCurrentFrameInternal(nullptr);
}
media::ScopedNativeTextureWrapper NativeTextureWrapperImpl::Create(
bool enable_texture_copy,
gl::ohos::TextureOwnerMode texture_owner_mode,
scoped_refptr<NativeTextureFactory> factory,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner) {
return media::ScopedNativeTextureWrapper(new NativeTextureWrapperImpl(
enable_texture_copy, texture_owner_mode, factory, main_task_runner));
}
scoped_refptr<media::VideoFrame> NativeTextureWrapperImpl::GetCurrentFrame() {
base::AutoLock auto_lock(current_frame_lock_);
return current_frame_;
}
void NativeTextureWrapperImpl::CreateVideoFrame(
const gpu::Mailbox& mailbox,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
const absl::optional<gpu::VulkanYCbCrInfo>& ycbcr_info) {
gpu::MailboxHolder holders[media::VideoFrame::kMaxPlanes] = {
gpu::MailboxHolder(mailbox, gpu::SyncToken(), GL_TEXTURE_EXTERNAL_OES)};
gpu::SharedImageInterface* sii = factory_->SharedImageInterface();
sii->NotifyMailboxAdded(mailbox, gpu::SHARED_IMAGE_USAGE_DISPLAY_READ |
gpu::SHARED_IMAGE_USAGE_GLES2 |
gpu::SHARED_IMAGE_USAGE_RASTER);
scoped_refptr<media::VideoFrame> new_frame =
media::VideoFrame::WrapNativeTextures(
media::PIXEL_FORMAT_ABGR, holders,
base::BindPostTask(
main_task_runner_,
base::BindOnce(&OnReleaseVideoFrame, factory_, mailbox)),
coded_size, visible_rect, visible_rect.size(), base::TimeDelta());
new_frame->set_ycbcr_info(ycbcr_info);
if (enable_texture_copy_) {
new_frame->metadata().copy_required = true;
}
SetCurrentFrameInternal(new_frame);
}
void NativeTextureWrapperImpl::ClearCBOnAnyThread() {
if (native_texture_proxy_) {
native_texture_proxy_->ClearReceivedFrameCB();
native_texture_proxy_->ClearDestroyTextureCB();
}
}
void NativeTextureWrapperImpl::SetCurrentFrameInternal(
scoped_refptr<media::VideoFrame> video_frame) {
base::AutoLock auto_lock(current_frame_lock_);
current_frame_ = std::move(video_frame);
}
void NativeTextureWrapperImpl::UpdateTextureSize(const gfx::Size& new_size) {
DVLOG(2) << __func__;
if (!main_task_runner_->BelongsToCurrentThread()) {
main_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&NativeTextureWrapperImpl::UpdateTextureSize,
weak_factory_.GetWeakPtr(), new_size));
return;
}
if (!native_texture_proxy_)
return;
if (rotated_visible_size_ == new_size)
return;
rotated_visible_size_ = new_size;
native_texture_proxy_->UpdateRotatedVisibleSize(rotated_visible_size_);
}
void NativeTextureWrapperImpl::Initialize(
const base::RepeatingClosure& received_frame_cb,
scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
StreamTextureWrapperInitCB init_cb,
CreateSurfaceTextureCB create_texture_cb,
DestroyTextureCB destroy_texture_cb) {
LOG(INFO) << "[NativeEmbed] NativeTextureWrapperImpl::Initialize.";
compositor_task_runner_ = compositor_task_runner;
main_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&NativeTextureWrapperImpl::InitializeOnMainThread,
weak_factory_.GetWeakPtr(), received_frame_cb,
base::BindPostTaskToCurrentDefault(std::move(init_cb)),
base::BindPostTaskToCurrentDefault(std::move(create_texture_cb)),
base::BindPostTaskToCurrentDefault(std::move(destroy_texture_cb))));
}
void NativeTextureWrapperImpl::InitializeOnMainThread(
const base::RepeatingClosure& received_frame_cb,
StreamTextureWrapperInitCB init_cb,
CreateSurfaceTextureCB create_texture_cb,
DestroyTextureCB destroy_texture_cb) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
if (!factory_) {
std::move(init_cb).Run(false);
return;
}
native_texture_proxy_ = factory_->CreateProxy(texture_owner_mode_);
if (!native_texture_proxy_) {
std::move(init_cb).Run(false);
return;
}
native_texture_proxy_->BindToTaskRunner(
received_frame_cb,
base::BindRepeating(&NativeTextureWrapperImpl::CreateVideoFrame,
base::Unretained(this)),
std::move(destroy_texture_cb), compositor_task_runner_);
std::move(init_cb).Run(true);
auto native_embed_id = native_texture_proxy_->current_native_embed_id();
if (native_embed_id != -1) {
LOG(INFO)
<< "[NativeEmbed] Running create_texture_cb(OnCreateSurface) callback.";
std::move(create_texture_cb).Run(native_embed_id);
}
}
void NativeTextureWrapperImpl::Destroy() {
if (!main_task_runner_->BelongsToCurrentThread()) {
main_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&NativeTextureWrapperImpl::Destroy,
base::Unretained(this)));
return;
}
delete this;
}
}