[vlc-commits] [Git][videolan/vlc][master] 5 commits: avcodec: split the InitVideoDec function in 2 parts

Steve Lhomme (@robUx4) gitlab at videolan.org
Sat May 6 06:55:22 UTC 2023



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
aad2bdfd by Steve Lhomme at 2023-05-06T06:33:09+00:00
avcodec: split the InitVideoDec function in 2 parts

No functional changes.

Also move the profile initialization with the p_sys init.

- - - - -
4416251e by Steve Lhomme at 2023-05-06T06:33:09+00:00
avcodec: move the code to open a VA in a function

Now the (un)locking is optional.

- - - - -
1effe16f by Steve Lhomme at 2023-05-06T06:33:09+00:00
avcodec: add a flag to only allow hardware decoding for the decoder

Only use 1 decoder thread when allowing only hardware decoders.

Restarting the decoder silently is not allowed. Either we can reuse the va or
we need to reload the decoder outside of lavc.

- - - - -
faec6b06 by Steve Lhomme at 2023-05-06T06:33:09+00:00
avcodec: va: document which fields of the AVCodecContext are used by the VA's

- - - - -
cd4d32f7 by Steve Lhomme at 2023-05-06T06:33:09+00:00
avcodec: add a hardware-only lavc AV1 video decoder with higher priority

The priority is higher than dav1d so it can handle hardware decoding even if
dav1d is present.

This version of lavc should only allow decoding if the decoder has a profile
that can be decoded by the hardware, otherwise it should let other decoders try
to do the decoding (dav1d, lavc with current priority, etc).

- - - - -


6 changed files:

- modules/codec/Makefile.am
- modules/codec/avcodec/avcodec.c
- modules/codec/avcodec/avcodec.h
- modules/codec/avcodec/va.h
- modules/codec/avcodec/video.c
- modules/codec/meson.build


Changes:

=====================================
modules/codec/Makefile.am
=====================================
@@ -379,7 +379,8 @@ libavcodec_plugin_la_SOURCES = \
 	codec/avcodec/subtitle.c \
 	codec/avcodec/audio.c \
 	codec/avcodec/va.c codec/avcodec/va.h \
-	codec/avcodec/avcodec.c codec/avcodec/avcodec.h
+	codec/avcodec/avcodec.c codec/avcodec/avcodec.h \
+	packetizer/av1_obu.c packetizer/av1_obu.h packetizer/av1.h
 if ENABLE_SOUT
 libavcodec_plugin_la_SOURCES += codec/avcodec/encoder.c
 endif


=====================================
modules/codec/avcodec/avcodec.c
=====================================
@@ -89,6 +89,11 @@ vlc_module_begin ()
     set_capability("video decoder", 70)
     set_callbacks(InitVideoDec, EndVideoDec)
 
+    add_submodule()
+    add_shortcut("ffmpeghw")
+    set_capability("video decoder", 10001)
+    set_callbacks(InitVideoHwDec, EndVideoDec)
+
     add_submodule()
     add_shortcut("ffmpeg")
     set_capability("audio decoder", 70)


=====================================
modules/codec/avcodec/avcodec.h
=====================================
@@ -35,6 +35,7 @@ void EndVideoEnc( encoder_t * );
 
 /* Video Decoder */
 int InitVideoDec( vlc_object_t * );
+int InitVideoHwDec( vlc_object_t * );
 void EndVideoDec( vlc_object_t * );
 
 /* Audio Decoder */


=====================================
modules/codec/avcodec/va.h
=====================================
@@ -67,10 +67,13 @@ bool vlc_va_MightDecode(enum AVPixelFormat hwfmt, enum AVPixelFormat swfmt);
 /**
  * Creates an accelerated video decoding back-end for libavcodec.
  * @param obj parent VLC object
+ * @param avctx AVContext to set the hwaccel_context on. The VA can assume fields
+ *   codec_id, coded_width, coded_height, active_thread_type, thread_count,
+ *   framerate, profile, refs (H264) and hw_pix_fmt are set correctly.
  * @param fmt VLC format of the content to decode
  * @return a new VLC object on success, NULL on error.
  */
-vlc_va_t *vlc_va_New(vlc_object_t *obj, AVCodecContext *,
+vlc_va_t *vlc_va_New(vlc_object_t *obj, AVCodecContext * avctx,
                      enum AVPixelFormat hwfmt, const AVPixFmtDescriptor *,
                      const es_format_t *fmt, vlc_decoder_device *device,
                      video_format_t *, vlc_video_context **vtcx_out);


=====================================
modules/codec/avcodec/video.c
=====================================
@@ -54,6 +54,8 @@
 # include <libavutil/hdr_dynamic_metadata.h>
 #endif
 
+#include "../../packetizer/av1_obu.h"
+#include "../../packetizer/av1.h"
 #include "../cc.h"
 #define FRAME_INFO_DEPTH 64
 
@@ -81,6 +83,7 @@ typedef struct
     bool b_hurry_up;
     bool b_show_corrupted;
     bool b_from_preroll;
+    bool b_hardware_only;
     enum AVDiscard i_skip_frame;
 
     struct frame_info_s frame_info[FRAME_INFO_DEPTH];
@@ -377,13 +380,14 @@ static int OpenVideoCodec( decoder_t *p_dec )
     ctx->width  = p_dec->fmt_in->video.i_visible_width;
     ctx->height = p_dec->fmt_in->video.i_visible_height;
 
-    ctx->coded_width = p_dec->fmt_in->video.i_width;
-    ctx->coded_height = p_dec->fmt_in->video.i_height;
+    if (!ctx->coded_width || !ctx->coded_height)
+    {
+        ctx->coded_width = p_dec->fmt_in->video.i_width;
+        ctx->coded_height = p_dec->fmt_in->video.i_height;
+    }
 
     ctx->bits_per_coded_sample = p_dec->fmt_in->video.i_bits_per_pixel;
     p_sys->pix_fmt = AV_PIX_FMT_NONE;
-    p_sys->profile = -1;
-    p_sys->level = -1;
     cc_Init( &p_sys->cc );
 
     set_video_color_settings( &p_dec->fmt_in->video, ctx );
@@ -422,33 +426,13 @@ static int OpenVideoCodec( decoder_t *p_dec )
     return 0;
 }
 
-/*****************************************************************************
- * InitVideo: initialize the video decoder
- *****************************************************************************
- * the ffmpeg codec will be opened, some memory allocated. The vout is not yet
- * opened (done after the first decoded frame).
- *****************************************************************************/
-int InitVideoDec( vlc_object_t *obj )
+static int InitVideoDecCommon( decoder_t *p_dec )
 {
-    decoder_t *p_dec = (decoder_t *)obj;
-    const AVCodec *p_codec;
-    AVCodecContext *p_context = ffmpeg_AllocContext( p_dec, &p_codec );
-    if( p_context == NULL )
-        return VLC_EGENERIC;
-
+    decoder_sys_t *p_sys = p_dec->p_sys;
+    AVCodecContext *p_context = p_sys->p_context;
+    const AVCodec *p_codec = p_sys->p_codec;
     int i_val;
 
-    /* Allocate the memory needed to store the decoder's structure */
-    decoder_sys_t *p_sys = calloc( 1, sizeof(*p_sys) );
-    if( unlikely(p_sys == NULL) )
-    {
-        avcodec_free_context( &p_context );
-        return VLC_ENOMEM;
-    }
-
-    p_dec->p_sys = p_sys;
-    p_sys->p_context = p_context;
-    p_sys->p_codec = p_codec;
     p_sys->p_va = NULL;
     vlc_mutex_init( &p_sys->lock );
 
@@ -518,7 +502,7 @@ int InitVideoDec( vlc_object_t *obj )
     p_context->opaque = p_dec;
     p_context->reordered_opaque = 0;
 
-    int i_thread_count = var_InheritInteger( p_dec, "avcodec-threads" );
+    int i_thread_count = p_sys->b_hardware_only ? 1 : var_InheritInteger( p_dec, "avcodec-threads" );
     if( i_thread_count <= 0 )
     {
         i_thread_count = vlc_GetCPUCount();
@@ -604,6 +588,206 @@ int InitVideoDec( vlc_object_t *obj )
     return VLC_SUCCESS;
 }
 
+static int ffmpeg_OpenVa(decoder_t *p_dec, AVCodecContext *p_context,
+                         enum AVPixelFormat hwfmt, enum AVPixelFormat swfmt,
+                         const AVPixFmtDescriptor *src_desc,
+                         vlc_mutex_t *open_lock)
+{
+    decoder_sys_t *p_sys = p_dec->p_sys;
+
+    if( hwfmt == AV_PIX_FMT_NONE )
+        return VLC_EGENERIC;
+
+    if (!vlc_va_MightDecode(hwfmt, swfmt))
+        return VLC_EGENERIC; /* Unknown brand of hardware acceleration */
+    if (p_context->width == 0 || p_context->height == 0)
+    {   /* should never happen */
+        msg_Err(p_dec, "unspecified video dimensions");
+        return VLC_EGENERIC;
+    }
+    const AVPixFmtDescriptor *dsc = av_pix_fmt_desc_get(hwfmt);
+    vlc_decoder_device *init_device = NULL;
+    msg_Dbg(p_dec, "trying format %s", dsc ? dsc->name : "unknown");
+    if (lavc_UpdateVideoFormat(p_dec, p_context, hwfmt, swfmt, &init_device))
+        return VLC_EGENERIC; /* Unsupported brand of hardware acceleration */
+    if (open_lock)
+        vlc_mutex_unlock(open_lock);
+
+    p_dec->fmt_out.video.i_chroma = 0; // make sure the va sets its output chroma
+    vlc_video_context *vctx_out;
+    vlc_va_t *va = vlc_va_New(VLC_OBJECT(p_dec), p_context, hwfmt, src_desc,
+                                p_dec->fmt_in, init_device,
+                                &p_dec->fmt_out.video, &vctx_out);
+    if (init_device)
+        vlc_decoder_device_Release(init_device);
+    if (open_lock)
+        vlc_mutex_lock(open_lock);
+    if (va == NULL)
+        return VLC_EGENERIC; /* Unsupported codec profile or such */
+    assert(p_dec->fmt_out.video.i_chroma != 0);
+    assert(vctx_out != NULL);
+    p_dec->fmt_out.i_codec = p_dec->fmt_out.video.i_chroma;
+
+    if (decoder_UpdateVideoOutput(p_dec, vctx_out))
+    {
+        vlc_va_Delete(va, p_context);
+        return VLC_EGENERIC; /* Unsupported codec profile or such */
+    }
+
+    p_sys->p_va = va;
+    p_sys->vctx_out = vlc_video_context_Hold( vctx_out );
+    p_sys->pix_fmt = hwfmt;
+    return VLC_SUCCESS;
+}
+
+static const enum AVPixelFormat hwfmts[] =
+{
+#ifdef _WIN32
+    AV_PIX_FMT_D3D11VA_VLD,
+    AV_PIX_FMT_DXVA2_VLD,
+#endif
+    AV_PIX_FMT_VAAPI,
+    AV_PIX_FMT_VDPAU,
+    AV_PIX_FMT_NONE,
+};
+
+int InitVideoHwDec( vlc_object_t *obj )
+{
+    decoder_t *p_dec = container_of(obj, decoder_t, obj);
+
+    if (p_dec->fmt_in->i_codec != VLC_CODEC_AV1)
+        return VLC_EGENERIC;
+
+    decoder_sys_t *p_sys = calloc(1, sizeof(*p_sys));
+    if( unlikely(p_sys == NULL) )
+        return VLC_ENOMEM;
+
+    const AVCodec *p_codec;
+    AVCodecContext *p_context = ffmpeg_AllocContext( p_dec, &p_codec );
+    if( unlikely(p_context == NULL) )
+    {
+        free(p_sys);
+        return VLC_ENOMEM;
+    }
+
+    av1_OBU_sequence_header_t *sequence_hdr = NULL;
+    unsigned w, h;
+
+    if (p_dec->fmt_in->i_extra > 4)
+    {
+        // in ISOBMFF/WebM/Matroska the first 4 bytes are from the AV1CodecConfigurationBox
+        // and then one or more OBU
+        const uint8_t *obu_start = ((const uint8_t*) p_dec->fmt_in->p_extra) + 4;
+        int obu_size = p_dec->fmt_in->i_extra - 4;
+        if (AV1_OBUIsValid(obu_start, obu_size) && AV1_OBUGetType(obu_start) == AV1_OBU_SEQUENCE_HEADER)
+            sequence_hdr = AV1_OBU_parse_sequence_header(obu_start, obu_size);
+    }
+
+    if (sequence_hdr == NULL)
+        goto failed;
+
+    // fill the AVCodecContext with the values from the sequence header
+    // so we can create the expected VA right away:
+    // coded_width, coded_height, framerate, profile and sw_pix_fmt
+
+    vlc_fourcc_t chroma = AV1_get_chroma(sequence_hdr);
+    if (chroma == 0)
+    {
+        AV1_release_sequence_header(sequence_hdr);
+        goto failed;
+    }
+    p_context->sw_pix_fmt = FindFfmpegChroma(chroma);
+
+    if (p_context->sw_pix_fmt == AV_PIX_FMT_NONE)
+    {
+        AV1_release_sequence_header(sequence_hdr);
+        goto failed;
+    }
+
+    AV1_get_frame_max_dimensions(sequence_hdr, &w, &h);
+
+    p_context->coded_width  = p_context->width  = w;
+    p_context->coded_height = p_context->height = h;
+
+    if (!p_dec->fmt_in->video.i_frame_rate || !p_dec->fmt_in->video.i_frame_rate_base)
+    {
+        unsigned num, den;
+        if (AV1_get_frame_rate(sequence_hdr, &num, &den))
+        {
+            p_context->framerate.num = num;
+            p_context->framerate.den = den;
+        }
+    }
+
+    int tier;
+    AV1_get_profile_level(sequence_hdr, &p_sys->profile, &p_sys->level, &tier);
+
+    AV1_release_sequence_header(sequence_hdr);
+
+    p_dec->p_sys = p_sys;
+    p_sys->p_context = p_context;
+    p_sys->p_codec = p_codec;
+    p_sys->pix_fmt = AV_PIX_FMT_NONE;
+    p_sys->b_hardware_only = true;
+
+    int res = InitVideoDecCommon( p_dec );
+    if (res != VLC_SUCCESS)
+        goto not_usable;
+
+    for( size_t i = 0; hwfmts[i] != AV_PIX_FMT_NONE; i++ )
+    {
+        enum AVPixelFormat hwfmt = hwfmts[i];
+
+        const AVPixFmtDescriptor *dsc = av_pix_fmt_desc_get(hwfmt);
+        if (dsc == NULL)
+            continue;
+
+        if (ffmpeg_OpenVa(p_dec, p_context, hwfmt, p_context->sw_pix_fmt, dsc, NULL) == VLC_SUCCESS)
+            // we have a matching hardware decoder
+            return VLC_SUCCESS;
+    }
+
+not_usable:
+    EndVideoDec(obj);
+    return VLC_EGENERIC;
+failed:
+    avcodec_free_context( &p_context );
+    free(p_sys);
+    return VLC_EGENERIC;
+}
+
+/*****************************************************************************
+ * InitVideo: initialize the video decoder
+ *****************************************************************************
+ * the ffmpeg codec will be opened, some memory allocated. The vout is not yet
+ * opened (done after the first decoded frame).
+ *****************************************************************************/
+int InitVideoDec( vlc_object_t *obj )
+{
+    decoder_t *p_dec = (decoder_t *)obj;
+    const AVCodec *p_codec;
+    AVCodecContext *p_context = ffmpeg_AllocContext( p_dec, &p_codec );
+    if( p_context == NULL )
+        return VLC_EGENERIC;
+
+    /* Allocate the memory needed to store the decoder's structure */
+    decoder_sys_t *p_sys = calloc( 1, sizeof(*p_sys) );
+    if( unlikely(p_sys == NULL) )
+    {
+        avcodec_free_context( &p_context );
+        return VLC_ENOMEM;
+    }
+
+    p_dec->p_sys = p_sys;
+    p_sys->p_context = p_context;
+    p_sys->p_codec = p_codec;
+    p_sys->profile = -1;
+    p_sys->level = -1;
+    p_sys->b_hardware_only = false;
+
+    return InitVideoDecCommon( p_dec );
+}
+
 /*****************************************************************************
  * Flush:
  *****************************************************************************/
@@ -1658,13 +1842,13 @@ static enum AVPixelFormat ffmpeg_GetFormat( AVCodecContext *p_context,
 
             can_hwaccel = true;
         }
-        else if (swfmt == AV_PIX_FMT_NONE)
+        else if (swfmt == AV_PIX_FMT_NONE && !p_sys->b_hardware_only)
             swfmt = pi_fmt[i];
     }
 
     /* Use the default fmt in priority of any sw fmt if the default fmt is a hw
      * one */
-    if (defaultfmt != AV_PIX_FMT_NONE)
+    if (defaultfmt != AV_PIX_FMT_NONE && !p_sys->b_hardware_only)
         swfmt = defaultfmt;
 
     if (p_sys->pix_fmt == AV_PIX_FMT_NONE)
@@ -1704,6 +1888,10 @@ no_reuse:
     if (p_sys->p_va != NULL)
     {
         msg_Err(p_dec, "existing hardware acceleration cannot be reused");
+        // the decoder changes have to be handled outside of lavc so that
+        // switching to a software decoder will not silently decode nothing
+        // (get_format will fail to use AV_PIX_FMT_NONE)
+        assert(!p_sys->b_hardware_only);
         vlc_va_Delete(p_sys->p_va, NULL);
         p_sys->p_va = NULL;
         vlc_video_context_Release( p_sys->vctx_out );
@@ -1728,17 +1916,6 @@ no_reuse:
 
     vlc_mutex_lock(&p_sys->lock);
 
-    static const enum AVPixelFormat hwfmts[] =
-    {
-#ifdef _WIN32
-        AV_PIX_FMT_D3D11VA_VLD,
-        AV_PIX_FMT_DXVA2_VLD,
-#endif
-        AV_PIX_FMT_VAAPI,
-        AV_PIX_FMT_VDPAU,
-        AV_PIX_FMT_NONE,
-    };
-
     const AVPixFmtDescriptor *src_desc = av_pix_fmt_desc_get(swfmt);
 
     for( size_t i = 0; hwfmts[i] != AV_PIX_FMT_NONE; i++ )
@@ -1748,46 +1925,9 @@ no_reuse:
             if( hwfmts[i] == pi_fmt[j] )
                 hwfmt = hwfmts[i];
 
-        if( hwfmt == AV_PIX_FMT_NONE )
-            continue;
-
-        if (!vlc_va_MightDecode(hwfmt, swfmt))
-            continue; /* Unknown brand of hardware acceleration */
-        if (p_context->width == 0 || p_context->height == 0)
-        {   /* should never happen */
-            msg_Err(p_dec, "unspecified video dimensions");
+        if (ffmpeg_OpenVa(p_dec, p_context, hwfmt, swfmt, src_desc, &p_sys->lock) != VLC_SUCCESS)
             continue;
-        }
-        const AVPixFmtDescriptor *dsc = av_pix_fmt_desc_get(hwfmt);
-        vlc_decoder_device *init_device = NULL;
-        msg_Dbg(p_dec, "trying format %s", dsc ? dsc->name : "unknown");
-        if (lavc_UpdateVideoFormat(p_dec, p_context, hwfmt, swfmt, &init_device))
-            continue; /* Unsupported brand of hardware acceleration */
-        vlc_mutex_unlock(&p_sys->lock);
-
-        p_dec->fmt_out.video.i_chroma = 0; // make sure the va sets its output chroma
-        vlc_video_context *vctx_out;
-        vlc_va_t *va = vlc_va_New(VLC_OBJECT(p_dec), p_context, hwfmt, src_desc,
-                                  p_dec->fmt_in, init_device,
-                                  &p_dec->fmt_out.video, &vctx_out);
-        if (init_device)
-            vlc_decoder_device_Release(init_device);
-        vlc_mutex_lock(&p_sys->lock);
-        if (va == NULL)
-            continue; /* Unsupported codec profile or such */
-        assert(p_dec->fmt_out.video.i_chroma != 0);
-        assert(vctx_out != NULL);
-        p_dec->fmt_out.i_codec = p_dec->fmt_out.video.i_chroma;
-
-        if (decoder_UpdateVideoOutput(p_dec, vctx_out))
-        {
-            vlc_va_Delete(va, p_context);
-            continue; /* Unsupported codec profile or such */
-        }
 
-        p_sys->p_va = va;
-        p_sys->vctx_out = vlc_video_context_Hold( vctx_out );
-        p_sys->pix_fmt = hwfmt;
         vlc_mutex_unlock(&p_sys->lock);
         return hwfmt;
     }


=====================================
modules/codec/meson.build
=====================================
@@ -591,6 +591,9 @@ if avcodec_dep.found()
                 'avcodec/audio.c',
                 'avcodec/va.c',
                 'avcodec/avcodec.c',
+                '../packetizer/av1_obu.c',
+                '../packetizer/av1_obu.h',
+                '../packetizer/av1.h',
                 avcodec_extra_sources
         ),
         'dependencies' : [avutil_dep, avcodec_dep],



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/2a2a29fbae499d9832054cc966e1e9768911c683...cd4d32f71b27c439a44ff37abf2718dc064f2ff1

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/2a2a29fbae499d9832054cc966e1e9768911c683...cd4d32f71b27c439a44ff37abf2718dc064f2ff1
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list