#include "libavutil/imgutils.h"
#include "va/va.h"
#include "va/va_x11.h"
+#include "dlfcn.h"
#include "maru_brillcodec_plugin.h"
#define SURFACE_COUNT 4
-#ifndef VA_SURFACE_ATTRIB_SETTABLE
-#define vaCreateSurfaces(d, f, w, h, s, ns, a, na) \
- vaCreateSurfaces(d, w, h, f, ns, s)
-#endif
-
-
typedef struct VAPluginContext {
+ VAContextID context_id;
VASurfaceID surface_id[SURFACE_COUNT];
bool surface_is_occupied[SURFACE_COUNT];
} VAPluginContext;
static void *va_display;
+static int va_major_version, va_minor_version;
// FIXME
static VAPluginContext *va_ctx = &(VAPluginContext) {};
+
+// fuction pointers to VAAPI
+VADisplay (*_vaGetDisplay)(Display *);
+VAStatus (*_vaInitialize)(VADisplay, int *, int *);
+int (*_vaMaxNumProfiles)(VADisplay);
+VAStatus (*_vaQueryConfigProfiles)(VADisplay, VAProfile *, int *);
+VAStatus (*_vaGetConfigAttributes)(VADisplay, VAProfile, VAEntrypoint, VAConfigAttrib *, int);
+VAStatus (*_vaCreateConfig)(VADisplay, VAProfile, VAEntrypoint, VAConfigAttrib *, int, VAConfigID *);
+
+void (*_vaCreateSurfaces)(void);
+// for VAAPI version >= 0.34
+typedef VAStatus (*_vaCreateSurfaces8)(VADisplay, unsigned int, unsigned int, unsigned int, VASurfaceID *,
+ unsigned int, VASurfaceAttrib *, unsigned int);
+// for VAAPI version < 0.34
+typedef VAStatus (*_vaCreateSurfaces6)(VADisplay, int, int, int, int, VASurfaceID *);
+
+VAStatus (*_vaCreateContext)(VADisplay, VAConfigID, int, int, int, VASurfaceID *, int, VAContextID *);
+int (*_vaMaxNumImageFormats)(VADisplay dpy);
+VAStatus (*_vaQueryImageFormats)(VADisplay, VAImageFormat *, int *);
+VAStatus (*_vaDeriveImage)(VADisplay, VASurfaceID, VAImage *);
+VAStatus (*_vaCreateImage)(VADisplay, VAImageFormat *, int, int, VAImage *);
+VAStatus (*_vaDestroyImage)(VADisplay, VAImageID);
+
+void (*_vaSyncSurface)(void);
+// for VAAPI version >= 0.31
+typedef VAStatus (*_vaSyncSurface2)(VADisplay, VASurfaceID);
+// for VAAPI version < 0.31
+typedef VAStatus (*_vaSyncSurface3)(VADisplay, VAContextID, VASurfaceID);
+
+VAStatus (*_vaGetImage)(VADisplay, VASurfaceID, int, int, unsigned int, unsigned int, VAImageID);
+VAStatus (*_vaMapBuffer)(VADisplay, VABufferID, void **);
+VAStatus (*_vaUnmapBuffer)(VADisplay, VABufferID);
+
+static inline bool check_version(int major, int minor)
+{
+ if (va_major_version > major ||
+ (va_major_version == major && va_minor_version >= minor)) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool initialize(void)
+{
+ if (!va_display) {
+ Display *display = XOpenDisplay(NULL);
+ if (!display)
+ {
+ printf("Could not connect to x server\n");
+ return false;
+ }
+
+ va_display = _vaGetDisplay(display);
+ if (!va_display)
+ {
+ printf("Could not get a VAAPI device\n");
+ return false;
+ }
+
+ if (_vaInitialize(va_display, &va_major_version, &va_minor_version))
+ {
+ va_display = NULL;
+ printf("Failed to initialize the VAAPI device\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#define DLSYM(func) \
+ { _##func = dlsym(handle, #func); \
+ if (!_##func) { goto error; } }
+
+static bool probe(void)
+{
+ void *handle = dlopen("libva-x11.so", RTLD_NOW);
+ if (!handle) {
+ goto error;
+ }
+
+ DLSYM(vaGetDisplay);
+
+ handle = dlopen("libva.so", RTLD_NOW);
+ if (!handle) {
+ goto error;
+ }
+
+ DLSYM(vaInitialize);
+ DLSYM(vaMaxNumProfiles);
+ DLSYM(vaQueryConfigProfiles);
+ DLSYM(vaGetConfigAttributes);
+ DLSYM(vaCreateConfig);
+ DLSYM(vaCreateSurfaces);
+ DLSYM(vaCreateContext);
+ DLSYM(vaMaxNumImageFormats);
+ DLSYM(vaQueryImageFormats);
+ DLSYM(vaDeriveImage);
+ DLSYM(vaCreateImage);
+ DLSYM(vaDestroyImage);
+ DLSYM(vaSyncSurface);
+ DLSYM(vaGetImage);
+ DLSYM(vaMapBuffer);
+ DLSYM(vaUnmapBuffer);
+
+ // we initialize vaapi now for sure...
+ if (!initialize()) {
+ printf("Can not initialize VA-API\n");
+ return false;
+ }
+
+ return true;
+
+error:
+ printf("plugin load failed : %s\n", dlerror());
+
+ return false;
+}
+
static int create_surfaces(AVCodecContext *ctx, int width, int height, VAProfile profile)
{
assert(width > 0 && height > 0);
VAConfigAttrib attrib;
memset(&attrib, 0, sizeof(attrib));
attrib.type = VAConfigAttribRTFormat;
- if (vaGetConfigAttributes(va_display,
+ if (_vaGetConfigAttributes(va_display,
profile, VAEntrypointVLD, &attrib, 1)) {
goto error;
}
if ((attrib.value & VA_RT_FORMAT_YUV420) == 0)
goto error;
- if (vaCreateConfig(va_display,
+ if (_vaCreateConfig(va_display,
profile, VAEntrypointVLD, &attrib, 1, &config_id)) {
goto error;
}
/* Create surfaces */
- if (vaCreateSurfaces(va_display, VA_RT_FORMAT_YUV420, width, height,
- va_ctx->surface_id, SURFACE_COUNT, NULL, 0)) {
- goto error;
+ if (check_version(0, 34)) {
+ if (((_vaCreateSurfaces8)_vaCreateSurfaces)(va_display, VA_RT_FORMAT_YUV420, width, height,
+ va_ctx->surface_id, SURFACE_COUNT, NULL, 0)) {
+ goto error;
+ }
+ } else {
+ if (((_vaCreateSurfaces6)_vaCreateSurfaces)(va_display, width, height, VA_RT_FORMAT_YUV420,
+ SURFACE_COUNT, va_ctx->surface_id)) {
+ goto error;
+ }
}
- VAContextID context_id = VA_INVALID_ID;
+ va_ctx->context_id = VA_INVALID_ID;
/* Create a context */
- if (vaCreateContext(va_display, config_id,
+ if (_vaCreateContext(va_display, config_id,
width, height, VA_PROGRESSIVE,
- va_ctx->surface_id, SURFACE_COUNT, &context_id)) {
+ va_ctx->surface_id, SURFACE_COUNT, &va_ctx->context_id)) {
goto error;
}
- int fmt_count = vaMaxNumImageFormats(va_display);
- VAImageFormat *p_fmt = calloc(fmt_count, sizeof(*p_fmt));
+ int fmt_count = _vaMaxNumImageFormats(va_display);
+ VAImageFormat *p_fmt = g_malloc0_n(fmt_count, sizeof(*p_fmt));
if (!p_fmt) {
goto error;
}
- if (vaQueryImageFormats(va_display, p_fmt, &fmt_count)) {
- free( p_fmt );
+ if (_vaQueryImageFormats(va_display, p_fmt, &fmt_count)) {
+ g_free(p_fmt);
goto error;
}
VAImage test_image;
- if (vaDeriveImage(va_display, va_ctx->surface_id[0], &test_image) == VA_STATUS_SUCCESS) {
+ if (_vaDeriveImage(va_display, va_ctx->surface_id[0], &test_image) == VA_STATUS_SUCCESS) {
va_ctx->is_supports_derive = true;
- vaDestroyImage(va_display, test_image.image_id);
+ _vaDestroyImage(va_display, test_image.image_id);
}
int i;
for (i = 0; i < fmt_count; ++i) {
if (p_fmt[i].fourcc == VA_FOURCC_YV12) { // we support only VA_FOURCC_YV12 for now...
- if (vaCreateImage(va_display, &p_fmt[i], width, height, &va_ctx->image )) {
+ if (_vaCreateImage(va_display, &p_fmt[i], width, height, &va_ctx->image )) {
goto error;
}
}
}
if (va_ctx->is_supports_derive) {
- vaDestroyImage(va_display, va_ctx->image.image_id);
+ _vaDestroyImage(va_display, va_ctx->image.image_id);
va_ctx->image.image_id = VA_INVALID_ID;
}
hw_context->display = va_display;
hw_context->config_id = config_id;
- hw_context->context_id = context_id;
+ hw_context->context_id = va_ctx->context_id;
return 0;
}
static bool setup(AVCodecContext *ctx, int width, int height) {
- if (!va_display) {
- Display *display = XOpenDisplay(NULL);
- if(!display)
- {
- printf("Could not connect to x server\n");
- }
-
- va_display = vaGetDisplay(display);
- if(!va_display)
- {
- printf("Could not get a VAAPI device\n");
- }
-
- int major, minor;
- if(vaInitialize(va_display, &major, &minor))
- {
- printf("Failed to initialize the VAAPI device\n");
- }
- }
-
VAProfile profile;
int codec_id = ctx->codec_id;
goto error;
}
- int num_profiles = vaMaxNumProfiles(va_display);
- VAProfile *profiles_list = calloc(num_profiles, sizeof(VAProfile));
+ int num_profiles = _vaMaxNumProfiles(va_display);
+ VAProfile *profiles_list = g_malloc0_n(num_profiles, sizeof(VAProfile));
bool is_supported_profile;
int i;
goto error;
}
- VAStatus status = vaQueryConfigProfiles(va_display, profiles_list, &num_profiles);
+ VAStatus status = _vaQueryConfigProfiles(va_display, profiles_list, &num_profiles);
if (status == VA_STATUS_SUCCESS) {
for (i = 0; i < num_profiles; ++i) {
if (profiles_list[i] == profile) {
}
}
}
- free(profiles_list);
+ g_free(profiles_list);
if (!is_supported_profile)
{
printf("Codec and profile not supported by the VAAPI device");
AVFrame *frame = (AVFrame *)src;
VASurfaceID surface_id = (VASurfaceID)(uintptr_t)frame->data[3];
-#if VA_CHECK_VERSION(0,31,0)
- if (vaSyncSurface(va_display, surface_id))
-#else
-#error
-#endif
- {
- return;
+ if (check_version(0, 31)) {
+ if (((_vaSyncSurface2)_vaSyncSurface)(va_display, surface_id)) {
+ return;
+ }
+ } else {
+ if (((_vaSyncSurface3)_vaSyncSurface)(va_display, va_ctx->context_id, surface_id)) {
+ return;
+ }
}
if (va_ctx->is_supports_derive) {
- if (vaDeriveImage(va_display, surface_id, &va_ctx->image) != VA_STATUS_SUCCESS) {
+ if (_vaDeriveImage(va_display, surface_id, &va_ctx->image) != VA_STATUS_SUCCESS) {
return;
}
} else {
- if (vaGetImage(va_display, surface_id,
+ if (_vaGetImage(va_display, surface_id,
0, 0, frame->width, frame->height,
va_ctx->image.image_id)) {
return;
}
void *p_base;
- if (vaMapBuffer(va_display, va_ctx->image.buf, &p_base)) {
+ if (_vaMapBuffer(va_display, va_ctx->image.buf, &p_base)) {
return;
}
return;
}
- if (vaUnmapBuffer(va_display, va_ctx->image.buf)) {
+ if (_vaUnmapBuffer(va_display, va_ctx->image.buf)) {
return;
}
if (va_ctx->is_supports_derive)
{
- vaDestroyImage(va_display, va_ctx->image.image_id);
+ _vaDestroyImage(va_display, va_ctx->image.image_id);
va_ctx->image.image_id = VA_INVALID_ID;
}
}
CodecPlugin vaapi_plugin = {
+ .name = "VA-API",
.pix_fmt = PIX_FMT_VAAPI_VLD,
.output_pix_fmt = PIX_FMT_YUV420P,
+ .probe = probe,
.setup = setup,
.get_buffer = get_surface,
.release_buffer = release_surface,