1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 07:43:03 +04:00

Merge pull request #21049 from sivanov-work:vpl_dx11_merge

G-API: oneVPL merge DX11 acceleration

* Merge DX11 initial

* Fold conditions row in MACRO in utils

* Inject DeviceSelector

* Turn on DeviceSelector in DX11

* Change sharedLock logic & Move FMT checking in FrameAdapter c-tor

* Move out NumSuggestFrame to configure params

* Drain file source fix

* Fix compilation

* Force zero initializetion of SharedLock

* Fix some compiler warnings

* Fix integer comparison warnings

* Fix integers in sample

* Integrate Demux

* Fix compilation

* Add predefined names for some CfgParam

* Trigger CI

* Fix MultithreadCtx bug, Add Dx11 GetBlobParam(), Get rif of ATL CComPtr

* Fix UT: remove unit test with deprecated video from opencv_extra

* Add creators for most usable CfgParam

* Eliminate some warnings

* Fix warning in GAPI_Assert

* Apply comments

* Add VPL wrapped header with MSVC pragma to get rid of global warning masking
This commit is contained in:
Sergey Ivanov
2021-12-08 10:09:33 +03:00
committed by GitHub
parent 41d108ead6
commit 5c91f5b71d
49 changed files with 3231 additions and 866 deletions
@@ -21,8 +21,100 @@ namespace cv {
namespace gapi {
namespace wip {
namespace onevpl {
namespace utils {
mfxU32 GetSurfaceSize_(mfxU32 FourCC, mfxU32 width, mfxU32 height) {
mfxU32 nbytes = 0;
VPLCPUAccelerationPolicy::VPLCPUAccelerationPolicy() {
mfxU32 half_width = width / 2;
mfxU32 half_height = height / 2;
switch (FourCC) {
case MFX_FOURCC_I420:
case MFX_FOURCC_NV12:
nbytes = width * height + 2 * half_width * half_height;
break;
case MFX_FOURCC_I010:
case MFX_FOURCC_P010:
nbytes = width * height + 2 * half_width * half_height;
nbytes *= 2;
break;
case MFX_FOURCC_RGB4:
nbytes = width * height * 4;
break;
default:
break;
}
return nbytes;
}
surface_ptr_t create_surface_RGB4_(mfxFrameInfo frameInfo,
std::shared_ptr<void> out_buf_ptr,
size_t out_buf_ptr_offset,
size_t out_buf_size)
{
mfxU8* buf = reinterpret_cast<mfxU8*>(out_buf_ptr.get());
mfxU16 surfW = frameInfo.Width * 4;
mfxU16 surfH = frameInfo.Height;
(void)surfH;
// TODO more intelligent check
if (out_buf_size <= out_buf_ptr_offset) {
GAPI_LOG_WARNING(nullptr, "Not enough buffer, ptr: " << out_buf_ptr <<
", size: " << out_buf_size <<
", offset: " << out_buf_ptr_offset <<
", W: " << surfW <<
", H: " << surfH);
GAPI_Assert(false && "Invalid offset");
}
std::unique_ptr<mfxFrameSurface1> handle(new mfxFrameSurface1);
memset(handle.get(), 0, sizeof(mfxFrameSurface1));
handle->Info = frameInfo;
handle->Data.B = buf + out_buf_ptr_offset;
handle->Data.G = handle->Data.B + 1;
handle->Data.R = handle->Data.B + 2;
handle->Data.A = handle->Data.B + 3;
handle->Data.Pitch = surfW;
return Surface::create_surface(std::move(handle), out_buf_ptr);
}
surface_ptr_t create_surface_other_(mfxFrameInfo frameInfo,
std::shared_ptr<void> out_buf_ptr,
size_t out_buf_ptr_offset,
size_t out_buf_size)
{
mfxU8* buf = reinterpret_cast<mfxU8*>(out_buf_ptr.get());
mfxU16 surfH = frameInfo.Height;
mfxU16 surfW = (frameInfo.FourCC == MFX_FOURCC_P010) ? frameInfo.Width * 2 : frameInfo.Width;
// TODO more intelligent check
if (out_buf_size <=
out_buf_ptr_offset + (surfW * surfH) + ((surfW / 2) * (surfH / 2))) {
GAPI_LOG_WARNING(nullptr, "Not enough buffer, ptr: " << out_buf_ptr <<
", size: " << out_buf_size <<
", offset: " << out_buf_ptr_offset <<
", W: " << surfW <<
", H: " << surfH);
GAPI_Assert(false && "Invalid offset");
}
std::unique_ptr<mfxFrameSurface1> handle(new mfxFrameSurface1);
memset(handle.get(), 0, sizeof(mfxFrameSurface1));
handle->Info = frameInfo;
handle->Data.Y = buf + out_buf_ptr_offset;
handle->Data.U = buf + out_buf_ptr_offset + (surfW * surfH);
handle->Data.V = handle->Data.U + ((surfW / 2) * (surfH / 2));
handle->Data.Pitch = surfW;
return Surface::create_surface(std::move(handle), out_buf_ptr);
}
} // namespace utils
VPLCPUAccelerationPolicy::VPLCPUAccelerationPolicy(device_selector_ptr_t selector) :
VPLAccelerationPolicy(selector) {
GAPI_LOG_INFO(nullptr, "created");
}
@@ -117,6 +209,37 @@ VPLCPUAccelerationPolicy::create_surface_pool(size_t pool_size, size_t surface_s
return preallocated_pool_memory_ptr;
}
VPLCPUAccelerationPolicy::pool_key_t
VPLCPUAccelerationPolicy::create_surface_pool(const mfxFrameAllocRequest& alloc_request, mfxVideoParam& param) {
// External (application) allocation of decode surfaces
GAPI_LOG_DEBUG(nullptr, "Query mfxFrameAllocRequest.NumFrameSuggested: " << alloc_request.NumFrameSuggested <<
", mfxFrameAllocRequest.Type: " << alloc_request.Type);
mfxU32 singleSurfaceSize = utils::GetSurfaceSize_(param.mfx.FrameInfo.FourCC,
param.mfx.FrameInfo.Width,
param.mfx.FrameInfo.Height);
if (!singleSurfaceSize) {
throw std::runtime_error("Cannot determine surface size for: fourCC: " +
std::to_string(param.mfx.FrameInfo.FourCC) +
", width: " + std::to_string(param.mfx.FrameInfo.Width) +
", height: " + std::to_string(param.mfx.FrameInfo.Height));
}
const auto &frameInfo = param.mfx.FrameInfo;
auto surface_creator =
[&frameInfo] (std::shared_ptr<void> out_buf_ptr, size_t out_buf_ptr_offset,
size_t out_buf_size) -> surface_ptr_t {
return (frameInfo.FourCC == MFX_FOURCC_RGB4) ?
utils::create_surface_RGB4_(frameInfo, out_buf_ptr, out_buf_ptr_offset,
out_buf_size) :
utils::create_surface_other_(frameInfo, out_buf_ptr, out_buf_ptr_offset,
out_buf_size);};
return create_surface_pool(alloc_request.NumFrameSuggested,
singleSurfaceSize, surface_creator);
}
VPLCPUAccelerationPolicy::surface_weak_ptr_t VPLCPUAccelerationPolicy::get_free_surface(pool_key_t key) {
auto pool_it = pool_table.find(key);
if (pool_it == pool_table.end()) {
@@ -13,7 +13,6 @@
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
#ifdef HAVE_ONEVPL
#include <vpl/mfxvideo.h>
#include "streaming/onevpl/accelerators/accel_policy_interface.hpp"
#include "streaming/onevpl/accelerators/surface/surface_pool.hpp"
@@ -25,14 +24,15 @@ namespace onevpl {
// GAPI_EXPORTS for tests
struct GAPI_EXPORTS VPLCPUAccelerationPolicy final : public VPLAccelerationPolicy
{
VPLCPUAccelerationPolicy();
VPLCPUAccelerationPolicy(device_selector_ptr_t selector);
~VPLCPUAccelerationPolicy();
using pool_t = CachedPool;
void init(session_t session) override;
void deinit(session_t session) override;
pool_key_t create_surface_pool(size_t pool_size, size_t surface_size_bytes, surface_ptr_ctr_t creator) override;
pool_key_t create_surface_pool(size_t pool_size, size_t surface_size_bytes, surface_ptr_ctr_t creator);
pool_key_t create_surface_pool(const mfxFrameAllocRequest& alloc_request, mfxVideoParam& param) override;
surface_weak_ptr_t get_free_surface(pool_key_t key) override;
size_t get_free_surface_count(pool_key_t key) const override;
size_t get_surface_count(pool_key_t key) const override;
@@ -5,8 +5,10 @@
// Copyright (C) 2021 Intel Corporation
#ifdef HAVE_ONEVPL
#include <opencv2/gapi/util/compiler_hints.hpp>
#include "streaming/onevpl/accelerators/accel_policy_dx11.hpp"
#include "streaming/onevpl/accelerators/surface/cpu_frame_adapter.hpp"
#include "streaming/onevpl/accelerators/surface/dx11_frame_adapter.hpp"
#include "streaming/onevpl/accelerators/surface/surface.hpp"
#include "streaming/onevpl/utils.hpp"
#include "logger.hpp"
@@ -30,28 +32,60 @@ namespace gapi {
namespace wip {
namespace onevpl {
VPLDX11AccelerationPolicy::VPLDX11AccelerationPolicy() :
hw_handle(nullptr)
VPLDX11AccelerationPolicy::VPLDX11AccelerationPolicy(device_selector_ptr_t selector) :
VPLAccelerationPolicy(selector),
hw_handle(),
device_context(),
allocator()
{
#ifdef CPU_ACCEL_ADAPTER
adapter.reset(new VPLCPUAccelerationPolicy);
#endif
// setup dx11 device
IDeviceSelector::DeviceScoreTable devices = get_device_selector()->select_devices();
GAPI_Assert(devices.size() == 1 && "Multiple(or zero) acceleration devices case is unsupported");
AccelType accel_type = devices.begin()->second.get_type();
GAPI_Assert(accel_type == AccelType::DX11 &&
"Unexpected device AccelType while is waiting AccelType::DX11");
hw_handle = reinterpret_cast<ID3D11Device*>(devices.begin()->second.get_ptr());
// setup dx11 context
IDeviceSelector::DeviceContexts contexts = get_device_selector()->select_context();
GAPI_Assert(contexts.size() == 1 && "Multiple(or zero) acceleration context case is unsupported");
accel_type = contexts.begin()->get_type();
GAPI_Assert(accel_type == AccelType::DX11 &&
"Unexpected context AccelType while is waiting AccelType::DX11");
device_context = reinterpret_cast<ID3D11DeviceContext*>(contexts.begin()->get_ptr());
// setup dx11 allocator
memset(&allocator, 0, sizeof(mfxFrameAllocator));
allocator.Alloc = alloc_cb;
allocator.Lock = lock_cb;
allocator.Unlock = unlock_cb;
allocator.GetHDL = get_hdl_cb;
allocator.Free = free_cb;
allocator.pthis = this;
}
VPLDX11AccelerationPolicy::~VPLDX11AccelerationPolicy()
{
if (hw_handle)
{
GAPI_LOG_INFO(nullptr, "VPLDX11AccelerationPolicy release ID3D11Device");
hw_handle->Release();
for (auto& allocation_pair : allocation_table) {
allocation_pair.second.reset();
}
GAPI_LOG_INFO(nullptr, "destroyed");
}
void VPLDX11AccelerationPolicy::init(session_t session) {
mfxStatus sts = MFXVideoCORE_GetHandle(session, MFX_HANDLE_D3D11_DEVICE, reinterpret_cast<mfxHDL*>(&hw_handle));
mfxStatus sts = MFXVideoCORE_SetHandle(session, MFX_HANDLE_D3D11_DEVICE,
static_cast<mfxHDL>(hw_handle));
if (sts != MFX_ERR_NONE)
{
throw std::logic_error("Cannot create VPLDX11AccelerationPolicy, MFXVideoCORE_GetHandle error: " +
throw std::logic_error("Cannot create VPLDX11AccelerationPolicy, MFXVideoCORE_SetHandle error: " +
mfxstatus_to_string(sts));
}
sts = MFXVideoCORE_SetFrameAllocator(session, &allocator);
if (sts != MFX_ERR_NONE)
{
throw std::logic_error("Cannot create VPLDX11AccelerationPolicy, MFXVideoCORE_SetFrameAllocator error: " +
mfxstatus_to_string(sts));
}
@@ -63,53 +97,289 @@ void VPLDX11AccelerationPolicy::deinit(session_t session) {
}
VPLDX11AccelerationPolicy::pool_key_t
VPLDX11AccelerationPolicy::create_surface_pool(size_t pool_size, size_t surface_size_bytes,
surface_ptr_ctr_t creator) {
GAPI_LOG_DEBUG(nullptr, "pool size: " << pool_size << ", surface size bytes: " << surface_size_bytes);
VPLDX11AccelerationPolicy::create_surface_pool(const mfxFrameAllocRequest& alloc_req,
mfxVideoParam& param) {
param.IOPattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY;
#ifdef CPU_ACCEL_ADAPTER
return adapter->create_surface_pool(pool_size, surface_size_bytes, creator);
#endif
(void)pool_size;
(void)surface_size_bytes;
(void)creator;
throw std::runtime_error("VPLDX11AccelerationPolicy::create_surface_pool() is not implemented");
// allocate textures by explicit request
mfxFrameAllocResponse mfxResponse;
mfxStatus sts = on_alloc(&alloc_req, &mfxResponse);
if (sts != MFX_ERR_NONE)
{
throw std::logic_error("Cannot create allocated memory for surfaces, error: " +
mfxstatus_to_string(sts));
}
// get reference pointer
auto table_it = allocation_table.find(alloc_req.AllocId);
GAPI_DbgAssert (allocation_table.end() != table_it);
mfxU16 numSurfaces = alloc_req.NumFrameSuggested;
// NB: create pool with numSurfaces reservation
pool_t pool(numSurfaces);
for (int i = 0; i < numSurfaces; i++) {
std::unique_ptr<mfxFrameSurface1> handle(new mfxFrameSurface1 {});
handle->Info = param.mfx.FrameInfo;
handle->Data.MemId = mfxResponse.mids[i];
pool.push_back(Surface::create_surface(std::move(handle), table_it->second));
}
// remember pool by key
pool_key_t key = reinterpret_cast<pool_key_t>(table_it->second.get());
GAPI_LOG_INFO(nullptr, "New pool allocated, key: " << key <<
", surface count: " << pool.total_size());
try {
if (!pool_table.emplace(key, std::move(pool)).second) {
throw std::runtime_error(std::string("VPLDX11AccelerationPolicy::create_surface_pool - ") +
"cannot insert pool, table size: " + std::to_string(pool_table.size()));
}
} catch (const std::exception&) {
throw;
}
return key;
}
VPLDX11AccelerationPolicy::surface_weak_ptr_t VPLDX11AccelerationPolicy::get_free_surface(pool_key_t key)
{
#ifdef CPU_ACCEL_ADAPTER
return adapter->get_free_surface(key);
#endif
(void)key;
throw std::runtime_error("VPLDX11AccelerationPolicy::get_free_surface() is not implemented");
VPLDX11AccelerationPolicy::surface_weak_ptr_t VPLDX11AccelerationPolicy::get_free_surface(pool_key_t key) {
auto pool_it = pool_table.find(key);
if (pool_it == pool_table.end()) {
std::stringstream ss;
ss << "key is not found: " << key << ", table size: " << pool_table.size();
const std::string& str = ss.str();
GAPI_LOG_WARNING(nullptr, str);
throw std::runtime_error(std::string(__FUNCTION__) + " - " + str);
}
pool_t& requested_pool = pool_it->second;
return requested_pool.find_free();
}
size_t VPLDX11AccelerationPolicy::get_free_surface_count(pool_key_t key) const {
#ifdef CPU_ACCEL_ADAPTER
return adapter->get_free_surface_count(key);
#endif
(void)key;
throw std::runtime_error("get_free_surface_count() is not implemented");
size_t VPLDX11AccelerationPolicy::get_free_surface_count(pool_key_t) const {
GAPI_Assert(false && "get_free_surface_count() is not implemented");
}
size_t VPLDX11AccelerationPolicy::get_surface_count(pool_key_t key) const {
#ifdef CPU_ACCEL_ADAPTER
return adapter->get_surface_count(key);
#endif
(void)key;
throw std::runtime_error("VPLDX11AccelerationPolicy::get_surface_count() is not implemented");
size_t VPLDX11AccelerationPolicy::get_surface_count(pool_key_t) const {
GAPI_Assert(false && "VPLDX11AccelerationPolicy::get_surface_count() is not implemented");
}
cv::MediaFrame::AdapterPtr VPLDX11AccelerationPolicy::create_frame_adapter(pool_key_t key,
mfxFrameSurface1* surface) {
auto pool_it = pool_table.find(key);
if (pool_it == pool_table.end()) {
std::stringstream ss;
ss << "key is not found: " << key << ", table size: " << pool_table.size();
const std::string& str = ss.str();
GAPI_LOG_WARNING(nullptr, str);
throw std::runtime_error(std::string(__FUNCTION__) + " - " + str);
}
#ifdef CPU_ACCEL_ADAPTER
return adapter->create_frame_adapter(key, surface);
#endif
(void)key;
(void)surface;
throw std::runtime_error("VPLDX11AccelerationPolicy::create_frame_adapter() is not implemented");
pool_t& requested_pool = pool_it->second;
return cv::MediaFrame::AdapterPtr{new VPLMediaFrameDX11Adapter(requested_pool.find_by_handle(surface))};
}
mfxStatus VPLDX11AccelerationPolicy::alloc_cb(mfxHDL pthis, mfxFrameAllocRequest *request,
mfxFrameAllocResponse *response) {
if (!pthis) {
return MFX_ERR_MEMORY_ALLOC;
}
VPLDX11AccelerationPolicy *self = static_cast<VPLDX11AccelerationPolicy *>(pthis);
return self->on_alloc(request, response);
}
mfxStatus VPLDX11AccelerationPolicy::lock_cb(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr) {
VPLDX11AccelerationPolicy *self = static_cast<VPLDX11AccelerationPolicy *>(pthis);
GAPI_LOG_DEBUG(nullptr, "called from: " << self ? "Policy" : "Resource");
cv::util::suppress_unused_warning(self);
return on_lock(mid, ptr);
}
mfxStatus VPLDX11AccelerationPolicy::unlock_cb(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr) {
VPLDX11AccelerationPolicy *self = static_cast<VPLDX11AccelerationPolicy *>(pthis);
GAPI_LOG_DEBUG(nullptr, "called from: " << self ? "Policy" : "Resource");
cv::util::suppress_unused_warning(self);
return on_unlock(mid, ptr);
}
mfxStatus VPLDX11AccelerationPolicy::get_hdl_cb(mfxHDL pthis, mfxMemId mid, mfxHDL *handle) {
VPLDX11AccelerationPolicy *self = static_cast<VPLDX11AccelerationPolicy *>(pthis);
GAPI_LOG_DEBUG(nullptr, "called from: " << self ? "Policy" : "Resource");
cv::util::suppress_unused_warning(self);
return on_get_hdl(mid, handle);
}
mfxStatus VPLDX11AccelerationPolicy::free_cb(mfxHDL pthis, mfxFrameAllocResponse *response) {
if (!pthis) {
return MFX_ERR_MEMORY_ALLOC;
}
VPLDX11AccelerationPolicy *self = static_cast<VPLDX11AccelerationPolicy *>(pthis);
return self->on_free(response);
}
mfxStatus VPLDX11AccelerationPolicy::on_alloc(const mfxFrameAllocRequest *request,
mfxFrameAllocResponse *response) {
GAPI_LOG_DEBUG(nullptr, "Requested allocation id: " << std::to_string(request->AllocId) <<
", type: " << ext_mem_frame_type_to_cstr(request->Type) <<
", size: " << request->Info.Width << "x" << request->Info.Height <<
", frames minimum count: " << request->NumFrameMin <<
", frames suggested count: " << request->NumFrameSuggested);
auto table_it = allocation_table.find(request->AllocId);
if (allocation_table.end() != table_it) {
GAPI_LOG_WARNING(nullptr, "Allocation already exists, id: " + std::to_string(request->AllocId) +
". Total allocation size: " + std::to_string(allocation_table.size()));
// TODO cache
allocation_t &resources_array = table_it->second;
response->AllocId = request->AllocId;
GAPI_DbgAssert(static_cast<size_t>(std::numeric_limits<mfxU16>::max()) > resources_array->size() &&
"Invalid num frames: overflow");
response->NumFrameActual = static_cast<mfxU16>(resources_array->size());
response->mids = reinterpret_cast<mfxMemId *>(resources_array->data());
return MFX_ERR_NONE;
}
DXGI_FORMAT colorFormat = VPLMediaFrameDX11Adapter::get_dx11_color_format(request->Info.FourCC);
if (DXGI_FORMAT_UNKNOWN == colorFormat || colorFormat != DXGI_FORMAT_NV12) {
GAPI_LOG_WARNING(nullptr, "Unsupported fourcc :" << request->Info.FourCC);
return MFX_ERR_UNSUPPORTED;
}
D3D11_TEXTURE2D_DESC desc = { 0 };
desc.Width = request->Info.Width;
desc.Height = request->Info.Height;
desc.MipLevels = 1;
// single texture with subresources
desc.ArraySize = request->NumFrameSuggested;
desc.Format = colorFormat;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
desc.BindFlags = D3D11_BIND_DECODER;
if (request->Type & MFX_MEMTYPE_SHARED_RESOURCE) {
desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
}
ComPtrGuard<ID3D11Texture2D> main_texture = createCOMPtrGuard<ID3D11Texture2D>();
HRESULT err = S_OK;
{
ID3D11Texture2D *pTexture2D = nullptr;
err = hw_handle->CreateTexture2D(&desc, nullptr, &pTexture2D);
if (FAILED(err)) {
GAPI_LOG_WARNING(nullptr, "Cannot create texture, error: " + std::to_string(HRESULT_CODE(err)));
return MFX_ERR_MEMORY_ALLOC;
}
main_texture.reset(pTexture2D);
}
// create staging texture to read it from
desc.ArraySize = 1;
desc.Usage = D3D11_USAGE_STAGING;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
desc.BindFlags = 0;
desc.MiscFlags = 0;
std::vector<ComPtrGuard<ID3D11Texture2D>> staging_textures;
staging_textures.reserve(request->NumFrameSuggested);
for (int i = 0; i < request->NumFrameSuggested; i++ ) {
ID3D11Texture2D *staging_texture_2d = nullptr;
err = hw_handle->CreateTexture2D(&desc, NULL, &staging_texture_2d);
if (FAILED(err)) {
GAPI_LOG_WARNING(nullptr, "Cannot create staging texture, error: " + std::to_string(HRESULT_CODE(err)));
return MFX_ERR_MEMORY_ALLOC;
}
staging_textures.push_back(createCOMPtrGuard(staging_texture_2d));
}
// for multiple subresources initialize allocation array
auto cand_resource_it = allocation_table.end();
{
// insert into global table
auto inserted_it =
allocation_table.emplace(request->AllocId,
DX11AllocationRecord::create(request->NumFrameSuggested,
device_context,
allocator,
std::move(main_texture),
std::move(staging_textures)));
if (!inserted_it.second) {
GAPI_LOG_WARNING(nullptr, "Cannot assign allocation by id: " + std::to_string(request->AllocId) +
" - aldeady exist. Total allocation size: " + std::to_string(allocation_table.size()));
return MFX_ERR_MEMORY_ALLOC;
}
GAPI_LOG_DEBUG(nullptr, "allocation by id: " << request->AllocId <<
" was created, total allocations count: " << allocation_table.size());
cand_resource_it = inserted_it.first;
}
// fill out response
GAPI_DbgAssert(cand_resource_it != allocation_table.end() && "Invalid cand_resource_it");
allocation_t &resources_array = cand_resource_it->second;
response->AllocId = request->AllocId;
response->NumFrameActual = request->NumFrameSuggested;
response->mids = reinterpret_cast<mfxMemId *>(resources_array->data());
return MFX_ERR_NONE;
}
mfxStatus VPLDX11AccelerationPolicy::on_lock(mfxMemId mid, mfxFrameData *ptr) {
DX11AllocationRecord::AllocationId data = reinterpret_cast<DX11AllocationRecord::AllocationId>(mid);
if (!data) {
GAPI_LOG_WARNING(nullptr, "Allocation record is empty");
return MFX_ERR_LOCK_MEMORY;
}
return data->acquire_access(ptr);
}
mfxStatus VPLDX11AccelerationPolicy::on_unlock(mfxMemId mid, mfxFrameData *ptr) {
DX11AllocationRecord::AllocationId data = reinterpret_cast<DX11AllocationRecord::AllocationId>(mid);
if (!data) {
return MFX_ERR_LOCK_MEMORY;
}
return data->release_access(ptr);
}
mfxStatus VPLDX11AccelerationPolicy::on_get_hdl(mfxMemId mid, mfxHDL *handle) {
DX11AllocationRecord::AllocationId data = reinterpret_cast<DX11AllocationRecord::AllocationId>(mid);
if (!data) {
return MFX_ERR_INVALID_HANDLE;
}
mfxHDLPair *pPair = reinterpret_cast<mfxHDLPair *>(handle);
pPair->first = data->get_texture_ptr();
pPair->second = static_cast<mfxHDL>(reinterpret_cast<DX11AllocationItem::subresource_id_t *>(
static_cast<uint64_t>(data->get_subresource())));
GAPI_LOG_DEBUG(nullptr, "texture : " << pPair->first << ", sub id: " << pPair->second);
return MFX_ERR_NONE;
}
mfxStatus VPLDX11AccelerationPolicy::on_free(mfxFrameAllocResponse *response) {
GAPI_LOG_DEBUG(nullptr, "Allocations count before: " << allocation_table.size() <<
", requested id: " << response->AllocId);
auto table_it = allocation_table.find(response->AllocId);
if (allocation_table.end() == table_it) {
GAPI_LOG_WARNING(nullptr, "Cannot find allocation id: " + std::to_string(response->AllocId) +
". Total allocation size: " + std::to_string(allocation_table.size()));
return MFX_ERR_MEMORY_ALLOC;
}
allocation_table.erase(table_it);
return MFX_ERR_NONE;
}
} // namespace onevpl
} // namespace wip
@@ -6,18 +6,14 @@
#ifndef GAPI_STREAMING_ONEVPL_ACCELERATORS_ACCEL_POLICY_DX11_HPP
#define GAPI_STREAMING_ONEVPL_ACCELERATORS_ACCEL_POLICY_DX11_HPP
#include <map>
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
//TODO Remove the next MACRO right after DX11 implementation
#define CPU_ACCEL_ADAPTER
#ifdef HAVE_ONEVPL
#include <vpl/mfxvideo.h>
#include "streaming/onevpl/accelerators/accel_policy_interface.hpp"
#ifdef CPU_ACCEL_ADAPTER
#include "streaming/onevpl/accelerators/accel_policy_cpu.hpp"
#endif
#include "streaming/onevpl/accelerators/surface/surface_pool.hpp"
#include "streaming/onevpl/accelerators/dx11_alloc_resource.hpp"
#ifdef HAVE_DIRECTX
#ifdef HAVE_D3D11
@@ -39,30 +35,52 @@ namespace onevpl {
struct GAPI_EXPORTS VPLDX11AccelerationPolicy final: public VPLAccelerationPolicy
{
// GAPI_EXPORTS for tests
VPLDX11AccelerationPolicy();
VPLDX11AccelerationPolicy(device_selector_ptr_t selector);
~VPLDX11AccelerationPolicy();
using pool_t = CachedPool;
void init(session_t session) override;
void deinit(session_t session) override;
pool_key_t create_surface_pool(size_t pool_size, size_t surface_size_bytes, surface_ptr_ctr_t creator) override;
pool_key_t create_surface_pool(const mfxFrameAllocRequest& alloc_request,
mfxVideoParam& param) override;
surface_weak_ptr_t get_free_surface(pool_key_t key) override;
size_t get_free_surface_count(pool_key_t key) const override;
size_t get_surface_count(pool_key_t key) const override;
cv::MediaFrame::AdapterPtr create_frame_adapter(pool_key_t key,
mfxFrameSurface1* surface) override;
mfxFrameSurface1* surface) override;
private:
ID3D11Device *hw_handle;
ID3D11DeviceContext* device_context;
#ifdef CPU_ACCEL_ADAPTER
std::unique_ptr<VPLCPUAccelerationPolicy> adapter;
#endif
mfxFrameAllocator allocator;
static mfxStatus MFX_CDECL alloc_cb(mfxHDL pthis,
mfxFrameAllocRequest *request,
mfxFrameAllocResponse *response);
static mfxStatus MFX_CDECL lock_cb(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr);
static mfxStatus MFX_CDECL unlock_cb(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr);
static mfxStatus MFX_CDECL get_hdl_cb(mfxHDL pthis, mfxMemId mid, mfxHDL *handle);
static mfxStatus MFX_CDECL free_cb(mfxHDL pthis, mfxFrameAllocResponse *response);
virtual mfxStatus on_alloc(const mfxFrameAllocRequest *request,
mfxFrameAllocResponse *response);
static mfxStatus on_lock(mfxMemId mid, mfxFrameData *ptr);
static mfxStatus on_unlock(mfxMemId mid, mfxFrameData *ptr);
static mfxStatus on_get_hdl(mfxMemId mid, mfxHDL *handle);
virtual mfxStatus on_free(mfxFrameAllocResponse *response);
using alloc_id_t = mfxU32;
using allocation_t = std::shared_ptr<DX11AllocationRecord>;
std::map<alloc_id_t, allocation_t> allocation_table;
std::map<pool_key_t, pool_t> pool_table;
};
} // namespace onevpl
} // namespace wip
} // namespace gapi
} // namespace cv
#undef NOMINMAX
#endif // HAVE_D3D11
#endif // HAVE_DIRECTX
@@ -12,9 +12,10 @@
#include <type_traits>
#include <opencv2/gapi/media.hpp>
#include <opencv2/gapi/streaming/onevpl/device_selector_interface.hpp>
#ifdef HAVE_ONEVPL
#include <vpl/mfxvideo.h>
#include "streaming/onevpl/onevpl_export.hpp"
namespace cv {
namespace gapi {
@@ -24,7 +25,10 @@ namespace onevpl {
class Surface;
struct VPLAccelerationPolicy
{
virtual ~VPLAccelerationPolicy() {}
using device_selector_ptr_t = std::shared_ptr<IDeviceSelector>;
VPLAccelerationPolicy(device_selector_ptr_t selector) : device_selector(selector) {}
virtual ~VPLAccelerationPolicy() = default;
using pool_key_t = void*;
@@ -36,6 +40,13 @@ struct VPLAccelerationPolicy
size_t out_buf_ptr_offset,
size_t out_buf_ptr_size)>;
device_selector_ptr_t get_device_selector() {
return device_selector;
}
const device_selector_ptr_t get_device_selector() const {
return device_selector;
}
virtual void init(session_t session) = 0;
virtual void deinit(session_t session) = 0;
@@ -43,7 +54,7 @@ struct VPLAccelerationPolicy
// for existing workspace in existing pool (see realloc)
// thus it is not implemented,
// PLEASE provide initial memory area large enough
virtual pool_key_t create_surface_pool(size_t pool_size, size_t surface_size_bytes, surface_ptr_ctr_t creator) = 0;
virtual pool_key_t create_surface_pool(const mfxFrameAllocRequest& alloc_request, mfxVideoParam& param) = 0;
virtual surface_weak_ptr_t get_free_surface(pool_key_t key) = 0;
virtual size_t get_free_surface_count(pool_key_t key) const = 0;
@@ -51,6 +62,8 @@ struct VPLAccelerationPolicy
virtual cv::MediaFrame::AdapterPtr create_frame_adapter(pool_key_t key,
mfxFrameSurface1* surface) = 0;
private:
device_selector_ptr_t device_selector;
};
} // namespace onevpl
} // namespace wip
@@ -0,0 +1,404 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2021 Intel Corporation
#ifdef HAVE_ONEVPL
#include "streaming/onevpl/accelerators/dx11_alloc_resource.hpp"
#include "streaming/onevpl/accelerators/utils/shared_lock.hpp"
#include "logger.hpp"
#ifdef HAVE_DIRECTX
#ifdef HAVE_D3D11
namespace cv {
namespace gapi {
namespace wip {
namespace onevpl {
LockAdapter::LockAdapter(mfxFrameAllocator origin_allocator) :
lockable_allocator(origin_allocator),
impl() {
GAPI_DbgAssert((lockable_allocator.Lock && lockable_allocator.Unlock) &&
"Cannot create LockAdapter for empty origin allocator");
// abandon unusable c-allocator interfaces
// because LockAdapter requires Lock & Unlock only
lockable_allocator.Alloc = nullptr;
lockable_allocator.Free = nullptr;
lockable_allocator.pthis = nullptr;
}
size_t LockAdapter::read_lock(mfxMemId mid, mfxFrameData &data) {
size_t prev_lock_count = 0;
if (impl) {
prev_lock_count = impl->shared_lock();
}
// dispatch to VPL allocator using READ access mode
mfxStatus sts = MFX_ERR_LOCK_MEMORY;
try {
sts = lockable_allocator.Lock(nullptr, mid, &data);
} catch(...) {
}
// adapter will throw error if VPL frame allocator fails
if (sts != MFX_ERR_NONE) {
impl->unlock_shared();
GAPI_Assert(false && "Cannot lock frame on READ using VPL allocator");
}
return prev_lock_count;
}
size_t LockAdapter::unlock_read(mfxMemId mid, mfxFrameData &data) {
GAPI_DbgAssert(!impl || !is_write_acquired() &&
"Reject `unlock_read` in `write_lock` state");
lockable_allocator.Unlock(nullptr, mid, &data);
return impl ? impl->unlock_shared() : 0;
}
void LockAdapter::write_lock(mfxMemId mid, mfxFrameData &data) {
if (impl) {
// TODO consider using `try_lock` in loop with limited iteration count
// to prevent dead-lock with WARN at least notification
impl->lock();
}
// dispatch to VPL allocator using READ access mode
mfxStatus sts = MFX_ERR_LOCK_MEMORY;
try {
sts = lockable_allocator.Lock(nullptr, mid, &data);
} catch(...) {
}
// adapter will throw error if VPL frame allocator fails
if (sts != MFX_ERR_NONE) {
impl->unlock();
GAPI_Assert(false && "Cannot lock frame on WRITE using VPL allocator");
}
}
bool LockAdapter::is_write_acquired() {
if(!impl) return true;
return impl->owns();
}
void LockAdapter::unlock_write(mfxMemId mid, mfxFrameData &data) {
GAPI_DbgAssert(is_write_acquired() &&
"Reject `unlock_write` for unlocked state");
lockable_allocator.Unlock(nullptr, mid, &data);
if (impl) {
impl->unlock();
}
}
SharedLock* LockAdapter::set_adaptee(SharedLock* new_impl) {
SharedLock* old_impl = impl;
impl = new_impl;
return old_impl;
}
SharedLock* LockAdapter::get_adaptee() {
return impl;
}
NativeHandleAdapter::NativeHandleAdapter(mfxFrameAllocator origin_allocator) :
native_handle_getter(origin_allocator) {
GAPI_DbgAssert(native_handle_getter.GetHDL &&
"Cannot create NativeHandleAdapter for empty origin allocator");
// abandon unusable c-allocator interfaces
// because NativeHandleAdapter requires `GetHDL` only
native_handle_getter.Alloc = nullptr;
native_handle_getter.Free = nullptr;
native_handle_getter.Lock = nullptr;
native_handle_getter.Unlock = nullptr;
native_handle_getter.pthis = nullptr;
}
void NativeHandleAdapter::get_handle(mfxMemId mid, mfxHDL& out) {
if (native_handle_getter.GetHDL(nullptr, mid, &out) != MFX_ERR_NONE) {
GAPI_Assert(nullptr && "Cannot get native handle for resourse by mid");
}
}
DX11AllocationItem::DX11AllocationItem(std::weak_ptr<DX11AllocationRecord> parent,
ID3D11DeviceContext* origin_ctx,
mfxFrameAllocator origin_allocator,
ComSharedPtrGuard<ID3D11Texture2D> tex_ptr,
subresource_id_t subtex_id,
ComPtrGuard<ID3D11Texture2D>&& staging_tex_ptr) :
LockAdapter(origin_allocator),
NativeHandleAdapter(origin_allocator),
shared_device_context(origin_ctx),
texture_ptr(tex_ptr),
subresource_id(subtex_id),
staging_texture_ptr(std::move(staging_tex_ptr)),
observer(parent) {
GAPI_DbgAssert(texture_ptr &&
"Cannot create DX11AllocationItem for empty texture");
GAPI_DbgAssert(staging_texture_ptr &&
"Cannot create DX11AllocationItem for empty staging texture");
GAPI_DbgAssert(observer.lock() &&
"Cannot create DX11AllocationItem for empty parent");
shared_device_context->AddRef();
}
DX11AllocationItem::~DX11AllocationItem() {
release();
observer.reset();
if (shared_device_context) {
shared_device_context->Release();
}
}
void DX11AllocationItem::release() {
auto parent = observer.lock();
GAPI_LOG_DEBUG(nullptr, "texture: " << texture_ptr <<
", subresource id: " << subresource_id <<
", parent: " << parent.get());
cv::util::suppress_unused_warning(parent);
}
ID3D11Texture2D* DX11AllocationItem::get_texture_ptr() {
return texture_ptr.get();
}
ID3D11Texture2D* DX11AllocationItem::get_staging_texture_ptr() {
return staging_texture_ptr.get();
}
DX11AllocationItem::subresource_id_t DX11AllocationItem::get_subresource() const {
return subresource_id;
}
ID3D11DeviceContext* DX11AllocationItem::get_device_ctx_ptr() {
return shared_device_context;//shared_device_context.get();
}
void DX11AllocationItem::on_first_in_impl(mfxFrameData *ptr) {
D3D11_MAP mapType = D3D11_MAP_READ;
UINT mapFlags = D3D11_MAP_FLAG_DO_NOT_WAIT;
shared_device_context->CopySubresourceRegion(get_staging_texture_ptr(), 0,
0, 0, 0,
get_texture_ptr(),
get_subresource(),
nullptr);
HRESULT err = S_OK;
D3D11_MAPPED_SUBRESOURCE lockedRect {};
do {
err = shared_device_context->Map(get_staging_texture_ptr(), 0, mapType, mapFlags, &lockedRect);
if (S_OK != err && DXGI_ERROR_WAS_STILL_DRAWING != err) {
GAPI_LOG_WARNING(nullptr, "Cannot Map staging texture in device context, error: " << std::to_string(HRESULT_CODE(err)));
GAPI_Assert(false && "Cannot Map staging texture in device context");
}
} while (DXGI_ERROR_WAS_STILL_DRAWING == err);
if (FAILED(err)) {
GAPI_LOG_WARNING(nullptr, "Cannot lock frame");
GAPI_Assert(false && "Cannot lock frame");
return ;
}
D3D11_TEXTURE2D_DESC desc {};
get_texture_ptr()->GetDesc(&desc);
switch (desc.Format) {
case DXGI_FORMAT_NV12:
ptr->Pitch = (mfxU16)lockedRect.RowPitch;
ptr->Y = (mfxU8 *)lockedRect.pData;
ptr->UV = (mfxU8 *)lockedRect.pData + desc.Height * lockedRect.RowPitch;
GAPI_Assert(ptr->Y && ptr->UV && "DXGI_FORMAT_NV12 locked frame data is nullptr");
break;
default:
GAPI_LOG_WARNING(nullptr, "Unknown DXGI format: " << desc.Format);
return;
}
}
void DX11AllocationItem::on_last_out_impl(mfxFrameData *ptr) {
shared_device_context->Unmap(get_staging_texture_ptr(), 0);
if (ptr) {
ptr->Pitch = 0;
ptr->U = ptr->V = ptr->Y = 0;
ptr->A = ptr->R = ptr->G = ptr->B = 0;
}
}
mfxStatus DX11AllocationItem::acquire_access(mfxFrameData *ptr) {
if (is_write_acquired()) {
return exclusive_access_acquire_unsafe(ptr);
}
return shared_access_acquire_unsafe(ptr);
}
mfxStatus DX11AllocationItem::release_access(mfxFrameData *ptr) {
if (is_write_acquired()) {
return exclusive_access_release_unsafe(ptr);
}
return shared_access_release_unsafe(ptr);
}
mfxStatus DX11AllocationItem::shared_access_acquire_unsafe(mfxFrameData *ptr) {
GAPI_LOG_DEBUG(nullptr, "acquire READ lock: " << this);
GAPI_LOG_DEBUG(nullptr, "texture: " << get_texture_ptr() <<
", sub id: " << get_subresource());
// shared access requires elastic barrier
// first-in visited thread uses resource mapping on host memory
// subsequent threads reuses mapped memory
//
// exclusive access is prohibited while any one shared access has been obtained
visit_in(ptr);
if (!(ptr->Y && (ptr->UV || (ptr->U && ptr->V)))) {
GAPI_LOG_WARNING(nullptr, "No any data obtained: " << this);
return MFX_ERR_LOCK_MEMORY;
}
GAPI_LOG_DEBUG(nullptr, "READ access granted: " << this);
return MFX_ERR_NONE;
}
mfxStatus DX11AllocationItem::shared_access_release_unsafe(mfxFrameData *ptr) {
GAPI_LOG_DEBUG(nullptr, "releasing READ lock: " << this);
GAPI_LOG_DEBUG(nullptr, "texture: " << get_texture_ptr() <<
", sub id: " << get_subresource());
// releasing shared access requires elastic barrier
// last-out thread must make memory unmapping then and only then no more
// read access is coming. If another read-access goes into critical section
// (or waiting for acees) we must drop off unmapping procedure
visit_out(ptr);
GAPI_LOG_DEBUG(nullptr, "access on READ released: " << this);
return MFX_ERR_NONE;
}
mfxStatus DX11AllocationItem::exclusive_access_acquire_unsafe(mfxFrameData *ptr) {
GAPI_LOG_DEBUG(nullptr, "acquire WRITE lock: " << this);
GAPI_LOG_DEBUG(nullptr, "texture: " << get_texture_ptr() <<
", sub id: " << get_subresource());
D3D11_MAP mapType = D3D11_MAP_WRITE;
UINT mapFlags = D3D11_MAP_FLAG_DO_NOT_WAIT;
HRESULT err = S_OK;
D3D11_MAPPED_SUBRESOURCE lockedRect {};
do {
err = get_device_ctx_ptr()->Map(get_staging_texture_ptr(), 0, mapType, mapFlags, &lockedRect);
if (S_OK != err && DXGI_ERROR_WAS_STILL_DRAWING != err) {
GAPI_LOG_WARNING(nullptr, "Cannot Map staging texture in device context, error: " << std::to_string(HRESULT_CODE(err)));
return MFX_ERR_LOCK_MEMORY;
}
} while (DXGI_ERROR_WAS_STILL_DRAWING == err);
if (FAILED(err)) {
GAPI_LOG_WARNING(nullptr, "Cannot lock frame");
return MFX_ERR_LOCK_MEMORY;
}
D3D11_TEXTURE2D_DESC desc {};
get_texture_ptr()->GetDesc(&desc);
switch (desc.Format) {
case DXGI_FORMAT_NV12:
ptr->Pitch = (mfxU16)lockedRect.RowPitch;
ptr->Y = (mfxU8 *)lockedRect.pData;
ptr->UV = (mfxU8 *)lockedRect.pData + desc.Height * lockedRect.RowPitch;
if (!ptr->Y || !ptr->UV) {
GAPI_LOG_WARNING(nullptr, "DXGI_FORMAT_NV12 locked frame data is nullptr");
return MFX_ERR_LOCK_MEMORY;
}
break;
default:
GAPI_LOG_WARNING(nullptr, "Unknown DXGI format: " << desc.Format);
return MFX_ERR_LOCK_MEMORY;
}
GAPI_LOG_DEBUG(nullptr, "WRITE access granted: " << this);
return MFX_ERR_NONE;
}
mfxStatus DX11AllocationItem::exclusive_access_release_unsafe(mfxFrameData *ptr) {
GAPI_LOG_DEBUG(nullptr, "releasing WRITE lock: " << this);
GAPI_LOG_DEBUG(nullptr, "texture: " << get_texture_ptr() <<
", sub id: " << get_subresource());
get_device_ctx_ptr()->Unmap(get_staging_texture_ptr(), 0);
get_device_ctx_ptr()->CopySubresourceRegion(get_texture_ptr(),
get_subresource(),
0, 0, 0,
get_staging_texture_ptr(), 0,
nullptr);
if (ptr) {
ptr->Pitch = 0;
ptr->U = ptr->V = ptr->Y = 0;
ptr->A = ptr->R = ptr->G = ptr->B = 0;
}
GAPI_LOG_DEBUG(nullptr, "access on WRITE released: " << this);
return MFX_ERR_NONE;
}
DX11AllocationRecord::DX11AllocationRecord() = default;
DX11AllocationRecord::~DX11AllocationRecord() {
GAPI_LOG_DEBUG(nullptr, "record: " << this <<
", subresources count: " << resources.size());
for (AllocationId id : resources) {
delete id;
}
resources.clear();
GAPI_LOG_DEBUG(nullptr, "release final referenced texture: " << texture_ptr.get());
}
void DX11AllocationRecord::init(unsigned int items,
ID3D11DeviceContext* origin_ctx,
mfxFrameAllocator origin_allocator,
ComPtrGuard<ID3D11Texture2D>&& texture,
std::vector<ComPtrGuard<ID3D11Texture2D>> &&staging_textures) {
GAPI_DbgAssert(items != 0 && "Cannot create DX11AllocationRecord with empty items");
GAPI_DbgAssert(items == staging_textures.size() && "Allocation items count and staging size are not equal");
GAPI_DbgAssert(origin_ctx &&
"Cannot create DX11AllocationItem for empty origin_ctx");
auto shared_allocator_copy = origin_allocator;
GAPI_DbgAssert((shared_allocator_copy.Lock && shared_allocator_copy.Unlock) &&
"Cannot create DX11AllocationItem for empty origin allocator");
// abandon unusable c-allocator interfaces
shared_allocator_copy.Alloc = nullptr;
shared_allocator_copy.Free = nullptr;
shared_allocator_copy.pthis = nullptr;
GAPI_LOG_DEBUG(nullptr, "subresources count: " << items << ", text: " << texture.get());
resources.reserve(items);
// no AddRef here, because DX11AllocationRecord receive ownership it here
texture_ptr = createCOMSharedPtrGuard(std::move(texture));
for(unsigned int i = 0; i < items; i++) {
resources.emplace_back(new DX11AllocationItem(get_ptr(), origin_ctx, shared_allocator_copy,
texture_ptr, i, std::move(staging_textures[i])));
}
}
DX11AllocationRecord::Ptr DX11AllocationRecord::get_ptr() {
return shared_from_this();
}
DX11AllocationRecord::AllocationId* DX11AllocationRecord::data() {
return resources.data();
}
size_t DX11AllocationRecord::size() const {
return resources.size();
}
} // namespace onevpl
} // namespace wip
} // namespace gapi
} // namespace cv
#endif // HAVE_D3D11
#endif // HAVE_DIRECTX
#endif // HAVE_ONEVPL
@@ -0,0 +1,151 @@
#ifndef GAPI_STREAMING_ONEVPL_ACCEL_DX11_ALLOC_RESOURCE_HPP
#define GAPI_STREAMING_ONEVPL_ACCEL_DX11_ALLOC_RESOURCE_HPP
#include <map>
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
#include <opencv2/gapi/util/compiler_hints.hpp>
#ifdef HAVE_ONEVPL
#include "streaming/onevpl/onevpl_export.hpp"
#include "streaming/onevpl/accelerators/utils/elastic_barrier.hpp"
#include "streaming/onevpl/utils.hpp"
#ifdef HAVE_DIRECTX
#ifdef HAVE_D3D11
#pragma comment(lib,"d3d11.lib")
#define D3D11_NO_HELPERS
#define NOMINMAX
#include <d3d11.h>
#include <d3d11_4.h>
#include <codecvt>
#include "opencv2/core/directx.hpp"
#ifdef HAVE_OPENCL
#include <CL/cl_d3d11.h>
#endif // HAVE_OPENCL
#undef D3D11_NO_HELPERS
#undef NOMINMAX
namespace cv {
namespace gapi {
namespace wip {
namespace onevpl {
class SharedLock;
// GAPI_EXPORTS for tests
struct GAPI_EXPORTS LockAdapter {
LockAdapter(mfxFrameAllocator origin_allocator);
size_t read_lock(mfxMemId mid, mfxFrameData &data);
size_t unlock_read(mfxMemId mid, mfxFrameData &data);
void write_lock(mfxMemId mid, mfxFrameData &data);
bool is_write_acquired();
void unlock_write(mfxMemId mid, mfxFrameData &data);
SharedLock* set_adaptee(SharedLock* new_impl);
SharedLock* get_adaptee();
private:
LockAdapter(const LockAdapter&) = delete;
LockAdapter(LockAdapter&&) = delete;
LockAdapter& operator= (const LockAdapter&) = delete;
LockAdapter& operator= (LockAdapter&&) = delete;
mfxFrameAllocator lockable_allocator;
SharedLock* impl;
};
struct GAPI_EXPORTS NativeHandleAdapter {
NativeHandleAdapter(mfxFrameAllocator origin_allocator);
void get_handle(mfxMemId mid, mfxHDL& out);
private:
mfxFrameAllocator native_handle_getter;
};
struct DX11AllocationRecord;
struct DX11AllocationItem : public LockAdapter,
public NativeHandleAdapter,
public elastic_barrier<DX11AllocationItem> {
using subresource_id_t = unsigned int;
friend struct DX11AllocationRecord;
friend class elastic_barrier<DX11AllocationItem>;
~DX11AllocationItem();
void release();
ID3D11Texture2D* get_texture_ptr();
ID3D11Texture2D* get_staging_texture_ptr();
DX11AllocationItem::subresource_id_t get_subresource() const;
ID3D11DeviceContext* get_device_ctx_ptr();
// public transactional access to resources.
// implements dispatching through different access acquisition modes.
// current acquisition mode determined by `LockAdapter` with `is_write_acquired()`
mfxStatus acquire_access(mfxFrameData *ptr);
mfxStatus release_access(mfxFrameData *ptr);
private:
DX11AllocationItem(std::weak_ptr<DX11AllocationRecord> parent,
ID3D11DeviceContext* origin_ctx,
mfxFrameAllocator origin_allocator,
ComSharedPtrGuard<ID3D11Texture2D> texture_ptr,
subresource_id_t subresource_id,
ComPtrGuard<ID3D11Texture2D>&& staging_tex_ptr);
// elastic barrier interface impl
void on_first_in_impl(mfxFrameData *ptr);
void on_last_out_impl(mfxFrameData *ptr);
mfxStatus shared_access_acquire_unsafe(mfxFrameData *ptr);
mfxStatus shared_access_release_unsafe(mfxFrameData *ptr);
mfxStatus exclusive_access_acquire_unsafe(mfxFrameData *ptr);
mfxStatus exclusive_access_release_unsafe(mfxFrameData *ptr);
ID3D11DeviceContext* shared_device_context;
ComSharedPtrGuard<ID3D11Texture2D> texture_ptr;
subresource_id_t subresource_id = 0;
ComPtrGuard<ID3D11Texture2D> staging_texture_ptr;
std::weak_ptr<DX11AllocationRecord> observer;
};
struct DX11AllocationRecord : public std::enable_shared_from_this<DX11AllocationRecord> {
using Ptr = std::shared_ptr<DX11AllocationRecord>;
~DX11AllocationRecord();
template<typename... Args>
static Ptr create(Args&& ...args) {
std::shared_ptr<DX11AllocationRecord> record(new DX11AllocationRecord);
record->init(std::forward<Args>(args)...);
return record;
}
Ptr get_ptr();
// Raw ptr is required as a part of VPL `Mid` c-interface
// which requires contiguous memory
using AllocationId = DX11AllocationItem*;
AllocationId* data();
size_t size() const;
private:
DX11AllocationRecord();
void init(unsigned int items, ID3D11DeviceContext* origin_ctx,
mfxFrameAllocator origin_allocator,
ComPtrGuard<ID3D11Texture2D>&& texture, std::vector<ComPtrGuard<ID3D11Texture2D>> &&staging_textures);
std::vector<AllocationId> resources;
ComSharedPtrGuard<ID3D11Texture2D> texture_ptr;
};
} // namespace onevpl
} // namespace wip
} // namespace gapi
} // namespace cv
#endif // HAVE_D3D11
#endif // HAVE_DIRECTX
#endif // HAVE_ONEVPL
#endif // GAPI_STREAMING_ONEVPL_ACCEL_DX11_ALLOC_RESOURCE_HPP
@@ -9,12 +9,7 @@
#include "logger.hpp"
#ifdef HAVE_ONEVPL
#if (MFX_VERSION >= 2000)
#include <vpl/mfxdispatcher.h>
#endif
#include <vpl/mfx.h>
#include "streaming/onevpl/onevpl_export.hpp"
namespace cv {
namespace gapi {
@@ -25,12 +20,25 @@ VPLMediaFrameCPUAdapter::VPLMediaFrameCPUAdapter(std::shared_ptr<Surface> surfac
parent_surface_ptr(surface) {
GAPI_Assert(parent_surface_ptr && "Surface is nullptr");
parent_surface_ptr->obtain_lock();
GAPI_LOG_DEBUG(nullptr, "surface: " << parent_surface_ptr->get_handle() <<
", w: " << parent_surface_ptr->get_info().Width <<
", h: " << parent_surface_ptr->get_info().Height <<
", p: " << parent_surface_ptr->get_data().Pitch);
const Surface::info_t& info = parent_surface_ptr->get_info();
switch(info.FourCC)
{
case MFX_FOURCC_I420:
throw std::runtime_error("MediaFrame doesn't support I420 type");
break;
case MFX_FOURCC_NV12:
frame_desc.fmt = MediaFormat::NV12;
break;
default:
throw std::runtime_error("MediaFrame unknown 'fmt' type: " + std::to_string(info.FourCC));
}
frame_desc.size = cv::Size{info.Width, info.Height};
parent_surface_ptr->obtain_lock();
}
VPLMediaFrameCPUAdapter::~VPLMediaFrameCPUAdapter() {
@@ -42,22 +50,7 @@ VPLMediaFrameCPUAdapter::~VPLMediaFrameCPUAdapter() {
}
cv::GFrameDesc VPLMediaFrameCPUAdapter::meta() const {
GFrameDesc desc;
const Surface::info_t& info = parent_surface_ptr->get_info();
switch(info.FourCC)
{
case MFX_FOURCC_I420:
throw std::runtime_error("MediaFrame doesn't support I420 type");
break;
case MFX_FOURCC_NV12:
desc.fmt = MediaFormat::NV12;
break;
default:
throw std::runtime_error("MediaFrame unknown 'fmt' type: " + std::to_string(info.FourCC));
}
desc.size = cv::Size{info.Width, info.Height};
return desc;
return frame_desc;
}
MediaFrame::View VPLMediaFrameCPUAdapter::access(MediaFrame::Access) {
@@ -33,6 +33,7 @@ public:
void deserialize(cv::gapi::s11n::IIStream&) override;
private:
std::shared_ptr<Surface> parent_surface_ptr;
GFrameDesc frame_desc;
};
} // namespace onevpl
} // namespace wip
@@ -0,0 +1,232 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2021 Intel Corporation
#include "streaming/onevpl/accelerators/surface/dx11_frame_adapter.hpp"
#include "streaming/onevpl/accelerators/dx11_alloc_resource.hpp"
#include "streaming/onevpl/accelerators/surface/surface.hpp"
#include "logger.hpp"
#ifdef HAVE_ONEVPL
#include "streaming/onevpl/onevpl_export.hpp"
#ifdef HAVE_INF_ENGINE
// For IE classes (ParamMap, etc)
#include <inference_engine.hpp>
#endif // HAVE_INF_ENGINE
namespace cv {
namespace gapi {
namespace wip {
namespace onevpl {
void lock_mid(mfxMemId mid, mfxFrameData &data, MediaFrame::Access mode) {
LockAdapter* alloc_data = reinterpret_cast<LockAdapter *>(mid);
if (mode == MediaFrame::Access::R) {
alloc_data->read_lock(mid, data);
} else {
alloc_data->write_lock(mid, data);
}
}
void unlock_mid(mfxMemId mid, mfxFrameData &data, MediaFrame::Access mode) {
LockAdapter* alloc_data = reinterpret_cast<LockAdapter*>(data.MemId);
if (mode == MediaFrame::Access::R) {
alloc_data->unlock_read(mid, data);
} else {
alloc_data->unlock_write(mid, data);
}
}
VPLMediaFrameDX11Adapter::VPLMediaFrameDX11Adapter(std::shared_ptr<Surface> surface):
parent_surface_ptr(surface) {
GAPI_Assert(parent_surface_ptr && "Surface is nullptr");
const Surface::info_t& info = parent_surface_ptr->get_info();
Surface::data_t& data = parent_surface_ptr->get_data();
GAPI_LOG_DEBUG(nullptr, "surface: " << parent_surface_ptr->get_handle() <<
", w: " << info.Width << ", h: " << info.Height <<
", p: " << data.Pitch);
switch(info.FourCC)
{
case MFX_FOURCC_I420:
throw std::runtime_error("MediaFrame doesn't support I420 type");
break;
case MFX_FOURCC_NV12:
frame_desc.fmt = MediaFormat::NV12;
break;
default:
throw std::runtime_error("MediaFrame unknown 'fmt' type: " + std::to_string(info.FourCC));
}
frame_desc.size = cv::Size{info.Width, info.Height};
LockAdapter* alloc_data = reinterpret_cast<LockAdapter*>(data.MemId);
alloc_data->set_adaptee(this);
parent_surface_ptr->obtain_lock();
}
VPLMediaFrameDX11Adapter::~VPLMediaFrameDX11Adapter() {
// Each VPLMediaFrameDX11Adapter releases mfx surface counter
// The last VPLMediaFrameDX11Adapter releases shared Surface pointer
// The last surface pointer releases workspace memory
Surface::data_t& data = parent_surface_ptr->get_data();
LockAdapter* alloc_data = reinterpret_cast<LockAdapter*>(data.MemId);
alloc_data->set_adaptee(nullptr);
parent_surface_ptr->release_lock();
}
cv::GFrameDesc VPLMediaFrameDX11Adapter::meta() const {
return frame_desc;
}
MediaFrame::View VPLMediaFrameDX11Adapter::access(MediaFrame::Access mode) {
Surface::data_t& data = parent_surface_ptr->get_data();
const Surface::info_t& info = parent_surface_ptr->get_info();
void* frame_id = reinterpret_cast<void*>(this);
GAPI_LOG_DEBUG(nullptr, "START lock frame in surface: " << parent_surface_ptr->get_handle() <<
", frame id: " << frame_id);
// lock MT
lock_mid(data.MemId, data, mode);
GAPI_LOG_DEBUG(nullptr, "FINISH lock frame in surface: " << parent_surface_ptr->get_handle() <<
", frame id: " << frame_id);
using stride_t = typename cv::MediaFrame::View::Strides::value_type;
stride_t pitch = static_cast<stride_t>(data.Pitch);
// NB: make copy for some copyable object, because access release may be happened
// after source/pool destruction, so we need a copy
auto parent_surface_ptr_copy = parent_surface_ptr;
switch(info.FourCC) {
case MFX_FOURCC_I420:
{
GAPI_Assert(data.Y && data.U && data.V && "MFX_FOURCC_I420 frame data is nullptr");
cv::MediaFrame::View::Ptrs pp = { data.Y, data.U, data.V, nullptr };
cv::MediaFrame::View::Strides ss = { pitch, pitch / 2, pitch / 2, 0u };
return cv::MediaFrame::View(std::move(pp), std::move(ss),
[parent_surface_ptr_copy,
frame_id, mode] () {
parent_surface_ptr_copy->obtain_lock();
auto& data = parent_surface_ptr_copy->get_data();
GAPI_LOG_DEBUG(nullptr, "START unlock frame in surface: " << parent_surface_ptr_copy->get_handle() <<
", frame id: " << frame_id);
unlock_mid(data.MemId, data, mode);
GAPI_LOG_DEBUG(nullptr, "FINISH unlock frame in surface: " << parent_surface_ptr_copy->get_handle() <<
", frame id: " << frame_id);
parent_surface_ptr_copy->release_lock();
});
}
case MFX_FOURCC_NV12:
{
if (!data.Y || !data.UV) {
GAPI_LOG_WARNING(nullptr, "Empty data detected!!! for surface: " << parent_surface_ptr->get_handle() <<
", frame id: " << frame_id);
}
GAPI_Assert(data.Y && data.UV && "MFX_FOURCC_NV12 frame data is nullptr");
cv::MediaFrame::View::Ptrs pp = { data.Y, data.UV, nullptr, nullptr };
cv::MediaFrame::View::Strides ss = { pitch, pitch, 0u, 0u };
return cv::MediaFrame::View(std::move(pp), std::move(ss),
[parent_surface_ptr_copy,
frame_id, mode] () {
parent_surface_ptr_copy->obtain_lock();
auto& data = parent_surface_ptr_copy->get_data();
GAPI_LOG_DEBUG(nullptr, "START unlock frame in surface: " << parent_surface_ptr_copy->get_handle() <<
", frame id: " << frame_id);
unlock_mid(data.MemId, data, mode);
GAPI_LOG_DEBUG(nullptr, "FINISH unlock frame in surface: " << parent_surface_ptr_copy->get_handle() <<
", frame id: " << frame_id);
parent_surface_ptr_copy->release_lock();
});
}
break;
default:
throw std::runtime_error("MediaFrame unknown 'fmt' type: " + std::to_string(info.FourCC));
}
}
cv::util::any VPLMediaFrameDX11Adapter::blobParams() const {
#ifdef HAVE_INF_ENGINE
GAPI_Assert(false && "VPLMediaFrameDX11Adapter::blobParams() is not fully operable "
"in G-API streaming. Please waiting for future PRs");
Surface::data_t& data = parent_surface_ptr->get_data();
NativeHandleAdapter* native_handle_getter = reinterpret_cast<NativeHandleAdapter*>(data.MemId);
mfxHDLPair handle{};
native_handle_getter->get_handle(data.MemId, reinterpret_cast<mfxHDL&>(handle));
InferenceEngine::ParamMap params{{"SHARED_MEM_TYPE", "VA_SURFACE"},
{"DEV_OBJECT_HANDLE", handle.first},
{"COLOR_FORMAT", InferenceEngine::ColorFormat::NV12},
{"VA_PLANE",
static_cast<DX11AllocationItem::subresource_id_t>(
reinterpret_cast<uint64_t>(
reinterpret_cast<DX11AllocationItem::subresource_id_t *>(
handle.second)))}};//,
const Surface::info_t& info = parent_surface_ptr->get_info();
InferenceEngine::TensorDesc tdesc({InferenceEngine::Precision::U8,
{1, 3, static_cast<size_t>(info.Height),
static_cast<size_t>(info.Width)},
InferenceEngine::Layout::NCHW});
return std::make_pair(tdesc, params);
#else
GAPI_Assert(false && "VPLMediaFrameDX11Adapter::blobParams() is not implemented");
#endif // HAVE_INF_ENGINE
}
void VPLMediaFrameDX11Adapter::serialize(cv::gapi::s11n::IOStream&) {
GAPI_Assert(false && "VPLMediaFrameDX11Adapter::serialize() is not implemented");
}
void VPLMediaFrameDX11Adapter::deserialize(cv::gapi::s11n::IIStream&) {
GAPI_Assert(false && "VPLMediaFrameDX11Adapter::deserialize() is not implemented");
}
DXGI_FORMAT VPLMediaFrameDX11Adapter::get_dx11_color_format(uint32_t mfx_fourcc) {
switch (mfx_fourcc) {
case MFX_FOURCC_NV12:
return DXGI_FORMAT_NV12;
case MFX_FOURCC_YUY2:
return DXGI_FORMAT_YUY2;
case MFX_FOURCC_RGB4:
return DXGI_FORMAT_B8G8R8A8_UNORM;
case MFX_FOURCC_P8:
case MFX_FOURCC_P8_TEXTURE:
return DXGI_FORMAT_P8;
case MFX_FOURCC_ARGB16:
case MFX_FOURCC_ABGR16:
return DXGI_FORMAT_R16G16B16A16_UNORM;
case MFX_FOURCC_P010:
return DXGI_FORMAT_P010;
case MFX_FOURCC_A2RGB10:
return DXGI_FORMAT_R10G10B10A2_UNORM;
case DXGI_FORMAT_AYUV:
case MFX_FOURCC_AYUV:
return DXGI_FORMAT_AYUV;
default:
return DXGI_FORMAT_UNKNOWN;
}
}
} // namespace onevpl
} // namespace wip
} // namespace gapi
} // namespace cv
#endif // HAVE_ONEVPL
@@ -0,0 +1,63 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2021 Intel Corporation
#ifndef GAPI_STREAMING_ONEVPL_ACCELERATORS_SURFACE_DX11_FRAME_ADAPTER_HPP
#define GAPI_STREAMING_ONEVPL_ACCELERATORS_SURFACE_DX11_FRAME_ADAPTER_HPP
#include <memory>
#include <opencv2/gapi/media.hpp>
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
#include "streaming/onevpl/accelerators/utils/shared_lock.hpp"
#ifdef HAVE_ONEVPL
#include "streaming/onevpl/onevpl_export.hpp"
#ifdef HAVE_DIRECTX
#ifdef HAVE_D3D11
#define D3D11_NO_HELPERS
#define NOMINMAX
#include <d3d11.h>
#include <codecvt>
#include "opencv2/core/directx.hpp"
#ifdef HAVE_OPENCL
#include <CL/cl_d3d11.h>
#endif
namespace cv {
namespace gapi {
namespace wip {
namespace onevpl {
class Surface;
class VPLMediaFrameDX11Adapter final: public cv::MediaFrame::IAdapter,
public SharedLock {
public:
// GAPI_EXPORTS for tests
GAPI_EXPORTS VPLMediaFrameDX11Adapter(std::shared_ptr<Surface> assoc_surface);
GAPI_EXPORTS ~VPLMediaFrameDX11Adapter();
cv::GFrameDesc meta() const override;
MediaFrame::View access(MediaFrame::Access) override;
// The default implementation does nothing
cv::util::any blobParams() const override;
void serialize(cv::gapi::s11n::IOStream&) override;
void deserialize(cv::gapi::s11n::IIStream&) override;
static DXGI_FORMAT get_dx11_color_format(uint32_t mfx_fourcc);
private:
std::shared_ptr<Surface> parent_surface_ptr;
mfxFrameAllocator allocator;
GFrameDesc frame_desc;
};
} // namespace onevpl
} // namespace wip
} // namespace gapi
} // namespace cv
#undef NOMINMAX
#endif // HAVE_D3D11
#endif // HAVE_DIRECTX
#endif // HAVE_ONEVPL
#endif // GAPI_STREAMING_ONEVPL_ACCELERATORS_SURFACE_DX11_FRAME_ADAPTER_HPP
@@ -20,18 +20,20 @@ Surface::Surface(std::unique_ptr<handle_t>&& surf, std::shared_ptr<void> associa
mirrored_locked_count() {
GAPI_Assert(mfx_surface && "Surface is nullptr");
mirrored_locked_count.store(mfx_surface->Data.Locked);
GAPI_LOG_DEBUG(nullptr, "create surface: " << mfx_surface <<
", locked count: " << mfx_surface->Data.Locked);
}
Surface::~Surface() {
GAPI_LOG_DEBUG(nullptr, "destroy surface: " << mfx_surface <<
", worspace memory counter: " << workspace_memory_ptr.use_count());
", worspace memory counter: " <<
workspace_memory_ptr.use_count());
}
std::shared_ptr<Surface> Surface::create_surface(std::unique_ptr<handle_t>&& surf,
std::shared_ptr<void> accociated_memory) {
Surface::info_t& info = surf->Info;
info.FourCC = MFX_FOURCC_NV12;
surface_ptr_t ret {new Surface(std::move(surf), accociated_memory)};
return ret;
}
@@ -48,14 +50,16 @@ const Surface::data_t& Surface::get_data() const {
return mfx_surface->Data;
}
Surface::data_t& Surface::get_data() {
return const_cast<Surface::data_t&>(static_cast<const Surface*>(this)->get_data());
}
size_t Surface::get_locks_count() const {
return mirrored_locked_count.load();
return mirrored_locked_count.load() + mfx_surface->Data.Locked;
}
size_t Surface::obtain_lock() {
size_t locked_count = mirrored_locked_count.fetch_add(1);
GAPI_Assert(locked_count < std::numeric_limits<mfxU16>::max() && "Too many references ");
mfx_surface->Data.Locked = static_cast<mfxU16>(locked_count + 1);
GAPI_LOG_DEBUG(nullptr, "surface: " << mfx_surface.get() <<
", locked times: " << locked_count + 1);
return locked_count; // return preceding value
@@ -63,9 +67,7 @@ size_t Surface::obtain_lock() {
size_t Surface::release_lock() {
size_t locked_count = mirrored_locked_count.fetch_sub(1);
GAPI_Assert(locked_count < std::numeric_limits<mfxU16>::max() && "Too many references ");
GAPI_Assert(locked_count && "Surface lock counter is invalid");
mfx_surface->Data.Locked = static_cast<mfxU16>(locked_count - 1);
GAPI_LOG_DEBUG(nullptr, "surface: " << mfx_surface.get() <<
", locked times: " << locked_count - 1);
return locked_count; // return preceding value
@@ -13,12 +13,7 @@
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
#ifdef HAVE_ONEVPL
#if (MFX_VERSION >= 2000)
#include <vpl/mfxdispatcher.h>
#endif
#include <vpl/mfx.h>
#include "streaming/onevpl/onevpl_export.hpp"
namespace cv {
namespace gapi {
@@ -45,24 +40,21 @@ namespace onevpl {
* - @ref Surface::obtain_lock() against @ref Surface::release_lock()
* - @ref Surface::release_lock() against @ref Surface::release_lock()
*/
class Surface {
using handle_t = mfxFrameSurface1;
std::shared_ptr<void> workspace_memory_ptr;
std::unique_ptr<handle_t> mfx_surface;
std::atomic<size_t> mirrored_locked_count;
class GAPI_EXPORTS Surface final { // GAPI_EXPORTS for tests
public:
using handle_t = mfxFrameSurface1;
using info_t = mfxFrameInfo;
using data_t = mfxFrameData;
// GAPI_EXPORTS for tests
GAPI_EXPORTS static std::shared_ptr<Surface> create_surface(std::unique_ptr<handle_t>&& surf,
std::shared_ptr<void> accociated_memory);
GAPI_EXPORTS ~Surface();
GAPI_EXPORTS handle_t* get_handle() const;
GAPI_EXPORTS const info_t& get_info() const;
GAPI_EXPORTS const data_t& get_data() const;
static std::shared_ptr<Surface> create_surface(std::unique_ptr<handle_t>&& surf,
std::shared_ptr<void> accociated_memory);
~Surface();
handle_t* get_handle() const;
const info_t& get_info() const;
const data_t& get_data() const;
data_t& get_data();
/**
* Extract value thread-safe lock counter (see @ref Surface description).
@@ -71,7 +63,7 @@ public:
*
* @return fetched locks count.
*/
GAPI_EXPORTS size_t get_locks_count() const;
size_t get_locks_count() const;
/**
* Atomically increase value of thread-safe lock counter (see @ref Surface description).
@@ -80,7 +72,7 @@ public:
*
* @return locks count just before its increasing.
*/
GAPI_EXPORTS size_t obtain_lock();
size_t obtain_lock();
/**
* Atomically decrease value of thread-safe lock counter (see @ref Surface description).
@@ -89,9 +81,13 @@ public:
*
* @return locks count just before its decreasing.
*/
GAPI_EXPORTS size_t release_lock();
size_t release_lock();
private:
Surface(std::unique_ptr<handle_t>&& surf, std::shared_ptr<void> accociated_memory);
std::shared_ptr<void> workspace_memory_ptr;
std::unique_ptr<handle_t> mfx_surface;
std::atomic<size_t> mirrored_locked_count;
};
using surface_ptr_t = std::shared_ptr<Surface>;
@@ -8,11 +8,7 @@
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
#ifdef HAVE_ONEVPL
#if (MFX_VERSION >= 2000)
#include <vpl/mfxdispatcher.h>
#endif
#include <vpl/mfx.h>
#include "streaming/onevpl/onevpl_export.hpp"
namespace cv {
namespace gapi {
@@ -0,0 +1,296 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2021 Intel Corporation
#ifndef GAPI_STREAMING_ONEVPL_ACCELERATORS_UTILS_ELASTIC_BARRIER_HPP
#define GAPI_STREAMING_ONEVPL_ACCELERATORS_UTILS_ELASTIC_BARRIER_HPP
#include <atomic>
namespace cv {
namespace gapi {
namespace wip {
namespace onevpl {
template<typename Impl>
class elastic_barrier {
public:
using self_t = Impl;
elastic_barrier() :
incoming_requests(),
outgoing_requests(),
pending_requests(),
reinit(false) {
}
self_t* get_self() {
return static_cast<self_t*>(this);
}
template<typename ...Args>
void visit_in (Args&& ...args) {
on_lock(std::forward<Args>(args)...);
}
template<typename ...Args>
void visit_out (Args&& ...args) {
on_unlock(std::forward<Args>(args)...);
}
protected:
~elastic_barrier() = default;
private:
std::atomic<size_t> incoming_requests;
std::atomic<size_t> outgoing_requests;
std::atomic<size_t> pending_requests;
std::atomic<bool> reinit;
template<typename ...Args>
void on_first_in(Args&& ...args) {
get_self()->on_first_in_impl(std::forward<Args>(args)...);
}
template<typename ...Args>
void on_last_out(Args&& ...args) {
get_self()->on_last_out_impl(std::forward<Args>(args)...);
}
template<typename ...Args>
void on_lock(Args&& ...args) {
// Read access is more complex
// each `incoming` request must check in before acquire resource
size_t thread_id = incoming_requests.fetch_add(1);
if (thread_id == 0) {
/*
* only one `incoming` request is allowable to init resource
* at first time
* let's filter out the first one by `thread_id`
*
* The first one `incoming` request becomes main `incoming` request
* */
if (outgoing_requests.load() == 0) {
get_self()->on_first_in(std::forward<Args>(args)...);
/*
* The main `incoming` request finished resource initialization
* and became `outgoing`
*
* Non empty `outgoing` count means that
* other further `incoming` (or busy-wait) requests
* are getting on with its job without resource initialization,
* because main `incoming` request has already initialized it at here
* */
outgoing_requests.fetch_add(1);
return;
}
return;
} else {
/*
* CASE 1)
*
* busy wait for others `incoming` requests for resource initialization
* besides main `incoming` request which are getting on
* resource initialization at this point
*
* */
// OR
/*
* CASE 2)
*
* busy wait for ALL `incoming` request for resource initialization
* including main `incoming` request. It will happen if
* new `incoming` requests had came here while resource was getting on deinit
* in `on_unlock` in another processing thread.
* In this case no actual main `incoming` request is available and
* all `incoming` requests must be in busy-wait stare
*
* */
// Each `incoming` request became `busy-wait` request
size_t busy_thread_id = pending_requests.fetch_add(1);
/*
* CASE 1)
*
* Non empty `outgoing` requests count means that other further `incoming` or
* `busy-wait` request are getting on with its job
* without resource initialization because
* main thread has already initialized it at here
* */
while (outgoing_requests.load() == 0) {
// OR
/*
* CASE 2)
*
* In case of NO master `incoming `request is available and doesn't
* provide resource initialization. All `incoming` requests must be in
* busy-wait state.
* If it is not true then CASE 1) is going on
*
* OR
*
* `on_unlock` is in deinitialization phase in another thread.
* Both cases mean busy-wait state here
* */
if (pending_requests.load() == incoming_requests.load()) {
/*
* CASE 2) ONLY
*
* It will happen if 'on_unlock` in another thread
* finishes its execution only
*
* `on_unlock` in another thread might finished with either
* deinitialization action or without deinitialization action
* (the call off deinitialization case)
*
* We must not continue at here (without reinit)
* if deinitialization happens in `on_unlock` in another thread.
* So try it on
* */
// only single `busy-wait` request must make sure about possible
// deinitialization. So first `busy-wait` request becomes
// main `busy-wait` request
if (busy_thread_id == 0) {
bool expected_reinit = true;
if (!reinit.compare_exchange_strong(expected_reinit, false)) {
/*
* deinitialization called off in `on_unlock`
* because new `incoming` request had appeared at here before
* `on_unlock` started deinit procedure in another thread.
* So no reinit required because no deinit had happended
*
* main `busy-wait` request must break busy-wait state
* and become `outgoing` request.
* Non empty `outgoing` count means that other
* further `incoming` requests or
* `busy-wait` requests are getting on with its job
* without resource initialization/reinitialization
* because no deinit happened in `on_unlock`
* in another thread
* */
break; //just quit busy loop
} else {
/* Deinitialization had happened in `on_unlock`
* in another thread right before
* new `incoming` requests appeared.
* So main `busy-wait` request must start reinit procedure
*/
get_self()->on_first_in(std::forward<Args>(args)...);
/*
* Main `busy-wait` request has finished reinit procedure
* and becomes `outgong` request.
* Non empty `outgoing` count means that other
* further `incoming` requests or
* `busy-wait` requests are getting on with its job
* without resource initialization because
* main `busy-wait` request
* has already re-initialized it at here
*/
outgoing_requests.fetch_add(1);
pending_requests.fetch_sub(1);
return;
}
}
}
}
// All non main requests became `outgoing` and look at on initialized resource
outgoing_requests++;
// Each `busy-wait` request are not busy-wait now
pending_requests.fetch_sub(1);
}
return;
}
template<typename ...Args>
void on_unlock(Args&& ...args) {
// Read unlock
/*
* Each released `outgoing` request checks out to doesn't use resource anymore.
* The last `outgoing` request becomes main `outgoing` request and
* must deinitialize resource if no `incoming` or `busy-wait` requests
* are waiting for it
*/
size_t thread_id = outgoing_requests.fetch_sub(1);
if (thread_id == 1) {
/*
* Make sure that no another `incoming` (including `busy-wait)
* exists.
* But beforehand its must make sure that no `incoming` or `pending`
* requests are exist.
*
* The main `outgoing` request is an one of `incoming` request
* (it is the oldest one in the current `incoming` bunch) and still
* holds resource in initialized state (thus we compare with 1).
* We must not deinitialize resource before decrease
* `incoming` requests counter because
* after it has got 0 value in `on_lock` another thread
* will start initialize resource procedure which will get conflict
* with current deinitialize procedure
*
* From this point, all `on_lock` request in another thread would
* become `busy-wait` without reaching main `incoming` state (CASE 2)
* */
if (incoming_requests.load() == 1) {
/*
* The main `outgoing` request is ready to deinit shared resource
* in unconflicting manner.
*
* This is a critical section for single thread for main `outgoing`
* request
*
* CASE 2 only available in `on_lock` thread
* */
get_self()->on_last_out(std::forward<Args>(args)...);
/*
* Before main `outgoinq` request become released it must notify
* subsequent `busy-wait` requests in `on_lock` in another thread
* that main `busy-wait` must start reinit resource procedure
* */
reinit.store(true);
/*
* Deinitialize procedure is finished and main `outgoing` request
* (it is the oldest one in `incoming` request) must become released
*
* Right after when we decrease `incoming` counter
* the condition for equality
* `busy-wait` and `incoming` counter will become true (CASE 2 only)
* in `on_lock` in another threads. After that
* a main `busy-wait` request would check `reinit` condition
* */
incoming_requests.fetch_sub(1);
return;
}
/*
* At this point we have guarantee that new `incoming` requests
* had became increased in `on_lock` in another thread right before
* current thread deinitialize resource.
*
* So call off deinitialization procedure here
* */
}
incoming_requests.fetch_sub(1);
}
elastic_barrier(const elastic_barrier&) = delete;
elastic_barrier(elastic_barrier&&) = delete;
elastic_barrier& operator() (const elastic_barrier&) = delete;
elastic_barrier& operator() (elastic_barrier&&) = delete;
};
} // namespace onevpl
} // namespace wip
} // namespace gapi
} // namespace cv
#endif // GAPI_STREAMING_ONEVPL_ACCELERATORS_UTILS_ELASTIC_BARRIER_HPP
@@ -0,0 +1,95 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2021 Intel Corporation
#include <thread>
#include "streaming/onevpl/accelerators/utils/shared_lock.hpp"
namespace cv {
namespace gapi {
namespace wip {
namespace onevpl {
SharedLock::SharedLock() {
exclusive_lock.store(false);
shared_counter.store(0);
}
size_t SharedLock::shared_lock() {
size_t prev = 0;
bool in_progress = false;
bool pred_excl = exclusive_lock.load();
do {
if (!pred_excl) {
// if no exclusive lock then start shared lock transaction
prev = shared_counter.fetch_add(1);
in_progress = true; // transaction is in progress
} else {
if (in_progress) {
in_progress = false;
shared_counter.fetch_sub(1);
}
std::this_thread::yield();
}
// test if exclusive lock happened before
pred_excl = exclusive_lock.load();
} while (pred_excl || !in_progress);
return prev;
}
size_t SharedLock::unlock_shared() {
return shared_counter.fetch_sub(1);
}
void SharedLock::lock() {
bool in_progress = false;
size_t prev_shared = shared_counter.load();
do {
if (prev_shared == 0) {
bool expected = false;
while (!exclusive_lock.compare_exchange_strong(expected, true)) {
expected = false;
std::this_thread::yield();
}
in_progress = true;
} else {
if (in_progress) {
in_progress = false;
exclusive_lock.store(false);
}
std::this_thread::yield();
}
prev_shared = shared_counter.load();
} while (prev_shared != 0 || !in_progress);
}
bool SharedLock::try_lock() {
if (shared_counter.load() != 0) {
return false;
}
bool expected = false;
if (exclusive_lock.compare_exchange_strong(expected, true)) {
if (shared_counter.load() == 0) {
return true;
} else {
exclusive_lock.store(false);
}
}
return false;
}
void SharedLock::unlock() {
exclusive_lock.store(false);
}
bool SharedLock::owns() const {
return exclusive_lock.load();
}
} // namespace onevpl
} // namespace wip
} // namespace gapi
} // namespace cv
@@ -0,0 +1,47 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2021 Intel Corporation
#ifndef GAPI_STREAMING_ONEVPL_ACCELERATORS_SURFACE_SHARED_LOCK_HPP
#define GAPI_STREAMING_ONEVPL_ACCELERATORS_SURFACE_SHARED_LOCK_HPP
#include <atomic>
#include <memory>
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
namespace cv {
namespace gapi {
namespace wip {
namespace onevpl {
class GAPI_EXPORTS SharedLock {
public:
SharedLock();
~SharedLock() = default;
size_t shared_lock();
size_t unlock_shared();
void lock();
bool try_lock();
void unlock();
bool owns() const;
private:
SharedLock(const SharedLock&) = delete;
SharedLock& operator= (const SharedLock&) = delete;
SharedLock(SharedLock&&) = delete;
SharedLock& operator== (SharedLock&&) = delete;
std::atomic<bool> exclusive_lock;
std::atomic<size_t> shared_counter;
};
} // namespace onevpl
} // namespace wip
} // namespace gapi
} // namespace cv
#endif // GAPI_STREAMING_ONEVPL_ACCELERATORS_SURFACE_SHARED_LOCK_HPP
@@ -5,7 +5,7 @@
// Copyright (C) 2021 Intel Corporation
#ifdef HAVE_ONEVPL
#include <vpl/mfxvideo.h>
#include "streaming/onevpl/onevpl_export.hpp"
#include <opencv2/gapi/own/assert.hpp>
#include <opencv2/gapi/util/variant.hpp>
@@ -44,7 +44,7 @@ CfgParamDeviceSelector::CfgParamDeviceSelector(const CfgParams& cfg_params) :
auto accel_mode_it =
std::find_if(cfg_params.begin(), cfg_params.end(), [] (const CfgParam& value) {
return value.get_name() == "mfxImplDescription.AccelerationMode";
return value.get_name() == CfgParam::acceleration_mode_name();
});
if (accel_mode_it == cfg_params.end())
{
@@ -128,9 +128,11 @@ CfgParamDeviceSelector::CfgParamDeviceSelector(const CfgParams& cfg_params) :
suggested_device = IDeviceSelector::create<Device>(hw_handle, "GPU", AccelType::DX11);
suggested_context = IDeviceSelector::create<Context>(device_context, AccelType::DX11);
#else
GAPI_LOG_WARNING(nullptr, "Unavailable \"mfxImplDescription.AccelerationMode: MFX_ACCEL_MODE_VIA_D3D11\""
GAPI_LOG_WARNING(nullptr, "Unavailable \"" << CfgParam::acceleration_mode_name() << ": MFX_ACCEL_MODE_VIA_D3D11\""
"was chosen for current project configuration");
throw std::logic_error("Unsupported \"mfxImplDescription.AccelerationMode: MFX_ACCEL_MODE_VIA_D3D11\"");
throw std::logic_error(std::string("Unsupported \"") +
CfgParam::acceleration_mode_name() +
": MFX_ACCEL_MODE_VIA_D3D11\"");
#endif // HAVE_DIRECTX
#endif // HAVE_D3D11
break;
@@ -140,7 +142,8 @@ CfgParamDeviceSelector::CfgParamDeviceSelector(const CfgParams& cfg_params) :
break;
}
default:
throw std::logic_error("Unsupported \"mfxImplDescription.AccelerationMode\" requested: " +
throw std::logic_error(std::string("Unsupported \"") +
CfgParam::acceleration_mode_name() +"\" requested: " +
std::to_string(accel_mode.Data.U32));
break;
}
@@ -154,14 +157,16 @@ CfgParamDeviceSelector::CfgParamDeviceSelector(Device::Ptr device_ptr,
suggested_context(IDeviceSelector::create<Context>(nullptr, AccelType::HOST)) {
auto accel_mode_it =
std::find_if(cfg_params.begin(), cfg_params.end(), [] (const CfgParam& value) {
return value.get_name() == "mfxImplDescription.AccelerationMode";
return value.get_name() == CfgParam::acceleration_mode_name();
});
if (accel_mode_it == cfg_params.end()) {
GAPI_LOG_WARNING(nullptr, "Cannot deternime \"device_ptr\" type. "
"Make sure a param \"mfxImplDescription.AccelerationMode\" "
"Make sure a param \"" << CfgParam::acceleration_mode_name() << "\" "
"presents in configurations and has correct value according to "
"\"device_ptr\" type");
throw std::logic_error("Missing \"mfxImplDescription.AccelerationMode\" param");
throw std::logic_error(std::string("Missing \"") +
CfgParam::acceleration_mode_name() +
"\" param");
}
GAPI_LOG_DEBUG(nullptr, "Turn on HW acceleration support for device: " <<
@@ -169,7 +174,7 @@ CfgParamDeviceSelector::CfgParamDeviceSelector(Device::Ptr device_ptr,
", context: " << ctx_ptr);
if (!device_ptr) {
GAPI_LOG_WARNING(nullptr, "Empty \"device_ptr\" is not allowed when "
"param \"mfxImplDescription.AccelerationMode\" existed");
"param \"" << CfgParam::acceleration_mode_name() << "\" existed");
throw std::logic_error("Invalid param: \"device_ptr\"");
}
@@ -191,23 +196,36 @@ CfgParamDeviceSelector::CfgParamDeviceSelector(Device::Ptr device_ptr,
suggested_context = IDeviceSelector::create<Context>(ctx_ptr, AccelType::DX11);
ID3D11DeviceContext* dx_ctx_ptr =
reinterpret_cast<ID3D11DeviceContext*>(suggested_context.get_ptr());
// oneVPL recommendation
{
ID3D11Multithread *pD11Multithread = nullptr;
dx_ctx_ptr->QueryInterface(IID_PPV_ARGS(&pD11Multithread));
pD11Multithread->SetMultithreadProtected(true);
pD11Multithread->Release();
}
dx_ctx_ptr->AddRef();
#else
GAPI_LOG_WARNING(nullptr, "Unavailable \"mfxImplDescription.AccelerationMode: MFX_ACCEL_MODE_VIA_D3D11\""
GAPI_LOG_WARNING(nullptr, "Unavailable \"" << CfgParam::acceleration_mode_name() <<
": MFX_ACCEL_MODE_VIA_D3D11\""
"was chosen for current project configuration");
throw std::logic_error("Unsupported \"mfxImplDescription.AccelerationMode: MFX_ACCEL_MODE_VIA_D3D11\"");
throw std::logic_error(std::string("Unsupported \"") +
CfgParam::acceleration_mode_name() + ": MFX_ACCEL_MODE_VIA_D3D11\"");
#endif // HAVE_DIRECTX
#endif // HAVE_D3D11
break;
}
case MFX_ACCEL_MODE_NA: {
GAPI_LOG_WARNING(nullptr, "Incompatible \"mfxImplDescription.AccelerationMode: MFX_ACCEL_MODE_NA\" with "
GAPI_LOG_WARNING(nullptr, "Incompatible \"" << CfgParam::acceleration_mode_name() <<
": MFX_ACCEL_MODE_NA\" with "
"\"device_ptr\" and \"ctx_ptr\" arguments. "
"You should not clarify these arguments with \"MFX_ACCEL_MODE_NA\" mode");
throw std::logic_error("Incompatible param: MFX_ACCEL_MODE_NA");
}
default:
throw std::logic_error("Unsupported \"mfxImplDescription.AccelerationMode\" requested: " +
throw std::logic_error(std::string("Unsupported \"") + CfgParam::acceleration_mode_name() +
"\" requested: " +
std::to_string(accel_mode.Data.U32));
break;
}
@@ -86,6 +86,34 @@ CfgParam::CfgParam (const std::string& param_name, value_t&& param_value, bool i
CfgParam::~CfgParam() = default;
CfgParam CfgParam::create_frames_pool_size(uint64_t value) {
return CfgParam::create(CfgParam::frames_pool_size_name(), value, false);
}
CfgParam CfgParam::create_acceleration_mode(uint32_t value) {
return CfgParam::create(CfgParam::acceleration_mode_name(), value);
}
CfgParam CfgParam::create_acceleration_mode(const char* value) {
return CfgParam::create(CfgParam::acceleration_mode_name(), std::string(value));
}
CfgParam CfgParam::create_decoder_id(uint32_t value) {
return CfgParam::create(CfgParam::decoder_id_name(), value);
}
CfgParam CfgParam::create_decoder_id(const char* value) {
return CfgParam::create(CfgParam::decoder_id_name(), std::string(value));
}
CfgParam CfgParam::create_implementation(uint32_t value) {
return CfgParam::create(CfgParam::implementation_name(), value);
}
CfgParam CfgParam::create_implementation(const char* value) {
return CfgParam::create(CfgParam::implementation_name(), std::string(value));
}
CfgParam& CfgParam::operator=(const CfgParam& src) {
if (this != &src) {
m_priv = src.m_priv;
@@ -22,19 +22,16 @@ namespace onevpl {
template <>
struct ParamCreator<CfgParam> {
template<typename ValueType>
CfgParam create (const std::string& name, ValueType&& value) {
CfgParam create (const std::string& name, ValueType&& value, bool is_major_flag = false) {
return CfgParam::create(name, std::forward<ValueType>(value), is_major_flag);
}
bool is_major_flag = false;
};
template <>
struct ParamCreator<mfxVariant> {
template<typename ValueType>
mfxVariant create (const std::string& name, ValueType&& value) {
static_assert(std::is_same<typename std::decay<ValueType>::type, mfxU32>::value,
"ParamCreator<mfxVariant> supports mfxU32 at the moment. "
"Feel free to extend for more types");
mfxVariant create (const std::string& name, ValueType&& value, bool is_major_flag = false) {
cv::util::suppress_unused_warning(is_major_flag);
return create_impl(name, value);
}
private:
@@ -44,6 +41,18 @@ private:
ret.Data.U32 = value;
return ret;
}
mfxVariant create_impl(const std::string&, mfxI64 value) {
mfxVariant ret;
ret.Type = MFX_VARIANT_TYPE_I64;
ret.Data.I64 = value;
return ret;
}
mfxVariant create_impl(const std::string&, mfxU64 value) {
mfxVariant ret;
ret.Type = MFX_VARIANT_TYPE_U64;
ret.Data.U64 = value;
return ret;
}
};
template<typename ValueType>
@@ -67,14 +76,16 @@ std::vector<ValueType> get_params_from_string(const std::string& str) {
std::string value = line.substr(name_endline_pos + 2);
ParamCreator<ValueType> creator;
if (name == "mfxImplDescription.Impl") {
if (name == CfgParam::implementation_name()) {
ret.push_back(creator.create<mfxU32>(name, cstr_to_mfx_impl(value.c_str())));
} else if (name == "mfxImplDescription.mfxDecoderDescription.decoder.CodecID") {
} else if (name == CfgParam::decoder_id_name()) {
ret.push_back(creator.create<mfxU32>(name, cstr_to_mfx_codec_id(value.c_str())));
} else if (name == "mfxImplDescription.AccelerationMode") {
} else if (name == CfgParam::acceleration_mode_name()) {
ret.push_back(creator.create<mfxU32>(name, cstr_to_mfx_accel_mode(value.c_str())));
} else if (name == "mfxImplDescription.ApiVersion.Version") {
ret.push_back(creator.create<mfxU32>(name, cstr_to_mfx_version(value.c_str())));
} else if (name == CfgParam::frames_pool_size_name()) {
ret.push_back(creator.create(name, strtoull_or_throw(value.c_str()), false));
} else {
GAPI_LOG_DEBUG(nullptr, "Cannot parse configuration param, name: " << name <<
", value: " << value);
@@ -116,6 +127,32 @@ mfxVariant cfg_param_to_mfx_variant(const CfgParam& cfg_val) {
}), cfg_val.get_value());
return ret;
}
size_t strtoull_or_throw(const char* str) {
char *end_ptr = nullptr;
errno = 0;
size_t ret = strtoull(str, &end_ptr, 10);
if ((end_ptr == str) ||
((ret == LONG_MAX || ret == LONG_MIN) && errno == ERANGE)) {
// nothing parsed from the string, handle errors or exit
GAPI_LOG_WARNING(nullptr, "strtoull failed for: " << str);
GAPI_Assert(false && "strtoull_or_throw");
}
return ret;
}
int64_t strtoll_or_throw(const char* str) {
char *end_ptr = nullptr;
errno = 0;
int64_t ret = strtoll(str, &end_ptr, 10);
if ((end_ptr == str) ||
((ret == LONG_MAX || ret == LONG_MIN) && errno == ERANGE)) {
// nothing parsed from the string, handle errors or exit
GAPI_LOG_WARNING(nullptr, "strtoll failed for: " << str);
GAPI_Assert(false && "strtoll_or_throw");
}
return ret;
}
} // namespace onevpl
} // namespace wip
} // namespace gapi
@@ -8,12 +8,7 @@
#define GAPI_STREAMING_ONEVPL_CFG_PARAM_PARSER_HPP
#ifdef HAVE_ONEVPL
#if (MFX_VERSION >= 2000)
#include <vpl/mfxdispatcher.h>
#endif // MFX_VERSION
#include <vpl/mfx.h>
#include <vpl/mfxvideo.h>
#include "streaming/onevpl/onevpl_export.hpp"
#include <map>
#include <string>
@@ -31,10 +26,14 @@ std::vector<ValueType> get_params_from_string(const std::string& str);
template <typename ReturnType>
struct ParamCreator {
template<typename ValueType>
ReturnType create(const std::string& name, ValueType&& value);
ReturnType create(const std::string& name, ValueType&& value, bool is_major = false);
};
mfxVariant cfg_param_to_mfx_variant(const CfgParam& value);
size_t strtoull_or_throw(const char* str);
int64_t strtoll_or_throw(const char* str);
} // namespace onevpl
} // namespace wip
} // namespace gapi
@@ -2,8 +2,7 @@
#define GAPI_STREAMING_ONEVPL_DATA_PROVIDER_DEFINES_HPP
#ifdef HAVE_ONEVPL
#include <vpl/mfxcommon.h>
#include <vpl/mfxvideo.h>
#include "streaming/onevpl/onevpl_export.hpp"
#endif // HAVE_ONEVPL
#include <opencv2/gapi/own/assert.hpp>
@@ -25,13 +25,14 @@ IDataProvider::Ptr DataProviderDispatcher::create(const std::string& file_path,
// Look-up CodecId from input params
// If set then raw data provider is preferred
GAPI_LOG_DEBUG(nullptr, "try find explicit cfg param\"mfxImplDescription.mfxDecoderDescription.decoder.CodecID\"");
GAPI_LOG_DEBUG(nullptr, "try find explicit cfg param \"" <<
CfgParam::decoder_id_name() <<"\"");
auto codec_it =
std::find_if(cfg_params.begin(), cfg_params.end(), [] (const CfgParam& value) {
return value.get_name() == "mfxImplDescription.mfxDecoderDescription.decoder.CodecID";
return value.get_name() == CfgParam::decoder_id_name();
});
if (codec_it != cfg_params.end()) {
GAPI_LOG_DEBUG(nullptr, "Dispatcher found \"mfxImplDescription.mfxDecoderDescription.decoder.CodecID\""
GAPI_LOG_DEBUG(nullptr, "Dispatcher found \"" << CfgParam::decoder_id_name() << "\""
" so try on raw data provider at first");
try {
@@ -5,8 +5,7 @@
// Copyright (C) 2021 Intel Corporation
#ifdef HAVE_ONEVPL
#include <vpl/mfxvideo.h>
#include <vpl/mfxjpeg.h>
#include "streaming/onevpl/onevpl_export.hpp"
#endif // HAVE_ONEVPL
#include <errno.h>
@@ -13,7 +13,7 @@
#include <queue>
#ifdef HAVE_ONEVPL
#include <vpl/mfxvideo.h>
#include "streaming/onevpl/onevpl_export.hpp"
#ifdef _WIN32
#define NOMINMAX
@@ -16,6 +16,7 @@
#include "streaming/onevpl/engine/decode/decode_session.hpp"
#include "streaming/onevpl/accelerators/accel_policy_interface.hpp"
#include "streaming/onevpl/accelerators/surface/surface.hpp"
#include "streaming/onevpl/cfg_params_parser.hpp"
#include "streaming/onevpl/utils.hpp"
#include "logger.hpp"
@@ -24,95 +25,6 @@ namespace cv {
namespace gapi {
namespace wip {
namespace onevpl {
/* UTILS */
mfxU32 GetSurfaceSize(mfxU32 FourCC, mfxU32 width, mfxU32 height) {
mfxU32 nbytes = 0;
mfxU32 half_width = width / 2;
mfxU32 half_height = height / 2;
switch (FourCC) {
case MFX_FOURCC_I420:
case MFX_FOURCC_NV12:
nbytes = width * height + 2 * half_width * half_height;
break;
case MFX_FOURCC_I010:
case MFX_FOURCC_P010:
nbytes = width * height + 2 * half_width * half_height;
nbytes *= 2;
break;
case MFX_FOURCC_RGB4:
nbytes = width * height * 4;
break;
default:
GAPI_LOG_WARNING(nullptr, "Unsupported FourCC requested: " << FourCC);
GAPI_Assert(false && "Unsupported FourCC requested");
break;
}
return nbytes;
}
surface_ptr_t create_surface_RGB4(mfxFrameInfo frameInfo,
std::shared_ptr<void> out_buf_ptr,
size_t out_buf_ptr_offset,
size_t out_buf_size)
{
mfxU8* buf = reinterpret_cast<mfxU8*>(out_buf_ptr.get());
mfxU16 surfW = frameInfo.Width * 4;
mfxU16 surfH = frameInfo.Height;
(void)surfH;
// TODO more intelligent check
if (out_buf_size <= out_buf_ptr_offset) {
throw std::runtime_error(std::string("Insufficient buffer size: ") +
std::to_string(out_buf_size) + ", buffer offset: " +
std::to_string(out_buf_ptr_offset) +
", expected surface width: " + std::to_string(surfW) +
", height: " + std::to_string(surfH));
}
std::unique_ptr<mfxFrameSurface1> handle(new mfxFrameSurface1);
memset(handle.get(), 0, sizeof(mfxFrameSurface1));
handle->Info = frameInfo;
handle->Data.B = buf + out_buf_ptr_offset;
handle->Data.G = handle->Data.B + 1;
handle->Data.R = handle->Data.B + 2;
handle->Data.A = handle->Data.B + 3;
handle->Data.Pitch = surfW;
return Surface::create_surface(std::move(handle), out_buf_ptr);
}
surface_ptr_t create_surface_other(mfxFrameInfo frameInfo,
std::shared_ptr<void> out_buf_ptr,
size_t out_buf_ptr_offset,
size_t out_buf_size)
{
mfxU8* buf = reinterpret_cast<mfxU8*>(out_buf_ptr.get());
mfxU16 surfH = frameInfo.Height;
mfxU16 surfW = (frameInfo.FourCC == MFX_FOURCC_P010) ? frameInfo.Width * 2 : frameInfo.Width;
// TODO more intelligent check
if (out_buf_size <=
out_buf_ptr_offset + (surfW * surfH) + ((surfW / 2) * (surfH / 2))) {
throw std::runtime_error(std::string("Insufficient buffer size: ") +
std::to_string(out_buf_size) + ", buffer offset: " +
std::to_string(out_buf_ptr_offset) +
", expected surface width: " + std::to_string(surfW) +
", height: " + std::to_string(surfH));
}
std::unique_ptr<mfxFrameSurface1> handle(new mfxFrameSurface1);
memset(handle.get(), 0, sizeof(mfxFrameSurface1));
handle->Info = frameInfo;
handle->Data.Y = buf + out_buf_ptr_offset;
handle->Data.U = buf + out_buf_ptr_offset + (surfW * surfH);
handle->Data.V = handle->Data.U + ((surfW / 2) * (surfH / 2));
handle->Data.Pitch = surfW;
return Surface::create_surface(std::move(handle), out_buf_ptr);
}
VPLLegacyDecodeEngine::VPLLegacyDecodeEngine(std::unique_ptr<VPLAccelerationPolicy>&& accel)
: ProcessingEngineBase(std::move(accel)) {
@@ -146,8 +58,9 @@ VPLLegacyDecodeEngine::VPLLegacyDecodeEngine(std::unique_ptr<VPLAccelerationPoli
// enqueue decode operation with current session surface
my_sess.last_status =
MFXVideoDECODE_DecodeFrameAsync(my_sess.session,
my_sess.last_status == MFX_ERR_NONE
(my_sess.data_provider || (my_sess.stream && my_sess.stream->DataLength))
? my_sess.stream.get()
: nullptr, /* No more data to read, start decode draining mode*/
my_sess.procesing_surface_ptr.lock()->get_handle(),
&sync_pair.second,
@@ -164,33 +77,30 @@ VPLLegacyDecodeEngine::VPLLegacyDecodeEngine(std::unique_ptr<VPLAccelerationPoli
}
my_sess.last_status =
MFXVideoDECODE_DecodeFrameAsync(my_sess.session,
&my_sess.stream,
my_sess.stream.get(),
my_sess.procesing_surface_ptr.lock()->get_handle(),
&sync_pair.second,
&sync_pair.first);
} catch (const std::runtime_error& ex) {
// NB: not an error, yield CPU ticks to check
// surface availability at a next phase.
// But print WARNING to notify user about pipeline stuck
GAPI_LOG_WARNING(nullptr, "[" << my_sess.session <<
"] has no surface, reason: " <<
ex.what());
// TODO it is supposed to place `break;` here
// to simulate `yield`-like behavior.
// Further DX11 intergation logic claims more strict rules
// for enqueue surfaces. If no free surface
// is available it had better to wait free one by checking
// for async result than waste time in spinning.
//
// Put it as-is at now to not break
// current compatibility and avoid further merge-conflicts
break;
}
}
if (my_sess.last_status == MFX_ERR_NONE) {
my_sess.sync_queue.emplace(sync_pair);
} else if (my_sess.last_status != MFX_ERR_MORE_DATA) /* suppress MFX_ERR_MORE_DATA warning */ {
GAPI_LOG_WARNING(nullptr, "pending ops count: " << my_sess.sync_queue.size() <<
GAPI_LOG_WARNING(nullptr, "decode pending ops count: " <<
my_sess.sync_queue.size() <<
", sync id: " << sync_pair.first <<
", status: " << mfxstatus_to_string(my_sess.last_status));
", status: " <<
mfxstatus_to_string(my_sess.last_status));
}
return ExecutionStatus::Continue;
},
@@ -198,20 +108,26 @@ VPLLegacyDecodeEngine::VPLLegacyDecodeEngine(std::unique_ptr<VPLAccelerationPoli
[this] (EngineSession& sess) -> ExecutionStatus
{
LegacyDecodeSession& my_sess = static_cast<LegacyDecodeSession&>(sess);
if (!my_sess.sync_queue.empty()) // FIFO: check the oldest async operation complete
{
LegacyDecodeSession::op_handle_t& pending_op = my_sess.sync_queue.front();
sess.last_status = MFXVideoCORE_SyncOperation(sess.session, pending_op.first, 0);
do {
if (!my_sess.sync_queue.empty()) { // FIFO: check the oldest async operation complete
LegacyDecodeSession::op_handle_t& pending_op = my_sess.sync_queue.front();
sess.last_status = MFXVideoCORE_SyncOperation(sess.session, pending_op.first, 0);
GAPI_LOG_DEBUG(nullptr, "pending ops count: " << my_sess.sync_queue.size() <<
", sync id: " << pending_op.first <<
", status: " << mfxstatus_to_string(my_sess.last_status));
GAPI_LOG_DEBUG(nullptr, "pending ops count: " <<
my_sess.sync_queue.size() <<
", sync id: " <<
pending_op.first <<
", surface: " <<
pending_op.second <<
", status: " <<
mfxstatus_to_string(my_sess.last_status));
// put frames in ready queue on success
if (MFX_ERR_NONE == sess.last_status) {
on_frame_ready(my_sess, pending_op.second);
// put frames in ready queue on success
if (MFX_ERR_NONE == sess.last_status) {
on_frame_ready(my_sess, pending_op.second);
}
}
}
} while (MFX_ERR_NONE == sess.last_status && !my_sess.sync_queue.empty());
return ExecutionStatus::Continue;
},
// 4) Falls back on generic status procesing
@@ -222,45 +138,138 @@ VPLLegacyDecodeEngine::VPLLegacyDecodeEngine(std::unique_ptr<VPLAccelerationPoli
);
}
void VPLLegacyDecodeEngine::initialize_session(mfxSession mfx_session,
DecoderParams&& decoder_param,
std::shared_ptr<onevpl::IDataProvider> provider)
{
mfxFrameAllocRequest decRequest = {};
ProcessingEngineBase::session_ptr
VPLLegacyDecodeEngine::initialize_session(mfxSession mfx_session,
const std::vector<CfgParam>& cfg_params,
std::shared_ptr<IDataProvider> provider) {
GAPI_DbgAssert(provider && "Cannot create decoder, data provider is nullptr");
// init session
acceleration_policy->init(mfx_session);
// Get codec ID from data provider
IDataProvider::mfx_codec_id_type decoder_id_name = provider->get_mfx_codec_id();
// Prepare video param
mfxVideoParam mfxDecParams {};
mfxDecParams.mfx.CodecId = decoder_id_name;
// set memory stream direction accroding to accelearion policy device type
IDeviceSelector::DeviceScoreTable devices = acceleration_policy->get_device_selector()->select_devices();
GAPI_Assert(devices.size() == 1 && "Multiple(or zero) acceleration devices case is unsupported");
AccelType accel_type = devices.begin()->second.get_type();
if (accel_type == AccelType::DX11) {
mfxDecParams.IOPattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY;
} else if (accel_type == AccelType::HOST) {
mfxDecParams.IOPattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
} else {
GAPI_Assert(false && "unsupported AccelType from device selector");
}
// try fetch & decode input data
mfxStatus sts = MFX_ERR_NONE;
std::shared_ptr<IDataProvider::mfx_bitstream> bitstream{};
bool can_fetch_data = false;
do {
can_fetch_data = provider->fetch_bitstream_data(bitstream);
if (!can_fetch_data) {
// must fetch data always because EOF critical at this point
GAPI_LOG_WARNING(nullptr, "cannot decode header from provider: " << provider.get() <<
". Unexpected EOF");
throw std::runtime_error("Error reading bitstream: EOF");
}
sts = MFXVideoDECODE_DecodeHeader(mfx_session, bitstream.get(), &mfxDecParams);
if(MFX_ERR_NONE != sts && MFX_ERR_MORE_DATA != sts) {
throw std::runtime_error("Error decoding header, error: " +
mfxstatus_to_string(sts));
}
} while (sts == MFX_ERR_MORE_DATA && !provider->empty());
if (MFX_ERR_NONE != sts) {
GAPI_LOG_WARNING(nullptr, "cannot decode header from provider: " << provider.get()
<< ". Make sure data source is valid and/or "
"\"" << CfgParam::decoder_id_name() << "\""
" has correct value in case of demultiplexed raw input");
throw std::runtime_error("Error decode header, error: " +
mfxstatus_to_string(sts));
}
mfxFrameAllocRequest decRequest {};
// Query number required surfaces for decoder
MFXVideoDECODE_QueryIOSurf(mfx_session, &decoder_param.param, &decRequest);
MFXVideoDECODE_QueryIOSurf(mfx_session, &mfxDecParams, &decRequest);
// External (application) allocation of decode surfaces
GAPI_LOG_DEBUG(nullptr, "Query IOSurf for session: " << mfx_session <<
", mfxFrameAllocRequest.NumFrameMin: " << decRequest.NumFrameMin <<
", mfxFrameAllocRequest.NumFrameSuggested: " << decRequest.NumFrameSuggested <<
", mfxFrameAllocRequest.Type: " << decRequest.Type);
mfxU32 singleSurfaceSize = GetSurfaceSize(decoder_param.param.mfx.FrameInfo.FourCC,
decoder_param.param.mfx.FrameInfo.Width,
decoder_param.param.mfx.FrameInfo.Height);
if (!singleSurfaceSize) {
throw std::runtime_error("Cannot determine surface size for: fourCC" +
std::to_string(decoder_param.param.mfx.FrameInfo.FourCC) +
", width: " + std::to_string(decoder_param.param.mfx.FrameInfo.Width) +
", height: " + std::to_string(decoder_param.param.mfx.FrameInfo.Height));
// NB: override NumFrameSuggested preallocation size (how many frames we can hold)
size_t preallocated_frames_count = decRequest.NumFrameSuggested;
// NB: if you see bunch of WARNING about "cannot get free surface from pool"
// and have abundant RAM size then increase `preallocated_frames_count`
// to keep more free surfaces in a round. Otherwise VPL decode pipeline will be waiting
// till application is freeing unusable surface on its side.
//
auto queue_capacity_it = std::find_if(cfg_params.begin(), cfg_params.end(), [] (const CfgParam& value) {
return value.get_name() == CfgParam::frames_pool_size_name();
});
if (queue_capacity_it != cfg_params.end()) {
cv::util::visit(cv::util::overload_lambdas(
[&preallocated_frames_count](uint8_t value) { preallocated_frames_count = static_cast<size_t>(value); },
[&preallocated_frames_count](int8_t value) { preallocated_frames_count = static_cast<size_t>(value); },
[&preallocated_frames_count](uint16_t value) { preallocated_frames_count = static_cast<size_t>(value); },
[&preallocated_frames_count](int16_t value) { preallocated_frames_count = static_cast<size_t>(value); },
[&preallocated_frames_count](uint32_t value) { preallocated_frames_count = static_cast<size_t>(value); },
[&preallocated_frames_count](int32_t value) { preallocated_frames_count = static_cast<size_t>(value); },
[&preallocated_frames_count](uint64_t value) { preallocated_frames_count = static_cast<size_t>(value); },
[&preallocated_frames_count](int64_t value) { preallocated_frames_count = static_cast<size_t>(value); },
[&preallocated_frames_count](float_t value) { preallocated_frames_count = static_cast<size_t>(value); },
[&preallocated_frames_count](double_t value) { preallocated_frames_count = static_cast<size_t>(value); },
[&preallocated_frames_count](void*) { GAPI_Assert(false && "`void*` is unsupported type"); },
[&preallocated_frames_count](const std::string& value) {
preallocated_frames_count = strtoull_or_throw(value.c_str());
}),
queue_capacity_it->get_value());
GAPI_LOG_INFO(nullptr, "Try to use CfgParam \"" << CfgParam::frames_pool_size_name() << "\": " <<
preallocated_frames_count << ", for session: " << mfx_session);
}
if (preallocated_frames_count < decRequest.NumFrameMin) {
GAPI_LOG_WARNING(nullptr, "Cannot proceed with CfgParam \"" << CfgParam::frames_pool_size_name() << "\": " <<
preallocated_frames_count << ". It must be equal or greater than "
"mfxFrameAllocRequest.NumFrameMin: " << decRequest.NumFrameMin);
throw std::runtime_error(std::string("Invalid value of param: ") +
CfgParam::frames_pool_size_name() + ", underflow");
} else {
if (static_cast<size_t>(std::numeric_limits<mfxU16>::max()) < preallocated_frames_count) {
GAPI_LOG_WARNING(nullptr, "Cannot proceed with CfgParam \"" << CfgParam::frames_pool_size_name() << "\": " <<
preallocated_frames_count << ". It must not be equal than " <<
std::numeric_limits<mfxU16>::max());
throw std::runtime_error(std::string("Invalid value of param: ") +
CfgParam::frames_pool_size_name() + ", overflow");
}
decRequest.NumFrameSuggested = static_cast<mfxU16>(preallocated_frames_count);
GAPI_LOG_DEBUG(nullptr, "mfxFrameAllocRequest overriden by user input for session: " << mfx_session <<
", mfxFrameAllocRequest.NumFrameMin: " << decRequest.NumFrameMin <<
", mfxFrameAllocRequest.NumFrameSuggested: " << decRequest.NumFrameSuggested <<
", mfxFrameAllocRequest.Type: " << decRequest.Type);
}
const auto &frameInfo = decoder_param.param.mfx.FrameInfo;
auto surface_creator =
[&frameInfo] (std::shared_ptr<void> out_buf_ptr, size_t out_buf_ptr_offset,
size_t out_buf_size) -> surface_ptr_t {
return (frameInfo.FourCC == MFX_FOURCC_RGB4) ?
create_surface_RGB4(frameInfo, out_buf_ptr, out_buf_ptr_offset,
out_buf_size) :
create_surface_other(frameInfo, out_buf_ptr, out_buf_ptr_offset,
out_buf_size);};
//TODO Configure preallocation size (how many frames we can hold)
const size_t preallocated_frames_count = 30;
VPLAccelerationPolicy::pool_key_t decode_pool_key =
acceleration_policy->create_surface_pool(decRequest.NumFrameSuggested * preallocated_frames_count,
singleSurfaceSize,
surface_creator);
acceleration_policy->create_surface_pool(decRequest, mfxDecParams);
// Input parameters finished, now initialize decode
// create decoder for session accoring to header recovered from source file
sts = MFXVideoDECODE_Init(mfx_session, &mfxDecParams);
if (MFX_ERR_NONE != sts) {
throw std::runtime_error("Error initializing Decode, error: " +
mfxstatus_to_string(sts));
}
DecoderParams decoder_param {bitstream, mfxDecParams};
// create session
std::shared_ptr<LegacyDecodeSession> sess_ptr =
@@ -271,6 +280,7 @@ void VPLLegacyDecodeEngine::initialize_session(mfxSession mfx_session,
sess_ptr->init_surface_pool(decode_pool_key);
// prepare working decode surface
sess_ptr->swap_surface(*this);
return sess_ptr;
}
ProcessingEngineBase::ExecutionStatus VPLLegacyDecodeEngine::execute_op(operation_t& op, EngineSession& sess) {
@@ -303,14 +313,13 @@ ProcessingEngineBase::ExecutionStatus VPLLegacyDecodeEngine::process_error(mfxSt
sess.swap_surface(*this);
return ExecutionStatus::Continue;
} catch (const std::runtime_error& ex) {
GAPI_LOG_WARNING(nullptr, "[" << sess.session << "] error: " << ex.what() <<
"Abort");
// TODO it is supposed to be `break;` here in future PR
GAPI_LOG_WARNING(nullptr, "[" << sess.session << "] error: " << ex.what());
return ExecutionStatus::Continue; // read more data
}
}
case MFX_ERR_MORE_DATA: // The function requires more bitstream at input before decoding can proceed
if (!sess.data_provider || sess.data_provider->empty()) {
// No more data to drain from decoder, start encode draining mode
if (!(sess.data_provider || (sess.stream && sess.stream->DataLength))) {
// No more data to drain from decoder
return ExecutionStatus::Processed;
}
else
@@ -326,7 +335,7 @@ ProcessingEngineBase::ExecutionStatus VPLLegacyDecodeEngine::process_error(mfxSt
return ExecutionStatus::Continue;
} catch (const std::runtime_error& ex) {
GAPI_LOG_WARNING(nullptr, "[" << sess.session << "] error: " << ex.what());
// TODO it is supposed to be `break;` here in future PR
return ExecutionStatus::Continue; // read more data
}
break;
}
@@ -371,9 +380,8 @@ ProcessingEngineBase::ExecutionStatus VPLLegacyDecodeEngine::process_error(mfxSt
sess.swap_surface(*this);
return ExecutionStatus::Continue;
} catch (const std::runtime_error& ex) {
GAPI_LOG_WARNING(nullptr, "[" << sess.session << "] error: " << ex.what() <<
"Abort");
// TODO it is supposed to be `break;` here in future PR
GAPI_LOG_WARNING(nullptr, "[" << sess.session << "] error: " << ex.what());
return ExecutionStatus::Continue;
}
default:
GAPI_LOG_WARNING(nullptr, "Unknown status code: " << mfxstatus_to_string(status) <<
@@ -12,10 +12,7 @@
#include "streaming/onevpl/engine/processing_engine_base.hpp"
#ifdef HAVE_ONEVPL
#if (MFX_VERSION >= 2000)
#include <vpl/mfxdispatcher.h>
#endif
#include <vpl/mfx.h>
#include "streaming/onevpl/onevpl_export.hpp"
namespace cv {
namespace gapi {
@@ -31,8 +28,9 @@ class VPLLegacyDecodeEngine : public ProcessingEngineBase {
public:
VPLLegacyDecodeEngine(std::unique_ptr<VPLAccelerationPolicy>&& accel);
void initialize_session(mfxSession mfx_session, DecoderParams&& decoder_param,
std::shared_ptr<IDataProvider> provider) override;
session_ptr initialize_session(mfxSession mfx_session,
const std::vector<CfgParam>& cfg_params,
std::shared_ptr<IDataProvider> provider) override;
private:
ExecutionStatus execute_op(operation_t& op, EngineSession& sess) override;
@@ -52,8 +52,10 @@ void LegacyDecodeSession::swap_surface(VPLLegacyDecodeEngine& engine) {
procesing_surface_ptr = cand;
} catch (const std::runtime_error& ex) {
GAPI_LOG_WARNING(nullptr, "[" << session << "] error: " << ex.what() <<
"Abort");
GAPI_LOG_WARNING(nullptr, "[" << session << "] error: " << ex.what());
// Delegate exception processing on caller
throw;
}
}
@@ -72,6 +74,10 @@ Data::Meta LegacyDecodeSession::generate_frame_meta() {
};
return meta;
}
const mfxVideoParam& LegacyDecodeSession::get_video_param() const {
return mfx_decoder_param;
}
} // namespace onevpl
} // namespace wip
} // namespace gapi
@@ -15,10 +15,7 @@
#include "streaming/onevpl/engine/engine_session.hpp"
#include "streaming/onevpl/accelerators/accel_policy_interface.hpp"
#ifdef HAVE_ONEVPL
#if (MFX_VERSION >= 2000)
#include <vpl/mfxdispatcher.h>
#endif
#include <vpl/mfx.h>
#include "streaming/onevpl/onevpl_export.hpp"
namespace cv {
namespace gapi {
@@ -40,11 +37,11 @@ public:
void swap_surface(VPLLegacyDecodeEngine& engine);
void init_surface_pool(VPLAccelerationPolicy::pool_key_t key);
Data::Meta generate_frame_meta();
const mfxVideoParam& get_video_param() const override;
private:
mfxVideoParam mfx_decoder_param;
std::shared_ptr<IDataProvider> data_provider;
Data::Meta generate_frame_meta();
private:
VPLAccelerationPolicy::pool_key_t decoder_pool_id;
mfxFrameAllocRequest request;
@@ -18,7 +18,7 @@
#include <opencv2/gapi/streaming/onevpl/data_provider_interface.hpp>
#ifdef HAVE_ONEVPL
#include <vpl/mfxvideo.h>
#include "streaming/onevpl/onevpl_export.hpp"
namespace cv {
namespace gapi {
@@ -40,6 +40,8 @@ struct GAPI_EXPORTS EngineSession {
EngineSession(mfxSession sess, std::shared_ptr<IDataProvider::mfx_bitstream>&& str);
std::string error_code_to_str() const;
virtual ~EngineSession();
virtual const mfxVideoParam& get_video_param() const = 0;
};
} // namespace onevpl
} // namespace wip
@@ -23,7 +23,8 @@ ProcessingEngineBase::ProcessingEngineBase(std::unique_ptr<VPLAccelerationPolicy
}
ProcessingEngineBase::~ProcessingEngineBase() {
GAPI_LOG_INFO(nullptr, "destroyed");
GAPI_LOG_INFO(nullptr, "destroyed, elapsed sessions count: " << sessions.size());
sessions.clear();
}
ProcessingEngineBase::ExecutionStatus ProcessingEngineBase::process(mfxSession session) {
@@ -42,6 +43,7 @@ ProcessingEngineBase::ExecutionStatus ProcessingEngineBase::process(mfxSession s
{
exec_data.op_id = 0;
}
cv::util::suppress_unused_warning(old_op_id);
GAPI_LOG_DEBUG(nullptr, "[" << session <<"] finish op id: " << old_op_id <<
", " << processing_session->error_code_to_str() <<
", " << ProcessingEngineBase::status_to_string(status) <<
@@ -57,6 +59,7 @@ ProcessingEngineBase::ExecutionStatus ProcessingEngineBase::process(mfxSession s
}
if (status == ExecutionStatus::Processed) {
GAPI_LOG_INFO(nullptr, "Processed [" << session << "]");
sessions.erase(sess_it);
execution_table.erase(session);
}
@@ -90,6 +93,7 @@ void ProcessingEngineBase::get_frame(Data &data)
{
data = ready_frames.front();
ready_frames.pop();
GAPI_LOG_DEBUG(nullptr, " elapsed ready frames count: " << ready_frames.size());
}
const VPLAccelerationPolicy* ProcessingEngineBase::get_accel() const {
@@ -8,6 +8,7 @@
#define GAPI_STREAMING_ONEVPL_ENGINE_PROCESSING_ENGINE_BASE_HPP
#include <queue>
#include <opencv2/gapi/streaming/onevpl/cfg_params.hpp>
#include "streaming/onevpl/engine/engine_session.hpp"
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
@@ -49,9 +50,9 @@ public:
ProcessingEngineBase(std::unique_ptr<VPLAccelerationPolicy>&& accel);
virtual ~ProcessingEngineBase();
virtual void initialize_session(mfxSession mfx_session,
DecoderParams&& decoder_param,
std::shared_ptr<IDataProvider> provider) = 0;
virtual session_ptr initialize_session(mfxSession mfx_session,
const std::vector<CfgParam>& cfg_params,
std::shared_ptr<IDataProvider> provider) = 0;
ExecutionStatus process(mfxSession session);
size_t get_ready_frames_count() const;
@@ -28,14 +28,14 @@ FileDataProvider::FileDataProvider(const std::string& file_path,
codec_params.size());
auto codec_it =
std::find_if(codec_params.begin(), codec_params.end(), [] (const CfgParam& value) {
return value.get_name() == "mfxImplDescription.mfxDecoderDescription.decoder.CodecID";
return value.get_name() == CfgParam::decoder_id_name();
});
if (codec_it == codec_params.end())
{
GAPI_LOG_WARNING(nullptr, "[" << this << "] " <<
"\"mfxImplDescription.mfxDecoderDescription.decoder.CodecID\" "
"\"" << CfgParam::decoder_id_name() << "\" "
"is absent, total param count" << codec_params.size());
throw DataProviderUnsupportedException("\"mfxImplDescription.mfxDecoderDescription.decoder.CodecID\" "
throw DataProviderUnsupportedException(std::string("\"") + CfgParam::decoder_id_name() + "\" "
"is required for FileDataProvider");
}
@@ -0,0 +1,25 @@
#ifndef GAPI_STREAMING_ONEVPL_EXPORT_HPP
#define GAPI_STREAMING_ONEVPL_EXPORT_HPP
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4201)
#pragma warning(disable : 4302)
#pragma warning(disable : 4311)
#pragma warning(disable : 4312)
#endif // defined(_MSC_VER)
#ifdef HAVE_ONEVPL
#if (MFX_VERSION >= 2000)
#include <vpl/mfxdispatcher.h>
#endif // MFX_VERSION
#include <vpl/mfx.h>
#include <vpl/mfxvideo.h>
#endif // HAVE_ONEVPL
#if defined(_MSC_VER)
#pragma warning(pop)
#endif // defined(_MSC_VER)
#endif // GAPI_STREAMING_ONEVPL_EXPORT_HPP
@@ -53,14 +53,15 @@ GSource::Priv::Priv() :
mfx_session(),
description(),
description_is_valid(false),
engine()
engine(),
consumed_frames_count()
{
GAPI_LOG_INFO(nullptr, "Initialized MFX handle: " << mfx_handle);
}
GSource::Priv::Priv(std::shared_ptr<IDataProvider> provider,
const std::vector<CfgParam>& params,
std::shared_ptr<IDeviceSelector>) :
std::shared_ptr<IDeviceSelector> device_selector) :
GSource::Priv()
{
// Enable Config
@@ -193,13 +194,9 @@ GSource::Priv::Priv(std::shared_ptr<IDataProvider> provider,
GAPI_LOG_INFO(nullptr, "Initialized MFX session: " << mfx_session);
// initialize decoder
// Find codec ID from config
IDataProvider::mfx_codec_id_type decoder_id = provider->get_mfx_codec_id();
// create session driving engine if required
if (!engine) {
std::unique_ptr<VPLAccelerationPolicy> acceleration = initializeHWAccel();
std::unique_ptr<VPLAccelerationPolicy> acceleration = initializeHWAccel(device_selector);
// TODO Add factory static method in ProcessingEngineBase
if (mfx_impl_description->ApiVersion.Major >= VPL_NEW_API_MAJOR_VERSION) {
@@ -211,106 +208,54 @@ GSource::Priv::Priv(std::shared_ptr<IDataProvider> provider,
}
}
//create decoder for session accoring to header recovered from source file
DecoderParams decoder_param = create_decoder_from_file(decoder_id, provider);
// create engine session for processing mfx session pipeline
engine->initialize_session(mfx_session, std::move(decoder_param),
provider);
auto engine_session_ptr = engine->initialize_session(mfx_session, cfg_params,
provider);
const mfxVideoParam& video_param = engine_session_ptr->get_video_param();
// set valid description
description.size = cv::Size {
video_param.mfx.FrameInfo.Width,
video_param.mfx.FrameInfo.Height};
switch(video_param.mfx.FrameInfo.FourCC) {
case MFX_FOURCC_I420:
throw std::runtime_error("Cannot parse GMetaArg description: MediaFrame doesn't support I420 type");
case MFX_FOURCC_NV12:
description.fmt = cv::MediaFormat::NV12;
break;
default:
throw std::runtime_error("Cannot parse GMetaArg description: MediaFrame unknown 'fmt' type: " +
std::to_string(video_param.mfx.FrameInfo.FourCC));
}
description_is_valid = true;
//prepare session for processing
engine->process(mfx_session);
}
GSource::Priv::~Priv()
{
GSource::Priv::~Priv() {
engine.reset();
GAPI_LOG_INFO(nullptr, "consumed frames count: " << consumed_frames_count);
GAPI_LOG_INFO(nullptr, "Unload MFX implementation description: " << mfx_impl_description);
MFXDispReleaseImplDescription(mfx_handle, mfx_impl_description);
GAPI_LOG_INFO(nullptr, "Unload MFX handle: " << mfx_handle);
MFXUnload(mfx_handle);
}
DecoderParams GSource::Priv::create_decoder_from_file(uint32_t decoder_id,
std::shared_ptr<IDataProvider> provider)
{
GAPI_DbgAssert(provider && "Cannot create decoder, data provider is nullptr");
std::shared_ptr<IDataProvider::mfx_bitstream> bitstream{};
// Retrieve the frame information from input stream
mfxVideoParam mfxDecParams {};
mfxDecParams.mfx.CodecId = decoder_id;
mfxDecParams.IOPattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;//MFX_IOPATTERN_OUT_VIDEO_MEMORY;
mfxStatus sts = MFX_ERR_NONE;
bool can_fetch_data = false;
do {
can_fetch_data = provider->fetch_bitstream_data(bitstream);
if (!can_fetch_data) {
// must fetch data always because EOF critical at this point
GAPI_LOG_WARNING(nullptr, "cannot decode header from provider: " << provider.get() <<
". Unexpected EOF");
throw std::runtime_error("Error reading bitstream: EOF");
}
sts = MFXVideoDECODE_DecodeHeader(mfx_session, bitstream.get(), &mfxDecParams);
if(MFX_ERR_NONE != sts && MFX_ERR_MORE_DATA != sts) {
throw std::runtime_error("Error decoding header, error: " +
mfxstatus_to_string(sts));
}
} while (sts == MFX_ERR_MORE_DATA && !provider->empty());
if (MFX_ERR_NONE != sts) {
GAPI_LOG_WARNING(nullptr, "cannot decode header from provider: " << provider.get()
<< ". Make sure data source is valid and/or "
"\"mfxImplDescription.mfxDecoderDescription.decoder.CodecID\""
" has correct value in case of demultiplexed raw input");
throw std::runtime_error("Error decode header, error: " +
mfxstatus_to_string(sts));
}
// Input parameters finished, now initialize decode
sts = MFXVideoDECODE_Init(mfx_session, &mfxDecParams);
if (MFX_ERR_NONE != sts) {
throw std::runtime_error("Error initializing Decode, error: " +
mfxstatus_to_string(sts));
}
// set valid description
description.size = cv::Size {
mfxDecParams.mfx.FrameInfo.Width,
mfxDecParams.mfx.FrameInfo.Height};
switch(mfxDecParams.mfx.FrameInfo.FourCC) {
case MFX_FOURCC_I420:
GAPI_Assert(false && "Cannot create GMetaArg description: "
"MediaFrame doesn't support I420 type");
case MFX_FOURCC_NV12:
description.fmt = cv::MediaFormat::NV12;
break;
default:
{
GAPI_LOG_WARNING(nullptr, "Cannot create GMetaArg description: "
"MediaFrame unknown 'fmt' type: " <<
std::to_string(mfxDecParams.mfx.FrameInfo.FourCC));
GAPI_Assert(false && "Cannot create GMetaArg description: invalid value");
}
}
description_is_valid = true;
return {bitstream, mfxDecParams};
}
std::unique_ptr<VPLAccelerationPolicy> GSource::Priv::initializeHWAccel()
std::unique_ptr<VPLAccelerationPolicy> GSource::Priv::initializeHWAccel(std::shared_ptr<IDeviceSelector> selector)
{
std::unique_ptr<VPLAccelerationPolicy> ret;
auto accel_mode_it = std::find_if(cfg_params.begin(), cfg_params.end(), [] (const CfgParam& value) {
return value.get_name() == "mfxImplDescription.AccelerationMode";
return value.get_name() == CfgParam::acceleration_mode_name();
});
if (accel_mode_it == cfg_params.end())
{
GAPI_LOG_DEBUG(nullptr, "No HW Accel requested. Use CPU");
ret.reset(new VPLCPUAccelerationPolicy);
ret.reset(new VPLCPUAccelerationPolicy(selector));
return ret;
}
@@ -320,13 +265,13 @@ std::unique_ptr<VPLAccelerationPolicy> GSource::Priv::initializeHWAccel()
switch(accel_mode.Data.U32) {
case MFX_ACCEL_MODE_VIA_D3D11:
{
std::unique_ptr<VPLDX11AccelerationPolicy> cand(new VPLDX11AccelerationPolicy);
std::unique_ptr<VPLDX11AccelerationPolicy> cand(new VPLDX11AccelerationPolicy(selector));
ret = std::move(cand);
break;
}
case MFX_ACCEL_MODE_NA:
{
std::unique_ptr<VPLCPUAccelerationPolicy> cand(new VPLCPUAccelerationPolicy);
std::unique_ptr<VPLCPUAccelerationPolicy> cand(new VPLCPUAccelerationPolicy(selector));
ret = std::move(cand);
break;
}
@@ -367,6 +312,7 @@ bool GSource::Priv::pull(cv::gapi::wip::Data& data)
if (engine->get_ready_frames_count()) {
engine->get_frame(data);
consumed_frames_count++;
return true;
} else {
return false;
@@ -17,14 +17,7 @@
#include <opencv2/gapi/streaming/onevpl/source.hpp>
#ifdef HAVE_ONEVPL
#if (MFX_VERSION >= 2000)
#include <vpl/mfxdispatcher.h>
#endif // MFX_VERSION
#include <vpl/mfx.h>
#include <vpl/mfxvideo.h>
#include "streaming/onevpl/onevpl_export.hpp"
#include "streaming/onevpl/engine/processing_engine_base.hpp"
namespace cv {
@@ -49,9 +42,7 @@ struct GSource::Priv
GMetaArg descr_of() const;
private:
Priv();
DecoderParams create_decoder_from_file(uint32_t decoder_id,
std::shared_ptr<IDataProvider> provider);
std::unique_ptr<VPLAccelerationPolicy> initializeHWAccel();
std::unique_ptr<VPLAccelerationPolicy> initializeHWAccel(std::shared_ptr<IDeviceSelector> selector);
mfxLoader mfx_handle;
mfxImplDescription *mfx_impl_description;
@@ -64,6 +55,8 @@ private:
bool description_is_valid;
std::unique_ptr<ProcessingEngineBase> engine;
size_t consumed_frames_count;
};
} // namespace onevpl
} // namespace wip
+184 -282
View File
@@ -14,6 +14,18 @@
#include "streaming/onevpl/utils.hpp"
#include "logger.hpp"
#define ONEVPL_STRINGIFY_CASE(value) \
case value: return #value;
#define ONEVPL_STRINGIFY_IF(value) \
if (!strcmp(cstr, #value)) { \
return value; \
}
#define APPEND_STRINGIFY_MASK_N_ERASE(value, pref, mask) \
if (value & mask) { ss << pref << #mask; value ^= mask; }
namespace cv {
namespace gapi {
namespace wip {
@@ -21,153 +33,96 @@ namespace onevpl {
const char* mfx_impl_to_cstr(const mfxIMPL impl) {
switch (impl) {
case MFX_IMPL_TYPE_SOFTWARE:
return "MFX_IMPL_TYPE_SOFTWARE";
case MFX_IMPL_TYPE_HARDWARE:
return "MFX_IMPL_TYPE_HARDWARE";
default:
return "unknown mfxIMPL";
ONEVPL_STRINGIFY_CASE(MFX_IMPL_TYPE_SOFTWARE);
ONEVPL_STRINGIFY_CASE(MFX_IMPL_TYPE_HARDWARE);
default: return "unknown mfxIMPL";
}
}
mfxIMPL cstr_to_mfx_impl(const char* cstr) {
if (!strcmp(cstr, "MFX_IMPL_TYPE_SOFTWARE")) {
return MFX_IMPL_TYPE_SOFTWARE;
} else if (!strcmp(cstr, "MFX_IMPL_TYPE_HARDWARE")) {
return MFX_IMPL_TYPE_HARDWARE;
}
throw std::logic_error(std::string("Invalid \"mfxImplDescription.Impl\":") + cstr);
ONEVPL_STRINGIFY_IF(MFX_IMPL_TYPE_SOFTWARE)
ONEVPL_STRINGIFY_IF(MFX_IMPL_TYPE_HARDWARE)
throw std::logic_error(std::string("Invalid \"") + CfgParam::implementation_name() +
"\":" + cstr);
}
const char* mfx_accel_mode_to_cstr (const mfxAccelerationMode mode) {
switch (mode) {
case MFX_ACCEL_MODE_NA:
return "MFX_ACCEL_MODE_NA";
case MFX_ACCEL_MODE_VIA_D3D9:
return "MFX_ACCEL_MODE_VIA_D3D9";
case MFX_ACCEL_MODE_VIA_D3D11:
return "MFX_ACCEL_MODE_VIA_D3D11";
case MFX_ACCEL_MODE_VIA_VAAPI:
return "MFX_ACCEL_MODE_VIA_VAAPI";
case MFX_ACCEL_MODE_VIA_VAAPI_DRM_MODESET:
return "MFX_ACCEL_MODE_VIA_VAAPI_DRM_MODESET";
case MFX_ACCEL_MODE_VIA_VAAPI_GLX:
return "MFX_ACCEL_MODE_VIA_VAAPI_GLX";
case MFX_ACCEL_MODE_VIA_VAAPI_X11:
return "MFX_ACCEL_MODE_VIA_VAAPI_X11";
case MFX_ACCEL_MODE_VIA_VAAPI_WAYLAND:
return "MFX_ACCEL_MODE_VIA_VAAPI_WAYLAND";
case MFX_ACCEL_MODE_VIA_HDDLUNITE:
return "MFX_ACCEL_MODE_VIA_HDDLUNITE";
default:
return "unknown mfxAccelerationMode";
ONEVPL_STRINGIFY_CASE(MFX_ACCEL_MODE_NA)
ONEVPL_STRINGIFY_CASE(MFX_ACCEL_MODE_VIA_D3D9)
ONEVPL_STRINGIFY_CASE(MFX_ACCEL_MODE_VIA_D3D11)
ONEVPL_STRINGIFY_CASE(MFX_ACCEL_MODE_VIA_VAAPI)
ONEVPL_STRINGIFY_CASE(MFX_ACCEL_MODE_VIA_VAAPI_DRM_MODESET)
ONEVPL_STRINGIFY_CASE(MFX_ACCEL_MODE_VIA_VAAPI_GLX)
ONEVPL_STRINGIFY_CASE(MFX_ACCEL_MODE_VIA_VAAPI_X11)
ONEVPL_STRINGIFY_CASE(MFX_ACCEL_MODE_VIA_VAAPI_WAYLAND)
ONEVPL_STRINGIFY_CASE(MFX_ACCEL_MODE_VIA_HDDLUNITE)
default: return "unknown mfxAccelerationMode";
}
return "unknown mfxAccelerationMode";
}
mfxAccelerationMode cstr_to_mfx_accel_mode(const char* cstr) {
if (!strcmp(cstr, "MFX_ACCEL_MODE_NA")) {
return MFX_ACCEL_MODE_NA;
} else if (!strcmp(cstr, "MFX_ACCEL_MODE_VIA_D3D9")) {
return MFX_ACCEL_MODE_VIA_D3D9;
} else if (!strcmp(cstr, "MFX_ACCEL_MODE_VIA_D3D11")) {
return MFX_ACCEL_MODE_VIA_D3D11;
} else if (!strcmp(cstr, "MFX_ACCEL_MODE_VIA_VAAPI")) {
return MFX_ACCEL_MODE_VIA_VAAPI;
} else if (!strcmp(cstr, "MFX_ACCEL_MODE_VIA_VAAPI_DRM_MODESET")) {
return MFX_ACCEL_MODE_VIA_VAAPI_DRM_MODESET;
} else if (!strcmp(cstr, "MFX_ACCEL_MODE_VIA_VAAPI_GLX")) {
return MFX_ACCEL_MODE_VIA_VAAPI_GLX;
} else if (!strcmp(cstr, "MFX_ACCEL_MODE_VIA_VAAPI_X11")) {
return MFX_ACCEL_MODE_VIA_VAAPI_X11;
} else if (!strcmp(cstr, "MFX_ACCEL_MODE_VIA_VAAPI_WAYLAND")) {
return MFX_ACCEL_MODE_VIA_VAAPI_WAYLAND;
} else if (!strcmp(cstr, "MFX_ACCEL_MODE_VIA_HDDLUNITE")) {
return MFX_ACCEL_MODE_VIA_HDDLUNITE;
}
throw std::logic_error(std::string("Invalid \"mfxImplDescription.AccelerationMode\":") + cstr);
ONEVPL_STRINGIFY_IF(MFX_ACCEL_MODE_NA)
ONEVPL_STRINGIFY_IF(MFX_ACCEL_MODE_VIA_D3D9)
ONEVPL_STRINGIFY_IF(MFX_ACCEL_MODE_VIA_D3D11)
ONEVPL_STRINGIFY_IF(MFX_ACCEL_MODE_VIA_VAAPI)
ONEVPL_STRINGIFY_IF(MFX_ACCEL_MODE_VIA_VAAPI_DRM_MODESET)
ONEVPL_STRINGIFY_IF(MFX_ACCEL_MODE_VIA_VAAPI_GLX)
ONEVPL_STRINGIFY_IF(MFX_ACCEL_MODE_VIA_VAAPI_X11)
ONEVPL_STRINGIFY_IF(MFX_ACCEL_MODE_VIA_VAAPI_WAYLAND)
ONEVPL_STRINGIFY_IF(MFX_ACCEL_MODE_VIA_HDDLUNITE)
throw std::logic_error(std::string("Invalid \"") +
CfgParam::acceleration_mode_name() +
"\":" + cstr);
}
const char* mfx_resource_type_to_cstr (const mfxResourceType type) {
switch (type) {
case MFX_RESOURCE_SYSTEM_SURFACE:
return "MFX_RESOURCE_SYSTEM_SURFACE";
case MFX_RESOURCE_VA_SURFACE:
return "MFX_RESOURCE_VA_SURFACE";
case MFX_RESOURCE_VA_BUFFER:
return "MFX_RESOURCE_VA_BUFFER";
case MFX_RESOURCE_DX9_SURFACE:
return "MFX_RESOURCE_DX9_SURFACE";
case MFX_RESOURCE_DX11_TEXTURE:
return "MFX_RESOURCE_DX11_TEXTURE";
case MFX_RESOURCE_DX12_RESOURCE:
return "MFX_RESOURCE_DX12_RESOURCE";
case MFX_RESOURCE_DMA_RESOURCE:
return "MFX_RESOURCE_DMA_RESOURCE";
case MFX_RESOURCE_HDDLUNITE_REMOTE_MEMORY:
return "MFX_RESOURCE_HDDLUNITE_REMOTE_MEMORY";
default:
return "unknown mfxResourceType";
ONEVPL_STRINGIFY_CASE(MFX_RESOURCE_SYSTEM_SURFACE)
ONEVPL_STRINGIFY_CASE(MFX_RESOURCE_VA_SURFACE)
ONEVPL_STRINGIFY_CASE(MFX_RESOURCE_VA_BUFFER)
ONEVPL_STRINGIFY_CASE(MFX_RESOURCE_DX9_SURFACE)
ONEVPL_STRINGIFY_CASE(MFX_RESOURCE_DX11_TEXTURE)
ONEVPL_STRINGIFY_CASE(MFX_RESOURCE_DX12_RESOURCE)
ONEVPL_STRINGIFY_CASE(MFX_RESOURCE_DMA_RESOURCE)
ONEVPL_STRINGIFY_CASE(MFX_RESOURCE_HDDLUNITE_REMOTE_MEMORY)
default: return "unknown mfxResourceType";
}
}
mfxResourceType cstr_to_mfx_resource_type(const char* cstr) {
if (!strcmp(cstr, "MFX_RESOURCE_SYSTEM_SURFACE")) {
return MFX_RESOURCE_SYSTEM_SURFACE;
} else if (!strcmp(cstr, "MFX_RESOURCE_VA_SURFACE")) {
return MFX_RESOURCE_VA_SURFACE;
} else if (!strcmp(cstr, "MFX_RESOURCE_VA_BUFFER")) {
return MFX_RESOURCE_VA_BUFFER;
} else if (!strcmp(cstr, "MFX_RESOURCE_DX9_SURFACE")) {
return MFX_RESOURCE_DX9_SURFACE;
} else if (!strcmp(cstr, "MFX_RESOURCE_DX11_TEXTURE")) {
return MFX_RESOURCE_DX11_TEXTURE;
} else if (!strcmp(cstr, "MFX_RESOURCE_DX12_RESOURCE")) {
return MFX_RESOURCE_DX12_RESOURCE;
} else if (!strcmp(cstr, "MFX_RESOURCE_DMA_RESOURCE")) {
return MFX_RESOURCE_DMA_RESOURCE;
} else if (!strcmp(cstr, "MFX_RESOURCE_HDDLUNITE_REMOTE_MEMORY")) {
return MFX_RESOURCE_HDDLUNITE_REMOTE_MEMORY;
}
ONEVPL_STRINGIFY_IF(MFX_RESOURCE_SYSTEM_SURFACE)
ONEVPL_STRINGIFY_IF(MFX_RESOURCE_VA_SURFACE)
ONEVPL_STRINGIFY_IF(MFX_RESOURCE_VA_BUFFER)
ONEVPL_STRINGIFY_IF(MFX_RESOURCE_DX9_SURFACE)
ONEVPL_STRINGIFY_IF(MFX_RESOURCE_DX11_TEXTURE)
ONEVPL_STRINGIFY_IF(MFX_RESOURCE_DX12_RESOURCE)
ONEVPL_STRINGIFY_IF(MFX_RESOURCE_DMA_RESOURCE)
ONEVPL_STRINGIFY_IF(MFX_RESOURCE_HDDLUNITE_REMOTE_MEMORY)
throw std::logic_error(std::string("Invalid \"decoder.Profiles.MemDesc.MemHandleType\":") + cstr);
}
mfxU32 cstr_to_mfx_codec_id(const char* cstr) {
if (!strcmp(cstr, "MFX_CODEC_AVC")) {
return MFX_CODEC_AVC;
} else if (!strcmp(cstr, "MFX_CODEC_HEVC")) {
return MFX_CODEC_HEVC;
} else if (!strcmp(cstr, "MFX_CODEC_MPEG2")) {
return MFX_CODEC_MPEG2;
} else if (!strcmp(cstr, "MFX_CODEC_VC1")) {
return MFX_CODEC_VC1;
} else if (!strcmp(cstr, "MFX_CODEC_CAPTURE")) {
return MFX_CODEC_CAPTURE;
} else if (!strcmp(cstr, "MFX_CODEC_VP9")) {
return MFX_CODEC_VP9;
} else if (!strcmp(cstr, "MFX_CODEC_AV1")) {
return MFX_CODEC_AV1;
}
throw std::logic_error(std::string("Cannot parse \"mfxImplDescription.mfxDecoderDescription.decoder.CodecID\" value: ") + cstr);
ONEVPL_STRINGIFY_IF(MFX_CODEC_AVC)
ONEVPL_STRINGIFY_IF(MFX_CODEC_HEVC)
ONEVPL_STRINGIFY_IF(MFX_CODEC_MPEG2)
ONEVPL_STRINGIFY_IF(MFX_CODEC_VC1)
ONEVPL_STRINGIFY_IF(MFX_CODEC_CAPTURE)
ONEVPL_STRINGIFY_IF(MFX_CODEC_VP9)
ONEVPL_STRINGIFY_IF(MFX_CODEC_AV1)
throw std::logic_error(std::string("Cannot parse \"") + CfgParam::decoder_id_name() +
"\" value: " + cstr);
}
const char* mfx_codec_id_to_cstr(mfxU32 mfx_id) {
switch(mfx_id) {
case MFX_CODEC_AVC:
return "MFX_CODEC_AVC";
case MFX_CODEC_HEVC:
return "MFX_CODEC_HEVC";
case MFX_CODEC_MPEG2:
return "MFX_CODEC_MPEG2";
case MFX_CODEC_VC1:
return "MFX_CODEC_VC1";
case MFX_CODEC_VP9:
return "MFX_CODEC_VP9";
case MFX_CODEC_AV1:
return "MFX_CODEC_AV1";
case MFX_CODEC_JPEG:
return "MFX_CODEC_JPEG";
ONEVPL_STRINGIFY_CASE(MFX_CODEC_AVC)
ONEVPL_STRINGIFY_CASE(MFX_CODEC_HEVC)
ONEVPL_STRINGIFY_CASE(MFX_CODEC_MPEG2)
ONEVPL_STRINGIFY_CASE(MFX_CODEC_VC1)
ONEVPL_STRINGIFY_CASE(MFX_CODEC_VP9)
ONEVPL_STRINGIFY_CASE(MFX_CODEC_AV1)
ONEVPL_STRINGIFY_CASE(MFX_CODEC_JPEG)
default:
return "<unsupported>";
}
@@ -189,145 +144,92 @@ const char* mfx_codec_type_to_cstr(const mfxU32 fourcc, const mfxU32 type) {
switch (fourcc) {
case MFX_CODEC_JPEG: {
switch (type) {
case MFX_PROFILE_UNKNOWN:
return "MFX_PROFILE_UNKNOWN";
case MFX_PROFILE_JPEG_BASELINE:
return "MFX_PROFILE_JPEG_BASELINE";
default:
return "<unknown MFX_CODEC_JPEG profile";
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_UNKNOWN)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_JPEG_BASELINE)
default: return "<unknown MFX_CODEC_JPEG profile";
}
}
case MFX_CODEC_AVC: {
switch (type) {
case MFX_PROFILE_UNKNOWN:
return "MFX_PROFILE_UNKNOWN";
case MFX_PROFILE_AVC_BASELINE:
return "MFX_PROFILE_AVC_BASELINE";
case MFX_PROFILE_AVC_MAIN:
return "MFX_PROFILE_AVC_MAIN";
case MFX_PROFILE_AVC_EXTENDED:
return "MFX_PROFILE_AVC_EXTENDED";
case MFX_PROFILE_AVC_HIGH:
return "MFX_PROFILE_AVC_HIGH";
case MFX_PROFILE_AVC_HIGH10:
return "MFX_PROFILE_AVC_HIGH10";
case MFX_PROFILE_AVC_HIGH_422:
return "MFX_PROFILE_AVC_HIGH_422";
case MFX_PROFILE_AVC_CONSTRAINED_BASELINE:
return "MFX_PROFILE_AVC_CONSTRAINED_BASELINE";
case MFX_PROFILE_AVC_CONSTRAINED_HIGH:
return "MFX_PROFILE_AVC_CONSTRAINED_HIGH";
case MFX_PROFILE_AVC_PROGRESSIVE_HIGH:
return "MFX_PROFILE_AVC_PROGRESSIVE_HIGH";
default:
return "<unknown MFX_CODEC_AVC profile";
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_UNKNOWN)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_AVC_BASELINE)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_AVC_MAIN)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_AVC_EXTENDED)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_AVC_HIGH)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_AVC_HIGH10)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_AVC_HIGH_422)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_AVC_CONSTRAINED_BASELINE)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_AVC_CONSTRAINED_HIGH)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_AVC_PROGRESSIVE_HIGH)
default: return "<unknown MFX_CODEC_AVC profile";
}
}
case MFX_CODEC_HEVC: {
switch (type) {
case MFX_PROFILE_UNKNOWN:
return "MFX_PROFILE_UNKNOWN";
case MFX_PROFILE_HEVC_MAIN:
return "MFX_PROFILE_HEVC_MAIN";
case MFX_PROFILE_HEVC_MAIN10:
return "MFX_PROFILE_HEVC_MAIN10";
case MFX_PROFILE_HEVC_MAINSP:
return "MFX_PROFILE_HEVC_MAINSP";
case MFX_PROFILE_HEVC_REXT:
return "MFX_PROFILE_HEVC_REXT";
case MFX_PROFILE_HEVC_SCC:
return "MFX_PROFILE_HEVC_SCC";
default:
return "<unknown MFX_CODEC_HEVC profile";
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_UNKNOWN)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_HEVC_MAIN)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_HEVC_MAIN10)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_HEVC_MAINSP)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_HEVC_REXT)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_HEVC_SCC)
default: return "<unknown MFX_CODEC_HEVC profile";
}
}
case MFX_CODEC_MPEG2: {
switch (type) {
case MFX_PROFILE_UNKNOWN:
return "MFX_PROFILE_UNKNOWN";
case MFX_PROFILE_MPEG2_SIMPLE:
return "MFX_PROFILE_MPEG2_SIMPLE";
case MFX_PROFILE_MPEG2_MAIN:
return "MFX_PROFILE_MPEG2_MAIN";
case MFX_LEVEL_MPEG2_HIGH:
return "MFX_LEVEL_MPEG2_HIGH";
case MFX_LEVEL_MPEG2_HIGH1440:
return "MFX_LEVEL_MPEG2_HIGH1440";
default:
return "<unknown MFX_CODEC_MPEG2 profile";
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_UNKNOWN)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_MPEG2_SIMPLE)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_MPEG2_MAIN)
ONEVPL_STRINGIFY_CASE(MFX_LEVEL_MPEG2_HIGH)
ONEVPL_STRINGIFY_CASE(MFX_LEVEL_MPEG2_HIGH1440)
default: return "<unknown MFX_CODEC_MPEG2 profile";
}
}
case MFX_CODEC_VP8: {
switch (type) {
case MFX_PROFILE_UNKNOWN:
return "MFX_PROFILE_UNKNOWN";
case MFX_PROFILE_VP8_0:
return "MFX_PROFILE_VP8_0";
case MFX_PROFILE_VP8_1:
return "MFX_PROFILE_VP8_1";
case MFX_PROFILE_VP8_2:
return "MFX_PROFILE_VP8_2";
case MFX_PROFILE_VP8_3:
return "MFX_PROFILE_VP8_3";
default:
return "<unknown MFX_CODEC_VP8 profile";
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_UNKNOWN)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_VP8_0)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_VP8_1)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_VP8_2)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_VP8_3)
default: return "<unknown MFX_CODEC_VP8 profile";
}
}
case MFX_CODEC_VC1: {
switch (type) {
case MFX_PROFILE_UNKNOWN:
return "MFX_PROFILE_UNKNOWN";
case MFX_PROFILE_VC1_SIMPLE:
return "MFX_PROFILE_VC1_SIMPLE";
case MFX_PROFILE_VC1_MAIN:
return "MFX_PROFILE_VC1_MAIN";
case MFX_PROFILE_VC1_ADVANCED:
return "MFX_PROFILE_VC1_ADVANCED";
default:
return "<unknown MFX_CODEC_VC1 profile";
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_UNKNOWN)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_VC1_SIMPLE)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_VC1_MAIN)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_VC1_ADVANCED)
default: return "<unknown MFX_CODEC_VC1 profile";
}
}
case MFX_CODEC_VP9: {
switch (type) {
case MFX_PROFILE_UNKNOWN:
return "MFX_PROFILE_UNKNOWN";
case MFX_PROFILE_VP9_0:
return "MFX_PROFILE_VP9_0";
case MFX_PROFILE_VP9_1:
return "MFX_PROFILE_VP9_1";
case MFX_PROFILE_VP9_2:
return "MFX_PROFILE_VP9_2";
case MFX_PROFILE_VP9_3:
return "MFX_PROFILE_VP9_3";
default:
return "<unknown MFX_CODEC_VP9 profile";
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_UNKNOWN)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_VP9_0)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_VP9_1)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_VP9_2)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_VP9_3)
default: return "<unknown MFX_CODEC_VP9 profile";
}
}
case MFX_CODEC_AV1: {
switch (type) {
case MFX_PROFILE_UNKNOWN:
return "MFX_PROFILE_UNKNOWN";
case MFX_PROFILE_AV1_MAIN:
return "MFX_PROFILE_AV1_MAIN";
case MFX_PROFILE_AV1_HIGH:
return "MFX_PROFILE_AV1_HIGH";
case MFX_PROFILE_AV1_PRO:
return "MFX_PROFILE_AV1_PRO";
default:
return "<unknown MFX_CODEC_AV1 profile";
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_UNKNOWN)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_AV1_MAIN)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_AV1_HIGH)
ONEVPL_STRINGIFY_CASE(MFX_PROFILE_AV1_PRO)
default: return "<unknown MFX_CODEC_AV1 profile";
}
}
default:
return "unknown codec type :";
default: return "unknown codec type :";
}
}
@@ -354,8 +256,8 @@ std::ostream& operator<< (std::ostream& out, const mfxImplDescription& idesc)
{
out << "mfxImplDescription.Version: " << static_cast<int>(idesc.Version.Major)
<< "." << static_cast<int>(idesc.Version.Minor) << std::endl;
out << "mfxImplDescription.Impl: " << mfx_impl_to_cstr(idesc.Impl) << std::endl;
out << "(*)mfxImplDescription.AccelerationMode: " << mfx_accel_mode_to_cstr(idesc.AccelerationMode) << std::endl;
out << "(*)" << CfgParam::implementation_name() << ": " << mfx_impl_to_cstr(idesc.Impl) << std::endl;
out << "(*)" << CfgParam::acceleration_mode_name() << ": " << mfx_accel_mode_to_cstr(idesc.AccelerationMode) << std::endl;
out << "mfxImplDescription.ApiVersion: " << idesc.ApiVersion.Major << "." << idesc.ApiVersion.Minor << std::endl;
out << "(*)mfxImplDescription.ApiVersion.Version: " << idesc.ApiVersion.Version << std::endl;
out << "mfxImplDescription.ImplName: " << idesc.ImplName << std::endl;
@@ -386,7 +288,7 @@ std::ostream& operator<< (std::ostream& out, const mfxImplDescription& idesc)
<< "." << static_cast<int>(dec.Version.Minor) << std::endl;
for (int codec = 0; codec < dec.NumCodecs; codec++) {
auto cid = dec.Codecs[codec].CodecID;
out << "(*)mfxImplDescription.mfxDecoderDescription.decoder.CodecID: " << cid;//(cid & 0xff) << "." << (cid >> 8 & 0xff) << "." << (cid >> 16 & 0xff) << "." << (cid >> 24 & 0xff) << std::endl;
out << "(*)" << CfgParam::decoder_id_name() << ": " << cid;//(cid & 0xff) << "." << (cid >> 8 & 0xff) << "." << (cid >> 16 & 0xff) << "." << (cid >> 24 & 0xff) << std::endl;
out << "mfxImplDescription.mfxDecoderDescription.decoder.MaxcodecLevel: " << dec.Codecs[codec].MaxcodecLevel << std::endl;
for (int profile = 0; profile < dec.Codecs[codec].NumProfiles; profile++) {
out << "mfxImplDescription.mfxDecoderDescription.decoder.Profiles: "
@@ -422,69 +324,69 @@ std::string mfxstatus_to_string(int64_t err) {
}
std::string mfxstatus_to_string(mfxStatus err) {
switch(err)
{
case MFX_ERR_NONE:
return "MFX_ERR_NONE";
case MFX_ERR_UNKNOWN:
return "MFX_ERR_UNKNOWN";
case MFX_ERR_NULL_PTR:
return "MFX_ERR_NULL_PTR";
case MFX_ERR_UNSUPPORTED:
return "MFX_ERR_UNSUPPORTED";
case MFX_ERR_MEMORY_ALLOC:
return "MFX_ERR_MEMORY_ALLOC";
case MFX_ERR_NOT_ENOUGH_BUFFER:
return "MFX_ERR_NOT_ENOUGH_BUFFER";
case MFX_ERR_INVALID_HANDLE:
return "MFX_ERR_INVALID_HANDLE";
case MFX_ERR_LOCK_MEMORY:
return "MFX_ERR_LOCK_MEMORY";
case MFX_ERR_NOT_INITIALIZED:
return "MFX_ERR_NOT_INITIALIZED";
case MFX_ERR_NOT_FOUND:
return "MFX_ERR_NOT_FOUND";
case MFX_ERR_MORE_DATA:
return "MFX_ERR_MORE_DATA";
case MFX_ERR_MORE_SURFACE:
return "MFX_ERR_MORE_SURFACE";
case MFX_ERR_ABORTED:
return "MFX_ERR_ABORTED";
case MFX_ERR_DEVICE_LOST:
return "MFX_ERR_DEVICE_LOST";
case MFX_ERR_INCOMPATIBLE_VIDEO_PARAM:
return "MFX_ERR_INCOMPATIBLE_VIDEO_PARAM";
case MFX_ERR_INVALID_VIDEO_PARAM:
return "MFX_ERR_INVALID_VIDEO_PARAM";
case MFX_ERR_UNDEFINED_BEHAVIOR:
return "MFX_ERR_UNDEFINED_BEHAVIOR";
case MFX_ERR_DEVICE_FAILED:
return "MFX_ERR_DEVICE_FAILED";
case MFX_ERR_MORE_BITSTREAM:
return "MFX_ERR_MORE_BITSTREAM";
case MFX_ERR_GPU_HANG:
return "MFX_ERR_GPU_HANG";
case MFX_ERR_REALLOC_SURFACE:
return "MFX_ERR_REALLOC_SURFACE";
case MFX_ERR_RESOURCE_MAPPED:
return "MFX_ERR_RESOURCE_MAPPED";
case MFX_ERR_NOT_IMPLEMENTED:
return "MFX_ERR_NOT_IMPLEMENTED";
case MFX_WRN_DEVICE_BUSY:
return "MFX_WRN_DEVICE_BUSY";
case MFX_WRN_VIDEO_PARAM_CHANGED:
return "MFX_WRN_VIDEO_PARAM_CHANGED";
case MFX_WRN_IN_EXECUTION:
return "MFX_WRN_IN_EXECUTION";
default:
break;
switch(err) {
ONEVPL_STRINGIFY_CASE(MFX_ERR_NONE)
ONEVPL_STRINGIFY_CASE(MFX_ERR_UNKNOWN)
ONEVPL_STRINGIFY_CASE(MFX_ERR_NULL_PTR)
ONEVPL_STRINGIFY_CASE(MFX_ERR_UNSUPPORTED)
ONEVPL_STRINGIFY_CASE(MFX_ERR_MEMORY_ALLOC)
ONEVPL_STRINGIFY_CASE(MFX_ERR_NOT_ENOUGH_BUFFER)
ONEVPL_STRINGIFY_CASE(MFX_ERR_INVALID_HANDLE)
ONEVPL_STRINGIFY_CASE(MFX_ERR_LOCK_MEMORY)
ONEVPL_STRINGIFY_CASE(MFX_ERR_NOT_INITIALIZED)
ONEVPL_STRINGIFY_CASE(MFX_ERR_NOT_FOUND)
ONEVPL_STRINGIFY_CASE(MFX_ERR_MORE_DATA)
ONEVPL_STRINGIFY_CASE(MFX_ERR_MORE_SURFACE)
ONEVPL_STRINGIFY_CASE(MFX_ERR_ABORTED)
ONEVPL_STRINGIFY_CASE(MFX_ERR_DEVICE_LOST)
ONEVPL_STRINGIFY_CASE(MFX_ERR_INCOMPATIBLE_VIDEO_PARAM)
ONEVPL_STRINGIFY_CASE(MFX_ERR_INVALID_VIDEO_PARAM)
ONEVPL_STRINGIFY_CASE(MFX_ERR_UNDEFINED_BEHAVIOR)
ONEVPL_STRINGIFY_CASE(MFX_ERR_DEVICE_FAILED)
ONEVPL_STRINGIFY_CASE(MFX_ERR_MORE_BITSTREAM)
ONEVPL_STRINGIFY_CASE(MFX_ERR_GPU_HANG)
ONEVPL_STRINGIFY_CASE(MFX_ERR_REALLOC_SURFACE)
ONEVPL_STRINGIFY_CASE(MFX_ERR_RESOURCE_MAPPED)
ONEVPL_STRINGIFY_CASE(MFX_ERR_NOT_IMPLEMENTED)
ONEVPL_STRINGIFY_CASE(MFX_WRN_DEVICE_BUSY)
ONEVPL_STRINGIFY_CASE(MFX_WRN_VIDEO_PARAM_CHANGED)
ONEVPL_STRINGIFY_CASE(MFX_WRN_IN_EXECUTION)
default: break;
}
std::string ret("<unknown ");
ret += std::to_string(err) + ">";
return ret;
}
std::string ext_mem_frame_type_to_cstr(int type) {
std::stringstream ss;
APPEND_STRINGIFY_MASK_N_ERASE(type, "|", MFX_MEMTYPE_DXVA2_DECODER_TARGET);
APPEND_STRINGIFY_MASK_N_ERASE(type, "|", MFX_MEMTYPE_DXVA2_PROCESSOR_TARGET);
// NB: accoring to VPL source the commented MFX_* constane below are belong to the
// same actual integral value as condition abobe. So it is impossible
// to distinct them in condition branch. Just put this comment and possible
// constans here...
//APPEND_STRINGIFY_MASK_N_ERASE(type, "|", MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET);
//APPEND_STRINGIFY_MASK_N_ERASE(type, "|", MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET);
APPEND_STRINGIFY_MASK_N_ERASE(type, "|", MFX_MEMTYPE_SYSTEM_MEMORY);
APPEND_STRINGIFY_MASK_N_ERASE(type, "|", MFX_MEMTYPE_RESERVED1);
APPEND_STRINGIFY_MASK_N_ERASE(type, "|", MFX_MEMTYPE_FROM_ENCODE);
APPEND_STRINGIFY_MASK_N_ERASE(type, "|", MFX_MEMTYPE_FROM_DECODE);
APPEND_STRINGIFY_MASK_N_ERASE(type, "|", MFX_MEMTYPE_FROM_VPPIN);
APPEND_STRINGIFY_MASK_N_ERASE(type, "|", MFX_MEMTYPE_FROM_VPPOUT);
APPEND_STRINGIFY_MASK_N_ERASE(type, "|", MFX_MEMTYPE_FROM_ENC);
APPEND_STRINGIFY_MASK_N_ERASE(type, "|", MFX_MEMTYPE_INTERNAL_FRAME);
APPEND_STRINGIFY_MASK_N_ERASE(type, "|", MFX_MEMTYPE_EXTERNAL_FRAME);
APPEND_STRINGIFY_MASK_N_ERASE(type, "|", MFX_MEMTYPE_EXPORT_FRAME);
//APPEND_STRINGIFY_MASK_N_ERASE(type, "|", MFX_MEMTYPE_SHARED_RESOURCE);
APPEND_STRINGIFY_MASK_N_ERASE(type, "|", MFX_MEMTYPE_VIDEO_MEMORY_ENCODER_TARGET);
if (type != 0) {
ss << "(rest: " << std::to_string(type) << ")";
}
return ss.str();
}
} // namespace onevpl
} // namespace wip
} // namespace gapi
+10 -6
View File
@@ -8,12 +8,7 @@
#define GAPI_STREAMING_ONEVPL_ONEVPL_UTILS_HPP
#ifdef HAVE_ONEVPL
#if (MFX_VERSION >= 2000)
#include <vpl/mfxdispatcher.h>
#endif // MFX_VERSION
#include <vpl/mfx.h>
#include <vpl/mfxvideo.h>
#include "streaming/onevpl/onevpl_export.hpp"
#include <map>
#include <memory>
@@ -42,11 +37,19 @@ void release(COMNonManageableType *ptr) {
template <typename COMNonManageableType>
using ComPtrGuard = std::unique_ptr<COMNonManageableType, decltype(&release<COMNonManageableType>)>;
template <typename COMNonManageableType>
using ComSharedPtrGuard = std::shared_ptr<COMNonManageableType>;
template <typename COMNonManageableType>
ComPtrGuard<COMNonManageableType> createCOMPtrGuard(COMNonManageableType *ptr = nullptr) {
return ComPtrGuard<COMNonManageableType> {ptr, &release<COMNonManageableType>};
}
template <typename COMNonManageableType>
ComSharedPtrGuard<COMNonManageableType> createCOMSharedPtrGuard(ComPtrGuard<COMNonManageableType>&& unique_guard) {
return ComSharedPtrGuard<COMNonManageableType>(std::move(unique_guard));
}
const char* mfx_impl_to_cstr(const mfxIMPL impl);
@@ -75,6 +78,7 @@ std::string mfxstatus_to_string(mfxStatus err);
std::ostream& operator<< (std::ostream& out, const mfxImplDescription& idesc);
std::string ext_mem_frame_type_to_cstr(int type);
} // namespace onevpl
} // namespace wip
} // namespace gapi