[vlc-commits] [Git][videolan/vlc][master] 5 commits: avcodec: split ffmpeg_OpenVa

Steve Lhomme (@robUx4) gitlab at videolan.org
Tue Dec 17 11:19:21 UTC 2024



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
15a5fcc9 by Thomas Guillem at 2024-12-17T10:58:02+00:00
avcodec: split ffmpeg_OpenVa

Into lavc_UpdateHWVideoFormat() + ffmpeg_OpenVa().

lavc_UpdateHWVideoFormat() call lavc_UpdateVideoFormat() and create
the decoder device that is now passed to ffmpeg_OpenVa().

This will be needed to restart vlc_va when keeping the same decoder
device.

- - - - -
095a093c by Thomas Guillem at 2024-12-17T10:58:02+00:00
avcodec: remove dec_device from lavc_UpdateVideoFormat()

It is needed only from lavc_UpdateHWVideoFormat()

- - - - -
4f293243 by Thomas Guillem at 2024-12-17T10:58:02+00:00
avcodec: add ffmpeg_CloseVa

- - - - -
f587d349 by Thomas Guillem at 2024-12-17T10:58:02+00:00
avcodec: va: recreate module if use_hwframes

- - - - -
acf6f375 by Thomas Guillem at 2024-12-17T10:58:02+00:00
avcodec: vaapi: set use_hwframes

- - - - -


3 changed files:

- modules/codec/avcodec/va.h
- modules/codec/avcodec/vaapi.c
- modules/codec/avcodec/video.c


Changes:

=====================================
modules/codec/avcodec/va.h
=====================================
@@ -66,6 +66,13 @@ struct vlc_va_cfg
      * to this pointer.
      */
     vlc_video_context *vctx_out;
+
+    /**
+     * Indicate if the module is using the new AVHWFramesContext API
+     *
+     * False, by default, set to true if the module is using this API
+     */
+    bool use_hwframes;
 };
 
 struct vlc_va_operations {


=====================================
modules/codec/avcodec/vaapi.c
=====================================
@@ -283,6 +283,7 @@ static int Create(vlc_va_t *va, struct vlc_va_cfg *cfg)
     va->ops = &ops;
     va->sys = vctx;
     cfg->vctx_out = vctx;
+    cfg->use_hwframes = true;
     return VLC_SUCCESS;
 }
 


=====================================
modules/codec/avcodec/video.c
=====================================
@@ -128,6 +128,7 @@ typedef struct
     int profile;
     int level;
     vlc_video_context *vctx_out;
+    bool use_hwframes;
 
     // decoder output seen by lavc, regardless of texture padding
     unsigned decoder_width;
@@ -363,8 +364,7 @@ static int lavc_GetVideoFormat(decoder_t *dec, video_format_t *restrict fmt,
 
 static int lavc_UpdateVideoFormat(decoder_t *dec, AVCodecContext *ctx,
                                   enum AVPixelFormat fmt,
-                                  enum AVPixelFormat swfmt,
-                                  vlc_decoder_device **pp_dec_device)
+                                  enum AVPixelFormat swfmt)
 {
     video_format_t fmt_out;
     int val;
@@ -408,11 +408,6 @@ static int lavc_UpdateVideoFormat(decoder_t *dec, AVCodecContext *ctx,
     p_sys->decoder_width  = dec->fmt_out.video.i_width;
     p_sys->decoder_height = dec->fmt_out.video.i_height;
 
-    if (pp_dec_device)
-    {
-        *pp_dec_device = decoder_GetDecoderDevice(dec);
-        return *pp_dec_device == NULL;
-    }
     return 0;
 }
 
@@ -713,12 +708,10 @@ static int InitVideoDecCommon( decoder_t *p_dec )
     return VLC_SUCCESS;
 }
 
-static int ffmpeg_OpenVa(decoder_t *p_dec, AVCodecContext *p_context,
-                         enum AVPixelFormat hwfmt, enum AVPixelFormat swfmt,
-                         const AVPixFmtDescriptor *src_desc)
+static int lavc_UpdateHWVideoFormat(decoder_t *p_dec, AVCodecContext *p_context,
+                                    enum AVPixelFormat hwfmt, enum AVPixelFormat swfmt,
+                                    vlc_decoder_device **pp_dec_device)
 {
-    decoder_sys_t *p_sys = p_dec->p_sys;
-
     if( hwfmt == AV_PIX_FMT_NONE )
         return VLC_EGENERIC;
 
@@ -730,24 +723,52 @@ static int ffmpeg_OpenVa(decoder_t *p_dec, AVCodecContext *p_context,
         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))
+    if (lavc_UpdateVideoFormat(p_dec, p_context, hwfmt, swfmt))
         return VLC_EGENERIC; /* Unsupported brand of hardware acceleration */
 
+    *pp_dec_device = decoder_GetDecoderDevice(p_dec);
+    if (*pp_dec_device == NULL)
+        return VLC_EGENERIC;
+
+    return VLC_SUCCESS;
+}
+
+static void ffmpeg_CloseVa(decoder_t *p_dec, AVCodecContext *context)
+{
+    decoder_sys_t *p_sys = p_dec->p_sys;
+    assert(p_sys->p_va != NULL);
+    assert(p_sys->vctx_out != NULL);
+
+    vlc_va_Delete(p_sys->p_va, NULL);
+    p_sys->p_va = NULL;
+    vlc_video_context_Release(p_sys->vctx_out);
+    p_sys->vctx_out = NULL;
+    p_sys->use_hwframes = false;
+
+    if (context != NULL)
+        context->hwaccel_context = NULL;
+}
+
+static int ffmpeg_OpenVa(decoder_t *p_dec, AVCodecContext *p_context,
+                         enum AVPixelFormat hwfmt,
+                         const AVPixFmtDescriptor *src_desc,
+                         vlc_decoder_device *dec_device)
+{
+    decoder_sys_t *p_sys = p_dec->p_sys;
+
     p_dec->fmt_out.video.i_chroma = 0; // make sure the va sets its output chroma
     struct vlc_va_cfg cfg = {
         .avctx = p_context,
         .hwfmt = hwfmt,
         .desc = src_desc,
         .fmt_in = p_dec->fmt_in,
-        .dec_device = init_device,
+        .dec_device = dec_device,
         .video_fmt_out = &p_dec->fmt_out.video,
         .vctx_out = NULL,
+        .use_hwframes = false,
     };
     vlc_va_t *va = vlc_va_New(VLC_OBJECT(p_dec), &cfg);
-    if (init_device)
-        vlc_decoder_device_Release(init_device);
 
     if (va == NULL)
         return VLC_EGENERIC; /* Unsupported codec profile or such */
@@ -764,9 +785,30 @@ static int ffmpeg_OpenVa(decoder_t *p_dec, AVCodecContext *p_context,
     p_sys->p_va = va;
     p_sys->vctx_out = vlc_video_context_Hold( cfg.vctx_out );
     p_sys->pix_fmt = hwfmt;
+    p_sys->use_hwframes = cfg.use_hwframes;
     return VLC_SUCCESS;
 }
 
+static int ffmpeg_RecreateVa(decoder_t *p_dec, AVCodecContext *p_context,
+                             enum AVPixelFormat hwfmt, enum AVPixelFormat swfmt)
+{
+    decoder_sys_t *p_sys = p_dec->p_sys;
+    assert(p_sys->vctx_out != NULL);
+
+    vlc_decoder_device *dec_device =
+        vlc_video_context_HoldDevice(p_sys->vctx_out);
+
+    ffmpeg_CloseVa(p_dec, p_context);
+
+    const AVPixFmtDescriptor *src_desc = av_pix_fmt_desc_get(swfmt);
+
+    int ret = ffmpeg_OpenVa(p_dec, p_context, p_sys->pix_fmt,
+                            src_desc, dec_device);
+    if (dec_device != NULL)
+        vlc_decoder_device_Release(dec_device);
+    return ret;
+}
+
 static const enum AVPixelFormat hwfmts[] =
 {
 #ifdef _WIN32
@@ -874,7 +916,17 @@ int InitVideoHwDec( vlc_object_t *obj )
 
     for( size_t i = 0; hwfmts[i] != AV_PIX_FMT_NONE; i++ )
     {
-        if (ffmpeg_OpenVa(p_dec, p_context, hwfmts[i], p_context->sw_pix_fmt, src_desc) == VLC_SUCCESS)
+        vlc_decoder_device *dec_device;
+        int ret = lavc_UpdateHWVideoFormat(p_dec, p_context, hwfmts[i],
+                                           p_context->sw_pix_fmt, &dec_device);
+        if (ret != VLC_SUCCESS)
+            continue;
+
+        ret = ffmpeg_OpenVa(p_dec, p_context, hwfmts[i], src_desc, dec_device);
+        if (dec_device != NULL)
+            vlc_decoder_device_Release(dec_device);
+
+        if (ret == VLC_SUCCESS)
             // we have a matching hardware decoder
             return VLC_SUCCESS;
     }
@@ -1562,7 +1614,7 @@ static int DecodeBlock( decoder_t *p_dec, block_t **pp_block )
              * then picture buffer can be allocated. */
             if (p_sys->p_va == NULL
              && lavc_UpdateVideoFormat(p_dec, p_context, p_context->pix_fmt,
-                                       p_context->pix_fmt, NULL) == 0
+                                       p_context->pix_fmt) == 0
              && decoder_UpdateVideoOutput(p_dec, NULL) == 0)
                 p_pic = decoder_NewPicture(p_dec);
 
@@ -1694,11 +1746,7 @@ void EndVideoDec( vlc_object_t *obj )
     avcodec_free_context( &ctx );
 
     if( p_sys->p_va )
-    {
-        vlc_va_Delete( p_sys->p_va, NULL );
-        vlc_video_context_Release( p_sys->vctx_out );
-        p_sys->vctx_out = NULL;
-    }
+        ffmpeg_CloseVa(p_dec, NULL);
 
     free( p_sys );
 }
@@ -1928,7 +1976,7 @@ static int lavc_GetFrame(struct AVCodecContext *ctx, AVFrame *frame, int flags)
         /* Most unaccelerated decoders do not call get_format(), so we need to
          * update the output video format here. The MT semaphore must be held
          * to protect p_dec->fmt_out. */
-        if (lavc_UpdateVideoFormat(dec, ctx, ctx->pix_fmt, ctx->pix_fmt, NULL) ||
+        if (lavc_UpdateVideoFormat(dec, ctx, ctx->pix_fmt, ctx->pix_fmt) ||
             decoder_UpdateVideoOutput(dec, NULL))
         {
             vlc_mutex_unlock(&sys->lock);
@@ -1961,6 +2009,7 @@ static enum AVPixelFormat ffmpeg_GetFormat( AVCodecContext *p_context,
     /* Enumerate available formats */
     enum AVPixelFormat defaultfmt = avcodec_default_get_format(p_context, pi_fmt);
     enum AVPixelFormat swfmt = AV_PIX_FMT_NONE;
+    enum AVPixelFormat skipfmt = AV_PIX_FMT_NONE;
     bool can_hwaccel = false;
 
     for (size_t i = 0; pi_fmt[i] != AV_PIX_FMT_NONE; i++)
@@ -2029,7 +2078,25 @@ static enum AVPixelFormat ffmpeg_GetFormat( AVCodecContext *p_context,
      for (size_t i = 0; pi_fmt[i] != AV_PIX_FMT_NONE; i++)
         if (pi_fmt[i] == p_sys->pix_fmt)
         {
-            msg_Dbg(p_dec, "reusing decoder output format %d", pi_fmt[i]);
+            if (p_sys->use_hwframes)
+            {
+                /* When using hwframes API, ffmpeg is reseting the hardware
+                 * context of the AVCodecContext before calling the
+                 * `get_format` callback. Therefore, the va context need to be
+                 * closed and opened again. */
+                msg_Dbg(p_dec, "recreating decoder output format %d", pi_fmt[i]);
+                int ret = ffmpeg_RecreateVa(p_dec, p_context, p_sys->pix_fmt,
+                                            swfmt);
+                if (ret != VLC_SUCCESS)
+                {
+                    msg_Err(p_dec, "error restarting va module");
+                    skipfmt = p_sys->pix_fmt; /* Don't retry this fmt */
+                    p_sys->pix_fmt = AV_PIX_FMT_NONE;
+                    goto no_reuse;
+                }
+            }
+            else
+                msg_Dbg(p_dec, "reusing decoder output format %d", pi_fmt[i]);
             return p_sys->pix_fmt;
         }
 
@@ -2041,11 +2108,7 @@ no_reuse:
         // 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 );
-        p_sys->vctx_out = NULL;
-        p_context->hwaccel_context = NULL;
+        ffmpeg_CloseVa(p_dec, p_context);
     }
 
     p_sys->profile = p_context->profile;
@@ -2063,7 +2126,20 @@ no_reuse:
             if( hwfmts[i] == pi_fmt[j] )
                 hwfmt = hwfmts[i];
 
-        if (ffmpeg_OpenVa(p_dec, p_context, hwfmt, swfmt, src_desc) != VLC_SUCCESS)
+        if (hwfmt == skipfmt)
+            continue;
+
+        vlc_decoder_device *dec_device;
+        int ret = lavc_UpdateHWVideoFormat(p_dec, p_context, hwfmt, swfmt,
+                                           &dec_device);
+        if (ret != VLC_SUCCESS)
+            continue;
+
+        ret = ffmpeg_OpenVa(p_dec, p_context, hwfmt, src_desc, dec_device);
+        if (dec_device != NULL)
+            vlc_decoder_device_Release(dec_device);
+
+        if (ret != VLC_SUCCESS)
             continue;
 
         return hwfmt;



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/ec2645d1accbd2f666577fca8f74d61d6045f4d4...acf6f37533e59da1750e9c4285edbc7e60c964ce

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/ec2645d1accbd2f666577fca8f74d61d6045f4d4...acf6f37533e59da1750e9c4285edbc7e60c964ce
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