]> git.sesse.net Git - vlc/blobdiff - modules/codec/avcodec/vaapi.c
avcodec: do not overwrite libavcodec internal AVCodec data
[vlc] / modules / codec / avcodec / vaapi.c
index c85e122d45d48a95ffa574564ce8d449709f0931..204e8dab1e3e0e218d4ccbb4803a9d202d7e36f9 100644 (file)
 #include <vlc_common.h>
 #include <vlc_plugin.h>
 #include <vlc_fourcc.h>
-#include <vlc_xlib.h>
 
+#ifdef VLC_VA_BACKEND_XLIB
+# include <vlc_xlib.h>
+# include <va/va_x11.h>
+#endif
+#ifdef VLC_VA_BACKEND_DRM
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+# include <vlc_fs.h>
+# include <va/va_drm.h>
+#endif
 #include <libavcodec/avcodec.h>
 #include <libavcodec/vaapi.h>
-#include <X11/Xlib.h>
-#include <va/va_x11.h>
 
 #include "avcodec.h"
 #include "va.h"
@@ -50,11 +58,16 @@ static int Create( vlc_va_t *, AVCodecContext *, const es_format_t * );
 static void Delete( vlc_va_t * );
 
 vlc_module_begin ()
-    set_description( N_("Video Acceleration (VA) API") )
+#if defined (VLC_VA_BACKEND_XLIB)
+    set_description( N_("VA-API video decoder via X11") )
+#elif defined (VLC_VA_BACKEND_DRM)
+    set_description( N_("VA-API video decoder via DRM") )
+#endif
     set_capability( "hw decoder", 0 )
     set_category( CAT_INPUT )
     set_subcategory( SUBCAT_INPUT_VCODEC )
     set_callbacks( Create, Delete )
+    add_shortcut( "vaapi" )
 vlc_module_end ()
 
 typedef struct
@@ -67,7 +80,12 @@ typedef struct
 
 struct vlc_va_sys_t
 {
-    Display      *p_display_x11;
+#ifdef VLC_VA_BACKEND_XLIB
+        Display  *p_display_x11;
+#endif
+#ifdef VLC_VA_BACKEND_DRM
+        int       drm_fd;
+#endif
     VADisplay     p_display;
 
     VAConfigID    i_config_id;
@@ -128,16 +146,17 @@ static int Open( vlc_va_t *va, int i_codec_id, int i_thread_count )
         i_surface_count = 16 + i_thread_count + 2;
         break;;
     default:
+        free( sys );
         return VLC_EGENERIC;
     }
 
     /* */
-    va->description = NULL;
     sys->i_config_id  = VA_INVALID_ID;
     sys->i_context_id = VA_INVALID_ID;
     sys->image.image_id = VA_INVALID_ID;
 
     /* Create a VA display */
+#ifdef VLC_VA_BACKEND_XLIB
     sys->p_display_x11 = XOpenDisplay(NULL);
     if( !sys->p_display_x11 )
     {
@@ -146,6 +165,17 @@ static int Open( vlc_va_t *va, int i_codec_id, int i_thread_count )
     }
 
     sys->p_display = vaGetDisplay( sys->p_display_x11 );
+#endif
+#ifdef VLC_VA_BACKEND_DRM
+    sys->drm_fd = vlc_open("/dev/dri/card0", O_RDWR);
+    if( sys->drm_fd == -1 )
+    {
+        msg_Err( va, "Could not access rendering device: %m" );
+        goto error;
+    }
+
+    sys->p_display = vaGetDisplayDRM( sys->drm_fd );
+#endif
     if( !sys->p_display )
     {
         msg_Err( va, "Could not get a VAAPI device" );
@@ -160,9 +190,6 @@ static int Open( vlc_va_t *va, int i_codec_id, int i_thread_count )
         goto error;
     }
 
-    if( asprintf( &va->description, "VA API v%d.%d", major, minor ) < 0 )
-        va->description = NULL;
-
     /* Check if the selected profile is supported */
     i_profiles_nb = vaMaxNumProfiles( sys->p_display );
     p_profiles_list = calloc( i_profiles_nb, sizeof( VAProfile ) );
@@ -213,14 +240,20 @@ static int Open( vlc_va_t *va, int i_codec_id, int i_thread_count )
     vlc_mutex_init(&sys->lock);
 
     va->sys = sys;
+    va->description = vaQueryVendorString( sys->p_display );
     return VLC_SUCCESS;
 
 error:
-    free( va->description );
     if( sys->p_display != NULL )
         vaTerminate( sys->p_display );
+#ifdef VLC_VA_BACKEND_XLIB
     if( sys->p_display_x11 != NULL )
         XCloseDisplay( sys->p_display_x11 );
+#endif
+#ifdef VLC_VA_BACKEND_DRM
+    if( sys->drm_fd != -1 )
+        close( sys->drm_fd );
+#endif
     free( sys );
     return VLC_EGENERIC;
 }
@@ -312,19 +345,21 @@ static int CreateSurfaces( vlc_va_sys_t *sys, void **pp_hw_ctx, vlc_fourcc_t *pi
     }
 
     VAImage test_image;
+    vlc_fourcc_t  deriveImageFormat = 0;
     if(vaDeriveImage(sys->p_display, pi_surface_id[0], &test_image) == VA_STATUS_SUCCESS)
     {
         sys->b_supports_derive = true;
+        deriveImageFormat = test_image.format.fourcc;
         vaDestroyImage(sys->p_display, test_image.image_id);
     }
 
     vlc_fourcc_t  i_chroma = 0;
-    VAImageFormat fmt;
+    int nv12support = -1;
     for( int i = 0; i < i_fmt_count; i++ )
     {
-        if( p_fmt[i].fourcc == VA_FOURCC( 'Y', 'V', '1', '2' ) ||
-            p_fmt[i].fourcc == VA_FOURCC( 'I', '4', '2', '0' ) ||
-            p_fmt[i].fourcc == VA_FOURCC( 'N', 'V', '1', '2' ) )
+        if( p_fmt[i].fourcc == VA_FOURCC_YV12 ||
+            p_fmt[i].fourcc == VA_FOURCC_IYUV ||
+            p_fmt[i].fourcc == VA_FOURCC_NV12 )
         {
             if( vaCreateImage(  sys->p_display, &p_fmt[i], i_width, i_height, &sys->image ) )
             {
@@ -341,11 +376,34 @@ static int CreateSurfaces( vlc_va_sys_t *sys, void **pp_hw_ctx, vlc_fourcc_t *pi
                 continue;
             }
 
+            if( p_fmt[i].fourcc == VA_FOURCC_NV12 )
+            {
+                /* Mark NV12 as supported, but favor other formats first */
+                nv12support = i;
+                vaDestroyImage( sys->p_display, sys->image.image_id );
+                sys->image.image_id = VA_INVALID_ID;
+                continue;
+            }
             i_chroma = VLC_CODEC_YV12;
-            fmt = p_fmt[i];
             break;
         }
     }
+
+    if( !i_chroma && nv12support >= 0 )
+    {
+        /* only nv12 is supported, so use that format */
+        if( vaCreateImage(  sys->p_display, &p_fmt[nv12support], i_width, i_height, &sys->image ) )
+        {
+            sys->image.image_id = VA_INVALID_ID;
+        }
+        i_chroma = VLC_CODEC_YV12;
+    }
+    else if( sys->b_supports_derive && deriveImageFormat != sys->image.format.fourcc )
+    {
+        /* only use vaDerive if it's giving us a format we handle natively */
+        sys->b_supports_derive = false;
+    }
+
     free( p_fmt );
     if( !i_chroma )
         goto error;
@@ -434,10 +492,10 @@ static int Extract( vlc_va_t *va, picture_t *p_picture, void *opaque,
         return VLC_EGENERIC;
 
     const uint32_t i_fourcc = sys->image.format.fourcc;
-    if( i_fourcc == VA_FOURCC('Y','V','1','2') ||
-        i_fourcc == VA_FOURCC('I','4','2','0') )
+    if( i_fourcc == VA_FOURCC_YV12 ||
+        i_fourcc == VA_FOURCC_IYUV )
     {
-        bool b_swap_uv = i_fourcc == VA_FOURCC('I','4','2','0');
+        bool b_swap_uv = i_fourcc == VA_FOURCC_IYUV;
         uint8_t *pp_plane[3];
         size_t  pi_pitch[3];
 
@@ -454,7 +512,7 @@ static int Extract( vlc_va_t *va, picture_t *p_picture, void *opaque,
     }
     else
     {
-        assert( i_fourcc == VA_FOURCC('N','V','1','2') );
+        assert( i_fourcc == VA_FOURCC_NV12 );
         uint8_t *pp_plane[2];
         size_t  pi_pitch[2];
 
@@ -531,25 +589,31 @@ static void Close( vlc_va_sys_t *sys )
     if( sys->i_config_id != VA_INVALID_ID )
         vaDestroyConfig( sys->p_display, sys->i_config_id );
     vaTerminate( sys->p_display );
+#ifdef VLC_VA_BACKEND_XLIB
     XCloseDisplay( sys->p_display_x11 );
+#endif
+#ifdef VLC_VA_BACKEND_DRM
+    close( sys->drm_fd );
+#endif
 }
 
 static void Delete( vlc_va_t *va )
 {
     vlc_va_sys_t *sys = va->sys;
     Close( sys );
-    free( va->description );
     free( sys );
 }
 
 static int Create( vlc_va_t *p_va, AVCodecContext *ctx,
                    const es_format_t *fmt )
 {
+#ifdef VLC_VA_BACKEND_XLIB
     if( !vlc_xlib_init( VLC_OBJECT(p_va) ) )
     {
         msg_Warn( p_va, "Ignoring VA API" );
         return VLC_EGENERIC;
     }
+#endif
 
     (void) fmt;