vlc | branch: master | Steve Lhomme <[email protected]> | 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 <[email protected]> > 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 <[email protected]> + * + * 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() _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
