]> git.sesse.net Git - vlc/blobdiff - modules/codec/avcodec/vaapi.c
LGPL
[vlc] / modules / codec / avcodec / vaapi.c
index f57439cdfed0aadb12f5f96dea50b8a617217d45..40319ad1ca49d174151e3ae501a1e1f5a9fb2f9e 100644 (file)
@@ -1,52 +1,56 @@
 /*****************************************************************************
- * vaapi.c: VAAPI helpers for the ffmpeg decoder
+ * vaapi.c: VAAPI helpers for the libavcodec decoder
  *****************************************************************************
  * Copyright (C) 2009 Laurent Aimar
  * $Id$
  *
  * Authors: Laurent Aimar <fenrir_AT_ videolan _DOT_ org>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
 
+#include <assert.h>
+
 #include <vlc_common.h>
+#include <vlc_plugin.h>
 #include <vlc_fourcc.h>
-#include <assert.h>
+#include <vlc_xlib.h>
 
-#ifdef HAVE_LIBAVCODEC_AVCODEC_H
-#   include <libavcodec/avcodec.h>
-#elif defined(HAVE_FFMPEG_AVCODEC_H)
-#   include <ffmpeg/avcodec.h>
-#else
-#   include <avcodec.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"
 #include "copy.h"
 
-#ifdef HAVE_AVCODEC_VAAPI
+static int Create( vlc_va_t *, int, const es_format_t * );
+static void Delete( vlc_va_t * );
 
-#include <libavcodec/vaapi.h>
-
-#include <X11/Xlib.h>
-#include <va/va_x11.h>
+vlc_module_begin ()
+    set_description( N_("Video Acceleration (VA) API") )
+    set_capability( "hw decoder", 50 )
+    set_category( CAT_INPUT )
+    set_subcategory( SUBCAT_INPUT_VCODEC )
+    set_callbacks( Create, Delete )
+vlc_module_end ()
 
 typedef struct
 {
@@ -56,11 +60,8 @@ typedef struct
 
 } vlc_va_surface_t;
 
-typedef struct
+struct vlc_va_sys_t
 {
-    vlc_va_t     va;
-
-    /* */
     Display      *p_display_x11;
     VADisplay     p_display;
 
@@ -85,17 +86,18 @@ typedef struct
     VAImage      image;
     copy_cache_t image_cache;
 
-} vlc_va_vaapi_t;
-
-static vlc_va_vaapi_t *vlc_va_vaapi_Get( void *p_va )
-{
-    return p_va;
-}
+};
 
 /* */
-static int Open( vlc_va_vaapi_t *p_va, int i_codec_id )
+static int Open( vlc_va_t *p_external, int i_codec_id )
 {
-    VAProfile i_profile;
+    vlc_va_sys_t *p_va = calloc( 1, sizeof(*p_va) );
+    if ( unlikely(p_va == NULL) )
+       return VLC_ENOMEM;
+
+    VAProfile i_profile, *p_profiles_list;
+    bool b_supported_profile = false;
+    int i_profiles_nb = 0;
     int i_surface_count;
 
     /* */
@@ -127,24 +129,55 @@ static int Open( vlc_va_vaapi_t *p_va, int i_codec_id )
     }
 
     /* */
-    memset( p_va, 0, sizeof(*p_va) );
     p_va->i_config_id  = VA_INVALID_ID;
     p_va->i_context_id = VA_INVALID_ID;
+    p_va->image.image_id = VA_INVALID_ID;
 
     /* Create a VA display */
-    if( !XInitThreads() )
-        return VLC_EGENERIC;
-
     p_va->p_display_x11 = XOpenDisplay(NULL);
     if( !p_va->p_display_x11 )
+    {
+        msg_Err( p_external, "Could not connect to X server" );
         goto error;
+    }
 
     p_va->p_display = vaGetDisplay( p_va->p_display_x11 );
     if( !p_va->p_display )
+    {
+        msg_Err( p_external, "Could not get a VAAPI device" );
         goto error;
+    }
 
     if( vaInitialize( p_va->p_display, &p_va->i_version_major, &p_va->i_version_minor ) )
+    {
+        msg_Err( p_external, "Failed to initialize the VAAPI device" );
         goto error;
+    }
+
+    /* Check if the selected profile is supported */
+    i_profiles_nb = vaMaxNumProfiles( p_va->p_display );
+    p_profiles_list = calloc( i_profiles_nb, sizeof( VAProfile ) );
+    if( !p_profiles_list )
+        goto error;
+
+    VAStatus i_status = vaQueryConfigProfiles( p_va->p_display, p_profiles_list, &i_profiles_nb );
+    if ( i_status == VA_STATUS_SUCCESS )
+    {
+        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( p_external, "Codec and profile not supported by the hardware" );
+        goto error;
+    }
 
     /* Create a VA configuration */
     VAConfigAttrib attrib;
@@ -166,19 +199,20 @@ static int Open( vlc_va_vaapi_t *p_va, int i_codec_id )
 
     p_va->i_surface_count = i_surface_count;
 
-    if( asprintf( &p_va->va.description, "VA API version %d.%d",
+    if( asprintf( &p_external->description, "VA API version %d.%d",
                   p_va->i_version_major, p_va->i_version_minor ) < 0 )
-        p_va->va.description = NULL;
+        p_external->description = NULL;
 
+    p_external->sys = p_va;
     return VLC_SUCCESS;
 
 error:
     return VLC_EGENERIC;
 }
 
-static void DestroySurfaces( vlc_va_vaapi_t *p_va )
+static void DestroySurfaces( vlc_va_sys_t *p_va )
 {
-    if( p_va->image.image_id != VA_INVALID_SURFACE )
+    if( p_va->image.image_id != VA_INVALID_ID )
     {
         CopyCleanCache( &p_va->image_cache );
         vaDestroyImage( p_va->p_display, p_va->image.image_id );
@@ -197,13 +231,13 @@ static void DestroySurfaces( vlc_va_vaapi_t *p_va )
     free( p_va->p_surface );
 
     /* */
-    p_va->image.image_id = VA_INVALID_SURFACE;
+    p_va->image.image_id = VA_INVALID_ID;
     p_va->i_context_id = VA_INVALID_ID;
     p_va->p_surface = NULL;
     p_va->i_surface_width = 0;
     p_va->i_surface_height = 0;
 }
-static int CreateSurfaces( vlc_va_vaapi_t *p_va, void **pp_hw_ctx, vlc_fourcc_t *pi_chroma,
+static int CreateSurfaces( vlc_va_sys_t *p_va, void **pp_hw_ctx, vlc_fourcc_t *pi_chroma,
                            int i_width, int i_height )
 {
     assert( i_width > 0 && i_height > 0 );
@@ -212,7 +246,7 @@ static int CreateSurfaces( vlc_va_vaapi_t *p_va, void **pp_hw_ctx, vlc_fourcc_t
     p_va->p_surface = calloc( p_va->i_surface_count, sizeof(*p_va->p_surface) );
     if( !p_va->p_surface )
         return VLC_EGENERIC;
-    p_va->image.image_id = VA_INVALID_SURFACE;
+    p_va->image.image_id = VA_INVALID_ID;
     p_va->i_context_id   = VA_INVALID_ID;
 
     /* Create surfaces */
@@ -265,7 +299,7 @@ static int CreateSurfaces( vlc_va_vaapi_t *p_va, void **pp_hw_ctx, vlc_fourcc_t
         {
             if( vaCreateImage(  p_va->p_display, &p_fmt[i], i_width, i_height, &p_va->image ) )
             {
-                p_va->image.image_id = VA_INVALID_SURFACE;
+                p_va->image.image_id = VA_INVALID_ID;
                 continue;
             }
             /* Validate that vaGetImage works with this format */
@@ -274,7 +308,7 @@ static int CreateSurfaces( vlc_va_vaapi_t *p_va, void **pp_hw_ctx, vlc_fourcc_t
                             p_va->image.image_id) )
             {
                 vaDestroyImage( p_va->p_display, p_va->image.image_id );
-                p_va->image.image_id = VA_INVALID_SURFACE;
+                p_va->image.image_id = VA_INVALID_ID;
                 continue;
             }
 
@@ -288,7 +322,8 @@ static int CreateSurfaces( vlc_va_vaapi_t *p_va, void **pp_hw_ctx, vlc_fourcc_t
         goto error;
     *pi_chroma = i_chroma;
 
-    CopyInitCache( &p_va->image_cache, i_width );
+    if( unlikely(CopyInitCache( &p_va->image_cache, i_width )) )
+        goto error;
 
     /* Setup the ffmpeg hardware context */
     *pp_hw_ctx = &p_va->hw_ctx;
@@ -312,7 +347,7 @@ error:
 static int Setup( vlc_va_t *p_external, void **pp_hw_ctx, vlc_fourcc_t *pi_chroma,
                   int i_width, int i_height )
 {
-    vlc_va_vaapi_t *p_va = vlc_va_vaapi_Get(p_external);
+    vlc_va_sys_t *p_va = p_external->sys;
 
     if( p_va->i_surface_width == i_width &&
         p_va->i_surface_height == i_height )
@@ -334,10 +369,7 @@ static int Setup( vlc_va_t *p_external, void **pp_hw_ctx, vlc_fourcc_t *pi_chrom
 }
 static int Extract( vlc_va_t *p_external, picture_t *p_picture, AVFrame *p_ff )
 {
-    vlc_va_vaapi_t *p_va = vlc_va_vaapi_Get(p_external);
-
-    if( !p_va->image_cache.buffer )
-        return VLC_EGENERIC;
+    vlc_va_sys_t *p_va = p_external->sys;
 
     VASurfaceID i_surface_id = (VASurfaceID)(uintptr_t)p_ff->data[3];
 
@@ -404,7 +436,7 @@ static int Extract( vlc_va_t *p_external, picture_t *p_picture, AVFrame *p_ff )
 }
 static int Get( vlc_va_t *p_external, AVFrame *p_ff )
 {
-    vlc_va_vaapi_t *p_va = vlc_va_vaapi_Get(p_external);
+    vlc_va_sys_t *p_va = p_external->sys;
     int i_old;
     int i;
 
@@ -441,7 +473,7 @@ static int Get( vlc_va_t *p_external, AVFrame *p_ff )
 }
 static void Release( vlc_va_t *p_external, AVFrame *p_ff )
 {
-    vlc_va_vaapi_t *p_va = vlc_va_vaapi_Get(p_external);
+    vlc_va_sys_t *p_va = p_external->sys;
 
     VASurfaceID i_surface_id = (VASurfaceID)(uintptr_t)p_ff->data[3];
 
@@ -454,7 +486,7 @@ static void Release( vlc_va_t *p_external, AVFrame *p_ff )
     }
 }
 
-static void Close( vlc_va_vaapi_t *p_va )
+static void Close( vlc_va_sys_t *p_va )
 {
     if( p_va->i_surface_width || p_va->i_surface_height )
         DestroySurfaces( p_va );
@@ -466,46 +498,34 @@ static void Close( vlc_va_vaapi_t *p_va )
     if( p_va->p_display_x11 )
         XCloseDisplay( p_va->p_display_x11 );
 }
+
 static void Delete( vlc_va_t *p_external )
 {
-    vlc_va_vaapi_t *p_va = vlc_va_vaapi_Get(p_external);
+    vlc_va_sys_t *p_va = p_external->sys;
     Close( p_va );
-    free( p_va->va.description );
+    free( p_external->description );
     free( p_va );
 }
 
-/* */
-vlc_va_t *vlc_va_NewVaapi( int i_codec_id )
+static int Create( vlc_va_t *p_va, int i_codec_id, const es_format_t *fmt )
 {
-    bool fail;
-
-    vlc_global_lock( VLC_XLIB_MUTEX );
-    fail = !XInitThreads();
-    vlc_global_unlock( VLC_XLIB_MUTEX );
-    if( unlikely(fail) )
-        return NULL;
-
-    vlc_va_vaapi_t *p_va = calloc( 1, sizeof(*p_va) );
-    if( !p_va )
-        return NULL;
-    if( Open( p_va, i_codec_id ) )
+    if( !vlc_xlib_init( VLC_OBJECT(p_va) ) )
     {
-        free( p_va );
-        return NULL;
+        msg_Warn( p_va, "Ignoring VA API" );
+        return VLC_EGENERIC;
     }
 
-    /* */
-    p_va->va.setup = Setup;
-    p_va->va.get = Get;
-    p_va->va.release = Release;
-    p_va->va.extract = Extract;
-    p_va->va.close = Delete;
-    return &p_va->va;
-}
-#else
-vlc_va_t *vlc_va_NewVaapi( int i_codec_id )
-{
-    VLC_UNUSED( i_codec_id );
-    return NULL;
+    (void) fmt;
+
+    int err = Open( p_va, i_codec_id );
+    if( err )
+        return err;
+
+    /* Only VLD supported */
+    p_va->pix_fmt = PIX_FMT_VAAPI_VLD;
+    p_va->setup = Setup;
+    p_va->get = Get;
+    p_va->release = Release;
+    p_va->extract = Extract;
+    return VLC_SUCCESS;
 }
-#endif