direct3d11: fix leak when given improper data
[vlc.git] / modules / video_output / win32 / d3d11_adjust.c
blob3efc83245a5e63480199f32a5fb52bdbc8ccc0bc
1 /*****************************************************************************
2 * d3d11_adjust.c: D3D11 adjust filter (no gamma)
3 *****************************************************************************
4 * Copyright (C) 2017 Videolabs SAS
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 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 #include <stdlib.h>
28 #include <assert.h>
30 #include <vlc_common.h>
31 #include <vlc_configuration.h>
32 #include <vlc_plugin.h>
33 #include <vlc_filter.h>
34 #include <vlc_picture.h>
35 #include <vlc_atomic.h>
37 #define COBJMACROS
38 #include <initguid.h>
39 #include <d3d11.h>
41 #include "../../video_chroma/d3d11_fmt.h"
43 #ifdef __MINGW32__
44 #define D3D11_VIDEO_PROCESSOR_FILTER_CAPS_BRIGHTNESS 0x1
45 #define D3D11_VIDEO_PROCESSOR_FILTER_CAPS_CONTRAST 0x2
46 #define D3D11_VIDEO_PROCESSOR_FILTER_CAPS_HUE 0x4
47 #define D3D11_VIDEO_PROCESSOR_FILTER_CAPS_SATURATION 0x8
48 #endif
50 #define PROCESSOR_SLICES 2
52 struct filter_level
54 atomic_int level;
55 float default_val;
56 float min;
57 float max;
58 D3D11_VIDEO_PROCESSOR_FILTER_RANGE Range;
61 struct filter_sys_t
63 float f_gamma;
64 bool b_brightness_threshold;
66 struct filter_level Brightness;
67 struct filter_level Contrast;
68 struct filter_level Hue;
69 struct filter_level Saturation;
71 ID3D11VideoDevice *d3dviddev;
72 ID3D11VideoContext *d3dvidctx;
73 ID3D11VideoProcessor *videoProcessor;
74 ID3D11VideoProcessorEnumerator *procEnumerator;
76 HANDLE context_mutex;
77 union {
78 ID3D11Texture2D *outTexture;
79 ID3D11Resource *outResource;
81 ID3D11VideoProcessorInputView *procInput[PROCESSOR_SLICES];
82 ID3D11VideoProcessorOutputView *procOutput[PROCESSOR_SLICES];
85 #define THRES_TEXT N_("Brightness threshold")
86 #define THRES_LONGTEXT N_("When this mode is enabled, pixels will be " \
87 "shown as black or white. The threshold value will be the brightness " \
88 "defined below." )
89 #define CONT_TEXT N_("Image contrast (0-2)")
90 #define CONT_LONGTEXT N_("Set the image contrast, between 0 and 2. Defaults to 1.")
91 #define HUE_TEXT N_("Image hue (0-360)")
92 #define HUE_LONGTEXT N_("Set the image hue, between 0 and 360. Defaults to 0.")
93 #define SAT_TEXT N_("Image saturation (0-3)")
94 #define SAT_LONGTEXT N_("Set the image saturation, between 0 and 3. Defaults to 1.")
95 #define LUM_TEXT N_("Image brightness (0-2)")
96 #define LUM_LONGTEXT N_("Set the image brightness, between 0 and 2. Defaults to 1.")
97 #define GAMMA_TEXT N_("Image gamma (0-10)")
98 #define GAMMA_LONGTEXT N_("Set the image gamma, between 0.01 and 10. Defaults to 1.")
100 static const char *const ppsz_filter_options[] = {
101 "contrast", "brightness", "hue", "saturation", "gamma",
102 "brightness-threshold", NULL
105 static int assert_ProcessorInput(filter_t *p_filter, picture_sys_t *p_sys_src)
107 filter_sys_t *p_sys = p_filter->p_sys;
108 if (!p_sys_src->processorInput)
110 D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inDesc = {
111 .FourCC = 0,
112 .ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D,
113 .Texture2D.MipSlice = 0,
114 .Texture2D.ArraySlice = p_sys_src->slice_index,
116 HRESULT hr;
118 hr = ID3D11VideoDevice_CreateVideoProcessorInputView(p_sys->d3dviddev,
119 p_sys_src->resource[KNOWN_DXGI_INDEX],
120 p_sys->procEnumerator,
121 &inDesc,
122 &p_sys_src->processorInput);
123 if (FAILED(hr))
125 #ifndef NDEBUG
126 msg_Dbg(p_filter,"Failed to create processor input for slice %d. (hr=0x%lX)", p_sys_src->slice_index, hr);
127 #endif
128 return VLC_EGENERIC;
131 return VLC_SUCCESS;
134 static bool ApplyFilter( filter_sys_t *p_sys,
135 D3D11_VIDEO_PROCESSOR_FILTER filter,
136 const struct filter_level *p_level,
137 ID3D11VideoProcessorInputView *input,
138 ID3D11VideoProcessorOutputView *output )
140 HRESULT hr;
142 int level = atomic_load(&p_level->level);
143 if (level == p_level->Range.Default)
144 return false;
146 ID3D11VideoContext_VideoProcessorSetStreamFilter(p_sys->d3dvidctx,
147 p_sys->videoProcessor,
149 filter,
150 TRUE,
151 level);
153 D3D11_VIDEO_PROCESSOR_STREAM stream = {0};
154 stream.Enable = TRUE;
155 stream.pInputSurface = input;
157 hr = ID3D11VideoContext_VideoProcessorBlt(p_sys->d3dvidctx,
158 p_sys->videoProcessor,
159 output,
160 0, 1, &stream);
161 return SUCCEEDED(hr);
164 static void SetLevel(struct filter_level *range, float val)
166 int level;
167 if (val > range->default_val)
168 level = (range->Range.Maximum - range->Range.Default) * (val - range->default_val) /
169 (range->max - range->default_val);
170 else if (val < range->default_val)
171 level = (range->Range.Minimum - range->Range.Default) * (val - range->default_val) /
172 (range->min - range->default_val);
173 else
174 level = 0;
176 atomic_store( &range->level, range->Range.Default + level );
179 static void InitLevel(filter_t *filter, struct filter_level *range, const char *p_name, float def)
181 int level = 0;
183 module_config_t *cfg = config_FindConfig(p_name);
184 if (unlikely(cfg == NULL))
186 range->min = 0.;
187 range->max = 2.;
188 range->default_val = 1.;
190 else
192 range->min = cfg->min.f;
193 range->max = cfg->max.f;
194 range->default_val = def;
196 float val = var_CreateGetFloatCommand( filter, p_name );
198 if (val > range->default_val)
199 level = (range->Range.Maximum - range->Range.Default) * (val - range->default_val) /
200 (range->max - range->default_val);
201 else if (val < range->default_val)
202 level = (range->Range.Minimum - range->Range.Default) * (val - range->default_val) /
203 (range->min - range->default_val);
206 atomic_init( &range->level, range->Range.Default + level );
209 static picture_t *Filter(filter_t *p_filter, picture_t *p_pic)
211 filter_sys_t *p_sys = p_filter->p_sys;
213 picture_sys_t *p_src_sys = ActivePictureSys(p_pic);
214 if ( assert_ProcessorInput(p_filter, ActivePictureSys(p_pic) ) )
216 picture_Release( p_pic );
217 return NULL;
220 picture_t *p_outpic = filter_NewPicture( p_filter );
221 if( !p_outpic )
223 picture_Release( p_pic );
224 return NULL;
227 picture_CopyProperties( p_outpic, p_pic );
229 if( p_sys->context_mutex != INVALID_HANDLE_VALUE )
230 WaitForSingleObjectEx( p_sys->context_mutex, INFINITE, FALSE );
232 ID3D11VideoProcessorInputView *inputs[4] = {
233 p_src_sys->processorInput,
234 p_sys->procInput[0],
235 p_sys->procInput[1],
236 p_sys->procInput[0]
239 ID3D11VideoProcessorOutputView *outputs[4] = {
240 p_sys->procOutput[0],
241 p_sys->procOutput[1],
242 p_sys->procOutput[0],
243 p_sys->procOutput[1]
246 size_t idx = 0;
247 /* contrast */
248 if ( ApplyFilter( p_sys,
249 D3D11_VIDEO_PROCESSOR_FILTER_CONTRAST, &p_sys->Contrast,
250 inputs[idx], outputs[idx] ) )
251 idx++;
252 /* brightness */
253 if ( ApplyFilter( p_sys,
254 D3D11_VIDEO_PROCESSOR_FILTER_BRIGHTNESS, &p_sys->Brightness,
255 inputs[idx], outputs[idx] ) )
256 idx++;
257 /* hue */
258 if ( ApplyFilter( p_sys,
259 D3D11_VIDEO_PROCESSOR_FILTER_HUE, &p_sys->Hue,
260 inputs[idx], outputs[idx] ) )
261 idx++;
262 /* saturation */
263 if ( ApplyFilter( p_sys,
264 D3D11_VIDEO_PROCESSOR_FILTER_SATURATION, &p_sys->Saturation,
265 inputs[idx], outputs[idx] ) )
266 idx++;
268 ID3D11DeviceContext_CopySubresourceRegion(p_outpic->p_sys->context,
269 p_outpic->p_sys->resource[KNOWN_DXGI_INDEX],
270 p_outpic->p_sys->slice_index,
271 0, 0, 0,
272 p_sys->outResource,
273 outputs[idx] == p_sys->procOutput[0] ? 1 : 0,
274 NULL);
276 if( p_sys->context_mutex != INVALID_HANDLE_VALUE )
277 ReleaseMutex( p_sys->context_mutex );
279 picture_Release( p_pic );
280 return p_outpic;
283 static int AdjustCallback( vlc_object_t *p_this, char const *psz_var,
284 vlc_value_t oldval, vlc_value_t newval,
285 void *p_data )
287 VLC_UNUSED(p_this); VLC_UNUSED(oldval);
288 filter_sys_t *p_sys = (filter_sys_t *)p_data;
290 if( !strcmp( psz_var, "contrast" ) )
291 SetLevel( &p_sys->Contrast, newval.f_float );
292 else if( !strcmp( psz_var, "brightness" ) )
293 SetLevel( &p_sys->Brightness, newval.f_float );
294 else if( !strcmp( psz_var, "hue" ) )
295 SetLevel( &p_sys->Hue, newval.f_float );
296 else if( !strcmp( psz_var, "saturation" ) )
297 SetLevel( &p_sys->Saturation, newval.f_float );
299 return VLC_SUCCESS;
302 static int Open(vlc_object_t *obj)
304 filter_t *filter = (filter_t *)obj;
305 HRESULT hr;
306 ID3D11Device *d3ddevice = NULL;
307 ID3D11VideoProcessorEnumerator *processorEnumerator = NULL;
309 if (filter->fmt_in.video.i_chroma != VLC_CODEC_D3D11_OPAQUE
310 && filter->fmt_in.video.i_chroma != VLC_CODEC_D3D11_OPAQUE_10B)
311 return VLC_EGENERIC;
312 if (!video_format_IsSimilar(&filter->fmt_in.video, &filter->fmt_out.video))
313 return VLC_EGENERIC;
315 picture_t *dst = filter_NewPicture(filter);
316 if (dst == NULL)
317 return VLC_EGENERIC;
318 if (!dst->p_sys)
320 msg_Dbg(filter, "D3D11 opaque without a texture");
321 picture_Release(dst);
322 return VLC_EGENERIC;
325 D3D11_TEXTURE2D_DESC dstDesc;
326 ID3D11Texture2D_GetDesc(dst->p_sys->texture[KNOWN_DXGI_INDEX], &dstDesc);
328 filter_sys_t *sys = malloc(sizeof (*sys));
329 if (unlikely(sys == NULL))
330 goto error;
331 memset(sys, 0, sizeof (*sys));
333 ID3D11DeviceContext_GetDevice(dst->p_sys->context, &d3ddevice);
335 hr = ID3D11Device_QueryInterface(d3ddevice, &IID_ID3D11VideoDevice, (void **)&sys->d3dviddev);
336 if (FAILED(hr)) {
337 msg_Err(filter, "Could not Query ID3D11VideoDevice Interface. (hr=0x%lX)", hr);
338 goto error;
341 hr = ID3D11DeviceContext_QueryInterface(dst->p_sys->context, &IID_ID3D11VideoContext, (void **)&sys->d3dvidctx);
342 if (FAILED(hr)) {
343 msg_Err(filter, "Could not Query ID3D11VideoContext Interface from the picture. (hr=0x%lX)", hr);
344 goto error;
347 HANDLE context_lock = INVALID_HANDLE_VALUE;
348 UINT dataSize = sizeof(context_lock);
349 hr = ID3D11Device_GetPrivateData(d3ddevice, &GUID_CONTEXT_MUTEX, &dataSize, &context_lock);
350 if (FAILED(hr))
351 msg_Warn(filter, "No mutex found to lock the decoder");
352 sys->context_mutex = context_lock;
354 const video_format_t *fmt = &dst->format;
356 D3D11_VIDEO_PROCESSOR_CONTENT_DESC processorDesc = {
357 .InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE,
358 .InputFrameRate = {
359 .Numerator = fmt->i_frame_rate,
360 .Denominator = fmt->i_frame_rate_base,
362 .InputWidth = fmt->i_width,
363 .InputHeight = fmt->i_height,
364 .OutputWidth = dst->format.i_width,
365 .OutputHeight = dst->format.i_height,
366 .OutputFrameRate = {
367 .Numerator = dst->format.i_frame_rate,
368 .Denominator = dst->format.i_frame_rate_base,
370 .Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL,
372 hr = ID3D11VideoDevice_CreateVideoProcessorEnumerator(sys->d3dviddev, &processorDesc, &processorEnumerator);
373 if ( processorEnumerator == NULL )
375 msg_Dbg(filter, "Can't get a video processor for the video.");
376 goto error;
379 UINT flags;
380 #ifndef NDEBUG
381 for (int format = 0; format < 188; format++) {
382 hr = ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator, format, &flags);
383 if (SUCCEEDED(hr) && (flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT))
384 msg_Dbg(filter, "processor format %s (%d) is supported for input", DxgiFormatToStr(format),format);
385 if (SUCCEEDED(hr) && (flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT))
386 msg_Dbg(filter, "processor format %s (%d) is supported for output", DxgiFormatToStr(format),format);
388 #endif
389 hr = ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator, dst->p_sys->formatTexture, &flags);
390 if (!SUCCEEDED(hr))
392 msg_Dbg(filter, "can't read processor support for %s", DxgiFormatToStr(dst->p_sys->formatTexture));
393 goto error;
395 if ( !(flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT) ||
396 !(flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT) )
398 msg_Dbg(filter, "input/output %s is not supported", DxgiFormatToStr(dst->p_sys->formatTexture));
399 goto error;
402 D3D11_VIDEO_PROCESSOR_CAPS processorCaps;
403 hr = ID3D11VideoProcessorEnumerator_GetVideoProcessorCaps(processorEnumerator, &processorCaps);
404 if (FAILED(hr))
405 goto error;
407 const UINT neededCaps = D3D11_VIDEO_PROCESSOR_FILTER_CAPS_BRIGHTNESS |
408 D3D11_VIDEO_PROCESSOR_FILTER_CAPS_CONTRAST |
409 D3D11_VIDEO_PROCESSOR_FILTER_CAPS_HUE |
410 D3D11_VIDEO_PROCESSOR_FILTER_CAPS_SATURATION;
411 if ((processorCaps.FilterCaps & neededCaps) != neededCaps)
413 msg_Dbg(filter, "missing capabilities 0x%x", neededCaps - (processorCaps.FilterCaps & neededCaps));
414 goto error;
417 hr = ID3D11VideoProcessorEnumerator_GetVideoProcessorFilterRange(processorEnumerator,
418 D3D11_VIDEO_PROCESSOR_FILTER_BRIGHTNESS,
419 &sys->Brightness.Range);
420 if (FAILED(hr))
421 goto error;
423 hr = ID3D11VideoProcessorEnumerator_GetVideoProcessorFilterRange(processorEnumerator,
424 D3D11_VIDEO_PROCESSOR_FILTER_CONTRAST,
425 &sys->Contrast.Range);
426 if (FAILED(hr))
427 goto error;
429 hr = ID3D11VideoProcessorEnumerator_GetVideoProcessorFilterRange(processorEnumerator,
430 D3D11_VIDEO_PROCESSOR_FILTER_HUE,
431 &sys->Hue.Range);
432 if (FAILED(hr))
433 goto error;
435 hr = ID3D11VideoProcessorEnumerator_GetVideoProcessorFilterRange(processorEnumerator,
436 D3D11_VIDEO_PROCESSOR_FILTER_SATURATION,
437 &sys->Saturation.Range);
438 if (FAILED(hr))
439 goto error;
441 /* needed to get options passed in transcode using the
442 * adjust{name=value} syntax */
443 config_ChainParse( filter, "", ppsz_filter_options, filter->p_cfg );
445 InitLevel(filter, &sys->Contrast, "contrast", 1.0 );
446 InitLevel(filter, &sys->Brightness, "brightness", 1.0 );
447 InitLevel(filter, &sys->Hue, "hue", 0.0 );
448 InitLevel(filter, &sys->Saturation, "saturation", 1.0 );
449 sys->f_gamma = var_CreateGetFloatCommand( filter, "gamma" );
450 sys->b_brightness_threshold =
451 var_CreateGetBoolCommand( filter, "brightness-threshold" );
453 var_AddCallback( filter, "contrast", AdjustCallback, sys );
454 var_AddCallback( filter, "brightness", AdjustCallback, sys );
455 var_AddCallback( filter, "hue", AdjustCallback, sys );
456 var_AddCallback( filter, "saturation", AdjustCallback, sys );
457 var_AddCallback( filter, "gamma", AdjustCallback, sys );
458 var_AddCallback( filter, "brightness-threshold",
459 AdjustCallback, sys );
461 hr = ID3D11VideoDevice_CreateVideoProcessor(sys->d3dviddev,
462 processorEnumerator, 0,
463 &sys->videoProcessor);
464 if (FAILED(hr) || sys->videoProcessor == NULL)
466 msg_Dbg(filter, "failed to create the processor");
467 goto error;
470 D3D11_TEXTURE2D_DESC texDesc;
471 ZeroMemory(&texDesc, sizeof(texDesc));
472 texDesc.MipLevels = 1;
473 texDesc.SampleDesc.Count = 1;
474 texDesc.MiscFlags = 0; //D3D11_RESOURCE_MISC_SHARED;
475 texDesc.Usage = D3D11_USAGE_DEFAULT;
476 texDesc.CPUAccessFlags = 0;
477 texDesc.Format = dstDesc.Format;
478 texDesc.BindFlags = D3D11_BIND_RENDER_TARGET;
479 texDesc.Usage = D3D11_USAGE_DEFAULT;
480 texDesc.CPUAccessFlags = 0;
481 texDesc.ArraySize = PROCESSOR_SLICES;
482 texDesc.Height = dstDesc.Height;
483 texDesc.Width = dstDesc.Width;
485 hr = ID3D11Device_CreateTexture2D( d3ddevice, &texDesc, NULL, &sys->outTexture );
486 if (FAILED(hr)) {
487 msg_Err(filter, "CreateTexture2D failed. (hr=0x%0lx)", hr);
488 goto error;
491 D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outDesc = {
492 .ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2DARRAY,
493 .Texture2DArray.MipSlice = 0,
494 .Texture2DArray.ArraySize = 1,
497 D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inDesc = {
498 .FourCC = 0,
499 .ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D,
500 .Texture2D.MipSlice = 0,
503 for (int i=0; i<PROCESSOR_SLICES; i++)
505 outDesc.Texture2DArray.FirstArraySlice = i;
506 hr = ID3D11VideoDevice_CreateVideoProcessorOutputView(sys->d3dviddev,
507 sys->outResource,
508 processorEnumerator,
509 &outDesc,
510 &sys->procOutput[i]);
511 if (FAILED(hr))
513 msg_Dbg(filter,"Failed to create processor output. (hr=0x%lX)", hr);
514 goto error;
517 inDesc.Texture2D.ArraySlice = i;
518 hr = ID3D11VideoDevice_CreateVideoProcessorInputView(sys->d3dviddev,
519 sys->outResource,
520 processorEnumerator,
521 &inDesc,
522 &sys->procInput[i]);
524 if (FAILED(hr))
526 msg_Dbg(filter,"Failed to create processor input. (hr=0x%lX)", hr);
527 goto error;
531 sys->procEnumerator = processorEnumerator;
533 filter->pf_video_filter = Filter;
534 filter->p_sys = sys;
536 ID3D11Device_Release(d3ddevice);
537 picture_Release(dst);
538 return VLC_SUCCESS;
539 error:
540 if (d3ddevice)
541 ID3D11Device_Release(d3ddevice);
542 picture_Release(dst);
544 for (int i=0; i<PROCESSOR_SLICES; i++)
546 if (sys->procInput[i])
547 ID3D11VideoProcessorInputView_Release(sys->procInput[i]);
548 if (sys->procOutput[i])
549 ID3D11VideoProcessorOutputView_Release(sys->procOutput[i]);
552 if (sys->outTexture)
553 ID3D11Texture2D_Release(sys->outTexture);
554 if (sys->videoProcessor)
555 ID3D11VideoProcessor_Release(sys->videoProcessor);
556 if (processorEnumerator)
557 ID3D11VideoProcessorEnumerator_Release(processorEnumerator);
558 if (sys->d3dvidctx)
559 ID3D11VideoContext_Release(sys->d3dvidctx);
560 if (sys->d3dviddev)
561 ID3D11VideoDevice_Release(sys->d3dviddev);
563 return VLC_EGENERIC;
566 static void Close(vlc_object_t *obj)
568 filter_t *filter = (filter_t *)obj;
569 filter_sys_t *sys = filter->p_sys;
571 var_DelCallback( filter, "contrast", AdjustCallback, sys );
572 var_DelCallback( filter, "brightness", AdjustCallback, sys );
573 var_DelCallback( filter, "hue", AdjustCallback, sys );
574 var_DelCallback( filter, "saturation", AdjustCallback, sys );
575 var_DelCallback( filter, "gamma", AdjustCallback, sys );
576 var_DelCallback( filter, "brightness-threshold",
577 AdjustCallback, sys );
579 for (int i=0; i<PROCESSOR_SLICES; i++)
581 ID3D11VideoProcessorInputView_Release(sys->procInput[i]);
582 ID3D11VideoProcessorOutputView_Release(sys->procOutput[i]);
584 ID3D11Texture2D_Release(sys->outTexture);
585 ID3D11VideoProcessor_Release(sys->videoProcessor);
586 ID3D11VideoProcessorEnumerator_Release(sys->procEnumerator);
587 ID3D11VideoContext_Release(sys->d3dvidctx);
588 ID3D11VideoDevice_Release(sys->d3dviddev);
590 free(sys);
593 vlc_module_begin()
594 set_description(N_("Direct3D11 adjust filter"))
595 set_capability("video filter", 0)
596 set_category( CAT_VIDEO )
597 set_subcategory( SUBCAT_VIDEO_VFILTER )
598 set_callbacks(Open, Close)
599 add_shortcut( "adjust" )
601 add_float_with_range( "contrast", 1.0, 0.0, 2.0,
602 CONT_TEXT, CONT_LONGTEXT, false )
603 change_safe()
604 add_float_with_range( "brightness", 1.0, 0.0, 2.0,
605 LUM_TEXT, LUM_LONGTEXT, false )
606 change_safe()
607 add_float_with_range( "hue", 0, -180., +180.,
608 HUE_TEXT, HUE_LONGTEXT, false )
609 change_safe()
610 add_float_with_range( "saturation", 1.0, 0.0, 3.0,
611 SAT_TEXT, SAT_LONGTEXT, false )
612 change_safe()
613 add_float_with_range( "gamma", 1.0, 0.01, 10.0,
614 GAMMA_TEXT, GAMMA_LONGTEXT, false )
615 change_safe()
616 add_bool( "brightness-threshold", false,
617 THRES_TEXT, THRES_LONGTEXT, false )
618 change_safe()
620 vlc_module_end()