mirror of
https://github.com/opencv/opencv.git
synced 2025-08-06 14:36:36 +08: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:
parent
41d108ead6
commit
5c91f5b71d
@ -174,10 +174,13 @@ set(gapi_srcs
|
||||
src/streaming/onevpl/utils.cpp
|
||||
src/streaming/onevpl/data_provider_interface_exception.cpp
|
||||
src/streaming/onevpl/accelerators/surface/cpu_frame_adapter.cpp
|
||||
src/streaming/onevpl/accelerators/surface/dx11_frame_adapter.cpp
|
||||
src/streaming/onevpl/accelerators/surface/surface.cpp
|
||||
src/streaming/onevpl/accelerators/surface/surface_pool.cpp
|
||||
src/streaming/onevpl/accelerators/utils/shared_lock.cpp
|
||||
src/streaming/onevpl/accelerators/accel_policy_cpu.cpp
|
||||
src/streaming/onevpl/accelerators/accel_policy_dx11.cpp
|
||||
src/streaming/onevpl/accelerators/dx11_alloc_resource.cpp
|
||||
src/streaming/onevpl/engine/engine_session.cpp
|
||||
src/streaming/onevpl/engine/processing_engine_base.cpp
|
||||
src/streaming/onevpl/engine/decode/decode_engine_legacy.cpp
|
||||
@ -282,12 +285,16 @@ if(HAVE_GAPI_ONEVPL)
|
||||
if(TARGET opencv_test_gapi)
|
||||
ocv_target_compile_definitions(opencv_test_gapi PRIVATE -DHAVE_ONEVPL)
|
||||
ocv_target_link_libraries(opencv_test_gapi PRIVATE ${VPL_IMPORTED_TARGETS})
|
||||
if(MSVC)
|
||||
target_compile_options(opencv_test_gapi PUBLIC "/wd4201")
|
||||
endif()
|
||||
if(HAVE_D3D11 AND HAVE_OPENCL)
|
||||
ocv_target_include_directories(opencv_test_gapi SYSTEM PRIVATE ${OPENCL_INCLUDE_DIRS})
|
||||
endif()
|
||||
endif()
|
||||
ocv_target_compile_definitions(${the_module} PRIVATE -DHAVE_ONEVPL)
|
||||
ocv_target_link_libraries(${the_module} PRIVATE ${VPL_IMPORTED_TARGETS})
|
||||
|
||||
if(HAVE_D3D11 AND HAVE_OPENCL)
|
||||
ocv_target_include_directories(${the_module} SYSTEM PRIVATE ${OPENCL_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
@ -46,9 +46,72 @@ struct GAPI_EXPORTS CfgParam {
|
||||
double_t,
|
||||
void*,
|
||||
std::string>;
|
||||
/**
|
||||
* @brief frames_pool_size_name
|
||||
*
|
||||
* Special configuration parameter name for onevp::GSource:
|
||||
*
|
||||
* @note frames_pool_size_name allows to allocate surfaces pool appropriate size to keep
|
||||
* decoded frames in accelerator memory ready before
|
||||
* they would be consumed by onevp::GSource::pull operation. If you see
|
||||
* a lot of WARNING about lack of free surface then it's time to increase
|
||||
* frames_pool_size_name but be aware of accelerator free memory volume.
|
||||
* If not set then MFX implementation use
|
||||
* mfxFrameAllocRequest::NumFrameSuggested behavior
|
||||
*
|
||||
*/
|
||||
static constexpr const char *frames_pool_size_name() { return "frames_pool_size"; }
|
||||
static CfgParam create_frames_pool_size(uint64_t value);
|
||||
|
||||
/**
|
||||
* Create onevp::GSource configuration parameter.
|
||||
* @brief acceleration_mode_name
|
||||
*
|
||||
* Special configuration parameter names for onevp::GSource:
|
||||
*
|
||||
* @note acceleration_mode_name allows to activate hardware acceleration &
|
||||
* device memory management.
|
||||
* Supported values:
|
||||
* - MFX_ACCEL_MODE_VIA_D3D11 Will activate DX11 acceleration and will produces
|
||||
* MediaFrames with data allocated in DX11 device memory
|
||||
*
|
||||
* If not set then MFX implementation will use default acceleration behavior:
|
||||
* all decoding operation uses default GPU resources but MediaFrame produces
|
||||
* data allocated by using host RAM
|
||||
*
|
||||
*/
|
||||
static constexpr const char *acceleration_mode_name() { return "mfxImplDescription.AccelerationMode"; }
|
||||
static CfgParam create_acceleration_mode(uint32_t value);
|
||||
static CfgParam create_acceleration_mode(const char* value);
|
||||
|
||||
/**
|
||||
* @brief decoder_id_name
|
||||
*
|
||||
* Special configuration parameter names for onevp::GSource:
|
||||
*
|
||||
* @note decoder_id_name allows to specify VPL decoder type which MUST present
|
||||
* in case of RAW video input data and MUST NOT present as CfgParam if video
|
||||
* stream incapsulated into container(*.mp4, *.mkv and so on). In latter case
|
||||
* onevp::GSource will determine it automatically
|
||||
* Supported values:
|
||||
* - MFX_CODEC_AVC
|
||||
* - MFX_CODEC_HEVC
|
||||
* - MFX_CODEC_MPEG2
|
||||
* - MFX_CODEC_VC1
|
||||
* - MFX_CODEC_CAPTURE
|
||||
* - MFX_CODEC_VP9
|
||||
* - MFX_CODEC_AV1
|
||||
*
|
||||
*/
|
||||
static constexpr const char *decoder_id_name() { return "mfxImplDescription.mfxDecoderDescription.decoder.CodecID"; }
|
||||
static CfgParam create_decoder_id(uint32_t value);
|
||||
static CfgParam create_decoder_id(const char* value);
|
||||
|
||||
static constexpr const char *implementation_name() { return "mfxImplDescription.Impl"; }
|
||||
static CfgParam create_implementation(uint32_t value);
|
||||
static CfgParam create_implementation(const char* value);
|
||||
|
||||
/**
|
||||
* Create generic onevp::GSource configuration parameter.
|
||||
*
|
||||
*@param name name of parameter.
|
||||
*@param value value of parameter.
|
||||
|
@ -18,16 +18,19 @@ using namespace perf;
|
||||
const std::string files[] = {
|
||||
"highgui/video/big_buck_bunny.h265",
|
||||
"highgui/video/big_buck_bunny.h264",
|
||||
"highgui/video/sample_322x242_15frames.yuv420p.libx265.mp4",
|
||||
};
|
||||
|
||||
const std::string codec[] = {
|
||||
"MFX_CODEC_HEVC",
|
||||
"MFX_CODEC_AVC"
|
||||
"MFX_CODEC_AVC",
|
||||
"",
|
||||
};
|
||||
|
||||
using source_t = std::string;
|
||||
using codec_t = std::string;
|
||||
using source_description_t = std::tuple<source_t, codec_t>;
|
||||
using accel_mode_t = std::string;
|
||||
using source_description_t = std::tuple<source_t, codec_t, accel_mode_t>;
|
||||
|
||||
class OneVPLSourcePerfTest : public TestPerfParams<source_description_t> {};
|
||||
class VideoCapSourcePerfTest : public TestPerfParams<source_t> {};
|
||||
@ -39,12 +42,20 @@ PERF_TEST_P_(OneVPLSourcePerfTest, TestPerformance)
|
||||
const auto params = GetParam();
|
||||
source_t src = findDataFile(get<0>(params));
|
||||
codec_t type = get<1>(params);
|
||||
accel_mode_t mode = get<2>(params);
|
||||
|
||||
std::vector<CfgParam> cfg_params {
|
||||
CfgParam::create<std::string>("mfxImplDescription.Impl", "MFX_IMPL_TYPE_HARDWARE"),
|
||||
CfgParam::create("mfxImplDescription.mfxDecoderDescription.decoder.CodecID", type),
|
||||
CfgParam::create_implementation("MFX_IMPL_TYPE_HARDWARE"),
|
||||
};
|
||||
|
||||
if (!type.empty()) {
|
||||
cfg_params.push_back(CfgParam::create_decoder_id(type.c_str()));
|
||||
}
|
||||
|
||||
if (!mode.empty()) {
|
||||
cfg_params.push_back(CfgParam::create_acceleration_mode(mode.c_str()));
|
||||
}
|
||||
|
||||
auto source_ptr = cv::gapi::wip::make_onevpl_src(src, cfg_params);
|
||||
|
||||
cv::gapi::wip::Data out;
|
||||
@ -72,12 +83,17 @@ PERF_TEST_P_(VideoCapSourcePerfTest, TestPerformance)
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Streaming, OneVPLSourcePerfTest,
|
||||
Values(source_description_t(files[0], codec[0]),
|
||||
source_description_t(files[1], codec[1])));
|
||||
Values(source_description_t(files[0], codec[0], ""),
|
||||
source_description_t(files[0], codec[0], "MFX_ACCEL_MODE_VIA_D3D11"),
|
||||
source_description_t(files[1], codec[1], ""),
|
||||
source_description_t(files[1], codec[1], "MFX_ACCEL_MODE_VIA_D3D11"),
|
||||
source_description_t(files[2], codec[2], ""),
|
||||
source_description_t(files[2], codec[2], "MFX_ACCEL_MODE_VIA_D3D11")));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Streaming, VideoCapSourcePerfTest,
|
||||
Values(files[0],
|
||||
files[1]));
|
||||
files[1],
|
||||
files[2]));
|
||||
} // namespace opencv_test
|
||||
|
||||
#endif // HAVE_ONEVPL
|
||||
|
@ -38,12 +38,14 @@
|
||||
const std::string about =
|
||||
"This is an OpenCV-based version of oneVPLSource decoder example";
|
||||
const std::string keys =
|
||||
"{ h help | | Print this help message }"
|
||||
"{ input | | Path to the input demultiplexed video file }"
|
||||
"{ output | | Path to the output RAW video file. Use .avi extension }"
|
||||
"{ facem | face-detection-adas-0001.xml | Path to OpenVINO IE face detection model (.xml) }"
|
||||
"{ faced | CPU | Target device for face detection model (e.g. CPU, GPU, VPU, ...) }"
|
||||
"{ cfg_params | <prop name>:<value>;<prop name>:<value> | Semicolon separated list of oneVPL mfxVariants which is used for configuring source (see `MFXSetConfigFilterProperty` by https://spec.oneapi.io/versions/latest/elements/oneVPL/source/index.html) }";
|
||||
"{ h help | | Print this help message }"
|
||||
"{ input | | Path to the input demultiplexed video file }"
|
||||
"{ output | | Path to the output RAW video file. Use .avi extension }"
|
||||
"{ facem | face-detection-adas-0001.xml | Path to OpenVINO IE face detection model (.xml) }"
|
||||
"{ faced | AUTO | Target device for face detection model (e.g. AUTO, GPU, VPU, ...) }"
|
||||
"{ cfg_params | <prop name>:<value>;<prop name>:<value> | Semicolon separated list of oneVPL mfxVariants which is used for configuring source (see `MFXSetConfigFilterProperty` by https://spec.oneapi.io/versions/latest/elements/oneVPL/source/index.html) }"
|
||||
"{ streaming_queue_capacity | 1 | Streaming executor queue capacity. Calculated automaticaly if 0 }"
|
||||
"{ frames_pool_size | 0 | OneVPL source applies this parameter as preallocated frames pool size}";
|
||||
|
||||
|
||||
namespace {
|
||||
@ -194,6 +196,8 @@ int main(int argc, char *argv[]) {
|
||||
std::string file_path = cmd.get<std::string>("input");
|
||||
const std::string output = cmd.get<std::string>("output");
|
||||
const auto face_model_path = cmd.get<std::string>("facem");
|
||||
const auto streaming_queue_capacity = cmd.get<uint64_t>("streaming_queue_capacity");
|
||||
const auto source_queue_capacity = cmd.get<uint64_t>("frames_pool_size");
|
||||
|
||||
// check ouput file extension
|
||||
if (!output.empty()) {
|
||||
@ -217,6 +221,10 @@ int main(int argc, char *argv[]) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (source_queue_capacity != 0) {
|
||||
source_cfgs.push_back(cv::gapi::wip::onevpl::CfgParam::create_frames_pool_size(source_queue_capacity));
|
||||
}
|
||||
|
||||
const std::string& device_id = cmd.get<std::string>("faced");
|
||||
auto face_net = cv::gapi::ie::Params<custom::FaceDetector> {
|
||||
face_model_path, // path to topology IR
|
||||
@ -298,6 +306,10 @@ int main(int argc, char *argv[]) {
|
||||
< custom::OCVLocateROI
|
||||
, custom::OCVBBoxes>();
|
||||
auto networks = cv::gapi::networks(face_net);
|
||||
auto face_detection_args = cv::compile_args(networks, kernels);
|
||||
if (streaming_queue_capacity != 0) {
|
||||
face_detection_args += cv::compile_args(cv::gapi::streaming::queue_capacity{ streaming_queue_capacity });
|
||||
}
|
||||
|
||||
// Create source
|
||||
cv::Ptr<cv::gapi::wip::IStreamSource> cap;
|
||||
@ -331,7 +343,7 @@ int main(int argc, char *argv[]) {
|
||||
cv::GStreamingCompiled pipeline;
|
||||
try {
|
||||
pipeline = cv::GComputation(cv::GIn(in), cv::GOut(out))
|
||||
.compileStreaming(cv::compile_args(kernels, networks));
|
||||
.compileStreaming(std::move(face_detection_args));
|
||||
} catch (const std::exception& ex) {
|
||||
std::cerr << "Exception occured during pipeline construction: " << ex.what() << std::endl;
|
||||
return -1;
|
||||
|
@ -128,15 +128,12 @@ GAPI_OCV_KERNEL_ST(RenderFrameOCVImpl, cv::gapi::wip::draw::GRenderFrame, Render
|
||||
out = in;
|
||||
|
||||
auto desc = out.desc();
|
||||
auto w_out = out.access(cv::MediaFrame::Access::W);
|
||||
cv::Mat upsample_uv, yuv;
|
||||
{
|
||||
auto r_in = in.access(cv::MediaFrame::Access::R);
|
||||
|
||||
auto out_y = cv::Mat(desc.size, CV_8UC1, w_out.ptr[0], w_out.stride[0]);
|
||||
auto out_uv = cv::Mat(desc.size / 2, CV_8UC2, w_out.ptr[1], w_out.stride[1]);
|
||||
|
||||
auto r_in = in.access(cv::MediaFrame::Access::R);
|
||||
|
||||
auto in_y = cv::Mat(desc.size, CV_8UC1, r_in.ptr[0], r_in.stride[0]);
|
||||
auto in_uv = cv::Mat(desc.size / 2, CV_8UC2, r_in.ptr[1], r_in.stride[1]);
|
||||
auto in_y = cv::Mat(desc.size, CV_8UC1, r_in.ptr[0], r_in.stride[0]);
|
||||
auto in_uv = cv::Mat(desc.size / 2, CV_8UC2, r_in.ptr[1], r_in.stride[1]);
|
||||
|
||||
/* FIXME How to render correctly on NV12 format ?
|
||||
*
|
||||
@ -157,19 +154,26 @@ GAPI_OCV_KERNEL_ST(RenderFrameOCVImpl, cv::gapi::wip::draw::GRenderFrame, Render
|
||||
*
|
||||
*/
|
||||
|
||||
// NV12 -> YUV
|
||||
cv::Mat upsample_uv, yuv;
|
||||
cv::resize(in_uv, upsample_uv, in_uv.size() * 2, cv::INTER_LINEAR);
|
||||
cv::merge(std::vector<cv::Mat>{in_y, upsample_uv}, yuv);
|
||||
// NV12 -> YUV
|
||||
cv::resize(in_uv, upsample_uv, in_uv.size() * 2, cv::INTER_LINEAR);
|
||||
cv::merge(std::vector<cv::Mat>{in_y, upsample_uv}, yuv);
|
||||
}
|
||||
|
||||
cv::gapi::wip::draw::drawPrimitivesOCVYUV(yuv, prims, state.ftpr);
|
||||
|
||||
// YUV -> NV12
|
||||
cv::Mat out_u, out_v, uv_plane;
|
||||
std::vector<cv::Mat> chs = { out_y, out_u, out_v };
|
||||
cv::split(yuv, chs);
|
||||
cv::merge(std::vector<cv::Mat>{chs[1], chs[2]}, uv_plane);
|
||||
cv::resize(uv_plane, out_uv, uv_plane.size() / 2, cv::INTER_LINEAR);
|
||||
{
|
||||
auto w_out = out.access(cv::MediaFrame::Access::W);
|
||||
|
||||
auto out_y = cv::Mat(desc.size, CV_8UC1, w_out.ptr[0], w_out.stride[0]);
|
||||
auto out_uv = cv::Mat(desc.size / 2, CV_8UC2, w_out.ptr[1], w_out.stride[1]);
|
||||
|
||||
cv::Mat out_u, out_v, uv_plane;
|
||||
std::vector<cv::Mat> chs = { out_y, out_u, out_v };
|
||||
cv::split(yuv, chs);
|
||||
cv::merge(std::vector<cv::Mat>{chs[1], chs[2]}, uv_plane);
|
||||
cv::resize(uv_plane, out_uv, uv_plane.size() / 2, cv::INTER_LINEAR);
|
||||
}
|
||||
}
|
||||
|
||||
static void setup(const cv::GFrameDesc& /* in_nv12 */,
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
25
modules/gapi/src/streaming/onevpl/onevpl_export.hpp
Normal file
25
modules/gapi/src/streaming/onevpl/onevpl_export.hpp
Normal file
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
86
modules/gapi/test/common/gapi_streaming_tests_common.hpp
Normal file
86
modules/gapi/test/common/gapi_streaming_tests_common.hpp
Normal file
@ -0,0 +1,86 @@
|
||||
// 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 OPENCV_GAPI_STREAMING_TESTS_COMMON_HPP
|
||||
#define OPENCV_GAPI_STREAMING_TESTS_COMMON_HPP
|
||||
|
||||
#include "gapi_tests_common.hpp"
|
||||
#include <opencv2/gapi/streaming/onevpl/source.hpp>
|
||||
#include <opencv2/gapi/streaming/onevpl/data_provider_interface.hpp>
|
||||
#include "streaming/onevpl/data_provider_defines.hpp"
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
#include "streaming/onevpl/onevpl_export.hpp"
|
||||
|
||||
namespace opencv_test {
|
||||
namespace streaming {
|
||||
namespace onevpl {
|
||||
|
||||
struct StreamDataProvider : public cv::gapi::wip::onevpl::IDataProvider {
|
||||
|
||||
StreamDataProvider(std::istream& in) : data_stream (in) {
|
||||
EXPECT_TRUE(in);
|
||||
}
|
||||
|
||||
mfx_codec_id_type get_mfx_codec_id() const override {
|
||||
return MFX_CODEC_HEVC;
|
||||
}
|
||||
|
||||
bool fetch_bitstream_data(std::shared_ptr<mfx_bitstream> &out_bitstream) override {
|
||||
if (empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!out_bitstream) {
|
||||
out_bitstream = std::make_shared<mfx_bitstream>();
|
||||
out_bitstream->MaxLength = 2000000;
|
||||
out_bitstream->Data = (mfxU8 *)calloc(out_bitstream->MaxLength, sizeof(mfxU8));
|
||||
if(!out_bitstream->Data) {
|
||||
throw std::runtime_error("Cannot allocate bitstream.Data bytes: " +
|
||||
std::to_string(out_bitstream->MaxLength * sizeof(mfxU8)));
|
||||
}
|
||||
out_bitstream->CodecId = get_mfx_codec_id();
|
||||
}
|
||||
|
||||
mfxU8 *p0 = out_bitstream->Data;
|
||||
mfxU8 *p1 = out_bitstream->Data + out_bitstream->DataOffset;
|
||||
EXPECT_FALSE(out_bitstream->DataOffset > out_bitstream->MaxLength - 1);
|
||||
EXPECT_FALSE(out_bitstream->DataLength + out_bitstream->DataOffset > out_bitstream->MaxLength);
|
||||
|
||||
std::copy_n(p1, out_bitstream->DataLength, p0);
|
||||
|
||||
out_bitstream->DataOffset = 0;
|
||||
out_bitstream->DataLength += static_cast<mfxU32>(fetch_data(out_bitstream->MaxLength - out_bitstream->DataLength,
|
||||
out_bitstream->Data + out_bitstream->DataLength));
|
||||
return out_bitstream->DataLength != 0;
|
||||
}
|
||||
|
||||
size_t fetch_data(size_t out_data_size, void* out_data_buf) {
|
||||
data_stream.read(reinterpret_cast<char*>(out_data_buf), out_data_size);
|
||||
return data_stream.gcount();
|
||||
}
|
||||
bool empty() const override {
|
||||
return data_stream.eof() || data_stream.bad();
|
||||
}
|
||||
private:
|
||||
std::istream& data_stream;
|
||||
};
|
||||
|
||||
static const unsigned char hevc_header[] = {
|
||||
0x00, 0x00, 0x00, 0x01, 0x40, 0x01, 0x0C, 0x06, 0xFF, 0xFF, 0x01, 0x40, 0x00,
|
||||
0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0x00,
|
||||
0x00, 0x04, 0x02, 0x10, 0x30, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x03,
|
||||
0x01, 0xE5, 0x00, 0x00, 0x00, 0x01, 0x42, 0x01, 0x06, 0x01, 0x40, 0x00, 0x00,
|
||||
0x03, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0x00, 0x00,
|
||||
0xA0, 0x10, 0x20, 0x61, 0x63, 0x41, 0x00, 0x86, 0x49, 0x1B, 0x2B, 0x20, 0x00,
|
||||
0x00, 0x00, 0x01, 0x44, 0x01, 0xC0, 0x71, 0xC0, 0xD9, 0x20, 0x00, 0x00, 0x00,
|
||||
0x01, 0x26, 0x01, 0xAF, 0x0C
|
||||
};
|
||||
} // namespace onevpl
|
||||
} // namespace streaming
|
||||
} // namespace opencv_test
|
||||
#endif // HAVE_ONEVPL
|
||||
#endif // OPENCV_GAPI_STREAMING_TESTS_HPP
|
@ -7,7 +7,7 @@
|
||||
|
||||
#include "../test_precomp.hpp"
|
||||
|
||||
#include "../common/gapi_tests_common.hpp"
|
||||
#include "../common/gapi_streaming_tests_common.hpp"
|
||||
|
||||
#include <thread> // sleep_for (Delay)
|
||||
|
||||
@ -24,18 +24,8 @@
|
||||
#include <opencv2/gapi/streaming/cap.hpp>
|
||||
#include <opencv2/gapi/streaming/desync.hpp>
|
||||
#include <opencv2/gapi/streaming/format.hpp>
|
||||
#include <opencv2/gapi/gstreaming.hpp>
|
||||
|
||||
#include <opencv2/gapi/streaming/onevpl/source.hpp>
|
||||
#include "streaming/onevpl/data_provider_defines.hpp"
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
|
||||
#if (MFX_VERSION >= 2000)
|
||||
#include <vpl/mfxdispatcher.h>
|
||||
#endif
|
||||
|
||||
#include <vpl/mfx.h>
|
||||
#endif // HAVE_ONEVPL
|
||||
|
||||
namespace opencv_test
|
||||
{
|
||||
@ -116,7 +106,7 @@ struct GAPI_Streaming: public ::testing::TestWithParam<std::tuple<KernelPackage,
|
||||
using namespace cv::gapi;
|
||||
auto args = cv::compile_args(use_only{pkg});
|
||||
if (cap) {
|
||||
args += cv::compile_args(streaming::queue_capacity{cap.value()});
|
||||
args += cv::compile_args(cv::gapi::streaming::queue_capacity{cap.value()});
|
||||
}
|
||||
return args;
|
||||
}
|
||||
@ -269,57 +259,6 @@ void checkPullOverload(const cv::Mat& ref,
|
||||
EXPECT_EQ(0., cv::norm(ref, out_mat, cv::NORM_INF));
|
||||
}
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
struct StreamDataProvider : public cv::gapi::wip::onevpl::IDataProvider {
|
||||
|
||||
StreamDataProvider(std::istream& in) : data_stream (in) {
|
||||
EXPECT_TRUE(in);
|
||||
}
|
||||
|
||||
mfx_codec_id_type get_mfx_codec_id() const override {
|
||||
return MFX_CODEC_HEVC;
|
||||
}
|
||||
|
||||
bool fetch_bitstream_data(std::shared_ptr<mfx_bitstream> &out_bitstream) override {
|
||||
if (empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!out_bitstream) {
|
||||
out_bitstream = std::make_shared<mfx_bitstream>();
|
||||
out_bitstream->MaxLength = 2000000;
|
||||
out_bitstream->Data = (mfxU8 *)calloc(out_bitstream->MaxLength, sizeof(mfxU8));
|
||||
if(!out_bitstream->Data) {
|
||||
throw std::runtime_error("Cannot allocate bitstream.Data bytes: " +
|
||||
std::to_string(out_bitstream->MaxLength * sizeof(mfxU8)));
|
||||
}
|
||||
out_bitstream->CodecId = get_mfx_codec_id();
|
||||
}
|
||||
|
||||
mfxU8 *p0 = out_bitstream->Data;
|
||||
mfxU8 *p1 = out_bitstream->Data + out_bitstream->DataOffset;
|
||||
EXPECT_FALSE(out_bitstream->DataOffset > out_bitstream->MaxLength - 1);
|
||||
EXPECT_FALSE(out_bitstream->DataLength + out_bitstream->DataOffset > out_bitstream->MaxLength);
|
||||
|
||||
std::copy_n(p1, out_bitstream->DataLength, p0);
|
||||
|
||||
out_bitstream->DataOffset = 0;
|
||||
out_bitstream->DataLength += static_cast<mfxU32>(fetch_data(out_bitstream->MaxLength - out_bitstream->DataLength,
|
||||
out_bitstream->Data + out_bitstream->DataLength));
|
||||
return out_bitstream->DataLength != 0;
|
||||
}
|
||||
|
||||
size_t fetch_data(size_t out_data_size, void* out_data_buf) {
|
||||
data_stream.read(reinterpret_cast<char*>(out_data_buf), out_data_size);
|
||||
return (size_t)data_stream.gcount();
|
||||
}
|
||||
bool empty() const override {
|
||||
return data_stream.eof() || data_stream.bad();
|
||||
}
|
||||
private:
|
||||
std::istream& data_stream;
|
||||
};
|
||||
#endif // HAVE_ONEVPL
|
||||
} // anonymous namespace
|
||||
|
||||
TEST_P(GAPI_Streaming, SmokeTest_ConstInput_GMat)
|
||||
@ -2244,31 +2183,21 @@ TEST(GAPI_Streaming, TestPythonAPI)
|
||||
}
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
const unsigned char hevc_header[] = {
|
||||
0x00, 0x00, 0x00, 0x01, 0x40, 0x01, 0x0C, 0x06, 0xFF, 0xFF, 0x01, 0x40, 0x00,
|
||||
0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0x00,
|
||||
0x00, 0x04, 0x02, 0x10, 0x30, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x03,
|
||||
0x01, 0xE5, 0x00, 0x00, 0x00, 0x01, 0x42, 0x01, 0x06, 0x01, 0x40, 0x00, 0x00,
|
||||
0x03, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0x00, 0x00,
|
||||
0xA0, 0x10, 0x20, 0x61, 0x63, 0x41, 0x00, 0x86, 0x49, 0x1B, 0x2B, 0x20, 0x00,
|
||||
0x00, 0x00, 0x01, 0x44, 0x01, 0xC0, 0x71, 0xC0, 0xD9, 0x20, 0x00, 0x00, 0x00,
|
||||
0x01, 0x26, 0x01, 0xAF, 0x0C
|
||||
};
|
||||
|
||||
TEST(OneVPL_Source, Init)
|
||||
{
|
||||
using CfgParam = cv::gapi::wip::onevpl::CfgParam;
|
||||
|
||||
std::vector<CfgParam> src_params;
|
||||
src_params.push_back(CfgParam::create<uint32_t>("mfxImplDescription.Impl",
|
||||
MFX_IMPL_TYPE_HARDWARE));
|
||||
src_params.push_back(CfgParam::create<uint32_t>("mfxImplDescription.AccelerationMode",
|
||||
MFX_ACCEL_MODE_VIA_D3D11, false));
|
||||
src_params.push_back(CfgParam::create<uint32_t>("mfxImplDescription.mfxDecoderDescription.decoder.CodecID",
|
||||
MFX_CODEC_HEVC));
|
||||
src_params.push_back(CfgParam::create_implementation(MFX_IMPL_TYPE_HARDWARE));
|
||||
src_params.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11));
|
||||
src_params.push_back(CfgParam::create_decoder_id(MFX_CODEC_HEVC));
|
||||
std::stringstream stream(std::ios_base::in | std::ios_base::out | std::ios_base::binary);
|
||||
EXPECT_TRUE(stream.write(reinterpret_cast<char*>(const_cast<unsigned char *>(hevc_header)),
|
||||
sizeof(hevc_header)));
|
||||
auto stream_data_provider = std::make_shared<StreamDataProvider>(stream);
|
||||
|
||||
EXPECT_TRUE(stream.write(reinterpret_cast<char*>(const_cast<unsigned char *>(streaming::onevpl::hevc_header)),
|
||||
sizeof(streaming::onevpl::hevc_header)));
|
||||
std::shared_ptr<cv::gapi::wip::onevpl::IDataProvider> stream_data_provider =
|
||||
std::make_shared<streaming::onevpl::StreamDataProvider>(stream);
|
||||
|
||||
cv::Ptr<cv::gapi::wip::IStreamSource> cap;
|
||||
bool cap_created = false;
|
||||
@ -2285,7 +2214,7 @@ TEST(OneVPL_Source, Init)
|
||||
}
|
||||
EXPECT_TRUE(stream_data_provider->empty());
|
||||
}
|
||||
#endif
|
||||
#endif // HAVE_ONEVPL
|
||||
|
||||
TEST(GAPI_Streaming, TestDesyncRMat) {
|
||||
cv::GMat in;
|
||||
|
348
modules/gapi/test/streaming/gapi_streaming_utils_test.cpp
Normal file
348
modules/gapi/test/streaming/gapi_streaming_utils_test.cpp
Normal file
@ -0,0 +1,348 @@
|
||||
// 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 "../test_precomp.hpp"
|
||||
|
||||
#include "../common/gapi_streaming_tests_common.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
|
||||
#define private public
|
||||
#include "streaming/onevpl/accelerators/utils/shared_lock.hpp"
|
||||
#undef private
|
||||
|
||||
#include "streaming/onevpl/accelerators/utils/elastic_barrier.hpp"
|
||||
|
||||
namespace opencv_test
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using cv::gapi::wip::onevpl::SharedLock;
|
||||
|
||||
struct TestBarrier : public cv::gapi::wip::onevpl::elastic_barrier<TestBarrier> {
|
||||
void on_first_in_impl(size_t visitor_id) {
|
||||
|
||||
static std::atomic<int> thread_counter{};
|
||||
thread_counter++;
|
||||
EXPECT_EQ(thread_counter.load(), 1);
|
||||
|
||||
visitors_in.insert(visitor_id);
|
||||
last_visitor_id = visitor_id;
|
||||
|
||||
thread_counter--;
|
||||
EXPECT_EQ(thread_counter.load(), 0);
|
||||
}
|
||||
|
||||
void on_last_out_impl(size_t visitor_id) {
|
||||
|
||||
static std::atomic<int> thread_counter{};
|
||||
thread_counter++;
|
||||
EXPECT_EQ(thread_counter.load(), 1);
|
||||
|
||||
visitors_out.insert(visitor_id);
|
||||
last_visitor_id = visitor_id;
|
||||
|
||||
thread_counter--;
|
||||
EXPECT_EQ(thread_counter.load(), 0);
|
||||
}
|
||||
|
||||
size_t last_visitor_id = 0;
|
||||
std::set<size_t> visitors_in;
|
||||
std::set<size_t> visitors_out;
|
||||
};
|
||||
|
||||
TEST(OneVPL_SharedLock, Create) {
|
||||
SharedLock lock;
|
||||
EXPECT_EQ(lock.shared_counter.load(), size_t{0});
|
||||
}
|
||||
|
||||
TEST(OneVPL_SharedLock, Read_SingleThread)
|
||||
{
|
||||
SharedLock lock;
|
||||
|
||||
const size_t single_thread_read_count = 100;
|
||||
for(size_t i = 0; i < single_thread_read_count; i++) {
|
||||
lock.shared_lock();
|
||||
EXPECT_FALSE(lock.owns());
|
||||
}
|
||||
EXPECT_EQ(lock.shared_counter.load(), single_thread_read_count);
|
||||
|
||||
for(size_t i = 0; i < single_thread_read_count; i++) {
|
||||
lock.unlock_shared();
|
||||
EXPECT_FALSE(lock.owns());
|
||||
}
|
||||
|
||||
EXPECT_EQ(lock.shared_counter.load(), size_t{0});
|
||||
}
|
||||
|
||||
TEST(OneVPL_SharedLock, TryLock_SingleThread)
|
||||
{
|
||||
SharedLock lock;
|
||||
|
||||
EXPECT_TRUE(lock.try_lock());
|
||||
EXPECT_TRUE(lock.owns());
|
||||
|
||||
lock.unlock();
|
||||
EXPECT_FALSE(lock.owns());
|
||||
EXPECT_EQ(lock.shared_counter.load(), size_t{0});
|
||||
}
|
||||
|
||||
TEST(OneVPL_SharedLock, Write_SingleThread)
|
||||
{
|
||||
SharedLock lock;
|
||||
|
||||
lock.lock();
|
||||
EXPECT_TRUE(lock.owns());
|
||||
|
||||
lock.unlock();
|
||||
EXPECT_FALSE(lock.owns());
|
||||
EXPECT_EQ(lock.shared_counter.load(), size_t{0});
|
||||
}
|
||||
|
||||
TEST(OneVPL_SharedLock, TryLockTryLock_SingleThread)
|
||||
{
|
||||
SharedLock lock;
|
||||
|
||||
lock.try_lock();
|
||||
EXPECT_FALSE(lock.try_lock());
|
||||
lock.unlock();
|
||||
|
||||
EXPECT_FALSE(lock.owns());
|
||||
}
|
||||
|
||||
TEST(OneVPL_SharedLock, ReadTryLock_SingleThread)
|
||||
{
|
||||
SharedLock lock;
|
||||
|
||||
lock.shared_lock();
|
||||
EXPECT_FALSE(lock.owns());
|
||||
EXPECT_FALSE(lock.try_lock());
|
||||
lock.unlock_shared();
|
||||
|
||||
EXPECT_TRUE(lock.try_lock());
|
||||
EXPECT_TRUE(lock.owns());
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
TEST(OneVPL_SharedLock, WriteTryLock_SingleThread)
|
||||
{
|
||||
SharedLock lock;
|
||||
|
||||
lock.lock();
|
||||
EXPECT_TRUE(lock.owns());
|
||||
EXPECT_FALSE(lock.try_lock());
|
||||
lock.unlock();
|
||||
|
||||
EXPECT_TRUE(lock.try_lock());
|
||||
EXPECT_TRUE(lock.owns());
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
|
||||
TEST(OneVPL_SharedLock, Write_MultiThread)
|
||||
{
|
||||
SharedLock lock;
|
||||
|
||||
std::promise<void> barrier;
|
||||
std::shared_future<void> sync = barrier.get_future();
|
||||
|
||||
static const size_t inc_count = 10000000;
|
||||
size_t shared_value = 0;
|
||||
auto work = [&lock, &shared_value](size_t count) {
|
||||
for (size_t i = 0; i < count; i ++) {
|
||||
lock.lock();
|
||||
shared_value ++;
|
||||
lock.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
std::thread worker_thread([&barrier, sync, work] () {
|
||||
|
||||
std::thread sub_worker([&barrier, work] () {
|
||||
barrier.set_value();
|
||||
work(inc_count);
|
||||
});
|
||||
|
||||
sync.wait();
|
||||
work(inc_count);
|
||||
sub_worker.join();
|
||||
});
|
||||
sync.wait();
|
||||
|
||||
work(inc_count);
|
||||
worker_thread.join();
|
||||
|
||||
EXPECT_EQ(shared_value, inc_count * 3);
|
||||
}
|
||||
|
||||
TEST(OneVPL_SharedLock, ReadWrite_MultiThread)
|
||||
{
|
||||
SharedLock lock;
|
||||
|
||||
std::promise<void> barrier;
|
||||
std::future<void> sync = barrier.get_future();
|
||||
|
||||
static const size_t inc_count = 10000000;
|
||||
size_t shared_value = 0;
|
||||
auto write_work = [&lock, &shared_value](size_t count) {
|
||||
for (size_t i = 0; i < count; i ++) {
|
||||
lock.lock();
|
||||
shared_value ++;
|
||||
lock.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
auto read_work = [&lock, &shared_value](size_t count) {
|
||||
|
||||
auto old_shared_value = shared_value;
|
||||
for (size_t i = 0; i < count; i ++) {
|
||||
lock.shared_lock();
|
||||
EXPECT_TRUE(shared_value >= old_shared_value);
|
||||
old_shared_value = shared_value;
|
||||
lock.unlock_shared();
|
||||
}
|
||||
};
|
||||
|
||||
std::thread writer_thread([&barrier, write_work] () {
|
||||
barrier.set_value();
|
||||
write_work(inc_count);
|
||||
});
|
||||
sync.wait();
|
||||
|
||||
read_work(inc_count);
|
||||
writer_thread.join();
|
||||
|
||||
EXPECT_EQ(shared_value, inc_count);
|
||||
}
|
||||
|
||||
|
||||
TEST(OneVPL_ElasticBarrier, single_thread_visit)
|
||||
{
|
||||
TestBarrier barrier;
|
||||
|
||||
const size_t max_visit_count = 10000;
|
||||
size_t visit_id = 0;
|
||||
for (visit_id = 0; visit_id < max_visit_count; visit_id++) {
|
||||
barrier.visit_in(visit_id);
|
||||
EXPECT_EQ(barrier.visitors_in.size(), size_t{1});
|
||||
}
|
||||
EXPECT_EQ(barrier.last_visitor_id, size_t{0});
|
||||
EXPECT_EQ(barrier.visitors_out.size(), size_t{0});
|
||||
|
||||
for (visit_id = 0; visit_id < max_visit_count; visit_id++) {
|
||||
barrier.visit_out(visit_id);
|
||||
EXPECT_EQ(barrier.visitors_in.size(), size_t{1});
|
||||
}
|
||||
EXPECT_EQ(barrier.last_visitor_id, visit_id - 1);
|
||||
EXPECT_EQ(barrier.visitors_out.size(), size_t{1});
|
||||
}
|
||||
|
||||
|
||||
TEST(OneVPL_ElasticBarrier, multi_thread_visit)
|
||||
{
|
||||
TestBarrier tested_barrier;
|
||||
|
||||
static const size_t max_visit_count = 10000000;
|
||||
std::atomic<size_t> visit_in_wait_counter{};
|
||||
std::promise<void> start_sync_barrier;
|
||||
std::shared_future<void> start_sync = start_sync_barrier.get_future();
|
||||
std::promise<void> phase_sync_barrier;
|
||||
std::shared_future<void> phase_sync = phase_sync_barrier.get_future();
|
||||
|
||||
auto visit_worker_job = [&tested_barrier,
|
||||
&visit_in_wait_counter,
|
||||
start_sync,
|
||||
phase_sync] (size_t worker_id) {
|
||||
|
||||
start_sync.wait();
|
||||
|
||||
// first phase
|
||||
const size_t begin_range = worker_id * max_visit_count;
|
||||
const size_t end_range = (worker_id + 1) * max_visit_count;
|
||||
for (size_t visit_id = begin_range; visit_id < end_range; visit_id++) {
|
||||
tested_barrier.visit_in(visit_id);
|
||||
}
|
||||
|
||||
// notify all worker first phase ready
|
||||
visit_in_wait_counter.fetch_add(1);
|
||||
|
||||
// wait main second phase
|
||||
phase_sync.wait();
|
||||
|
||||
// second phase
|
||||
for (size_t visit_id = begin_range; visit_id < end_range; visit_id++) {
|
||||
tested_barrier.visit_out(visit_id);
|
||||
}
|
||||
};
|
||||
|
||||
auto visit_main_job = [&tested_barrier,
|
||||
&visit_in_wait_counter,
|
||||
&phase_sync_barrier] (size_t total_workers_count,
|
||||
size_t worker_id) {
|
||||
|
||||
const size_t begin_range = worker_id * max_visit_count;
|
||||
const size_t end_range = (worker_id + 1) * max_visit_count;
|
||||
for (size_t visit_id = begin_range; visit_id < end_range; visit_id++) {
|
||||
tested_barrier.visit_in(visit_id);
|
||||
}
|
||||
|
||||
// wait all workers first phase done
|
||||
visit_in_wait_counter.fetch_add(1);
|
||||
while (visit_in_wait_counter.load() != total_workers_count) {
|
||||
std::this_thread::yield();
|
||||
};
|
||||
|
||||
// TEST invariant: last_visitor_id MUST be one from any FIRST worker visitor_id
|
||||
bool one_of_available_ids_matched = false;
|
||||
for (size_t id = 0; id < total_workers_count; id ++) {
|
||||
size_t expected_last_visitor_for_id = id * max_visit_count;
|
||||
one_of_available_ids_matched |=
|
||||
(tested_barrier.last_visitor_id == expected_last_visitor_for_id) ;
|
||||
}
|
||||
EXPECT_TRUE(one_of_available_ids_matched);
|
||||
|
||||
// unblock all workers to work out second phase
|
||||
phase_sync_barrier.set_value();
|
||||
|
||||
// continue second phase
|
||||
for (size_t visit_id = begin_range; visit_id < end_range; visit_id++) {
|
||||
tested_barrier.visit_out(visit_id);
|
||||
}
|
||||
};
|
||||
|
||||
size_t max_worker_count = std::thread::hardware_concurrency();
|
||||
if (max_worker_count < 2) {
|
||||
max_worker_count = 2; // logical 2 threads required at least
|
||||
}
|
||||
std::vector<std::thread> workers;
|
||||
workers.reserve(max_worker_count);
|
||||
for (size_t worker_id = 1; worker_id < max_worker_count; worker_id++) {
|
||||
workers.emplace_back(visit_worker_job, worker_id);
|
||||
}
|
||||
|
||||
// let's go for first phase
|
||||
start_sync_barrier.set_value();
|
||||
|
||||
// utilize main thread as well
|
||||
visit_main_job(max_worker_count, 0);
|
||||
|
||||
// join all threads second phase
|
||||
for (auto& w : workers) {
|
||||
w.join();
|
||||
}
|
||||
|
||||
// TEST invariant: last_visitor_id MUST be one from any LATTER worker visitor_id
|
||||
bool one_of_available_ids_matched = false;
|
||||
for (size_t id = 0; id < max_worker_count; id ++) {
|
||||
one_of_available_ids_matched |=
|
||||
(tested_barrier.last_visitor_id == ((id + 1) * max_visit_count - 1)) ;
|
||||
}
|
||||
EXPECT_TRUE(one_of_available_ids_matched);
|
||||
}
|
||||
}
|
||||
} // opencv_test
|
@ -7,7 +7,7 @@
|
||||
|
||||
#include "../test_precomp.hpp"
|
||||
|
||||
#include "../common/gapi_tests_common.hpp"
|
||||
#include "../common/gapi_streaming_tests_common.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
@ -27,14 +27,16 @@
|
||||
#include <opencv2/gapi/streaming/desync.hpp>
|
||||
#include <opencv2/gapi/streaming/format.hpp>
|
||||
|
||||
#include <opencv2/gapi/streaming/onevpl/source.hpp>
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
#include <opencv2/gapi/streaming/onevpl/data_provider_interface.hpp>
|
||||
#include "streaming/onevpl/cfg_param_device_selector.hpp"
|
||||
|
||||
#include "streaming/onevpl/accelerators/surface/surface.hpp"
|
||||
#include "streaming/onevpl/accelerators/surface/cpu_frame_adapter.hpp"
|
||||
#include "streaming/onevpl/accelerators/accel_policy_cpu.hpp"
|
||||
#include "streaming/onevpl/accelerators/accel_policy_dx11.hpp"
|
||||
#include "streaming/onevpl/accelerators/dx11_alloc_resource.hpp"
|
||||
#include "streaming/onevpl/accelerators/utils/shared_lock.hpp"
|
||||
#include "streaming/onevpl/engine/processing_engine_base.hpp"
|
||||
#include "streaming/onevpl/engine/engine_session.hpp"
|
||||
|
||||
@ -60,6 +62,11 @@ struct TestProcessingSession : public cv::gapi::wip::onevpl::EngineSession {
|
||||
TestProcessingSession(mfxSession mfx_session) :
|
||||
EngineSession(mfx_session, {}) {
|
||||
}
|
||||
|
||||
const mfxVideoParam& get_video_param() const override {
|
||||
static mfxVideoParam empty;
|
||||
return empty;
|
||||
}
|
||||
};
|
||||
|
||||
struct TestProcessingEngine: public cv::gapi::wip::onevpl::ProcessingEngineBase {
|
||||
@ -98,14 +105,66 @@ struct TestProcessingEngine: public cv::gapi::wip::onevpl::ProcessingEngineBase
|
||||
);
|
||||
}
|
||||
|
||||
void initialize_session(mfxSession mfx_session,
|
||||
cv::gapi::wip::onevpl::DecoderParams&&,
|
||||
std::shared_ptr<cv::gapi::wip::onevpl::IDataProvider>) override {
|
||||
std::shared_ptr<cv::gapi::wip::onevpl::EngineSession>
|
||||
initialize_session(mfxSession mfx_session,
|
||||
const std::vector<cv::gapi::wip::onevpl::CfgParam>&,
|
||||
std::shared_ptr<cv::gapi::wip::onevpl::IDataProvider>) override {
|
||||
|
||||
register_session<TestProcessingSession>(mfx_session);
|
||||
return register_session<TestProcessingSession>(mfx_session);
|
||||
}
|
||||
};
|
||||
|
||||
template <class LockProcessor, class UnlockProcessor>
|
||||
class TestLockableAllocator {
|
||||
public :
|
||||
using self_t = TestLockableAllocator<LockProcessor, UnlockProcessor>;
|
||||
mfxFrameAllocator get() {
|
||||
return m_allocator;
|
||||
}
|
||||
private:
|
||||
TestLockableAllocator(mfxFrameAllocator allocator) :
|
||||
m_allocator(allocator) {
|
||||
}
|
||||
|
||||
static mfxStatus MFX_CDECL lock_cb(mfxHDL, mfxMemId mid, mfxFrameData *ptr) {
|
||||
auto it = lock_processor_table.find(mid);
|
||||
EXPECT_TRUE(it != lock_processor_table.end());
|
||||
return it->second(mid, ptr);
|
||||
}
|
||||
static mfxStatus MFX_CDECL unlock_cb(mfxHDL, mfxMemId mid, mfxFrameData *ptr) {
|
||||
auto it = unlock_processor_table.find(mid);
|
||||
EXPECT_TRUE(it != unlock_processor_table.end());
|
||||
return it->second(mid, ptr);
|
||||
}
|
||||
|
||||
template <class L, class U>
|
||||
friend TestLockableAllocator<L,U> create_test_allocator(mfxMemId, L, U);
|
||||
|
||||
static std::map<mfxMemId, LockProcessor> lock_processor_table;
|
||||
static std::map<mfxMemId, UnlockProcessor> unlock_processor_table;
|
||||
|
||||
mfxFrameAllocator m_allocator;
|
||||
};
|
||||
template <class LockProcessor, class UnlockProcessor>
|
||||
std::map<mfxMemId, UnlockProcessor> TestLockableAllocator<LockProcessor, UnlockProcessor>::lock_processor_table {};
|
||||
|
||||
template <class LockProcessor, class UnlockProcessor>
|
||||
std::map<mfxMemId, UnlockProcessor> TestLockableAllocator<LockProcessor, UnlockProcessor>::unlock_processor_table {};
|
||||
|
||||
template <class LockProcessor, class UnlockProcessor>
|
||||
TestLockableAllocator<LockProcessor, UnlockProcessor>
|
||||
create_test_allocator(mfxMemId mid, LockProcessor lock_p, UnlockProcessor unlock_p) {
|
||||
mfxFrameAllocator allocator {};
|
||||
|
||||
TestLockableAllocator<LockProcessor, UnlockProcessor>::lock_processor_table[mid] = lock_p;
|
||||
allocator.Lock = &TestLockableAllocator<LockProcessor, UnlockProcessor>::lock_cb;
|
||||
|
||||
TestLockableAllocator<LockProcessor, UnlockProcessor>::unlock_processor_table[mid] = unlock_p;
|
||||
allocator.Unlock = &TestLockableAllocator<LockProcessor, UnlockProcessor>::unlock_cb;
|
||||
|
||||
return TestLockableAllocator<LockProcessor, UnlockProcessor> {allocator};
|
||||
}
|
||||
|
||||
cv::gapi::wip::onevpl::surface_ptr_t create_test_surface(std::shared_ptr<void> out_buf_ptr,
|
||||
size_t, size_t) {
|
||||
std::unique_ptr<mfxFrameSurface1> handle(new mfxFrameSurface1{});
|
||||
@ -262,8 +321,10 @@ TEST(OneVPL_Source_CPU_Accelerator, InitDestroy)
|
||||
{
|
||||
using cv::gapi::wip::onevpl::VPLCPUAccelerationPolicy;
|
||||
using cv::gapi::wip::onevpl::VPLAccelerationPolicy;
|
||||
using cv::gapi::wip::onevpl::CfgParamDeviceSelector;
|
||||
|
||||
auto acceleration_policy = std::make_shared<VPLCPUAccelerationPolicy>();
|
||||
auto acceleration_policy =
|
||||
std::make_shared<VPLCPUAccelerationPolicy>(std::make_shared<CfgParamDeviceSelector>());
|
||||
|
||||
size_t surface_count = 10;
|
||||
size_t surface_size_bytes = 1024;
|
||||
@ -292,9 +353,11 @@ TEST(OneVPL_Source_CPU_Accelerator, PoolProduceConsume)
|
||||
{
|
||||
using cv::gapi::wip::onevpl::VPLCPUAccelerationPolicy;
|
||||
using cv::gapi::wip::onevpl::VPLAccelerationPolicy;
|
||||
using cv::gapi::wip::onevpl::CfgParamDeviceSelector;
|
||||
using cv::gapi::wip::onevpl::Surface;
|
||||
|
||||
auto acceleration_policy = std::make_shared<VPLCPUAccelerationPolicy>();
|
||||
auto acceleration_policy =
|
||||
std::make_shared<VPLCPUAccelerationPolicy>(std::make_shared<CfgParamDeviceSelector>());
|
||||
|
||||
size_t surface_count = 10;
|
||||
size_t surface_size_bytes = 1024;
|
||||
@ -348,9 +411,11 @@ TEST(OneVPL_Source_CPU_Accelerator, PoolProduceConcurrentConsume)
|
||||
{
|
||||
using cv::gapi::wip::onevpl::VPLCPUAccelerationPolicy;
|
||||
using cv::gapi::wip::onevpl::VPLAccelerationPolicy;
|
||||
using cv::gapi::wip::onevpl::CfgParamDeviceSelector;
|
||||
using cv::gapi::wip::onevpl::Surface;
|
||||
|
||||
auto acceleration_policy = std::make_shared<VPLCPUAccelerationPolicy>();
|
||||
auto acceleration_policy =
|
||||
std::make_shared<VPLCPUAccelerationPolicy>(std::make_shared<CfgParamDeviceSelector>());
|
||||
|
||||
size_t surface_count = 10;
|
||||
size_t surface_size_bytes = 1024;
|
||||
@ -416,7 +481,7 @@ TEST(OneVPL_Source_ProcessingEngine, Init)
|
||||
TestProcessingEngine engine(std::move(accel));
|
||||
|
||||
mfxSession mfx_session{};
|
||||
engine.initialize_session(mfx_session, DecoderParams{}, std::shared_ptr<IDataProvider>{});
|
||||
engine.initialize_session(mfx_session, {}, std::shared_ptr<IDataProvider>{});
|
||||
|
||||
EXPECT_EQ(0, engine.get_ready_frames_count());
|
||||
ProcessingEngineBase::ExecutionStatus ret = engine.process(mfx_session);
|
||||
@ -444,6 +509,181 @@ TEST(OneVPL_Source_ProcessingEngine, Init)
|
||||
cv::gapi::wip::Data frame;
|
||||
engine.get_frame(frame);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DIRECTX
|
||||
#ifdef HAVE_D3D11
|
||||
TEST(OneVPL_Source_DX11_Accel, Init)
|
||||
{
|
||||
using namespace cv::gapi::wip::onevpl;
|
||||
|
||||
std::vector<CfgParam> cfg_params_w_dx11;
|
||||
cfg_params_w_dx11.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11));
|
||||
VPLDX11AccelerationPolicy accel(std::make_shared<CfgParamDeviceSelector>(cfg_params_w_dx11));
|
||||
|
||||
mfxLoader mfx_handle = MFXLoad();
|
||||
|
||||
mfxConfig cfg_inst_0 = MFXCreateConfig(mfx_handle);
|
||||
EXPECT_TRUE(cfg_inst_0);
|
||||
mfxVariant mfx_param_0;
|
||||
mfx_param_0.Type = MFX_VARIANT_TYPE_U32;
|
||||
mfx_param_0.Data.U32 = MFX_IMPL_TYPE_HARDWARE;
|
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_0,(mfxU8 *)CfgParam::implementation_name(),
|
||||
mfx_param_0), MFX_ERR_NONE);
|
||||
|
||||
mfxConfig cfg_inst_1 = MFXCreateConfig(mfx_handle);
|
||||
EXPECT_TRUE(cfg_inst_1);
|
||||
mfxVariant mfx_param_1;
|
||||
mfx_param_1.Type = MFX_VARIANT_TYPE_U32;
|
||||
mfx_param_1.Data.U32 = MFX_ACCEL_MODE_VIA_D3D11;
|
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_1,(mfxU8 *)CfgParam::acceleration_mode_name(),
|
||||
mfx_param_1), MFX_ERR_NONE);
|
||||
|
||||
mfxConfig cfg_inst_2 = MFXCreateConfig(mfx_handle);
|
||||
EXPECT_TRUE(cfg_inst_2);
|
||||
mfxVariant mfx_param_2;
|
||||
mfx_param_2.Type = MFX_VARIANT_TYPE_U32;
|
||||
mfx_param_2.Data.U32 = MFX_CODEC_HEVC;
|
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_2,(mfxU8 *)CfgParam::decoder_id_name(),
|
||||
mfx_param_2), MFX_ERR_NONE);
|
||||
|
||||
// create session
|
||||
mfxSession mfx_session{};
|
||||
mfxStatus sts = MFXCreateSession(mfx_handle, 0, &mfx_session);
|
||||
EXPECT_EQ(MFX_ERR_NONE, sts);
|
||||
|
||||
// assign acceleration
|
||||
EXPECT_NO_THROW(accel.init(mfx_session));
|
||||
|
||||
// create proper bitstream
|
||||
mfxBitstream bitstream{};
|
||||
const int BITSTREAM_BUFFER_SIZE = 2000000;
|
||||
bitstream.MaxLength = BITSTREAM_BUFFER_SIZE;
|
||||
bitstream.Data = (mfxU8 *)calloc(bitstream.MaxLength, sizeof(mfxU8));
|
||||
EXPECT_TRUE(bitstream.Data);
|
||||
|
||||
// simulate read stream
|
||||
bitstream.DataOffset = 0;
|
||||
bitstream.DataLength = sizeof(streaming::onevpl::hevc_header) * sizeof(streaming::onevpl::hevc_header[0]);
|
||||
memcpy(bitstream.Data, streaming::onevpl::hevc_header, bitstream.DataLength);
|
||||
bitstream.CodecId = MFX_CODEC_HEVC;
|
||||
|
||||
// prepare dec params
|
||||
mfxVideoParam mfxDecParams {};
|
||||
mfxDecParams.mfx.CodecId = bitstream.CodecId;
|
||||
mfxDecParams.IOPattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY;
|
||||
sts = MFXVideoDECODE_DecodeHeader(mfx_session, &bitstream, &mfxDecParams);
|
||||
EXPECT_EQ(MFX_ERR_NONE, sts);
|
||||
|
||||
mfxFrameAllocRequest request{};
|
||||
memset(&request, 0, sizeof(request));
|
||||
sts = MFXVideoDECODE_QueryIOSurf(mfx_session, &mfxDecParams, &request);
|
||||
EXPECT_EQ(MFX_ERR_NONE, sts);
|
||||
|
||||
// Allocate surfaces for decoder
|
||||
VPLAccelerationPolicy::pool_key_t key = accel.create_surface_pool(request,
|
||||
mfxDecParams);
|
||||
auto cand_surface = accel.get_free_surface(key).lock();
|
||||
|
||||
sts = MFXVideoDECODE_Init(mfx_session, &mfxDecParams);
|
||||
EXPECT_EQ(MFX_ERR_NONE, sts);
|
||||
|
||||
MFXVideoDECODE_Close(mfx_session);
|
||||
EXPECT_EQ(MFX_ERR_NONE, sts);
|
||||
|
||||
EXPECT_NO_THROW(accel.deinit(mfx_session));
|
||||
MFXClose(mfx_session);
|
||||
MFXUnload(mfx_handle);
|
||||
}
|
||||
#endif // HAVE_DIRECTX
|
||||
#endif // HAVE_D3D11
|
||||
|
||||
TEST(OneVPL_Source_DX11_FrameLockable, LockUnlock_without_Adaptee)
|
||||
{
|
||||
using namespace cv::gapi::wip::onevpl;
|
||||
mfxMemId mid = 0;
|
||||
int lock_counter = 0;
|
||||
int unlock_counter = 0;
|
||||
|
||||
std::function<mfxStatus(mfxMemId, mfxFrameData *)> lock =
|
||||
[&lock_counter] (mfxMemId, mfxFrameData *) {
|
||||
lock_counter ++;
|
||||
return MFX_ERR_NONE;
|
||||
};
|
||||
std::function<mfxStatus(mfxMemId, mfxFrameData *)> unlock =
|
||||
[&unlock_counter] (mfxMemId, mfxFrameData *) {
|
||||
unlock_counter++;
|
||||
return MFX_ERR_NONE;
|
||||
};
|
||||
|
||||
auto test_allocator = create_test_allocator(mid, lock, unlock);
|
||||
LockAdapter adapter(test_allocator.get());
|
||||
|
||||
mfxFrameData data;
|
||||
const int exec_count = 123;
|
||||
for (int i = 0; i < exec_count; i ++) {
|
||||
EXPECT_EQ(adapter.read_lock(mid, data), 0);
|
||||
adapter.write_lock(mid, data);
|
||||
EXPECT_EQ(adapter.unlock_read(mid, data), 0);
|
||||
adapter.unlock_write(mid, data);
|
||||
}
|
||||
|
||||
EXPECT_EQ(lock_counter, exec_count * 2);
|
||||
EXPECT_EQ(unlock_counter, exec_count * 2);
|
||||
}
|
||||
|
||||
TEST(OneVPL_Source_DX11_FrameLockable, LockUnlock_with_Adaptee)
|
||||
{
|
||||
using namespace cv::gapi::wip::onevpl;
|
||||
mfxMemId mid = 0;
|
||||
int r_lock_counter = 0;
|
||||
int r_unlock_counter = 0;
|
||||
int w_lock_counter = 0;
|
||||
int w_unlock_counter = 0;
|
||||
|
||||
SharedLock adaptee;
|
||||
std::function<mfxStatus(mfxMemId, mfxFrameData *)> lock =
|
||||
[&r_lock_counter, &w_lock_counter, &adaptee] (mfxMemId, mfxFrameData *) {
|
||||
if (adaptee.owns()) {
|
||||
w_lock_counter ++;
|
||||
} else {
|
||||
r_lock_counter ++;
|
||||
}
|
||||
return MFX_ERR_NONE;
|
||||
};
|
||||
std::function<mfxStatus(mfxMemId, mfxFrameData *)> unlock =
|
||||
[&r_unlock_counter, &w_unlock_counter, &adaptee] (mfxMemId, mfxFrameData *) {
|
||||
if (adaptee.owns()) {
|
||||
w_unlock_counter ++;
|
||||
} else {
|
||||
r_unlock_counter ++;
|
||||
}
|
||||
return MFX_ERR_NONE;
|
||||
};
|
||||
|
||||
auto test_allocator = create_test_allocator(mid, lock, unlock);
|
||||
LockAdapter adapter(test_allocator.get());
|
||||
|
||||
adapter.set_adaptee(&adaptee);
|
||||
|
||||
mfxFrameData data;
|
||||
const int exec_count = 123;
|
||||
for (int i = 0; i < exec_count; i ++) {
|
||||
EXPECT_EQ(adapter.read_lock(mid, data), 0);
|
||||
EXPECT_FALSE(adaptee.try_lock());
|
||||
|
||||
EXPECT_EQ(adapter.unlock_read(mid, data), 1);
|
||||
EXPECT_TRUE(adaptee.try_lock());
|
||||
adaptee.unlock();
|
||||
|
||||
adapter.write_lock(mid, data);
|
||||
adapter.unlock_write(mid, data);
|
||||
}
|
||||
|
||||
EXPECT_EQ(r_lock_counter, exec_count);
|
||||
EXPECT_EQ(r_unlock_counter, exec_count);
|
||||
EXPECT_EQ(w_lock_counter, exec_count);
|
||||
EXPECT_EQ(w_unlock_counter, exec_count);
|
||||
}
|
||||
}
|
||||
} // namespace opencv_test
|
||||
#endif // HAVE_ONEVPL
|
||||
|
@ -39,8 +39,6 @@ array_element_t files[] = {
|
||||
true, true, true},
|
||||
array_element_t {"highgui/video/sample_322x242_15frames.yuv420p.libvpx-vp9.mp4",
|
||||
true, true, true},
|
||||
array_element_t {"highgui/video/sample_322x242_15frames.yuv420p.libx264.avi",
|
||||
true, true, true},
|
||||
array_element_t {"highgui/video/sample_322x242_15frames.yuv420p.libx264.mp4",
|
||||
true, true, true},
|
||||
array_element_t {"highgui/video/sample_322x242_15frames.yuv420p.libx265.mp4",
|
||||
@ -82,7 +80,7 @@ TEST_P(OneVPL_Source_MFPAsyncDispatcherTest, open_and_decode_file)
|
||||
mfxVariant mfx_param_0;
|
||||
mfx_param_0.Type = MFX_VARIANT_TYPE_U32;
|
||||
mfx_param_0.Data.U32 = provider_ptr->get_mfx_codec_id();
|
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_0,(mfxU8 *)"mfxImplDescription.mfxDecoderDescription.decoder.CodecID",
|
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_0,(mfxU8 *)CfgParam::decoder_id_name(),
|
||||
mfx_param_0), MFX_ERR_NONE);
|
||||
|
||||
// create MFX session
|
||||
@ -135,7 +133,7 @@ TEST_P(OneVPL_Source_MFPAsyncDispatcherTest, choose_dmux_provider)
|
||||
EXPECT_FALSE(dd_result);
|
||||
provider_ptr = DataProviderDispatcher::create(path,
|
||||
{ CfgParam::create<std::string>(
|
||||
"mfxImplDescription.mfxDecoderDescription.decoder.CodecID",
|
||||
CfgParam::decoder_id_name(),
|
||||
"MFX_CODEC_HEVC") /* Doesn't matter what codec for RAW here*/});
|
||||
EXPECT_TRUE(std::dynamic_pointer_cast<FileDataProvider>(provider_ptr));
|
||||
GTEST_SUCCEED();
|
||||
|
@ -30,7 +30,7 @@
|
||||
#endif // HAVE_DIRECTX
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
#include <vpl/mfxvideo.h>
|
||||
#include "streaming/onevpl/onevpl_export.hpp"
|
||||
#include "streaming/onevpl/cfg_param_device_selector.hpp"
|
||||
|
||||
namespace opencv_test
|
||||
@ -94,8 +94,7 @@ TEST(OneVPL_Source_Device_Selector_CfgParam, DefaultDeviceWithAccelNACfgParam)
|
||||
{
|
||||
using namespace cv::gapi::wip::onevpl;
|
||||
std::vector<CfgParam> cfg_params_w_no_accel;
|
||||
cfg_params_w_no_accel.push_back(CfgParam::create<uint32_t>("mfxImplDescription.AccelerationMode",
|
||||
MFX_ACCEL_MODE_NA));
|
||||
cfg_params_w_no_accel.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_NA));
|
||||
CfgParamDeviceSelector selector(cfg_params_w_no_accel);
|
||||
IDeviceSelector::DeviceScoreTable devs = selector.select_devices();
|
||||
EXPECT_EQ(devs.size(), 1);
|
||||
@ -126,8 +125,7 @@ TEST(OneVPL_Source_Device_Selector_CfgParam, DefaultDeviceWithDX11AccelCfgParam_
|
||||
{
|
||||
using namespace cv::gapi::wip::onevpl;
|
||||
std::vector<CfgParam> cfg_params_w_dx11;
|
||||
cfg_params_w_dx11.push_back(CfgParam::create<uint32_t>("mfxImplDescription.AccelerationMode",
|
||||
MFX_ACCEL_MODE_VIA_D3D11));
|
||||
cfg_params_w_dx11.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11));
|
||||
std::unique_ptr<CfgParamDeviceSelector> selector_ptr;
|
||||
EXPECT_NO_THROW(selector_ptr.reset(new CfgParamDeviceSelector(cfg_params_w_dx11)));
|
||||
IDeviceSelector::DeviceScoreTable devs = selector_ptr->select_devices();
|
||||
@ -146,8 +144,7 @@ TEST(OneVPL_Source_Device_Selector_CfgParam, NULLDeviceWithDX11AccelCfgParam_DX1
|
||||
{
|
||||
using namespace cv::gapi::wip::onevpl;
|
||||
std::vector<CfgParam> cfg_params_w_dx11;
|
||||
cfg_params_w_dx11.push_back(CfgParam::create<uint32_t>("mfxImplDescription.AccelerationMode",
|
||||
MFX_ACCEL_MODE_VIA_D3D11));
|
||||
cfg_params_w_dx11.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11));
|
||||
Device::Ptr empty_device_ptr = nullptr;
|
||||
Context::Ptr empty_ctx_ptr = nullptr;
|
||||
EXPECT_THROW(CfgParamDeviceSelector sel(empty_device_ptr, "GPU",
|
||||
@ -179,8 +176,7 @@ TEST(OneVPL_Source_Device_Selector_CfgParam, ExternalDeviceWithDX11AccelCfgParam
|
||||
|
||||
std::unique_ptr<CfgParamDeviceSelector> selector_ptr;
|
||||
std::vector<CfgParam> cfg_params_w_dx11;
|
||||
cfg_params_w_dx11.push_back(CfgParam::create<uint32_t>("mfxImplDescription.AccelerationMode",
|
||||
MFX_ACCEL_MODE_VIA_D3D11));
|
||||
cfg_params_w_dx11.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11));
|
||||
EXPECT_NO_THROW(selector_ptr.reset(new CfgParamDeviceSelector(device, "GPU",
|
||||
device_context,
|
||||
cfg_params_w_dx11)));
|
||||
@ -205,8 +201,7 @@ TEST(OneVPL_Source_Device_Selector_CfgParam, DX11DeviceFromCfgParamWithDX11Disab
|
||||
{
|
||||
using namespace cv::gapi::wip::onevpl;
|
||||
std::vector<CfgParam> cfg_params_w_non_existed_dx11;
|
||||
cfg_params_w_not_existed_dx11.push_back(CfgParam::create<uint32_t>("mfxImplDescription.AccelerationMode",
|
||||
MFX_ACCEL_MODE_VIA_D3D11));
|
||||
cfg_params_w_not_existed_dx11.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11));
|
||||
EXPECT_THROW(CfgParamDeviceSelector{cfg_params_w_non_existed_dx11},
|
||||
std::logic_error);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user