Browse Source

hw: vaapi: add pictures and pool helpers

pull/58/head
Thomas Guillem 9 years ago
parent
commit
a520cc7880
  1. 330
      modules/hw/vaapi/vlc_vaapi.c
  2. 37
      modules/hw/vaapi/vlc_vaapi.h

330
modules/hw/vaapi/vlc_vaapi.c

@ -35,6 +35,11 @@
#include <va/va.h>
#include <vlc_common.h>
#include <vlc_atomic.h>
#include <vlc_fourcc.h>
#include <vlc_picture_pool.h>
/* This macro is designed to wrap any VA call, and in case of failure,
display the VA error string then goto the 'error' label (which you must
define). */
@ -251,3 +256,328 @@ vlc_vaapi_EndPicture(vlc_object_t *o, VADisplay dpy, VAContextID ctx)
return VLC_SUCCESS;
error: return VLC_EGENERIC;
}
/*****************
* VAAPI helpers *
*****************/
static bool
IsVaProfileSupported(VADisplay dpy, VAProfile i_profile)
{
/* Check if the selected profile is supported */
if (i_profile == VAProfileNone)
return true;
int i_profiles_nb = vaMaxNumProfiles(dpy);
if (i_profiles_nb < 0)
return false;
VAProfile *p_profiles_list = calloc(i_profiles_nb, sizeof(VAProfile));
if (!p_profiles_list)
return false;
bool b_supported_profile = false;
VAStatus status =
vaQueryConfigProfiles(dpy, p_profiles_list, &i_profiles_nb);
if (status != VA_STATUS_SUCCESS)
goto error;
for (int i = 0; i < i_profiles_nb; i++)
{
if (p_profiles_list[i] == i_profile)
{
b_supported_profile = true;
break;
}
}
error:
free(p_profiles_list);
return b_supported_profile;
}
static bool
IsEntrypointAvailable(VADisplay dpy, VAProfile i_profile,
VAEntrypoint entrypoint)
{
VAEntrypoint * entrypoints;
int num_entrypoints = vaMaxNumEntrypoints(dpy);
bool ret = false;
if (num_entrypoints <= 0)
return false;
entrypoints = malloc(num_entrypoints * sizeof(VAEntrypoint));
if (!entrypoints)
return false;
VAStatus status =
vaQueryConfigEntrypoints(dpy, i_profile, entrypoints, &num_entrypoints);
if (status != VA_STATUS_SUCCESS)
goto error;
for (int i = 0; i < num_entrypoints; ++i)
if (entrypoint == entrypoints[i])
{
ret = true;
break;
}
error:
free(entrypoints);
return ret;
}
VAConfigID
vlc_vaapi_CreateConfigChecked(vlc_object_t *o, VADisplay dpy,
VAProfile i_profile, VAEntrypoint entrypoint,
int va_force_fourcc)
{
if (!IsVaProfileSupported(dpy, i_profile))
{
msg_Err(o, "profile(%d) is not supported", i_profile);
return VA_INVALID_ID;
}
if (!IsEntrypointAvailable(dpy, i_profile, entrypoint))
{
msg_Err(o, "entrypoint(%d) is not available", entrypoint);
return VA_INVALID_ID;
}
/* Create a VA configuration */
VAConfigAttrib attrib = {
.type = VAConfigAttribRTFormat,
};
if (vaGetConfigAttributes(dpy, i_profile, entrypoint, &attrib, 1))
{
msg_Err(o, "vaGetConfigAttributes failed");
return VA_INVALID_ID;
}
/* Not sure what to do if not, I don't have a way to test */
if ((attrib.value & VA_RT_FORMAT_YUV420) == 0)
{
msg_Err(o, "config doesn't support VA_RT_FORMAT_YUV420");
return VA_INVALID_ID;
}
unsigned int num_sattribs;
VASurfaceAttrib *sattribs = NULL;
VAConfigID va_config_id = VA_INVALID_ID;
VA_CALL(o, vaCreateConfig, dpy, i_profile, entrypoint, &attrib, 1,
&va_config_id);
if (va_force_fourcc == 0)
return va_config_id;
/* Fetch VASurfaceAttrib list to make sure the decoder can output NV12 */
if (vaQuerySurfaceAttributes(dpy, va_config_id, NULL, &num_sattribs)
!= VA_STATUS_SUCCESS)
goto error;
sattribs = malloc(num_sattribs * sizeof(*sattribs));
if (sattribs == NULL)
goto error;
if (vaQuerySurfaceAttributes(dpy, va_config_id, sattribs, &num_sattribs)
!= VA_STATUS_SUCCESS)
goto error;
for (unsigned i = 0; i < num_sattribs; ++i)
{
VASurfaceAttrib *sattrib = &sattribs[i];
if (sattrib->type == VASurfaceAttribPixelFormat
&& sattrib->flags & VA_SURFACE_ATTRIB_SETTABLE
&& sattrib->value.value.i == va_force_fourcc)
{
free(sattribs);
return va_config_id;
}
}
error:
free(sattribs);
if (va_config_id != VA_INVALID_ID)
{
msg_Err(o, "config doesn't support forced fourcc");
vlc_vaapi_DestroyConfig(o, dpy, va_config_id);
}
return VA_INVALID_ID;
}
struct vaapi_pic_ctx
{
picture_context_t s;
VASurfaceID surface;
picture_t *picref;
};
struct pic_sys_vaapi_instance
{
atomic_int refcount;
VADisplay dpy;
unsigned num_render_targets;
VASurfaceID render_targets[];
};
struct picture_sys_t
{
struct pic_sys_vaapi_instance *instance;
struct vaapi_pic_ctx ctx;
};
static void
pool_pic_destroy_cb(picture_t *pic)
{
picture_sys_t *p_sys = pic->p_sys;
struct pic_sys_vaapi_instance *instance = p_sys->instance;
if (atomic_fetch_sub(&instance->refcount, 1) == 1)
{
vaDestroySurfaces(instance->dpy, instance->render_targets,
instance->num_render_targets);
vlc_vaapi_ReleaseInstance(instance->dpy);
free(instance);
}
free(pic->p_sys);
free(pic);
}
static void
pic_ctx_destroy_cb(struct picture_context_t *opaque)
{
struct vaapi_pic_ctx *ctx = (struct vaapi_pic_ctx *) opaque;
picture_Release(ctx->picref);
free(opaque);
}
static struct picture_context_t *
pic_ctx_copy_cb(struct picture_context_t *opaque)
{
struct vaapi_pic_ctx *src_ctx = (struct vaapi_pic_ctx *) opaque;
struct vaapi_pic_ctx *dst_ctx = malloc(sizeof *dst_ctx);
if (dst_ctx == NULL)
return NULL;
dst_ctx->s.destroy = pic_ctx_destroy_cb;
dst_ctx->s.copy = pic_ctx_copy_cb;
dst_ctx->surface = src_ctx->surface;
dst_ctx->picref = picture_Hold(src_ctx->picref);
return &dst_ctx->s;
}
static void
pic_sys_ctx_destroy_cb(struct picture_context_t *opaque)
{
(void) opaque;
}
picture_pool_t *
vlc_vaapi_PoolNew(vlc_object_t *o, VADisplay dpy, unsigned count,
VASurfaceID **render_targets,
const video_format_t *restrict fmt,
unsigned va_rt_format, int va_force_fourcc)
{
struct pic_sys_vaapi_instance *instance =
malloc(sizeof(*instance) + count * sizeof(VASurfaceID));
if (!instance)
return NULL;
instance->num_render_targets = count;
atomic_init(&instance->refcount, 0);
VASurfaceAttrib *attribs = NULL;
unsigned num_attribs = 0;
VASurfaceAttrib fourcc_attribs[1] = {
{
.type = VASurfaceAttribPixelFormat,
.flags = VA_SURFACE_ATTRIB_SETTABLE,
.value.type = VAGenericValueTypeInteger,
.value.value.i = va_force_fourcc,
}
};
if (va_force_fourcc != 0)
{
attribs = fourcc_attribs;
num_attribs = 1;
}
picture_t *pics[count];
VA_CALL(o, vaCreateSurfaces, dpy, va_rt_format,
fmt->i_visible_width, fmt->i_visible_height,
instance->render_targets, instance->num_render_targets,
attribs, num_attribs);
for (unsigned i = 0; i < count; i++)
{
picture_sys_t *p_sys = malloc(sizeof *p_sys);
if (p_sys == NULL)
{
count = i;
goto error_pic;
}
p_sys->instance = instance;
p_sys->ctx.s.destroy = pic_sys_ctx_destroy_cb;
p_sys->ctx.s.copy = pic_ctx_copy_cb;
p_sys->ctx.surface = instance->render_targets[i];
p_sys->ctx.picref = NULL;
picture_resource_t rsc = {
.p_sys = p_sys,
.pf_destroy = pool_pic_destroy_cb,
};
pics[i] = picture_NewFromResource(fmt, &rsc);
if (pics[i] == NULL)
{
free(p_sys);
count = i;
goto error_pic;
}
}
picture_pool_t *pool = picture_pool_New(count, pics);
if (!pool)
goto error_pic;
atomic_store(&instance->refcount, count);
instance->dpy = vlc_vaapi_GetInstance(); /* Hold a reference on VADisplay */
assert(instance->dpy == dpy);
*render_targets = instance->render_targets;
return pool;
error_pic:
while (count > 0)
picture_Release(pics[--count]);
VA_CALL(o, vaDestroySurfaces, instance->dpy, instance->render_targets,
instance->num_render_targets);
error:
free(instance);
return NULL;
}
unsigned
vlc_vaapi_PicSysGetRenderTargets(picture_sys_t *sys,
VASurfaceID **render_targets)
{
assert(sys && sys->instance);
*render_targets = sys->instance->render_targets;
return sys->instance->num_render_targets;
}
void
vlc_vaapi_PicAttachContext(picture_t *pic)
{
assert(pic->p_sys != NULL);
assert(pic->context == NULL);
pic->p_sys->ctx.picref = pic;
pic->context = &pic->p_sys->ctx.s;
}
VASurfaceID
vlc_vaapi_PicGetSurface(picture_t *pic)
{
assert(pic->context);
return ((struct vaapi_pic_ctx *)pic->context)->surface;
}

37
modules/hw/vaapi/vlc_vaapi.h

@ -27,6 +27,10 @@
#include <va/va.h>
#include <vlc_common.h>
#include <vlc_fourcc.h>
#include <vlc_picture_pool.h>
/**************************
* VA instance management *
**************************/
@ -160,4 +164,37 @@ vlc_vaapi_RenderPicture(vlc_object_t *o, VADisplay dpy, VAContextID ctx,
int
vlc_vaapi_EndPicture(vlc_object_t *o, VADisplay dpy, VAContextID ctx);
/*****************
* VAAPI helpers *
*****************/
/* Creates a VAConfigID */
VAConfigID
vlc_vaapi_CreateConfigChecked(vlc_object_t *o, VADisplay dpy,
VAProfile i_profile, VAEntrypoint entrypoint,
int va_force_fourcc);
/* Create a pool backed by VASurfaceID. render_targets will destroyed once
* the pool and every pictures are released. */
picture_pool_t *
vlc_vaapi_PoolNew(vlc_object_t *o, VADisplay va_dpy,
unsigned count, VASurfaceID **render_targets,
const video_format_t *restrict fmt,
unsigned va_rt_format, int va_force_fourcc);
/* Get render targets from a pic_sys allocated by the vaapi pool (see
* vlc_vaapi_PoolNew()) */
unsigned
vlc_vaapi_PicSysGetRenderTargets(picture_sys_t *sys,
VASurfaceID **render_targets);
/* Attachs the VASurface to the picture context, the picture must be allocated
* by a vaapi pool (see vlc_vaapi_PoolNew()) */
void
vlc_vaapi_PicAttachContext(picture_t *pic);
/* Get the VASurfaceID attached to the pic */
VASurfaceID
vlc_vaapi_PicGetSurface(picture_t *pic);
#endif /* VLC_VAAPI_H */

Loading…
Cancel
Save