X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fcodec%2Favcodec%2Fvaapi.c;h=710fddd1d1a5898c07142b579fb05e650b1cf983;hb=066e381ff4047e994ad2335d55e5cce33c5c90a1;hp=cb2a39a266f282e00c5463e79476caf67b6666f4;hpb=c4ef9658d0d33dcb42f811ae1261ff8fe2eda878;p=vlc diff --git a/modules/codec/avcodec/vaapi.c b/modules/codec/avcodec/vaapi.c index cb2a39a266..710fddd1d1 100644 --- a/modules/codec/avcodec/vaapi.c +++ b/modules/codec/avcodec/vaapi.c @@ -26,29 +26,28 @@ #endif #include -#include +#include #include #ifdef HAVE_LIBAVCODEC_AVCODEC_H # include -# ifdef HAVE_AVCODEC_VAAPI -# include -# endif -#elif defined(HAVE_FFMPEG_AVCODEC_H) -# include #else # include #endif #include "avcodec.h" #include "va.h" +#include "copy.h" #ifdef HAVE_AVCODEC_VAAPI +#include + +#include + #include #include - typedef struct { VASurfaceID i_id; @@ -84,6 +83,7 @@ typedef struct vlc_va_surface_t *p_surface; VAImage image; + copy_cache_t image_cache; } vlc_va_vaapi_t; @@ -128,6 +128,9 @@ 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 */ p_va->p_display_x11 = XOpenDisplay(NULL); @@ -155,7 +158,7 @@ static int Open( vlc_va_vaapi_t *p_va, int i_codec_id ) 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; } @@ -173,10 +176,13 @@ 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++ ) @@ -189,8 +195,8 @@ static void DestroySurfaces( vlc_va_vaapi_t *p_va ) 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; @@ -204,6 +210,8 @@ 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_ID; + p_va->i_context_id = VA_INVALID_ID; /* Create surfaces */ VASurfaceID pi_surface_id[p_va->i_surface_count]; @@ -229,11 +237,11 @@ static int CreateSurfaces( vlc_va_vaapi_t *p_va, void **pp_hw_ctx, vlc_fourcc_t 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 ) @@ -250,29 +258,35 @@ static int CreateSurfaces( vlc_va_vaapi_t *p_va, void **pp_hw_ctx, vlc_fourcc_t 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; @@ -320,6 +334,9 @@ 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; + VASurfaceID i_surface_id = (VASurfaceID)(uintptr_t)p_ff->data[3]; #if VA_CHECK_VERSION(0,31,0) @@ -342,28 +359,40 @@ static int Extract( vlc_va_t *p_external, picture_t *p_picture, AVFrame *p_ff ) 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 ) ) @@ -428,7 +457,7 @@ static void Close( vlc_va_vaapi_t *p_va ) 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 ); @@ -444,8 +473,11 @@ static void Delete( vlc_va_t *p_external ) } /* */ -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; @@ -465,8 +497,9 @@ vlc_va_t *vlc_va_NewVaapi( int i_codec_id ) 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; }