Merge pull request #21618 from sivanov-work:vpp_preproc_core
G-API: Add VPL/VPP preproc core module * Add BaseMediAdapter for VPL * Add PreprocSession & PreprocEngine interface part * Implement preproc UT, Fix base path * Add common PP interface, add common pp_params * Rough decoupling VPL & Preproc * Add syntax sugar for PP interface * Integrate VPP preproc in GIEbackend * Add PP bypass * Add perf tests for PP * Fix warning in vpl core UT * Add inner preproc resolution Unit Test * Remove VPP preproc description from single ROI sample * Apply SetROIBlob for diferent Infer operations * Eliminate extra branch-lines for cfg_param_parser & transcode_engine * Fix UT warning &PreprocSession compile * Fix compilation & warnings * Reduce Session&Engine code amount * Apply some comments * Revert IE changes, rename preproc * Fix for DX11 infer for OV: turn off texture array * Remove dependency PP on IE * Change fixture tests params * Apply other comments & turn off ROI for GPU * Fix compilation: remove forgotten INFER define * Apply debt comments * Fix PP UTs: add FrameInfo value comparator * Fix style * Remove standalone map for preproc frames storage * Add other commentspull/21658/head
parent
92312fbc0c
commit
8f1c502d2b
43 changed files with 2260 additions and 398 deletions
@ -0,0 +1,70 @@ |
||||
// 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) 2022 Intel Corporation
|
||||
|
||||
#include "streaming/onevpl/accelerators/surface/base_frame_adapter.hpp" |
||||
#include "streaming/onevpl/accelerators/surface/surface.hpp" |
||||
#include "logger.hpp" |
||||
|
||||
#ifdef HAVE_ONEVPL |
||||
#include "streaming/onevpl/onevpl_export.hpp" |
||||
|
||||
namespace cv { |
||||
namespace gapi { |
||||
namespace wip { |
||||
namespace onevpl { |
||||
BaseFrameAdapter::BaseFrameAdapter(std::shared_ptr<Surface> surface, SessionHandle assoc_handle): |
||||
parent_surface_ptr(surface), parent_handle(assoc_handle) { |
||||
GAPI_Assert(parent_surface_ptr && "Surface is nullptr"); |
||||
GAPI_Assert(parent_handle && "mfxSession is nullptr"); |
||||
|
||||
const Surface::info_t& info = parent_surface_ptr->get_info(); |
||||
GAPI_LOG_DEBUG(nullptr, "surface: " << parent_surface_ptr->get_handle() << |
||||
", w: " << info.Width << ", h: " << info.Height << |
||||
", p: " << parent_surface_ptr->get_data().Pitch << |
||||
", frame id: " << reinterpret_cast<void*>(this)); |
||||
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(); |
||||
} |
||||
|
||||
BaseFrameAdapter::~BaseFrameAdapter() { |
||||
// Each BaseFrameAdapter releases mfx surface counter
|
||||
// The last BaseFrameAdapter releases shared Surface pointer
|
||||
// The last surface pointer releases workspace memory
|
||||
GAPI_LOG_DEBUG(nullptr, "destroy frame id: " << reinterpret_cast<void*>(this)); |
||||
parent_surface_ptr->release_lock(); |
||||
} |
||||
|
||||
const std::shared_ptr<Surface>& BaseFrameAdapter::get_surface() const { |
||||
return parent_surface_ptr; |
||||
} |
||||
|
||||
std::shared_ptr<Surface> BaseFrameAdapter::surface() { |
||||
return parent_surface_ptr; |
||||
} |
||||
|
||||
const BaseFrameAdapter::SessionHandle BaseFrameAdapter::get_session_handle() const { |
||||
return parent_handle; |
||||
} |
||||
|
||||
cv::GFrameDesc BaseFrameAdapter::meta() const { |
||||
return frame_desc; |
||||
} |
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
#endif // HAVE_ONEVPL
|
@ -0,0 +1,43 @@ |
||||
// 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) 2022 Intel Corporation
|
||||
|
||||
#ifndef GAPI_STREAMING_ONEVPL_ACCELERATORS_SURFACE_BASE_FRAME_ADAPTER_HPP |
||||
#define GAPI_STREAMING_ONEVPL_ACCELERATORS_SURFACE_BASE_FRAME_ADAPTER_HPP |
||||
#include <memory> |
||||
|
||||
#include <opencv2/gapi/media.hpp> |
||||
#include "streaming/onevpl/accelerators/surface/surface.hpp" |
||||
|
||||
#ifdef HAVE_ONEVPL |
||||
|
||||
namespace cv { |
||||
namespace gapi { |
||||
namespace wip { |
||||
namespace onevpl { |
||||
class BaseFrameAdapter : public cv::MediaFrame::IAdapter { |
||||
public: |
||||
using SessionHandle = mfxSession; |
||||
|
||||
const std::shared_ptr<Surface>& get_surface() const; |
||||
const SessionHandle get_session_handle() const; |
||||
|
||||
cv::GFrameDesc meta() const override; |
||||
protected: |
||||
BaseFrameAdapter(std::shared_ptr<Surface> assoc_surface, SessionHandle assoc_handle); |
||||
~BaseFrameAdapter(); |
||||
std::shared_ptr<Surface> surface(); |
||||
|
||||
std::shared_ptr<Surface> parent_surface_ptr; |
||||
SessionHandle parent_handle; |
||||
GFrameDesc frame_desc; |
||||
}; |
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // HAVE_ONEVPL
|
||||
#endif // GAPI_STREAMING_ONEVPL_ACCELERATORS_SURFACE_BASE_FRAME_ADAPTER_HPP
|
@ -0,0 +1,459 @@ |
||||
// 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) 2022 Intel Corporation
|
||||
|
||||
#ifdef HAVE_ONEVPL |
||||
|
||||
#include <algorithm> |
||||
#include <exception> |
||||
|
||||
#include <opencv2/gapi/streaming/onevpl/data_provider_interface.hpp> |
||||
|
||||
#include "streaming/onevpl/engine/preproc/preproc_engine.hpp" |
||||
#include "streaming/onevpl/engine/preproc/preproc_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 "logger.hpp" |
||||
|
||||
#define ALIGN16(value) (((value + 15) >> 4) << 4) |
||||
|
||||
namespace cv { |
||||
namespace gapi { |
||||
namespace wip { |
||||
namespace onevpl { |
||||
|
||||
bool FrameInfoComparator::operator()(const mfxFrameInfo& lhs, const mfxFrameInfo& rhs) const { |
||||
return lhs < rhs; |
||||
} |
||||
|
||||
bool FrameInfoComparator::equal_to(const mfxFrameInfo& lhs, const mfxFrameInfo& rhs) { |
||||
return lhs == rhs; |
||||
} |
||||
|
||||
VPPPreprocEngine::VPPPreprocEngine(std::unique_ptr<VPLAccelerationPolicy>&& accel) : |
||||
ProcessingEngineBase(std::move(accel)) { |
||||
GAPI_LOG_INFO(nullptr, "Create VPP preprocessing engine"); |
||||
preprocessed_frames_count = 0; |
||||
create_pipeline( |
||||
// 0) preproc decoded surface with VPP params
|
||||
[this] (EngineSession& sess) -> ExecutionStatus |
||||
{ |
||||
session_type &my_sess = static_cast<session_type&>(sess); |
||||
while (!my_sess.sync_in_queue.empty()) { |
||||
do { |
||||
if (!my_sess.processing_surface_ptr.expired()) { |
||||
session_type::incoming_task pending_op = my_sess.sync_in_queue.front(); |
||||
GAPI_LOG_DEBUG(nullptr, "pending IN operations count: " << |
||||
my_sess.sync_in_queue.size() << |
||||
", sync id: " << |
||||
pending_op.sync_handle << |
||||
", surface: " << |
||||
pending_op.decoded_surface_ptr); |
||||
|
||||
my_sess.sync_in_queue.pop(); |
||||
auto *vpp_suface = my_sess.processing_surface_ptr.lock()->get_handle(); |
||||
|
||||
/* TODO: consider CROP/ROI here
|
||||
static int x_offset = 0; |
||||
static int y_offset = 0; |
||||
dec_surface->Info.CropX = x_offset; |
||||
dec_surface->Info.CropY = y_offset; |
||||
dec_surface->Info.CropW = 100 + x_offset++; |
||||
dec_surface->Info.CropH = 100 + y_offset++; |
||||
*/ |
||||
session_type::outgoing_task vpp_pending_op {pending_op.sync_handle, nullptr}; |
||||
my_sess.last_status = MFXVideoVPP_RunFrameVPPAsync(my_sess.session, |
||||
pending_op.decoded_surface_ptr, |
||||
vpp_suface, |
||||
nullptr, &vpp_pending_op.sync_handle); |
||||
vpp_pending_op.vpp_surface_ptr = vpp_suface; |
||||
|
||||
GAPI_LOG_DEBUG(nullptr, "Got VPP async operation" << |
||||
", sync id: " << |
||||
vpp_pending_op.sync_handle << |
||||
", dec surface: " << |
||||
pending_op.decoded_surface_ptr << |
||||
", trans surface: " << |
||||
vpp_pending_op.vpp_surface_ptr << |
||||
", status: " << |
||||
mfxstatus_to_string(my_sess.last_status)); |
||||
|
||||
// NB: process status
|
||||
if (my_sess.last_status == MFX_ERR_MORE_SURFACE || |
||||
my_sess.last_status == MFX_ERR_NONE) { |
||||
vpp_pending_op.vpp_surface_ptr->Data.Locked++; // TODO -S- workaround
|
||||
my_sess.vpp_out_queue.emplace(vpp_pending_op); |
||||
} |
||||
} |
||||
|
||||
try { |
||||
my_sess.swap_surface(*this); |
||||
} 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 VPP surface, reason: " << |
||||
ex.what()); |
||||
my_sess.processing_surface_ptr.reset(); |
||||
break; |
||||
} |
||||
} while(my_sess.last_status == MFX_ERR_MORE_SURFACE); |
||||
|
||||
if (my_sess.processing_surface_ptr.expired()) { |
||||
// TODO break main loop
|
||||
break; |
||||
} |
||||
} |
||||
return ExecutionStatus::Continue; |
||||
}, |
||||
// 1) Wait for ASYNC decode result
|
||||
[this] (EngineSession& sess) -> ExecutionStatus |
||||
{ |
||||
session_type& my_sess = static_cast<session_type&>(sess); |
||||
do { |
||||
if (!my_sess.vpp_out_queue.empty()) { // FIFO: check the oldest async operation complete
|
||||
session_type::outgoing_task& pending_op = my_sess.vpp_out_queue.front(); |
||||
sess.last_status = MFXVideoCORE_SyncOperation(sess.session, pending_op.sync_handle, 0); |
||||
|
||||
GAPI_LOG_DEBUG(nullptr, "pending VPP operations count: " << |
||||
my_sess.vpp_out_queue.size() << |
||||
", sync id: " << |
||||
pending_op.sync_handle << |
||||
", surface: " << |
||||
pending_op.vpp_surface_ptr << |
||||
", 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.vpp_surface_ptr); |
||||
} |
||||
} |
||||
} while (MFX_ERR_NONE == sess.last_status && !my_sess.vpp_out_queue.empty()); |
||||
return ExecutionStatus::Continue; |
||||
}, |
||||
// 2) Falls back on generic status procesing
|
||||
[this] (EngineSession& sess) -> ExecutionStatus |
||||
{ |
||||
return this->process_error(sess.last_status, static_cast<session_type&>(sess)); |
||||
} |
||||
); |
||||
} |
||||
|
||||
cv::util::optional<pp_params> VPPPreprocEngine::is_applicable(const cv::MediaFrame& in_frame) { |
||||
// TODO consider something smarter than RTI
|
||||
cv::util::optional<pp_params> ret; |
||||
BaseFrameAdapter *vpl_adapter = in_frame.get<BaseFrameAdapter>(); |
||||
GAPI_LOG_DEBUG(nullptr, "validate VPP preprocessing is applicable for frame"); |
||||
if (vpl_adapter) { |
||||
ret = cv::util::make_optional<pp_params>( |
||||
pp_params::create<vpp_pp_params>(vpl_adapter->get_session_handle(), |
||||
vpl_adapter->get_surface()->get_info())); |
||||
GAPI_LOG_DEBUG(nullptr, "VPP preprocessing applicable, session [" << |
||||
vpl_adapter->get_session_handle() << "]"); |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
pp_session VPPPreprocEngine::initialize_preproc(const pp_params& initial_frame_param, |
||||
const GFrameDesc& required_frame_descr) { |
||||
const vpp_pp_params ¶ms = initial_frame_param.get<vpp_pp_params>(); |
||||
|
||||
// adjust preprocessing settings
|
||||
mfxVideoParam mfxVPPParams{0}; |
||||
// NB: IN params for VPP session must be equal to decoded surface params
|
||||
mfxVPPParams.vpp.In = params.info; |
||||
|
||||
// NB: OUT params must refer to IN params of a network
|
||||
GAPI_LOG_DEBUG(nullptr, "network input size: " << required_frame_descr.size.width << |
||||
"x" << required_frame_descr.size.height); |
||||
mfxVPPParams.vpp.Out = mfxVPPParams.vpp.In; |
||||
switch (required_frame_descr.fmt) { |
||||
case MediaFormat::NV12: |
||||
mfxVPPParams.vpp.Out.FourCC = MFX_FOURCC_NV12; |
||||
break; |
||||
default: |
||||
GAPI_LOG_WARNING(nullptr, "Unsupported MediaFormat in preprocessing: " << |
||||
static_cast<int>(required_frame_descr.fmt) << |
||||
". Frame will be rejected"); |
||||
throw std::runtime_error("unsupported MediaFormat value in VPP preprocessing"); |
||||
} |
||||
|
||||
mfxVPPParams.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420; |
||||
mfxVPPParams.vpp.Out.Width = static_cast<mfxU16>(required_frame_descr.size.width); |
||||
mfxVPPParams.vpp.Out.Height = static_cast<mfxU16>(required_frame_descr.size.height); |
||||
mfxVPPParams.vpp.Out.CropW = mfxVPPParams.vpp.Out.Width; |
||||
mfxVPPParams.vpp.Out.CropH = mfxVPPParams.vpp.Out.Height; |
||||
|
||||
// check In & Out equally to bypass preproc
|
||||
if (mfxVPPParams.vpp.Out == mfxVPPParams.vpp.In) { |
||||
GAPI_LOG_DEBUG(nullptr, "no preproc required"); |
||||
return pp_session::create<EngineSession>(nullptr); |
||||
} |
||||
|
||||
// recalculate size param according to VPP alignment
|
||||
mfxVPPParams.vpp.Out.Width = ALIGN16(mfxVPPParams.vpp.Out.Width); |
||||
mfxVPPParams.vpp.Out.Height = ALIGN16(mfxVPPParams.vpp.Out.Height); |
||||
mfxVPPParams.vpp.Out.CropW = mfxVPPParams.vpp.Out.Width; |
||||
mfxVPPParams.vpp.Out.CropH = mfxVPPParams.vpp.Out.Height; |
||||
|
||||
GAPI_LOG_DEBUG(nullptr, "\nFrom:\n{\n" << mfx_frame_info_to_string(mfxVPPParams.vpp.In) << |
||||
"}\nTo:\n{\n" << mfx_frame_info_to_string(mfxVPPParams.vpp.Out) << "}"); |
||||
|
||||
// find existing session
|
||||
GAPI_LOG_DEBUG(nullptr, "Find existing VPPPreprocSession for requested frame params" |
||||
", total sessions: " << preproc_session_map.size()); |
||||
auto it = preproc_session_map.find(mfxVPPParams.vpp.In); |
||||
if (it != preproc_session_map.end()) { |
||||
GAPI_LOG_DEBUG(nullptr, "[" << it->second->session << "] found"); |
||||
return pp_session::create(std::static_pointer_cast<EngineSession>(it->second)); |
||||
} |
||||
|
||||
// NB: make some sanity checks
|
||||
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(); |
||||
// assign acceleration
|
||||
if (accel_type == AccelType::DX11) { |
||||
mfxVPPParams.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY; |
||||
} else { |
||||
mfxVPPParams.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY | MFX_IOPATTERN_OUT_SYSTEM_MEMORY; |
||||
} |
||||
|
||||
// clone existing VPL session to inherit VPL loader configuration
|
||||
// and avoid refer to any global state
|
||||
// TODO no clone due to clone issue
|
||||
|
||||
mfxSession mfx_vpp_session = params.handle; |
||||
mfxStatus sts = MFX_ERR_NONE; |
||||
|
||||
// TODO: simply use clone after VPL bug fixing
|
||||
//sts = MFXCloneSession(params.handle, &mfx_vpp_session);
|
||||
sts = MFXCreateSession(mfx_handle, impl_number, &mfx_vpp_session); |
||||
if (sts != MFX_ERR_NONE) { |
||||
GAPI_LOG_WARNING(nullptr, "Cannot clone VPP session, error: " << mfxstatus_to_string(sts)); |
||||
GAPI_Assert(false && "Cannot continue VPP preprocessing"); |
||||
} |
||||
|
||||
sts = MFXJoinSession(params.handle, mfx_vpp_session); |
||||
if (sts != MFX_ERR_NONE) { |
||||
GAPI_LOG_WARNING(nullptr, "Cannot join VPP sessions, error: " << mfxstatus_to_string(sts)); |
||||
GAPI_Assert(false && "Cannot continue VPP preprocessing"); |
||||
} |
||||
|
||||
GAPI_LOG_INFO(nullptr, "[" << mfx_vpp_session << "] starting pool allocation"); |
||||
VPLAccelerationPolicy::pool_key_t vpp_out_pool_key {}; |
||||
try { |
||||
// assign HW acceleration processor
|
||||
acceleration_policy->init(mfx_vpp_session); |
||||
try { |
||||
// ask to allocate external memory pool
|
||||
mfxFrameAllocRequest vppRequests[2]; |
||||
memset(&vppRequests, 0, sizeof(mfxFrameAllocRequest) * 2); |
||||
sts = MFXVideoVPP_QueryIOSurf(mfx_vpp_session, &mfxVPPParams, vppRequests); |
||||
if (MFX_ERR_NONE != sts) { |
||||
GAPI_LOG_WARNING(nullptr, "cannot execute MFXVideoVPP_QueryIOSurf, error: " << |
||||
mfxstatus_to_string(sts)); |
||||
throw std::runtime_error("Cannot execute MFXVideoVPP_QueryIOSurf"); |
||||
} |
||||
|
||||
// NB: Assing ID as upper limit descendant to distinguish specific VPP allocation
|
||||
// from decode allocations witch started from 0: by local module convention
|
||||
|
||||
static uint16_t request_id = 0; |
||||
vppRequests[1].AllocId = std::numeric_limits<uint16_t>::max() - request_id++; |
||||
GAPI_Assert(request_id != std::numeric_limits<uint16_t>::max() && "Something wrong"); |
||||
|
||||
vppRequests[1].Type |= MFX_MEMTYPE_FROM_VPPIN; |
||||
vpp_out_pool_key = acceleration_policy->create_surface_pool(vppRequests[1], |
||||
mfxVPPParams.vpp.Out); |
||||
|
||||
sts = MFXVideoVPP_Init(mfx_vpp_session, &mfxVPPParams); |
||||
if (MFX_ERR_NONE != sts) { |
||||
GAPI_LOG_WARNING(nullptr, "cannot Init VPP, error: " << |
||||
mfxstatus_to_string(sts)); |
||||
// TODO consider deallocate pool
|
||||
// but not necessary now cause every fail processed as GAPI_Assert
|
||||
throw std::runtime_error("Cannot init VPP, error: " + |
||||
mfxstatus_to_string(sts)); |
||||
} |
||||
} catch (const std::exception&) { |
||||
GAPI_LOG_WARNING(nullptr, "[" << mfx_vpp_session << "] allocation failed, rollback"); |
||||
acceleration_policy->deinit(mfx_vpp_session); |
||||
throw; |
||||
} |
||||
} catch (const std::exception&) { |
||||
MFXClose(mfx_vpp_session); |
||||
GAPI_Assert(false && "Cannot init preproc resources"); |
||||
} |
||||
|
||||
// create engine session after all
|
||||
session_ptr_type sess_ptr = register_session<session_type>(mfx_vpp_session, |
||||
mfxVPPParams); |
||||
sess_ptr->init_surface_pool(vpp_out_pool_key); |
||||
sess_ptr->swap_surface(*this); |
||||
|
||||
bool inserted = preproc_session_map.emplace(mfxVPPParams.vpp.In, sess_ptr).second; |
||||
GAPI_Assert(inserted && "preproc session is exist"); |
||||
GAPI_LOG_INFO(nullptr, "VPPPreprocSession created, total sessions: " << preproc_session_map.size()); |
||||
return pp_session::create(std::static_pointer_cast<EngineSession>(sess_ptr)); |
||||
} |
||||
|
||||
void VPPPreprocEngine::on_frame_ready(session_type& sess, |
||||
mfxFrameSurface1* ready_surface) |
||||
{ |
||||
GAPI_LOG_DEBUG(nullptr, "[" << sess.session << "], frame ready"); |
||||
|
||||
// manage memory ownership rely on acceleration policy
|
||||
ready_surface->Data.Locked--; // TODO -S- workaround
|
||||
VPLAccelerationPolicy::FrameConstructorArgs args{ready_surface, sess.session}; |
||||
auto frame_adapter = acceleration_policy->create_frame_adapter(sess.vpp_pool_id, |
||||
args); |
||||
ready_frames.emplace(cv::MediaFrame(std::move(frame_adapter)), sess.generate_frame_meta()); |
||||
|
||||
// pop away synced out object
|
||||
sess.vpp_out_queue.pop(); |
||||
} |
||||
|
||||
VPPPreprocEngine::session_ptr |
||||
VPPPreprocEngine::initialize_session(mfxSession, |
||||
const std::vector<CfgParam>&, |
||||
std::shared_ptr<IDataProvider>) { |
||||
return {}; |
||||
} |
||||
|
||||
cv::MediaFrame VPPPreprocEngine::run_sync(const pp_session& sess, const cv::MediaFrame& in_frame) { |
||||
|
||||
std::shared_ptr<EngineSession> pp_sess_impl = sess.get<EngineSession>(); |
||||
if (!pp_sess_impl) { |
||||
// bypass case
|
||||
return in_frame; |
||||
} |
||||
session_ptr_type s = std::static_pointer_cast<session_type>(pp_sess_impl); |
||||
GAPI_DbgAssert(s && "Session is nullptr"); |
||||
GAPI_DbgAssert(is_applicable(in_frame) && |
||||
"VPP preproc is not applicable for the given frame"); |
||||
BaseFrameAdapter *vpl_adapter = in_frame.get<BaseFrameAdapter>(); |
||||
if (!vpl_adapter) { |
||||
GAPI_LOG_WARNING(nullptr, "VPP preproc is inapplicable for a given frame. " |
||||
"Make sure the frame is collected using onevpl::GSource"); |
||||
throw std::runtime_error("VPP preproc is inapplicable for given frame"); |
||||
} |
||||
|
||||
// schedule decoded surface into preproc queue
|
||||
session_type::incoming_task in_preproc_request {nullptr, |
||||
vpl_adapter->get_surface()->get_handle(), |
||||
in_frame}; |
||||
s->sync_in_queue.emplace(in_preproc_request); |
||||
|
||||
// invoke pipeline to transform decoded surface into preprocessed surface
|
||||
try |
||||
{ |
||||
ExecutionStatus status = ExecutionStatus::Continue; |
||||
while (0 == get_ready_frames_count() && |
||||
status == ExecutionStatus::Continue) { |
||||
status = process(s->session); |
||||
} |
||||
|
||||
if (get_ready_frames_count() == 0) { |
||||
GAPI_LOG_WARNING(nullptr, "failed: cannot obtain preprocessed frames, last status: " << |
||||
ProcessingEngineBase::status_to_string(status)); |
||||
throw std::runtime_error("cannot finalize VPP preprocessing operation"); |
||||
} |
||||
} catch(const std::exception&) { |
||||
throw; |
||||
} |
||||
// obtain new frame is available
|
||||
cv::gapi::wip::Data data; |
||||
get_frame(data); |
||||
preprocessed_frames_count++; |
||||
GAPI_LOG_DEBUG(nullptr, "processed frames count: " << preprocessed_frames_count); |
||||
return cv::util::get<cv::MediaFrame>(data); |
||||
} |
||||
|
||||
ProcessingEngineBase::ExecutionStatus VPPPreprocEngine::process_error(mfxStatus status, session_type& sess) { |
||||
GAPI_LOG_DEBUG(nullptr, "status: " << mfxstatus_to_string(status)); |
||||
|
||||
switch (status) { |
||||
case MFX_ERR_NONE: |
||||
{ |
||||
// prepare sync object for new surface
|
||||
try { |
||||
sess.swap_surface(*this); |
||||
return ExecutionStatus::Continue; |
||||
} catch (const std::runtime_error& ex) { |
||||
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
|
||||
return ExecutionStatus::Processed; |
||||
case MFX_ERR_MORE_SURFACE: |
||||
{ |
||||
// The function requires more frame surface at output before decoding can proceed.
|
||||
// This applies to external memory allocations and should not be expected for
|
||||
// a simple internal allocation case like this
|
||||
try { |
||||
sess.swap_surface(*this); |
||||
return ExecutionStatus::Continue; |
||||
} catch (const std::runtime_error& ex) { |
||||
GAPI_LOG_WARNING(nullptr, "[" << sess.session << "] error: " << ex.what()); |
||||
return ExecutionStatus::Continue; // read more data
|
||||
} |
||||
break; |
||||
} |
||||
case MFX_ERR_DEVICE_LOST: |
||||
// For non-CPU implementations,
|
||||
// Cleanup if device is lost
|
||||
GAPI_DbgAssert(false && "VPPPreprocEngine::process_error - " |
||||
"MFX_ERR_DEVICE_LOST is not processed"); |
||||
break; |
||||
case MFX_WRN_DEVICE_BUSY: |
||||
// For non-CPU implementations,
|
||||
// Wait a few milliseconds then try again
|
||||
GAPI_DbgAssert(false && "VPPPreprocEngine::process_error - " |
||||
"MFX_WRN_DEVICE_BUSY is not processed"); |
||||
break; |
||||
case MFX_WRN_VIDEO_PARAM_CHANGED: |
||||
// The decoder detected a new sequence header in the bitstream.
|
||||
// Video parameters may have changed.
|
||||
// In external memory allocation case, might need to reallocate the output surface
|
||||
GAPI_LOG_WARNING(nullptr, "[" << sess.session << "] got MFX_WRN_VIDEO_PARAM_CHANGED"); |
||||
return ExecutionStatus::Continue; |
||||
break; |
||||
case MFX_ERR_INCOMPATIBLE_VIDEO_PARAM: |
||||
// The function detected that video parameters provided by the application
|
||||
// are incompatible with initialization parameters.
|
||||
// The application should close the component and then reinitialize it
|
||||
GAPI_DbgAssert(false && "VPPPreprocEngine::process_error - " |
||||
"MFX_ERR_INCOMPATIBLE_VIDEO_PARAM is not processed"); |
||||
break; |
||||
case MFX_ERR_REALLOC_SURFACE: |
||||
// Bigger surface_work required. May be returned only if
|
||||
// mfxInfoMFX::EnableReallocRequest was set to ON during initialization.
|
||||
// This applies to external memory allocations and should not be expected for
|
||||
// a simple internal allocation case like this
|
||||
GAPI_DbgAssert(false && "VPPPreprocEngine::process_error - " |
||||
"MFX_ERR_REALLOC_SURFACE is not processed"); |
||||
break; |
||||
case MFX_WRN_IN_EXECUTION: |
||||
GAPI_LOG_WARNING(nullptr, "[" << sess.session << "] got MFX_WRN_IN_EXECUTION"); |
||||
return ExecutionStatus::Continue; |
||||
default: |
||||
GAPI_LOG_WARNING(nullptr, "Unknown status code: " << mfxstatus_to_string(status) << |
||||
", decoded frames: " << sess.preprocessed_frames_count); |
||||
break; |
||||
} |
||||
|
||||
return ExecutionStatus::Failed; |
||||
} |
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
#endif // HAVE_ONEVPL
|
@ -0,0 +1,67 @@ |
||||
// 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) 2022 Intel Corporation
|
||||
|
||||
#ifndef GAPI_STREAMING_ONVPL_PREPROC_ENGINE_HPP |
||||
#define GAPI_STREAMING_ONVPL_PREPROC_ENGINE_HPP |
||||
#include <stdio.h> |
||||
#include <memory> |
||||
#include <unordered_map> |
||||
|
||||
#include "streaming/onevpl/engine/processing_engine_base.hpp" |
||||
#include "streaming/onevpl/accelerators/utils/shared_lock.hpp" |
||||
|
||||
#include "streaming/onevpl/engine/preproc_engine_interface.hpp" |
||||
|
||||
#ifdef HAVE_ONEVPL |
||||
#include "streaming/onevpl/onevpl_export.hpp" |
||||
|
||||
namespace cv { |
||||
namespace gapi { |
||||
namespace wip { |
||||
namespace onevpl { |
||||
// GAPI_EXPORTS for tests
|
||||
struct GAPI_EXPORTS FrameInfoComparator { |
||||
bool operator()(const mfxFrameInfo& lhs, const mfxFrameInfo& rhs) const; |
||||
static bool equal_to(const mfxFrameInfo& lhs, const mfxFrameInfo& rhs); |
||||
}; |
||||
|
||||
class VPPPreprocSession; |
||||
struct IDataProvider; |
||||
struct VPLAccelerationPolicy; |
||||
|
||||
// GAPI_EXPORTS for tests
|
||||
class GAPI_EXPORTS VPPPreprocEngine final : public ProcessingEngineBase, |
||||
public cv::gapi::wip::IPreprocEngine { |
||||
public: |
||||
using session_type = VPPPreprocSession; |
||||
using session_ptr_type = std::shared_ptr<session_type>; |
||||
|
||||
VPPPreprocEngine(std::unique_ptr<VPLAccelerationPolicy>&& accel); |
||||
|
||||
cv::util::optional<pp_params> is_applicable(const cv::MediaFrame& in_frame) override; |
||||
|
||||
pp_session initialize_preproc(const pp_params& initial_frame_param, |
||||
const GFrameDesc& required_frame_descr) override; |
||||
|
||||
cv::MediaFrame run_sync(const pp_session &session_handle, |
||||
const cv::MediaFrame& in_frame) override; |
||||
|
||||
private: |
||||
std::map<mfxFrameInfo, session_ptr_type, FrameInfoComparator> preproc_session_map; |
||||
void on_frame_ready(session_type& sess, |
||||
mfxFrameSurface1* ready_surface); |
||||
ExecutionStatus process_error(mfxStatus status, session_type& sess); |
||||
session_ptr initialize_session(mfxSession mfx_session, |
||||
const std::vector<CfgParam>& cfg_params, |
||||
std::shared_ptr<IDataProvider> provider) override; |
||||
size_t preprocessed_frames_count; |
||||
}; |
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
#endif // HAVE_ONEVPL
|
||||
#endif // GAPI_STREAMING_ONVPL_PREPROC_ENGINE_HPP
|
@ -0,0 +1,67 @@ |
||||
// 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) 2022 Intel Corporation
|
||||
|
||||
#ifdef HAVE_ONEVPL |
||||
|
||||
#include <chrono> |
||||
#include <exception> |
||||
|
||||
#include "streaming/onevpl/engine/preproc/preproc_session.hpp" |
||||
#include "streaming/onevpl/engine/preproc/preproc_engine.hpp" |
||||
#include "streaming/onevpl/accelerators/surface/surface.hpp" |
||||
#include "streaming/onevpl/utils.hpp" |
||||
#include "logger.hpp" |
||||
|
||||
namespace cv { |
||||
namespace gapi { |
||||
namespace wip { |
||||
namespace onevpl { |
||||
VPPPreprocSession::VPPPreprocSession(mfxSession sess, const mfxVideoParam& vpp_out_param) : |
||||
EngineSession(sess), |
||||
mfx_vpp_out_param(vpp_out_param), |
||||
processing_surface_ptr(), |
||||
sync_in_queue(), |
||||
vpp_out_queue(), |
||||
preprocessed_frames_count() |
||||
{ |
||||
} |
||||
|
||||
VPPPreprocSession::~VPPPreprocSession() { |
||||
GAPI_LOG_INFO(nullptr, "Close VPP for session: " << session); |
||||
MFXVideoVPP_Close(session); |
||||
} |
||||
|
||||
Data::Meta VPPPreprocSession::generate_frame_meta() { |
||||
const auto now = std::chrono::system_clock::now(); |
||||
const auto dur = std::chrono::duration_cast<std::chrono::microseconds> |
||||
(now.time_since_epoch()); |
||||
Data::Meta meta { |
||||
{cv::gapi::streaming::meta_tag::timestamp, int64_t{dur.count()} }, |
||||
{cv::gapi::streaming::meta_tag::seq_id, int64_t{preprocessed_frames_count++}} |
||||
}; |
||||
return meta; |
||||
} |
||||
|
||||
void VPPPreprocSession::swap_surface(VPPPreprocEngine& engine) { |
||||
VPLAccelerationPolicy* acceleration_policy = engine.get_accel(); |
||||
GAPI_Assert(acceleration_policy && "Empty acceleration_policy"); |
||||
request_free_surface(session, vpp_pool_id, *acceleration_policy, |
||||
processing_surface_ptr, true); |
||||
} |
||||
|
||||
void VPPPreprocSession::init_surface_pool(VPLAccelerationPolicy::pool_key_t key) { |
||||
GAPI_Assert(key && "Init preproc pull with empty key"); |
||||
vpp_pool_id = key; |
||||
} |
||||
|
||||
const mfxFrameInfo& VPPPreprocSession::get_video_param() const { |
||||
return mfx_vpp_out_param.vpp.Out; |
||||
} |
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
#endif // HAVE_ONEVPL
|
@ -0,0 +1,61 @@ |
||||
// 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) 2022 Intel Corporation
|
||||
|
||||
#ifndef GAPI_STREAMING_ONVPL_PREPROC_SESSION_HPP |
||||
#define GAPI_STREAMING_ONVPL_PREPROC_SESSION_HPP |
||||
#include <memory> |
||||
#include <queue> |
||||
|
||||
#include <opencv2/gapi/streaming/meta.hpp> |
||||
#include "streaming/onevpl/engine/engine_session.hpp" |
||||
#include "streaming/onevpl/accelerators/accel_policy_interface.hpp" |
||||
#include "streaming/onevpl/engine/preproc/vpp_preproc_defines.hpp" |
||||
|
||||
#ifdef HAVE_ONEVPL |
||||
|
||||
namespace cv { |
||||
namespace gapi { |
||||
namespace wip { |
||||
namespace onevpl { |
||||
class VPPPreprocEngine; |
||||
|
||||
class VPPPreprocSession : public EngineSession { |
||||
public: |
||||
friend class VPPPreprocEngine; |
||||
VPPPreprocSession(mfxSession sess, const mfxVideoParam &vpp_out_param); |
||||
~VPPPreprocSession(); |
||||
|
||||
Data::Meta generate_frame_meta(); |
||||
void swap_surface(VPPPreprocEngine& engine); |
||||
void init_surface_pool(VPLAccelerationPolicy::pool_key_t key); |
||||
|
||||
virtual const mfxFrameInfo& get_video_param() const override; |
||||
private: |
||||
mfxVideoParam mfx_vpp_out_param; |
||||
VPLAccelerationPolicy::pool_key_t vpp_pool_id; |
||||
std::weak_ptr<Surface> processing_surface_ptr; |
||||
|
||||
struct incoming_task { |
||||
mfxSyncPoint sync_handle; |
||||
mfxFrameSurface1* decoded_surface_ptr; |
||||
cv::MediaFrame decoded_frame_copy; |
||||
}; |
||||
|
||||
struct outgoing_task { |
||||
mfxSyncPoint sync_handle; |
||||
mfxFrameSurface1* vpp_surface_ptr; |
||||
}; |
||||
|
||||
std::queue<incoming_task> sync_in_queue; |
||||
std::queue<outgoing_task> vpp_out_queue; |
||||
int64_t preprocessed_frames_count; |
||||
}; |
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
#endif // HAVE_ONEVPL
|
||||
#endif // GAPI_STREAMING_ONVPL_PREPROC_SESSION_HPP
|
@ -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) 2022 Intel Corporation
|
||||
|
||||
#include <type_traits> |
||||
|
||||
#include "streaming/onevpl/engine/preproc/utils.hpp" |
||||
|
||||
#ifdef HAVE_ONEVPL |
||||
#include "streaming/onevpl/onevpl_export.hpp" |
||||
#include "logger.hpp" |
||||
|
||||
namespace cv { |
||||
namespace gapi { |
||||
namespace wip { |
||||
namespace onevpl { |
||||
namespace utils { |
||||
|
||||
cv::MediaFormat fourcc_to_MediaFormat(int value) { |
||||
switch (value) |
||||
{ |
||||
case MFX_FOURCC_BGRP: |
||||
return cv::MediaFormat::BGR; |
||||
case MFX_FOURCC_NV12: |
||||
return cv::MediaFormat::NV12; |
||||
default: |
||||
GAPI_LOG_WARNING(nullptr, "Unsupported FourCC format requested: " << value << |
||||
". Cannot cast to cv::MediaFrame"); |
||||
GAPI_Assert(false && "Unsupported FOURCC"); |
||||
|
||||
} |
||||
} |
||||
|
||||
int MediaFormat_to_fourcc(cv::MediaFormat value) { |
||||
switch (value) |
||||
{ |
||||
case cv::MediaFormat::BGR: |
||||
return MFX_FOURCC_BGRP; |
||||
case cv::MediaFormat::NV12: |
||||
return MFX_FOURCC_NV12; |
||||
default: |
||||
GAPI_LOG_WARNING(nullptr, "Unsupported cv::MediaFormat format requested: " << |
||||
static_cast<typename std::underlying_type<cv::MediaFormat>::type>(value) << |
||||
". Cannot cast to FourCC"); |
||||
GAPI_Assert(false && "Unsupported cv::MediaFormat"); |
||||
} |
||||
} |
||||
int MediaFormat_to_chroma(cv::MediaFormat value) { |
||||
switch (value) |
||||
{ |
||||
case cv::MediaFormat::BGR: |
||||
return MFX_CHROMAFORMAT_MONOCHROME; |
||||
case cv::MediaFormat::NV12: |
||||
return MFX_CHROMAFORMAT_YUV420; |
||||
default: |
||||
GAPI_LOG_WARNING(nullptr, "Unsupported cv::MediaFormat format requested: " << |
||||
static_cast<typename std::underlying_type<cv::MediaFormat>::type>(value) << |
||||
". Cannot cast to ChromaFormateIdc"); |
||||
GAPI_Assert(false && "Unsupported cv::MediaFormat"); |
||||
} |
||||
} |
||||
|
||||
mfxFrameInfo to_mfxFrameInfo(const cv::GFrameDesc& frame_info) { |
||||
mfxFrameInfo ret {0}; |
||||
ret.FourCC = MediaFormat_to_fourcc(frame_info.fmt); |
||||
ret.ChromaFormat = MediaFormat_to_chroma(frame_info.fmt); |
||||
ret.Width = frame_info.size.width; |
||||
ret.Height = frame_info.size.height; |
||||
ret.CropX = 0; |
||||
ret.CropY = 0; |
||||
ret.CropW = 0; |
||||
ret.CropH = 0; |
||||
ret.PicStruct = MFX_PICSTRUCT_UNKNOWN; |
||||
ret.FrameRateExtN = 0; |
||||
ret.FrameRateExtD = 0; |
||||
return ret; |
||||
} |
||||
} // namespace utils
|
||||
} // namespace cv
|
||||
} // namespace gapi
|
||||
} // namespace wip
|
||||
} // namespace onevpl
|
||||
|
||||
#endif // HAVE_ONEVPL
|
@ -0,0 +1,32 @@ |
||||
// 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) 2022 Intel Corporation
|
||||
|
||||
#ifndef GAPI_STREAMING_ONEVPL_PREPROC_UTILS_HPP |
||||
#define GAPI_STREAMING_ONEVPL_PREPROC_UTILS_HPP |
||||
|
||||
#ifdef HAVE_ONEVPL |
||||
#include "streaming/onevpl/onevpl_export.hpp" |
||||
|
||||
#include <opencv2/gapi/gframe.hpp> |
||||
|
||||
namespace cv { |
||||
namespace gapi { |
||||
namespace wip { |
||||
namespace onevpl { |
||||
namespace utils { |
||||
|
||||
cv::MediaFormat fourcc_to_MediaFormat(int value); |
||||
int MediaFormat_to_fourcc(cv::MediaFormat value); |
||||
int MediaFormat_to_chroma(cv::MediaFormat value); |
||||
|
||||
mfxFrameInfo to_mfxFrameInfo(const cv::GFrameDesc& frame_info); |
||||
} // namespace utils
|
||||
} // namespace cv
|
||||
} // namespace gapi
|
||||
} // namespace wip
|
||||
} // namespace onevpl
|
||||
#endif // #ifdef HAVE_ONEVPL
|
||||
#endif // GAPI_STREAMING_ONEVPL_PREPROC_UTILS_HPP
|
@ -0,0 +1,29 @@ |
||||
// 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) 2022 Intel Corporation
|
||||
|
||||
#ifdef HAVE_ONEVPL |
||||
|
||||
#ifndef VPP_PREPROC_ENGINE |
||||
#define VPP_PREPROC_ENGINE |
||||
#include "streaming/onevpl/onevpl_export.hpp" |
||||
#include "streaming/onevpl/engine/engine_session.hpp" |
||||
|
||||
namespace cv { |
||||
namespace gapi { |
||||
namespace wip { |
||||
namespace onevpl { |
||||
struct vpp_pp_params { |
||||
mfxSession handle; |
||||
mfxFrameInfo info; |
||||
}; |
||||
|
||||
using vpp_pp_session_ptr = std::shared_ptr<EngineSession>; |
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
#endif // VPP_PREPROC_ENGINE
|
||||
#endif // HAVE_ONEVPL
|
@ -0,0 +1,89 @@ |
||||
// 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) 2022 Intel Corporation
|
||||
|
||||
#ifndef GAPI_STREAMING_ONEVPL_ENGINE_PREPROC_DEFINES_HPP |
||||
#define GAPI_STREAMING_ONEVPL_ENGINE_PREPROC_DEFINES_HPP |
||||
|
||||
#ifdef HAVE_ONEVPL |
||||
#include "streaming/onevpl/utils.hpp" |
||||
#include "streaming/onevpl/engine/preproc/vpp_preproc_defines.hpp" |
||||
#endif // HAVE_ONEVPL
|
||||
|
||||
|
||||
namespace cv { |
||||
namespace gapi { |
||||
namespace wip { |
||||
|
||||
#ifdef VPP_PREPROC_ENGINE |
||||
#define GAPI_BACKEND_PP_PARAMS cv::gapi::wip::onevpl::vpp_pp_params |
||||
#define GAPI_BACKEND_PP_SESSIONS cv::gapi::wip::onevpl::vpp_pp_session_ptr |
||||
#else // VPP_PREPROC_ENGINE
|
||||
struct empty_pp_params {}; |
||||
struct empty_pp_session {}; |
||||
#define GAPI_BACKEND_PP_PARAMS cv::gapi::wip::empty_pp_params; |
||||
#define GAPI_BACKEND_PP_SESSIONS std::shared_ptr<cv::gapi::wip::empty_pp_session>; |
||||
#endif // VPP_PREPROC_ENGINE
|
||||
|
||||
struct pp_params { |
||||
using value_type = cv::util::variant<GAPI_BACKEND_PP_PARAMS>; |
||||
|
||||
template<typename BackendSpecificParamType, typename ...Args> |
||||
static pp_params create(Args&& ...args) { |
||||
static_assert(cv::detail::contains<BackendSpecificParamType, GAPI_BACKEND_PP_PARAMS>::value, |
||||
"Invalid BackendSpecificParamType requested"); |
||||
pp_params ret; |
||||
ret.value = BackendSpecificParamType{std::forward<Args>(args)...}; |
||||
return ret; |
||||
} |
||||
|
||||
template<typename BackendSpecificParamType> |
||||
BackendSpecificParamType& get() { |
||||
static_assert(cv::detail::contains<BackendSpecificParamType, GAPI_BACKEND_PP_PARAMS>::value, |
||||
"Invalid BackendSpecificParamType requested"); |
||||
return cv::util::get<BackendSpecificParamType>(value); |
||||
} |
||||
|
||||
template<typename BackendSpecificParamType> |
||||
const BackendSpecificParamType& get() const { |
||||
return static_cast<const BackendSpecificParamType&>(const_cast<pp_params*>(this)->get<BackendSpecificParamType>()); |
||||
} |
||||
private: |
||||
value_type value; |
||||
}; |
||||
|
||||
struct pp_session { |
||||
using value_type = cv::util::variant<GAPI_BACKEND_PP_SESSIONS>; |
||||
|
||||
template<typename BackendSpecificSesionType> |
||||
static pp_session create(std::shared_ptr<BackendSpecificSesionType> session) { |
||||
static_assert(cv::detail::contains<std::shared_ptr<BackendSpecificSesionType>, |
||||
GAPI_BACKEND_PP_SESSIONS>::value, |
||||
"Invalid BackendSpecificSesionType requested"); |
||||
pp_session ret; |
||||
ret.value = session; |
||||
return ret; |
||||
} |
||||
|
||||
template<typename BackendSpecificSesionType> |
||||
std::shared_ptr<BackendSpecificSesionType> get() { |
||||
using ptr_type = std::shared_ptr<BackendSpecificSesionType>; |
||||
static_assert(cv::detail::contains<ptr_type, GAPI_BACKEND_PP_SESSIONS>::value, |
||||
"Invalid BackendSpecificSesionType requested"); |
||||
return cv::util::get<ptr_type>(value); |
||||
} |
||||
|
||||
template<typename BackendSpecificSesionType> |
||||
std::shared_ptr<BackendSpecificSesionType> get() const { |
||||
return const_cast<pp_session*>(this)->get<BackendSpecificSesionType>(); |
||||
} |
||||
private: |
||||
value_type value; |
||||
}; |
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // GAPI_STREAMING_ONEVPL_ENGINE_PREPROC_DEFINES_HPP
|
@ -0,0 +1,35 @@ |
||||
// 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) 2022 Intel Corporation
|
||||
|
||||
#ifndef GAPI_STREAMING_ONEVPL_ENGINE_PROCESSING_ENGINE_INTERFACE_HPP |
||||
#define GAPI_STREAMING_ONEVPL_ENGINE_PROCESSING_ENGINE_INTERFACE_HPP |
||||
|
||||
#include "precomp.hpp" |
||||
#include <opencv2/gapi/media.hpp> |
||||
#include <opencv2/gapi/util/optional.hpp> |
||||
|
||||
#include "streaming/onevpl/engine/preproc_defines.hpp" |
||||
|
||||
namespace cv { |
||||
namespace gapi { |
||||
namespace wip { |
||||
|
||||
struct IPreprocEngine { |
||||
virtual ~IPreprocEngine() = default; |
||||
|
||||
virtual cv::util::optional<pp_params> |
||||
is_applicable(const cv::MediaFrame& in_frame) = 0; |
||||
|
||||
virtual pp_session |
||||
initialize_preproc(const pp_params& initial_frame_param, |
||||
const GFrameDesc& required_frame_descr) = 0; |
||||
virtual cv::MediaFrame |
||||
run_sync(const pp_session &sess, const cv::MediaFrame& in_frame) = 0; |
||||
}; |
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
#endif // GAPI_STREAMING_ONEVPL_ENGINE_PROCESSING_ENGINE_INTERFACE_HPP
|
@ -0,0 +1,495 @@ |
||||
// 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) 2022 Intel Corporation
|
||||
|
||||
|
||||
#include "../test_precomp.hpp" |
||||
|
||||
#include "../common/gapi_tests_common.hpp" |
||||
#include "../common/gapi_streaming_tests_common.hpp" |
||||
|
||||
#include <chrono> |
||||
#include <future> |
||||
#include <tuple> |
||||
|
||||
#include <opencv2/gapi/media.hpp> |
||||
#include <opencv2/gapi/cpu/core.hpp> |
||||
#include <opencv2/gapi/cpu/imgproc.hpp> |
||||
|
||||
#include <opencv2/gapi/fluid/core.hpp> |
||||
#include <opencv2/gapi/fluid/imgproc.hpp> |
||||
#include <opencv2/gapi/fluid/gfluidkernel.hpp> |
||||
|
||||
#include <opencv2/gapi/ocl/core.hpp> |
||||
#include <opencv2/gapi/ocl/imgproc.hpp> |
||||
|
||||
#include <opencv2/gapi/streaming/cap.hpp> |
||||
#include <opencv2/gapi/streaming/desync.hpp> |
||||
#include <opencv2/gapi/streaming/format.hpp> |
||||
|
||||
#ifdef HAVE_ONEVPL |
||||
|
||||
#include <opencv2/gapi/streaming/onevpl/data_provider_interface.hpp> |
||||
#include "streaming/onevpl/file_data_provider.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/surface/dx11_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" |
||||
#define private public |
||||
#define protected public |
||||
#include "streaming/onevpl/engine/decode/decode_engine_legacy.hpp" |
||||
#include "streaming/onevpl/engine/decode/decode_session.hpp" |
||||
|
||||
#include "streaming/onevpl/engine/preproc/preproc_engine.hpp" |
||||
#include "streaming/onevpl/engine/preproc/preproc_session.hpp" |
||||
|
||||
#include "streaming/onevpl/engine/transcode/transcode_engine_legacy.hpp" |
||||
#include "streaming/onevpl/engine/transcode/transcode_session.hpp" |
||||
#undef protected |
||||
#undef private |
||||
#include "logger.hpp" |
||||
|
||||
#define ALIGN16(value) (((value + 15) >> 4) << 4) |
||||
|
||||
namespace opencv_test |
||||
{ |
||||
namespace |
||||
{ |
||||
template<class ProcessingEngine> |
||||
cv::MediaFrame extract_decoded_frame(mfxSession sessId, ProcessingEngine& engine) { |
||||
using namespace cv::gapi::wip::onevpl; |
||||
ProcessingEngineBase::ExecutionStatus status = ProcessingEngineBase::ExecutionStatus::Continue; |
||||
while (0 == engine.get_ready_frames_count() && |
||||
status == ProcessingEngineBase::ExecutionStatus::Continue) { |
||||
status = engine.process(sessId); |
||||
} |
||||
|
||||
if (engine.get_ready_frames_count() == 0) { |
||||
GAPI_LOG_WARNING(nullptr, "failed: cannot obtain preprocessed frames, last status: " << |
||||
ProcessingEngineBase::status_to_string(status)); |
||||
throw std::runtime_error("cannot finalize VPP preprocessing operation"); |
||||
} |
||||
cv::gapi::wip::Data data; |
||||
engine.get_frame(data); |
||||
return cv::util::get<cv::MediaFrame>(data); |
||||
} |
||||
|
||||
std::tuple<mfxLoader, mfxConfig> prepare_mfx(int mfx_codec, int mfx_accel_mode) { |
||||
using namespace cv::gapi::wip::onevpl; |
||||
mfxLoader mfx = MFXLoad(); |
||||
mfxConfig cfg_inst_0 = MFXCreateConfig(mfx); |
||||
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); |
||||
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; |
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_1,(mfxU8 *)CfgParam::acceleration_mode_name(), |
||||
mfx_param_1), MFX_ERR_NONE); |
||||
|
||||
mfxConfig cfg_inst_2 = MFXCreateConfig(mfx); |
||||
EXPECT_TRUE(cfg_inst_2); |
||||
mfxVariant mfx_param_2; |
||||
mfx_param_2.Type = MFX_VARIANT_TYPE_U32; |
||||
mfx_param_2.Data.U32 = mfx_codec; |
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_2,(mfxU8 *)CfgParam::decoder_id_name(), |
||||
mfx_param_2), MFX_ERR_NONE); |
||||
|
||||
mfxConfig cfg_inst_3 = MFXCreateConfig(mfx); |
||||
EXPECT_TRUE(cfg_inst_3); |
||||
mfxVariant mfx_param_3; |
||||
mfx_param_3.Type = MFX_VARIANT_TYPE_U32; |
||||
mfx_param_3.Data.U32 = MFX_EXTBUFF_VPP_SCALING; |
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_3, |
||||
(mfxU8 *)"mfxImplDescription.mfxVPPDescription.filter.FilterFourCC", |
||||
mfx_param_3), MFX_ERR_NONE); |
||||
return std::make_tuple(mfx, cfg_inst_3); |
||||
} |
||||
|
||||
class SafeQueue { |
||||
public: |
||||
void push(cv::MediaFrame&& f) { |
||||
std::unique_lock<std::mutex> lock(mutex); |
||||
queue.push(std::move(f)); |
||||
cv.notify_all(); |
||||
} |
||||
|
||||
cv::MediaFrame pop() { |
||||
cv::MediaFrame ret; |
||||
std::unique_lock<std::mutex> lock(mutex); |
||||
cv.wait(lock, [this] () { |
||||
return !queue.empty(); |
||||
}); |
||||
ret = queue.front(); |
||||
queue.pop(); |
||||
return ret; |
||||
} |
||||
|
||||
void push_stop() { |
||||
push(cv::MediaFrame::Create<IStopAdapter>()); |
||||
} |
||||
|
||||
static bool is_stop(const cv::MediaFrame &f) { |
||||
try { |
||||
return f.get<IStopAdapter>(); |
||||
} catch(...) {} |
||||
return false; |
||||
} |
||||
|
||||
private: |
||||
struct IStopAdapter final : public cv::MediaFrame::IAdapter { |
||||
~IStopAdapter() {} |
||||
cv::GFrameDesc meta() const { return {}; }; |
||||
MediaFrame::View access(MediaFrame::Access) { return {{}, {}}; }; |
||||
}; |
||||
private: |
||||
std::condition_variable cv; |
||||
std::mutex mutex; |
||||
std::queue<cv::MediaFrame> queue; |
||||
}; |
||||
|
||||
struct EmptyDataProvider : public cv::gapi::wip::onevpl::IDataProvider { |
||||
|
||||
bool empty() const override { |
||||
return true; |
||||
} |
||||
mfx_codec_id_type get_mfx_codec_id() const override { |
||||
return std::numeric_limits<uint32_t>::max(); |
||||
} |
||||
bool fetch_bitstream_data(std::shared_ptr<mfx_bitstream> &) override { |
||||
return false; |
||||
} |
||||
}; |
||||
} |
||||
|
||||
using source_t = std::string; |
||||
using decoder_t = int; |
||||
using acceleration_t = int; |
||||
using out_frame_info_t = cv::GFrameDesc; |
||||
using preproc_args_t = std::tuple<source_t, decoder_t, acceleration_t, out_frame_info_t>; |
||||
|
||||
class VPPPreprocParams : public ::testing::TestWithParam<preproc_args_t> {}; |
||||
|
||||
preproc_args_t files[] = { |
||||
preproc_args_t {"highgui/video/big_buck_bunny.h264", |
||||
MFX_CODEC_AVC, MFX_ACCEL_MODE_VIA_D3D11, |
||||
cv::GFrameDesc {cv::MediaFormat::NV12, {1920, 1080}}}, |
||||
preproc_args_t {"highgui/video/big_buck_bunny.h265", |
||||
MFX_CODEC_HEVC, MFX_ACCEL_MODE_VIA_D3D11, |
||||
cv::GFrameDesc {cv::MediaFormat::NV12, {1920, 1280}}} |
||||
}; |
||||
|
||||
#ifdef HAVE_DIRECTX |
||||
#ifdef HAVE_D3D11 |
||||
TEST(OneVPL_Source_PreprocEngine, functional_single_thread) |
||||
{ |
||||
using namespace cv::gapi::wip::onevpl; |
||||
using namespace cv::gapi::wip; |
||||
|
||||
std::vector<CfgParam> cfg_params_w_dx11; |
||||
cfg_params_w_dx11.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11)); |
||||
std::unique_ptr<VPLAccelerationPolicy> decode_accel_policy ( |
||||
new VPLDX11AccelerationPolicy(std::make_shared<CfgParamDeviceSelector>(cfg_params_w_dx11))); |
||||
|
||||
// create file data provider
|
||||
std::string file_path = findDataFile("highgui/video/big_buck_bunny.h265"); |
||||
std::shared_ptr<IDataProvider> data_provider(new FileDataProvider(file_path, |
||||
{CfgParam::create_decoder_id(MFX_CODEC_HEVC)})); |
||||
|
||||
mfxLoader mfx{}; |
||||
mfxConfig mfx_cfg{}; |
||||
std::tie(mfx, mfx_cfg) = prepare_mfx(MFX_CODEC_HEVC, MFX_ACCEL_MODE_VIA_D3D11); |
||||
|
||||
// create decode session
|
||||
mfxSession mfx_decode_session{}; |
||||
mfxStatus sts = MFXCreateSession(mfx, 0, &mfx_decode_session); |
||||
EXPECT_EQ(MFX_ERR_NONE, sts); |
||||
|
||||
// create decode engine
|
||||
auto device_selector = decode_accel_policy->get_device_selector(); |
||||
VPLLegacyDecodeEngine decode_engine(std::move(decode_accel_policy)); |
||||
auto sess_ptr = decode_engine.initialize_session(mfx_decode_session, |
||||
cfg_params_w_dx11, |
||||
data_provider); |
||||
|
||||
// simulate net info
|
||||
cv::GFrameDesc required_frame_param {cv::MediaFormat::NV12, |
||||
{1920, 1080}}; |
||||
|
||||
// create VPP preproc engine
|
||||
VPPPreprocEngine preproc_engine(std::unique_ptr<VPLAccelerationPolicy>{ |
||||
new VPLDX11AccelerationPolicy(device_selector)}); |
||||
|
||||
// launch pipeline
|
||||
// 1) decode frame
|
||||
cv::MediaFrame first_decoded_frame; |
||||
ASSERT_NO_THROW(first_decoded_frame = extract_decoded_frame(sess_ptr->session, decode_engine)); |
||||
cv::GFrameDesc first_frame_decoded_desc = first_decoded_frame.desc(); |
||||
|
||||
// 1.5) create preproc session based on frame description & network info
|
||||
cv::util::optional<pp_params> first_pp_params = preproc_engine.is_applicable(first_decoded_frame); |
||||
ASSERT_TRUE(first_pp_params.has_value()); |
||||
pp_session first_pp_sess = preproc_engine.initialize_preproc(first_pp_params.value(), |
||||
required_frame_param); |
||||
|
||||
// 2) make preproc using incoming decoded frame & preproc session
|
||||
cv::MediaFrame first_pp_frame = preproc_engine.run_sync(first_pp_sess, first_decoded_frame); |
||||
cv::GFrameDesc first_outcome_pp_desc = first_pp_frame.desc(); |
||||
ASSERT_FALSE(first_frame_decoded_desc == first_outcome_pp_desc); |
||||
|
||||
// do not hold media frames because they share limited DX11 surface pool resources
|
||||
first_decoded_frame = cv::MediaFrame(); |
||||
first_pp_frame = cv::MediaFrame(); |
||||
|
||||
// make test in loop
|
||||
bool in_progress = false; |
||||
size_t frames_processed_count = 1; |
||||
const auto &first_pp_param_value_impl = |
||||
cv::util::get<cv::gapi::wip::onevpl::vpp_pp_params>(first_pp_params.value().value); |
||||
try { |
||||
while(true) { |
||||
cv::MediaFrame decoded_frame = extract_decoded_frame(sess_ptr->session, decode_engine); |
||||
in_progress = true; |
||||
ASSERT_EQ(decoded_frame.desc(), first_frame_decoded_desc); |
||||
|
||||
cv::util::optional<pp_params> params = preproc_engine.is_applicable(decoded_frame); |
||||
ASSERT_TRUE(params.has_value()); |
||||
const auto &cur_pp_param_value_impl = |
||||
cv::util::get<cv::gapi::wip::onevpl::vpp_pp_params>(params.value().value); |
||||
|
||||
ASSERT_EQ(first_pp_param_value_impl.handle, cur_pp_param_value_impl.handle); |
||||
ASSERT_TRUE(FrameInfoComparator::equal_to(first_pp_param_value_impl.info, cur_pp_param_value_impl.info)); |
||||
|
||||
pp_session pp_sess = preproc_engine.initialize_preproc(params.value(), |
||||
required_frame_param); |
||||
ASSERT_EQ(pp_sess.get<EngineSession>().get(), |
||||
first_pp_sess.get<EngineSession>().get()); |
||||
|
||||
cv::MediaFrame pp_frame = preproc_engine.run_sync(pp_sess, decoded_frame); |
||||
cv::GFrameDesc pp_desc = pp_frame.desc(); |
||||
ASSERT_TRUE(pp_desc == first_outcome_pp_desc); |
||||
in_progress = false; |
||||
frames_processed_count++; |
||||
} |
||||
} catch (...) {} |
||||
|
||||
// test if interruption has happened
|
||||
ASSERT_FALSE(in_progress); |
||||
ASSERT_NE(frames_processed_count, 1); |
||||
} |
||||
|
||||
|
||||
TEST_P(VPPPreprocParams, functional_different_threads) |
||||
{ |
||||
using namespace cv::gapi::wip; |
||||
using namespace cv::gapi::wip::onevpl; |
||||
source_t file_path; |
||||
decoder_t decoder_id; |
||||
acceleration_t accel; |
||||
out_frame_info_t required_frame_param; |
||||
std::tie(file_path, decoder_id, accel, required_frame_param) = GetParam(); |
||||
|
||||
file_path = findDataFile(file_path); |
||||
|
||||
std::vector<CfgParam> cfg_params_w_dx11; |
||||
cfg_params_w_dx11.push_back(CfgParam::create_acceleration_mode(accel)); |
||||
std::unique_ptr<VPLAccelerationPolicy> decode_accel_policy ( |
||||
new VPLDX11AccelerationPolicy(std::make_shared<CfgParamDeviceSelector>(cfg_params_w_dx11))); |
||||
|
||||
// create file data provider
|
||||
std::shared_ptr<IDataProvider> data_provider(new FileDataProvider(file_path, |
||||
{CfgParam::create_decoder_id(decoder_id)})); |
||||
|
||||
mfxLoader mfx{}; |
||||
mfxConfig mfx_cfg{}; |
||||
std::tie(mfx, mfx_cfg) = prepare_mfx(decoder_id, accel); |
||||
|
||||
// create decode session
|
||||
mfxSession mfx_decode_session{}; |
||||
mfxStatus sts = MFXCreateSession(mfx, 0, &mfx_decode_session); |
||||
EXPECT_EQ(MFX_ERR_NONE, sts); |
||||
|
||||
// create decode engine
|
||||
auto device_selector = decode_accel_policy->get_device_selector(); |
||||
VPLLegacyDecodeEngine decode_engine(std::move(decode_accel_policy)); |
||||
auto sess_ptr = decode_engine.initialize_session(mfx_decode_session, |
||||
cfg_params_w_dx11, |
||||
data_provider); |
||||
|
||||
// create VPP preproc engine
|
||||
VPPPreprocEngine preproc_engine(std::unique_ptr<VPLAccelerationPolicy>{ |
||||
new VPLDX11AccelerationPolicy(device_selector)}); |
||||
|
||||
// launch threads
|
||||
SafeQueue queue; |
||||
size_t decoded_number = 1; |
||||
size_t preproc_number = 0; |
||||
|
||||
std::thread decode_thread([&decode_engine, sess_ptr, |
||||
&queue, &decoded_number] () { |
||||
// decode first frame
|
||||
{ |
||||
cv::MediaFrame decoded_frame; |
||||
ASSERT_NO_THROW(decoded_frame = extract_decoded_frame(sess_ptr->session, decode_engine)); |
||||
queue.push(std::move(decoded_frame)); |
||||
} |
||||
|
||||
// launch pipeline
|
||||
try { |
||||
while(true) { |
||||
queue.push(extract_decoded_frame(sess_ptr->session, decode_engine)); |
||||
decoded_number++; |
||||
} |
||||
} catch (...) {} |
||||
|
||||
// send stop
|
||||
queue.push_stop(); |
||||
}); |
||||
|
||||
std::thread preproc_thread([&preproc_engine, &queue, &preproc_number, required_frame_param] () { |
||||
// create preproc session based on frame description & network info
|
||||
cv::MediaFrame first_decoded_frame = queue.pop(); |
||||
cv::util::optional<pp_params> first_pp_params = preproc_engine.is_applicable(first_decoded_frame); |
||||
ASSERT_TRUE(first_pp_params.has_value()); |
||||
pp_session first_pp_sess = |
||||
preproc_engine.initialize_preproc(first_pp_params.value(), required_frame_param); |
||||
|
||||
// make preproc using incoming decoded frame & preproc session
|
||||
cv::MediaFrame first_pp_frame = preproc_engine.run_sync(first_pp_sess, first_decoded_frame); |
||||
cv::GFrameDesc first_outcome_pp_desc = first_pp_frame.desc(); |
||||
|
||||
// do not hold media frames because they share limited DX11 surface pool resources
|
||||
first_decoded_frame = cv::MediaFrame(); |
||||
first_pp_frame = cv::MediaFrame(); |
||||
|
||||
// launch pipeline
|
||||
bool in_progress = false; |
||||
// let's allow counting of preprocessed frames to check this value later:
|
||||
// Currently, it looks redundant to implement any kind of gracefull shutdown logic
|
||||
// in this test - so let's apply agreement that media source is processed
|
||||
// succesfully when preproc_number != 1 in result
|
||||
preproc_number = 1; |
||||
try { |
||||
while(true) { |
||||
cv::MediaFrame decoded_frame = queue.pop(); |
||||
if (SafeQueue::is_stop(decoded_frame)) { |
||||
break; |
||||
} |
||||
in_progress = true; |
||||
|
||||
cv::util::optional<pp_params> params = preproc_engine.is_applicable(decoded_frame); |
||||
ASSERT_TRUE(params.has_value()); |
||||
ASSERT_TRUE(0 == memcmp(¶ms.value(), &first_pp_params.value(), sizeof(pp_params))); |
||||
|
||||
pp_session pp_sess = preproc_engine.initialize_preproc(params.value(), |
||||
required_frame_param); |
||||
ASSERT_EQ(pp_sess.get<EngineSession>().get(), |
||||
first_pp_sess.get<EngineSession>().get()); |
||||
|
||||
cv::MediaFrame pp_frame = preproc_engine.run_sync(pp_sess, decoded_frame); |
||||
cv::GFrameDesc pp_desc = pp_frame.desc(); |
||||
ASSERT_TRUE(pp_desc == first_outcome_pp_desc); |
||||
in_progress = false; |
||||
preproc_number++; |
||||
} |
||||
} catch (...) {} |
||||
|
||||
// test if interruption has happened
|
||||
ASSERT_FALSE(in_progress); |
||||
ASSERT_NE(preproc_number, 1); |
||||
}); |
||||
|
||||
decode_thread.join(); |
||||
preproc_thread.join(); |
||||
ASSERT_EQ(preproc_number, decoded_number); |
||||
} |
||||
|
||||
INSTANTIATE_TEST_CASE_P(OneVPL_Source_PreprocEngine, VPPPreprocParams, |
||||
testing::ValuesIn(files)); |
||||
|
||||
using VPPInnerPreprocParams = VPPPreprocParams; |
||||
TEST_P(VPPInnerPreprocParams, functional_inner_preproc_size) |
||||
{ |
||||
using namespace cv::gapi::wip; |
||||
using namespace cv::gapi::wip::onevpl; |
||||
source_t file_path; |
||||
decoder_t decoder_id; |
||||
acceleration_t accel; |
||||
out_frame_info_t required_frame_param; |
||||
std::tie(file_path, decoder_id, accel, required_frame_param) = GetParam(); |
||||
|
||||
file_path = findDataFile(file_path); |
||||
|
||||
std::vector<CfgParam> cfg_params_w_dx11_vpp; |
||||
|
||||
// create accel policy
|
||||
cfg_params_w_dx11_vpp.push_back(CfgParam::create_acceleration_mode(accel)); |
||||
std::unique_ptr<VPLAccelerationPolicy> accel_policy ( |
||||
new VPLDX11AccelerationPolicy(std::make_shared<CfgParamDeviceSelector>(cfg_params_w_dx11_vpp))); |
||||
|
||||
// create file data provider
|
||||
std::shared_ptr<IDataProvider> data_provider(new FileDataProvider(file_path, |
||||
{CfgParam::create_decoder_id(decoder_id)})); |
||||
|
||||
// create decode session
|
||||
mfxLoader mfx{}; |
||||
mfxConfig mfx_cfg{}; |
||||
std::tie(mfx, mfx_cfg) = prepare_mfx(decoder_id, accel); |
||||
|
||||
mfxSession mfx_decode_session{}; |
||||
mfxStatus sts = MFXCreateSession(mfx, 0, &mfx_decode_session); |
||||
EXPECT_EQ(MFX_ERR_NONE, sts); |
||||
|
||||
// fill vpp params beforehand: resolution
|
||||
cfg_params_w_dx11_vpp.push_back(CfgParam::create_vpp_out_width( |
||||
static_cast<uint16_t>(required_frame_param.size.width))); |
||||
cfg_params_w_dx11_vpp.push_back(CfgParam::create_vpp_out_height( |
||||
static_cast<uint16_t>(required_frame_param.size.height))); |
||||
|
||||
// create transcode engine
|
||||
auto device_selector = accel_policy->get_device_selector(); |
||||
VPLLegacyTranscodeEngine engine(std::move(accel_policy)); |
||||
auto sess_ptr = engine.initialize_session(mfx_decode_session, |
||||
cfg_params_w_dx11_vpp, |
||||
data_provider); |
||||
// make test in loop
|
||||
bool in_progress = false; |
||||
size_t frames_processed_count = 1; |
||||
try { |
||||
while(true) { |
||||
cv::MediaFrame decoded_frame = extract_decoded_frame(sess_ptr->session, engine); |
||||
in_progress = true; |
||||
ASSERT_EQ(decoded_frame.desc().size.width, |
||||
ALIGN16(required_frame_param.size.width)); |
||||
ASSERT_EQ(decoded_frame.desc().size.height, |
||||
ALIGN16(required_frame_param.size.height)); |
||||
ASSERT_EQ(decoded_frame.desc().fmt, required_frame_param.fmt); |
||||
frames_processed_count++; |
||||
in_progress = false; |
||||
} |
||||
} catch (...) {} |
||||
|
||||
// test if interruption has happened
|
||||
ASSERT_FALSE(in_progress); |
||||
ASSERT_NE(frames_processed_count, 1); |
||||
} |
||||
|
||||
INSTANTIATE_TEST_CASE_P(OneVPL_Source_PreprocInner, VPPInnerPreprocParams, |
||||
testing::ValuesIn(files)); |
||||
#endif // HAVE_DIRECTX
|
||||
#endif // HAVE_D3D11
|
||||
} // namespace opencv_test
|
||||
#endif // HAVE_ONEVPL
|
Loading…
Reference in new issue