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

Merge pull request #19755 from mikhail-nikolskiy:ffmpeg-umat

cv::UMat output/input in VideoCapture/VideoWriter (data stays in GPU memory)

* FFMPEG with UMat input/output

* OpenCL_D3D* context

* fix Linux build

* cosmetic changes

* fix build if USE_AV_HW_CODECS=0

* simplify how child context pointer stored in parent context

* QSV interop with OpenCL on Windows

* detect_msdk.cmake via pkg-config

* fix av_buffer_ref() usage

* revert windows-decode-mfx whitelisting; remove debug msg

* address review comments

* rename property to HW_ACCELERATION_USE_OPENCL

* fix issue with "cl_khr_d3d11_sharing" extension not reported by OpenCL GPU+CPU platform

* core(ocl): add OpenCL stubs for configurations without OpenCL

* videoio(ffmpeg): update #if guards

* Put OpenCL related code under HAVE_OPENCL; simplify reuse of media context from OpenCL context

* videoio(test): skip unsupported tests

- plugins don't support OpenCL/UMat yet
- change handling of *_USE_OPENCL flag

* videoio(ffmpeg): OpenCL dependency

* videoio(ffmpeg): MediaSDK/oneVPL dependency

* cleanup, logging

* cmake: fix handling of 3rdparty interface targets

Co-authored-by: Alexander Alekhin <alexander.a.alekhin@gmail.com>
This commit is contained in:
Mikhail Nikolskii
2021-05-14 19:48:50 +03:00
committed by GitHub
parent bb92eb5a93
commit a604d44d06
17 changed files with 1347 additions and 783 deletions
+23
View File
@@ -43,6 +43,8 @@
#define OPENCV_OPENCL_HPP
#include "opencv2/core.hpp"
#include <typeinfo>
#include <typeindex>
namespace cv { namespace ocl {
@@ -277,6 +279,12 @@ public:
/** @returns cl_context value */
void* ptr() const;
/**
* @brief Get OpenCL context property specified on context creation
* @param propertyId Property id (CL_CONTEXT_* as defined in cl_context_properties type)
* @returns Property value if property was specified on clCreateContext, or NULL if context created without the property
*/
void* getOpenCLContextProperty(int propertyId) const;
bool useSVM() const;
void setUseSVM(bool enabled);
@@ -290,6 +298,21 @@ public:
void release();
class CV_EXPORTS UserContext {
public:
virtual ~UserContext();
};
template <typename T>
inline void setUserContext(const std::shared_ptr<T>& userContext) {
setUserContext(typeid(T), userContext);
}
template <typename T>
inline std::shared_ptr<T> getUserContext() {
return std::dynamic_pointer_cast<T>(getUserContext(typeid(T)));
}
void setUserContext(std::type_index typeId, const std::shared_ptr<UserContext>& userContext);
std::shared_ptr<UserContext> getUserContext(std::type_index typeId);
struct Impl;
inline Impl* getImpl() const { return (Impl*)p; }
inline bool empty() const { return !p; }
File diff suppressed because it is too large Load Diff
-23
View File
@@ -1,23 +0,0 @@
// 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.
#ifndef OPENCV_CORE_SRC_DIRECTX_HPP
#define OPENCV_CORE_SRC_DIRECTX_HPP
#ifndef HAVE_DIRECTX
#error Invalid build configuration
#endif
namespace cv {
namespace directx {
namespace internal {
struct OpenCLDirectXImpl;
OpenCLDirectXImpl* createDirectXImpl();
void deleteDirectXImpl(OpenCLDirectXImpl**);
OpenCLDirectXImpl* getDirectXImpl(ocl::Context& ctx);
}}} // namespace internal
#endif // OPENCV_CORE_SRC_DIRECTX_HPP
+49 -32
View File
@@ -113,10 +113,6 @@
#include "opencv2/core/opencl/runtime/opencl_core.hpp"
#ifdef HAVE_DIRECTX
#include "directx.hpp"
#endif
#ifdef HAVE_OPENCL_SVM
#include "opencv2/core/opencl/runtime/opencl_svm_20.hpp"
#include "opencv2/core/opencl/runtime/opencl_svm_hsa_extension.hpp"
@@ -2367,9 +2363,6 @@ protected:
, contextId(CV_XADD(&g_contextId, 1))
, configuration(configuration_)
, handle(0)
#ifdef HAVE_DIRECTX
, p_directx_impl(0)
#endif
#ifdef HAVE_OPENCL_SVM
, svmInitialized(false)
#endif
@@ -2395,11 +2388,10 @@ protected:
handle = NULL;
}
devices.clear();
#ifdef HAVE_DIRECTX
directx::internal::deleteDirectXImpl(&p_directx_impl);
#endif
}
userContextStorage.clear();
{
cv::AutoLock lock(cv::getInitializationMutex());
auto& container = getGlobalContainer();
@@ -2705,18 +2697,20 @@ public:
return *bufferPoolHostPtr_.get();
}
#ifdef HAVE_DIRECTX
directx::internal::OpenCLDirectXImpl* p_directx_impl;
directx::internal::OpenCLDirectXImpl* getDirectXImpl()
{
if (!p_directx_impl)
{
p_directx_impl = directx::internal::createDirectXImpl();
}
return p_directx_impl;
std::map<std::type_index, std::shared_ptr<UserContext>> userContextStorage;
cv::Mutex userContextMutex;
void setUserContext(std::type_index typeId, const std::shared_ptr<UserContext>& userContext) {
cv::AutoLock lock(userContextMutex);
userContextStorage[typeId] = userContext;
}
std::shared_ptr<UserContext> getUserContext(std::type_index typeId) {
cv::AutoLock lock(userContextMutex);
auto it = userContextStorage.find(typeId);
if (it != userContextStorage.end())
return it->second;
else
return nullptr;
}
#endif
#ifdef HAVE_OPENCL_SVM
bool svmInitialized;
@@ -3036,6 +3030,25 @@ Context Context::create(const std::string& configuration)
return ctx;
}
void* Context::getOpenCLContextProperty(int propertyId) const
{
if (p == NULL)
return nullptr;
::size_t size = 0;
CV_OCL_CHECK(clGetContextInfo(p->handle, CL_CONTEXT_PROPERTIES, 0, NULL, &size));
std::vector<cl_context_properties> prop(size / sizeof(cl_context_properties), (cl_context_properties)0);
CV_OCL_CHECK(clGetContextInfo(p->handle, CL_CONTEXT_PROPERTIES, size, prop.data(), NULL));
for (size_t i = 0; i < prop.size(); i += 2)
{
if (prop[i] == (cl_context_properties)propertyId)
{
CV_LOG_DEBUG(NULL, "OpenCL: found context property=" << propertyId << ") => " << (void*)prop[i + 1]);
return (void*)prop[i + 1];
}
}
return nullptr;
}
#ifdef HAVE_OPENCL_SVM
bool Context::useSVM() const
{
@@ -3097,6 +3110,21 @@ CV_EXPORTS bool useSVM(UMatUsageFlags usageFlags)
} // namespace cv::ocl::svm
#endif // HAVE_OPENCL_SVM
Context::UserContext::~UserContext()
{
}
void Context::setUserContext(std::type_index typeId, const std::shared_ptr<Context::UserContext>& userContext)
{
CV_Assert(p);
p->setUserContext(typeId, userContext);
}
std::shared_ptr<Context::UserContext> Context::getUserContext(std::type_index typeId)
{
CV_Assert(p);
return p->getUserContext(typeId);
}
static void get_platform_name(cl_platform_id id, String& name)
{
@@ -7505,15 +7533,4 @@ uint64 Timer::durationNS() const
}} // namespace
#ifdef HAVE_DIRECTX
namespace cv { namespace directx { namespace internal {
OpenCLDirectXImpl* getDirectXImpl(ocl::Context& ctx)
{
ocl::Context::Impl* i = ctx.getImpl();
CV_Assert(i);
return i->getDirectXImpl();
}
}}} // namespace cv::directx::internal
#endif
#endif // HAVE_OPENCL
+7
View File
@@ -172,9 +172,16 @@ Context& Context::getDefault(bool initialize)
}
void* Context::ptr() const { return NULL; }
void* Context::getOpenCLContextProperty(int /*propertyId*/) const { OCL_NOT_AVAILABLE(); }
bool Context::useSVM() const { return false; }
void Context::setUseSVM(bool enabled) { }
Context::UserContext::~UserContext() { }
void Context::setUserContext(std::type_index /*typeId*/, const std::shared_ptr<Context::UserContext>& /*userContext*/) { OCL_NOT_AVAILABLE(); }
std::shared_ptr<Context::UserContext> Context::getUserContext(std::type_index /*typeId*/) { OCL_NOT_AVAILABLE(); }
/* static */ Context Context::fromHandle(void* context) { OCL_NOT_AVAILABLE(); }
/* static */ Context Context::fromDevice(const ocl::Device& device) { OCL_NOT_AVAILABLE(); }
/* static */ Context Context::create(const std::string& configuration) { OCL_NOT_AVAILABLE(); }
+56 -42
View File
@@ -7,6 +7,8 @@
#include "precomp.hpp"
#include <opencv2/core/utils/logger.hpp>
#ifdef HAVE_VA
# include <va/va.h>
#else // HAVE_VA
@@ -48,12 +50,28 @@ namespace cv { namespace va_intel {
#ifdef HAVE_VA_INTEL
static clGetDeviceIDsFromVA_APIMediaAdapterINTEL_fn clGetDeviceIDsFromVA_APIMediaAdapterINTEL = NULL;
static clCreateFromVA_APIMediaSurfaceINTEL_fn clCreateFromVA_APIMediaSurfaceINTEL = NULL;
static clEnqueueAcquireVA_APIMediaSurfacesINTEL_fn clEnqueueAcquireVA_APIMediaSurfacesINTEL = NULL;
static clEnqueueReleaseVA_APIMediaSurfacesINTEL_fn clEnqueueReleaseVA_APIMediaSurfacesINTEL = NULL;
static bool contextInitialized = false;
class VAAPIInterop : public ocl::Context::UserContext
{
public:
VAAPIInterop(cl_platform_id platform) {
clCreateFromVA_APIMediaSurfaceINTEL = (clCreateFromVA_APIMediaSurfaceINTEL_fn)
clGetExtensionFunctionAddressForPlatform(platform, "clCreateFromVA_APIMediaSurfaceINTEL");
clEnqueueAcquireVA_APIMediaSurfacesINTEL = (clEnqueueAcquireVA_APIMediaSurfacesINTEL_fn)
clGetExtensionFunctionAddressForPlatform(platform, "clEnqueueAcquireVA_APIMediaSurfacesINTEL");
clEnqueueReleaseVA_APIMediaSurfacesINTEL = (clEnqueueReleaseVA_APIMediaSurfacesINTEL_fn)
clGetExtensionFunctionAddressForPlatform(platform, "clEnqueueReleaseVA_APIMediaSurfacesINTEL");
if (!clCreateFromVA_APIMediaSurfaceINTEL ||
!clEnqueueAcquireVA_APIMediaSurfacesINTEL ||
!clEnqueueReleaseVA_APIMediaSurfacesINTEL) {
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't get extension function for VA-API interop");
}
}
virtual ~VAAPIInterop() {
}
clCreateFromVA_APIMediaSurfaceINTEL_fn clCreateFromVA_APIMediaSurfaceINTEL;
clEnqueueAcquireVA_APIMediaSurfacesINTEL_fn clEnqueueAcquireVA_APIMediaSurfacesINTEL;
clEnqueueReleaseVA_APIMediaSurfacesINTEL_fn clEnqueueReleaseVA_APIMediaSurfacesINTEL;
};
#endif // HAVE_VA_INTEL
@@ -65,10 +83,8 @@ Context& initializeContextFromVA(VADisplay display, bool tryInterop)
#if !defined(HAVE_VA)
NO_VA_SUPPORT_ERROR;
#else // !HAVE_VA
init_libva();
# ifdef HAVE_VA_INTEL
contextInitialized = false;
if (tryInterop)
{
cl_uint numPlatforms;
@@ -97,20 +113,10 @@ Context& initializeContextFromVA(VADisplay display, bool tryInterop)
for (int i = 0; i < (int)numPlatforms; ++i)
{
// Get extension function pointers
clGetDeviceIDsFromVA_APIMediaAdapterINTEL_fn clGetDeviceIDsFromVA_APIMediaAdapterINTEL;
clGetDeviceIDsFromVA_APIMediaAdapterINTEL = (clGetDeviceIDsFromVA_APIMediaAdapterINTEL_fn)
clGetExtensionFunctionAddressForPlatform(platforms[i], "clGetDeviceIDsFromVA_APIMediaAdapterINTEL");
clCreateFromVA_APIMediaSurfaceINTEL = (clCreateFromVA_APIMediaSurfaceINTEL_fn)
clGetExtensionFunctionAddressForPlatform(platforms[i], "clCreateFromVA_APIMediaSurfaceINTEL");
clEnqueueAcquireVA_APIMediaSurfacesINTEL = (clEnqueueAcquireVA_APIMediaSurfacesINTEL_fn)
clGetExtensionFunctionAddressForPlatform(platforms[i], "clEnqueueAcquireVA_APIMediaSurfacesINTEL");
clEnqueueReleaseVA_APIMediaSurfacesINTEL = (clEnqueueReleaseVA_APIMediaSurfacesINTEL_fn)
clGetExtensionFunctionAddressForPlatform(platforms[i], "clEnqueueReleaseVA_APIMediaSurfacesINTEL");
if (((void*)clGetDeviceIDsFromVA_APIMediaAdapterINTEL == NULL) ||
((void*)clCreateFromVA_APIMediaSurfaceINTEL == NULL) ||
((void*)clEnqueueAcquireVA_APIMediaSurfacesINTEL == NULL) ||
((void*)clEnqueueReleaseVA_APIMediaSurfacesINTEL == NULL))
if ((void*)clGetDeviceIDsFromVA_APIMediaAdapterINTEL == NULL)
{
continue;
}
@@ -151,8 +157,6 @@ Context& initializeContextFromVA(VADisplay display, bool tryInterop)
if (found >= 0)
{
contextInitialized = true;
cl_platform_id platform = platforms[found];
std::string platformName = PlatformInfo(&platform).name();
@@ -160,6 +164,7 @@ Context& initializeContextFromVA(VADisplay display, bool tryInterop)
try
{
clExecCtx = OpenCLExecutionContext::create(platformName, platform, context, device);
clExecCtx.getContext().setUserContext(std::make_shared<VAAPIInterop>(platform));
}
catch (...)
{
@@ -520,7 +525,6 @@ void convertToVASurface(VADisplay display, InputArray src, VASurfaceID surface,
#if !defined(HAVE_VA)
NO_VA_SUPPORT_ERROR;
#else // !HAVE_VA
init_libva();
const int stype = CV_8UC3;
@@ -531,7 +535,18 @@ void convertToVASurface(VADisplay display, InputArray src, VASurfaceID surface,
CV_Assert(srcSize.width == size.width && srcSize.height == size.height);
#ifdef HAVE_VA_INTEL
if (contextInitialized)
ocl::OpenCLExecutionContext& ocl_context = ocl::OpenCLExecutionContext::getCurrent();
VAAPIInterop* interop = ocl_context.getContext().getUserContext<VAAPIInterop>().get();
CV_LOG_IF_DEBUG(NULL, !interop,
"OpenCL/VA_INTEL: Can't interop with current OpenCL context - missing VAAPIInterop API. "
"OpenCL context should be created through initializeContextFromVA()");
void* context_display = ocl_context.getContext().getOpenCLContextProperty(CL_CONTEXT_VA_API_DISPLAY_INTEL);
CV_LOG_IF_INFO(NULL, interop && !context_display,
"OpenCL/VA_INTEL: Can't interop with current OpenCL context - missing VA display, context re-creation is required");
bool isValidContextDisplay = (display == context_display);
CV_LOG_IF_INFO(NULL, interop && context_display && !isValidContextDisplay,
"OpenCL/VA_INTEL: Can't interop with current OpenCL context - VA display mismatch: " << context_display << "(context) vs " << (void*)display << "(surface)");
if (isValidContextDisplay && interop)
{
UMat u = src.getUMat();
@@ -541,28 +556,26 @@ void convertToVASurface(VADisplay display, InputArray src, VASurfaceID surface,
cl_mem clBuffer = (cl_mem)u.handle(ACCESS_READ);
using namespace cv::ocl;
Context& ctx = Context::getDefault();
cl_context context = (cl_context)ctx.ptr();
cl_context context = (cl_context)ocl_context.getContext().ptr();
cl_int status = 0;
cl_mem clImageY = clCreateFromVA_APIMediaSurfaceINTEL(context, CL_MEM_WRITE_ONLY, &surface, 0, &status);
cl_mem clImageY = interop->clCreateFromVA_APIMediaSurfaceINTEL(context, CL_MEM_WRITE_ONLY, &surface, 0, &status);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clCreateFromVA_APIMediaSurfaceINTEL failed (Y plane)");
cl_mem clImageUV = clCreateFromVA_APIMediaSurfaceINTEL(context, CL_MEM_WRITE_ONLY, &surface, 1, &status);
cl_mem clImageUV = interop->clCreateFromVA_APIMediaSurfaceINTEL(context, CL_MEM_WRITE_ONLY, &surface, 1, &status);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clCreateFromVA_APIMediaSurfaceINTEL failed (UV plane)");
cl_command_queue q = (cl_command_queue)Queue::getDefault().ptr();
cl_command_queue q = (cl_command_queue)ocl_context.getQueue().ptr();
cl_mem images[2] = { clImageY, clImageUV };
status = clEnqueueAcquireVA_APIMediaSurfacesINTEL(q, 2, images, 0, NULL, NULL);
status = interop->clEnqueueAcquireVA_APIMediaSurfacesINTEL(q, 2, images, 0, NULL, NULL);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueAcquireVA_APIMediaSurfacesINTEL failed");
if (!ocl::ocl_convert_bgr_to_nv12(clBuffer, (int)u.step[0], u.cols, u.rows, clImageY, clImageUV))
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: ocl_convert_bgr_to_nv12 failed");
clEnqueueReleaseVA_APIMediaSurfacesINTEL(q, 2, images, 0, NULL, NULL);
interop->clEnqueueReleaseVA_APIMediaSurfacesINTEL(q, 2, images, 0, NULL, NULL);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueReleaseVA_APIMediaSurfacesINTEL failed");
@@ -580,6 +593,7 @@ void convertToVASurface(VADisplay display, InputArray src, VASurfaceID surface,
else
# endif // HAVE_VA_INTEL
{
init_libva();
Mat m = src.getMat();
// TODO Add support for roi
@@ -626,7 +640,6 @@ void convertFromVASurface(VADisplay display, VASurfaceID surface, Size size, Out
#if !defined(HAVE_VA)
NO_VA_SUPPORT_ERROR;
#else // !HAVE_VA
init_libva();
const int dtype = CV_8UC3;
@@ -634,7 +647,9 @@ void convertFromVASurface(VADisplay display, VASurfaceID surface, Size size, Out
dst.create(size, dtype);
#ifdef HAVE_VA_INTEL
if (contextInitialized)
ocl::OpenCLExecutionContext& ocl_context = ocl::OpenCLExecutionContext::getCurrent();
VAAPIInterop* interop = ocl_context.getContext().getUserContext<VAAPIInterop>().get();
if (display == ocl_context.getContext().getOpenCLContextProperty(CL_CONTEXT_VA_API_DISPLAY_INTEL) && interop)
{
UMat u = dst.getUMat();
@@ -644,28 +659,26 @@ void convertFromVASurface(VADisplay display, VASurfaceID surface, Size size, Out
cl_mem clBuffer = (cl_mem)u.handle(ACCESS_WRITE);
using namespace cv::ocl;
Context& ctx = Context::getDefault();
cl_context context = (cl_context)ctx.ptr();
cl_context context = (cl_context)ocl_context.getContext().ptr();
cl_int status = 0;
cl_mem clImageY = clCreateFromVA_APIMediaSurfaceINTEL(context, CL_MEM_READ_ONLY, &surface, 0, &status);
cl_mem clImageY = interop->clCreateFromVA_APIMediaSurfaceINTEL(context, CL_MEM_READ_ONLY, &surface, 0, &status);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clCreateFromVA_APIMediaSurfaceINTEL failed (Y plane)");
cl_mem clImageUV = clCreateFromVA_APIMediaSurfaceINTEL(context, CL_MEM_READ_ONLY, &surface, 1, &status);
cl_mem clImageUV = interop->clCreateFromVA_APIMediaSurfaceINTEL(context, CL_MEM_READ_ONLY, &surface, 1, &status);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clCreateFromVA_APIMediaSurfaceINTEL failed (UV plane)");
cl_command_queue q = (cl_command_queue)Queue::getDefault().ptr();
cl_command_queue q = (cl_command_queue)ocl_context.getQueue().ptr();
cl_mem images[2] = { clImageY, clImageUV };
status = clEnqueueAcquireVA_APIMediaSurfacesINTEL(q, 2, images, 0, NULL, NULL);
status = interop->clEnqueueAcquireVA_APIMediaSurfacesINTEL(q, 2, images, 0, NULL, NULL);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueAcquireVA_APIMediaSurfacesINTEL failed");
if (!ocl::ocl_convert_nv12_to_bgr(clImageY, clImageUV, clBuffer, (int)u.step[0], u.cols, u.rows))
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: ocl_convert_nv12_to_bgr failed");
status = clEnqueueReleaseVA_APIMediaSurfacesINTEL(q, 2, images, 0, NULL, NULL);
status = interop->clEnqueueReleaseVA_APIMediaSurfacesINTEL(q, 2, images, 0, NULL, NULL);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueReleaseVA_APIMediaSurfacesINTEL failed");
@@ -683,6 +696,7 @@ void convertFromVASurface(VADisplay display, VASurfaceID surface, Size size, Out
else
# endif // HAVE_VA_INTEL
{
init_libva();
Mat m = dst.getMat();
// TODO Add support for roi