| // 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 |