Merge pull request #5272 from avershov:opencl-vaapi-fallback

pull/5322/merge
Vadim Pisarevsky 9 years ago
commit 9533982729
  1. 13
      CMakeLists.txt
  2. 20
      cmake/OpenCVFindLibsVideo.cmake
  3. 19
      cmake/OpenCVFindVA.cmake
  4. 44
      cmake/OpenCVFindVAAPI.cmake
  5. 44
      cmake/OpenCVFindVA_INTEL.cmake
  6. 7
      cmake/templates/cvconfig.h.in
  7. 2
      modules/core/CMakeLists.txt
  8. 43
      modules/core/include/opencv2/core/va_intel.hpp
  9. 2
      modules/core/src/precomp.hpp
  10. 528
      modules/core/src/va_intel.cpp
  11. 302
      modules/core/src/vaapi.cpp
  12. 4
      samples/CMakeLists.txt
  13. 14
      samples/va_intel/CMakeLists.txt
  14. 89
      samples/va_intel/display.cpp.inc
  15. 184
      samples/va_intel/va_intel_interop.cpp

@ -205,7 +205,8 @@ OCV_OPTION(WITH_OPENCLAMDBLAS "Include AMD OpenCL BLAS library support" ON
OCV_OPTION(WITH_DIRECTX "Include DirectX support" ON IF (WIN32 AND NOT WINRT) )
OCV_OPTION(WITH_INTELPERC "Include Intel Perceptual Computing support" OFF IF (WIN32 AND NOT WINRT) )
OCV_OPTION(WITH_IPP_A "Include Intel IPP_A support" OFF IF (MSVC OR X86 OR X86_64) )
OCV_OPTION(WITH_VAAPI "Include VA-API support" OFF IF (UNIX AND NOT ANDROID) )
OCV_OPTION(WITH_VA "Include VA support" OFF IF (UNIX AND NOT ANDROID) )
OCV_OPTION(WITH_VA_INTEL "Include Intel VA-API/OpenCL support" OFF IF (UNIX AND NOT ANDROID) )
OCV_OPTION(WITH_GDAL "Include GDAL Support" OFF IF (NOT ANDROID AND NOT IOS AND NOT WINRT) )
OCV_OPTION(WITH_GPHOTO2 "Include gPhoto2 library support" ON IF (UNIX AND NOT ANDROID) )
@ -1066,9 +1067,13 @@ if(DEFINED WITH_IPP_A)
status(" Use IPP Async:" HAVE_IPP_A THEN "YES" ELSE NO)
endif(DEFINED WITH_IPP_A)
if(DEFINED WITH_VAAPI)
status(" Use Intel VA-API:" HAVE_VAAPI THEN "YES (MSDK: ${VAAPI_MSDK_ROOT} OpenCL: ${VAAPI_IOCL_ROOT})" ELSE NO)
endif(DEFINED WITH_VAAPI)
if(DEFINED WITH_VA)
status(" Use VA:" HAVE_VA THEN "YES" ELSE NO)
endif(DEFINED WITH_VA)
if(DEFINED WITH_VA_INTEL)
status(" Use Intel VA-API/OpenCL:" HAVE_VA_INTEL THEN "YES (MSDK: ${VA_INTEL_MSDK_ROOT} OpenCL: ${VA_INTEL_IOCL_ROOT})" ELSE NO)
endif(DEFINED WITH_VA_INTEL)
status(" Use Eigen:" HAVE_EIGEN THEN "YES (ver ${EIGEN_WORLD_VERSION}.${EIGEN_MAJOR_VERSION}.${EIGEN_MINOR_VERSION})" ELSE NO)
status(" Use Cuda:" HAVE_CUDA THEN "YES (ver ${CUDA_VERSION_STRING})" ELSE NO)

@ -318,10 +318,18 @@ if(WITH_GPHOTO2)
CHECK_MODULE(libgphoto2 HAVE_GPHOTO2)
endif(WITH_GPHOTO2)
# --- VA-API ---
if(WITH_VAAPI)
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVFindVAAPI.cmake")
if(VAAPI_IOCL_INCLUDE_DIR)
ocv_include_directories(${VAAPI_IOCL_INCLUDE_DIR})
# --- VA & VA_INTEL ---
if(WITH_VA_INTEL)
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVFindVA_INTEL.cmake")
if(VA_INTEL_IOCL_INCLUDE_DIR)
ocv_include_directories(${VA_INTEL_IOCL_INCLUDE_DIR})
endif()
endif(WITH_VAAPI)
set(WITH_VA YES)
endif(WITH_VA_INTEL)
if(WITH_VA)
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVFindVA.cmake")
if(VA_INCLUDE_DIR)
ocv_include_directories(${VA_INCLUDE_DIR})
endif()
endif(WITH_VA)

@ -0,0 +1,19 @@
# Main variables:
# HAVE_VA for conditional compilation OpenCV with/without libva
if(UNIX AND NOT ANDROID)
find_path(
VA_INCLUDE_DIR
NAMES va/va.h
PATHS "/usr/include"
PATH_SUFFIXES include
DOC "Path to libva headers")
endif()
if(VA_INCLUDE_DIR)
set(HAVE_VA TRUE)
set(VA_LIBRARIES "-lva" "-lva-x11")
else()
set(HAVE_VA FALSE)
message(WARNING "libva installation is not found.")
endif()

@ -1,44 +0,0 @@
# Main variables:
# VAAPI_MSDK_INCLUDE_DIR and VAAPI_IOCL_INCLUDE_DIR to use VAAPI
# HAVE_VAAPI for conditional compilation OpenCV with/without VAAPI
# VAAPI_MSDK_ROOT - root of Intel MSDK installation
# VAAPI_IOCL_ROOT - root of Intel OCL installation
if(UNIX AND NOT ANDROID)
if($ENV{VAAPI_MSDK_ROOT})
set(VAAPI_MSDK_ROOT $ENV{VAAPI_MSDK_ROOT})
else()
set(VAAPI_MSDK_ROOT "/opt/intel/mediasdk")
endif()
if($ENV{VAAPI_IOCL_ROOT})
set(VAAPI_IOCL_ROOT $ENV{VAAPI_IOCL_ROOT})
else()
set(VAAPI_IOCL_ROOT "/opt/intel/opencl")
endif()
find_path(
VAAPI_MSDK_INCLUDE_DIR
NAMES mfxdefs.h
PATHS ${VAAPI_MSDK_ROOT}
PATH_SUFFIXES include
DOC "Path to Intel MSDK headers")
find_path(
VAAPI_IOCL_INCLUDE_DIR
NAMES CL/va_ext.h
PATHS ${VAAPI_IOCL_ROOT}
PATH_SUFFIXES include
DOC "Path to Intel OpenCL headers")
endif()
if(VAAPI_MSDK_INCLUDE_DIR AND VAAPI_IOCL_INCLUDE_DIR)
set(HAVE_VAAPI TRUE)
set(VAAPI_EXTRA_LIBS "-lva" "-lva-drm")
else()
set(HAVE_VAAPI FALSE)
message(WARNING "Intel MSDK & OpenCL installation is not found.")
endif()
mark_as_advanced(FORCE VAAPI_MSDK_INCLUDE_DIR VAAPI_IOCL_INCLUDE_DIR)

@ -0,0 +1,44 @@
# Main variables:
# VA_INTEL_MSDK_INCLUDE_DIR and VA_INTEL_IOCL_INCLUDE_DIR to use VA_INTEL
# HAVE_VA_INTEL for conditional compilation OpenCV with/without VA_INTEL
# VA_INTEL_MSDK_ROOT - root of Intel MSDK installation
# VA_INTEL_IOCL_ROOT - root of Intel OCL installation
if(UNIX AND NOT ANDROID)
if($ENV{VA_INTEL_MSDK_ROOT})
set(VA_INTEL_MSDK_ROOT $ENV{VA_INTEL_MSDK_ROOT})
else()
set(VA_INTEL_MSDK_ROOT "/opt/intel/mediasdk")
endif()
if($ENV{VA_INTEL_IOCL_ROOT})
set(VA_INTEL_IOCL_ROOT $ENV{VA_INTEL_IOCL_ROOT})
else()
set(VA_INTEL_IOCL_ROOT "/opt/intel/opencl")
endif()
find_path(
VA_INTEL_MSDK_INCLUDE_DIR
NAMES mfxdefs.h
PATHS ${VA_INTEL_MSDK_ROOT}
PATH_SUFFIXES include
DOC "Path to Intel MSDK headers")
find_path(
VA_INTEL_IOCL_INCLUDE_DIR
NAMES CL/va_ext.h
PATHS ${VA_INTEL_IOCL_ROOT}
PATH_SUFFIXES include
DOC "Path to Intel OpenCL headers")
endif()
if(VA_INTEL_MSDK_INCLUDE_DIR AND VA_INTEL_IOCL_INCLUDE_DIR)
set(HAVE_VA_INTEL TRUE)
set(VA_INTEL_LIBRARIES "-lva" "-lva-drm")
else()
set(HAVE_VA_INTEL FALSE)
message(WARNING "Intel MSDK & OpenCL installation is not found.")
endif()
mark_as_advanced(FORCE VA_INTEL_MSDK_INCLUDE_DIR VA_INTEL_IOCL_INCLUDE_DIR)

@ -189,5 +189,8 @@
/* gPhoto2 library */
#cmakedefine HAVE_GPHOTO2
/* Intel VA-API */
#cmakedefine HAVE_VAAPI
/* VA library (libva) */
#cmakedefine HAVE_VA
/* Intel VA-API/OpenCL */
#cmakedefine HAVE_VA_INTEL

@ -1,7 +1,7 @@
set(the_description "The Core Functionality")
ocv_add_module(core
opencv_hal
PRIVATE_REQUIRED ${ZLIB_LIBRARIES} "${OPENCL_LIBRARIES}"
PRIVATE_REQUIRED ${ZLIB_LIBRARIES} "${OPENCL_LIBRARIES}" "${VA_LIBRARIES}"
OPTIONAL opencv_cudev
WRAP java python)

@ -5,36 +5,36 @@
// Copyright (C) 2015, Itseez, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
#ifndef __OPENCV_CORE_VAAPI_HPP__
#define __OPENCV_CORE_VAAPI_HPP__
#ifndef __OPENCV_CORE_VA_INTEL_HPP__
#define __OPENCV_CORE_VA_INTEL_HPP__
#ifndef __cplusplus
# error vaapi.hpp header must be compiled as C++
# error va_intel.hpp header must be compiled as C++
#endif
#include "opencv2/core.hpp"
#include "ocl.hpp"
#if defined(HAVE_VAAPI)
#if defined(HAVE_VA)
# include "va/va.h"
#else // HAVE_VAAPI
#else // HAVE_VA
# if !defined(_VA_H_)
typedef void* VADisplay;
typedef unsigned int VASurfaceID;
# endif // !_VA_H_
#endif // HAVE_VAAPI
#endif // HAVE_VA
namespace cv { namespace vaapi {
namespace cv { namespace va_intel {
/** @addtogroup core_vaapi
This section describes CL-VA (VA-API) interoperability.
/** @addtogroup core_va_intel
This section describes Intel VA-API/OpenCL (CL-VA) interoperability.
To enable CL-VA interoperability support, configure OpenCV using CMake with WITH_VAAPI=ON . Currently VA-API is
To enable CL-VA interoperability support, configure OpenCV using CMake with WITH_VA_INTEL=ON . Currently VA-API is
supported on Linux only. You should also install Intel Media Server Studio (MSS) to use this feature. You may
have to specify the path(s) to MSS components for cmake in environment variables: VAAPI_MSDK_ROOT for Media SDK
(default is "/opt/intel/mediasdk"), and VAAPI_IOCL_ROOT for Intel OpenCL (default is "/opt/intel/opencl").
have to specify the path(s) to MSS components for cmake in environment variables: VA_INTEL_MSDK_ROOT for Media SDK
(default is "/opt/intel/mediasdk"), and VA_INTEL_IOCL_ROOT for Intel OpenCL (default is "/opt/intel/opencl").
To use VA-API interoperability you should first create VADisplay (libva), and then call initializeContextFromVA()
To use CL-VA interoperability you should first create VADisplay (libva), and then call initializeContextFromVA()
function to create OpenCL context and set up interoperability.
*/
//! @{
@ -46,29 +46,32 @@ using namespace cv::ocl;
// TODO static functions in the Context class
/** @brief Creates OpenCL context from VA.
@param display - VADisplay for which CL interop should be established.
@param display - VADisplay for which CL interop should be established.
@param tryInterop - try to set up for interoperability, if true; set up for use slow copy if false.
@return Returns reference to OpenCL Context
*/
CV_EXPORTS Context& initializeContextFromVA(VADisplay display);
CV_EXPORTS Context& initializeContextFromVA(VADisplay display, bool tryInterop = true);
} // namespace cv::vaapi::ocl
} // namespace cv::va_intel::ocl
/** @brief Converts InputArray to VASurfaceID object.
@param display - VADisplay object.
@param src - source InputArray.
@param surface - destination VASurfaceID object.
@param size - size of image represented by VASurfaceID object.
*/
CV_EXPORTS void convertToVASurface(InputArray src, VASurfaceID surface, Size size);
CV_EXPORTS void convertToVASurface(VADisplay display, InputArray src, VASurfaceID surface, Size size);
/** @brief Converts VASurfaceID object to OutputArray.
@param display - VADisplay object.
@param surface - source VASurfaceID object.
@param size - size of image represented by VASurfaceID object.
@param dst - destination OutputArray.
*/
CV_EXPORTS void convertFromVASurface(VASurfaceID surface, Size size, OutputArray dst);
CV_EXPORTS void convertFromVASurface(VADisplay display, VASurfaceID surface, Size size, OutputArray dst);
//! @}
}} // namespace cv::vaapi
}} // namespace cv::va_intel
#endif /* __OPENCV_CORE_VAAPI_HPP__ */
#endif /* __OPENCV_CORE_VA_INTEL_HPP__ */

@ -50,7 +50,7 @@
#include "opencv2/core/core_c.h"
#include "opencv2/core/cuda.hpp"
#include "opencv2/core/opengl.hpp"
#include "opencv2/core/vaapi.hpp"
#include "opencv2/core/va_intel.hpp"
#include "opencv2/core/private.hpp"
#include "opencv2/core/private.cuda.hpp"

@ -0,0 +1,528 @@
// 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) 2015, Itseez, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
#include "precomp.hpp"
#ifdef HAVE_VA
# include <va/va.h>
#else // HAVE_VA
# define NO_VA_SUPPORT_ERROR CV_ErrorNoReturn(cv::Error::StsBadFunc, "OpenCV was build without VA support (libva)")
#endif // HAVE_VA
using namespace cv;
////////////////////////////////////////////////////////////////////////
// CL-VA Interoperability
#ifdef HAVE_OPENCL
# include "opencv2/core/opencl/runtime/opencl_core.hpp"
# include "opencv2/core.hpp"
# include "opencv2/core/ocl.hpp"
# include "opencl_kernels_core.hpp"
#endif // HAVE_OPENCL
#if defined(HAVE_VA_INTEL) && defined(HAVE_OPENCL)
# include <CL/va_ext.h>
#endif // HAVE_VA_INTEL && HAVE_OPENCL
namespace cv { namespace va_intel {
#if defined(HAVE_VA_INTEL) && defined(HAVE_OPENCL)
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;
#endif // HAVE_VA_INTEL && HAVE_OPENCL
namespace ocl {
Context& initializeContextFromVA(VADisplay display, bool tryInterop)
{
(void)display; (void)tryInterop;
#if !defined(HAVE_VA)
NO_VA_SUPPORT_ERROR;
#else // !HAVE_VA
# if (defined(HAVE_VA_INTEL) && defined(HAVE_OPENCL))
contextInitialized = false;
if (tryInterop)
{
cl_uint numPlatforms;
cl_int status = clGetPlatformIDs(0, NULL, &numPlatforms);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't get number of platforms");
if (numPlatforms == 0)
CV_Error(cv::Error::OpenCLInitError, "OpenCL: No available platforms");
std::vector<cl_platform_id> platforms(numPlatforms);
status = clGetPlatformIDs(numPlatforms, &platforms[0], NULL);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't get platform Id list");
// For CL-VA interop, we must find platform/device with "cl_intel_va_api_media_sharing" extension.
// With standard initialization procedure, we should examine platform extension string for that.
// But in practice, the platform ext string doesn't contain it, while device ext string does.
// Follow Intel procedure (see tutorial), we should obtain device IDs by extension call.
// Note that we must obtain function pointers using specific platform ID, and can't provide pointers in advance.
// So, we iterate and select the first platform, for which we got non-NULL pointers, device, and CL context.
int found = -1;
cl_context context = 0;
cl_device_id device = 0;
for (int i = 0; i < (int)numPlatforms; ++i)
{
// Get extension function pointers
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))
{
continue;
}
// Query device list
cl_uint numDevices = 0;
status = clGetDeviceIDsFromVA_APIMediaAdapterINTEL(platforms[i], CL_VA_API_DISPLAY_INTEL, display,
CL_PREFERRED_DEVICES_FOR_VA_API_INTEL, 0, NULL, &numDevices);
if ((status != CL_SUCCESS) || !(numDevices > 0))
continue;
numDevices = 1; // initializeContextFromHandle() expects only 1 device
status = clGetDeviceIDsFromVA_APIMediaAdapterINTEL(platforms[i], CL_VA_API_DISPLAY_INTEL, display,
CL_PREFERRED_DEVICES_FOR_VA_API_INTEL, numDevices, &device, NULL);
if (status != CL_SUCCESS)
continue;
// Creating CL-VA media sharing OpenCL context
cl_context_properties props[] = {
CL_CONTEXT_VA_API_DISPLAY_INTEL, (cl_context_properties) display,
CL_CONTEXT_INTEROP_USER_SYNC, CL_FALSE, // no explicit sync required
0
};
context = clCreateContext(props, numDevices, &device, NULL, NULL, &status);
if (status != CL_SUCCESS)
{
clReleaseDevice(device);
}
else
{
found = i;
break;
}
}
if (found >= 0)
{
contextInitialized = true;
Context& ctx = Context::getDefault(false);
initializeContextFromHandle(ctx, platforms[found], context, device);
return ctx;
}
}
# endif // HAVE_VA_INTEL && HAVE_OPENCL
{
Context& ctx = Context::getDefault(true);
return ctx;
}
#endif // !HAVE_VA
}
#if defined(HAVE_VA_INTEL) && defined(HAVE_OPENCL)
static bool ocl_convert_nv12_to_bgr(cl_mem clImageY, cl_mem clImageUV, cl_mem clBuffer, int step, int cols, int rows)
{
ocl::Kernel k;
k.create("YUV2BGR_NV12_8u", cv::ocl::core::cvtclr_dx_oclsrc, "");
if (k.empty())
return false;
k.args(clImageY, clImageUV, clBuffer, step, cols, rows);
size_t globalsize[] = { cols, rows };
return k.run(2, globalsize, 0, false);
}
static bool ocl_convert_bgr_to_nv12(cl_mem clBuffer, int step, int cols, int rows, cl_mem clImageY, cl_mem clImageUV)
{
ocl::Kernel k;
k.create("BGR2YUV_NV12_8u", cv::ocl::core::cvtclr_dx_oclsrc, "");
if (k.empty())
return false;
k.args(clBuffer, step, cols, rows, clImageY, clImageUV);
size_t globalsize[] = { cols, rows };
return k.run(2, globalsize, 0, false);
}
#endif // HAVE_VA_INTEL && HAVE_OPENCL
} // namespace cv::va_intel::ocl
#if defined(HAVE_VA)
const int NCHANNELS = 3;
static void copy_convert_nv12_to_bgr(const VAImage& image, const unsigned char* buffer, Mat& bgr)
{
const float d1 = 16.0f;
const float d2 = 128.0f;
static const float coeffs[5] =
{
1.163999557f,
2.017999649f,
-0.390999794f,
-0.812999725f,
1.5959997177f
};
const size_t srcOffsetY = image.offsets[0];
const size_t srcOffsetUV = image.offsets[1];
const size_t srcStepY = image.pitches[0];
const size_t srcStepUV = image.pitches[1];
const size_t dstStep = bgr.step;
const unsigned char* srcY0 = buffer + srcOffsetY;
const unsigned char* srcUV = buffer + srcOffsetUV;
unsigned char* dst0 = bgr.data;
for (int y = 0; y < bgr.rows; y += 2)
{
const unsigned char* srcY1 = srcY0 + srcStepY;
unsigned char *dst1 = dst0 + dstStep;
for (int x = 0; x < bgr.cols; x += 2)
{
float Y0 = float(srcY0[x+0]);
float Y1 = float(srcY0[x+1]);
float Y2 = float(srcY1[x+0]);
float Y3 = float(srcY1[x+1]);
float U = float(srcUV[2*(x/2)+0]) - d2;
float V = float(srcUV[2*(x/2)+1]) - d2;
Y0 = std::max(0.0f, Y0 - d1) * coeffs[0];
Y1 = std::max(0.0f, Y1 - d1) * coeffs[0];
Y2 = std::max(0.0f, Y2 - d1) * coeffs[0];
Y3 = std::max(0.0f, Y3 - d1) * coeffs[0];
float ruv = coeffs[4]*V;
float guv = coeffs[3]*V + coeffs[2]*U;
float buv = coeffs[1]*U;
dst0[(x+0)*NCHANNELS+0] = saturate_cast<unsigned char>(Y0 + buv);
dst0[(x+0)*NCHANNELS+1] = saturate_cast<unsigned char>(Y0 + guv);
dst0[(x+0)*NCHANNELS+2] = saturate_cast<unsigned char>(Y0 + ruv);
dst0[(x+1)*NCHANNELS+0] = saturate_cast<unsigned char>(Y1 + buv);
dst0[(x+1)*NCHANNELS+1] = saturate_cast<unsigned char>(Y1 + guv);
dst0[(x+1)*NCHANNELS+2] = saturate_cast<unsigned char>(Y1 + ruv);
dst1[(x+0)*NCHANNELS+0] = saturate_cast<unsigned char>(Y2 + buv);
dst1[(x+0)*NCHANNELS+1] = saturate_cast<unsigned char>(Y2 + guv);
dst1[(x+0)*NCHANNELS+2] = saturate_cast<unsigned char>(Y2 + ruv);
dst1[(x+1)*NCHANNELS+0] = saturate_cast<unsigned char>(Y3 + buv);
dst1[(x+1)*NCHANNELS+1] = saturate_cast<unsigned char>(Y3 + guv);
dst1[(x+1)*NCHANNELS+2] = saturate_cast<unsigned char>(Y3 + ruv);
}
srcY0 = srcY1 + srcStepY;
srcUV += srcStepUV;
dst0 = dst1 + dstStep;
}
}
static void copy_convert_bgr_to_nv12(const VAImage& image, const Mat& bgr, unsigned char* buffer)
{
const float d1 = 16.0f;
const float d2 = 128.0f;
static const float coeffs[8] =
{
0.256999969f, 0.50399971f, 0.09799957f, -0.1479988098f,
-0.2909994125f, 0.438999176f, -0.3679990768f, -0.0709991455f
};
const size_t dstOffsetY = image.offsets[0];
const size_t dstOffsetUV = image.offsets[1];
const size_t dstStepY = image.pitches[0];
const size_t dstStepUV = image.pitches[1];
const size_t srcStep = bgr.step;
const unsigned char* src0 = bgr.data;
unsigned char* dstY0 = buffer + dstOffsetY;
unsigned char* dstUV = buffer + dstOffsetUV;
for (int y = 0; y < bgr.rows; y += 2)
{
const unsigned char *src1 = src0 + srcStep;
unsigned char* dstY1 = dstY0 + dstStepY;
for (int x = 0; x < bgr.cols; x += 2)
{
float B0 = float(src0[(x+0)*NCHANNELS+0]);
float G0 = float(src0[(x+0)*NCHANNELS+1]);
float R0 = float(src0[(x+0)*NCHANNELS+2]);
float B1 = float(src0[(x+1)*NCHANNELS+0]);
float G1 = float(src0[(x+1)*NCHANNELS+1]);
float R1 = float(src0[(x+1)*NCHANNELS+2]);
float B2 = float(src1[(x+0)*NCHANNELS+0]);
float G2 = float(src1[(x+0)*NCHANNELS+1]);
float R2 = float(src1[(x+0)*NCHANNELS+2]);
float B3 = float(src1[(x+1)*NCHANNELS+0]);
float G3 = float(src1[(x+1)*NCHANNELS+1]);
float R3 = float(src1[(x+1)*NCHANNELS+2]);
float Y0 = coeffs[0]*R0 + coeffs[1]*G0 + coeffs[2]*B0 + d1;
float Y1 = coeffs[0]*R1 + coeffs[1]*G1 + coeffs[2]*B1 + d1;
float Y2 = coeffs[0]*R2 + coeffs[1]*G2 + coeffs[2]*B2 + d1;
float Y3 = coeffs[0]*R3 + coeffs[1]*G3 + coeffs[2]*B3 + d1;
float U = coeffs[3]*R0 + coeffs[4]*G0 + coeffs[5]*B0 + d2;
float V = coeffs[5]*R0 + coeffs[6]*G0 + coeffs[7]*B0 + d2;
dstY0[x+0] = saturate_cast<unsigned char>(Y0);
dstY0[x+1] = saturate_cast<unsigned char>(Y1);
dstY1[x+0] = saturate_cast<unsigned char>(Y2);
dstY1[x+1] = saturate_cast<unsigned char>(Y3);
dstUV[2*(x/2)+0] = saturate_cast<unsigned char>(U);
dstUV[2*(x/2)+1] = saturate_cast<unsigned char>(V);
}
src0 = src1 + srcStep;
dstY0 = dstY1 + dstStepY;
dstUV += dstStepUV;
}
}
#endif // HAVE_VA
void convertToVASurface(VADisplay display, InputArray src, VASurfaceID surface, Size size)
{
(void)display; (void)src; (void)surface; (void)size;
#if !defined(HAVE_VA)
NO_VA_SUPPORT_ERROR;
#else // !HAVE_VA
const int stype = CV_8UC3;
int srcType = src.type();
CV_Assert(srcType == stype);
Size srcSize = src.size();
CV_Assert(srcSize.width == size.width && srcSize.height == size.height);
# if (defined(HAVE_VA_INTEL) && defined(HAVE_OPENCL))
if (contextInitialized)
{
UMat u = src.getUMat();
// TODO Add support for roi
CV_Assert(u.offset == 0);
CV_Assert(u.isContinuous());
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_int status = 0;
cl_mem clImageY = 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);
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_mem images[2] = { clImageY, clImageUV };
status = 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);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueReleaseVA_APIMediaSurfacesINTEL failed");
status = clFinish(q); // TODO Use events
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clFinish failed");
status = clReleaseMemObject(clImageY); // TODO RAII
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clReleaseMem failed (Y plane)");
status = clReleaseMemObject(clImageUV);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clReleaseMem failed (UV plane)");
}
else
# endif // HAVE_VA_INTEL && HAVE_OPENCL
{
Mat m = src.getMat();
// TODO Add support for roi
CV_Assert(m.data == m.datastart);
CV_Assert(m.isContinuous());
VAStatus status = 0;
status = vaSyncSurface(display, surface);
if (status != VA_STATUS_SUCCESS)
CV_Error(cv::Error::StsError, "VA-API: vaSyncSurface failed");
VAImage image;
status = vaDeriveImage(display, surface, &image);
if (status != VA_STATUS_SUCCESS)
CV_Error(cv::Error::StsError, "VA-API: vaDeriveImage failed");
unsigned char* buffer = 0;
status = vaMapBuffer(display, image.buf, (void **)&buffer);
if (status != VA_STATUS_SUCCESS)
CV_Error(cv::Error::StsError, "VA-API: vaMapBuffer failed");
CV_Assert(image.format.fourcc == VA_FOURCC_NV12);
copy_convert_bgr_to_nv12(image, m, buffer);
status = vaUnmapBuffer(display, image.buf);
if (status != VA_STATUS_SUCCESS)
CV_Error(cv::Error::StsError, "VA-API: vaUnmapBuffer failed");
status = vaDestroyImage(display, image.image_id);
if (status != VA_STATUS_SUCCESS)
CV_Error(cv::Error::StsError, "VA-API: vaDestroyImage failed");
}
#endif // !HAVE_VA
}
void convertFromVASurface(VADisplay display, VASurfaceID surface, Size size, OutputArray dst)
{
(void)display; (void)surface; (void)dst; (void)size;
#if !defined(HAVE_VA)
NO_VA_SUPPORT_ERROR;
#else // !HAVE_VA
const int dtype = CV_8UC3;
// TODO Need to specify ACCESS_WRITE here somehow to prevent useless data copying!
dst.create(size, dtype);
# if (defined(HAVE_VA_INTEL) && defined(HAVE_OPENCL))
if (contextInitialized)
{
UMat u = dst.getUMat();
// TODO Add support for roi
CV_Assert(u.offset == 0);
CV_Assert(u.isContinuous());
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_int status = 0;
cl_mem clImageY = 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);
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_mem images[2] = { clImageY, clImageUV };
status = 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);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueReleaseVA_APIMediaSurfacesINTEL failed");
status = clFinish(q); // TODO Use events
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clFinish failed");
status = clReleaseMemObject(clImageY); // TODO RAII
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clReleaseMem failed (Y plane)");
status = clReleaseMemObject(clImageUV);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clReleaseMem failed (UV plane)");
}
else
# endif // HAVE_VA_INTEL && HAVE_OPENCL
{
Mat m = dst.getMat();
// TODO Add support for roi
CV_Assert(m.data == m.datastart);
CV_Assert(m.isContinuous());
VAStatus status = 0;
status = vaSyncSurface(display, surface);
if (status != VA_STATUS_SUCCESS)
CV_Error(cv::Error::StsError, "VA-API: vaSyncSurface failed");
VAImage image;
status = vaDeriveImage(display, surface, &image);
if (status != VA_STATUS_SUCCESS)
CV_Error(cv::Error::StsError, "VA-API: vaDeriveImage failed");
unsigned char* buffer = 0;
status = vaMapBuffer(display, image.buf, (void **)&buffer);
if (status != VA_STATUS_SUCCESS)
CV_Error(cv::Error::StsError, "VA-API: vaMapBuffer failed");
CV_Assert(image.format.fourcc == VA_FOURCC_NV12);
copy_convert_nv12_to_bgr(image, buffer, m);
status = vaUnmapBuffer(display, image.buf);
if (status != VA_STATUS_SUCCESS)
CV_Error(cv::Error::StsError, "VA-API: vaUnmapBuffer failed");
status = vaDestroyImage(display, image.image_id);
if (status != VA_STATUS_SUCCESS)
CV_Error(cv::Error::StsError, "VA-API: vaDestroyImage failed");
}
#endif // !HAVE_VA
}
}} // namespace cv::va_intel

@ -1,302 +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.
// Copyright (C) 2015, Itseez, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
#include "precomp.hpp"
#ifdef HAVE_VAAPI
#else // HAVE_VAAPI
# define NO_VAAPI_SUPPORT_ERROR CV_ErrorNoReturn(cv::Error::StsBadFunc, "OpenCV was build without VA-API support")
#endif // HAVE_VAAPI
using namespace cv;
////////////////////////////////////////////////////////////////////////
// CL-VA Interoperability
#ifdef HAVE_OPENCL
# include "opencv2/core/opencl/runtime/opencl_core.hpp"
# include "opencv2/core.hpp"
# include "opencv2/core/ocl.hpp"
# include "opencl_kernels_core.hpp"
#else // HAVE_OPENCL
# define NO_OPENCL_SUPPORT_ERROR CV_ErrorNoReturn(cv::Error::StsBadFunc, "OpenCV was build without OpenCL support")
#endif // HAVE_OPENCL
#if defined(HAVE_VAAPI) && defined(HAVE_OPENCL)
# include <CL/va_ext.h>
#endif // HAVE_VAAPI && HAVE_OPENCL
namespace cv { namespace vaapi {
#if defined(HAVE_VAAPI) && defined(HAVE_OPENCL)
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;
#endif // HAVE_VAAPI && HAVE_OPENCL
namespace ocl {
Context& initializeContextFromVA(VADisplay display)
{
(void)display;
#if !defined(HAVE_VAAPI)
NO_VAAPI_SUPPORT_ERROR;
#elif !defined(HAVE_OPENCL)
NO_OPENCL_SUPPORT_ERROR;
#else
contextInitialized = false;
cl_uint numPlatforms;
cl_int status = clGetPlatformIDs(0, NULL, &numPlatforms);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't get number of platforms");
if (numPlatforms == 0)
CV_Error(cv::Error::OpenCLInitError, "OpenCL: No available platforms");
std::vector<cl_platform_id> platforms(numPlatforms);
status = clGetPlatformIDs(numPlatforms, &platforms[0], NULL);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't get platform Id list");
// For CL-VA interop, we must find platform/device with "cl_intel_va_api_media_sharing" extension.
// With standard initialization procedure, we should examine platform extension string for that.
// But in practice, the platform ext string doesn't contain it, while device ext string does.
// Follow Intel procedure (see tutorial), we should obtain device IDs by extension call.
// Note that we must obtain function pointers using specific platform ID, and can't provide pointers in advance.
// So, we iterate and select the first platform, for which we got non-NULL pointers, device, and CL context.
int found = -1;
cl_context context = 0;
cl_device_id device = 0;
for (int i = 0; i < (int)numPlatforms; ++i)
{
// Get extension function pointers
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))
{
continue;
}
// Query device list
cl_uint numDevices = 0;
status = clGetDeviceIDsFromVA_APIMediaAdapterINTEL(platforms[i], CL_VA_API_DISPLAY_INTEL, display,
CL_PREFERRED_DEVICES_FOR_VA_API_INTEL, 0, NULL, &numDevices);
if ((status != CL_SUCCESS) || !(numDevices > 0))
continue;
numDevices = 1; // initializeContextFromHandle() expects only 1 device
status = clGetDeviceIDsFromVA_APIMediaAdapterINTEL(platforms[i], CL_VA_API_DISPLAY_INTEL, display,
CL_PREFERRED_DEVICES_FOR_VA_API_INTEL, numDevices, &device, NULL);
if (status != CL_SUCCESS)
continue;
// Creating CL-VA media sharing OpenCL context
cl_context_properties props[] = {
CL_CONTEXT_VA_API_DISPLAY_INTEL, (cl_context_properties) display,
CL_CONTEXT_INTEROP_USER_SYNC, CL_FALSE, // no explicit sync required
0
};
context = clCreateContext(props, numDevices, &device, NULL, NULL, &status);
if (status != CL_SUCCESS)
{
clReleaseDevice(device);
}
else
{
found = i;
break;
}
}
if (found < 0)
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't create context for VA-API interop");
Context& ctx = Context::getDefault(false);
initializeContextFromHandle(ctx, platforms[found], context, device);
contextInitialized = true;
return ctx;
#endif
}
#if defined(HAVE_VAAPI) && defined(HAVE_OPENCL)
static bool ocl_convert_nv12_to_bgr(cl_mem clImageY, cl_mem clImageUV, cl_mem clBuffer, int step, int cols, int rows)
{
ocl::Kernel k;
k.create("YUV2BGR_NV12_8u", cv::ocl::core::cvtclr_dx_oclsrc, "");
if (k.empty())
return false;
k.args(clImageY, clImageUV, clBuffer, step, cols, rows);
size_t globalsize[] = { cols, rows };
return k.run(2, globalsize, 0, false);
}
static bool ocl_convert_bgr_to_nv12(cl_mem clBuffer, int step, int cols, int rows, cl_mem clImageY, cl_mem clImageUV)
{
ocl::Kernel k;
k.create("BGR2YUV_NV12_8u", cv::ocl::core::cvtclr_dx_oclsrc, "");
if (k.empty())
return false;
k.args(clBuffer, step, cols, rows, clImageY, clImageUV);
size_t globalsize[] = { cols, rows };
return k.run(2, globalsize, 0, false);
}
#endif // HAVE_VAAPI && HAVE_OPENCL
} // namespace cv::vaapi::ocl
void convertToVASurface(InputArray src, VASurfaceID surface, Size size)
{
(void)src; (void)surface; (void)size;
#if !defined(HAVE_VAAPI)
NO_VAAPI_SUPPORT_ERROR;
#elif !defined(HAVE_OPENCL)
NO_OPENCL_SUPPORT_ERROR;
#else
if (!contextInitialized)
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Context for VA-API interop hasn't been created");
const int stype = CV_8UC4;
int srcType = src.type();
CV_Assert(srcType == stype);
Size srcSize = src.size();
CV_Assert(srcSize.width == size.width && srcSize.height == size.height);
UMat u = src.getUMat();
// TODO Add support for roi
CV_Assert(u.offset == 0);
CV_Assert(u.isContinuous());
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_int status = 0;
cl_mem clImageY = 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);
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_mem images[2] = { clImageY, clImageUV };
status = 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);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueReleaseVA_APIMediaSurfacesINTEL failed");
status = clFinish(q); // TODO Use events
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clFinish failed");
status = clReleaseMemObject(clImageY); // TODO RAII
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clReleaseMem failed (Y plane)");
status = clReleaseMemObject(clImageUV);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clReleaseMem failed (UV plane)");
#endif
}
void convertFromVASurface(VASurfaceID surface, Size size, OutputArray dst)
{
(void)surface; (void)dst; (void)size;
#if !defined(HAVE_VAAPI)
NO_VAAPI_SUPPORT_ERROR;
#elif !defined(HAVE_OPENCL)
NO_OPENCL_SUPPORT_ERROR;
#else
if (!contextInitialized)
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Context for VA-API interop hasn't been created");
const int dtype = CV_8UC4;
// TODO Need to specify ACCESS_WRITE here somehow to prevent useless data copying!
dst.create(size, dtype);
UMat u = dst.getUMat();
// TODO Add support for roi
CV_Assert(u.offset == 0);
CV_Assert(u.isContinuous());
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_int status = 0;
cl_mem clImageY = 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);
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_mem images[2] = { clImageY, clImageUV };
status = 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);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueReleaseVA_APIMediaSurfacesINTEL failed");
status = clFinish(q); // TODO Use events
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clFinish failed");
status = clReleaseMemObject(clImageY); // TODO RAII
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clReleaseMem failed (Y plane)");
status = clReleaseMemObject(clImageUV);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clReleaseMem failed (UV plane)");
#endif
}
}} // namespace cv::vaapi

@ -22,8 +22,8 @@ if((NOT ANDROID) AND HAVE_OPENGL)
add_subdirectory(opengl)
endif()
if(UNIX AND NOT ANDROID AND HAVE_VAAPI)
add_subdirectory(vaapi)
if(UNIX AND NOT ANDROID AND (HAVE_VA OR HAVE_VA_INTEL))
add_subdirectory(va_intel)
endif()
if(ANDROID AND BUILD_ANDROID_EXAMPLES)

@ -1,23 +1,23 @@
SET(OPENCV_VAAPI_SAMPLES_REQUIRED_DEPS opencv_core opencv_imgproc opencv_imgcodecs opencv_videoio opencv_highgui)
SET(OPENCV_VA_INTEL_SAMPLES_REQUIRED_DEPS opencv_core opencv_imgproc opencv_imgcodecs opencv_videoio opencv_highgui)
ocv_check_dependencies(${OPENCV_VAAPI_SAMPLES_REQUIRED_DEPS})
ocv_check_dependencies(${OPENCV_VA_INTEL_SAMPLES_REQUIRED_DEPS})
if(BUILD_EXAMPLES AND OCV_DEPENDENCIES_FOUND)
set(project "vaapi")
set(project "va_intel")
string(TOUPPER "${project}" project_upper)
project("${project}_samples")
ocv_include_modules_recurse(${OPENCV_VAAPI_SAMPLES_REQUIRED_DEPS})
ocv_include_modules_recurse(${OPENCV_VA_INTEL_SAMPLES_REQUIRED_DEPS})
# ---------------------------------------------
# Define executable targets
# ---------------------------------------------
MACRO(OPENCV_DEFINE_VAAPI_EXAMPLE name srcs)
MACRO(OPENCV_DEFINE_VA_INTEL_EXAMPLE name srcs)
set(the_target "example_${project}_${name}")
add_executable(${the_target} ${srcs})
ocv_target_link_libraries(${the_target} ${OPENCV_LINKER_LIBS} ${OPENCV_VAAPI_SAMPLES_REQUIRED_DEPS} ${VAAPI_EXTRA_LIBS})
ocv_target_link_libraries(${the_target} ${OPENCV_LINKER_LIBS} ${OPENCV_VA_INTEL_SAMPLES_REQUIRED_DEPS} ${VA_LIBRARIES} ${VA_INTEL_LIBRARIES})
set_target_properties(${the_target} PROPERTIES
OUTPUT_NAME "${project}-example-${name}"
@ -33,6 +33,6 @@ if(BUILD_EXAMPLES AND OCV_DEPENDENCIES_FOUND)
foreach(sample_filename ${all_samples})
get_filename_component(sample ${sample_filename} NAME_WE)
file(GLOB sample_srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${sample}.*)
OPENCV_DEFINE_VAAPI_EXAMPLE(${sample} ${sample_srcs})
OPENCV_DEFINE_VA_INTEL_EXAMPLE(${sample} ${sample_srcs})
endforeach()
endif()

@ -7,25 +7,39 @@
#include <sys/types.h>
#include <unistd.h>
#include <va/va.h>
#include <va/va_drm.h>
#include "cvconfig.h"
#define VAAPI_PCI_DIR "/sys/bus/pci/devices"
#define VAAPI_DRI_DIR "/dev/dri/"
#define VAAPI_PCI_DISPLAY_CONTROLLER_CLASS 0x03
#include <va/va.h>
#if defined(HAVE_VA_INTEL)
# include <va/va_drm.h>
#elif defined(HAVE_VA)
# include <va/va_x11.h>
# include <X11/Xlib.h>
#endif //HAVE_VA_INTEL / HAVE_VA
namespace va {
static unsigned readId(const char* devName, const char* idName);
static int findAdapter(unsigned desiredVendorId);
#if defined(HAVE_VA_INTEL) || defined(HAVE_VA)
bool openDisplay();
void closeDisplay();
int drmfd = -1;
VADisplay display = NULL;
bool initialized = false;
#endif //HAVE_VA_INTEL || HAVE_VA
#if defined(HAVE_VA_INTEL)
#define VA_INTEL_PCI_DIR "/sys/bus/pci/devices"
#define VA_INTEL_DRI_DIR "/dev/dri/"
#define VA_INTEL_PCI_DISPLAY_CONTROLLER_CLASS 0x03
static unsigned readId(const char* devName, const char* idName);
static int findAdapter(unsigned desiredVendorId);
int drmfd = -1;
class Directory
{
typedef int (*fsort)(const struct dirent**, const struct dirent**);
@ -70,7 +84,7 @@ static unsigned readId(const char* devName, const char* idName)
long int id = 0;
char fileName[256];
snprintf(fileName, sizeof(fileName), "%s/%s/%s", VAAPI_PCI_DIR, devName, idName);
snprintf(fileName, sizeof(fileName), "%s/%s/%s", VA_INTEL_PCI_DIR, devName, idName);
FILE* file = fopen(fileName, "r");
if (file)
@ -88,14 +102,14 @@ static int findAdapter(unsigned desiredVendorId)
int adapterIndex = -1;
int numAdapters = 0;
Directory dir(VAAPI_PCI_DIR);
Directory dir(VA_INTEL_PCI_DIR);
for (int i = 0; i < dir.count(); ++i)
{
const char* name = dir[i]->d_name;
unsigned classId = readId(name, "class");
if ((classId >> 16) == VAAPI_PCI_DISPLAY_CONTROLLER_CLASS)
if ((classId >> 16) == VA_INTEL_PCI_DISPLAY_CONTROLLER_CLASS)
{
unsigned vendorId = readId(name, "vendor");
if (vendorId == desiredVendorId)
@ -122,9 +136,9 @@ public:
numbers[1] = adapterIndex;
for (int i = 0; i < NUM_NODES; ++i)
{
int sz = sizeof(VAAPI_DRI_DIR) + strlen(names[i]) + 3;
int sz = sizeof(VA_INTEL_DRI_DIR) + strlen(names[i]) + 3;
paths[i] = new char [sz];
snprintf(paths[i], sz, "%s%s%d", VAAPI_DRI_DIR, names[i], numbers[i]);
snprintf(paths[i], sz, "%s%s%d", VA_INTEL_DRI_DIR, names[i], numbers[i]);
}
}
~NodeInfo()
@ -205,4 +219,53 @@ void closeDisplay()
}
}
#elif defined(HAVE_VA)
static Display* x11Display = 0;
bool openDisplay()
{
if (!initialized)
{
display = 0;
x11Display = XOpenDisplay("");
if (x11Display != 0)
{
display = vaGetDisplay(x11Display);
if (display)
{
int majorVersion = 0, minorVersion = 0;
if (vaInitialize(display, &majorVersion, &minorVersion) == VA_STATUS_SUCCESS)
{
initialized = true;
return true;
}
display = 0;
}
XCloseDisplay(x11Display);
x11Display = 0;
}
return false; // Can't initialize X11/VA display
}
return true;
}
void closeDisplay()
{
if (initialized)
{
if (display)
vaTerminate(display);
if (x11Display)
XCloseDisplay(x11Display);
display = 0;
x11Display = 0;
initialized = false;
}
}
#endif // HAVE_VA_INTEL / HAVE_VA
} // namespace va

@ -24,6 +24,8 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <string>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@ -39,11 +41,12 @@
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/core/vaapi.hpp"
#include "opencv2/core/va_intel.hpp"
#include "cvconfig.h"
#define CHECK_VASTATUS(va_status,func) \
if (va_status != VA_STATUS_SUCCESS) { \
fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \
fprintf(stderr,"%s:%s (%d) failed(status=0x%08x),exit\n", __func__, func, __LINE__, va_status); \
exit(1); \
}
@ -129,7 +132,55 @@ static VASliceParameterBufferMPEG2 slice_param={
#define CLIP_WIDTH 16
#define CLIP_HEIGHT 16
static void dumpSurface(VADisplay display, VASurfaceID surface_id, const char* fileName)
class Timer
{
public:
enum UNITS
{
USEC = 0,
MSEC,
SEC
};
Timer() : m_t0(0), m_diff(0)
{
m_tick_frequency = (float)cv::getTickFrequency();
m_unit_mul[USEC] = 1000000;
m_unit_mul[MSEC] = 1000;
m_unit_mul[SEC] = 1;
}
void clear()
{
m_t0 = m_diff = 0;
}
void start()
{
m_t0 = cv::getTickCount();
}
void stop()
{
m_diff = cv::getTickCount() - m_t0;
}
float time(UNITS u = MSEC)
{
float sec = m_diff / m_tick_frequency;
return sec * m_unit_mul[u];
}
public:
float m_tick_frequency;
int64 m_t0;
int64 m_diff;
int m_unit_mul[3];
};
static void dumpSurface(VADisplay display, VASurfaceID surface_id, const char* fileName, bool doInterop)
{
VAStatus va_status;
@ -153,7 +204,8 @@ static void dumpSurface(VADisplay display, VASurfaceID surface_id, const char* f
printf("image.pitches[0..2] = 0x%08x 0x%08x 0x%08x\n", image.pitches[0], image.pitches[1], image.pitches[2]);
printf("image.offsets[0..2] = 0x%08x 0x%08x 0x%08x\n", image.offsets[0], image.offsets[1], image.offsets[2]);
*/
FILE* out = fopen(fileName, "wb");
std::string fn = std::string(fileName) + std::string(doInterop ? ".on" : ".off");
FILE* out = fopen(fn.c_str(), "wb");
if (!out)
{
perror(fileName);
@ -169,10 +221,8 @@ static void dumpSurface(VADisplay display, VASurfaceID surface_id, const char* f
CHECK_VASTATUS(va_status, "vaDestroyImage");
}
int main(int argc,char **argv)
static float run(const char* fn1, const char* fn2, bool doInterop)
{
(void)argc; (void)argv;
VAEntrypoint entrypoints[5];
int num_entrypoints,vld_entrypoint;
VAConfigAttrib attrib;
@ -181,24 +231,9 @@ int main(int argc,char **argv)
VAContextID context_id;
VABufferID pic_param_buf,iqmatrix_buf,slice_param_buf,slice_data_buf;
VAStatus va_status;
Timer t;
if (argc < 3)
{
fprintf(stderr,
"Usage: vaapi_interop file1 file2\n\n"
"where: file1 is to be created, contains original surface data (NV12)\n"
" file2 is to be created, contains processed surface data (NV12)\n");
exit(0);
}
if (!va::openDisplay())
{
fprintf(stderr, "Failed to open VA display for CL-VA interoperability\n");
exit(1);
}
fprintf(stderr, "VA display opened successfully\n");
cv::vaapi::ocl::initializeContextFromVA(va::display);
cv::va_intel::ocl::initializeContextFromVA(va::display, doInterop);
va_status = vaQueryConfigEntrypoints(va::display, VAProfileMPEG2Main, entrypoints,
&num_entrypoints);
@ -294,22 +329,113 @@ int main(int argc,char **argv)
va_status = vaSyncSurface(va::display, surface_id);
CHECK_VASTATUS(va_status, "vaSyncSurface");
dumpSurface(va::display, surface_id, argv[1]);
dumpSurface(va::display, surface_id, fn1, doInterop);
cv::Size size(CLIP_WIDTH,CLIP_HEIGHT);
cv::UMat u;
cv::vaapi::convertFromVASurface(surface_id, size, u);
cv::va_intel::convertFromVASurface(va::display, surface_id, size, u);
cv::blur(u, u, cv::Size(7, 7), cv::Point(-3, -3));
cv::va_intel::convertToVASurface(va::display, u, surface_id, size);
t.start();
cv::va_intel::convertFromVASurface(va::display, surface_id, size, u);
cv::blur(u, u, cv::Size(7, 7), cv::Point(-3, -3));
cv::vaapi::convertToVASurface(u, surface_id, size);
cv::va_intel::convertToVASurface(va::display, u, surface_id, size);
t.stop();
dumpSurface(va::display, surface_id, argv[2]);
dumpSurface(va::display, surface_id, fn2, doInterop);
vaDestroySurfaces(va::display,&surface_id,1);
vaDestroyConfig(va::display,config_id);
vaDestroyContext(va::display,context_id);
vaTerminate(va::display);
return t.time(Timer::MSEC);
}
class CmdlineParser
{
public:
CmdlineParser(int argc, char** argv):
m_argc(argc), m_argv(argv)
{}
// true => go, false => usage/exit; extra args/unknown options are ignored for simplicity
bool run()
{
int n = 0;
m_files[0] = m_files[1] = 0;
#if defined(HAVE_VA_INTEL)
m_interop = true;
#elif defined(HAVE_VA)
m_interop = false;
#endif //HAVE_VA_INTEL / HAVE_VA
for (int i = 1; i < m_argc; ++i)
{
const char *arg = m_argv[i];
if (arg[0] == '-') // option
{
#if defined(HAVE_VA_INTEL)
if (!strcmp(arg, "-f"))
m_interop = false;
#endif //HAVE_VA_INTEL
}
else // parameter
{
if (n < 2)
m_files[n++] = arg;
}
}
return bool(n >= 2);
}
bool isInterop() const
{
return m_interop;
}
const char* getFile(int n) const
{
return ((n >= 0) && (n < 2)) ? m_files[n] : 0;
}
private:
int m_argc;
char** m_argv;
const char* m_files[2];
bool m_interop;
};
int main(int argc, char** argv)
{
CmdlineParser cmd(argc, argv);
if (!cmd.run())
{
fprintf(stderr,
#if defined(HAVE_VA_INTEL)
"Usage: va_intel_interop [-f] file1 file2\n\n"
"Interop ON/OFF version\n\n"
"where: -f option indicates interop is off (fallback mode); interop is on by default\n"
#elif defined(HAVE_VA)
"Usage: va_intel_interop file1 file2\n\n"
"Interop OFF only version\n\n"
"where:\n"
#endif //HAVE_VA_INTEL / HAVE_VA
" file1 is to be created, contains original surface data (NV12)\n"
" file2 is to be created, contains processed surface data (NV12)\n");
exit(0);
}
if (!va::openDisplay())
{
fprintf(stderr, "Failed to open VA display for CL-VA interoperability\n");
exit(1);
}
fprintf(stderr, "VA display opened successfully\n");
const char* file0 = cmd.getFile(0);
const char* file1 = cmd.getFile(1);
bool doInterop = cmd.isInterop();
float time = run(file0, file1, doInterop);
fprintf(stderr, "Interop %s: processing time, msec: %7.3f\n", (doInterop ? "ON " : "OFF"), time);
va::closeDisplay();
return 0;
}
Loading…
Cancel
Save