[vlc-devel] [PATCH] DxVA2: fix compatibility with avcodec frame multithreading

Steve Lhomme robux4 at videolabs.io
Tue Apr 7 10:32:16 CEST 2015


On Fri, Apr 3, 2015 at 4:48 PM, Steve Lhomme <robux4 at videolabs.io> wrote:
> There is a race condition when seeking in H264 :(
>
> Sometimes the Release() callback is called with a garbage `opaque`
> variable, which is supposed to be our vlc_va_surface_t object...

After seeking avcodec is still using buffers that we released when
reinitializing the VA. That results in display distortion and
sometimes freeing memory that has already been freed.

> On Fri, Apr 3, 2015 at 10:53 AM, Steve Lhomme <robux4 at videolabs.io> wrote:
>> Fixes #11693
>> Disable thread_safe_callbacks when we detect DXVA2 might be used
>>
>> --
>> the p_va of the decoder is not affected, a dummy p_va is used
>>
>> the decoding issues appeared on Intel HD Graphics 4000 hardware
>> ---
>>  modules/codec/avcodec/video.c | 75 ++++++++++++++++++++++++++++++++++---------
>>  1 file changed, 60 insertions(+), 15 deletions(-)
>>
>> diff --git a/modules/codec/avcodec/video.c b/modules/codec/avcodec/video.c
>> index 381fe62..c4488c0 100644
>> --- a/modules/codec/avcodec/video.c
>> +++ b/modules/codec/avcodec/video.c
>> @@ -105,6 +105,7 @@ static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *, AVFrame * );
>>  #endif
>>  static enum PixelFormat ffmpeg_GetFormat( AVCodecContext *,
>>                                            const enum PixelFormat * );
>> +static bool ffmpeg_CanHwAccel( AVCodecContext *, const enum PixelFormat * );
>>  static picture_t *DecodeVideo( decoder_t *, block_t ** );
>>
>>  static uint32_t ffmpeg_CodecTag( vlc_fourcc_t fcc )
>> @@ -374,7 +375,21 @@ int InitVideoDec( decoder_t *p_dec, AVCodecContext *p_context,
>>      i_thread_count = __MIN( i_thread_count, 16 );
>>      msg_Dbg( p_dec, "allowing %d thread(s) for decoding", i_thread_count );
>>      p_context->thread_count = i_thread_count;
>> +# if defined(_WIN32)
>> +    /* Frame multithreading is not thread safe with DXVA2.
>> +     * When a frame is being copied to host memory, the frame
>> +     * is locked and cannot be used as a reference frame
>> +     * simultaneously and thus decoding fails for some frames. This
>> +     * causes major image corruption. */
>> +    enum PixelFormat test_formats[] = { AV_PIX_FMT_DXVA2_VLD, AV_PIX_FMT_NONE };
>> +    if( ffmpeg_CanHwAccel( p_context, &test_formats ) )
>> +    {
>> +        msg_Dbg( p_dec, "threaded frame decoding with DXVA2 is not thread safe" );
>> +        p_context->thread_safe_callbacks = false;
>> +    }
>> +#else
>>      p_context->thread_safe_callbacks = true;
>> +#endif
>>
>>      switch( p_codec->id )
>>      {
>> @@ -396,21 +411,6 @@ int InitVideoDec( decoder_t *p_dec, AVCodecContext *p_context,
>>              break;
>>      }
>>
>> -    /* Workaround: frame multithreading is not compatible with
>> -     * DXVA2. When a frame is being copied to host memory, the frame
>> -     * is locked and cannot be used as a reference frame
>> -     * simultaneously and thus decoding fails for some frames. This
>> -     * causes major image corruption. */
>> -# if defined(_WIN32)
>> -    char *avcodec_hw = var_InheritString( p_dec, "avcodec-hw" );
>> -    if( avcodec_hw == NULL || strcasecmp( avcodec_hw, "none" ) )
>> -    {
>> -        msg_Warn( p_dec, "threaded frame decoding is not compatible with DXVA2, disabled" );
>> -        p_context->thread_type &= ~FF_THREAD_FRAME;
>> -    }
>> -    free( avcodec_hw );
>> -# endif
>> -
>>      if( p_context->thread_type & FF_THREAD_FRAME )
>>          p_dec->i_extra_picture_buffers = 2 * p_context->thread_count;
>>  #endif
>> @@ -1305,6 +1305,51 @@ static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context,
>>  }
>>  #endif
>>
>> +static bool ffmpeg_CanHwAccel( AVCodecContext *p_codec,
>> +                               const enum PixelFormat *pi_fmt )
>> +{
>> +    decoder_t *p_dec = p_codec->opaque;
>> +    decoder_sys_t *p_sys = p_dec->p_sys;
>> +    vlc_va_t *p_va;
>> +
>> +    /* Enumerate available formats */
>> +    bool can_hwaccel = false;
>> +    for( size_t i = 0; pi_fmt[i] != PIX_FMT_NONE; i++ )
>> +    {
>> +        const AVPixFmtDescriptor *dsc = av_pix_fmt_desc_get(pi_fmt[i]);
>> +        if (dsc == NULL)
>> +            continue;
>> +        if ( dsc->flags & AV_PIX_FMT_FLAG_HWACCEL )
>> +        {
>> +            can_hwaccel = true;
>> +            break;
>> +        }
>> +    }
>> +
>> +    if (!can_hwaccel)
>> +        goto end;
>> +
>> +    can_hwaccel = false;
>> +
>> +    /* Profile and level information is needed now.
>> +     * TODO: avoid code duplication with avcodec.c */
>> +    if( p_codec->profile != FF_PROFILE_UNKNOWN)
>> +        p_dec->fmt_in.i_profile = p_codec->profile;
>> +    if( p_codec->level != FF_LEVEL_UNKNOWN)
>> +        p_dec->fmt_in.i_level = p_codec->level;
>> +
>> +    p_va = vlc_va_New( VLC_OBJECT(p_dec), p_codec, &p_dec->fmt_in );
>> +    if( p_va == NULL )
>> +        goto end;
>> +
>> +    can_hwaccel = true;
>> +
>> +end:
>> +    if ( p_va != NULL )
>> +        vlc_va_Delete( p_va, p_codec );
>> +    return can_hwaccel;
>> +}
>> +
>>  static enum PixelFormat ffmpeg_GetFormat( AVCodecContext *p_context,
>>                                            const enum PixelFormat *pi_fmt )
>>  {
>> --
>> 2.3.0
>>
>> _______________________________________________
>> vlc-devel mailing list
>> To unsubscribe or modify your subscription options:
>> https://mailman.videolan.org/listinfo/vlc-devel



More information about the vlc-devel mailing list