1 /*****************************************************************************
2 * d3d9_filters.c: D3D9 filters module callbacks
3 *****************************************************************************
4 * Copyright © 2017 VLC authors, VideoLAN and VideoLabs
6 * Authors: Steve Lhomme <robux4@gmail.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32 #include <vlc_filter.h>
33 #include <vlc_picture.h>
34 #include <vlc_atomic.h>
40 #include "../../video_chroma/d3d9_fmt.h"
42 #include "d3d9_filters.h"
50 DXVA2_ValueRange Range
;
55 HINSTANCE hdecoder_dll
;
56 /* keep a reference in case the vout is released first */
58 IDirect3DDevice9
*d3ddev
;
59 IDirectXVideoProcessor
*processor
;
60 IDirect3DSurface9
*hw_surface
;
62 struct filter_level Brightness
;
63 struct filter_level Contrast
;
64 struct filter_level Hue
;
65 struct filter_level Saturation
;
68 #define THRES_TEXT N_("Brightness threshold")
69 #define THRES_LONGTEXT N_("When this mode is enabled, pixels will be " \
70 "shown as black or white. The threshold value will be the brightness " \
72 #define CONT_TEXT N_("Image contrast (0-2)")
73 #define CONT_LONGTEXT N_("Set the image contrast, between 0 and 2. Defaults to 1.")
74 #define HUE_TEXT N_("Image hue (0-360)")
75 #define HUE_LONGTEXT N_("Set the image hue, between 0 and 360. Defaults to 0.")
76 #define SAT_TEXT N_("Image saturation (0-3)")
77 #define SAT_LONGTEXT N_("Set the image saturation, between 0 and 3. Defaults to 1.")
78 #define LUM_TEXT N_("Image brightness (0-2)")
79 #define LUM_LONGTEXT N_("Set the image brightness, between 0 and 2. Defaults to 1.")
80 #define GAMMA_TEXT N_("Image gamma (0-10)")
81 #define GAMMA_LONGTEXT N_("Set the image gamma, between 0.01 and 10. Defaults to 1.")
83 static const char *const ppsz_filter_options
[] = {
84 "contrast", "brightness", "hue", "saturation", "gamma",
85 "brightness-threshold", NULL
88 static void FillSample( DXVA2_VideoSample
*p_sample
,
92 picture_sys_t
*p_sys_src
= ActivePictureSys(p_pic
);
94 p_sample
->SrcSurface
= p_sys_src
->surface
;
95 p_sample
->SampleFormat
.SampleFormat
= DXVA2_SampleProgressiveFrame
;
98 p_sample
->SampleData
= 0;
99 p_sample
->DstRect
= p_sample
->SrcRect
= *p_area
;
100 p_sample
->PlanarAlpha
= DXVA2_Fixed32OpaqueAlpha();
103 static picture_t
*Filter(filter_t
*p_filter
, picture_t
*p_pic
)
105 filter_sys_t
*p_sys
= p_filter
->p_sys
;
107 picture_sys_t
*p_src_sys
= ActivePictureSys(p_pic
);
109 picture_t
*p_outpic
= filter_NewPicture( p_filter
);
113 picture_CopyProperties( p_outpic
, p_pic
);
116 D3DSURFACE_DESC srcDesc
, dstDesc
;
119 hr
= IDirect3DSurface9_GetDesc( p_src_sys
->surface
, &srcDesc
);
120 if (unlikely(FAILED(hr
)))
122 hr
= IDirect3DSurface9_GetDesc( p_sys
->hw_surface
, &dstDesc
);
123 if (unlikely(FAILED(hr
)))
126 area
.top
= area
.left
= 0;
127 area
.bottom
= __MIN(srcDesc
.Height
, dstDesc
.Height
);
128 area
.right
= __MIN(srcDesc
.Width
, dstDesc
.Width
);
130 DXVA2_VideoProcessBltParams params
= {0};
131 DXVA2_VideoSample sample
= {0};
132 FillSample( &sample
, p_pic
, &area
);
134 params
.ProcAmpValues
.Brightness
.Value
= atomic_load( &p_sys
->Brightness
.level
);
135 params
.ProcAmpValues
.Contrast
.Value
= atomic_load( &p_sys
->Contrast
.level
);
136 params
.ProcAmpValues
.Hue
.Value
= atomic_load( &p_sys
->Hue
.level
);
137 params
.ProcAmpValues
.Saturation
.Value
= atomic_load( &p_sys
->Saturation
.level
);
138 params
.TargetFrame
= 0;
139 params
.TargetRect
= area
;
141 params
.Alpha
= DXVA2_Fixed32OpaqueAlpha();
142 params
.DestFormat
.SampleFormat
= DXVA2_SampleProgressiveFrame
;
143 params
.BackgroundColor
.Alpha
= 0xFFFF;
145 hr
= IDirectXVideoProcessor_VideoProcessBlt( p_sys
->processor
,
150 hr
= IDirect3DDevice9_StretchRect( p_sys
->d3ddev
,
151 p_sys
->hw_surface
, NULL
,
152 p_outpic
->p_sys
->surface
, NULL
,
157 picture_Release( p_pic
);
160 picture_Release( p_pic
);
164 static void SetLevel(struct filter_level
*range
, float val
)
167 if (val
> range
->default_val
)
168 level
= (range
->Range
.MaxValue
.Value
- range
->Range
.DefaultValue
.Value
) * (val
- range
->default_val
) /
169 (range
->max
- range
->default_val
);
170 else if (val
< range
->default_val
)
171 level
= (range
->Range
.MinValue
.Value
- range
->Range
.DefaultValue
.Value
) * (val
- range
->default_val
) /
172 (range
->min
- range
->default_val
);
176 atomic_store( &range
->level
, range
->Range
.DefaultValue
.Value
+ level
);
179 static void InitLevel(filter_t
*filter
, struct filter_level
*range
, const char *p_name
, float def
)
183 module_config_t
*cfg
= config_FindConfig(p_name
);
184 range
->min
= cfg
->min
.f
;
185 range
->max
= cfg
->max
.f
;
186 range
->default_val
= def
;
188 float val
= var_CreateGetFloatCommand( filter
, p_name
);
190 if (val
> range
->default_val
)
191 level
= (range
->Range
.MaxValue
.Value
- range
->Range
.DefaultValue
.Value
) * (val
- range
->default_val
) /
192 (range
->max
- range
->default_val
);
193 else if (val
< range
->default_val
)
194 level
= (range
->Range
.MinValue
.Value
- range
->Range
.DefaultValue
.Value
) * (val
- range
->default_val
) /
195 (range
->min
- range
->default_val
);
199 atomic_init( &range
->level
, range
->Range
.DefaultValue
.Value
+ level
);
202 static int AdjustCallback( vlc_object_t
*p_this
, char const *psz_var
,
203 vlc_value_t oldval
, vlc_value_t newval
,
206 VLC_UNUSED(p_this
); VLC_UNUSED(oldval
);
207 filter_sys_t
*p_sys
= (filter_sys_t
*)p_data
;
209 if( !strcmp( psz_var
, "contrast" ) )
210 SetLevel( &p_sys
->Contrast
, newval
.f_float
);
211 else if( !strcmp( psz_var
, "brightness" ) )
212 SetLevel( &p_sys
->Brightness
, newval
.f_float
);
213 else if( !strcmp( psz_var
, "hue" ) )
214 SetLevel( &p_sys
->Hue
, newval
.f_float
);
215 else if( !strcmp( psz_var
, "saturation" ) )
216 SetLevel( &p_sys
->Saturation
, newval
.f_float
);
221 static int D3D9OpenAdjust(vlc_object_t
*obj
)
223 filter_t
*filter
= (filter_t
*)obj
;
224 filter_sys_t
*sys
= NULL
;
225 HINSTANCE hdecoder_dll
= NULL
;
226 HINSTANCE d3d9_dll
= NULL
;
228 picture_t
*dst
= NULL
;
229 GUID
*processorGUIDs
= NULL
;
230 GUID
*processorGUID
= NULL
;
231 IDirectXVideoProcessorService
*processor
= NULL
;
233 if (filter
->fmt_in
.video
.i_chroma
!= VLC_CODEC_D3D9_OPAQUE
234 && filter
->fmt_in
.video
.i_chroma
!= VLC_CODEC_D3D9_OPAQUE_10B
)
236 if (!video_format_IsSimilar(&filter
->fmt_in
.video
, &filter
->fmt_out
.video
))
239 d3d9_dll
= LoadLibrary(TEXT("D3D9.DLL"));
243 hdecoder_dll
= LoadLibrary(TEXT("DXVA2.DLL"));
247 dst
= filter_NewPicture(filter
);
253 msg_Dbg(filter
, "D3D9 opaque without a texture");
257 sys
= calloc(1, sizeof (*sys
));
258 if (unlikely(sys
== NULL
))
261 HRESULT (WINAPI
*CreateVideoService
)(IDirect3DDevice9
*,
265 (void *)GetProcAddress(hdecoder_dll
, "DXVA2CreateVideoService");
266 if (CreateVideoService
== NULL
)
269 hr
= IDirect3DSurface9_GetDevice( dst
->p_sys
->surface
, &sys
->d3ddev
);
273 D3DSURFACE_DESC dstDesc
;
274 hr
= IDirect3DSurface9_GetDesc( dst
->p_sys
->surface
, &dstDesc
);
275 if (unlikely(FAILED(hr
)))
278 hr
= CreateVideoService( sys
->d3ddev
, &IID_IDirectXVideoProcessorService
,
284 ZeroMemory(&dsc
, sizeof(dsc
));
285 dsc
.SampleWidth
= dstDesc
.Width
;
286 dsc
.SampleHeight
= dstDesc
.Height
;
287 dsc
.Format
= dstDesc
.Format
;
288 if (filter
->fmt_in
.video
.i_frame_rate
&& filter
->fmt_in
.video
.i_frame_rate_base
) {
289 dsc
.InputSampleFreq
.Numerator
= filter
->fmt_in
.video
.i_frame_rate
;
290 dsc
.InputSampleFreq
.Denominator
= filter
->fmt_in
.video
.i_frame_rate_base
;
292 dsc
.InputSampleFreq
.Numerator
= 0;
293 dsc
.InputSampleFreq
.Denominator
= 0;
295 dsc
.OutputFrameFreq
= dsc
.InputSampleFreq
;
297 DXVA2_ExtendedFormat
*pFormat
= &dsc
.SampleFormat
;
298 pFormat
->SampleFormat
= DXVA2_SampleProgressiveFrame
;
301 hr
= IDirectXVideoProcessorService_GetVideoProcessorDeviceGuids( processor
,
308 const UINT neededCaps
= DXVA2_ProcAmp_Brightness
|
309 DXVA2_ProcAmp_Contrast
|
311 DXVA2_ProcAmp_Saturation
;
312 DXVA2_VideoProcessorCaps caps
;
313 unsigned best_score
= 0;
314 for (UINT i
=0; i
<count
; ++i
) {
315 hr
= IDirectXVideoProcessorService_GetVideoProcessorCaps( processor
,
320 if ( FAILED(hr
) || !caps
.ProcAmpControlCaps
)
323 unsigned score
= (caps
.ProcAmpControlCaps
& neededCaps
) ? 10 : 1;
324 if (best_score
< score
) {
326 processorGUID
= processorGUIDs
+ i
;
330 if (processorGUID
== NULL
)
332 msg_Dbg(filter
, "Could not find a filter to output the required format");
336 hr
= IDirectXVideoProcessorService_GetProcAmpRange( processor
, processorGUID
, &dsc
,
337 dstDesc
.Format
, DXVA2_ProcAmp_Brightness
,
338 &sys
->Brightness
.Range
);
342 hr
= IDirectXVideoProcessorService_GetProcAmpRange( processor
, processorGUID
, &dsc
,
343 dstDesc
.Format
, DXVA2_ProcAmp_Contrast
,
344 &sys
->Contrast
.Range
);
348 hr
= IDirectXVideoProcessorService_GetProcAmpRange( processor
, processorGUID
, &dsc
,
349 dstDesc
.Format
, DXVA2_ProcAmp_Hue
,
354 hr
= IDirectXVideoProcessorService_GetProcAmpRange( processor
, processorGUID
, &dsc
,
355 dstDesc
.Format
, DXVA2_ProcAmp_Saturation
,
356 &sys
->Saturation
.Range
);
360 /* needed to get options passed in transcode using the
361 * adjust{name=value} syntax */
362 config_ChainParse( filter
, "", ppsz_filter_options
, filter
->p_cfg
);
364 InitLevel(filter
, &sys
->Contrast
, "contrast", 1.0 );
365 InitLevel(filter
, &sys
->Brightness
, "brightness", 1.0 );
366 InitLevel(filter
, &sys
->Hue
, "hue", 0.0 );
367 InitLevel(filter
, &sys
->Saturation
, "saturation", 1.0 );
369 var_AddCallback( filter
, "contrast", AdjustCallback
, sys
);
370 var_AddCallback( filter
, "brightness", AdjustCallback
, sys
);
371 var_AddCallback( filter
, "hue", AdjustCallback
, sys
);
372 var_AddCallback( filter
, "saturation", AdjustCallback
, sys
);
373 var_AddCallback( filter
, "gamma", AdjustCallback
, sys
);
374 var_AddCallback( filter
, "brightness-threshold",
375 AdjustCallback
, sys
);
377 hr
= IDirectXVideoProcessorService_CreateVideoProcessor( processor
,
386 hr
= IDirectXVideoProcessorService_CreateSurface( processor
,
393 DXVA2_VideoProcessorRenderTarget
,
399 CoTaskMemFree(processorGUIDs
);
400 picture_Release(dst
);
401 IDirectXVideoProcessorService_Release(processor
);
403 sys
->hdecoder_dll
= hdecoder_dll
;
404 sys
->d3d9_dll
= d3d9_dll
;
406 filter
->pf_video_filter
= Filter
;
411 CoTaskMemFree(processorGUIDs
);
412 if (sys
&& sys
->processor
)
413 IDirectXVideoProcessor_Release( sys
->processor
);
415 IDirectXVideoProcessorService_Release(processor
);
416 if (sys
&& sys
->d3ddev
)
417 IDirect3DDevice9_Release( sys
->d3ddev
);
419 FreeLibrary(hdecoder_dll
);
421 FreeLibrary(d3d9_dll
);
423 picture_Release(dst
);
429 static void D3D9CloseAdjust(vlc_object_t
*obj
)
431 filter_t
*filter
= (filter_t
*)obj
;
432 filter_sys_t
*sys
= filter
->p_sys
;
434 IDirect3DSurface9_Release( sys
->hw_surface
);
435 IDirectXVideoProcessor_Release( sys
->processor
);
436 IDirect3DDevice9_Release( sys
->d3ddev
);
437 FreeLibrary( sys
->hdecoder_dll
);
438 FreeLibrary( sys
->d3d9_dll
);
444 set_description(N_("Direct3D9 adjust filter"))
445 set_capability("video filter", 0)
446 set_category(CAT_VIDEO
)
447 set_subcategory(SUBCAT_VIDEO_VFILTER
)
448 set_callbacks(D3D9OpenAdjust
, D3D9CloseAdjust
)
449 add_shortcut( "adjust" )
451 add_float_with_range( "contrast", 1.0, 0.0, 2.0,
452 CONT_TEXT
, CONT_LONGTEXT
, false )
454 add_float_with_range( "brightness", 1.0, 0.0, 2.0,
455 LUM_TEXT
, LUM_LONGTEXT
, false )
457 add_float_with_range( "hue", 0, -180., +180.,
458 HUE_TEXT
, HUE_LONGTEXT
, false )
460 add_float_with_range( "saturation", 1.0, 0.0, 3.0,
461 SAT_TEXT
, SAT_LONGTEXT
, false )
463 add_float_with_range( "gamma", 1.0, 0.01, 10.0,
464 GAMMA_TEXT
, GAMMA_LONGTEXT
, false )
466 add_bool( "brightness-threshold", false,
467 THRES_TEXT
, THRES_LONGTEXT
, false )
471 set_callbacks(D3D9OpenDeinterlace
, D3D9CloseDeinterlace
)
472 add_shortcut ("deinterlace")
475 set_capability( "video converter", 10 )
476 set_callbacks( D3D9OpenConverter
, D3D9CloseConverter
)
479 set_callbacks( D3D9OpenCPUConverter
, D3D9CloseCPUConverter
)
480 set_capability( "video converter", 10 )