[vlc-commits] direct3d9: add an adjust filter for d3d9 opaque formats
Steve Lhomme
git at videolan.org
Sat Jul 1 18:29:41 CEST 2017
vlc | branch: master | Steve Lhomme <robux4 at videolabs.io> | Sat Jul 1 16:51:05 2017 +0200| [63394df4e7c9daad57e390970d7ca3a6cb67f419] | committer: Jean-Baptiste Kempf
direct3d9: add an adjust filter for d3d9 opaque formats
it's missing the gamma handling
Signed-off-by: Jean-Baptiste Kempf <jb at videolan.org>
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=63394df4e7c9daad57e390970d7ca3a6cb67f419
---
NEWS | 3 +-
configure.ac | 2 +-
modules/MODULES_LIST | 1 +
modules/video_output/Makefile.am | 7 +-
modules/video_output/win32/d3d9_adjust.c | 467 +++++++++++++++++++++++++++++++
5 files changed, 476 insertions(+), 4 deletions(-)
diff --git a/NEWS b/NEWS
index 948f4d2725..27bc0fa8f4 100644
--- a/NEWS
+++ b/NEWS
@@ -67,7 +67,8 @@ Decoder:
* Support HEVC hardware decoding on Windows, using DxVA2 and D3D11
* Support hardware decoding using Direct3D11, including GPU-zerocopy mode,
and hardware filtering, for deinterlace and adjust
- * DxVA2 GPU-zerocopy for hardware decoding and displaying on Windows
+ * DxVA2 GPU-zerocopy for hardware decoding and displaying on Windows,
+ and support for hardware filtering, for deinterlace and adjust
* Support HEVC hardware decoding using OMX and MediaCodec (Android)
* Use MediaCodec via NDK native API after Android Lollipop
* Support MPEG-2, VC1/WMV3 on Android using MediaCodec
diff --git a/configure.ac b/configure.ac
index e8dc6867d9..a9c37c4a2f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3295,7 +3295,7 @@ AS_IF([test "${enable_directx}" != "no"], [
AC_CHECK_FUNCS([IDirectXVideoProcessorService_GetVideoProcessorDeviceGuids],
[
- VLC_ADD_PLUGIN([direct3d9_deinterlace])
+ VLC_ADD_PLUGIN([direct3d9_deinterlace direct3d9_adjust])
],
[AC_MSG_WARN([Could not find required IDirectXVideoDecoder in dxva2api.h])],
[#include <d3d9.h>
diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST
index ada0caf250..d4d600a39d 100644
--- a/modules/MODULES_LIST
+++ b/modules/MODULES_LIST
@@ -108,6 +108,7 @@ $Id$
* direct3d11_adjust: adjust filter for Direct3D11 video decoding
* direct3d11_deinterlace: deinterlacer for Direct3D11 video decoding
* direct3d9: video output module using the Direct3D9 API
+ * direct3d9_adjust: adjust filter for Direct3D9 video decoding
* direct3d9_deinterlace: deinterlacer for Direct3D9/DxVA video decoding
* directdraw: video output module using the DirectDraw API
* directfb: Direct Framebuffer video output
diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am
index e082b263b6..7227ae42cf 100644
--- a/modules/video_output/Makefile.am
+++ b/modules/video_output/Makefile.am
@@ -241,10 +241,13 @@ libdirect3d9_deinterlace_plugin_la_SOURCES = video_output/win32/dxva2_deinterlac
video_chroma/d3d9_fmt.h
libdirect3d9_deinterlace_plugin_la_LIBADD = $(LIBCOM)
libdirect3d9_deinterlace_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)'
+libdirect3d9_adjust_plugin_la_SOURCES = video_output/win32/d3d9_adjust.c \
+ video_chroma/dxgi_fmt.c video_chroma/dxgi_fmt.h
+libdirect3d9_adjust_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)'
if HAVE_WIN32_DESKTOP
vout_LTLIBRARIES += $(LTLIBdirect3d9)
-video_filter_LTLIBRARIES += $(LTLIBdirect3d9_deinterlace)
-EXTRA_LTLIBRARIES += libdirect3d9_plugin.la libdirect3d9_deinterlace_plugin.la
+video_filter_LTLIBRARIES += $(LTLIBdirect3d9_deinterlace) $(LTLIBdirect3d9_adjust)
+EXTRA_LTLIBRARIES += libdirect3d9_plugin.la libdirect3d9_deinterlace_plugin.la libdirect3d9_adjust_plugin.la
endif
libdirect3d11_plugin_la_SOURCES = video_output/win32/direct3d11.c \
diff --git a/modules/video_output/win32/d3d9_adjust.c b/modules/video_output/win32/d3d9_adjust.c
new file mode 100644
index 0000000000..58149bfadd
--- /dev/null
+++ b/modules/video_output/win32/d3d9_adjust.c
@@ -0,0 +1,467 @@
+/*****************************************************************************
+ * d3d9_adjust.c: D3D9 adjust filter (no gamma)
+ *****************************************************************************
+ * 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>
+#include <vlc_atomic.h>
+
+#define COBJMACROS
+#include <initguid.h>
+#include <d3d9.h>
+#include <dxva2api.h>
+#include "../../video_chroma/d3d9_fmt.h"
+
+struct filter_level
+{
+ atomic_int level;
+ float default_val;
+ float min;
+ float max;
+ DXVA2_ValueRange Range;
+};
+
+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;
+
+ struct filter_level Brightness;
+ struct filter_level Contrast;
+ struct filter_level Hue;
+ struct filter_level Saturation;
+};
+
+#define THRES_TEXT N_("Brightness threshold")
+#define THRES_LONGTEXT N_("When this mode is enabled, pixels will be " \
+ "shown as black or white. The threshold value will be the brightness " \
+ "defined below." )
+#define CONT_TEXT N_("Image contrast (0-2)")
+#define CONT_LONGTEXT N_("Set the image contrast, between 0 and 2. Defaults to 1.")
+#define HUE_TEXT N_("Image hue (0-360)")
+#define HUE_LONGTEXT N_("Set the image hue, between 0 and 360. Defaults to 0.")
+#define SAT_TEXT N_("Image saturation (0-3)")
+#define SAT_LONGTEXT N_("Set the image saturation, between 0 and 3. Defaults to 1.")
+#define LUM_TEXT N_("Image brightness (0-2)")
+#define LUM_LONGTEXT N_("Set the image brightness, between 0 and 2. Defaults to 1.")
+#define GAMMA_TEXT N_("Image gamma (0-10)")
+#define GAMMA_LONGTEXT N_("Set the image gamma, between 0.01 and 10. Defaults to 1.")
+
+static const char *const ppsz_filter_options[] = {
+ "contrast", "brightness", "hue", "saturation", "gamma",
+ "brightness-threshold", NULL
+};
+
+static void FillSample( DXVA2_VideoSample *p_sample,
+ picture_t *p_pic,
+ const RECT *p_area )
+{
+ picture_sys_t *p_sys_src = ActivePictureSys(p_pic);
+
+ p_sample->SrcSurface = p_sys_src->surface;
+ p_sample->SampleFormat.SampleFormat = DXVA2_SampleProgressiveFrame;
+ p_sample->Start = 0;
+ p_sample->End =0;
+ p_sample->SampleData = 0;
+ p_sample->DstRect = p_sample->SrcRect = *p_area;
+ p_sample->PlanarAlpha = DXVA2_Fixed32OpaqueAlpha();
+}
+
+static picture_t *Filter(filter_t *p_filter, picture_t *p_pic)
+{
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ picture_sys_t *p_src_sys = ActivePictureSys(p_pic);
+
+ picture_t *p_outpic = filter_NewPicture( p_filter );
+ if( !p_outpic )
+ goto failed;
+
+ picture_CopyProperties( p_outpic, p_pic );
+
+ RECT area;
+ D3DSURFACE_DESC srcDesc, dstDesc;
+ HRESULT hr;
+
+ hr = IDirect3DSurface9_GetDesc( p_src_sys->surface, &srcDesc );
+ if (unlikely(FAILED(hr)))
+ goto failed;
+ hr = IDirect3DSurface9_GetDesc( p_sys->hw_surface, &dstDesc );
+ if (unlikely(FAILED(hr)))
+ goto failed;
+
+ area.top = area.left = 0;
+ area.bottom = __MIN(srcDesc.Height, dstDesc.Height);
+ area.right = __MIN(srcDesc.Width, dstDesc.Width);
+
+ DXVA2_VideoProcessBltParams params = {0};
+ DXVA2_VideoSample sample = {0};
+ FillSample( &sample, p_pic, &area );
+
+ params.ProcAmpValues.Brightness.Value = atomic_load( &p_sys->Brightness.level );
+ params.ProcAmpValues.Contrast.Value = atomic_load( &p_sys->Contrast.level );
+ params.ProcAmpValues.Hue.Value = atomic_load( &p_sys->Hue.level );
+ params.ProcAmpValues.Saturation.Value = atomic_load( &p_sys->Saturation.level );
+ params.TargetFrame = 0;
+ params.TargetRect = area;
+ params.DestData = 0;
+ params.Alpha = DXVA2_Fixed32OpaqueAlpha();
+ params.DestFormat.SampleFormat = DXVA2_SampleProgressiveFrame;
+ params.BackgroundColor.Alpha = 0xFFFF;
+
+ hr = IDirectXVideoProcessor_VideoProcessBlt( p_sys->processor,
+ p_sys->hw_surface,
+ ¶ms,
+ &sample,
+ 1, NULL );
+ hr = IDirect3DDevice9_StretchRect( p_sys->d3ddev,
+ p_sys->hw_surface, NULL,
+ p_outpic->p_sys->surface, NULL,
+ D3DTEXF_NONE);
+ if (FAILED(hr))
+ goto failed;
+
+ picture_Release( p_pic );
+ return p_outpic;
+failed:
+ picture_Release( p_pic );
+ return NULL;
+}
+
+static void SetLevel(struct filter_level *range, float val)
+{
+ int level;
+ if (val > range->default_val)
+ level = (range->Range.MaxValue.Value - range->Range.DefaultValue.Value) * (val - range->default_val) /
+ (range->max - range->default_val);
+ else if (val < range->default_val)
+ level = (range->Range.MinValue.Value - range->Range.DefaultValue.Value) * (val - range->default_val) /
+ (range->min - range->default_val);
+ else
+ level = 0;
+
+ atomic_store( &range->level, range->Range.DefaultValue.Value + level );
+}
+
+static void InitLevel(filter_t *filter, struct filter_level *range, const char *p_name, float def)
+{
+ int level;
+
+ module_config_t *cfg = config_FindConfig( VLC_OBJECT(filter), p_name);
+ range->min = cfg->min.f;
+ range->max = cfg->max.f;
+ range->default_val = def;
+
+ float val = var_CreateGetFloatCommand( filter, p_name );
+
+ if (val > range->default_val)
+ level = (range->Range.MaxValue.Value - range->Range.DefaultValue.Value) * (val - range->default_val) /
+ (range->max - range->default_val);
+ else if (val < range->default_val)
+ level = (range->Range.MinValue.Value - range->Range.DefaultValue.Value) * (val - range->default_val) /
+ (range->min - range->default_val);
+ else
+ level = 0;
+
+ atomic_init( &range->level, range->Range.DefaultValue.Value + level );
+}
+
+static int AdjustCallback( vlc_object_t *p_this, char const *psz_var,
+ vlc_value_t oldval, vlc_value_t newval,
+ void *p_data )
+{
+ VLC_UNUSED(p_this); VLC_UNUSED(oldval);
+ filter_sys_t *p_sys = (filter_sys_t *)p_data;
+
+ if( !strcmp( psz_var, "contrast" ) )
+ SetLevel( &p_sys->Contrast, newval.f_float );
+ else if( !strcmp( psz_var, "brightness" ) )
+ SetLevel( &p_sys->Brightness, newval.f_float );
+ else if( !strcmp( psz_var, "hue" ) )
+ SetLevel( &p_sys->Hue, newval.f_float );
+ else if( !strcmp( psz_var, "saturation" ) )
+ SetLevel( &p_sys->Saturation, newval.f_float );
+
+ return VLC_SUCCESS;
+}
+
+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;
+
+ if (!dst->p_sys)
+ {
+ msg_Dbg(filter, "D3D11 opaque without a texture");
+ 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 (unlikely(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 = DXVA2_SampleProgressiveFrame;
+
+ UINT count = 0;
+ hr = IDirectXVideoProcessorService_GetVideoProcessorDeviceGuids( processor,
+ &dsc,
+ &count,
+ &processorGUIDs);
+ if (FAILED(hr))
+ goto error;
+
+ const UINT neededCaps = DXVA2_ProcAmp_Brightness |
+ DXVA2_ProcAmp_Contrast |
+ DXVA2_ProcAmp_Hue |
+ DXVA2_ProcAmp_Saturation;
+ DXVA2_VideoProcessorCaps caps;
+ unsigned best_score = 0;
+ for (UINT i=0; i<count; ++i) {
+ hr = IDirectXVideoProcessorService_GetVideoProcessorCaps( processor,
+ processorGUIDs+i,
+ &dsc,
+ dsc.Format,
+ &caps);
+ if ( FAILED(hr) || !caps.ProcAmpControlCaps )
+ continue;
+
+ unsigned score = (caps.ProcAmpControlCaps & neededCaps) ? 10 : 1;
+ if (best_score < score) {
+ best_score = score;
+ processorGUID = processorGUIDs + i;
+ }
+ }
+
+ if (processorGUID == NULL)
+ {
+ msg_Dbg(filter, "Could not find a filter to output the required format");
+ goto error;
+ }
+
+ hr = IDirectXVideoProcessorService_GetProcAmpRange( processor, processorGUID, &dsc,
+ dstDesc.Format, DXVA2_ProcAmp_Brightness,
+ &sys->Brightness.Range );
+ if (FAILED(hr))
+ goto error;
+
+ hr = IDirectXVideoProcessorService_GetProcAmpRange( processor, processorGUID, &dsc,
+ dstDesc.Format, DXVA2_ProcAmp_Contrast,
+ &sys->Contrast.Range );
+ if (FAILED(hr))
+ goto error;
+
+ hr = IDirectXVideoProcessorService_GetProcAmpRange( processor, processorGUID, &dsc,
+ dstDesc.Format, DXVA2_ProcAmp_Hue,
+ &sys->Hue.Range );
+ if (FAILED(hr))
+ goto error;
+
+ hr = IDirectXVideoProcessorService_GetProcAmpRange( processor, processorGUID, &dsc,
+ dstDesc.Format, DXVA2_ProcAmp_Saturation,
+ &sys->Saturation.Range );
+ if (FAILED(hr))
+ goto error;
+
+ /* needed to get options passed in transcode using the
+ * adjust{name=value} syntax */
+ config_ChainParse( filter, "", ppsz_filter_options, filter->p_cfg );
+
+ InitLevel(filter, &sys->Contrast, "contrast", 1.0 );
+ InitLevel(filter, &sys->Brightness, "brightness", 1.0 );
+ InitLevel(filter, &sys->Hue, "hue", 0.0 );
+ InitLevel(filter, &sys->Saturation, "saturation", 1.0 );
+
+ var_AddCallback( filter, "contrast", AdjustCallback, sys );
+ var_AddCallback( filter, "brightness", AdjustCallback, sys );
+ var_AddCallback( filter, "hue", AdjustCallback, sys );
+ var_AddCallback( filter, "saturation", AdjustCallback, sys );
+ var_AddCallback( filter, "gamma", AdjustCallback, sys );
+ var_AddCallback( filter, "brightness-threshold",
+ AdjustCallback, sys );
+
+ 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 = Filter;
+ 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( "adjust" )
+
+ add_float_with_range( "contrast", 1.0, 0.0, 2.0,
+ CONT_TEXT, CONT_LONGTEXT, false )
+ change_safe()
+ add_float_with_range( "brightness", 1.0, 0.0, 2.0,
+ LUM_TEXT, LUM_LONGTEXT, false )
+ change_safe()
+ add_float_with_range( "hue", 0, -180., +180.,
+ HUE_TEXT, HUE_LONGTEXT, false )
+ change_safe()
+ add_float_with_range( "saturation", 1.0, 0.0, 3.0,
+ SAT_TEXT, SAT_LONGTEXT, false )
+ change_safe()
+ add_float_with_range( "gamma", 1.0, 0.01, 10.0,
+ GAMMA_TEXT, GAMMA_LONGTEXT, false )
+ change_safe()
+ add_bool( "brightness-threshold", false,
+ THRES_TEXT, THRES_LONGTEXT, false )
+ change_safe()
+vlc_module_end()
More information about the vlc-commits
mailing list