#include "maru_brillcodec_plugin.h"
-#define SURFACE_COUNT 4
+#define DEFAULT_SURFACE_COUNT 4
-typedef struct VAPluginContext {
+struct SurfaceState;
+typedef struct SurfaceState SurfaceState;
+
+typedef struct {
+ void *display;
+ VAConfigID config_id;
VAContextID context_id;
- VASurfaceID surface_id[SURFACE_COUNT];
- bool surface_is_occupied[SURFACE_COUNT];
+
+ unsigned int surface_count;
+ VASurfaceID *surface_id;
+ SurfaceState *surface_state;
VAImage image;
bool is_supports_derive;
} VAPluginContext;
+struct SurfaceState {
+ VAPluginContext *va_ctx;
+ bool is_occupied;
+};
+
static void *va_display;
static int va_major_version, va_minor_version;
// FIXME
-static VAPluginContext *va_ctx = &(VAPluginContext) {};
-
+//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 *);
+VAStatus (*_vaDestroyConfig)(VADisplay, VAConfigID);
void (*_vaCreateSurfaces)(void);
// for VAAPI version >= 0.34
unsigned int, VASurfaceAttrib *, unsigned int);
// for VAAPI version < 0.34
typedef VAStatus (*_vaCreateSurfaces6)(VADisplay, int, int, int, int, VASurfaceID *);
+VAStatus (*_vaDestroySurfaces)(VADisplay, VASurfaceID *, int);
VAStatus (*_vaCreateContext)(VADisplay, VAConfigID, int, int, int, VASurfaceID *, int, VAContextID *);
+VAStatus (*_vaDestroyContext)(VADisplay, VAContextID);
int (*_vaMaxNumImageFormats)(VADisplay dpy);
VAStatus (*_vaQueryImageFormats)(VADisplay, VAImageFormat *, int *);
VAStatus (*_vaDeriveImage)(VADisplay, VASurfaceID, VAImage *);
DLSYM(vaQueryConfigProfiles);
DLSYM(vaGetConfigAttributes);
DLSYM(vaCreateConfig);
+ DLSYM(vaDestroyConfig);
DLSYM(vaCreateSurfaces);
+ DLSYM(vaDestroySurfaces);
DLSYM(vaCreateContext);
+ DLSYM(vaDestroyContext);
DLSYM(vaMaxNumImageFormats);
DLSYM(vaQueryImageFormats);
DLSYM(vaDeriveImage);
return false;
}
-static int create_surfaces(AVCodecContext *ctx, int width, int height, VAProfile profile)
+static int create_surfaces(VAPluginContext *va_ctx,
+ int width, int height, VAProfile profile)
{
assert(width > 0 && height > 0);
- VAConfigID config_id;
+ int i;
+ VAImageFormat *p_fmt = NULL;
/* Create a VA configuration */
VAConfigAttrib attrib;
memset(&attrib, 0, sizeof(attrib));
attrib.type = VAConfigAttribRTFormat;
- if (_vaGetConfigAttributes(va_display,
+ if (_vaGetConfigAttributes(va_ctx->display,
profile, VAEntrypointVLD, &attrib, 1)) {
goto error;
}
if ((attrib.value & VA_RT_FORMAT_YUV420) == 0)
goto error;
- if (_vaCreateConfig(va_display,
- profile, VAEntrypointVLD, &attrib, 1, &config_id)) {
+ if (_vaCreateConfig(va_ctx->display,
+ profile, VAEntrypointVLD, &attrib, 1, &va_ctx->config_id)) {
goto error;
}
+ va_ctx->surface_count = DEFAULT_SURFACE_COUNT; // FIXME
+
+ va_ctx->surface_id = g_malloc_n(va_ctx->surface_count, sizeof(VASurfaceID));
+ va_ctx->surface_state = g_malloc_n(va_ctx->surface_count, sizeof(SurfaceState));
+
+ for (i = 0; i < va_ctx->surface_count; ++i) {
+ va_ctx->surface_state[i].va_ctx = va_ctx;
+ va_ctx->surface_state[i].is_occupied = false;
+ }
+
/* Create surfaces */
if (check_version(0, 34)) {
- if (((_vaCreateSurfaces8)_vaCreateSurfaces)(va_display, VA_RT_FORMAT_YUV420, width, height,
- va_ctx->surface_id, SURFACE_COUNT, NULL, 0)) {
+ if (((_vaCreateSurfaces8)_vaCreateSurfaces)(va_ctx->display, VA_RT_FORMAT_YUV420, width, height,
+ va_ctx->surface_id, va_ctx->surface_count, NULL, 0)) {
goto error;
}
} else {
- if (((_vaCreateSurfaces6)_vaCreateSurfaces)(va_display, width, height, VA_RT_FORMAT_YUV420,
- SURFACE_COUNT, va_ctx->surface_id)) {
+ if (((_vaCreateSurfaces6)_vaCreateSurfaces)(va_ctx->display, width, height, VA_RT_FORMAT_YUV420,
+ va_ctx->surface_count, va_ctx->surface_id)) {
goto error;
}
}
va_ctx->context_id = VA_INVALID_ID;
/* Create a context */
- if (_vaCreateContext(va_display, config_id,
+ if (_vaCreateContext(va_ctx->display, va_ctx->config_id,
width, height, VA_PROGRESSIVE,
- va_ctx->surface_id, SURFACE_COUNT, &va_ctx->context_id)) {
+ va_ctx->surface_id, va_ctx->surface_count, &va_ctx->context_id)) {
goto error;
}
- int fmt_count = _vaMaxNumImageFormats(va_display);
- VAImageFormat *p_fmt = g_malloc0_n(fmt_count, sizeof(*p_fmt));
+ int fmt_count = _vaMaxNumImageFormats(va_ctx->display);
+ p_fmt = g_malloc0_n(fmt_count, sizeof(*p_fmt));
if (!p_fmt) {
goto error;
}
- if (_vaQueryImageFormats(va_display, p_fmt, &fmt_count)) {
- g_free(p_fmt);
+ if (_vaQueryImageFormats(va_ctx->display, p_fmt, &fmt_count)) {
goto error;
}
VAImage test_image;
- if (_vaDeriveImage(va_display, va_ctx->surface_id[0], &test_image) == VA_STATUS_SUCCESS) {
+ if (_vaDeriveImage(va_ctx->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_ctx->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_ctx->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_ctx->display, va_ctx->image.image_id);
va_ctx->image.image_id = VA_INVALID_ID;
}
- // prepare the libav hardware context
- struct vaapi_context *hw_context = g_malloc0(sizeof(struct vaapi_context));
- ctx->hwaccel_context = hw_context;
-
- hw_context->display = va_display;
- hw_context->config_id = config_id;
- hw_context->context_id = va_ctx->context_id;
+ g_free(p_fmt);
return 0;
error:
- // TODO: destroy sufaces
+ g_free(p_fmt);
return -1;
}
-static bool setup(AVCodecContext *ctx, int width, int height) {
+static void cleanup(void *opaque)
+{
+ VAPluginContext *va_ctx = (VAPluginContext *)opaque;
+
+ if (va_ctx->context_id) {
+ _vaDestroyContext(va_ctx->display, va_ctx->context_id);
+ va_ctx->context_id = 0;
+ }
+
+ if (va_ctx->surface_id) {
+ _vaDestroySurfaces(va_ctx->display, va_ctx->surface_id, va_ctx->surface_count);
+ va_ctx->surface_id = NULL;
+ }
+
+ if (va_ctx->config_id) {
+ _vaDestroyConfig(va_ctx->display, va_ctx->config_id);
+ va_ctx->config_id = 0;
+ }
+
+ g_free(va_ctx->surface_id);
+ g_free(va_ctx->surface_state);
+ g_free(va_ctx);
+}
+
+
+static void *setup(AVCodecContext *ctx, int width, int height) {
+ VAPluginContext *va_ctx = g_malloc0(sizeof(VAPluginContext));
+ va_ctx->display = va_display;
+
VAProfile profile;
int codec_id = ctx->codec_id;
goto error;
}
- int num_profiles = _vaMaxNumProfiles(va_display);
+ int num_profiles = _vaMaxNumProfiles(va_ctx->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_ctx->display, profiles_list, &num_profiles);
if (status == VA_STATUS_SUCCESS) {
for (i = 0; i < num_profiles; ++i) {
if (profiles_list[i] == profile) {
goto error;
}
- if(create_surfaces(ctx, width, height, profile)) {
+
+ if(create_surfaces(va_ctx, width, height, profile)) {
printf("Failed to initialize the VAAPI device\n");
+ goto error;
}
- return true;
+ // prepare the libav hardware context
+ struct vaapi_context *hw_context = g_malloc0(sizeof(struct vaapi_context));
+ ctx->hwaccel_context = hw_context;
+
+ hw_context->display = va_ctx->display;
+ hw_context->config_id = va_ctx->config_id;
+ hw_context->context_id = va_ctx->context_id;
+
+ return va_ctx;
error:
- // TODO: error handling
- return false;
+ cleanup(va_ctx);
+ g_free(va_ctx);
+ return NULL;
}
static void copy_plane(uint8_t *dst,
{
AVFrame *frame = (AVFrame *)src;
VASurfaceID surface_id = (VASurfaceID)(uintptr_t)frame->data[3];
+ VAPluginContext *va_ctx = (VAPluginContext *)((SurfaceState *)frame->opaque)->va_ctx;
if (check_version(0, 31)) {
- if (((_vaSyncSurface2)_vaSyncSurface)(va_display, surface_id)) {
+ if (((_vaSyncSurface2)_vaSyncSurface)(va_ctx->display, surface_id)) {
return;
}
} else {
- if (((_vaSyncSurface3)_vaSyncSurface)(va_display, va_ctx->context_id, surface_id)) {
+ if (((_vaSyncSurface3)_vaSyncSurface)(va_ctx->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_ctx->display, surface_id, &va_ctx->image) != VA_STATUS_SUCCESS) {
return;
}
} else {
- if (_vaGetImage(va_display, surface_id,
+ if (_vaGetImage(va_ctx->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_ctx->display, va_ctx->image.buf, &p_base)) {
return;
}
return;
}
- if (_vaUnmapBuffer(va_display, va_ctx->image.buf)) {
+ if (_vaUnmapBuffer(va_ctx->display, va_ctx->image.buf)) {
return;
}
if (va_ctx->is_supports_derive)
{
- _vaDestroyImage(va_display, va_ctx->image.image_id);
+ _vaDestroyImage(va_ctx->display, va_ctx->image.image_id);
va_ctx->image.image_id = VA_INVALID_ID;
}
return;
}
-static int get_surface(AVCodecContext *p_context,
+static int get_surface(AVCodecContext *ctx,
AVFrame *frame)
{
int i;
- for (i = 0; i < SURFACE_COUNT; ++i) {
- if (va_ctx->surface_is_occupied[i]) continue;
+ VAPluginContext *va_ctx = (VAPluginContext *)get_plugin_context(ctx);
+
+ for (i = 0; i < va_ctx->surface_count; ++i) {
+ if (va_ctx->surface_state[i].is_occupied) {
+ continue;
+ }
break;
}
+ va_ctx->surface_state[i].is_occupied = true;
+
frame->data[0] = (void *)(uintptr_t)va_ctx->surface_id[i];
frame->data[3] = frame->data[0];
frame->type = FF_BUFFER_TYPE_USER;
- frame->opaque = (void *)&(va_ctx->surface_is_occupied[i]);
- // is_occupied = true;
- *((bool *)frame->opaque) = true;
+
+ frame->opaque = (void *)&(va_ctx->surface_state[i]);
return 0;
}
-static void release_surface(AVCodecContext *p_context,
+static void release_surface(AVCodecContext *ctx,
AVFrame *frame)
{
int i;
+
for (i = 0; i < 4; ++i) {
frame->data[i] = NULL;
}
- // is_occupied = false;
- *((bool *)frame->opaque) = false;
+ ((SurfaceState *)frame->opaque)->is_occupied = false;
}
CodecPlugin vaapi_plugin = {
.output_pix_fmt = PIX_FMT_YUV420P,
.probe = probe,
.setup = setup,
+ .cleanup = cleanup,
.get_buffer = get_surface,
.release_buffer = release_surface,
.get_picture = extract,