vlc | branch: master | Thomas Guillem <[email protected]> | Thu Jun 15 17:56:25 2017 +0200| [f9b5400d73afdf84214221449d532997064b7e62] | committer: Thomas Guillem
avcodec: vaapi: use vlc_vaapi helpers This module will now always output opaque VLC_CODEC_VAAPI_420 pictures. For cpu rendering, we now use the vaapi chroma filter. Remove the Extract implementation. > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=f9b5400d73afdf84214221449d532997064b7e62 --- modules/codec/Makefile.am | 11 +- modules/codec/avcodec/va.c | 2 +- modules/codec/avcodec/vaapi.c | 375 +++++++++--------------------------------- 3 files changed, 84 insertions(+), 304 deletions(-) diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am index 14fc7f00b1..8c4e86f8a9 100644 --- a/modules/codec/Makefile.am +++ b/modules/codec/Makefile.am @@ -375,19 +375,18 @@ endif ### avcodec hardware acceleration ### libvaapi_drm_plugin_la_SOURCES = \ - video_chroma/copy.c video_chroma/copy.h \ - codec/avcodec/vaapi.c + codec/avcodec/vaapi.c hw/vaapi/vlc_vaapi.c hw/vaapi/vlc_vaapi.h libvaapi_drm_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -DVLC_VA_BACKEND_DRM libvaapi_drm_plugin_la_CFLAGS = $(AM_CFLAGS) \ $(LIBVA_DRM_CFLAGS) $(AVCODEC_CFLAGS) -libvaapi_drm_plugin_la_LIBADD = $(LIBVA_DRM_LIBS) +libvaapi_drm_plugin_la_LIBADD = $(LIBVA_DRM_LIBS) libvlc_vaapi_instance.la libvaapi_x11_plugin_la_SOURCES = \ - video_chroma/copy.c video_chroma/copy.h \ - codec/avcodec/vaapi.c + codec/avcodec/vaapi.c hw/vaapi/vlc_vaapi.c hw/vaapi/vlc_vaapi.h libvaapi_x11_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -DVLC_VA_BACKEND_XLIB libvaapi_x11_plugin_la_CFLAGS = $(AM_CFLAGS) \ $(LIBVA_X11_CFLAGS) $(X_CFLAGS) $(AVCODEC_CFLAGS) -libvaapi_x11_plugin_la_LIBADD = $(LIBVA_X11_LIBS) $(X_LIBS) $(X_PRE_LIBS) -lX11 +libvaapi_x11_plugin_la_LIBADD = $(LIBVA_X11_LIBS) $(X_LIBS) $(X_PRE_LIBS) \ + -lX11 libvlc_vaapi_instance.la if HAVE_AVCODEC_VAAPI if HAVE_VAAPI_DRM codec_LTLIBRARIES += libvaapi_drm_plugin.la diff --git a/modules/codec/avcodec/va.c b/modules/codec/avcodec/va.c index de10736013..1298f24e1e 100644 --- a/modules/codec/avcodec/va.c +++ b/modules/codec/avcodec/va.c @@ -38,7 +38,7 @@ vlc_fourcc_t vlc_va_GetChroma(enum PixelFormat hwfmt, enum PixelFormat swfmt) switch (hwfmt) { case AV_PIX_FMT_VAAPI_VLD: - return VLC_CODEC_YV12; + return VLC_CODEC_VAAPI_420; case AV_PIX_FMT_DXVA2_VLD: switch (swfmt) diff --git a/modules/codec/avcodec/vaapi.c b/modules/codec/avcodec/vaapi.c index c04821e100..2f0d045a05 100644 --- a/modules/codec/avcodec/vaapi.c +++ b/modules/codec/avcodec/vaapi.c @@ -1,6 +1,7 @@ /***************************************************************************** * vaapi.c: VAAPI helpers for the libavcodec decoder ***************************************************************************** + * Copyright (C) 2017 VLC authors and VideoLAN * Copyright (C) 2009-2010 Laurent Aimar * Copyright (C) 2012-2014 Rémi Denis-Courmont * @@ -31,6 +32,7 @@ #include <vlc_plugin.h> #include <vlc_fourcc.h> #include <vlc_picture.h> +#include <vlc_picture_pool.h> #ifdef VLC_VA_BACKEND_XLIB # include <vlc_xlib.h> @@ -48,35 +50,19 @@ #include "avcodec.h" #include "va.h" -#include "../../video_chroma/copy.h" - -#ifndef VA_SURFACE_ATTRIB_SETTABLE -#define vaCreateSurfaces(d, f, w, h, s, ns, a, na) \ - vaCreateSurfaces(d, w, h, f, ns, s) -#endif +#include "../../hw/vaapi/vlc_vaapi.h" struct vlc_va_sys_t { #ifdef VLC_VA_BACKEND_XLIB - Display *p_display_x11; + Display *p_display_x11; #endif #ifdef VLC_VA_BACKEND_DRM - int drm_fd; + int drm_fd; #endif struct vaapi_context hw_ctx; - /* */ - vlc_mutex_t lock; - int width; - int height; - VAImageFormat format; - - copy_cache_t image_cache; - - bool do_derive; - uint8_t count; - uint32_t available; - VASurfaceID surfaces[32]; + picture_pool_t *pool; }; static int GetVaProfile(AVCodecContext *ctx, VAProfile *va_profile, @@ -138,256 +124,91 @@ static int GetVaProfile(AVCodecContext *ctx, VAProfile *va_profile, return VLC_SUCCESS; } -static int Extract( vlc_va_t *va, picture_t *p_picture, uint8_t *data ) +static int Extract(vlc_va_t *va, picture_t *pic, uint8_t *data) { - vlc_va_sys_t *sys = va->sys; - VASurfaceID surface = (VASurfaceID)(uintptr_t)data; - VAImage image; - int ret = VLC_EGENERIC; - -#if VA_CHECK_VERSION(0,31,0) - if (vaSyncSurface(sys->hw_ctx.display, surface)) -#else - if (vaSyncSurface(sys->hw_ctx.display, sys->hw_ctx.context_id, surface)) -#endif - return VLC_EGENERIC; - - if (!sys->do_derive || vaDeriveImage(sys->hw_ctx.display, surface, &image)) - { /* Fallback if image derivation is not supported */ - if (vaCreateImage(sys->hw_ctx.display, &sys->format, sys->width, - sys->height, &image)) - return VLC_EGENERIC; - if (vaGetImage(sys->hw_ctx.display, surface, 0, 0, sys->width, - sys->height, image.image_id)) - goto error; - } - - void *p_base; - if (vaMapBuffer(sys->hw_ctx.display, image.buf, &p_base)) - goto error; - - const unsigned i_fourcc = sys->format.fourcc; - if( i_fourcc == VA_FOURCC_YV12 || - i_fourcc == VA_FOURCC_IYUV ) - { - bool b_swap_uv = i_fourcc == VA_FOURCC_IYUV; - uint8_t *pp_plane[3]; - size_t pi_pitch[3]; - - for( int i = 0; i < 3; i++ ) - { - const int i_src_plane = (b_swap_uv && i != 0) ? (3 - i) : i; - pp_plane[i] = (uint8_t*)p_base + image.offsets[i_src_plane]; - pi_pitch[i] = image.pitches[i_src_plane]; - } - CopyFromYv12ToYv12( p_picture, pp_plane, pi_pitch, - sys->height, &sys->image_cache ); - } - else - { - assert( i_fourcc == VA_FOURCC_NV12 ); - uint8_t *pp_plane[2]; - size_t pi_pitch[2]; - - for( int i = 0; i < 2; i++ ) - { - pp_plane[i] = (uint8_t*)p_base + image.offsets[i]; - pi_pitch[i] = image.pitches[i]; - } - CopyFromNv12ToYv12( p_picture, pp_plane, pi_pitch, - sys->height, &sys->image_cache ); - } - - vaUnmapBuffer(sys->hw_ctx.display, image.buf); - ret = VLC_SUCCESS; -error: - vaDestroyImage(sys->hw_ctx.display, image.image_id); - return ret; + (void) va; (void) pic; (void) data; + return VLC_SUCCESS; } -static int Get( vlc_va_t *va, picture_t *pic, uint8_t **data ) +static int Get(vlc_va_t *va, picture_t *pic, uint8_t **data) { vlc_va_sys_t *sys = va->sys; - unsigned i = sys->count; - - vlc_mutex_lock( &sys->lock ); - if (sys->available) - { - i = ctz(sys->available); - sys->available &= ~(1 << i); - } - vlc_mutex_unlock( &sys->lock ); - if( i >= sys->count ) - return VLC_ENOMEM; + picture_t *vapic = picture_pool_Wait(sys->pool); + if (vapic == NULL) + return VLC_EGENERIC; + vlc_vaapi_PicAttachContext(vapic); - VASurfaceID *surface = &sys->surfaces[i]; + pic->context = vapic->context->copy(vapic->context); + picture_Release(vapic); + if (pic->context == NULL) + return VLC_EGENERIC; - pic->context = surface; - *data = (void *)(uintptr_t)*surface; + *data = (void *)(uintptr_t)vlc_vaapi_PicGetSurface(pic); return VLC_SUCCESS; } -static void Release( void *opaque, uint8_t *data ) -{ - (void) data; - picture_t *pic = opaque; - VASurfaceID *surface = pic->context; - vlc_va_sys_t *sys = (void *)((((uintptr_t)surface) - - offsetof(vlc_va_sys_t, surfaces)) & ~(sizeof (sys->surfaces) - 1)); - unsigned i = surface - sys->surfaces; - - vlc_mutex_lock( &sys->lock ); - assert(((sys->available >> i) & 1) == 0); - sys->available |= 1 << i; - vlc_mutex_unlock( &sys->lock ); - - pic->context = NULL; - picture_Release(pic); -} - -static void Delete( vlc_va_t *va, AVCodecContext *avctx ) +static void Delete(vlc_va_t *va, AVCodecContext *avctx) { vlc_va_sys_t *sys = va->sys; + vlc_object_t *o = VLC_OBJECT(va); (void) avctx; - - vlc_mutex_destroy(&sys->lock); - CopyCleanCache(&sys->image_cache); - - vaDestroyContext(sys->hw_ctx.display, sys->hw_ctx.context_id); - vaDestroySurfaces(sys->hw_ctx.display, sys->surfaces, sys->count); - vaDestroyConfig(sys->hw_ctx.display, sys->hw_ctx.config_id); - vaTerminate(sys->hw_ctx.display); + picture_pool_Release(sys->pool); + vlc_vaapi_DestroyContext(o, sys->hw_ctx.display, sys->hw_ctx.context_id); + vlc_vaapi_DestroyConfig(o, sys->hw_ctx.display, sys->hw_ctx.config_id); + vlc_vaapi_ReleaseInstance(sys->hw_ctx.display); #ifdef VLC_VA_BACKEND_XLIB - XCloseDisplay( sys->p_display_x11 ); + XCloseDisplay(sys->p_display_x11); #endif #ifdef VLC_VA_BACKEND_DRM - vlc_close( sys->drm_fd ); + vlc_close(sys->drm_fd); #endif - free( sys ); -} - -/** Finds a supported image chroma */ -static int FindFormat(vlc_va_sys_t *sys) -{ - int count = vaMaxNumImageFormats(sys->hw_ctx.display); - - VAImageFormat *fmts = malloc(count * sizeof (*fmts)); - if (unlikely(fmts == NULL)) - return VLC_ENOMEM; - - if (vaQueryImageFormats(sys->hw_ctx.display, fmts, &count)) - { - free(fmts); - return VLC_EGENERIC; - } - - sys->format.fourcc = 0; - - for (int i = 0; i < count; i++) - { - unsigned fourcc = fmts[i].fourcc; - - if (fourcc != VA_FOURCC_YV12 && fourcc != VA_FOURCC_IYUV - && fourcc != VA_FOURCC_NV12) - continue; - - VAImage image; - - if (vaCreateImage(sys->hw_ctx.display, &fmts[i], sys->width, - sys->height, &image)) - continue; - - /* Validate that vaGetImage works with this format */ - int val = vaGetImage(sys->hw_ctx.display, sys->surfaces[0], 0, 0, - sys->width, sys->height, image.image_id); - - vaDestroyImage(sys->hw_ctx.display, image.image_id); - - if (val != VA_STATUS_SUCCESS) - continue; - - /* Mark NV12 as supported, but favor other formats first */ - sys->format = fmts[i]; - if (fourcc != VA_FOURCC_NV12) - break; - } - - free(fmts); - - if (sys->format.fourcc == 0) - return VLC_EGENERIC; /* None of the formats work */ - - VAImage image; - - /* Use vaDerive() iif it supports the best selected format */ - sys->do_derive = false; - - if (vaDeriveImage(sys->hw_ctx.display, sys->surfaces[0], - &image) == VA_STATUS_SUCCESS) - { - if (image.format.fourcc == sys->format.fourcc) - { - sys->do_derive = true; - sys->format = image.format; - } - vaDestroyImage(sys->hw_ctx.display, image.image_id); - } - - return VLC_SUCCESS; + free(sys); } -static int Create( vlc_va_t *va, AVCodecContext *ctx, enum PixelFormat pix_fmt, - const es_format_t *fmt, picture_sys_t *p_sys ) +static int Create(vlc_va_t *va, AVCodecContext *ctx, enum PixelFormat pix_fmt, + const es_format_t *fmt, picture_sys_t *p_sys) { - if( pix_fmt != AV_PIX_FMT_VAAPI_VLD ) + if (pix_fmt != AV_PIX_FMT_VAAPI_VLD) return VLC_EGENERIC; (void) fmt; (void) p_sys; + vlc_object_t *o = VLC_OBJECT(va); + #ifdef VLC_VA_BACKEND_XLIB - if( !vlc_xlib_init( VLC_OBJECT(va) ) ) + if (!vlc_xlib_init(o)) { - msg_Warn( va, "Ignoring VA-X11 API" ); + msg_Warn(va, "Ignoring VA-X11 API"); return VLC_EGENERIC; } #endif - VAProfile i_profile, *p_profiles_list; - bool b_supported_profile = false; - int i_profiles_nb = 0; + VAProfile i_profile; unsigned count; if (GetVaProfile(ctx, &i_profile, &count) != VLC_SUCCESS) return VLC_EGENERIC; vlc_va_sys_t *sys; - void *mem; - assert(popcount(sizeof (sys->surfaces)) == 1); - if (unlikely(posix_memalign(&mem, sizeof (sys->surfaces), sizeof (*sys)))) + sys = malloc(sizeof(vlc_va_sys_t)); + if (!sys) return VLC_ENOMEM; - - sys = mem; memset(sys, 0, sizeof (*sys)); /* */ sys->hw_ctx.display = NULL; sys->hw_ctx.config_id = VA_INVALID_ID; sys->hw_ctx.context_id = VA_INVALID_ID; - sys->width = ctx->coded_width; - sys->height = ctx->coded_height; - sys->count = count; - sys->available = (1 << sys->count) - 1; - assert(count < sizeof (sys->available) * CHAR_BIT); - assert(count * sizeof (sys->surfaces[0]) <= sizeof (sys->surfaces)); + sys->pool = NULL; /* Create a VA display */ #ifdef VLC_VA_BACKEND_XLIB sys->p_display_x11 = XOpenDisplay(NULL); - if( !sys->p_display_x11 ) + if (!sys->p_display_x11) { - msg_Err( va, "Could not connect to X server" ); + msg_Err(va, "Could not connect to X server"); goto error; } @@ -399,7 +220,8 @@ static int Create( vlc_va_t *va, AVCodecContext *ctx, enum PixelFormat pix_fmt, "/dev/dri/card0" }; - for (int i = 0; ARRAY_SIZE(drm_device_paths); i++) { + for (int i = 0; ARRAY_SIZE(drm_device_paths); i++) + { sys->drm_fd = vlc_open(drm_device_paths[i], O_RDWR); if (sys->drm_fd < 0) continue; @@ -414,117 +236,76 @@ static int Create( vlc_va_t *va, AVCodecContext *ctx, enum PixelFormat pix_fmt, #endif if (sys->hw_ctx.display == NULL) { - msg_Err( va, "Could not get a VAAPI device" ); + msg_Err(va, "Could not get a VAAPI device"); goto error; } - int major, minor; - if (vaInitialize(sys->hw_ctx.display, &major, &minor)) + if (vlc_vaapi_Initialize(o, sys->hw_ctx.display)) { - msg_Err( va, "Failed to initialize the VAAPI device" ); + sys->hw_ctx.display = NULL; goto error; } - /* Check if the selected profile is supported */ - i_profiles_nb = vaMaxNumProfiles(sys->hw_ctx.display); - p_profiles_list = calloc( i_profiles_nb, sizeof( VAProfile ) ); - if( !p_profiles_list ) - goto error; - - if (vaQueryConfigProfiles(sys->hw_ctx.display, p_profiles_list, - &i_profiles_nb) == VA_STATUS_SUCCESS) + if (vlc_vaapi_SetInstance(sys->hw_ctx.display)) { - for( int i = 0; i < i_profiles_nb; i++ ) - { - if ( p_profiles_list[i] == i_profile ) - { - b_supported_profile = true; - break; - } - } - } - free( p_profiles_list ); - if ( !b_supported_profile ) - { - msg_Dbg( va, "Codec and profile not supported by the hardware" ); + msg_Err(va, "VAAPI instance already in use"); goto error; } - /* Create a VA configuration */ - VAConfigAttrib attrib; - memset( &attrib, 0, sizeof(attrib) ); - attrib.type = VAConfigAttribRTFormat; - if (vaGetConfigAttributes(sys->hw_ctx.display, i_profile, VAEntrypointVLD, - &attrib, 1)) - goto error; - - /* Not sure what to do if not, I don't have a way to test */ - if( (attrib.value & VA_RT_FORMAT_YUV420) == 0 ) - goto error; - if (vaCreateConfig(sys->hw_ctx.display, i_profile, VAEntrypointVLD, - &attrib, 1, &sys->hw_ctx.config_id)) - { - sys->hw_ctx.config_id = VA_INVALID_ID; - goto error; - } + sys->hw_ctx.config_id = + vlc_vaapi_CreateConfigChecked(o, sys->hw_ctx.display, i_profile, + VAEntrypointVLD, 0); /* Create surfaces */ assert(ctx->coded_width > 0 && ctx->coded_height > 0); - if (vaCreateSurfaces(sys->hw_ctx.display, VA_RT_FORMAT_YUV420, - ctx->coded_width, ctx->coded_height, - sys->surfaces, sys->count, NULL, 0)) - { - goto error; - } - - /* Create a context */ - if (vaCreateContext(sys->hw_ctx.display, sys->hw_ctx.config_id, - ctx->coded_width, ctx->coded_height, VA_PROGRESSIVE, - sys->surfaces, sys->count, &sys->hw_ctx.context_id)) - { - sys->hw_ctx.context_id = VA_INVALID_ID; - vaDestroySurfaces(sys->hw_ctx.display, sys->surfaces, sys->count); - goto error; - } + video_format_t vfmt = { + .i_chroma = VLC_CODEC_VAAPI_420, + .i_width = ctx->coded_width, + .i_height = ctx->coded_height, + .i_visible_width = ctx->coded_width, + .i_visible_height = ctx->coded_height + }; + VASurfaceID *surfaces; + sys->pool = vlc_vaapi_PoolNew(o, sys->hw_ctx.display, count, + &surfaces, &vfmt, VA_RT_FORMAT_YUV420, 0); - if (FindFormat(sys)) + if (!sys->pool) goto error; - if (unlikely(CopyInitCache(&sys->image_cache, ctx->coded_width))) + /* Create a context */ + sys->hw_ctx.context_id = + vlc_vaapi_CreateContext(o, sys->hw_ctx.display, sys->hw_ctx.config_id, + ctx->coded_width, ctx->coded_height, + VA_PROGRESSIVE, surfaces, count); + if (sys->hw_ctx.context_id == VA_INVALID_ID) goto error; - vlc_mutex_init(&sys->lock); - - msg_Dbg(va, "using %s image format 0x%08x", - sys->do_derive ? "derive" : "get", sys->format.fourcc); - ctx->hwaccel_context = &sys->hw_ctx; va->sys = sys; va->description = vaQueryVendorString(sys->hw_ctx.display); va->get = Get; - va->release = Release; + va->release = NULL; va->extract = Extract; return VLC_SUCCESS; error: if (sys->hw_ctx.context_id != VA_INVALID_ID) - { - vaDestroyContext(sys->hw_ctx.display, sys->hw_ctx.context_id); - vaDestroySurfaces(sys->hw_ctx.display, sys->surfaces, sys->count); - } + vlc_vaapi_DestroyContext(o, sys->hw_ctx.display, sys->hw_ctx.context_id); + if (sys->pool != NULL) + picture_pool_Release(sys->pool); if (sys->hw_ctx.config_id != VA_INVALID_ID) - vaDestroyConfig(sys->hw_ctx.display, sys->hw_ctx.config_id); + vlc_vaapi_DestroyConfig(o, sys->hw_ctx.display, sys->hw_ctx.config_id); if (sys->hw_ctx.display != NULL) - vaTerminate(sys->hw_ctx.display); + vlc_vaapi_ReleaseInstance(sys->hw_ctx.display); #ifdef VLC_VA_BACKEND_XLIB - if( sys->p_display_x11 != NULL ) - XCloseDisplay( sys->p_display_x11 ); + if( sys->p_display_x11 != NULL) + XCloseDisplay(sys->p_display_x11); #endif #ifdef VLC_VA_BACKEND_DRM if( sys->drm_fd != -1 ) - vlc_close( sys->drm_fd ); + vlc_close(sys->drm_fd); #endif - free( sys ); + free(sys); return VLC_EGENERIC; } _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
