implemented core support & sample

fixed whitespaces
fixed issues
fixed issue
fixed module statement issues
fixed access mode
added initialization check
fixed warning
This commit is contained in:
Alexey Ershov 2015-08-12 11:59:05 +03:00
parent 09b9b0fb9e
commit a8656ea20f
11 changed files with 1002 additions and 0 deletions

View File

@ -205,6 +205,7 @@ 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_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) )
@ -1065,6 +1066,10 @@ 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)
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)
status(" Use OpenCL:" HAVE_OPENCL THEN YES ELSE NO)

View File

@ -317,3 +317,11 @@ ocv_clear_vars(HAVE_GPHOTO2)
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})
endif()
endif(WITH_VAAPI)

View File

@ -0,0 +1,44 @@
# 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)

View File

@ -188,3 +188,6 @@
/* gPhoto2 library */
#cmakedefine HAVE_GPHOTO2
/* Intel VA-API */
#cmakedefine HAVE_VAAPI

View File

@ -0,0 +1,74 @@
// 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.
#ifndef __OPENCV_CORE_VAAPI_HPP__
#define __OPENCV_CORE_VAAPI_HPP__
#ifndef __cplusplus
# error vaapi.hpp header must be compiled as C++
#endif
#include "opencv2/core.hpp"
#include "ocl.hpp"
#if defined(HAVE_VAAPI)
# include "va/va.h"
#else // HAVE_VAAPI
# if !defined(_VA_H_)
typedef void* VADisplay;
typedef unsigned int VASurfaceID;
# endif // !_VA_H_
#endif // HAVE_VAAPI
namespace cv { namespace vaapi {
/** @addtogroup core_vaapi
This section describes CL-VA (VA-API) interoperability.
To enable CL-VA interoperability support, configure OpenCV using CMake with WITH_VAAPI=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").
To use VA-API interoperability you should first create VADisplay (libva), and then call initializeContextFromVA()
function to create OpenCL context and set up interoperability.
*/
//! @{
/////////////////// CL-VA Interoperability Functions ///////////////////
namespace ocl {
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.
@return Returns reference to OpenCL Context
*/
CV_EXPORTS Context& initializeContextFromVA(VADisplay display);
} // namespace cv::vaapi::ocl
/** @brief Converts InputArray to VASurfaceID 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);
/** @brief Converts VASurfaceID object to OutputArray.
@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);
//! @}
}} // namespace cv::vaapi
#endif /* __OPENCV_CORE_VAAPI_HPP__ */

View File

@ -50,6 +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/private.hpp"
#include "opencv2/core/private.cuda.hpp"

302
modules/core/src/vaapi.cpp Normal file
View File

@ -0,0 +1,302 @@
// 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

View File

@ -22,6 +22,10 @@ if((NOT ANDROID) AND HAVE_OPENGL)
add_subdirectory(opengl)
endif()
if(UNIX AND NOT ANDROID AND HAVE_VAAPI)
add_subdirectory(vaapi)
endif()
if(ANDROID AND BUILD_ANDROID_EXAMPLES)
add_subdirectory(android)
endif()

View File

@ -0,0 +1,38 @@
SET(OPENCV_VAAPI_SAMPLES_REQUIRED_DEPS opencv_core opencv_imgproc opencv_imgcodecs opencv_videoio opencv_highgui)
ocv_check_dependencies(${OPENCV_VAAPI_SAMPLES_REQUIRED_DEPS})
if(BUILD_EXAMPLES AND OCV_DEPENDENCIES_FOUND)
set(project "vaapi")
string(TOUPPER "${project}" project_upper)
project("${project}_samples")
ocv_include_modules_recurse(${OPENCV_VAAPI_SAMPLES_REQUIRED_DEPS})
# ---------------------------------------------
# Define executable targets
# ---------------------------------------------
MACRO(OPENCV_DEFINE_VAAPI_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})
set_target_properties(${the_target} PROPERTIES
OUTPUT_NAME "${project}-example-${name}"
PROJECT_LABEL "(EXAMPLE_${project_upper}) ${name}")
if(ENABLE_SOLUTION_FOLDERS)
set_target_properties(${the_target} PROPERTIES FOLDER "samples//${project}")
endif()
ENDMACRO()
file(GLOB all_samples RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp)
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})
endforeach()
endif()

View File

@ -0,0 +1,208 @@
#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <va/va.h>
#include <va/va_drm.h>
#define VAAPI_PCI_DIR "/sys/bus/pci/devices"
#define VAAPI_DRI_DIR "/dev/dri/"
#define VAAPI_PCI_DISPLAY_CONTROLLER_CLASS 0x03
namespace va {
static unsigned readId(const char* devName, const char* idName);
static int findAdapter(unsigned desiredVendorId);
bool openDisplay();
void closeDisplay();
int drmfd = -1;
VADisplay display = NULL;
bool initialized = false;
class Directory
{
typedef int (*fsort)(const struct dirent**, const struct dirent**);
public:
Directory(const char* path)
{
dirEntries = 0;
numEntries = scandir(path, &dirEntries, filterFunc, (fsort)alphasort);
}
~Directory()
{
if (numEntries && dirEntries)
{
for (int i = 0; i < numEntries; ++i)
free(dirEntries[i]);
free(dirEntries);
}
}
int count() const
{
return numEntries;
}
const struct dirent* operator[](int index) const
{
return ((dirEntries != 0) && (index >= 0) && (index < numEntries)) ? dirEntries[index] : 0;
}
protected:
static int filterFunc(const struct dirent* dir)
{
if (!dir) return 0;
if (!strcmp(dir->d_name, ".")) return 0;
if (!strcmp(dir->d_name, "..")) return 0;
return 1;
}
private:
int numEntries;
struct dirent** dirEntries;
};
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);
FILE* file = fopen(fileName, "r");
if (file)
{
char str[16] = "";
if (fgets(str, sizeof(str), file))
id = strtol(str, NULL, 16);
fclose(file);
}
return (unsigned)id;
}
static int findAdapter(unsigned desiredVendorId)
{
int adapterIndex = -1;
int numAdapters = 0;
Directory dir(VAAPI_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)
{
unsigned vendorId = readId(name, "vendor");
if (vendorId == desiredVendorId)
{
adapterIndex = numAdapters;
break;
}
++numAdapters;
}
}
return adapterIndex;
}
class NodeInfo
{
enum { NUM_NODES = 2 };
public:
NodeInfo(int adapterIndex)
{
const char* names[NUM_NODES] = { "renderD", "card" };
int numbers[NUM_NODES];
numbers[0] = adapterIndex+128;
numbers[1] = adapterIndex;
for (int i = 0; i < NUM_NODES; ++i)
{
int sz = sizeof(VAAPI_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]);
}
}
~NodeInfo()
{
for (int i = 0; i < NUM_NODES; ++i)
{
delete paths[i];
paths[i] = 0;
}
}
int count() const
{
return NUM_NODES;
}
const char* path(int index) const
{
return ((index >= 0) && (index < NUM_NODES)) ? paths[index] : 0;
}
private:
char* paths[NUM_NODES];
};
bool openDisplay()
{
if (!initialized)
{
const unsigned IntelVendorID = 0x8086;
drmfd = -1;
display = 0;
int adapterIndex = findAdapter(IntelVendorID);
if (adapterIndex >= 0)
{
NodeInfo nodes(adapterIndex);
for (int i = 0; i < nodes.count(); ++i)
{
drmfd = open(nodes.path(i), O_RDWR);
if (drmfd >= 0)
{
display = vaGetDisplayDRM(drmfd);
if (display)
{
int majorVersion = 0, minorVersion = 0;
if (vaInitialize(display, &majorVersion, &minorVersion) == VA_STATUS_SUCCESS)
{
initialized = true;
return true;
}
display = 0;
}
close(drmfd);
drmfd = -1;
}
}
}
if (adapterIndex < 0)
return false; // Can't find Intel display adapter
if ((drmfd < 0) || !display)
return false; // Can't load VA display
}
return true;
}
void closeDisplay()
{
if (initialized)
{
if (display)
vaTerminate(display);
if (drmfd >= 0)
close(drmfd);
display = 0;
drmfd = -1;
initialized = false;
}
}
} // namespace va

View File

@ -0,0 +1,315 @@
/* origin: libva-1.3.1/test/decode/mpeg2vldemo.cpp */
/*
* Copyright (c) 2007-2008 Intel Corporation. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <va/va.h>
#include "display.cpp.inc"
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/core/vaapi.hpp"
#define CHECK_VASTATUS(va_status,func) \
if (va_status != VA_STATUS_SUCCESS) { \
fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \
exit(1); \
}
/* Data dump of a 16x16 MPEG2 video clip,it has one I frame
*/
static unsigned char mpeg2_clip[]={
0x00,0x00,0x01,0xb3,0x01,0x00,0x10,0x13,0xff,0xff,0xe0,0x18,0x00,0x00,0x01,0xb5,
0x14,0x8a,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0xb8,0x00,0x08,0x00,0x00,0x00,0x00,
0x01,0x00,0x00,0x0f,0xff,0xf8,0x00,0x00,0x01,0xb5,0x8f,0xff,0xf3,0x41,0x80,0x00,
0x00,0x01,0x01,0x13,0xe1,0x00,0x15,0x81,0x54,0xe0,0x2a,0x05,0x43,0x00,0x2d,0x60,
0x18,0x01,0x4e,0x82,0xb9,0x58,0xb1,0x83,0x49,0xa4,0xa0,0x2e,0x05,0x80,0x4b,0x7a,
0x00,0x01,0x38,0x20,0x80,0xe8,0x05,0xff,0x60,0x18,0xe0,0x1d,0x80,0x98,0x01,0xf8,
0x06,0x00,0x54,0x02,0xc0,0x18,0x14,0x03,0xb2,0x92,0x80,0xc0,0x18,0x94,0x42,0x2c,
0xb2,0x11,0x64,0xa0,0x12,0x5e,0x78,0x03,0x3c,0x01,0x80,0x0e,0x80,0x18,0x80,0x6b,
0xca,0x4e,0x01,0x0f,0xe4,0x32,0xc9,0xbf,0x01,0x42,0x69,0x43,0x50,0x4b,0x01,0xc9,
0x45,0x80,0x50,0x01,0x38,0x65,0xe8,0x01,0x03,0xf3,0xc0,0x76,0x00,0xe0,0x03,0x20,
0x28,0x18,0x01,0xa9,0x34,0x04,0xc5,0xe0,0x0b,0x0b,0x04,0x20,0x06,0xc0,0x89,0xff,
0x60,0x12,0x12,0x8a,0x2c,0x34,0x11,0xff,0xf6,0xe2,0x40,0xc0,0x30,0x1b,0x7a,0x01,
0xa9,0x0d,0x00,0xac,0x64
};
/* hardcoded here without a bitstream parser helper
* please see picture mpeg2-I.jpg for bitstream details
*/
static VAPictureParameterBufferMPEG2 pic_param={
horizontal_size:16,
vertical_size:16,
forward_reference_picture:0xffffffff,
backward_reference_picture:0xffffffff,
picture_coding_type:1,
f_code:0xffff,
{
{
intra_dc_precision:0,
picture_structure:3,
top_field_first:0,
frame_pred_frame_dct:1,
concealment_motion_vectors:0,
q_scale_type:0,
intra_vlc_format:0,
alternate_scan:0,
repeat_first_field:0,
progressive_frame:1 ,
is_first_field:1
},
}
};
/* see MPEG2 spec65 for the defines of matrix */
static VAIQMatrixBufferMPEG2 iq_matrix = {
load_intra_quantiser_matrix:1,
load_non_intra_quantiser_matrix:1,
load_chroma_intra_quantiser_matrix:0,
load_chroma_non_intra_quantiser_matrix:0,
intra_quantiser_matrix:{
8, 16, 16, 19, 16, 19, 22, 22,
22, 22, 22, 22, 26, 24, 26, 27,
27, 27, 26, 26, 26, 26, 27, 27,
27, 29, 29, 29, 34, 34, 34, 29,
29, 29, 27, 27, 29, 29, 32, 32,
34, 34, 37, 38, 37, 35, 35, 34,
35, 38, 38, 40, 40, 40, 48, 48,
46, 46, 56, 56, 58, 69, 69, 83
},
non_intra_quantiser_matrix:{16},
chroma_intra_quantiser_matrix:{0},
chroma_non_intra_quantiser_matrix:{0}
};
#if 1
static VASliceParameterBufferMPEG2 slice_param={
slice_data_size:150,
slice_data_offset:0,
slice_data_flag:0,
macroblock_offset:38, /* 4byte + 6bits=38bits */
slice_horizontal_position:0,
slice_vertical_position:0,
quantiser_scale_code:2,
intra_slice_flag:0
};
#endif
#define CLIP_WIDTH 16
#define CLIP_HEIGHT 16
static void dumpSurface(VADisplay display, VASurfaceID surface_id, const char* fileName)
{
VAStatus va_status;
va_status = vaSyncSurface(display, surface_id);
CHECK_VASTATUS(va_status, "vaSyncSurface");
VAImage image;
va_status = vaDeriveImage(display, surface_id, &image);
CHECK_VASTATUS(va_status, "vaDeriveImage");
unsigned char* buffer = 0;
va_status = vaMapBuffer(display, image.buf, (void **)&buffer);
CHECK_VASTATUS(va_status, "vaMapBuffer");
CV_Assert(image.format.fourcc == VA_FOURCC_NV12);
/*
printf("image.format.fourcc = 0x%08x\n", image.format.fourcc);
printf("image.[width x height] = %d x %d\n", image.width, image.height);
printf("image.data_size = %d\n", image.data_size);
printf("image.num_planes = %d\n", image.num_planes);
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");
if (!out)
{
perror(fileName);
exit(1);
}
fwrite(buffer, 1, image.data_size, out);
fclose(out);
vaUnmapBuffer(display, image.buf);
CHECK_VASTATUS(va_status, "vaUnmapBuffer");
vaDestroyImage(display, image.image_id);
CHECK_VASTATUS(va_status, "vaDestroyImage");
}
int main(int argc,char **argv)
{
(void)argc; (void)argv;
VAEntrypoint entrypoints[5];
int num_entrypoints,vld_entrypoint;
VAConfigAttrib attrib;
VAConfigID config_id;
VASurfaceID surface_id;
VAContextID context_id;
VABufferID pic_param_buf,iqmatrix_buf,slice_param_buf,slice_data_buf;
VAStatus va_status;
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);
va_status = vaQueryConfigEntrypoints(va::display, VAProfileMPEG2Main, entrypoints,
&num_entrypoints);
CHECK_VASTATUS(va_status, "vaQueryConfigEntrypoints");
for (vld_entrypoint = 0; vld_entrypoint < num_entrypoints; vld_entrypoint++) {
if (entrypoints[vld_entrypoint] == VAEntrypointVLD)
break;
}
if (vld_entrypoint == num_entrypoints) {
/* not find VLD entry point */
assert(0);
}
/* Assuming finding VLD, find out the format for the render target */
attrib.type = VAConfigAttribRTFormat;
vaGetConfigAttributes(va::display, VAProfileMPEG2Main, VAEntrypointVLD,
&attrib, 1);
if ((attrib.value & VA_RT_FORMAT_YUV420) == 0) {
/* not find desired YUV420 RT format */
assert(0);
}
va_status = vaCreateConfig(va::display, VAProfileMPEG2Main, VAEntrypointVLD,
&attrib, 1,&config_id);
CHECK_VASTATUS(va_status, "vaCreateConfig");
va_status = vaCreateSurfaces(
va::display,
VA_RT_FORMAT_YUV420, CLIP_WIDTH, CLIP_HEIGHT,
&surface_id, 1,
NULL, 0
);
CHECK_VASTATUS(va_status, "vaCreateSurfaces");
/* Create a context for this decode pipe */
va_status = vaCreateContext(va::display, config_id,
CLIP_WIDTH,
((CLIP_HEIGHT+15)/16)*16,
VA_PROGRESSIVE,
&surface_id,
1,
&context_id);
CHECK_VASTATUS(va_status, "vaCreateContext");
va_status = vaCreateBuffer(va::display, context_id,
VAPictureParameterBufferType,
sizeof(VAPictureParameterBufferMPEG2),
1, &pic_param,
&pic_param_buf);
CHECK_VASTATUS(va_status, "vaCreateBuffer");
va_status = vaCreateBuffer(va::display, context_id,
VAIQMatrixBufferType,
sizeof(VAIQMatrixBufferMPEG2),
1, &iq_matrix,
&iqmatrix_buf );
CHECK_VASTATUS(va_status, "vaCreateBuffer");
va_status = vaCreateBuffer(va::display, context_id,
VASliceParameterBufferType,
sizeof(VASliceParameterBufferMPEG2),
1,
&slice_param, &slice_param_buf);
CHECK_VASTATUS(va_status, "vaCreateBuffer");
va_status = vaCreateBuffer(va::display, context_id,
VASliceDataBufferType,
0xc4-0x2f+1,
1,
mpeg2_clip+0x2f,
&slice_data_buf);
CHECK_VASTATUS(va_status, "vaCreateBuffer");
va_status = vaBeginPicture(va::display, context_id, surface_id);
CHECK_VASTATUS(va_status, "vaBeginPicture");
va_status = vaRenderPicture(va::display,context_id, &pic_param_buf, 1);
CHECK_VASTATUS(va_status, "vaRenderPicture");
va_status = vaRenderPicture(va::display,context_id, &iqmatrix_buf, 1);
CHECK_VASTATUS(va_status, "vaRenderPicture");
va_status = vaRenderPicture(va::display,context_id, &slice_param_buf, 1);
CHECK_VASTATUS(va_status, "vaRenderPicture");
va_status = vaRenderPicture(va::display,context_id, &slice_data_buf, 1);
CHECK_VASTATUS(va_status, "vaRenderPicture");
va_status = vaEndPicture(va::display,context_id);
CHECK_VASTATUS(va_status, "vaEndPicture");
va_status = vaSyncSurface(va::display, surface_id);
CHECK_VASTATUS(va_status, "vaSyncSurface");
dumpSurface(va::display, surface_id, argv[1]);
cv::Size size(CLIP_WIDTH,CLIP_HEIGHT);
cv::UMat u;
cv::vaapi::convertFromVASurface(surface_id, size, u);
cv::blur(u, u, cv::Size(7, 7), cv::Point(-3, -3));
cv::vaapi::convertToVASurface(u, surface_id, size);
dumpSurface(va::display, surface_id, argv[2]);
vaDestroySurfaces(va::display,&surface_id,1);
vaDestroyConfig(va::display,config_id);
vaDestroyContext(va::display,context_id);
vaTerminate(va::display);
va::closeDisplay();
return 0;
}