blob: 34df928ae90f000bbe6ac5421e3a4492ae561e12 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <dxgi1_2.h>
#include "media/base/win/mf_helpers.h"
#include "media/renderers/win/media_foundation_texture_pool.h"
namespace {
using Microsoft::WRL::ComPtr;
// The Texture Count was determined empirically initially having a count of 30
// and running many different video presentations in frame server mode and
// recording the number of textures in use and the count never exceeded 3.
// Therefore for a max of 3 in flight with the 3 being written requires that
// we allocate 4 textures.
constexpr int kTexturePoolCount = 4;
} // namespace
namespace media {
MediaFoundationFrameInfo::MediaFoundationFrameInfo() = default;
MediaFoundationFrameInfo::~MediaFoundationFrameInfo() = default;
MediaFoundationFrameInfo::MediaFoundationFrameInfo(
MediaFoundationFrameInfo&& other) = default;
MediaFoundationTexturePool::TextureInfo::TextureInfo()
: texture_in_use_(false) {}
MediaFoundationTexturePool::TextureInfo::~TextureInfo() = default;
MediaFoundationTexturePool::TextureInfo::TextureInfo(const TextureInfo& other) =
default;
MediaFoundationTexturePool::TextureInfo&
MediaFoundationTexturePool::TextureInfo::operator=(
const MediaFoundationTexturePool::TextureInfo& other) = default;
MediaFoundationTexturePool::MediaFoundationTexturePool() = default;
MediaFoundationTexturePool::~MediaFoundationTexturePool() = default;
// TODO(crbug.com/1278157): The pool should release the textures when the media
// engine is idling to save resources.
HRESULT MediaFoundationTexturePool::Initialize(
ID3D11Device* device,
FramePoolInitializedCallback frame_pool_cb,
const gfx::Size& frame_size) {
D3D11_TEXTURE2D_DESC desc{
static_cast<UINT>(frame_size.width()),
static_cast<UINT>(frame_size.height()),
1,
1,
// TODO(crbug.com/1276134): Need to handle higher bit-depths like HDR.
DXGI_FORMAT_R8G8B8A8_UNORM,
{1, 0},
D3D11_USAGE_DEFAULT,
D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE,
0,
D3D11_RESOURCE_MISC_SHARED_NTHANDLE |
D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX};
std::vector<MediaFoundationFrameInfo> frame_infos;
bool callback_is_valid = !frame_pool_cb.is_null();
if (callback_is_valid) {
frame_infos.reserve(kTexturePoolCount);
}
// We can be reinitialized so remove all the previous textures from our
// pool.
texture_pool_.clear();
for (int i = 0; i < kTexturePoolCount; ++i) {
auto texture_info_element = std::make_unique<TextureInfo>();
auto texture_token = base::UnguessableToken::Create();
ComPtr<ID3D11Texture2D> d3d11_video_frame;
RETURN_IF_FAILED(
device->CreateTexture2D(&desc, nullptr, &d3d11_video_frame));
SetDebugName(d3d11_video_frame.Get(), "Media_MFFrameServerMode_Pool");
ComPtr<IDXGIResource1> d3d11_video_frame_resource;
RETURN_IF_FAILED(d3d11_video_frame.As(&d3d11_video_frame_resource));
HANDLE shared_texture_handle;
RETURN_IF_FAILED(d3d11_video_frame_resource->CreateSharedHandle(
nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE,
nullptr, &shared_texture_handle));
base::win::ScopedHandle scoped_shared_texture_handle;
scoped_shared_texture_handle.Set(shared_texture_handle);
shared_texture_handle = nullptr;
texture_pool_[texture_token].texture_ = std::move(d3d11_video_frame);
texture_pool_[texture_token].texture_in_use_ = false;
if (callback_is_valid) {
MediaFoundationFrameInfo frame_info;
frame_info.dxgi_handle = std::move(scoped_shared_texture_handle);
frame_info.token = texture_token;
frame_infos.emplace_back(std::move(frame_info));
}
}
if (callback_is_valid) {
frame_pool_cb.Run(std::move(frame_infos), frame_size);
}
return S_OK;
}
ComPtr<ID3D11Texture2D> MediaFoundationTexturePool::AcquireTexture(
base::UnguessableToken* texture_token) {
for (auto& texture_item : texture_pool_) {
if (!texture_item.second.texture_in_use_) {
*texture_token = texture_item.first;
texture_item.second.texture_in_use_ = true;
return texture_item.second.texture_;
}
}
return nullptr;
}
void MediaFoundationTexturePool::ReleaseTexture(
const base::UnguessableToken& texture_token) {
auto it = texture_pool_.find(texture_token);
if (it != texture_pool_.end()) {
it->second.texture_in_use_ = false;
}
}
} // namespace media