[vlc-devel] [PATCH 3/4] d3d11va: use the same output format order as the vout for safer compatibility

Steve Lhomme robux4 at gmail.com
Mon Jul 20 13:33:06 CEST 2015


From: Steve Lhomme <robUx4 at gmail.com>

in debug builds log all the support DXGI output formats
---
 modules/codec/Makefile.am             |  1 +
 modules/codec/avcodec/d3d11va.c       | 64 +++++++++++++++--------
 modules/video_chroma/dxgi_fmt.c       | 98 +++++++++++++++++++++++++++++++++++
 modules/video_chroma/dxgi_fmt.h       | 43 +++++++++++++++
 modules/video_output/Makefile.am      |  1 +
 modules/video_output/msw/direct3d11.c | 67 +++++++-----------------
 6 files changed, 203 insertions(+), 71 deletions(-)
 create mode 100644 modules/video_chroma/dxgi_fmt.c
 create mode 100644 modules/video_chroma/dxgi_fmt.h

diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am
index 4ae29ac..b1fdcf8 100644
--- a/modules/codec/Makefile.am
+++ b/modules/codec/Makefile.am
@@ -359,6 +359,7 @@ endif
 
 libd3d11va_plugin_la_SOURCES = \
 	codec/avcodec/d3d11va.c codec/avcodec/directx_va.c codec/avcodec/directx_va.h \
+	video_chroma/dxgi_fmt.c video_chroma/dxgi_fmt.h \
 	packetizer/h264_nal.c packetizer/h264_nal.h
 libd3d11va_plugin_la_LIBADD = -lole32 -luuid
 if HAVE_AVCODEC_D3D11VA
diff --git a/modules/codec/avcodec/d3d11va.c b/modules/codec/avcodec/d3d11va.c
index 54a30ca..d00e634 100644
--- a/modules/codec/avcodec/d3d11va.c
+++ b/modules/codec/avcodec/d3d11va.c
@@ -44,9 +44,11 @@
 #include "directx_va.h"
 
 #define COBJMACROS
+#define INITGUID
+#include <d3d11.h>
 #include <libavcodec/d3d11va.h>
 
-#include "../../video_chroma/copy.h"
+#include "../../video_chroma/dxgi_fmt.h"
 
 static int Open(vlc_va_t *, AVCodecContext *, enum PixelFormat,
                 const es_format_t *, picture_sys_t *p_sys);
@@ -618,38 +620,54 @@ static int DxSetupOutput(vlc_va_t *va, const GUID *input)
     directx_sys_t *dx_sys = &va->sys->dx_sys;
     HRESULT hr;
 
-    /* */
-    BOOL is_supported = false;
-    hr = ID3D11VideoDevice_CheckVideoDecoderFormat((ID3D11VideoDevice*) dx_sys->d3ddec, input, DXGI_FORMAT_NV12, &is_supported);
-    if (SUCCEEDED(hr) && is_supported)
-        msg_Dbg(va, "NV12 is supported for output");
+#ifndef NDEBUG
+    BOOL bSupported = false;
+    for (int format = 0; format < 188; format++) {
+        hr = ID3D11VideoDevice_CheckVideoDecoderFormat((ID3D11VideoDevice*) dx_sys->d3ddec, input, format, &bSupported);
+        if (SUCCEEDED(hr) && bSupported)
+            msg_Dbg(va, "format %s is supported for output", DxgiFormatToStr(format));
+    }
+#endif
 
+    DXGI_FORMAT processorInput[4];
+    int idx = 0;
     if ( va->sys->render != DXGI_FORMAT_UNKNOWN )
+        processorInput[idx++] = va->sys->render;
+    processorInput[idx++] = DXGI_FORMAT_NV12;
+    processorInput[idx++] = DXGI_FORMAT_UNKNOWN;
+
+    /* */
+    for (idx = 0; processorInput[idx] != DXGI_FORMAT_UNKNOWN; ++idx)
     {
-        is_supported = false;
-        hr = ID3D11VideoDevice_CheckVideoDecoderFormat((ID3D11VideoDevice*) dx_sys->d3ddec, input, va->sys->render, &is_supported);
+        BOOL is_supported = false;
+        hr = ID3D11VideoDevice_CheckVideoDecoderFormat((ID3D11VideoDevice*) dx_sys->d3ddec, input, processorInput[idx], &is_supported);
         if (SUCCEEDED(hr) && is_supported)
+            msg_Dbg(va, "%s is supported for output", DxgiFormatToStr(processorInput[idx]));
+        else
         {
-            /* We have our solution */
-            msg_Dbg(va, "Using decoder output from picture source.");
-            return VLC_SUCCESS;
+            msg_Dbg(va, "Can't get a decoder for output format %s.", DxgiFormatToStr(processorInput[idx]));
+            continue;
         }
-        msg_Dbg(va, "Output format from picture source not supported.");
-        return VLC_EGENERIC;
-    }
-    else
-    {
-        /* */
-        is_supported = false;
-        hr = ID3D11VideoDevice_CheckVideoDecoderFormat((ID3D11VideoDevice*) dx_sys->d3ddec, input, DXGI_FORMAT_NV12, &is_supported);
-        if (SUCCEEDED(hr) && is_supported)
+
+        // check if we can create render texture of that format
+        // check the decoder can output to that format
+        const UINT i_quadSupportFlags = D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_SHADER_LOAD;
+        UINT i_formatSupport;
+        bool b_needsProcessor = true;
+        if( SUCCEEDED( ID3D11Device_CheckFormatSupport((ID3D11Device*) dx_sys->d3ddev,
+                                                       processorInput[idx],
+                                                       &i_formatSupport)) &&
+                ( i_formatSupport & i_quadSupportFlags ) == i_quadSupportFlags )
+            b_needsProcessor = false;
+
+        if ( !b_needsProcessor )
         {
-            /* We have our solution */
-            msg_Dbg(va, "Using decoder output NV12");
-            va->sys->render = DXGI_FORMAT_NV12;
+            va->sys->render = processorInput[idx];
             return VLC_SUCCESS;
         }
     }
+
+    msg_Dbg(va, "Output format from picture source not supported.");
     return VLC_EGENERIC;
 }
 
diff --git a/modules/video_chroma/dxgi_fmt.c b/modules/video_chroma/dxgi_fmt.c
new file mode 100644
index 0000000..9772652
--- /dev/null
+++ b/modules/video_chroma/dxgi_fmt.c
@@ -0,0 +1,98 @@
+/*****************************************************************************
+ * d3d11_surface.c : D3D11 GPU surface conversion module for vlc
+ *****************************************************************************
+ * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
+ *
+ * Authors: Steve Lhomme <robux4 at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "dxgi_fmt.h"
+
+typedef struct
+{
+    const char   *name;
+    DXGI_FORMAT  format;
+} dxgi_format_t;
+
+static const dxgi_format_t dxgi_formats[] = {
+    { "NV12",        DXGI_FORMAT_NV12                },
+    { "I420_OPAQUE", DXGI_FORMAT_420_OPAQUE          },
+    { "RGBA",        DXGI_FORMAT_R8G8B8A8_UNORM      },
+    { "RGBA_SRGB",   DXGI_FORMAT_R8G8B8A8_UNORM_SRGB },
+    { "BGRX",        DXGI_FORMAT_B8G8R8X8_UNORM      },
+    { "BGRA",        DXGI_FORMAT_B8G8R8A8_UNORM      },
+    { "BGRA_SRGB",   DXGI_FORMAT_B8G8R8A8_UNORM_SRGB },
+    { "AYUV",        DXGI_FORMAT_AYUV                },
+    { "YUY2",        DXGI_FORMAT_YUY2                },
+    { "AI44",        DXGI_FORMAT_AI44                },
+    { "P8",          DXGI_FORMAT_P8                  },
+    { "A8P8",        DXGI_FORMAT_A8P8                },
+    { "B5G6R5",      DXGI_FORMAT_B5G6R5_UNORM        },
+    { "Y416",        DXGI_FORMAT_Y416                },
+    { "P010",        DXGI_FORMAT_P010                },
+    { "Y210",        DXGI_FORMAT_Y210                },
+    { "Y410",        DXGI_FORMAT_Y410                },
+    { "NV11",        DXGI_FORMAT_NV11                },
+    { "UNKNOWN",     DXGI_FORMAT_UNKNOWN             },
+
+    { NULL, 0,}
+};
+
+static const d3d_format_t d3d_formats[] = {
+    { "I420",     DXGI_FORMAT_NV12,           VLC_CODEC_I420,     DXGI_FORMAT_R8_UNORM,           DXGI_FORMAT_R8G8_UNORM },
+    { "YV12",     DXGI_FORMAT_NV12,           VLC_CODEC_YV12,     DXGI_FORMAT_R8_UNORM,           DXGI_FORMAT_R8G8_UNORM },
+    { "NV12",     DXGI_FORMAT_NV12,           VLC_CODEC_NV12,     DXGI_FORMAT_R8_UNORM,           DXGI_FORMAT_R8G8_UNORM },
+    { "VA_NV12",  DXGI_FORMAT_NV12,           VLC_CODEC_D3D11_OPAQUE, DXGI_FORMAT_R8_UNORM,       DXGI_FORMAT_R8G8_UNORM },
+#ifdef BROKEN_PIXEL
+    { "YUY2",     DXGI_FORMAT_YUY2,           VLC_CODEC_I422,     DXGI_FORMAT_R8G8B8A8_UNORM,     0 },
+    { "AYUV",     DXGI_FORMAT_AYUV,           VLC_CODEC_YUVA,     DXGI_FORMAT_R8G8B8A8_UNORM,     0 },
+    { "Y416",     DXGI_FORMAT_Y416,           VLC_CODEC_I444_16L, DXGI_FORMAT_R16G16B16A16_UINT,  0 },
+#endif
+#ifdef UNTESTED
+    { "P010",     DXGI_FORMAT_P010,           VLC_CODEC_I420_10L, DXGI_FORMAT_R16_UNORM,          DXGI_FORMAT_R16_UNORM },
+    { "Y210",     DXGI_FORMAT_Y210,           VLC_CODEC_I422_10L, DXGI_FORMAT_R16G16B16A16_UNORM, 0 },
+    { "Y410",     DXGI_FORMAT_Y410,           VLC_CODEC_I444_10L, DXGI_FORMAT_R10G10B10A2_UNORM,  0 },
+    { "NV11",     DXGI_FORMAT_NV11,           VLC_CODEC_I411,     DXGI_FORMAT_R8_UNORM,           DXGI_FORMAT_R8G8_UNORM },
+#endif
+    { "R8G8B8A8", DXGI_FORMAT_R8G8B8A8_UNORM, VLC_CODEC_RGBA,     DXGI_FORMAT_R8G8B8A8_UNORM,     0 },
+    { "VA_RGBA",  DXGI_FORMAT_R8G8B8A8_UNORM, VLC_CODEC_D3D11_OPAQUE, DXGI_FORMAT_R8G8B8A8_UNORM, 0 },
+    { "B8G8R8A8", DXGI_FORMAT_B8G8R8A8_UNORM, VLC_CODEC_BGRA,     DXGI_FORMAT_B8G8R8A8_UNORM,     0 },
+    { "VA_BGRA",  DXGI_FORMAT_B8G8R8A8_UNORM, VLC_CODEC_D3D11_OPAQUE, DXGI_FORMAT_B8G8R8A8_UNORM, 0 },
+    { "R8G8B8X8", DXGI_FORMAT_B8G8R8X8_UNORM, VLC_CODEC_RGB32,    DXGI_FORMAT_B8G8R8X8_UNORM,     0 },
+    { "B5G6R5",   DXGI_FORMAT_B5G6R5_UNORM,   VLC_CODEC_RGB16,    DXGI_FORMAT_B5G6R5_UNORM,       0 },
+
+    { NULL, 0, 0, 0, 0}
+};
+
+const char *DxgiFormatToStr(DXGI_FORMAT format)
+{
+    for (const dxgi_format_t *f = dxgi_formats; f->name != NULL; ++f)
+    {
+        if (f->format == format)
+            return f->name;
+    }
+    return NULL;
+}
+
+const d3d_format_t *GetRenderFormatList(void)
+{
+    return d3d_formats;
+}
diff --git a/modules/video_chroma/dxgi_fmt.h b/modules/video_chroma/dxgi_fmt.h
new file mode 100644
index 0000000..4a0c03d
--- /dev/null
+++ b/modules/video_chroma/dxgi_fmt.h
@@ -0,0 +1,43 @@
+/*****************************************************************************
+ * d3d11_surface.c : DXGI helper calls
+ *****************************************************************************
+ * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
+ *
+ * Authors: Steve Lhomme <robux4 at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef _VLC_VIDEOCHROMA_DXGI_H
+#define _VLC_VIDEOCHROMA_DXGI_H 1
+
+#include <dxgiformat.h>
+
+#include <vlc_common.h>
+#include <vlc_fourcc.h>
+
+typedef struct
+{
+    const char   *name;
+    DXGI_FORMAT  formatTexture;
+    vlc_fourcc_t fourcc;
+    DXGI_FORMAT  formatY;
+    DXGI_FORMAT  formatUV;
+} d3d_format_t;
+
+extern const char *DxgiFormatToStr(DXGI_FORMAT format);
+extern const d3d_format_t *GetRenderFormatList(void);
+
+#endif /* _VLC_VIDEOCHROMA_DXGI_H */
diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am
index fb5b20d..be79e90 100644
--- a/modules/video_output/Makefile.am
+++ b/modules/video_output/Makefile.am
@@ -178,6 +178,7 @@ vout_LTLIBRARIES += $(LTLIBdirect3d9)
 EXTRA_LTLIBRARIES += libdirect3d9_plugin.la
 
 libdirect3d11_plugin_la_SOURCES = video_output/msw/direct3d11.c \
+ video_chroma/dxgi_fmt.c video_chroma/dxgi_fmt.h \
  video_output/msw/common.c video_output/msw/common.h
 libdirect3d11_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) \
  -DMODULE_NAME_IS_direct3d11
diff --git a/modules/video_output/msw/direct3d11.c b/modules/video_output/msw/direct3d11.c
index e58287f..9894a78 100644
--- a/modules/video_output/msw/direct3d11.c
+++ b/modules/video_output/msw/direct3d11.c
@@ -38,6 +38,8 @@
 
 #include "common.h"
 
+#include "../../video_chroma/dxgi_fmt.h"
+
 #if !VLC_WINSTORE_APP
 # if USE_DXGI
 #  define D3D11CreateDeviceAndSwapChain(args...) sys->OurD3D11CreateDeviceAndSwapChain(args)
@@ -78,39 +80,6 @@ vlc_module_begin ()
     set_callbacks(Open, Close)
 vlc_module_end ()
 
-typedef struct
-{
-    const char   *name;
-    DXGI_FORMAT  formatTexture;
-    vlc_fourcc_t fourcc;
-    DXGI_FORMAT  formatY;
-    DXGI_FORMAT  formatUV;
-} d3d_format_t;
-
-static const d3d_format_t d3d_formats[] = {
-    { "I420",     DXGI_FORMAT_NV12,           VLC_CODEC_I420,     DXGI_FORMAT_R8_UNORM,           DXGI_FORMAT_R8G8_UNORM },
-    { "YV12",     DXGI_FORMAT_NV12,           VLC_CODEC_YV12,     DXGI_FORMAT_R8_UNORM,           DXGI_FORMAT_R8G8_UNORM },
-    { "NV12",     DXGI_FORMAT_NV12,           VLC_CODEC_NV12,     DXGI_FORMAT_R8_UNORM,           DXGI_FORMAT_R8G8_UNORM },
-    { "VA_NV12",  DXGI_FORMAT_NV12,           VLC_CODEC_D3D11_OPAQUE, DXGI_FORMAT_R8_UNORM,       DXGI_FORMAT_R8G8_UNORM },
-#ifdef BROKEN_PIXEL
-    { "YUY2",     DXGI_FORMAT_YUY2,           VLC_CODEC_I422,     DXGI_FORMAT_R8G8B8A8_UNORM,     0 },
-    { "AYUV",     DXGI_FORMAT_AYUV,           VLC_CODEC_YUVA,     DXGI_FORMAT_R8G8B8A8_UNORM,     0 },
-    { "Y416",     DXGI_FORMAT_Y416,           VLC_CODEC_I444_16L, DXGI_FORMAT_R16G16B16A16_UINT,  0 },
-#endif
-#ifdef UNTESTED
-    { "P010",     DXGI_FORMAT_P010,           VLC_CODEC_I420_10L, DXGI_FORMAT_R16_UNORM,          DXGI_FORMAT_R16_UNORM },
-    { "Y210",     DXGI_FORMAT_Y210,           VLC_CODEC_I422_10L, DXGI_FORMAT_R16G16B16A16_UNORM, 0 },
-    { "Y410",     DXGI_FORMAT_Y410,           VLC_CODEC_I444_10L, DXGI_FORMAT_R10G10B10A2_UNORM,  0 },
-    { "NV11",     DXGI_FORMAT_NV11,           VLC_CODEC_I411,     DXGI_FORMAT_R8_UNORM,           DXGI_FORMAT_R8G8_UNORM },
-#endif
-    { "R8G8B8A8", DXGI_FORMAT_R8G8B8A8_UNORM, VLC_CODEC_RGBA,     DXGI_FORMAT_R8G8B8A8_UNORM,     0 },
-    { "B8G8R8A8", DXGI_FORMAT_B8G8R8A8_UNORM, VLC_CODEC_BGRA,     DXGI_FORMAT_B8G8R8A8_UNORM,     0 },
-    { "R8G8B8X8", DXGI_FORMAT_B8G8R8X8_UNORM, VLC_CODEC_RGB32,    DXGI_FORMAT_B8G8R8X8_UNORM,     0 },
-    { "B5G6R5",   DXGI_FORMAT_B5G6R5_UNORM,   VLC_CODEC_RGB16,    DXGI_FORMAT_B5G6R5_UNORM,       0 },
-
-    { NULL, 0, 0, 0, 0}
-};
-
 #ifdef HAVE_ID3D11VIDEODECODER 
 /* VLC_CODEC_D3D11_OPAQUE */
 struct picture_sys_t
@@ -1028,20 +997,21 @@ static int Direct3D11Open(vout_display_t *vd, video_format_t *fmt)
     // look for the request pixel format first
     UINT i_quadSupportFlags = D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_SHADER_LOAD;
     UINT i_formatSupport;
-    for (unsigned i = 0; d3d_formats[i].name != 0; i++)
+    for (const d3d_format_t *output_format = GetRenderFormatList();
+         output_format->name != NULL; ++output_format)
     {
-        if( i_src_chroma == d3d_formats[i].fourcc)
+        if( i_src_chroma == output_format->fourcc)
         {
             if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys->d3ddevice,
-                                                           d3d_formats[i].formatTexture,
+                                                           output_format->formatTexture,
                                                            &i_formatSupport)) &&
                     ( i_formatSupport & i_quadSupportFlags ) == i_quadSupportFlags )
             {
-                msg_Dbg(vd, "Using pixel format %s", d3d_formats[i].name );
-                fmt->i_chroma = d3d_formats[i].fourcc;
-                sys->picQuadConfig.textureFormat      = d3d_formats[i].formatTexture;
-                sys->picQuadConfig.resourceFormatYRGB = d3d_formats[i].formatY;
-                sys->picQuadConfig.resourceFormatUV   = d3d_formats[i].formatUV;
+                msg_Dbg(vd, "Using pixel format %s", output_format->name );
+                fmt->i_chroma = output_format->fourcc;
+                sys->picQuadConfig.textureFormat      = output_format->formatTexture;
+                sys->picQuadConfig.resourceFormatYRGB = output_format->formatY;
+                sys->picQuadConfig.resourceFormatUV   = output_format->formatUV;
                 break;
             }
         }
@@ -1050,18 +1020,19 @@ static int Direct3D11Open(vout_display_t *vd, video_format_t *fmt)
     // look for any pixel format that we can handle
     if ( !fmt->i_chroma )
     {
-        for (unsigned i = 0; d3d_formats[i].name != 0; i++)
+        for (const d3d_format_t *output_format = GetRenderFormatList();
+             output_format->name != NULL; ++output_format)
         {
             if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys->d3ddevice,
-                                                           d3d_formats[i].formatTexture,
+                                                           output_format->formatTexture,
                                                            &i_formatSupport)) &&
                     ( i_formatSupport & i_quadSupportFlags ) == i_quadSupportFlags )
             {
-                msg_Dbg(vd, "Using pixel format %s", d3d_formats[i].name );
-                fmt->i_chroma = d3d_formats[i].fourcc;
-                sys->picQuadConfig.textureFormat      = d3d_formats[i].formatTexture;
-                sys->picQuadConfig.resourceFormatYRGB = d3d_formats[i].formatY;
-                sys->picQuadConfig.resourceFormatUV   = d3d_formats[i].formatUV;
+                msg_Dbg(vd, "Using pixel format %s", output_format->name );
+                fmt->i_chroma = output_format->fourcc;
+                sys->picQuadConfig.textureFormat      = output_format->formatTexture;
+                sys->picQuadConfig.resourceFormatYRGB = output_format->formatY;
+                sys->picQuadConfig.resourceFormatUV   = output_format->formatUV;
                 break;
             }
         }
-- 
2.4.2




More information about the vlc-devel mailing list