[vlc-devel] [PATCH 3/3] vout: win32: add a Direct3D9 deinterlacer for opaque surfaces
Steve Lhomme
robux4 at videolabs.io
Tue Apr 11 18:03:44 CEST 2017
--
replaces https://patches.videolan.org/patch/16357/
- only set the alpha on the background color
- fix linking/usage in the project
---
configure.ac | 3 +
modules/video_output/Makefile.am | 6 +-
modules/video_output/win32/d3d9_deinterlace.c | 289 ++++++++++++++++++++++++++
3 files changed, 297 insertions(+), 1 deletion(-)
create mode 100644 modules/video_output/win32/d3d9_deinterlace.c
diff --git a/configure.ac b/configure.ac
index dfbb3f4919..6130c4a437 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3276,6 +3276,9 @@ AS_IF([test "${enable_directx}" != "no"], [
dnl Direct3D9
AC_CHECK_HEADERS(d3d9.h, [
VLC_ADD_PLUGIN([direct3d9])
+ AC_CHECK_HEADERS(dxva2api.h, [
+ VLC_ADD_PLUGIN([direct3d9_deinterlace])
+ ])
])
])
diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am
index 3b9fb053f6..f78ca050eb 100644
--- a/modules/video_output/Makefile.am
+++ b/modules/video_output/Makefile.am
@@ -214,9 +214,13 @@ libdirect3d9_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) \
-DMODULE_NAME_IS_direct3d9
libdirect3d9_plugin_la_LIBADD = -lgdi32 $(LIBCOM) -luuid
libdirect3d9_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)'
+libdirect3d9_deinterlace_plugin_la_SOURCES = video_output/win32/d3d9_deinterlace.c
+libdirect3d9_deinterlace_plugin_la_LIBADD = $(LIBCOM)
+libdirect3d9_deinterlace_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)'
if HAVE_WIN32_DESKTOP
vout_LTLIBRARIES += $(LTLIBdirect3d9)
-EXTRA_LTLIBRARIES += libdirect3d9_plugin.la
+vout_LTLIBRARIES += $(LTLIBdirect3d9_deinterlace)
+EXTRA_LTLIBRARIES += libdirect3d9_plugin.la libdirect3d9_deinterlace_plugin.la
endif
libdirect3d11_plugin_la_SOURCES = video_output/win32/direct3d11.c \
diff --git a/modules/video_output/win32/d3d9_deinterlace.c b/modules/video_output/win32/d3d9_deinterlace.c
new file mode 100644
index 0000000000..56ce7d9c3b
--- /dev/null
+++ b/modules/video_output/win32/d3d9_deinterlace.c
@@ -0,0 +1,289 @@
+/*****************************************************************************
+ * 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 <d3d9.h>
+#include <dxva2api.h>
+
+struct picture_sys_t
+{
+ LPDIRECT3DSURFACE9 surface;
+};
+
+struct filter_sys_t
+{
+ HINSTANCE hdecoder_dll;
+ /* keep a reference in case the vout is released first */
+ HINSTANCE d3d9_dll;
+ IDirect3DDevice9 *d3ddev;
+ IDirectXVideoProcessor *processor;
+ IDirect3DSurface9 *hw_surface;
+};
+
+static picture_t *Deinterlace(filter_t *filter, picture_t *src)
+{
+ filter_sys_t *sys = filter->p_sys;
+ HRESULT hr;
+ DXVA2_VideoProcessBltParams params = {0};
+ DXVA2_VideoSample sample = {0};
+ D3DSURFACE_DESC dstDesc;
+
+ hr = IDirect3DSurface9_GetDesc( src->p_sys->surface, &dstDesc );
+ if (FAILED(hr))
+ return src; /* cannot deinterlace without copying fields */
+
+ picture_t *dst = filter_NewPicture(filter);
+ if (dst == NULL)
+ return src; /* cannot deinterlace without copying fields */
+
+ sample.SrcSurface = src->p_sys->surface;
+ sample.SampleFormat.SampleFormat = src->b_top_field_first ?
+ DXVA2_SampleFieldInterleavedEvenFirst :
+ DXVA2_SampleFieldInterleavedOddFirst;
+ sample.Start = 0;
+ sample.End = sample.Start + 333666;
+ sample.SampleData = DXVA2_SampleData_RFF_TFF_Present;
+ if (src->b_top_field_first)
+ sample.SampleData |= DXVA2_SampleData_TFF;
+ sample.SrcRect.bottom = dstDesc.Height;
+ sample.SrcRect.right = dstDesc.Width;
+ sample.DstRect = sample.SrcRect;
+ sample.PlanarAlpha = DXVA2_Fixed32OpaqueAlpha();
+
+ params.TargetFrame = sample.Start;
+ params.TargetRect = sample.DstRect;
+ params.DestData = sample.SampleData;
+ params.Alpha = DXVA2_Fixed32OpaqueAlpha();
+ params.DestFormat.SampleFormat = DXVA2_SampleProgressiveFrame;
+ params.BackgroundColor.Alpha = 0xFFFF;
+
+ hr = IDirectXVideoProcessor_VideoProcessBlt( sys->processor,
+ sys->hw_surface,
+ ¶ms,
+ &sample,
+ 1, NULL );
+ if (FAILED(hr))
+ goto error;
+
+ hr = IDirect3DDevice9_StretchRect( sys->d3ddev,
+ sys->hw_surface, NULL,
+ dst->p_sys->surface, NULL,
+ D3DTEXF_NONE);
+ if (FAILED(hr))
+ goto error;
+
+ picture_CopyProperties(dst, src);
+ picture_Release(src);
+ dst->b_progressive = true;
+ dst->i_nb_fields = 1;
+ return dst;
+error:
+ picture_Release(dst);
+ return src;
+}
+
+static int Open(vlc_object_t *obj)
+{
+ filter_t *filter = (filter_t *)obj;
+ HINSTANCE hdecoder_dll = NULL;
+ HINSTANCE d3d9_dll = NULL;
+ HRESULT hr;
+ picture_t *dst = NULL;
+ GUID *processorGUIDs = NULL;
+ GUID *processorGUID = NULL;
+ IDirectXVideoProcessorService *processor = NULL;
+
+ if (filter->fmt_in.video.i_chroma != VLC_CODEC_D3D9_OPAQUE
+ && filter->fmt_in.video.i_chroma != VLC_CODEC_D3D9_OPAQUE_10B)
+ return VLC_EGENERIC;
+ if (!video_format_IsSimilar(&filter->fmt_in.video, &filter->fmt_out.video))
+ return VLC_EGENERIC;
+
+ d3d9_dll = LoadLibrary(TEXT("D3D9.DLL"));
+ if (!d3d9_dll)
+ return VLC_EGENERIC;
+
+ hdecoder_dll = LoadLibrary(TEXT("DXVA2.DLL"));
+ if (!hdecoder_dll)
+ return VLC_EGENERIC;
+
+ dst = filter_NewPicture(filter);
+ if (dst == NULL)
+ return VLC_EGENERIC;
+
+ filter_sys_t *sys = malloc(sizeof (*sys));
+ if (unlikely(sys == NULL))
+ goto error;
+ memset(sys, 0, sizeof (*sys));
+ filter->p_sys = sys;
+
+ HRESULT (WINAPI *CreateVideoService)(IDirect3DDevice9 *,
+ REFIID riid,
+ void **ppService);
+ CreateVideoService =
+ (void *)GetProcAddress(hdecoder_dll, "DXVA2CreateVideoService");
+
+ hr = IDirect3DSurface9_GetDevice( dst->p_sys->surface, &sys->d3ddev );
+ if (FAILED(hr))
+ goto error;
+
+ D3DSURFACE_DESC dstDesc;
+ hr = IDirect3DSurface9_GetDesc( dst->p_sys->surface, &dstDesc );
+ if (FAILED(hr))
+ goto error;
+
+ hr = CreateVideoService( sys->d3ddev, &IID_IDirectXVideoProcessorService,
+ (void**)&processor);
+ if (FAILED(hr))
+ goto error;
+
+ DXVA2_VideoDesc dsc;
+ ZeroMemory(&dsc, sizeof(dsc));
+ dsc.SampleWidth = dstDesc.Width;
+ dsc.SampleHeight = dstDesc.Height;
+ dsc.Format = dstDesc.Format;
+ if (es_format_HasValidFrameRate( &filter->fmt_in )) {
+ dsc.InputSampleFreq.Numerator = filter->fmt_in.video.frame_rate.num;
+ dsc.InputSampleFreq.Denominator = filter->fmt_in.video.frame_rate.den;
+ } else {
+ dsc.InputSampleFreq.Numerator = 0;
+ dsc.InputSampleFreq.Denominator = 0;
+ }
+ dsc.OutputFrameFreq = dsc.InputSampleFreq;
+
+ DXVA2_ExtendedFormat *pFormat = &dsc.SampleFormat;
+ pFormat->SampleFormat = dst->b_top_field_first ?
+ DXVA2_SampleFieldInterleavedEvenFirst :
+ DXVA2_SampleFieldInterleavedOddFirst;
+
+ UINT count = 0;
+ hr = IDirectXVideoProcessorService_GetVideoProcessorDeviceGuids( processor,
+ &dsc,
+ &count,
+ &processorGUIDs);
+ if (FAILED(hr))
+ goto error;
+
+ DXVA2_VideoProcessorCaps caps;
+ for (UINT i=0; i<count && processorGUID==NULL; ++i) {
+ hr = IDirectXVideoProcessorService_GetVideoProcessorCaps( processor,
+ processorGUIDs+i,
+ &dsc,
+ dsc.Format,
+ &caps);
+ if ( SUCCEEDED(hr) && caps.DeinterlaceTechnology &&
+ !caps.NumForwardRefSamples && !caps.NumBackwardRefSamples )
+ processorGUID = processorGUIDs + i;
+ }
+
+ if (processorGUID == NULL)
+ {
+ msg_Dbg(filter, "Could not find a filter to output the required format");
+ goto error;
+ }
+
+ hr = IDirectXVideoProcessorService_CreateVideoProcessor( processor,
+ processorGUID,
+ &dsc,
+ dsc.Format,
+ 1,
+ &sys->processor );
+ if (FAILED(hr))
+ goto error;
+
+ hr = IDirectXVideoProcessorService_CreateSurface( processor,
+ dstDesc.Width,
+ dstDesc.Height,
+ 0,
+ dstDesc.Format,
+ D3DPOOL_DEFAULT,
+ 0,
+ DXVA2_VideoProcessorRenderTarget,
+ &sys->hw_surface,
+ NULL);
+ if (FAILED(hr))
+ goto error;
+
+ CoTaskMemFree(processorGUIDs);
+ picture_Release(dst);
+ IDirectXVideoProcessorService_Release(processor);
+
+ sys->hdecoder_dll = hdecoder_dll;
+ sys->d3d9_dll = d3d9_dll;
+ filter->pf_video_filter = Deinterlace;
+ filter->p_sys = sys;
+
+ return VLC_SUCCESS;
+error:
+ CoTaskMemFree(processorGUIDs);
+ if (sys && sys->processor)
+ IDirectXVideoProcessor_Release( sys->processor );
+ if (processor)
+ IDirectXVideoProcessorService_Release(processor);
+ if (sys && sys->d3ddev)
+ IDirect3DDevice9_Release( sys->d3ddev );
+ if (hdecoder_dll)
+ FreeLibrary(hdecoder_dll);
+ if (d3d9_dll)
+ FreeLibrary(d3d9_dll);
+ if (dst)
+ picture_Release(dst);
+ free(sys);
+
+ return VLC_EGENERIC;
+}
+
+static void Close(vlc_object_t *obj)
+{
+ filter_t *filter = (filter_t *)obj;
+ filter_sys_t *sys = filter->p_sys;
+
+ IDirect3DSurface9_Release( sys->hw_surface );
+ IDirectXVideoProcessor_Release( sys->processor );
+ IDirect3DDevice9_Release( sys->d3ddev );
+ FreeLibrary( sys->hdecoder_dll );
+ FreeLibrary( sys->d3d9_dll );
+
+ free(sys);
+}
+
+vlc_module_begin()
+ set_description(N_("Direct3D9 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()
--
2.11.1
More information about the vlc-devel
mailing list