vlc | branch: master | Thomas Guillem <[email protected]> | Fri Jun 16 12:01:29 2017 +0200| [a520cc788015fc24389d4bf38c236910ff790616] | committer: Thomas Guillem
hw: vaapi: add pictures and pool helpers > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=a520cc788015fc24389d4bf38c236910ff790616 --- modules/hw/vaapi/vlc_vaapi.c | 330 +++++++++++++++++++++++++++++++++++++++++++ modules/hw/vaapi/vlc_vaapi.h | 37 +++++ 2 files changed, 367 insertions(+) diff --git a/modules/hw/vaapi/vlc_vaapi.c b/modules/hw/vaapi/vlc_vaapi.c index 89052998ea..04514eb852 100644 --- a/modules/hw/vaapi/vlc_vaapi.c +++ b/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; +} diff --git a/modules/hw/vaapi/vlc_vaapi.h b/modules/hw/vaapi/vlc_vaapi.h index 564057b833..51dbc69a6c 100644 --- a/modules/hw/vaapi/vlc_vaapi.h +++ b/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 */ _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
