vout: win32: add a Direct3D9 deinterlacer for opaque surfaces
authorSteve Lhomme <robux4@videolabs.io>
Tue, 11 Apr 2017 09:21:45 +0000 (11:21 +0200)
committerJean-Baptiste Kempf <jb@videolan.org>
Thu, 13 Apr 2017 14:08:41 +0000 (16:08 +0200)
Close #12855

Signed-off-by: Jean-Baptiste Kempf <jb@videolan.org>
configure.ac
modules/MODULES_LIST
modules/video_output/Makefile.am
modules/video_output/win32/dxva2_deinterlace.c [new file with mode: 0644]

index 540dd0f..517ddca 100644 (file)
@@ -3272,8 +3272,16 @@ AS_IF([test "${enable_directx}" != "no"], [
   dnl Direct3D9
   AC_CHECK_HEADERS(d3d9.h, [
     VLC_ADD_PLUGIN([direct3d9])
-  ])
 
+    AC_CHECK_FUNCS([IDirectXVideoProcessorService_GetVideoProcessorDeviceGuids],
+      [
+        VLC_ADD_PLUGIN([dxva2_deinterlace])
+      ],
+      [AC_MSG_WARN([Could not find required IDirectXVideoDecoder in dxva2api.h])],
+      [#include <d3d9.h>
+       #include <dxva2api.h>])
+
+  ])
 ])
 
 dnl
index 340c549..3205a08 100644 (file)
@@ -124,6 +124,7 @@ $Id$
  * dvdread: input module for accessing DVDs, uses libdvdread
  * dxa9: Convert D3D9 GPU textures to YUV planes
  * dxva2: DxVA2 hardware-accelerated decoding
+ * dxva2_deinterlace: deinterlacer for DxVA 2.0 video decoding
  * dynamicoverlay: subpicture filter using shared memory that can be written to by external applications
  * edgedetection: edge detection video filter
  * edummy: dummy encoder
index 3b9fb05..dcd5307 100644 (file)
@@ -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)'
+libdxva2_deinterlace_plugin_la_SOURCES = video_output/win32/dxva2_deinterlace.c
+libdxva2_deinterlace_plugin_la_LIBADD = $(LIBCOM)
+libdxva2_deinterlace_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)'
 if HAVE_WIN32_DESKTOP
 vout_LTLIBRARIES += $(LTLIBdirect3d9)
-EXTRA_LTLIBRARIES += libdirect3d9_plugin.la
+vout_LTLIBRARIES += $(LTLIBdxva2_deinterlace)
+EXTRA_LTLIBRARIES += libdirect3d9_plugin.la libdxva2_deinterlace_plugin.la
 endif
 
 libdirect3d11_plugin_la_SOURCES = video_output/win32/direct3d11.c \
diff --git a/modules/video_output/win32/dxva2_deinterlace.c b/modules/video_output/win32/dxva2_deinterlace.c
new file mode 100644 (file)
index 0000000..dcfff72
--- /dev/null
@@ -0,0 +1,290 @@
+/*****************************************************************************
+ * dxva2_deinterlace.c: DxVA2 deinterlacing filter
+ *****************************************************************************
+ * Copyright (C) 2017 Videolabs SAS
+ *
+ * Authors: Steve Lhomme <robux4@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,
+                                                 &params,
+                                                 &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;
+    filter_sys_t *sys = NULL;
+    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)
+        goto error;
+
+    hdecoder_dll = LoadLibrary(TEXT("DXVA2.DLL"));
+    if (!hdecoder_dll)
+        goto error;
+
+    dst = filter_NewPicture(filter);
+    if (dst == NULL)
+        goto error;
+
+    sys = calloc(1, sizeof (*sys));
+    if (unlikely(sys == NULL))
+        goto error;
+
+    HRESULT (WINAPI *CreateVideoService)(IDirect3DDevice9 *,
+                                         REFIID riid,
+                                         void **ppService);
+    CreateVideoService =
+      (void *)GetProcAddress(hdecoder_dll, "DXVA2CreateVideoService");
+    if (CreateVideoService == NULL)
+        goto error;
+
+    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 (filter->fmt_in.video.i_frame_rate && filter->fmt_in.video.i_frame_rate_base) {
+        dsc.InputSampleFreq.Numerator   = filter->fmt_in.video.i_frame_rate;
+        dsc.InputSampleFreq.Denominator = filter->fmt_in.video.i_frame_rate_base;
+    } 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_("DXVA2 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()