[vlc-devel] [PATCH] [RFC] avcodec: check for VA capabilities early so we can decide the thread count

Steve Lhomme robux4 at ycbcr.xyz
Fri Apr 20 12:24:25 CEST 2018


Hardware decoding with multithread in libavcodec is not really supported and
discouraged. We use it because we need many threads for software decoding and
we couldn't easily switch between the two modes. But it has perfomance issues
that can result in display issues.

Here's an example of D3D11VA decoding of a 4K H264 stream that has lags because
of that:
https://drive.google.com/open?id=1Q_0ZamI_w8cBtzwHlSUh2uVClOpwd6kR
The GPU feeds bursts of 6 frames to the GPU and as a result some of the frames
are late to decode. Even when using 2 threads there as still lag issues, with
Intel and NVIDIA (didn't try AMD).

This patch checks whether a HW decoder is likely to be used. If this is the
case we start lavc with only one thread. The detection is restrictive so we
only do it when we are sure, otherwise we fall back to the current case.

If there's ever a case where we switch from HW to SW decoding only one thread
will be used, but it's very unlikely to happen.

WIN32 only for now.
---
 modules/codec/Makefile.am     |  4 ++-
 modules/codec/avcodec/video.c | 77 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+), 1 deletion(-)

diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am
index 1615fd58e1..cb45bc5fec 100644
--- a/modules/codec/Makefile.am
+++ b/modules/codec/Makefile.am
@@ -377,7 +377,9 @@ 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/h264_nal.c packetizer/h264_nal.h \
+	packetizer/hevc_nal.c packetizer/hevc_nal.h
 if ENABLE_SOUT
 libavcodec_plugin_la_SOURCES += codec/avcodec/encoder.c
 endif
diff --git a/modules/codec/avcodec/video.c b/modules/codec/avcodec/video.c
index b505d34846..372c5de408 100644
--- a/modules/codec/avcodec/video.c
+++ b/modules/codec/avcodec/video.c
@@ -49,6 +49,9 @@
 
 #include "../codec/cc.h"
 
+#include "../../packetizer/h264_nal.h"
+#include "../../packetizer/hevc_nal.h"
+
 /*****************************************************************************
  * decoder_sys_t : decoder descriptor
  *****************************************************************************/
@@ -450,6 +453,79 @@ static int OpenVideoCodec( decoder_t *p_dec )
     return 0;
 }
 
+#ifdef _WIN32
+static bool hasVaDecoder(decoder_t *p_dec)
+{
+    decoder_sys_t *p_sys = p_dec->p_sys;
+    vlc_va_t *va;
+    /* always align to 128 pixels */
+    p_sys->p_context->coded_width  = (p_dec->fmt_in.video.i_width  + 0x7F) & ~0x7F;
+    p_sys->p_context->coded_height = (p_dec->fmt_in.video.i_height + 0x7F) & ~0x7F;
+#if LIBAVUTIL_VERSION_CHECK(54, 13, 1, 24, 100)
+    va = vlc_va_New( VLC_OBJECT(p_dec), p_sys->p_context, AV_PIX_FMT_D3D11VA_VLD, &p_dec->fmt_in, NULL );
+    if (va != NULL)
+    {
+        vlc_va_Delete( va, NULL );
+        return true;
+    }
+#endif
+    va = vlc_va_New( VLC_OBJECT(p_dec), p_sys->p_context, AV_PIX_FMT_DXVA2_VLD, &p_dec->fmt_in, NULL );
+    if (va != NULL)
+    {
+        vlc_va_Delete( va, NULL );
+        return true;
+    }
+    return false;
+}
+#endif
+
+static int AdjustThreadCount(decoder_t *p_dec, int i_thread_count)
+{
+    if (i_thread_count == 1)
+        return 1; /* no need to adjust for hw decoding */
+#ifdef _WIN32
+    switch (p_dec->fmt_in.i_codec)
+    {
+    case VLC_CODEC_H264:
+    {
+        uint8_t profile;
+        if (h264_get_profile_level(&p_dec->fmt_in, &profile, NULL, NULL))
+        {
+            p_dec->fmt_in.i_profile = profile;
+            if (hasVaDecoder(p_dec))
+                i_thread_count = 1;
+        }
+        break;
+    }
+    case VLC_CODEC_HEVC:
+    {
+        uint8_t profile;
+        if (hevc_get_profile_level(&p_dec->fmt_in, &profile, NULL, NULL))
+        {
+            p_dec->fmt_in.i_profile = profile;
+            if (hasVaDecoder(p_dec))
+                i_thread_count = 1;
+        }
+    }
+        break;
+    /* we don't know the profile until lavc has parsed data
+    case VLC_CODEC_VP9:
+    case VLC_CODEC_MP2V:
+    */
+    /* codecs supported regardless of the profile */
+    case VLC_CODEC_MPGV:
+    case VLC_CODEC_VC1:
+    case VLC_CODEC_WMV3:
+    {
+        if (hasVaDecoder(p_dec))
+            i_thread_count = 1;
+    }
+        break;
+    }
+#endif
+    return i_thread_count;
+}
+
 /*****************************************************************************
  * InitVideo: initialize the video decoder
  *****************************************************************************
@@ -562,6 +638,7 @@ int InitVideoDec( vlc_object_t *obj )
         i_thread_count = __MIN( i_thread_count, p_codec->id == AV_CODEC_ID_HEVC ? 10 : 6 );
 #endif
     }
+    i_thread_count = AdjustThreadCount( p_dec, i_thread_count );
     i_thread_count = __MIN( i_thread_count, p_codec->id == AV_CODEC_ID_HEVC ? 32 : 16 );
     msg_Dbg( p_dec, "allowing %d thread(s) for decoding", i_thread_count );
     p_context->thread_count = i_thread_count;
-- 
2.16.2



More information about the vlc-devel mailing list