[vlc-commits] avcodec: vaapi: use vlc_vaapi helpers

Thomas Guillem git at videolan.org
Fri Jun 16 16:48:37 CEST 2017


vlc | branch: master | Thomas Guillem <thomas at gllm.fr> | 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;
 }
 



More information about the vlc-commits mailing list