#endif
#include <vlc_common.h>
-#include <vlc_vout.h>
+#include <vlc_fourcc.h>
#include <assert.h>
#ifdef HAVE_LIBAVCODEC_AVCODEC_H
# include <libavcodec/avcodec.h>
-# ifdef HAVE_AVCODEC_VAAPI
-# include <libavcodec/vaapi.h>
-# endif
-#elif defined(HAVE_FFMPEG_AVCODEC_H)
-# include <ffmpeg/avcodec.h>
#else
# include <avcodec.h>
#endif
#include "avcodec.h"
#include "va.h"
+#include "copy.h"
#ifdef HAVE_AVCODEC_VAAPI
+#include <vlc_xlib.h>
+
+#include <libavcodec/vaapi.h>
+
#include <X11/Xlib.h>
#include <va/va_x11.h>
-
typedef struct
{
VASurfaceID i_id;
vlc_va_surface_t *p_surface;
VAImage image;
+ copy_cache_t image_cache;
} vlc_va_vaapi_t;
/* */
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 */
p_va->p_display_x11 = XOpenDisplay(NULL);
if( vaCreateConfig( p_va->p_display,
i_profile, VAEntrypointVLD, &attrib, 1, &p_va->i_config_id ) )
{
- p_va->i_config_id = 0;
+ p_va->i_config_id = VA_INVALID_ID;
goto error;
}
static void DestroySurfaces( vlc_va_vaapi_t *p_va )
{
- if( p_va->image.image_id )
+ if( p_va->image.image_id != VA_INVALID_ID )
+ {
+ CopyCleanCache( &p_va->image_cache );
vaDestroyImage( p_va->p_display, p_va->image.image_id );
+ }
- if( p_va->i_context_id )
+ if( p_va->i_context_id != VA_INVALID_ID )
vaDestroyContext( p_va->p_display, p_va->i_context_id );
for( int i = 0; i < p_va->i_surface_count && p_va->p_surface; i++ )
free( p_va->p_surface );
/* */
- p_va->image.image_id = 0;
- p_va->i_context_id = 0;
+ 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;
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_ID;
+ p_va->i_context_id = VA_INVALID_ID;
/* Create surfaces */
VASurfaceID pi_surface_id[p_va->i_surface_count];
i_width, i_height, VA_PROGRESSIVE,
pi_surface_id, p_va->i_surface_count, &p_va->i_context_id ) )
{
- p_va->i_context_id = 0;
+ p_va->i_context_id = VA_INVALID_ID;
goto error;
}
- /* Find a supported image chroma */
+ /* Find and create a supported image chroma */
int i_fmt_count = vaMaxNumImageFormats( p_va->p_display );
VAImageFormat *p_fmt = calloc( i_fmt_count, sizeof(*p_fmt) );
if( !p_fmt )
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( 'I', '4', '2', '0' ) ||
+ p_fmt[i].fourcc == VA_FOURCC( 'N', 'V', '1', '2' ) )
{
- i_chroma = VLC_FOURCC( 'I', '4', '2', '0' );
+ if( vaCreateImage( p_va->p_display, &p_fmt[i], i_width, i_height, &p_va->image ) )
+ {
+ p_va->image.image_id = VA_INVALID_ID;
+ continue;
+ }
+ /* Validate that vaGetImage works with this format */
+ if( vaGetImage( p_va->p_display, pi_surface_id[0],
+ 0, 0, i_width, i_height,
+ p_va->image.image_id) )
+ {
+ vaDestroyImage( p_va->p_display, p_va->image.image_id );
+ p_va->image.image_id = VA_INVALID_ID;
+ continue;
+ }
+
+ i_chroma = VLC_CODEC_YV12;
fmt = p_fmt[i];
+ break;
}
- /* TODO: It seems that these may also be available (but not
- * with my setup):
- * VA_FOURCC( 'N', 'V', '1', '2')
- * VA_FOURCC( 'U', 'Y', 'V', 'Y')
- * VA_FOURCC( 'Y', 'U', 'Y', 'V')
- */
}
free( p_fmt );
if( !i_chroma )
goto error;
*pi_chroma = i_chroma;
- /* Create an image for surface extraction */
- if( vaCreateImage( p_va->p_display, &fmt, i_width, i_height, &p_va->image ) )
- {
- p_va->image.image_id = 0;
- goto error;
- }
+ CopyInitCache( &p_va->image_cache, i_width );
/* Setup the ffmpeg hardware context */
*pp_hw_ctx = &p_va->hw_ctx;
{
vlc_va_vaapi_t *p_va = vlc_va_vaapi_Get(p_external);
+ if( !p_va->image_cache.buffer )
+ return VLC_EGENERIC;
+
VASurfaceID i_surface_id = (VASurfaceID)(uintptr_t)p_ff->data[3];
#if VA_CHECK_VERSION(0,31,0)
if( vaMapBuffer( p_va->p_display, p_va->image.buf, &p_base ) )
return VLC_EGENERIC;
- for( int i_plane = 0; i_plane < p_picture->i_planes; i_plane++ )
+ const uint32_t i_fourcc = p_va->image.format.fourcc;
+ if( i_fourcc == VA_FOURCC('Y','V','1','2') ||
+ i_fourcc == VA_FOURCC('I','4','2','0') )
{
- const int i_src_plane = ((p_va->image.format.fourcc == VA_FOURCC('Y','V','1','2' )) && i_plane != 0) ? (3 - i_plane) : i_plane;
- const uint8_t *p_src = (uint8_t*)p_base + p_va->image.offsets[i_src_plane];
- const int i_src_stride = p_va->image.pitches[i_src_plane];
-
- uint8_t *p_dst = p_picture->p[i_plane].p_pixels;
- const int i_dst_stride = p_picture->p[i_plane].i_pitch;
+ bool b_swap_uv = i_fourcc == VA_FOURCC('I','4','2','0');
+ uint8_t *pp_plane[3];
+ size_t pi_pitch[3];
- if( i_src_stride != i_dst_stride )
+ for( int i = 0; i < 3; i++ )
{
- for( int i = 0; i < p_picture->p[i_plane].i_visible_lines; i++ )
- {
- vlc_memcpy( p_dst, p_src, __MIN( i_src_stride, i_dst_stride ) );
- p_src += i_src_stride;
- p_dst += i_dst_stride;
- }
+ const int i_src_plane = (b_swap_uv && i != 0) ? (3 - i) : i;
+ pp_plane[i] = (uint8_t*)p_base + p_va->image.offsets[i_src_plane];
+ pi_pitch[i] = p_va->image.pitches[i_src_plane];
}
- else
+ CopyFromYv12( p_picture, pp_plane, pi_pitch,
+ p_va->i_surface_width,
+ p_va->i_surface_height,
+ &p_va->image_cache );
+ }
+ else
+ {
+ assert( i_fourcc == VA_FOURCC('N','V','1','2') );
+ uint8_t *pp_plane[2];
+ size_t pi_pitch[2];
+
+ for( int i = 0; i < 2; i++ )
{
- vlc_memcpy( p_dst, p_src, p_picture->p[i_plane].i_visible_lines * i_src_stride );
+ pp_plane[i] = (uint8_t*)p_base + p_va->image.offsets[i];
+ pi_pitch[i] = p_va->image.pitches[i];
}
+ CopyFromNv12( p_picture, pp_plane, pi_pitch,
+ p_va->i_surface_width,
+ p_va->i_surface_height,
+ &p_va->image_cache );
}
if( vaUnmapBuffer( p_va->p_display, p_va->image.buf ) )
if( p_va->i_surface_width || p_va->i_surface_height )
DestroySurfaces( p_va );
- if( p_va->i_config_id )
+ if( p_va->i_config_id != VA_INVALID_ID )
vaDestroyConfig( p_va->p_display, p_va->i_config_id );
if( p_va->p_display )
vaTerminate( p_va->p_display );
}
/* */
-vlc_va_t *vlc_va_NewVaapi( int i_codec_id )
+vlc_va_t *vlc_va_NewVaapi( vlc_object_t *obj, int i_codec_id )
{
+ if( !vlc_xlib_init( obj ) )
+ return NULL;
+
vlc_va_vaapi_t *p_va = calloc( 1, sizeof(*p_va) );
if( !p_va )
return NULL;
return &p_va->va;
}
#else
-vlc_va_t *vlc_va_NewVaapi( int i_codec_id )
+vlc_va_t *vlc_va_NewVaapi( vlc_object_t *obj, int i_codec_id )
{
+ VLC_UNUSED( obj );
VLC_UNUSED( i_codec_id );
return NULL;
}