[vlc-devel] [PATCH 5/5] vout: win32: add a Direct3D11 deinterlacer

Steve Lhomme robux4 at videolabs.io
Tue Mar 28 16:24:00 CEST 2017


---
 modules/video_chroma/d3d11_fmt.h               |   1 +
 modules/video_output/Makefile.am               |   4 +
 modules/video_output/win32/d3d11_deinterlace.c | 285 +++++++++++++++++++++++++
 modules/video_output/win32/direct3d11.c        |   8 +
 4 files changed, 298 insertions(+)
 create mode 100644 modules/video_output/win32/d3d11_deinterlace.c

diff --git a/modules/video_chroma/d3d11_fmt.h b/modules/video_chroma/d3d11_fmt.h
index a0f15f650e..cd8af84496 100644
--- a/modules/video_chroma/d3d11_fmt.h
+++ b/modules/video_chroma/d3d11_fmt.h
@@ -38,6 +38,7 @@ struct picture_sys_t
     ID3D11DeviceContext           *context;
     unsigned                      slice_index;
     ID3D11VideoProcessorInputView *processorInput; /* when used as processor input */
+    ID3D11VideoProcessorOutputView *processorOutput;
     ID3D11ShaderResourceView      *resourceView[D3D11_MAX_SHADER_VIEW];
     DXGI_FORMAT                   formatTexture;
 };
diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am
index 483a197053..0d62bb7d20 100644
--- a/modules/video_output/Makefile.am
+++ b/modules/video_output/Makefile.am
@@ -236,6 +236,10 @@ libdirect3d11_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)'
 vout_LTLIBRARIES += $(LTLIBdirect3d11)
 EXTRA_LTLIBRARIES += libdirect3d11_plugin.la
 
+libdirect3d11_deinterlace_plugin_la_SOURCES = video_output/win32/d3d11_deinterlace.c \
+  video_chroma/dxgi_fmt.c video_chroma/dxgi_fmt.h
+vout_LTLIBRARIES += libdirect3d11_deinterlace_plugin.la
+
 libdirectdraw_plugin_la_SOURCES = video_output/win32/directdraw.c \
 	video_output/win32/common.c video_output/win32/common.h \
 	video_output/win32/events.c video_output/win32/events.h \
diff --git a/modules/video_output/win32/d3d11_deinterlace.c b/modules/video_output/win32/d3d11_deinterlace.c
new file mode 100644
index 0000000000..8dfce8e9e9
--- /dev/null
+++ b/modules/video_output/win32/d3d11_deinterlace.c
@@ -0,0 +1,285 @@
+/*****************************************************************************
+ * d3d11_deinterlace.c: D3D11 deinterlacing filter
+ *****************************************************************************
+ * Copyright (C) 2017 Videolabs SAS
+ *
+ * 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 <stdlib.h>
+#include <assert.h>
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_filter.h>
+#include <vlc_picture.h>
+
+#define COBJMACROS
+#include <initguid.h>
+#include <d3d11.h>
+
+#include "../../video_chroma/d3d11_fmt.h"
+
+#ifdef __MINGW32__
+#define D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_BOB  2
+#endif
+
+struct filter_sys_t
+{
+    ID3D11VideoDevice              *d3dviddev;
+    ID3D11VideoContext             *d3dvidctx;
+    ID3D11VideoProcessor           *videoProcessor;
+    ID3D11VideoProcessorEnumerator *procEnumerator;
+};
+
+static picture_t *Deinterlace(filter_t *filter, picture_t *src)
+{
+    filter_sys_t *sys = filter->p_sys;
+    HRESULT hr;
+
+    if (!src->p_sys->processorInput)
+    {
+        D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inDesc = {
+            .FourCC = 0,
+            .ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D,
+            .Texture2D.MipSlice = 0,
+            .Texture2D.ArraySlice = src->p_sys->slice_index,
+        };
+
+        hr = ID3D11VideoDevice_CreateVideoProcessorInputView(sys->d3dviddev,
+                                                             src->p_sys->resource[KNOWN_DXGI_INDEX],
+                                                             sys->procEnumerator,
+                                                             &inDesc,
+                                                             &src->p_sys->processorInput);
+        if (FAILED(hr))
+        {
+#ifndef NDEBUG
+            msg_Dbg(filter,"Failed to create processor input for slice %d. (hr=0x%lX)", src->p_sys->slice_index, hr);
+#endif
+            return src;
+        }
+    }
+
+    picture_t *dst = filter_NewPicture(filter);
+    if (dst == NULL)
+        return src; /* cannot deinterlace without copying fields */
+
+    if (!dst->p_sys->processorOutput)
+    {
+        assert(dst->p_sys->slice_index == 0);
+
+        D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outDesc = {
+            .ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D,
+            .Texture2D.MipSlice = 0,
+        };
+
+        hr = ID3D11VideoDevice_CreateVideoProcessorOutputView(sys->d3dviddev,
+                                                             dst->p_sys->resource[KNOWN_DXGI_INDEX],
+                                                             sys->procEnumerator,
+                                                             &outDesc,
+                                                             &dst->p_sys->processorOutput);
+        if (FAILED(hr))
+        {
+#ifndef NDEBUG
+            msg_Dbg(filter,"Failed to create processor output for slice %d. (hr=0x%lX)", dst->p_sys->slice_index, hr);
+#endif
+            picture_Release(dst);
+            return src;
+        }
+    }
+
+    D3D11_VIDEO_PROCESSOR_STREAM stream = {
+        .Enable = TRUE,
+        .pInputSurface = src->p_sys->processorInput,
+    };
+
+    D3D11_VIDEO_FRAME_FORMAT frameFormat = src->b_top_field_first ?
+                D3D11_VIDEO_FRAME_FORMAT_INTERLACED_TOP_FIELD_FIRST :
+                D3D11_VIDEO_FRAME_FORMAT_INTERLACED_BOTTOM_FIELD_FIRST;
+    ID3D11VideoContext_VideoProcessorSetStreamFrameFormat(sys->d3dvidctx, sys->videoProcessor, 0, frameFormat);
+
+    hr = ID3D11VideoContext_VideoProcessorBlt(sys->d3dvidctx, sys->videoProcessor,
+                                              dst->p_sys->processorOutput,
+                                              0, 1, &stream);
+
+    picture_CopyProperties(dst, src);
+    picture_Release(src);
+    dst->b_progressive = true;
+    dst->i_nb_fields = 1;
+    return dst;
+}
+
+static int Open(vlc_object_t *obj)
+{
+    filter_t *filter = (filter_t *)obj;
+    HRESULT hr;
+    ID3D11Device *d3ddevice;
+
+    if (filter->fmt_in.video.i_chroma != VLC_CODEC_D3D11_OPAQUE
+     && filter->fmt_in.video.i_chroma != VLC_CODEC_D3D11_OPAQUE_10B)
+        return VLC_EGENERIC;
+    if (!video_format_IsSimilar(&filter->fmt_in.video, &filter->fmt_out.video))
+        return VLC_EGENERIC;
+
+    picture_t *dst = filter_NewPicture(filter);
+    if (dst == NULL)
+        return VLC_EGENERIC;
+
+    D3D11_TEXTURE2D_DESC dstDesc;
+    ID3D11Texture2D_GetDesc(dst->p_sys->texture[KNOWN_DXGI_INDEX], &dstDesc);
+
+    filter_sys_t *sys = malloc(sizeof (*sys));
+    if (unlikely(sys == NULL))
+        goto error;
+    memset(sys, 0, sizeof (*sys));
+
+    ID3D11DeviceContext_GetDevice(dst->p_sys->context, &d3ddevice);
+
+    hr = ID3D11Device_QueryInterface(d3ddevice, &IID_ID3D11VideoDevice, (void **)&sys->d3dviddev);
+    ID3D11Device_Release(d3ddevice);
+    if (FAILED(hr)) {
+       msg_Err(filter, "Could not Query ID3D11VideoDevice Interface. (hr=0x%lX)", hr);
+       goto error;
+    }
+
+    hr = ID3D11DeviceContext_QueryInterface(dst->p_sys->context, &IID_ID3D11VideoContext, (void **)&sys->d3dvidctx);
+    if (FAILED(hr)) {
+       msg_Err(filter, "Could not Query ID3D11VideoDevice Interface from the picture. (hr=0x%lX)", hr);
+       goto error;
+    }
+
+    const video_format_t *fmt = &dst->format;
+
+    ID3D11VideoProcessorEnumerator *processorEnumerator;
+    D3D11_VIDEO_PROCESSOR_CONTENT_DESC processorDesc = {
+        .InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_INTERLACED_TOP_FIELD_FIRST,
+        .InputFrameRate = {
+            .Numerator   = fmt->i_frame_rate_base > 0 ? fmt->i_frame_rate : 0,
+            .Denominator = fmt->i_frame_rate_base,
+        },
+        .InputWidth   = fmt->i_width,
+        .InputHeight  = fmt->i_height,
+        .OutputWidth  = dst->format.i_width,
+        .OutputHeight = dst->format.i_height,
+        .OutputFrameRate = {
+            .Numerator   = dst->format.i_frame_rate_base > 0 ? dst->format.i_frame_rate : 0,
+            .Denominator = dst->format.i_frame_rate_base,
+        },
+        .Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL,
+    };
+    hr = ID3D11VideoDevice_CreateVideoProcessorEnumerator(sys->d3dviddev, &processorDesc, &processorEnumerator);
+    if ( processorEnumerator == NULL )
+    {
+        msg_Dbg(filter, "Can't get a video processor for the video.");
+        goto error;
+    }
+
+    UINT flags;
+#ifndef NDEBUG
+    for (int format = 0; format < 188; format++) {
+        hr = ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator, format, &flags);
+        if (SUCCEEDED(hr) && (flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT))
+            msg_Dbg(filter, "processor format %s (%d) is supported for input", DxgiFormatToStr(format),format);
+        if (SUCCEEDED(hr) && (flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT))
+            msg_Dbg(filter, "processor format %s (%d) is supported for output", DxgiFormatToStr(format),format);
+    }
+#endif
+    hr = ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator, dst->p_sys->formatTexture, &flags);
+    if (!SUCCEEDED(hr))
+    {
+        msg_Dbg(filter, "can't read processor support for %s", DxgiFormatToStr(dst->p_sys->formatTexture));
+        goto error;
+    }
+    if ( !(flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT) ||
+         !(flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT) )
+    {
+        msg_Dbg(filter, "deinterlacing %s is not supported", DxgiFormatToStr(dst->p_sys->formatTexture));
+        goto error;
+    }
+
+    D3D11_VIDEO_PROCESSOR_CAPS processorCaps;
+    hr = ID3D11VideoProcessorEnumerator_GetVideoProcessorCaps(processorEnumerator, &processorCaps);
+    if (FAILED(hr))
+        goto error;
+
+    for (UINT type = 0; type < processorCaps.RateConversionCapsCount; ++type)
+    {
+        D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS rateCaps;
+        ID3D11VideoProcessorEnumerator_GetVideoProcessorRateConversionCaps(processorEnumerator, type, &rateCaps);
+        if (!(rateCaps.ProcessorCaps & D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_BOB))
+            continue;
+
+        hr = ID3D11VideoDevice_CreateVideoProcessor(sys->d3dviddev,
+                                                    processorEnumerator, type, &sys->videoProcessor);
+        if (SUCCEEDED(hr))
+            break;
+        sys->videoProcessor = NULL;
+    }
+
+    if (sys->videoProcessor == NULL)
+    {
+        msg_Dbg(filter, "couldn't find a deinterlacing filter");
+        goto error;
+    }
+
+    sys->procEnumerator  = processorEnumerator;
+
+    filter->pf_video_filter = Deinterlace;
+    filter->p_sys = sys;
+
+    picture_Release(dst);
+    return VLC_SUCCESS;
+error:
+    picture_Release(dst);
+
+    if (sys->videoProcessor)
+        ID3D11VideoProcessor_Release(sys->videoProcessor);
+    if (processorEnumerator)
+        ID3D11VideoProcessorEnumerator_Release(processorEnumerator);
+    if (sys->d3dvidctx)
+        ID3D11VideoContext_Release(sys->d3dvidctx);
+    if (sys->d3dviddev)
+        ID3D11VideoDevice_Release(sys->d3dviddev);
+
+    return VLC_EGENERIC;
+}
+
+static void Close(vlc_object_t *obj)
+{
+    filter_t *filter = (filter_t *)obj;
+    filter_sys_t *sys = filter->p_sys;
+
+    ID3D11VideoProcessor_Release(sys->videoProcessor);
+    ID3D11VideoProcessorEnumerator_Release(sys->procEnumerator);
+    ID3D11VideoContext_Release(sys->d3dvidctx);
+    ID3D11VideoDevice_Release(sys->d3dviddev);
+
+    free(sys);
+}
+
+vlc_module_begin()
+    set_description(N_("Direct3D11 deinterlacing filter"))
+    set_capability("video filter", 0)
+    set_category(CAT_VIDEO)
+    set_subcategory(SUBCAT_VIDEO_VFILTER)
+    set_callbacks(Open, Close)
+    add_shortcut ("deinterlace")
+vlc_module_end()
diff --git a/modules/video_output/win32/direct3d11.c b/modules/video_output/win32/direct3d11.c
index 6b9b17ddc4..afed013d44 100644
--- a/modules/video_output/win32/direct3d11.c
+++ b/modules/video_output/win32/direct3d11.c
@@ -934,6 +934,14 @@ static void ReleasePictureResources(picture_sys_t *p_sys)
         ID3D11VideoDecoderOutputView_Release(p_sys->decoder);
         p_sys->decoder = NULL;
     }
+    if (p_sys->processorInput) {
+        ID3D11VideoProcessorInputView_Release(p_sys->processorInput);
+        p_sys->processorInput = NULL;
+    }
+    if (p_sys->processorOutput) {
+        ID3D11VideoProcessorInputView_Release(p_sys->processorOutput);
+        p_sys->processorOutput = NULL;
+    }
 }
 
 static void DestroyDisplayPoolPicture(picture_t *picture)
-- 
2.11.1



More information about the vlc-devel mailing list