]> git.sesse.net Git - vlc/blobdiff - modules/codec/avcodec/video.c
avcodec: factor frame initialization code
[vlc] / modules / codec / avcodec / video.c
index bffce38a8a9579129219ae8d40543bde6287739b..fe21d75b1b71b5dc5fb129c1705ba940655ab188 100644 (file)
@@ -33,7 +33,6 @@
 #include <vlc_codec.h>
 #include <vlc_avcodec.h>
 #include <vlc_cpu.h>
-#include <vlc_modules.h>
 #include <assert.h>
 
 #include <libavcodec/avcodec.h>
@@ -103,11 +102,14 @@ struct decoder_sys_t
  *****************************************************************************/
 static void ffmpeg_InitCodec      ( decoder_t * );
 static void ffmpeg_CopyPicture    ( decoder_t *, picture_t *, AVFrame * );
+#if LIBAVCODEC_VERSION_MAJOR >= 55
+static int lavc_GetFrame(struct AVCodecContext *, AVFrame *, int);
+#else
 static int  ffmpeg_GetFrameBuf    ( struct AVCodecContext *, AVFrame * );
 static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *, AVFrame * );
+#endif
 static enum PixelFormat ffmpeg_GetFormat( AVCodecContext *,
                                           const enum PixelFormat * );
-static void vlc_va_Delete( vlc_va_t * );
 
 static uint32_t ffmpeg_CodecTag( vlc_fourcc_t fcc )
 {
@@ -125,8 +127,14 @@ static inline picture_t *ffmpeg_NewPictBuf( decoder_t *p_dec,
 {
     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;
+    if( p_context->coded_width != p_context->width ||
+        p_context->coded_height != p_context->height )
+    {
+        p_dec->fmt_out.video.i_visible_width = p_context->width;
+        p_dec->fmt_out.video.i_visible_height = p_context->height;
+    }
+    p_dec->fmt_out.video.i_width = p_context->coded_width;
+    p_dec->fmt_out.video.i_height = p_context->coded_height;
 
     if( !p_context->width || !p_context->height )
     {
@@ -310,11 +318,16 @@ int InitVideoDec( decoder_t *p_dec, AVCodecContext *p_context,
         msg_Dbg( p_dec, "direct rendering is disabled" );
     }
 
+    p_sys->p_context->get_format = ffmpeg_GetFormat;
     /* Always use our get_buffer wrapper so we can calculate the
      * PTS correctly */
+#if LIBAVCODEC_VERSION_MAJOR >= 55
+    p_sys->p_context->get_buffer2 = lavc_GetFrame;
+#else
     p_sys->p_context->get_buffer = ffmpeg_GetFrameBuf;
     p_sys->p_context->reget_buffer = avcodec_default_reget_buffer;
     p_sys->p_context->release_buffer = ffmpeg_ReleaseFrameBuf;
+#endif
     p_sys->p_context->opaque = p_dec;
 
 #ifdef HAVE_AVCODEC_MT
@@ -331,37 +344,30 @@ 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_sys->p_context->thread_count = i_thread_count;
-#endif
+    p_sys->p_context->thread_safe_callbacks = true;
 
-    char *hw = var_CreateGetString( p_dec, "avcodec-hw" ); /* FIXME */
-    if( (hw == NULL || strcasecmp( hw, "none" )) &&
-        (i_codec_id == AV_CODEC_ID_MPEG1VIDEO || i_codec_id == AV_CODEC_ID_MPEG2VIDEO ||
-         i_codec_id == AV_CODEC_ID_MPEG4 || i_codec_id == AV_CODEC_ID_H263 ||
-         i_codec_id == AV_CODEC_ID_H264 ||
-         i_codec_id == AV_CODEC_ID_VC1 || i_codec_id == AV_CODEC_ID_WMV3) )
+    switch( i_codec_id )
     {
-#if defined(HAVE_AVCODEC_MT) && LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 1, 0)
-        if( p_sys->p_context->thread_type & FF_THREAD_FRAME )
-        {
-            msg_Warn( p_dec, "threaded frame decoding is not compatible with libavcodec-hw, disabled" );
-            p_sys->p_context->thread_type &= ~FF_THREAD_FRAME;
-        }
-        if( ( p_sys->p_context->thread_type & FF_THREAD_SLICE ) &&
-            ( i_codec_id == AV_CODEC_ID_MPEG1VIDEO || i_codec_id == AV_CODEC_ID_MPEG2VIDEO ) )
-        {
-            msg_Warn( p_dec, "threaded slice decoding is not compatible with libavcodec-hw, disabled" );
+        case AV_CODEC_ID_MPEG4:
+        case AV_CODEC_ID_H263:
+            p_sys->p_context->thread_type = 0;
+            break;
+        case AV_CODEC_ID_MPEG1VIDEO:
+        case AV_CODEC_ID_MPEG2VIDEO:
             p_sys->p_context->thread_type &= ~FF_THREAD_SLICE;
-        }
-#endif
-        p_sys->p_context->get_format = ffmpeg_GetFormat;
+            /* fall through */
+# if (LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 1, 0))
+        case AV_CODEC_ID_H264:
+        case AV_CODEC_ID_VC1:
+        case AV_CODEC_ID_WMV3:
+            p_sys->p_context->thread_type &= ~FF_THREAD_FRAME;
+# endif
     }
-    free( hw );
-#ifdef HAVE_AVCODEC_MT
+
     if( p_sys->p_context->thread_type & FF_THREAD_FRAME )
         p_dec->i_extra_picture_buffers = 2 * p_sys->p_context->thread_count;
 #endif
 
-
     /* ***** misc init ***** */
     p_sys->i_pts = VLC_TS_INVALID;
     p_sys->b_has_b_frames = false;
@@ -465,8 +471,10 @@ picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
 
         p_sys->i_late_frames = 0;
 
+        post_mt( p_sys );
         if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )
             avcodec_flush_buffers( p_context );
+        wait_mt( p_sys );
 
         block_Release( p_block );
         return NULL;
@@ -608,7 +616,7 @@ picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
             block_Release( p_block );
             return NULL;
         }
-        else if( i_used > p_block->i_buffer ||
+        else if( (unsigned)i_used > p_block->i_buffer ||
                  p_context->thread_count > 1 )
         {
             i_used = p_block->i_buffer;
@@ -767,13 +775,12 @@ void EndVideoDec( decoder_t *p_dec )
 
     wait_mt( p_sys );
 
-    if( p_sys->p_ff_pic ) av_free( p_sys->p_ff_pic );
+    if( p_sys->p_ff_pic )
+        av_free( p_sys->p_ff_pic );
 
     if( p_sys->p_va )
-    {
         vlc_va_Delete( p_sys->p_va );
-        p_sys->p_va = NULL;
-    }
+
     vlc_sem_destroy( &p_sys->sem_mt );
 }
 
@@ -886,76 +893,255 @@ static void ffmpeg_CopyPicture( decoder_t *p_dec,
     }
 }
 
-/*****************************************************************************
- * ffmpeg_GetFrameBuf: callback used by ffmpeg to get a frame buffer.
- *****************************************************************************
- * It is used for direct rendering as well as to get the right PTS for each
- * decoded picture (even in indirect rendering mode).
- *****************************************************************************/
-static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context,
-                               AVFrame *p_ff_pic )
+#if LIBAVCODEC_VERSION_MAJOR >= 55
+typedef struct
 {
-    decoder_t *p_dec = (decoder_t *)p_context->opaque;
-    decoder_sys_t *p_sys = p_dec->p_sys;
-    picture_t *p_pic;
+    vlc_va_t *va;
+    AVFrame *frame;
+} lavc_hw_ref_t;
 
-    /* */
-    p_ff_pic->opaque = NULL;
+static void lavc_va_ReleaseFrame(void *opaque, uint8_t *data)
+{
+    lavc_hw_ref_t *ref = opaque;
 
-    if( p_sys->p_va )
+    vlc_va_Release(ref->va, ref->frame);
+    free(ref);
+    (void) data;
+}
+
+static int lavc_va_GetFrame(struct AVCodecContext *ctx, AVFrame *frame)
+{
+    decoder_t *dec = ctx->opaque;
+    decoder_sys_t *sys = dec->p_sys;
+    vlc_va_t *va = sys->p_va;
+
+    if (vlc_va_Setup(va, &ctx->hwaccel_context, &dec->fmt_out.video.i_chroma,
+                     ctx->coded_width, ctx->coded_height))
     {
-        /* hwaccel_context is not present in old ffmpeg version */
-        if( vlc_va_Setup( p_sys->p_va,
-                          &p_context->hwaccel_context, &p_dec->fmt_out.video.i_chroma,
-                          p_context->width, p_context->height ) )
-        {
-            msg_Err( p_dec, "vlc_va_Setup failed" );
-            return -1;
-        }
+        msg_Err(dec, "hardware acceleration setup failed");
+        return -1;
+    }
+    if (vlc_va_Get(va, frame))
+    {
+        msg_Err(dec, "hardware acceleration picture allocation failed");
+        return -1;
+    }
 
-        /* */
-        p_ff_pic->type = FF_BUFFER_TYPE_USER;
+    lavc_hw_ref_t *ref = malloc(sizeof (*ref));
+    if (unlikely(ref == NULL))
+    {
+        vlc_va_Release(va, frame);
+        return -1;
+    }
+    ref->va = va;
+    ref->frame = frame;
 
-#if LIBAVCODEC_VERSION_MAJOR < 54
-        p_ff_pic->age = 256*256*256*64;
-#endif
+    frame->buf[0] = av_buffer_create(frame->data[0], 0, lavc_va_ReleaseFrame,
+                                     ref, 0);
+    if (unlikely(frame->buf[0] == NULL))
+    {
+        lavc_va_ReleaseFrame(ref, frame->data[0]);
+        return -1;
+    }
+    return 0;
+}
+
+typedef struct
+{
+    decoder_t *decoder;
+    picture_t *picture;
+} lavc_pic_ref_t;
+
+static void lavc_dr_ReleaseFrame(void *opaque, uint8_t *data)
+{
+    lavc_pic_ref_t *ref = opaque;
+
+    decoder_UnlinkPicture(ref->decoder, ref->picture);
+    free(ref);
+    (void) data;
+}
+
+static picture_t *lavc_dr_GetFrame(struct AVCodecContext *ctx,
+                                   AVFrame *frame, unsigned flags)
+{
+    decoder_t *dec = (decoder_t *)ctx->opaque;
+
+    if (GetVlcChroma(&dec->fmt_out.video, ctx->pix_fmt) != VLC_SUCCESS)
+        return NULL;
+    dec->fmt_out.i_codec = dec->fmt_out.video.i_chroma;
+    if (ctx->pix_fmt == PIX_FMT_PAL8)
+        return NULL;
+
+    int width = frame->width;
+    int height = frame->height;
+    int aligns[AV_NUM_DATA_POINTERS];
+
+    avcodec_align_dimensions2(ctx, &width, &height, aligns);
+
+    picture_t *pic = ffmpeg_NewPictBuf(dec, ctx);
+    if (pic == NULL)
+        return NULL;
+
+    /* Check that the picture is suitable for libavcodec */
+    if (pic->p[0].i_pitch < width * pic->p[0].i_pixel_pitch
+     || pic->p[0].i_lines < height)
+        goto no_dr;
 
-        if( vlc_va_Get( p_sys->p_va, p_ff_pic ) )
+    for (int i = 0; i < pic->i_planes; i++)
+    {
+        if (pic->p[i].i_pitch % aligns[i])
+            goto no_dr;
+        if (((uintptr_t)pic->p[i].p_pixels) % aligns[i])
+            goto no_dr;
+    }
+
+    /* Allocate buffer references */
+    for (int i = 0; i < pic->i_planes; i++)
+    {
+        lavc_pic_ref_t *ref = malloc(sizeof (*ref));
+        if (ref == NULL)
+            goto error;
+        ref->decoder = dec;
+        ref->picture = pic;
+        decoder_LinkPicture(dec, pic);
+
+        uint8_t *data = pic->p[i].p_pixels;
+        int size = pic->p[i].i_pitch * pic->p[i].i_lines;
+
+        frame->buf[i] = av_buffer_create(data, size, lavc_dr_ReleaseFrame,
+                                         ref, 0);
+        if (unlikely(frame->buf[i] == NULL))
         {
-            msg_Err( p_dec, "VaGrabSurface failed" );
-            return -1;
+            lavc_dr_ReleaseFrame(ref, data);
+            goto error;
         }
-        return 0;
     }
-    else if( !p_sys->b_direct_rendering )
+    decoder_UnlinkPicture(dec, pic);
+    (void) flags;
+    return pic;
+error:
+    for (unsigned i = 0; frame->buf[i] != NULL; i++)
+        av_buffer_unref(&frame->buf[i]);
+no_dr:
+    decoder_DeletePicture(dec, pic);
+    return NULL;
+}
+
+/**
+ * Callback used by libavcodec to get a frame buffer.
+ *
+ * It is used for direct rendering as well as to get the right PTS for each
+ * decoded picture (even in indirect rendering mode).
+ */
+static int lavc_GetFrame(struct AVCodecContext *ctx, AVFrame *frame, int flags)
+{
+    decoder_t *dec = ctx->opaque;
+    decoder_sys_t *sys = dec->p_sys;
+    picture_t *pic;
+
+    for (unsigned i = 0; i < AV_NUM_DATA_POINTERS; i++)
     {
-        /* Not much to do in indirect rendering mode. */
-        return avcodec_default_get_buffer( p_context, p_ff_pic );
+        frame->data[i] = NULL;
+        frame->linesize[i] = 0;
+        frame->buf[i] = NULL;
     }
 
-    wait_mt( p_sys );
+    if (sys->p_va != NULL)
+        return lavc_va_GetFrame(ctx, frame);
+
+    frame->opaque = NULL;
+    if (!sys->b_direct_rendering)
+        return avcodec_default_get_buffer2(ctx, frame, flags);
+
     /* Some codecs set pix_fmt only after the 1st frame has been decoded,
      * so we need to check for direct rendering again. */
+    wait_mt(sys);
+    pic = lavc_dr_GetFrame(ctx, frame, flags);
+    if (pic == NULL)
+    {
+        if (sys->i_direct_rendering_used != 0)
+        {
+            msg_Warn(dec, "disabling direct rendering");
+            sys->i_direct_rendering_used = 0;
+        }
+        post_mt(sys);
+        return avcodec_default_get_buffer2(ctx, frame, flags);
+    }
+
+    if (sys->i_direct_rendering_used != 1)
+    {
+        msg_Dbg(dec, "enabling direct rendering");
+        sys->i_direct_rendering_used = 1;
+    }
+    post_mt(sys);
+
+    frame->opaque = pic;
+    static_assert(PICTURE_PLANE_MAX <= AV_NUM_DATA_POINTERS, "Oops!");
+    for (unsigned i = 0; i < PICTURE_PLANE_MAX; i++)
+    {
+        frame->data[i] = pic->p[i].p_pixels;
+        frame->linesize[i] = pic->p[i].i_pitch;
+    }
+    for (unsigned i = PICTURE_PLANE_MAX; i < AV_NUM_DATA_POINTERS; i++)
+    {
+        frame->data[i] = NULL;
+        frame->linesize[i] = 0;
+    }
+    return 0;
+}
+#else
+static int ffmpeg_va_GetFrameBuf( 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;
+    vlc_va_t *p_va = p_sys->p_va;
+
+    /* hwaccel_context is not present in old ffmpeg version */
+    if( vlc_va_Setup( p_va,
+                &p_context->hwaccel_context, &p_dec->fmt_out.video.i_chroma,
+                p_context->coded_width, p_context->coded_height ) )
+    {
+        msg_Err( p_dec, "vlc_va_Setup failed" );
+        return -1;
+    }
+
+    if( vlc_va_Get( p_va, p_ff_pic ) )
+    {
+        msg_Err( p_dec, "vlc_va_Get failed" );
+        return -1;
+    }
+
+    p_ff_pic->type = FF_BUFFER_TYPE_USER;
+    return 0;
+}
+
+static picture_t *ffmpeg_dr_GetFrameBuf(struct AVCodecContext *p_context)
+{
+    decoder_t *p_dec = (decoder_t *)p_context->opaque;
+    decoder_sys_t *p_sys = p_dec->p_sys;
 
     int i_width = p_context->width;
     int i_height = p_context->height;
     avcodec_align_dimensions( p_context, &i_width, &i_height );
 
-    if( GetVlcChroma( &p_dec->fmt_out.video, p_context->pix_fmt ) != VLC_SUCCESS ||
-        p_context->pix_fmt == PIX_FMT_PAL8 )
+    picture_t *p_pic = NULL;
+    if (GetVlcChroma(&p_dec->fmt_out.video, p_context->pix_fmt) != VLC_SUCCESS)
+        goto no_dr;
+
+    if (p_context->pix_fmt == PIX_FMT_PAL8)
         goto no_dr;
 
     p_dec->fmt_out.i_codec = p_dec->fmt_out.video.i_chroma;
 
-    /* Get a new picture */
     p_pic = ffmpeg_NewPictBuf( p_dec, p_context );
     if( !p_pic )
         goto no_dr;
-    bool b_compatible = true;
+
     if( p_pic->p[0].i_pitch / p_pic->p[0].i_pixel_pitch < i_width ||
         p_pic->p[0].i_lines < i_height )
-        b_compatible = false;
-    for( int i = 0; i < p_pic->i_planes && b_compatible; i++ )
+        goto no_dr;
+
+    for( int i = 0; i < p_pic->i_planes; i++ )
     {
         unsigned i_align;
         switch( p_sys->i_codec_id )
@@ -972,29 +1158,71 @@ static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context,
             break;
         }
         if( p_pic->p[i].i_pitch % i_align )
-            b_compatible = false;
+            goto no_dr;
         if( (intptr_t)p_pic->p[i].p_pixels % i_align )
-            b_compatible = false;
+            goto no_dr;
     }
-    if( p_context->pix_fmt == PIX_FMT_YUV422P && b_compatible )
+
+    if( p_context->pix_fmt == PIX_FMT_YUV422P )
     {
         if( 2 * p_pic->p[1].i_pitch != p_pic->p[0].i_pitch ||
             2 * p_pic->p[2].i_pitch != p_pic->p[0].i_pitch )
-            b_compatible = false;
+            goto no_dr;
     }
-    if( !b_compatible )
-    {
+
+    return p_pic;
+
+no_dr:
+    if (p_pic)
         decoder_DeletePicture( p_dec, p_pic );
-        goto no_dr;
+
+    return NULL;
+}
+
+static int ffmpeg_GetFrameBuf( 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;
+
+    /* */
+    p_ff_pic->opaque = NULL;
+#if ! LIBAVCODEC_VERSION_CHECK(54, 34, 0, 79, 101)
+    p_ff_pic->pkt_pts = p_context->pkt ? p_context->pkt->pts : AV_NOPTS_VALUE;
+#endif
+#if LIBAVCODEC_VERSION_MAJOR < 54
+    p_ff_pic->age = 256*256*256*64;
+#endif
+
+    if( p_sys->p_va )
+        return ffmpeg_va_GetFrameBuf(p_context, p_ff_pic);
+
+    if( !p_sys->b_direct_rendering )
+        return avcodec_default_get_buffer( p_context, p_ff_pic );
+
+    wait_mt( p_sys );
+    /* Some codecs set pix_fmt only after the 1st frame has been decoded,
+     * so we need to check for direct rendering again. */
+
+    picture_t *p_pic = ffmpeg_dr_GetFrameBuf(p_context);
+    if (!p_pic) {
+        if( p_sys->i_direct_rendering_used != 0 )
+        {
+            msg_Warn( p_dec, "disabling direct rendering" );
+            p_sys->i_direct_rendering_used = 0;
+        }
+
+        post_mt( p_sys );
+        return avcodec_default_get_buffer( p_context, p_ff_pic );
     }
 
-    if( p_sys->i_direct_rendering_used != 1 )
-    {
+    if( p_sys->i_direct_rendering_used != 1 ) {
         msg_Dbg( p_dec, "using direct rendering" );
         p_sys->i_direct_rendering_used = 1;
     }
 
     p_context->draw_horiz_band = NULL;
+    post_mt( p_sys );
 
     p_ff_pic->opaque = (void*)p_pic;
     p_ff_pic->type = FF_BUFFER_TYPE_USER;
@@ -1008,21 +1236,7 @@ static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context,
     p_ff_pic->linesize[2] = p_pic->p[2].i_pitch;
     p_ff_pic->linesize[3] = 0;
 
-#if LIBAVCODEC_VERSION_MAJOR < 54
-    p_ff_pic->age = 256*256*256*64;
-#endif
-
-    post_mt( p_sys );
     return 0;
-
-no_dr:
-    if( p_sys->i_direct_rendering_used != 0 )
-    {
-        msg_Warn( p_dec, "disabling direct rendering" );
-        p_sys->i_direct_rendering_used = 0;
-    }
-    post_mt( p_sys );
-    return avcodec_default_get_buffer( p_context, p_ff_pic );
 }
 
 static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context,
@@ -1045,48 +1259,7 @@ static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context,
     for( int i = 0; i < 4; i++ )
         p_ff_pic->data[i] = NULL;
 }
-
-static int ffmpeg_va_Start( void *func, va_list ap )
-{
-    vlc_va_t *va = va_arg( ap, vlc_va_t * );
-    int codec = va_arg( ap, int );
-    const es_format_t *fmt = va_arg( ap, const es_format_t * );
-    int (*open)( vlc_va_t *, int, const es_format_t * ) = func;
-
-    return open( va, codec, fmt );
-}
-
-static vlc_va_t *vlc_va_New( vlc_object_t *parent, int codec_id,
-                             const es_format_t *fmt )
-{
-    vlc_va_t *p_va = vlc_object_create( parent, sizeof( *p_va ) );
-    if( unlikely(p_va == NULL) )
-        return NULL;
-
-    p_va->module = vlc_module_load( p_va, "hw decoder", "$avcodec-hw",
-                                    true, ffmpeg_va_Start, p_va,
-                                    codec_id, fmt );
-    if( p_va->module == NULL )
-    {
-        vlc_object_release( p_va );
-        p_va = NULL;
-    }
-    return p_va;
-}
-
-static void ffmpeg_va_Stop( void *func, va_list ap )
-{
-    vlc_va_t *va = va_arg( ap, vlc_va_t * );
-    void (*close)( vlc_va_t * ) = func;
-
-    close( va );
-}
-
-static void vlc_va_Delete( vlc_va_t *va )
-{
-    vlc_module_unload( va->module, ffmpeg_va_Stop, va );
-    vlc_object_release( va );
-}
+#endif
 
 static enum PixelFormat ffmpeg_GetFormat( AVCodecContext *p_context,
                                           const enum PixelFormat *pi_fmt )
@@ -1098,6 +1271,24 @@ static enum PixelFormat ffmpeg_GetFormat( AVCodecContext *p_context,
     if( p_va != NULL )
         vlc_va_Delete( 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;
+        bool hwaccel = (dsc->flags & AV_PIX_FMT_FLAG_HWACCEL) != 0;
+
+        msg_Dbg( p_dec, "available %sware decoder output format %d (%s)",
+                 hwaccel ? "hard" : "soft", pi_fmt[i], dsc->name );
+        if (hwaccel)
+            can_hwaccel = true;
+    }
+
+    if (!can_hwaccel)
+        goto end;
+
     /* Profile and level informations are needed now.
      * TODO: avoid code duplication with avcodec.c */
     if( p_context->profile != FF_PROFILE_UNKNOWN)
@@ -1109,12 +1300,8 @@ static enum PixelFormat ffmpeg_GetFormat( AVCodecContext *p_context,
     if( p_va == NULL )
         goto end;
 
-    /* Try too look for a supported hw acceleration */
     for( size_t i = 0; pi_fmt[i] != PIX_FMT_NONE; i++ )
     {
-        const char *name = av_get_pix_fmt_name(pi_fmt[i]);
-        msg_Dbg( p_dec, "Available decoder output format %d (%s)",
-                 pi_fmt[i], name ? name : "unknown" );
         if( p_va->pix_fmt != pi_fmt[i] )
             continue;
 
@@ -1142,12 +1329,10 @@ static enum PixelFormat ffmpeg_GetFormat( AVCodecContext *p_context,
         return pi_fmt[i];
     }
 
-    msg_Err( p_dec, "acceleration not available" );
     vlc_va_Delete( p_va );
 
-    p_sys->p_va = NULL;
-
 end:
     /* Fallback to default behaviour */
+    p_sys->p_va = NULL;
     return avcodec_default_get_format( p_context, pi_fmt );
 }