X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fcodec%2Favcodec%2Fvideo.c;h=2e5ab368c4c51206df5f80f9090966b5741db5ff;hb=0f79a0a02de9aa8f7aa6f5d0d797df3250fd4d85;hp=8acbcaae892bf1ad289af1be2762b0f2fcb4e1f8;hpb=78d87996ccb92d1dc91c9987685f976ed3be08a6;p=vlc diff --git a/modules/codec/avcodec/video.c b/modules/codec/avcodec/video.c index 8acbcaae89..2e5ab368c4 100644 --- a/modules/codec/avcodec/video.c +++ b/modules/codec/avcodec/video.c @@ -33,10 +33,14 @@ #include #include /* BITMAPINFOHEADER */ #include +#include /* ffmpeg header */ #ifdef HAVE_LIBAVCODEC_AVCODEC_H # include +# ifdef HAVE_AVCODEC_VAAPI +# include +# endif #elif defined(HAVE_FFMPEG_AVCODEC_H) # include #else @@ -44,6 +48,7 @@ #endif #include "avcodec.h" +#include "vaapi.h" /***************************************************************************** * decoder_sys_t : decoder descriptor @@ -84,6 +89,9 @@ struct decoder_sys_t /* */ bool b_flush; + + /* VA API */ + vlc_va_t *p_va; }; /* FIXME (dummy palette for now) */ @@ -100,6 +108,11 @@ static int ffmpeg_ReGetFrameBuf( struct AVCodecContext *, AVFrame * ); static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *, AVFrame * ); static void ffmpeg_NextPts( decoder_t * ); +#ifdef HAVE_AVCODEC_VAAPI +static enum PixelFormat ffmpeg_GetFormat( AVCodecContext *, + const enum PixelFormat * ); +#endif + static uint32_t ffmpeg_CodecTag( vlc_fourcc_t fcc ) { uint8_t *p = (uint8_t*)&fcc; @@ -114,7 +127,7 @@ static uint32_t ffmpeg_CodecTag( vlc_fourcc_t fcc ) static inline picture_t *ffmpeg_NewPictBuf( decoder_t *p_dec, AVCodecContext *p_context ) { - picture_t *p_pic; + decoder_sys_t *p_sys = p_dec->p_sys; p_dec->fmt_out.video.i_width = p_context->width; p_dec->fmt_out.video.i_height = p_context->height; @@ -124,10 +137,12 @@ static inline picture_t *ffmpeg_NewPictBuf( decoder_t *p_dec, return NULL; /* invalid display size */ } - if( GetVlcChroma( &p_dec->fmt_out.video, p_context->pix_fmt ) != VLC_SUCCESS ) + if( !p_sys->p_va && GetVlcChroma( &p_dec->fmt_out.video, p_context->pix_fmt ) ) { - /* we are doomed, but not really, because most codecs set their pix_fmt much later */ - p_dec->fmt_out.i_codec = VLC_CODEC_I420; + /* we are doomed, but not really, because most codecs set their pix_fmt + * much later + * FIXME does it make sense here ? */ + p_dec->fmt_out.video.i_chroma = VLC_CODEC_I420; } p_dec->fmt_out.i_codec = p_dec->fmt_out.video.i_chroma; @@ -165,9 +180,7 @@ static inline picture_t *ffmpeg_NewPictBuf( decoder_t *p_dec, p_dec->fmt_out.video.i_frame_rate_base = p_context->time_base.num; } - p_pic = decoder_NewPicture( p_dec ); - - return p_pic; + return decoder_NewPicture( p_dec ); } /***************************************************************************** @@ -192,6 +205,7 @@ int InitVideoDec( decoder_t *p_dec, AVCodecContext *p_context, p_sys->psz_namecodec = psz_namecodec; p_sys->p_ff_pic = avcodec_alloc_frame(); p_sys->b_delayed_open = true; + p_sys->p_va = NULL; /* ***** Fill p_context with init values ***** */ p_sys->p_context->codec_tag = ffmpeg_CodecTag( p_dec->fmt_in.i_original_fourcc ?: p_dec->fmt_in.i_codec ); @@ -318,6 +332,11 @@ int InitVideoDec( decoder_t *p_dec, AVCodecContext *p_context, p_sys->p_context->release_buffer = ffmpeg_ReleaseFrameBuf; p_sys->p_context->opaque = p_dec; +#ifdef HAVE_AVCODEC_VAAPI + if( var_CreateGetBool( p_dec, "ffmpeg-hw" ) ) + p_sys->p_context->get_format = ffmpeg_GetFormat; +#endif + /* ***** misc init ***** */ p_sys->input_pts = p_sys->input_dts = 0; p_sys->i_pts = 0; @@ -330,6 +349,7 @@ int InitVideoDec( decoder_t *p_dec, AVCodecContext *p_context, p_sys->p_buffer_orig = p_sys->p_buffer = malloc( p_sys->i_buffer_orig ); if( !p_sys->p_buffer_orig ) { + av_free( p_sys->p_ff_pic ); free( p_sys ); return VLC_ENOMEM; } @@ -380,6 +400,7 @@ int InitVideoDec( decoder_t *p_dec, AVCodecContext *p_context, if( ffmpeg_OpenCodec( p_dec ) < 0 ) { msg_Err( p_dec, "cannot open codec (%s)", p_sys->psz_namecodec ); + av_free( p_sys->p_ff_pic ); free( p_sys->p_buffer_orig ); free( p_sys ); return VLC_EGENERIC; @@ -618,7 +639,7 @@ picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block ) p_sys->i_late_frames = 0; } - if( !b_drawpicture || !p_sys->p_ff_pic->linesize[0] ) + if( !b_drawpicture || ( !p_sys->p_va && !p_sys->p_ff_pic->linesize[0] ) ) { /* Do not display the picture */ p_pic = (picture_t *)p_sys->p_ff_pic->opaque; @@ -731,8 +752,13 @@ void EndVideoDec( decoder_t *p_dec ) { decoder_sys_t *p_sys = p_dec->p_sys; + avcodec_flush_buffers( p_sys->p_context ); + if( p_sys->p_ff_pic ) av_free( p_sys->p_ff_pic ); free( p_sys->p_buffer_orig ); + + if( p_sys->p_va ) + VaDelete( p_sys->p_va ); } /***************************************************************************** @@ -819,7 +845,7 @@ static int ffmpeg_OpenCodec( decoder_t *p_dec ) } p_sys->p_context->width = p_dec->fmt_in.video.i_width; p_sys->p_context->height = p_dec->fmt_in.video.i_height; -#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(52, 0, 0) p_sys->p_context->bits_per_sample = p_dec->fmt_in.video.i_bits_per_pixel; #else p_sys->p_context->bits_per_coded_sample = p_dec->fmt_in.video.i_bits_per_pixel; @@ -835,6 +861,14 @@ static int ffmpeg_OpenCodec( decoder_t *p_dec ) p_sys->b_delayed_open = false; + if( p_sys->p_va ) + { + char psz_version[128]; + + VaVersion( p_sys->p_va, psz_version, sizeof(psz_version) ); + msg_Info( p_dec, "Using VA API version %s for hardware decoding.", psz_version ); + } + return VLC_SUCCESS; } /***************************************************************************** @@ -846,7 +880,11 @@ static void ffmpeg_CopyPicture( decoder_t *p_dec, { decoder_sys_t *p_sys = p_dec->p_sys; - if( TestFfmpegChroma( p_sys->p_context->pix_fmt, -1 ) == VLC_SUCCESS ) + if( p_sys->p_va ) + { + VaExtract( p_sys->p_va, p_pic, p_ff_pic ); + } + else if( TestFfmpegChroma( p_sys->p_context->pix_fmt, -1 ) == VLC_SUCCESS ) { int i_plane, i_size, i_line; uint8_t *p_dst, *p_src; @@ -896,11 +934,38 @@ static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context, ffmpeg_SetFrameBufferPts( p_dec, p_ff_pic ); /* */ - p_ff_pic->opaque = 0; + p_ff_pic->opaque = NULL; + + if( p_sys->p_va ) + { +#ifdef HAVE_AVCODEC_VAAPI + /* hwaccel_context is not present in old fffmpeg version */ + if( VaSetup( p_sys->p_va, + &p_sys->p_context->hwaccel_context, &p_dec->fmt_out.video.i_chroma, + p_sys->p_context->width, p_sys->p_context->height ) ) + { + msg_Err( p_dec, "VaSetup failed" ); + return -1; + } +#else + assert(0); +#endif + + /* */ + p_ff_pic->type = FF_BUFFER_TYPE_USER; + /* FIXME what is that, should give good value */ + p_ff_pic->age = 256*256*256*64; // FIXME FIXME from ffmpeg - /* Not much to do in indirect rendering mode */ - if( !p_sys->b_direct_rendering ) + if( VaGrabSurface( p_sys->p_va, p_ff_pic ) ) + { + msg_Err( p_dec, "VaGrabSurface failed" ); + return -1; + } + return 0; + } + else if( !p_sys->b_direct_rendering ) { + /* Not much to do in indirect rendering mode */ return avcodec_default_get_buffer( p_context, p_ff_pic ); } @@ -916,21 +981,16 @@ static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context, /* We only pad picture up to 16 */ PAD(p_sys->p_context->width,16) < i_width || PAD(p_sys->p_context->height,16) < i_height || p_context->pix_fmt == PIX_FMT_PAL8 ) - { - msg_Dbg( p_dec, "disabling direct rendering" ); - p_sys->b_direct_rendering = false; return avcodec_default_get_buffer( p_context, p_ff_pic ); - } + p_dec->fmt_out.i_codec = p_dec->fmt_out.video.i_chroma; /* Get a new picture */ //p_sys->p_vout->render.b_allow_modify_pics = 0; p_pic = ffmpeg_NewPictBuf( p_dec, p_sys->p_context ); if( !p_pic ) - { - p_sys->b_direct_rendering = false; return avcodec_default_get_buffer( p_context, p_ff_pic ); - } + p_sys->p_context->draw_horiz_band = NULL; p_ff_pic->opaque = (void*)p_pic; @@ -1009,20 +1069,30 @@ static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context, AVFrame *p_ff_pic ) { decoder_t *p_dec = (decoder_t *)p_context->opaque; + decoder_sys_t *p_sys = p_dec->p_sys; - if( !p_ff_pic->opaque ) + if( p_sys->p_va ) + { + VaUngrabSurface( p_sys->p_va, p_ff_pic ); + + /* */ + for( int i = 0; i < 4; i++ ) + p_ff_pic->data[i] = NULL; + } + else if( !p_ff_pic->opaque ) { avcodec_default_release_buffer( p_context, p_ff_pic ); - return; } + else + { + picture_t *p_pic = (picture_t*)p_ff_pic->opaque; - picture_t *p_pic = (picture_t*)p_ff_pic->opaque; - decoder_UnlinkPicture( p_dec, p_pic ); + decoder_UnlinkPicture( p_dec, p_pic ); - p_ff_pic->data[0] = NULL; - p_ff_pic->data[1] = NULL; - p_ff_pic->data[2] = NULL; - p_ff_pic->data[3] = NULL; + /* */ + for( int i = 0; i < 4; i++ ) + p_ff_pic->data[i] = NULL; + } } static void ffmpeg_NextPts( decoder_t *p_dec ) @@ -1043,9 +1113,69 @@ static void ffmpeg_NextPts( decoder_t *p_dec ) } else if( p_sys->p_context->time_base.den > 0 ) { +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52,20,0) + int i_tick = p_sys->p_context->ticks_per_frame; + if( i_tick <= 0 ) + i_tick = 1; +#else + int i_tick = 1; +#endif + p_sys->i_pts += INT64_C(1000000) * (2 + p_sys->p_ff_pic->repeat_pict) * - p_sys->p_context->time_base.num / + i_tick * p_sys->p_context->time_base.num / (2 * p_sys->p_context->time_base.den); } } + +#ifdef HAVE_AVCODEC_VAAPI +static enum PixelFormat ffmpeg_GetFormat( AVCodecContext *p_codec, + const enum PixelFormat *pi_fmt ) +{ + decoder_t *p_dec = p_codec->opaque; + decoder_sys_t *p_sys = p_dec->p_sys; + + if( p_sys->p_va ) + { + VaDelete( p_sys->p_va ); + p_sys->p_va = NULL; + } + + /* Try too look for a supported hw acceleration */ + for( int i = 0; pi_fmt[i] != PIX_FMT_NONE; i++ ) + { + static const char *ppsz_name[PIX_FMT_NB] = { + [PIX_FMT_VDPAU_H264] = "PIX_FMT_VDPAU_H264", + [PIX_FMT_VAAPI_IDCT] = "PIX_FMT_VAAPI_IDCT", + [PIX_FMT_VAAPI_VLD] = "PIX_FMT_VAAPI_VLD", + [PIX_FMT_VAAPI_MOCO] = "PIX_FMT_VAAPI_MOCO", + [PIX_FMT_YUYV422] = "PIX_FMT_YUYV422", + [PIX_FMT_YUV420P] = "PIX_FMT_YUV420P", + }; + msg_Dbg( p_dec, "Available decoder output format %d (%s)", pi_fmt[i], ppsz_name[pi_fmt[i]] ?: "Unknown" ); + + /* Only VLD supported */ + if( pi_fmt[i] == PIX_FMT_VAAPI_VLD ) + { + msg_Dbg( p_dec, "Trying VA API" ); + p_sys->p_va = VaNew( p_sys->i_codec_id ); + if( p_sys->p_va ) + { + /* FIXME this will disabled direct rendering + * even if a new pixel format is renegociated + * + * FIXME Try to call VaSetup when possible + * to detect errors when possible (later is too late) */ + p_sys->b_direct_rendering = false; + p_sys->p_context->draw_horiz_band = NULL; + return pi_fmt[i]; + } + msg_Warn( p_dec, "Failed to open VA API" ); + } + } + + /* Fallback to default behaviour */ + return avcodec_default_get_format( p_codec, pi_fmt ); +} +#endif +