]> git.sesse.net Git - vlc/blob - modules/video_filter/atmo/atmo.cpp
518e2c5aee10ff393ebf7aa498b17d56f2c29458
[vlc] / modules / video_filter / atmo / atmo.cpp
1 /*****************************************************************************
2  * atmo.cpp : "Atmo Light" video filter
3  *****************************************************************************
4  * Copyright (C) 2000-2006 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: AndrĂ© Weber (WeberAndre@gmx.de)
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 /*****************************************************************************
29 * Preamble
30 *****************************************************************************/
31 #define __STDC_FORMAT_MACROS 1
32 #include <stdlib.h>                                      /* malloc(), free() */
33 #include <string.h>
34 #include <math.h>                                            /* sin(), cos() */
35 #include <assert.h>
36
37 // #define __ATMO_DEBUG__
38
39 // [:Zs]+$
40 #include <vlc_common.h>
41 #include <vlc_plugin.h>
42 #include <vlc_vout.h>
43
44 #include <vlc_filter.h>
45 #include <vlc_atomic.h>
46 #include <vlc_charset.h>
47
48 #include "filter_picture.h"
49
50 #include "AtmoDefs.h"
51 #include "AtmoDynData.h"
52 #include "AtmoLiveView.h"
53 #include "AtmoTools.h"
54 #include "AtmoExternalCaptureInput.h"
55 #include "AtmoConfig.h"
56 #include "AtmoConnection.h"
57 #include "AtmoClassicConnection.h"
58
59
60 /*****************************************************************************
61 * Local prototypes
62 *****************************************************************************/
63 /* directly to vlc related functions required that the module is accepted */
64 static int  CreateFilter    ( vlc_object_t * );
65 static void DestroyFilter   ( vlc_object_t * );
66 static picture_t * Filter( filter_t *, picture_t *);
67
68 /* callback for atmo settings variables whose change
69    should be immediately realized and applied to output
70 */
71 static void DelAtmoSettingsVariablesCallbacks(filter_t *);
72 static void AddAtmoSettingsVariablesCallbacks(filter_t *);
73 static int AtmoSettingsCallback(vlc_object_t *, char const *,
74                                 vlc_value_t, vlc_value_t, void *);
75
76
77 #if defined(__ATMO_DEBUG__)
78 static void atmo_parse_crop(char *psz_cropconfig,
79                             video_format_t fmt_in,
80                             video_format_t fmt_render,
81                             int &i_visible_width,
82                             int &i_visible_height,
83                             int &i_x_offset,
84                             int &i_y_offset );
85 #endif
86
87
88 /* function to shutdown the fade thread which is started on pause*/
89 static void CheckAndStopFadeThread(filter_t *);
90
91 /* extracts a small RGB (BGR) Image from an YUV image */
92 static void ExtractMiniImage_YUV(filter_sys_t *, picture_t *, uint8_t *);
93
94 #if defined(__ATMO_DEBUG__)
95 void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename);
96 #endif
97
98 /*****************************************************************************
99 * External Prototypes for the AtmoCtrlLib.DLL
100 *****************************************************************************/
101 /*
102 * if effectmode = emLivePicture then the source could be GDI (Screencapture)
103 * or External - this means another application delivers Pixeldata to AtmoWin
104 * Clientsoftware through  AtmoCtrlLib.DLL and the COM Api
105 */
106 #define lvsGDI           0
107 #define lvsExternal      1
108
109 #define CLASSIC_ATMO_NUM_ZONES  5
110
111
112 /*
113 strings for settings menus and hints
114 */
115 #define MODULE_DESCRIPTION N_ ( \
116  "This module allows controlling an so called AtmoLight device "\
117  "connected to your computer.\n"\
118  "AtmoLight is the homegrown version of what Philips calls AmbiLight.\n"\
119  "If you need further information feel free to visit us at\n\n"\
120  "http://www.vdr-wiki.de/wiki/index.php/Atmo-plugin\n"\
121  "http://www.vdr-wiki.de/wiki/index.php/AtmoWin\n\n"\
122  "You can find there detailed descriptions on how to build it for yourself "\
123  "and where to get the required parts.\n" \
124  "You can also have a look at pictures and some movies showing such a device " \
125  "in live action.")
126
127 #define DRIVER_TEXT            N_("Device type")
128 #define DRIVER_LONGTEXT        N_("Choose your preferred hardware from " \
129                                   "the list, or choose AtmoWin Software " \
130                                   "to delegate processing to the external " \
131                                   "process - with more options")
132
133 static const int pi_device_type_values[] = {
134 #if defined( _WIN32 )
135      0, /* use AtmoWinA.exe userspace driver */
136 #endif
137      1, /* AtmoLight classic */
138      2, /* Quattro AtmoLight */
139      3, /* DMX Device */
140      4, /* MoMoLight device */
141      5  /* fnordlicht */
142 };
143 static const char *const ppsz_device_type_descriptions[] = {
144 #if defined( _WIN32 )
145         N_("AtmoWin Software"),
146 #endif
147         N_("Classic AtmoLight"),
148         N_("Quattro AtmoLight"),
149         N_("DMX"),
150         N_("MoMoLight"),
151         N_("fnordlicht")
152 };
153
154 #define DMX_CHANNELS_TEXT      N_("Count of AtmoLight channels")
155 #define DMX_CHANNELS_LONGTEXT  N_("How many AtmoLight channels, should be " \
156                                   "emulated with that DMX device")
157 #define DMX_CHBASE_TEXT        N_("DMX address for each channel")
158 #define DMX_CHBASE_LONGTEXT    N_("Define here the DMX base address for each " \
159                                   "channel use , or ; to separate the values")
160
161 #define MOMO_CHANNELS_TEXT      N_("Count of channels")
162 #define MOMO_CHANNELS_LONGTEXT  N_("Depending on your MoMoLight hardware " \
163                                    "choose 3 or 4 channels")
164
165 #define FNORDLICHT_AMOUNT_TEXT      N_("Count of fnordlicht's")
166 #define FNORDLICHT_AMOUNT_LONGTEXT  N_("Depending on the amount your " \
167                                    "fnordlicht hardware " \
168                                    "choose 1 to 254 channels")
169
170 #if defined( _WIN32 )
171 #  define DEFAULT_DEVICE   0
172 #else
173 #  define DEFAULT_DEVICE   1
174 #endif
175
176 #if defined( __ATMO_DEBUG__ )
177 #   define SAVEFRAMES_TEXT     N_("Save Debug Frames")
178 #   define SAVEFRAMES_LONGTEXT N_("Write every 128th miniframe to a folder.")
179 #   define FRAMEPATH_TEXT      N_("Debug Frame Folder")
180 #   define FRAMEPATH_LONGTEXT  N_("The path where the debugframes " \
181                                   "should be saved")
182 #endif
183
184 #define WIDTH_TEXT             N_("Extracted Image Width")
185 #define WIDTH_LONGTEXT         N_("The width of the mini image for " \
186                                   "further processing (64 is default)")
187
188 #define HEIGHT_TEXT            N_("Extracted Image Height")
189 #define HEIGHT_LONGTEXT        N_("The height of the mini image for " \
190                                   "further processing (48 is default)")
191
192 #define SHOW_DOTS_TEXT         N_("Mark analyzed pixels")
193 #define SHOW_DOTS_LONGTEXT     N_("makes the sample grid visible on screen as "\
194                                   "white pixels")
195
196 #define PCOLOR_TEXT            N_("Color when paused")
197 #define PCOLOR_LONGTEXT        N_("Set the color to show if the user " \
198                                   "pauses the video. (Have light to get " \
199                                   "another beer?)")
200 #define PCOLOR_RED_TEXT        N_("Pause-Red")
201 #define PCOLOR_RED_LONGTEXT    N_("Red component of the pause color")
202 #define PCOLOR_GREEN_TEXT      N_("Pause-Green")
203 #define PCOLOR_GREEN_LONGTEXT  N_("Green component of the pause color")
204 #define PCOLOR_BLUE_TEXT       N_("Pause-Blue")
205 #define PCOLOR_BLUE_LONGTEXT   N_("Blue component of the pause color")
206 #define FADESTEPS_TEXT         N_("Pause-Fadesteps")
207 #define FADESTEPS_LONGTEXT     N_("Number of steps to change current color " \
208                                   "to pause color (each step takes 40ms)")
209
210 #define ECOLOR_RED_TEXT        N_("End-Red")
211 #define ECOLOR_RED_LONGTEXT    N_("Red component of the shutdown color")
212 #define ECOLOR_GREEN_TEXT      N_("End-Green")
213 #define ECOLOR_GREEN_LONGTEXT  N_("Green component of the shutdown color")
214 #define ECOLOR_BLUE_TEXT       N_("End-Blue")
215 #define ECOLOR_BLUE_LONGTEXT   N_("Blue component of the shutdown color")
216 #define EFADESTEPS_TEXT        N_("End-Fadesteps")
217 #define EFADESTEPS_LONGTEXT  N_("Number of steps to change current color to " \
218                              "end color for dimming up the light in cinema " \
219                              "style... (each step takes 40ms)")
220
221 #define ZONE_TOP_TEXT          N_("Number of zones on top")
222 #define ZONE_TOP_LONGTEXT      N_("Number of zones on the top of the screen")
223 #define ZONE_BOTTOM_TEXT       N_("Number of zones on bottom")
224 #define ZONE_BOTTOM_LONGTEXT   N_("Number of zones on the bottom of the screen")
225 #define ZONE_LR_TEXT           N_("Zones on left / right side")
226 #define ZONE_LR_LONGTEXT       N_("left and right side having always the " \
227                                   "same number of zones")
228 #define ZONE_SUMMARY_TEXT      N_("Calculate a average zone")
229 #define ZONE_SUMMARY_LONGTEXT  N_("it contains the average of all pixels " \
230                                   "in the sample image (only useful for " \
231                                   "single channel AtmoLight)")
232
233
234 #define USEWHITEADJ_TEXT       N_("Use Software White adjust")
235 #define USEWHITEADJ_LONGTEXT   N_("Should the buildin driver do a white " \
236                                   "adjust or your LED stripes? recommend.")
237 #define WHITE_RED_TEXT         N_("White Red")
238 #define WHITE_RED_LONGTEXT     N_("Red value of a pure white on your "\
239                                   "LED stripes.")
240 #define WHITE_GREEN_TEXT       N_("White Green")
241 #define WHITE_GREEN_LONGTEXT   N_("Green value of a pure white on your "\
242                                   "LED stripes.")
243 #define WHITE_BLUE_TEXT        N_("White Blue")
244 #define WHITE_BLUE_LONGTEXT    N_("Blue value of a pure white on your "\
245                                   "LED stripes.")
246
247 #define SERIALDEV_TEXT         N_("Serial Port/Device")
248 #define SERIALDEV_LONGTEXT   N_("Name of the serial port where the AtmoLight "\
249                                 "controller is attached to.\n" \
250                                 "On Windows usually something like COM1 or " \
251                                 "COM2. On Linux /dev/ttyS01 f.e.")
252
253 #define EDGE_TEXT            N_("Edge weightning")
254 #define EDGE_LONGTEXT        N_("Increasing this value will result in color "\
255                                 "more depending on the border of the frame.")
256 #define BRIGHTNESS_TEXT     N_("Brightness")
257 #define BRIGHTNESS_LONGTEXT N_("Overall brightness of your LED stripes")
258 #define DARKNESS_TEXT       N_("Darkness limit")
259 #define DARKNESS_LONGTEXT   N_("Pixels with a saturation lower than this will "\
260                                "be ignored. Should be greater than one for "\
261                                "letterboxed videos.")
262 #define HUEWINSIZE_TEXT     N_("Hue windowing")
263 #define HUEWINSIZE_LONGTEXT N_("Used for statistics.")
264 #define SATWINSIZE_TEXT     N_("Sat windowing")
265 #define SATWINSIZE_LONGTEXT N_("Used for statistics.")
266
267 #define MEANLENGTH_TEXT     N_("Filter length (ms)")
268 #define MEANLENGTH_LONGTEXT N_("Time it takes until a color is completely "\
269                                 "changed. This prevents flickering.")
270 #define MEANTHRESHOLD_TEXT     N_("Filter threshold")
271 #define MEANTHRESHOLD_LONGTEXT N_("How much a color has to be changed for an "\
272                                   "immediate color change.")
273 #define MEANPERCENTNEW_TEXT     N_("Filter smoothness (%)")
274 #define MEANPERCENTNEW_LONGTEXT N_("Filter Smoothness")
275
276 #define FILTERMODE_TEXT        N_("Output Color filter mode")
277 #define FILTERMODE_LONGTEXT    N_("defines the how the output color should " \
278                                   "be calculated based on previous color")
279
280 static const int pi_filtermode_values[] = {
281        (int)afmNoFilter,
282        (int)afmCombined,
283        (int)afmPercent
284 };
285 static const char *const ppsz_filtermode_descriptions[] = {
286         N_("No Filtering"),
287         N_("Combined"),
288         N_("Percent")
289 };
290
291 #define FRAMEDELAY_TEXT       N_("Frame delay (ms)")
292 #define FRAMEDELAY_LONGTEXT   N_("Helps to get the video output and the light "\
293                                  "effects in sync. Values around 20ms should " \
294                                  "do the trick.")
295
296
297 #define CHANNEL_0_ASSIGN_TEXT N_("Channel 0: summary")
298 #define CHANNEL_1_ASSIGN_TEXT N_("Channel 1: left")
299 #define CHANNEL_2_ASSIGN_TEXT N_("Channel 2: right")
300 #define CHANNEL_3_ASSIGN_TEXT N_("Channel 3: top")
301 #define CHANNEL_4_ASSIGN_TEXT N_("Channel 4: bottom")
302
303 #define CHANNELASSIGN_LONGTEXT N_("Maps the hardware channel X to logical "\
304                                   "zone Y to fix wrong wiring :-)")
305 static const int pi_zone_assignment_values[] = {
306     -1,
307      4,
308      3,
309      1,
310      0,
311      2
312 };
313 static const char *const ppsz_zone_assignment_descriptions[] = {
314         N_("disabled"),
315         N_("Zone 4:summary"),
316         N_("Zone 3:left"),
317         N_("Zone 1:right"),
318         N_("Zone 0:top"),
319         N_("Zone 2:bottom")
320 };
321 #define CHANNELS_ASSIGN_TEXT        N_("Channel / Zone Assignment")
322 #define CHANNELS_ASSIGN_LONGTEXT N_("for devices with more than five " \
323                   "channels / zones write down here for each channel " \
324                   "the zone number to show and separate the values with " \
325                   ", or ; and use -1 to not use some channels. For the " \
326                   "classic AtmoLight the sequence 4,3,1,0,2 would set the " \
327                   "default channel/zone mapping. " \
328                   "Having only two zones on top, and one zone on left and " \
329                   "right and no summary zone the mapping for classic " \
330                   "AtmoLight would be -1,3,2,1,0")
331
332 #define ZONE_0_GRADIENT_TEXT N_("Zone 0: Top gradient")
333 #define ZONE_1_GRADIENT_TEXT N_("Zone 1: Right gradient")
334 #define ZONE_2_GRADIENT_TEXT N_("Zone 2: Bottom gradient")
335 #define ZONE_3_GRADIENT_TEXT N_("Zone 3: Left gradient")
336 #define ZONE_4_GRADIENT_TEXT N_("Zone 4: Summary gradient")
337 #define ZONE_X_GRADIENT_LONG_TEXT N_("Defines a small bitmap with 64x48 "\
338                                      "pixels, containing a grayscale gradient")
339
340 #define GRADIENT_PATH_TEXT      N_("Gradient bitmap searchpath")
341 #define GRADIENT_PATH_LONGTEXT  N_("Now preferred option to assign gradient "\
342     "bitmaps, put them as zone_0.bmp, zone_1.bmp etc. into one folder and "\
343     "set the foldername here")
344
345 #if defined( _WIN32 )
346 #   define ATMOWINEXE_TEXT      N_("Filename of AtmoWin*.exe")
347 #   define ATMOWINEXE_LONGTEXT  N_("if you want the AtmoLight control "\
348                                    "software to be launched by VLC, enter the "\
349                                    "complete path of AtmoWinA.exe here.")
350 #endif
351
352 #define CFG_PREFIX "atmo-"
353
354 /*****************************************************************************
355 * Module descriptor
356 *****************************************************************************/
357 vlc_module_begin ()
358 set_description( N_("AtmoLight Filter") )
359 set_help( MODULE_DESCRIPTION )
360 set_shortname( N_( "AtmoLight" ))
361 set_category( CAT_VIDEO )
362 set_subcategory( SUBCAT_VIDEO_VFILTER )
363
364 set_capability( "video filter2", 0 )
365
366
367 set_section( N_("Choose Devicetype and Connection" ), 0 )
368
369 add_integer( CFG_PREFIX "device", DEFAULT_DEVICE,
370             DRIVER_TEXT, DRIVER_LONGTEXT, false )
371 change_integer_list( pi_device_type_values,
372                      ppsz_device_type_descriptions )
373
374 #if defined(_WIN32)
375 add_string(CFG_PREFIX "serialdev", "COM1",
376            SERIALDEV_TEXT, SERIALDEV_LONGTEXT, false )
377 /*
378     on win32 the executeable external driver application
379     for automatic start if needed
380 */
381 add_loadfile(CFG_PREFIX "atmowinexe", NULL,
382              ATMOWINEXE_TEXT, ATMOWINEXE_LONGTEXT, false )
383 #else
384 add_string(CFG_PREFIX "serialdev", "/dev/ttyUSB0",
385            SERIALDEV_TEXT, SERIALDEV_LONGTEXT, false )
386 #endif
387
388 /*
389     color which is showed if you want durring pausing
390     your movie ... used for both buildin / external
391 */
392 set_section( N_("Illuminate the room with this color on pause" ), 0 )
393 add_bool(CFG_PREFIX "usepausecolor", false,
394          PCOLOR_TEXT, PCOLOR_LONGTEXT, false)
395 add_integer_with_range(CFG_PREFIX "pcolor-red",   0, 0, 255,
396                        PCOLOR_RED_TEXT, PCOLOR_RED_LONGTEXT, false)
397 add_integer_with_range(CFG_PREFIX "pcolor-green", 0, 0, 255,
398                        PCOLOR_GREEN_TEXT, PCOLOR_GREEN_LONGTEXT, false)
399 add_integer_with_range(CFG_PREFIX "pcolor-blue",  192, 0, 255,
400                        PCOLOR_BLUE_TEXT, PCOLOR_BLUE_LONGTEXT, false)
401 add_integer_with_range(CFG_PREFIX "fadesteps", 50, 1, 250,
402                        FADESTEPS_TEXT, FADESTEPS_LONGTEXT, false)
403
404 /*
405     color which is showed if you finished watching your movie ...
406     used for both buildin / external
407 */
408 set_section( N_("Illuminate the room with this color on shutdown" ), 0 )
409 add_integer_with_range(CFG_PREFIX "ecolor-red",   192, 0, 255,
410                        ECOLOR_RED_TEXT,   ECOLOR_RED_LONGTEXT,   false)
411 add_integer_with_range(CFG_PREFIX "ecolor-green", 192, 0, 255,
412                        ECOLOR_GREEN_TEXT, ECOLOR_GREEN_LONGTEXT, false)
413 add_integer_with_range(CFG_PREFIX "ecolor-blue",  192, 0, 255,
414                        ECOLOR_BLUE_TEXT,  ECOLOR_BLUE_LONGTEXT,  false)
415 add_integer_with_range(CFG_PREFIX "efadesteps",    50, 1, 250,
416                        EFADESTEPS_TEXT,   EFADESTEPS_LONGTEXT,    false)
417
418
419 set_section( N_("DMX options" ), 0 )
420 add_integer_with_range(CFG_PREFIX "dmx-channels",   5, 1, 64,
421                        DMX_CHANNELS_TEXT, DMX_CHANNELS_LONGTEXT, false)
422 add_string(CFG_PREFIX "dmx-chbase", "0,3,6,9,12",
423                        DMX_CHBASE_TEXT, DMX_CHBASE_LONGTEXT, false )
424
425 set_section( N_("MoMoLight options" ), 0 )
426 add_integer_with_range(CFG_PREFIX "momo-channels",   3, 3, 4,
427                        MOMO_CHANNELS_TEXT, MOMO_CHANNELS_LONGTEXT, false)
428
429 /* 2,2,4 means 2 is the default value, 1 minimum amount,
430    4 maximum amount
431 */
432 set_section( N_("fnordlicht options" ), 0 )
433 add_integer_with_range(CFG_PREFIX "fnordlicht-amount",   2, 1, 254,
434                        FNORDLICHT_AMOUNT_TEXT,
435                        FNORDLICHT_AMOUNT_LONGTEXT, false)
436
437
438 /*
439   instead of redefining the original AtmoLight zones with gradient
440   bitmaps, we can now define the layout of the zones useing these
441   parameters - the function with the gradient bitmaps would still
442   work (but for most cases its no longer required)
443
444   short description whats this means - f.e. the classic atmo would
445   have this layout
446   zones-top    = 1  - zone 0
447   zones-lr     = 1  - zone 1 und zone 3
448   zones-bottom = 1  - zone 2
449   zone-summary = true - zone 4
450          Z0
451    ,------------,
452    |            |
453  Z3|     Z4     | Z1
454    |____________|
455          Z2
456
457   the zone numbers will be counted clockwise starting at top / left
458   if you want to split the light at the top, without having a bottom zone
459   (which is my private config)
460
461   zones-top    = 2  - zone 0, zone 1
462   zones-lr     = 1  - zone 2 und zone 3
463   zones-bottom = 0
464   zone-summary = false
465
466       Z0    Z1
467    ,------------,
468    |            |
469  Z3|            | Z2
470    |____________|
471
472 */
473
474 set_section( N_("Zone Layout for the build-in Atmo" ), 0 )
475 add_integer_with_range(CFG_PREFIX "zones-top",   1, 0, 16,
476                        ZONE_TOP_TEXT, ZONE_TOP_LONGTEXT, false)
477 add_integer_with_range(CFG_PREFIX "zones-bottom",   1, 0, 16,
478                        ZONE_BOTTOM_TEXT, ZONE_BOTTOM_LONGTEXT, false)
479 add_integer_with_range(CFG_PREFIX "zones-lr",   1, 0, 16,
480                        ZONE_LR_TEXT, ZONE_LR_LONGTEXT, false)
481 add_bool(CFG_PREFIX "zone-summary", false,
482          ZONE_SUMMARY_TEXT, ZONE_SUMMARY_LONGTEXT, false)
483
484 /*
485  settings only for the buildin driver (if external driver app is used
486  these parameters are ignored.)
487
488  definition of parameters for the buildin filter ...
489 */
490 set_section( N_("Settings for the built-in Live Video Processor only" ), 0 )
491
492 add_integer_with_range(CFG_PREFIX "edgeweightning",   3, 1, 30,
493                        EDGE_TEXT, EDGE_LONGTEXT, false)
494
495 add_integer_with_range(CFG_PREFIX "brightness",   100, 50, 300,
496                        BRIGHTNESS_TEXT, BRIGHTNESS_LONGTEXT, false)
497
498 add_integer_with_range(CFG_PREFIX "darknesslimit",   3, 0, 10,
499                        DARKNESS_TEXT, DARKNESS_LONGTEXT, false)
500
501 add_integer_with_range(CFG_PREFIX "huewinsize",   3, 0, 5,
502                        HUEWINSIZE_TEXT, HUEWINSIZE_LONGTEXT, false)
503
504 add_integer_with_range(CFG_PREFIX "satwinsize",   3, 0, 5,
505                        SATWINSIZE_TEXT, SATWINSIZE_LONGTEXT, false)
506
507 add_integer(CFG_PREFIX "filtermode", (int)afmCombined,
508             FILTERMODE_TEXT, FILTERMODE_LONGTEXT, false )
509
510 change_integer_list(pi_filtermode_values, ppsz_filtermode_descriptions )
511
512 add_integer_with_range(CFG_PREFIX "meanlength",    300, 300, 5000,
513                        MEANLENGTH_TEXT, MEANLENGTH_LONGTEXT, false)
514
515 add_integer_with_range(CFG_PREFIX "meanthreshold",  40, 1, 100,
516                        MEANTHRESHOLD_TEXT, MEANTHRESHOLD_LONGTEXT, false)
517
518 add_integer_with_range(CFG_PREFIX "percentnew", 50, 1, 100,
519                       MEANPERCENTNEW_TEXT, MEANPERCENTNEW_LONGTEXT, false)
520
521 add_integer_with_range(CFG_PREFIX "framedelay", 18, 0, 200,
522                        FRAMEDELAY_TEXT, FRAMEDELAY_LONGTEXT, false)
523
524 /*
525   output channel reordering
526 */
527 set_section( N_("Change channel assignment (fixes wrong wiring)" ), 0 )
528 add_integer( CFG_PREFIX "channel_0", 4,
529             CHANNEL_0_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
530 change_integer_list( pi_zone_assignment_values,
531                      ppsz_zone_assignment_descriptions )
532
533 add_integer( CFG_PREFIX "channel_1", 3,
534             CHANNEL_1_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
535 change_integer_list( pi_zone_assignment_values,
536                      ppsz_zone_assignment_descriptions )
537
538 add_integer( CFG_PREFIX "channel_2", 1,
539             CHANNEL_2_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
540 change_integer_list( pi_zone_assignment_values,
541                      ppsz_zone_assignment_descriptions )
542
543 add_integer( CFG_PREFIX "channel_3", 0,
544             CHANNEL_3_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
545 change_integer_list( pi_zone_assignment_values,
546                      ppsz_zone_assignment_descriptions )
547
548 add_integer( CFG_PREFIX "channel_4", 2,
549             CHANNEL_4_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
550 change_integer_list( pi_zone_assignment_values,
551                      ppsz_zone_assignment_descriptions )
552
553 add_string(CFG_PREFIX "channels", "",
554            CHANNELS_ASSIGN_TEXT, CHANNELS_ASSIGN_LONGTEXT, false )
555
556
557 /*
558   LED color white calibration
559 */
560 set_section( N_("Adjust the white light to your LED stripes" ), 0 )
561 add_bool(CFG_PREFIX "whiteadj", true,
562          USEWHITEADJ_TEXT, USEWHITEADJ_LONGTEXT, false)
563 add_integer_with_range(CFG_PREFIX "white-red",   255, 0, 255,
564                        WHITE_RED_TEXT,   WHITE_RED_LONGTEXT,   false)
565
566 add_integer_with_range(CFG_PREFIX "white-green", 255, 0, 255,
567                        WHITE_GREEN_TEXT, WHITE_GREEN_LONGTEXT, false)
568
569 add_integer_with_range(CFG_PREFIX "white-blue",  255, 0, 255,
570                        WHITE_BLUE_TEXT,  WHITE_BLUE_LONGTEXT,  false)
571 /* end of definition of parameter for the buildin filter ... part 1 */
572
573
574 /*
575 only for buildin (external has own definition) per default the calucation
576 used linear gradients for assigning a priority to the pixel - depending
577 how near they are to the border ...for changing this you can create 64x48
578 Pixel BMP files - which contain your own grayscale... (you can produce funny
579 effects with this...) the images MUST not compressed, should have 24-bit per
580 pixel, or a simple 256 color grayscale palette
581 */
582 set_section( N_("Change gradients" ), 0 )
583 add_loadfile(CFG_PREFIX "gradient_zone_0", NULL,
584              ZONE_0_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
585 add_loadfile(CFG_PREFIX "gradient_zone_1", NULL,
586              ZONE_1_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
587 add_loadfile(CFG_PREFIX "gradient_zone_2", NULL,
588              ZONE_2_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
589 add_loadfile(CFG_PREFIX "gradient_zone_3", NULL,
590              ZONE_3_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
591 add_loadfile(CFG_PREFIX "gradient_zone_4", NULL,
592              ZONE_4_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
593 add_directory(CFG_PREFIX "gradient_path", NULL,
594            GRADIENT_PATH_TEXT, GRADIENT_PATH_LONGTEXT, false )
595
596 #if defined(__ATMO_DEBUG__)
597 add_bool(CFG_PREFIX "saveframes", false,
598          SAVEFRAMES_TEXT, SAVEFRAMES_LONGTEXT, false)
599 add_string(CFG_PREFIX "framepath", "",
600            FRAMEPATH_TEXT, FRAMEPATH_LONGTEXT, false )
601 #endif
602 /*
603    may be later if computers gets more power ;-) than now we increase
604    the samplesize from which we do the stats for output color calculation
605 */
606 add_integer_with_range(CFG_PREFIX "width",  64, 64, 512,
607                        WIDTH_TEXT,  WIDTH_LONGTEXT, true)
608 add_integer_with_range(CFG_PREFIX "height", 48, 48, 384,
609                        HEIGHT_TEXT,  HEIGHT_LONGTEXT, true)
610 add_bool(CFG_PREFIX "showdots", false,
611                    SHOW_DOTS_TEXT, SHOW_DOTS_LONGTEXT, false)
612 add_shortcut( "atmo" )
613 set_callbacks( CreateFilter, DestroyFilter  )
614 vlc_module_end ()
615
616
617 static const char *const ppsz_filter_options[] = {
618         "device",
619
620         "serialdev",
621
622
623         "edgeweightning",
624         "brightness",
625         "darknesslimit",
626         "huewinsize",
627         "satwinsize",
628
629         "filtermode",
630
631         "meanlength",
632         "meanthreshold",
633         "percentnew",
634         "framedelay",
635
636         "zones-top",
637         "zones-bottom",
638         "zones-lr",
639         "zone-summary",
640
641         "channel_0",
642         "channel_1",
643         "channel_2",
644         "channel_3",
645         "channel_4",
646         "channels",
647
648         "whiteadj",
649         "white-red",
650         "white-green",
651         "white-blue",
652
653         "usepausecolor",
654         "pcolor-red",
655         "pcolor-green",
656         "pcolor-blue",
657         "fadesteps",
658
659         "ecolor-red",
660         "ecolor-green",
661         "ecolor-blue",
662         "efadesteps",
663
664         "dmx-channels",
665         "dmx-chbase",
666         "momo-channels",
667         "fnordlicht-amount",
668
669 #if defined(_WIN32 )
670         "atmowinexe",
671 #endif
672 #if defined(__ATMO_DEBUG__)
673         "saveframes" ,
674         "framepath",
675 #endif
676         "width",
677         "height",
678         "showdots",
679         "gradient_zone_0",
680         "gradient_zone_1",
681         "gradient_zone_2",
682         "gradient_zone_3",
683         "gradient_zone_4",
684         "gradient_path",
685         NULL
686 };
687
688
689 /*****************************************************************************
690 * fadethread_t: Color Fading Thread
691 *****************************************************************************
692 * changes slowly the color of the output if videostream gets paused...
693 *****************************************************************************
694 */
695 typedef struct
696 {
697     filter_t *p_filter;
698     vlc_thread_t thread;
699     atomic_bool abort;
700
701     /* tell the thread which color should be the target of fading */
702     uint8_t ui_red;
703     uint8_t ui_green;
704     uint8_t ui_blue;
705     /* how many steps should happen until this */
706     int i_steps;
707
708 } fadethread_t;
709
710 static void *FadeToColorThread(void *);
711
712
713 /*****************************************************************************
714 * filter_sys_t: AtmoLight filter method descriptor
715 *****************************************************************************
716 * It describes the AtmoLight specific properties of an video filter.
717 *****************************************************************************/
718 struct filter_sys_t
719 {
720     /*
721     special for the access of the p_fadethread member all other members
722     need no special protection so far!
723     */
724     vlc_mutex_t filter_lock;
725
726     bool b_enabled;
727     int32_t i_AtmoOldEffect;
728     bool b_pause_live;
729     bool b_show_dots;
730     int32_t i_device_type;
731
732     bool b_swap_uv;
733
734     int32_t i_atmo_width;
735     int32_t i_atmo_height;
736     /* used to disable fadeout if less than 50 frames are processed
737        used to avoid long time waiting when switch quickly between
738        deinterlaceing modes, where the output filter chains is rebuild
739        on each switch
740     */
741     int32_t i_frames_processed;
742
743 #if defined(__ATMO_DEBUG__)
744     bool  b_saveframes;
745     uint32_t ui_frame_counter;
746     char sz_framepath[MAX_PATH];
747 #endif
748
749     /* light color on movie finish ... */
750     uint8_t ui_endcolor_red;
751     uint8_t ui_endcolor_green;
752     uint8_t ui_endcolor_blue;
753     int i_endfadesteps;
754
755     fadethread_t *p_fadethread;
756
757     /* Variables for buildin driver only... */
758
759     /* is only present and initialized if the internal driver is used*/
760     CAtmoConfig *p_atmo_config;
761     /* storage for temporal settings "volatile" */
762     CAtmoDynData *p_atmo_dyndata;
763     /* initialized for buildin driver with AtmoCreateTransferBuffers */
764     VLC_BITMAPINFOHEADER mini_image_format;
765     /* is only use buildin driver! */
766     uint8_t *p_atmo_transfer_buffer;
767     /* end buildin driver */
768
769     /*
770     contains the real output size of the video calculated on
771     change event of the variable "crop" from vout
772     */
773     int32_t i_crop_x_offset;
774     int32_t i_crop_y_offset;
775     int32_t i_crop_width;
776     int32_t i_crop_height;
777
778     void (*pf_extract_mini_image) (filter_sys_t *p_sys,
779         picture_t *p_inpic,
780         uint8_t *p_transfer_dest);
781
782 #if defined( _WIN32 )
783     /* External Library as wrapper arround COM Stuff */
784     HINSTANCE h_AtmoCtrl;
785     int32_t (*pf_ctrl_atmo_initialize) (void);
786     void (*pf_ctrl_atmo_finalize) (int32_t what);
787     int32_t (*pf_ctrl_atmo_switch_effect) (int32_t);
788     int32_t (*pf_ctrl_atmo_set_live_source) (int32_t);
789     void (*pf_ctrl_atmo_create_transfer_buffers) (int32_t, int32_t,
790                                                   int32_t , int32_t);
791     uint8_t* (*pf_ctrl_atmo_lock_transfer_buffer) (void);
792     void (*pf_ctrl_atmo_send_pixel_data) (void);
793     void (*pf_ctrl_atmo_get_image_size)(int32_t *,int32_t *);
794 #endif
795 };
796
797 /*
798 initialize previously configured Atmo Light environment
799 - if internal is enabled try to access the device on the serial port
800 - if not internal is enabled and we are on win32 try to initialize
801 the previously loaded DLL ...
802
803 Return Values may be: -1 (failed for some reason - filter will be disabled)
804 1 Ok. lets rock
805 */
806 static int32_t AtmoInitialize(filter_t *p_filter, bool b_for_thread)
807 {
808     filter_sys_t *p_sys = p_filter->p_sys;
809     if(p_sys->p_atmo_config)
810     {
811         if(!b_for_thread)
812         {
813             /* open com port */
814             /* setup Output Threads ... */
815             msg_Dbg( p_filter, "open atmo device...");
816             if(CAtmoTools::RecreateConnection(p_sys->p_atmo_dyndata)
817                == ATMO_TRUE)
818             {
819                 return 1;
820             } else {
821                 msg_Err( p_filter,"failed to open atmo device, "\
822                                   "some other software/driver may use it?");
823             }
824         }
825 #if defined(_WIN32)
826     } else if(p_sys->pf_ctrl_atmo_initialize)
827     {
828         /* on win32 with active ctrl dll */
829         return p_sys->pf_ctrl_atmo_initialize();
830 #endif
831     }
832     return -1;
833 }
834
835 /*
836 prepare the shutdown of the effect threads,
837 for build in filter - close the serialport after finishing the threads...
838 cleanup possible loaded DLL...
839 */
840 static void AtmoFinalize(filter_t *p_filter, int32_t what)
841 {
842     filter_sys_t *p_sys = p_filter->p_sys;
843     if(p_sys->p_atmo_config)
844     {
845         if(what == 1)
846         {
847             CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
848             if(p_atmo_dyndata)
849             {
850                 p_atmo_dyndata->LockCriticalSection();
851
852                 CAtmoInput *p_input = p_atmo_dyndata->getLiveInput();
853                 p_atmo_dyndata->setLiveInput( NULL );
854                 if(p_input != NULL)
855                 {
856                     p_input->Terminate();
857                     delete p_input;
858                     msg_Dbg( p_filter, "input thread died peacefully");
859                 }
860
861                 CThread *p_effect_thread = p_atmo_dyndata->getEffectThread();
862                 p_atmo_dyndata->setEffectThread(NULL);
863                 if(p_effect_thread != NULL)
864                 {
865                     /*
866                     forced the thread to die...
867                     and wait for termination of the thread
868                     */
869                     p_effect_thread->Terminate();
870                     delete p_effect_thread;
871                     msg_Dbg( p_filter, "effect thread died peacefully");
872                 }
873
874                 CAtmoPacketQueue *p_queue =
875                                            p_atmo_dyndata->getLivePacketQueue();
876                 p_atmo_dyndata->setLivePacketQueue( NULL );
877                 if(p_queue != NULL)
878                 {
879                    delete p_queue;
880                    msg_Dbg( p_filter, "packetqueue removed");
881                 }
882
883                 /*
884                 close serial port if it is open (all OS specific is inside
885                 CAtmoSerialConnection implemented / defined)
886                 */
887                 CAtmoConnection *p_atmo_connection =
888                                  p_atmo_dyndata->getAtmoConnection();
889                 p_atmo_dyndata->setAtmoConnection(NULL);
890                 if(p_atmo_connection) {
891                     p_atmo_connection->CloseConnection();
892                     delete p_atmo_connection;
893                 }
894                 p_atmo_dyndata->UnLockCriticalSection();
895             }
896         }
897 #if defined(_WIN32)
898     } else if(p_sys->pf_ctrl_atmo_finalize)
899     {
900         /* on win32 with active ctrl dll */
901         p_sys->pf_ctrl_atmo_finalize(what);
902 #endif
903     }
904 }
905
906 /*
907   switch the current light effect to LiveView
908 */
909 static int32_t AtmoSwitchEffect(filter_t *p_filter, int32_t newMode)
910 {
911     filter_sys_t *p_sys = p_filter->p_sys;
912
913     msg_Dbg( p_filter, "AtmoSwitchEffect %d", newMode );
914
915     if(p_sys->p_atmo_config)
916     {
917        return CAtmoTools::SwitchEffect(p_sys->p_atmo_dyndata, emLivePicture);
918 #if defined(_WIN32)
919     } else if(p_sys->pf_ctrl_atmo_switch_effect)
920     {
921         /* on win32 with active ctrl dll */
922         return p_sys->pf_ctrl_atmo_switch_effect( newMode );
923 #endif
924     }
925     return emDisabled;
926 }
927
928 /*
929 set the current live picture source, does only something on win32,
930 with the external libraries - if the buildin effects are used nothing
931 happens...
932 */
933 static int32_t AtmoSetLiveSource(filter_t *p_filter, int32_t newSource)
934 {
935     filter_sys_t *p_sys = p_filter->p_sys;
936
937     msg_Dbg( p_filter, "AtmoSetLiveSource %d", newSource );
938
939     if(p_sys->p_atmo_config)
940     {
941         /*
942         buildin driver
943
944         doesnt know different sources so this
945         function call would just do nothing special
946         in this case
947         */
948 #if defined(_WIN32)
949     } else if(p_sys->pf_ctrl_atmo_set_live_source)
950     {
951         /* on win32 with active ctrl dll */
952         return p_sys->pf_ctrl_atmo_set_live_source(newSource);
953 #endif
954     }
955     return lvsGDI;
956 }
957
958 /*
959 setup the pixel transferbuffers which is used to transfer pixeldata from
960 the filter to the effect thread, and possible accross the process
961 boundaries on win32, with the external DLL
962 */
963 static void AtmoCreateTransferBuffers(filter_t *p_filter,
964                                       int32_t FourCC,
965                                       int32_t bytePerPixel,
966                                       int32_t width,
967                                       int32_t height)
968 {
969     filter_sys_t *p_sys = p_filter->p_sys;
970     if(p_sys->p_atmo_config)
971     {
972         /*
973         we need a buffer where the image is stored (only for transfer
974         to the processing thread)
975         */
976         free( p_sys->p_atmo_transfer_buffer );
977
978         p_sys->p_atmo_transfer_buffer = (uint8_t *)malloc(bytePerPixel *
979                                                           width *  height);
980
981         memset(&p_sys->mini_image_format,0,sizeof(VLC_BITMAPINFOHEADER));
982
983         p_sys->mini_image_format.biSize = sizeof(VLC_BITMAPINFOHEADER);
984         p_sys->mini_image_format.biWidth = width;
985         p_sys->mini_image_format.biHeight = height;
986         p_sys->mini_image_format.biBitCount = bytePerPixel*8;
987         p_sys->mini_image_format.biCompression = FourCC;
988
989 #if defined(_WIN32)
990     } else if(p_sys->pf_ctrl_atmo_create_transfer_buffers)
991     {
992         /* on win32 with active ctrl dll */
993         p_sys->pf_ctrl_atmo_create_transfer_buffers(FourCC,
994             bytePerPixel,
995             width,
996             height);
997 #endif
998     }
999 }
1000
1001 /*
1002 acquire the transfer buffer pointer the buildin version only
1003 returns the pointer to the allocated buffer ... the
1004 external version on win32 has to do some COM stuff to lock the
1005 Variant Byte array which is behind the buffer
1006 */
1007 static uint8_t* AtmoLockTransferBuffer(filter_t *p_filter)
1008 {
1009     filter_sys_t *p_sys = p_filter->p_sys;
1010     if(p_sys->p_atmo_config)
1011     {
1012         return p_sys->p_atmo_transfer_buffer;
1013 #if defined(_WIN32)
1014     } else if(p_sys->pf_ctrl_atmo_lock_transfer_buffer)
1015     {
1016         /* on win32 with active ctrl dll */
1017         return p_sys->pf_ctrl_atmo_lock_transfer_buffer();
1018 #endif
1019     }
1020     return NULL;
1021 }
1022
1023 /*
1024 send the content of current pixel buffer got with AtmoLockTransferBuffer
1025 to the processing threads
1026 - build in version - will forward the data to AtmoExternalCaptureInput Thread
1027 - win32 external - will do the same, but across the process boundaries via
1028 COM to the AtmoWinA.exe Process
1029 */
1030 static void AtmoSendPixelData(filter_t *p_filter)
1031 {
1032     filter_sys_t *p_sys = p_filter->p_sys;
1033     if(p_sys->p_atmo_config && p_sys->p_atmo_transfer_buffer)
1034     {
1035         CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
1036         if(p_atmo_dyndata &&
1037           (p_atmo_dyndata->getLivePictureSource() == lpsExtern))
1038         {
1039             /*
1040             the cast will go Ok because we are inside videolan there is only
1041             this kind of effect thread implemented!
1042             */
1043             CAtmoExternalCaptureInput *p_atmo_external_capture_input_thread =
1044                 (CAtmoExternalCaptureInput *)p_atmo_dyndata->getLiveInput();
1045
1046             if(p_atmo_external_capture_input_thread)
1047             {
1048                 /*
1049                 the same as above inside videolan only this single kind of
1050                 input exists so we can cast without further tests!
1051
1052                 this call will do a 1:1 copy of this buffer, and wakeup
1053                 the thread from normal sleeping
1054                 */
1055                 p_atmo_external_capture_input_thread->
1056                      DeliverNewSourceDataPaket(&p_sys->mini_image_format,
1057                                                p_sys->p_atmo_transfer_buffer);
1058             }
1059         }
1060 #if defined(_WIN32)
1061     } else if(p_sys->pf_ctrl_atmo_send_pixel_data)
1062     {
1063         /* on win32 with active ctrl dll */
1064         p_sys->pf_ctrl_atmo_send_pixel_data();
1065 #endif
1066     } else
1067     {
1068        msg_Warn( p_filter, "AtmoSendPixelData no method");
1069     }
1070 }
1071
1072 /*
1073     Shutdown AtmoLight finally - is call from DestroyFilter
1074     does the cleanup restores the effectmode on the external Software
1075     (only win32) and possible setup the final light ...
1076 */
1077 static void Atmo_Shutdown(filter_t *p_filter)
1078 {
1079     filter_sys_t *p_sys = p_filter->p_sys;
1080
1081     if(p_sys->b_enabled)
1082     {
1083         msg_Dbg( p_filter, "shut down atmo!");
1084         /*
1085         if there is a still running show pause color thread kill him!
1086         */
1087         CheckAndStopFadeThread(p_filter);
1088
1089         // perpare spawn fadeing thread
1090         vlc_mutex_lock( &p_sys->filter_lock );
1091
1092         /*
1093         fade to end color (in case of external AtmoWin Software
1094         assume that the static color will equal to this
1095         one to get a soft change and no flash!
1096         */
1097         p_sys->b_pause_live = true;
1098
1099
1100         p_sys->p_fadethread = (fadethread_t *)calloc( 1, sizeof(fadethread_t) );
1101         p_sys->p_fadethread->p_filter = p_filter;
1102         p_sys->p_fadethread->ui_red   = p_sys->ui_endcolor_red;
1103         p_sys->p_fadethread->ui_green = p_sys->ui_endcolor_green;
1104         p_sys->p_fadethread->ui_blue  = p_sys->ui_endcolor_blue;
1105         if(p_sys->i_frames_processed < 50)
1106           p_sys->p_fadethread->i_steps  = 1;
1107         else
1108           p_sys->p_fadethread->i_steps  = p_sys->i_endfadesteps;
1109         atomic_store(&p_sys->p_fadethread->abort, false);
1110
1111         if( vlc_clone( &p_sys->p_fadethread->thread,
1112                        FadeToColorThread,
1113                        p_sys->p_fadethread,
1114                        VLC_THREAD_PRIORITY_LOW ) )
1115         {
1116             msg_Err( p_filter, "cannot create FadeToColorThread" );
1117             free( p_sys->p_fadethread );
1118             p_sys->p_fadethread = NULL;
1119             vlc_mutex_unlock( &p_sys->filter_lock );
1120
1121         } else {
1122
1123             vlc_mutex_unlock( &p_sys->filter_lock );
1124
1125             /* wait for the thread... */
1126             vlc_join(p_sys->p_fadethread->thread, NULL);
1127
1128             free(p_sys->p_fadethread);
1129
1130             p_sys->p_fadethread = NULL;
1131         }
1132
1133         /*
1134            the following happens only useing the
1135            external AtmoWin Device Software
1136         */
1137         if( !p_sys->p_atmo_config )
1138         {
1139            if(p_sys->i_AtmoOldEffect != emLivePicture)
1140               AtmoSwitchEffect( p_filter, p_sys->i_AtmoOldEffect);
1141            else
1142               AtmoSetLiveSource( p_filter, lvsGDI );
1143         }
1144
1145         /* close device connection etc. */
1146         AtmoFinalize(p_filter, 1);
1147
1148         /* disable filter method .. */
1149         p_sys->b_enabled = false;
1150     }
1151 }
1152
1153 /*
1154 depending on mode setup imagesize to 64x48(classic), or defined
1155 resolution of external atmowin.exe on windows
1156 */
1157 static void Atmo_SetupImageSize(filter_t *p_filter)
1158 {
1159     filter_sys_t *p_sys = p_filter->p_sys;
1160     /*
1161        size of extracted image by default 64x48 (other imagesizes are
1162        currently ignored by AtmoWin)
1163     */
1164     p_sys->i_atmo_width  = var_CreateGetIntegerCommand( p_filter,
1165         CFG_PREFIX "width");
1166     p_sys->i_atmo_height = var_CreateGetIntegerCommand( p_filter,
1167         CFG_PREFIX "height");
1168
1169     if(p_sys->p_atmo_config)
1170     {
1171 #if defined(_WIN32)
1172     } else if(p_sys->pf_ctrl_atmo_get_image_size)
1173     {
1174         /* on win32 with active ctrl dll */
1175         p_sys->pf_ctrl_atmo_get_image_size( &p_sys->i_atmo_width,
1176                                             &p_sys->i_atmo_height );
1177 #endif
1178     }
1179
1180     msg_Dbg(p_filter,"sample image size %d * %d pixels", p_sys->i_atmo_width,
1181         p_sys->i_atmo_height);
1182 }
1183
1184 /*
1185 initialize the zone and channel mapping for the buildin atmolight adapter
1186 */
1187 static void Atmo_SetupBuildZones(filter_t *p_filter)
1188 {
1189     filter_sys_t *p_sys = p_filter->p_sys;
1190
1191     p_sys->p_atmo_dyndata->LockCriticalSection();
1192
1193     CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
1194
1195
1196     CAtmoChannelAssignment *p_channel_assignment =
1197                             p_atmo_config->getChannelAssignment(0);
1198
1199     // channel 0 - zone 4
1200     p_channel_assignment->setZoneIndex( 0, var_CreateGetIntegerCommand(
1201                                         p_filter, CFG_PREFIX "channel_0")
1202                                         );
1203
1204     // channel 1 - zone 3
1205     p_channel_assignment->setZoneIndex( 1, var_CreateGetIntegerCommand(
1206                                         p_filter, CFG_PREFIX "channel_1")
1207                                         );
1208
1209     // channel 2 - zone 1
1210     p_channel_assignment->setZoneIndex( 2, var_CreateGetIntegerCommand(
1211                                         p_filter, CFG_PREFIX "channel_2")
1212                                         );
1213
1214     // channel 3 - zone 0
1215     p_channel_assignment->setZoneIndex( 3, var_CreateGetIntegerCommand(
1216                                         p_filter, CFG_PREFIX "channel_3")
1217                                         );
1218
1219     // channel 4 - zone 2
1220     p_channel_assignment->setZoneIndex( 4, var_CreateGetIntegerCommand(
1221                                         p_filter, CFG_PREFIX "channel_4")
1222                                         );
1223
1224     char *psz_channels = var_CreateGetStringCommand(
1225               p_filter,
1226               CFG_PREFIX "channels"
1227             );
1228     if( !EMPTY_STR(psz_channels) )
1229     {
1230         msg_Dbg( p_filter, "deal with new zone mapping %s", psz_channels );
1231         int channel = 0;
1232         char *psz_temp = psz_channels;
1233         char *psz_start = psz_temp;
1234         while( *psz_temp )
1235         {
1236             if(*psz_temp == ',' || *psz_temp == ';')
1237             {
1238                 *psz_temp = 0;
1239                 if(*psz_start)
1240                 {
1241                     int zone = atoi( psz_start );
1242                     if( zone < -1 ||
1243                         zone >= p_channel_assignment->getSize()) {
1244                          msg_Warn( p_filter, "Zone %d out of range -1..%d",
1245                                 zone, p_channel_assignment->getSize()-1 );
1246                     } else {
1247                         p_channel_assignment->setZoneIndex( channel, zone );
1248                         channel++;
1249                     }
1250                 }
1251                 psz_start = psz_temp;
1252                 psz_start++;
1253             }
1254
1255             psz_temp++;
1256         }
1257
1258         /*
1259           process the rest of the string
1260         */
1261         if( *psz_start && !*psz_temp )
1262         {
1263             int zone = atoi( psz_start );
1264             if( zone < -1 ||
1265                 zone >= p_channel_assignment->getSize()) {
1266                 msg_Warn( p_filter, "Zone %d out of range -1..%d",
1267                             zone, p_channel_assignment->getSize()-1 );
1268             } else {
1269                 p_channel_assignment->setZoneIndex( channel, zone );
1270             }
1271         }
1272     }
1273     free( psz_channels );
1274
1275     for(int i=0;i< p_channel_assignment->getSize() ;i++)
1276         msg_Info( p_filter, "map zone %d to hardware channel %d",
1277         p_channel_assignment->getZoneIndex( i ),
1278         i
1279         );
1280     p_sys->p_atmo_dyndata->getAtmoConnection()
1281          ->SetChannelAssignment( p_channel_assignment );
1282
1283
1284
1285
1286
1287     /*
1288       calculate the default gradients for each zone!
1289       depending on the zone layout set before, this now
1290       supports also multiple gradients on each side
1291       (older versions could do this only with external
1292       gradient bitmaps)
1293     */
1294     p_sys->p_atmo_dyndata->CalculateDefaultZones();
1295
1296
1297     /*
1298       first try to load the old style defined gradient bitmaps
1299       this could only be done for the first five zones
1300       - should be deprecated -
1301     */
1302     CAtmoZoneDefinition *p_zone;
1303     char psz_gradient_var_name[30];
1304     char *psz_gradient_file;
1305     for(int i=0;i<CLASSIC_ATMO_NUM_ZONES;i++)
1306     {
1307         sprintf(psz_gradient_var_name, CFG_PREFIX "gradient_zone_%d", i);
1308         psz_gradient_file = var_CreateGetStringCommand(
1309             p_filter,
1310             psz_gradient_var_name
1311             );
1312         if( !EMPTY_STR(psz_gradient_file) )
1313         {
1314             msg_Dbg( p_filter, "loading gradientfile %s for "\
1315                                 "zone %d", psz_gradient_file, i);
1316
1317             p_zone = p_atmo_config->getZoneDefinition(i);
1318             if( p_zone )
1319             {
1320                 int i_res = p_zone->LoadGradientFromBitmap(psz_gradient_file);
1321
1322                 if(i_res != ATMO_LOAD_GRADIENT_OK)
1323                 {
1324                     msg_Err( p_filter,"failed to load gradient '%s' with "\
1325                                     "error %d",psz_gradient_file,i_res);
1326                 }
1327             }
1328         }
1329         free( psz_gradient_file );
1330     }
1331
1332
1333     /*
1334       the new approach try to load a gradient bitmap for each zone
1335       from a previously defined folder containing
1336       zone_0.bmp
1337       zone_1.bmp
1338       zone_2.bmp etc.
1339     */
1340     char *psz_gradient_path = var_CreateGetStringCommand(
1341               p_filter,
1342               CFG_PREFIX "gradient_path"
1343             );
1344     if( EMPTY_STR(psz_gradient_path) )
1345     {
1346         char *psz_file_name = (char *)malloc( strlen(psz_gradient_path) + 16 );
1347         assert( psz_file_name );
1348
1349         for(int i=0; i < p_atmo_config->getZoneCount(); i++ )
1350         {
1351             p_zone = p_atmo_config->getZoneDefinition(i);
1352
1353             if( p_zone )
1354             {
1355                 sprintf(psz_file_name, "%s%szone_%d.bmp",
1356                                             psz_gradient_path, DIR_SEP, i );
1357
1358                 int i_res = p_zone->LoadGradientFromBitmap( psz_file_name );
1359
1360                 if( i_res == ATMO_LOAD_GRADIENT_OK )
1361                 {
1362                 msg_Dbg( p_filter, "loaded gradientfile %s for "\
1363                                    "zone %d", psz_file_name, i);
1364                 }
1365
1366                 if( (i_res != ATMO_LOAD_GRADIENT_OK) &&
1367                     (i_res != ATMO_LOAD_GRADIENT_FILENOTFOND) )
1368                 {
1369                     msg_Err( p_filter,"failed to load gradient '%s' with "\
1370                                     "error %d",psz_file_name,i_res);
1371                 }
1372             }
1373         }
1374
1375         free( psz_file_name );
1376     }
1377     free( psz_gradient_path );
1378
1379
1380     p_sys->p_atmo_dyndata->UnLockCriticalSection();
1381
1382 }
1383
1384 static void Atmo_SetupConfig(filter_t *p_filter, CAtmoConfig *p_atmo_config)
1385 {
1386     /*
1387        figuring out the device ports (com-ports, ttys)
1388     */
1389     char *psz_serialdev = var_CreateGetStringCommand( p_filter,
1390                                                       CFG_PREFIX "serialdev" );
1391     char *psz_temp = psz_serialdev;
1392
1393     if( !EMPTY_STR(psz_serialdev) )
1394     {
1395         char *psz_token;
1396         int i_port = 0;
1397         int i;
1398         int j;
1399
1400         msg_Dbg( p_filter, "use port(s) %s",psz_serialdev);
1401
1402         /*
1403           psz_serialdev - may contain up to 4 COM ports for the quattro device
1404           the quattro device is just hack of useing 4 classic devices as one
1405           logical device - thanks that usb-com-ports exists :)
1406           as Seperator I defined , or ; with the hope that these
1407           characters are never part of a device name
1408         */
1409         while( (psz_token = strsep(&psz_temp, ",;")) != NULL && i_port < 4 )
1410         {
1411             /*
1412               psz_token may contain spaces we have to trim away
1413             */
1414             i = 0;
1415             j = 0;
1416             /*
1417               find first none space in string
1418             */
1419             while( psz_token[i] == 32 ) i++;
1420             /*
1421               contains string only spaces or is empty? skip it
1422             */
1423             if( !psz_token[i] )
1424                 continue;
1425
1426             /*
1427               trim
1428             */
1429             while( psz_token[i] && psz_token[i] != 32 )
1430                 psz_token[ j++ ] = psz_token[ i++ ];
1431             psz_token[j++] = 0;
1432
1433             msg_Dbg( p_filter, "Serial Device [%d]: %s", i_port, psz_token );
1434
1435             p_atmo_config->setSerialDevice( i_port, psz_token );
1436
1437             i_port++;
1438         }
1439     }
1440     else
1441     {
1442        msg_Err(p_filter,"no serial devicename(s) set");
1443     }
1444     free( psz_serialdev );
1445
1446     /*
1447       configuration of light source layout arround the display
1448     */
1449     p_atmo_config->setZonesTopCount(
1450         var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-top")
1451         );
1452     p_atmo_config->setZonesBottomCount(
1453         var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-bottom")
1454         );
1455     p_atmo_config->setZonesLRCount(
1456         var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-lr")
1457         );
1458     p_atmo_config->setZoneSummary(
1459         var_CreateGetBoolCommand( p_filter, CFG_PREFIX "zone-summary")
1460         );
1461
1462
1463     p_atmo_config->setLiveViewFilterMode(
1464         (AtmoFilterMode)var_CreateGetIntegerCommand( p_filter,
1465                                                 CFG_PREFIX "filtermode")
1466         );
1467
1468     p_atmo_config->setLiveViewFilter_PercentNew(
1469         var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "percentnew")
1470         );
1471     p_atmo_config->setLiveViewFilter_MeanLength(
1472         var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "meanlength")
1473         );
1474     p_atmo_config->setLiveViewFilter_MeanThreshold(
1475         var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "meanthreshold")
1476         );
1477
1478     p_atmo_config->setLiveView_EdgeWeighting(
1479         var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "edgeweightning")
1480         );
1481     p_atmo_config->setLiveView_BrightCorrect(
1482         var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "brightness")
1483         );
1484     p_atmo_config->setLiveView_DarknessLimit(
1485         var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "darknesslimit")
1486         );
1487     p_atmo_config->setLiveView_HueWinSize(
1488         var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "huewinsize")
1489         );
1490     p_atmo_config->setLiveView_SatWinSize(
1491         var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "satwinsize")
1492         );
1493
1494     /* currently not required inside vlc */
1495     p_atmo_config->setLiveView_WidescreenMode( 0 );
1496
1497     p_atmo_config->setLiveView_FrameDelay(
1498         var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "framedelay")
1499         );
1500
1501
1502     p_atmo_config->setUseSoftwareWhiteAdj(
1503         var_CreateGetBoolCommand( p_filter, CFG_PREFIX "whiteadj")
1504         );
1505     p_atmo_config->setWhiteAdjustment_Red(
1506         var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-red")
1507         );
1508     p_atmo_config->setWhiteAdjustment_Green(
1509         var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-green")
1510         );
1511     p_atmo_config->setWhiteAdjustment_Blue(
1512         var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-blue")
1513         );
1514
1515     /*
1516       settings for DMX device only
1517     */
1518     p_atmo_config->setDMX_RGB_Channels(
1519         var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "dmx-channels")
1520         );
1521
1522     char *psz_chbase = var_CreateGetStringCommand( p_filter,
1523                                                    CFG_PREFIX "dmx-chbase" );
1524     if( !EMPTY_STR(psz_chbase) )
1525         p_atmo_config->setDMX_BaseChannels( psz_chbase );
1526
1527     free( psz_chbase );
1528
1529     /*
1530       momolight options
1531     */
1532     p_atmo_config->setMoMo_Channels(
1533         var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "momo-channels")
1534        );
1535
1536     /*
1537       fnordlicht options
1538     */
1539     p_atmo_config->setFnordlicht_Amount(
1540         var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "fnordlicht-amount")
1541        );
1542
1543 }
1544
1545
1546 /*
1547 initialize the filter_sys_t structure with the data from the settings
1548 variables - if the external filter on win32 is enabled try loading the DLL,
1549 if this fails fallback to the buildin software
1550 */
1551 static void Atmo_SetupParameters(filter_t *p_filter)
1552 {
1553     filter_sys_t *p_sys =  p_filter->p_sys;
1554
1555
1556     /* default filter disabled until DLL loaded and Init Success!*/
1557     p_sys->b_enabled             = false;
1558
1559     /* setup default mini image size (may be later a user option) */
1560     p_sys->i_atmo_width          = 64;
1561     p_sys->i_atmo_height         = 48;
1562
1563     p_sys->i_device_type = var_CreateGetIntegerCommand( p_filter,
1564                                                         CFG_PREFIX "device");
1565
1566     /*
1567       i_device_type
1568        0 => use AtmoWin Software (only win32)
1569        1 => use AtmoClassicConnection (direct)
1570        2 => use AtmoMultiConnection (direct up to four serial ports required)
1571        3 => use AtmoDmxConnection (simple serial DMX Device up to 255 channels)
1572     */
1573
1574
1575 #if defined(_WIN32)
1576     /*
1577     only on _WIN32 the user has the choice between
1578     internal driver and external
1579     */
1580
1581     if(p_sys->i_device_type == 0) {
1582
1583         /* Load the Com Wrapper Library (source available) */
1584         p_sys->h_AtmoCtrl = LoadLibraryA("AtmoCtrlLib.dll");
1585         if(p_sys->h_AtmoCtrl == NULL)
1586         {
1587             /*
1588               be clever if the location of atmowin.exe is set
1589               try to load the dll from the same folder :-)
1590             */
1591             char *psz_path = var_CreateGetStringCommand( p_filter,
1592                                                CFG_PREFIX "atmowinexe" );
1593             if( !EMPTY_STR(psz_path) )
1594             {
1595                 char *psz_bs = strrchr( psz_path , '\\');
1596                 if( psz_bs )
1597                 {
1598                     *psz_bs = 0;
1599                     /*
1600                       now format a new dll filename with complete path
1601                     */
1602                     char *psz_dllname = NULL;
1603                     asprintf( &psz_dllname, "%s\\AtmoCtrlLib.dll", psz_path );
1604                     if( psz_dllname )
1605                     {
1606                         msg_Dbg( p_filter, "Try Loading '%s'", psz_dllname );
1607                         TCHAR* ptsz_dllname = ToT(psz_dllname);
1608                         p_sys->h_AtmoCtrl = LoadLibrary( ptsz_dllname );
1609                         free(ptsz_dllname);
1610                     }
1611                     free( psz_dllname );
1612                 }
1613             }
1614             free( psz_path );
1615         }
1616
1617
1618         if(p_sys->h_AtmoCtrl != NULL)
1619         {
1620             msg_Dbg( p_filter, "Load Library ok!");
1621
1622             /* importing all required functions I hope*/
1623             p_sys->pf_ctrl_atmo_initialize =
1624                 (int32_t (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,
1625                             "AtmoInitialize");
1626             if(!p_sys->pf_ctrl_atmo_initialize)
1627                 msg_Err( p_filter, "export AtmoInitialize missing.");
1628
1629             p_sys->pf_ctrl_atmo_finalize =
1630                 (void (*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,
1631                             "AtmoFinalize");
1632             if(!p_sys->pf_ctrl_atmo_finalize)
1633                 msg_Err( p_filter, "export AtmoFinalize missing.");
1634
1635             p_sys->pf_ctrl_atmo_switch_effect =
1636                 (int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,
1637                             "AtmoSwitchEffect");
1638             if(!p_sys->pf_ctrl_atmo_switch_effect)
1639                 msg_Err( p_filter, "export AtmoSwitchEffect missing.");
1640
1641             p_sys->pf_ctrl_atmo_set_live_source =
1642                 (int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,
1643                             "AtmoSetLiveSource");
1644             if(!p_sys->pf_ctrl_atmo_set_live_source)
1645                 msg_Err( p_filter, "export AtmoSetLiveSource missing.");
1646
1647             p_sys->pf_ctrl_atmo_create_transfer_buffers =
1648                 (void (*)(int32_t, int32_t, int32_t , int32_t))
1649                     GetProcAddress(p_sys->h_AtmoCtrl,"AtmoCreateTransferBuffers");
1650             if(!p_sys->pf_ctrl_atmo_create_transfer_buffers)
1651                 msg_Err( p_filter, "export AtmoCreateTransferBuffers missing.");
1652
1653             p_sys->pf_ctrl_atmo_lock_transfer_buffer=
1654                 (uint8_t*(*) (void))GetProcAddress(p_sys->h_AtmoCtrl,
1655                             "AtmoLockTransferBuffer");
1656             if(!p_sys->pf_ctrl_atmo_lock_transfer_buffer)
1657                 msg_Err( p_filter, "export AtmoLockTransferBuffer missing.");
1658
1659             p_sys->pf_ctrl_atmo_send_pixel_data =
1660                 (void (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,
1661                             "AtmoSendPixelData");
1662             if(!p_sys->pf_ctrl_atmo_send_pixel_data)
1663                 msg_Err( p_filter, "export AtmoSendPixelData missing.");
1664
1665             p_sys->pf_ctrl_atmo_get_image_size =
1666                 (void (*)(int32_t*,int32_t*))GetProcAddress(p_sys->h_AtmoCtrl,
1667                             "AtmoWinGetImageSize");
1668             if(!p_sys->pf_ctrl_atmo_get_image_size)
1669                 msg_Err( p_filter, "export AtmoWinGetImageSize missing.");
1670
1671         } else {
1672             /* the DLL is missing try internal filter ...*/
1673             msg_Warn( p_filter,
1674                 "AtmoCtrlLib.dll missing fallback to internal atmo classic driver");
1675             p_sys->i_device_type = 1;
1676         }
1677     }
1678 #endif
1679
1680     if(p_sys->i_device_type >= 1) {
1681         msg_Dbg( p_filter, "try use buildin driver %d ", p_sys->i_device_type);
1682         /*
1683         now we have to read a lof of options from the config dialog
1684         most important the serial device if not set ... we can skip
1685         the rest and disable the filter...
1686         */
1687
1688         p_sys->p_atmo_config = new CAtmoConfig();
1689
1690         p_sys->p_atmo_dyndata = new CAtmoDynData(
1691                    (vlc_object_t *)p_filter,
1692                    p_sys->p_atmo_config
1693         );
1694
1695         Atmo_SetupConfig( p_filter, p_sys->p_atmo_config );
1696         switch(p_sys->i_device_type)
1697         {
1698             case 1:
1699                 p_sys->p_atmo_config->setConnectionType( actClassicAtmo );
1700                 break;
1701
1702             case 2:
1703                 p_sys->p_atmo_config->setConnectionType( actMultiAtmo );
1704                 break;
1705
1706             case 3:
1707                 p_sys->p_atmo_config->setConnectionType( actDMX );
1708                 break;
1709
1710             case 4:
1711                 p_sys->p_atmo_config->setConnectionType( actMoMoLight );
1712                 break;
1713
1714             case 5:
1715                 p_sys->p_atmo_config->setConnectionType( actFnordlicht );
1716                 break;
1717
1718             default:
1719                 msg_Warn( p_filter, "invalid device type %d found",
1720                                     p_sys->i_device_type );
1721         }
1722
1723         msg_Dbg( p_filter, "buildin driver config set");
1724
1725     }
1726
1727     switch( p_filter->fmt_in.video.i_chroma )
1728     {
1729     case VLC_CODEC_I420:
1730         p_sys->pf_extract_mini_image = ExtractMiniImage_YUV;
1731         p_sys->b_swap_uv = false;
1732         break;
1733     case VLC_CODEC_YV12:
1734         p_sys->pf_extract_mini_image = ExtractMiniImage_YUV;
1735         p_sys->b_swap_uv = true;
1736         break;
1737     default:
1738         msg_Warn( p_filter, "InitFilter-unsupported chroma: %4.4s",
1739                             (char *)&p_filter->fmt_in.video.i_chroma);
1740         p_sys->pf_extract_mini_image = NULL;
1741     }
1742
1743     /*
1744     for debugging purpose show the samplinggrid on each frame as
1745     white dots
1746     */
1747     p_sys->b_show_dots = var_CreateGetBoolCommand( p_filter,
1748         CFG_PREFIX "showdots"
1749         );
1750
1751 #if defined(__ATMO_DEBUG__)
1752     /* save debug images to a folder as Bitmap files ? */
1753     p_sys->b_saveframes  = var_CreateGetBoolCommand( p_filter,
1754         CFG_PREFIX "saveframes"
1755         );
1756     msg_Dbg(p_filter,"saveframes = %d", (int)p_sys->b_saveframes);
1757
1758     /*
1759     read debug image folder from config
1760     */
1761     psz_path = var_CreateGetStringCommand( p_filter, CFG_PREFIX "framepath" );
1762     if(psz_path != NULL)
1763     {
1764         strcpy(p_sys->sz_framepath, psz_path);
1765 #if defined( _WIN32 ) || defined( __OS2__ )
1766         size_t i_strlen = strlen(p_sys->sz_framepath);
1767         if((i_strlen>0) && (p_sys->sz_framepath[i_strlen-1] != '\\'))
1768         {
1769             p_sys->sz_framepath[i_strlen] = '\\';
1770             p_sys->sz_framepath[i_strlen+1] = 0;
1771         }
1772 #endif
1773         free(psz_path);
1774     }
1775     msg_Dbg(p_filter,"saveframesfolder %s",p_sys->sz_framepath);
1776 #endif
1777
1778
1779     /*
1780     this color is use on shutdown of the filter - the define the
1781     final light after playback... may be used to dim up the light -
1782     how it happens in the cinema...
1783     */
1784     p_sys->ui_endcolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1785         CFG_PREFIX "ecolor-red");
1786     p_sys->ui_endcolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1787         CFG_PREFIX "ecolor-green");
1788     p_sys->ui_endcolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1789         CFG_PREFIX "ecolor-blue");
1790     p_sys->i_endfadesteps = var_CreateGetIntegerCommand( p_filter,
1791         CFG_PREFIX "efadesteps");
1792     if(p_sys->i_endfadesteps < 1)
1793         p_sys->i_endfadesteps = 1;
1794     msg_Dbg(p_filter,"use ende color RGB: %d, %d, %d, Fadesteps: %d",
1795         p_sys->ui_endcolor_red,
1796         p_sys->ui_endcolor_green,
1797         p_sys->ui_endcolor_blue,
1798         p_sys->i_endfadesteps);
1799
1800
1801
1802     /*
1803       if the external DLL was loaded successfully call AtmoInitialize -
1804       (must be done for each thread where you want to use AtmoLight!)
1805     */
1806     int i = AtmoInitialize(p_filter, false);
1807
1808 #if defined( _WIN32 )
1809     if((i != 1) && (p_sys->i_device_type == 0))
1810     {
1811         /*
1812           COM Server for AtmoLight not running ?
1813           if the exe path is configured try to start the "userspace" driver
1814         */
1815         char *psz_path = var_CreateGetStringCommand( p_filter,
1816                                                CFG_PREFIX "atmowinexe" );
1817         LPTSTR ptsz_path = ToT(psz_path);
1818         if(psz_path != NULL)
1819         {
1820             STARTUPINFO startupinfo;
1821             PROCESS_INFORMATION pinfo;
1822             memset(&startupinfo, 0, sizeof(STARTUPINFO));
1823             startupinfo.cb = sizeof(STARTUPINFO);
1824             if(CreateProcess(ptsz_path, NULL, NULL, NULL,
1825                 FALSE, 0, NULL, NULL, &startupinfo, &pinfo) == TRUE)
1826             {
1827                 msg_Dbg(p_filter,"launched AtmoWin from %s", psz_path);
1828                 WaitForInputIdle(pinfo.hProcess, 5000);
1829                 /*
1830                   retry to initialize the library COM ... functionality
1831                   after the server was launched
1832                 */
1833                 i = AtmoInitialize(p_filter, false);
1834             } else {
1835                 msg_Err(p_filter,"failed to launch AtmoWin from %s", psz_path);
1836             }
1837             free(psz_path);
1838             free(ptsz_path);
1839         }
1840     }
1841 #endif
1842
1843     if(i == 1) /* Init Atmolight success... */
1844     {
1845         msg_Dbg( p_filter, "AtmoInitialize Ok!");
1846         /*
1847         configure
1848            p_sys->i_atmo_width and p_sys->i_atmo_height
1849            if the external AtmoWinA.exe is used, it may require
1850            a other sample image size than 64 x 48
1851            (this overrides the settings of the filter)
1852         */
1853         Atmo_SetupImageSize( p_filter );
1854
1855
1856         if( p_sys->i_device_type >= 1 )
1857         {
1858            /*
1859              AtmoConnection class initialized now we can initialize
1860              the default zone and channel mappings
1861            */
1862            Atmo_SetupBuildZones( p_filter );
1863         }
1864
1865         /* Setup Transferbuffers for 64 x 48 , RGB with 32bit Per Pixel */
1866         AtmoCreateTransferBuffers(p_filter, BI_RGB, 4,
1867             p_sys->i_atmo_width,
1868             p_sys->i_atmo_height
1869             );
1870
1871         /* say the userspace driver that a live mode should be activated
1872         the functions returns the old mode for later restore!
1873         - the buildin driver launches the live view thread in that case
1874         */
1875         p_sys->i_AtmoOldEffect = AtmoSwitchEffect(p_filter, emLivePicture);
1876
1877         /*
1878         live view can have two differnt source the AtmoWinA
1879         internal GDI Screencapture and the external one - which we
1880         need here...
1881         */
1882         AtmoSetLiveSource(p_filter, lvsExternal);
1883
1884         /* enable other parts only if everything is fine */
1885         p_sys->b_enabled = true;
1886
1887         msg_Dbg( p_filter, "Atmo Filter Enabled Ok!");
1888     }
1889
1890 }
1891
1892
1893 /*****************************************************************************
1894 * CreateFilter: allocates AtmoLight video thread output method
1895 *****************************************************************************
1896 * This function allocates and initializes a AtmoLight vout method.
1897 *****************************************************************************/
1898 static int CreateFilter( vlc_object_t *p_this )
1899 {
1900     filter_t *p_filter = (filter_t *)p_this;
1901     filter_sys_t *p_sys;
1902
1903     /* Allocate structure */
1904     p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) );
1905     p_filter->p_sys = p_sys;
1906     if( p_filter->p_sys == NULL )
1907         return VLC_ENOMEM;
1908     /* set all entries to zero */
1909     memset(p_sys, 0, sizeof( filter_sys_t ));
1910     vlc_mutex_init( &p_sys->filter_lock );
1911
1912     msg_Dbg( p_filter, "Create Atmo Filter");
1913
1914     /* further Setup Function pointers for videolan for calling my filter */
1915     p_filter->pf_video_filter = Filter;
1916
1917     config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
1918                        p_filter->p_cfg );
1919
1920     AddAtmoSettingsVariablesCallbacks(p_filter);
1921
1922     Atmo_SetupParameters(p_filter);
1923
1924
1925     return VLC_SUCCESS;
1926 }
1927
1928
1929
1930 /*****************************************************************************
1931 * DestroyFilter: destroy AtmoLight video thread output method
1932 *****************************************************************************
1933 * Terminate an output method created by CreateFilter
1934 *****************************************************************************/
1935
1936 static void DestroyFilter( vlc_object_t *p_this )
1937 {
1938     filter_t *p_filter = (filter_t *)p_this;
1939     filter_sys_t *p_sys =  p_filter->p_sys;
1940
1941     msg_Dbg( p_filter, "Destroy Atmo Filter");
1942
1943     DelAtmoSettingsVariablesCallbacks(p_filter);
1944
1945     Atmo_Shutdown(p_filter);
1946
1947 #if defined( _WIN32 )
1948     if(p_sys->h_AtmoCtrl != NULL)
1949     {
1950         FreeLibrary(p_sys->h_AtmoCtrl);
1951     }
1952 #endif
1953
1954     delete p_sys->p_atmo_dyndata;
1955     delete p_sys->p_atmo_config;
1956
1957     vlc_mutex_destroy( &p_sys->filter_lock );
1958
1959     free( p_sys );
1960 }
1961
1962
1963 /*
1964 function stolen from some other videolan source filter ;-)
1965 for the moment RGB is OK... but better would be a direct transformation
1966 from YUV --> HSV
1967 */
1968 static inline void yuv_to_rgb( uint8_t *r, uint8_t *g, uint8_t *b,
1969                               uint8_t y1, uint8_t u1, uint8_t v1 )
1970 {
1971     /* macros used for YUV pixel conversions */
1972 #   define SCALEBITS 10
1973 #   define ONE_HALF  (1 << (SCALEBITS - 1))
1974 #   define FIX(x)    ((int) ((x) * (1<<SCALEBITS) + 0.5))
1975 #   define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
1976
1977     int y, cb, cr, r_add, g_add, b_add;
1978
1979     cb = u1 - 128;
1980     cr = v1 - 128;
1981     r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
1982     g_add = - FIX(0.34414*255.0/224.0) * cb
1983         - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
1984     b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
1985     y = (y1 - 16) * FIX(255.0/219.0);
1986     *r = CLAMP((y + r_add) >> SCALEBITS);
1987     *g = CLAMP((y + g_add) >> SCALEBITS);
1988     *b = CLAMP((y + b_add) >> SCALEBITS);
1989 }
1990 /******************************************************************************
1991 * ExtractMiniImage_YUV: extract a small image from the picture as 24-bit RGB
1992 *******************************************************************************
1993 * p_sys is a pointer to
1994 * p_inpic is the source frame
1995 * p_transfer_dest is the target buffer for the picture must be big enough!
1996 * (in win32 environment this buffer comes from the external DLL where it is
1997 * create as "variant array" and returned through the AtmoLockTransferbuffer
1998 */
1999 static void ExtractMiniImage_YUV(filter_sys_t *p_sys,
2000                                  picture_t *p_inpic,
2001                                  uint8_t *p_transfer_dest)
2002 {
2003     int i_col;
2004     int i_row;
2005     uint8_t *p_src_y;
2006     uint8_t *p_src_u;
2007     uint8_t *p_src_v;
2008     uint8_t *p_rgb_dst_line_red;
2009     uint8_t *p_rgb_dst_line_green;
2010     uint8_t *p_rgb_dst_line_blue;
2011     int i_xpos_y;
2012     int i_xpos_u;
2013     int i_xpos_v;
2014
2015     /* calcute Pointers for Storage of B G R (A) */
2016     p_rgb_dst_line_blue      = p_transfer_dest;
2017     p_rgb_dst_line_green     = p_transfer_dest + 1;
2018     p_rgb_dst_line_red       = p_transfer_dest + 2 ;
2019
2020     int i_row_count = p_sys->i_atmo_height + 1;
2021     int i_col_count = p_sys->i_atmo_width + 1;
2022     int i_y_row,i_u_row,i_v_row,i_pixel_row;
2023     int i_pixel_col;
2024
2025
2026     /*  these two ugly loops extract the small image - goes it faster? how?
2027     the loops are so designed that there is a small border around the extracted
2028     image so we won't get column and row - zero from the frame, and not the most
2029     right and bottom pixels --- which may be clipped on computers useing TV out
2030     - through overscan!
2031
2032     TODO: try to find out if the output is clipped through VLC - and try here
2033     to ingore the clipped away area for a better result!
2034
2035     TODO: performance improvement in InitFilter percalculated the offsets of
2036     the lines inside the planes so I can save (i_row_count * 3) 2xMUL and
2037     one time DIV the same could be done for the inner loop I think...
2038     */
2039     for(i_row = 1; i_row < i_row_count; i_row++)
2040     {
2041         // calcute the current Lines in the source planes for this outputrow
2042         /*  Adresscalcuation  pointer to plane  Length of one pixelrow in bytes
2043         calculate row now number
2044         */
2045         /*
2046            p_inpic->format? transform Pixel row into row of plane...
2047            how? simple? fast? good?
2048         */
2049
2050         /* compute the source pixel row and respect the active cropping */
2051         i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
2052             + p_sys->i_crop_y_offset;
2053
2054         /*
2055         trans for these Pixel row into the row of each plane ..
2056         because planesize can differ from image size
2057         */
2058         i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
2059             p_inpic->format.i_visible_height;
2060
2061         i_u_row = (i_pixel_row * p_inpic->p[U_PLANE].i_visible_lines) /
2062             p_inpic->format.i_visible_height;
2063
2064         i_v_row = (i_pixel_row * p_inpic->p[V_PLANE].i_visible_lines) /
2065             p_inpic->format.i_visible_height;
2066
2067         /* calculate  the pointers to the pixeldata for this row
2068            in each plane
2069         */
2070         p_src_y = p_inpic->p[Y_PLANE].p_pixels +
2071             p_inpic->p[Y_PLANE].i_pitch * i_y_row;
2072         p_src_u = p_inpic->p[U_PLANE].p_pixels +
2073             p_inpic->p[U_PLANE].i_pitch * i_u_row;
2074         p_src_v = p_inpic->p[V_PLANE].p_pixels +
2075             p_inpic->p[V_PLANE].i_pitch * i_v_row;
2076
2077         if(p_sys->b_swap_uv)
2078         {
2079           /*
2080            swap u and v plane for YV12 images
2081           */
2082           uint8_t *p_temp_plane = p_src_u;
2083           p_src_u = p_src_v;
2084           p_src_v = p_temp_plane;
2085         }
2086
2087         for(i_col = 1; i_col < i_col_count; i_col++)
2088         {
2089             i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
2090                 p_sys->i_crop_x_offset;
2091             /*
2092             trans for these Pixel row into the row of each plane ..
2093             because planesize can differ from image size
2094             */
2095             i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
2096                 p_inpic->format.i_visible_width;
2097             i_xpos_u = (i_pixel_col * p_inpic->p[U_PLANE].i_visible_pitch) /
2098                 p_inpic->format.i_visible_width;
2099             i_xpos_v = (i_pixel_col * p_inpic->p[V_PLANE].i_visible_pitch) /
2100                 p_inpic->format.i_visible_width;
2101
2102             yuv_to_rgb(p_rgb_dst_line_red,
2103                 p_rgb_dst_line_green,
2104                 p_rgb_dst_line_blue,
2105
2106                 p_src_y[i_xpos_y],
2107                 p_src_u[i_xpos_u],
2108                 p_src_v[i_xpos_v]);
2109
2110             /* +4 because output image should be RGB32 with dword alignment! */
2111             p_rgb_dst_line_red   += 4;
2112             p_rgb_dst_line_green += 4;
2113             p_rgb_dst_line_blue  += 4;
2114         }
2115    }
2116
2117    if(p_sys->b_show_dots)
2118    {
2119        for(i_row = 1; i_row < i_row_count; i_row++)
2120        {
2121            i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
2122                    + p_sys->i_crop_y_offset;
2123
2124            i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
2125                    p_inpic->format.i_visible_height;
2126
2127            p_src_y = p_inpic->p[Y_PLANE].p_pixels +
2128                    p_inpic->p[Y_PLANE].i_pitch * i_y_row;
2129
2130            for(i_col = 1; i_col < i_col_count; i_col++)
2131            {
2132               i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
2133                             p_sys->i_crop_x_offset;
2134               i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
2135                          p_inpic->format.i_visible_width;
2136
2137               p_src_y[i_xpos_y] = 255;
2138            }
2139        }
2140    }
2141
2142 }
2143
2144
2145 /******************************************************************************
2146 * SaveBitmap: Saves the content of a transferbuffer as Bitmap to disk
2147 *******************************************************************************
2148 * just for debugging
2149 * p_sys -> configuration if Atmo from there the function will get height and
2150 *          width
2151 * p_pixels -> should be the dword aligned BGR(A) image data
2152 * psz_filename -> filename where to store
2153 */
2154 #if defined(__ATMO_DEBUG__)
2155 void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename)
2156 {
2157     /* for debug out only used*/
2158     VLC_BITMAPINFO bmp_info;
2159     BITMAPFILEHEADER  bmp_fileheader;
2160     FILE *fp_bitmap;
2161
2162     memset(&bmp_info, 0, sizeof(VLC_BITMAPINFO));
2163     bmp_info.bmiHeader.biSize = sizeof(VLC_BITMAPINFOHEADER);
2164     bmp_info.bmiHeader.biSizeImage   = p_sys->i_atmo_height *
2165                                        p_sys->i_atmo_width * 4;
2166     bmp_info.bmiHeader.biCompression = BI_RGB;
2167     bmp_info.bmiHeader.biWidth        = p_sys->i_atmo_width;
2168     bmp_info.bmiHeader.biHeight       = -p_sys->i_atmo_height;
2169     bmp_info.bmiHeader.biBitCount     = 32;
2170     bmp_info.bmiHeader.biPlanes       = 1;
2171
2172     bmp_fileheader.bfReserved1 = 0;
2173     bmp_fileheader.bfReserved2 = 0;
2174     bmp_fileheader.bfSize = sizeof(BITMAPFILEHEADER) +
2175                             sizeof(VLC_BITMAPINFOHEADER) +
2176                             bmp_info.bmiHeader.biSizeImage;
2177     bmp_fileheader.bfType = VLC_TWOCC('B','M');
2178     bmp_fileheader.bfOffBits = sizeof(BITMAPFILEHEADER) +
2179                                sizeof(VLC_BITMAPINFOHEADER);
2180
2181     fp_bitmap = fopen(psz_filename,"wb");
2182     if( fp_bitmap != NULL)
2183     {
2184         fwrite(&bmp_fileheader, sizeof(BITMAPFILEHEADER), 1, fp_bitmap);
2185         fwrite(&bmp_info.bmiHeader, sizeof(VLC_BITMAPINFOHEADER), 1, fp_bitmap);
2186         fwrite(p_pixels, bmp_info.bmiHeader.biSizeImage, 1, fp_bitmap);
2187         fclose(fp_bitmap);
2188     }
2189 }
2190 #endif
2191
2192
2193 /****************************************************************************
2194 * CreateMiniImage: extracts a 64x48 pixel image from the frame
2195 * (there is a small border arround thats why the loops starts with one
2196 * instead zero) without any interpolation
2197 *****************************************************************************/
2198 static void CreateMiniImage( filter_t *p_filter, picture_t *p_inpic)
2199 {
2200     filter_sys_t *p_sys = p_filter->p_sys;
2201     /*
2202     pointer to RGB Buffer created in external libary as safe array which
2203     is locked inside AtmoLockTransferBuffer
2204     */
2205     uint8_t *p_transfer;
2206 #if defined( __ATMO_DEBUG__ )
2207     /* for debug out only used*/
2208     char sz_filename[MAX_PATH];
2209 #endif
2210
2211     /*
2212     Lock the before created VarArray (AtmoCreateTransferBuffers)
2213     inside my wrapper library and give me a pointer to the buffer!
2214     below linux a global buffer may be used and protected with a mutex?
2215     */
2216     p_transfer = AtmoLockTransferBuffer(p_filter);
2217     if(p_transfer == NULL)
2218     {
2219         msg_Err( p_filter, "AtmoLight no transferbuffer available. "\
2220                            "AtmoLight will be disabled!");
2221         p_sys->b_enabled = false;
2222         return;
2223     }
2224
2225     /*
2226     do the call via pointer to function instead of having a
2227     case structure here
2228     */
2229     p_sys->pf_extract_mini_image(p_sys, p_inpic, p_transfer);
2230
2231
2232 #if defined( __ATMO_DEBUG__ )
2233     /*
2234     if debugging enabled save every 128th image to disk
2235     */
2236     if(p_sys->b_saveframes && p_sys->sz_framepath[0] != 0 )
2237     {
2238
2239         if((p_sys->ui_frame_counter & 127) == 0)
2240         {
2241             sprintf(sz_filename,"%satmo_dbg_%06u.bmp",p_sys->sz_framepath,
2242                 p_sys->ui_frame_counter);
2243             msg_Dbg(p_filter, "SaveFrame %s",sz_filename);
2244
2245             SaveBitmap(p_sys, p_transfer, sz_filename);
2246         }
2247     }
2248
2249     msg_Dbg( p_filter, "AtmoFrame %u Time: %d ms", p_sys->ui_frame_counter,
2250                 mdate() / 1000);
2251     p_sys->ui_frame_counter++;
2252 #endif
2253
2254     p_sys->i_frames_processed++;
2255
2256
2257     /* show the colors on the wall */
2258     AtmoSendPixelData( p_filter );
2259 }
2260
2261
2262
2263
2264 /*****************************************************************************
2265 * Filter: calls the extract method and forwards the incomming picture 1:1
2266 *****************************************************************************
2267 *
2268 *****************************************************************************/
2269
2270 static picture_t * Filter( filter_t *p_filter, picture_t *p_pic )
2271 {
2272     filter_sys_t *p_sys = p_filter->p_sys;
2273     if( !p_pic ) return NULL;
2274
2275     picture_t *p_outpic = filter_NewPicture( p_filter );
2276     if( !p_outpic )
2277     {
2278         picture_Release( p_pic );
2279         return NULL;
2280     }
2281     picture_CopyPixels( p_outpic, p_pic );
2282
2283     vlc_mutex_lock( &p_sys->filter_lock );
2284
2285     if(p_sys->b_enabled && p_sys->pf_extract_mini_image &&
2286        !p_sys->b_pause_live)
2287     {
2288         p_sys->i_crop_x_offset  = p_filter->fmt_in.video.i_x_offset;
2289         p_sys->i_crop_y_offset  = p_filter->fmt_in.video.i_y_offset;
2290         p_sys->i_crop_width     = p_filter->fmt_in.video.i_visible_width;
2291         p_sys->i_crop_height    = p_filter->fmt_in.video.i_visible_height;
2292
2293         CreateMiniImage(p_filter, p_outpic);
2294     }
2295
2296     vlc_mutex_unlock( &p_sys->filter_lock );
2297
2298
2299     return CopyInfoAndRelease( p_outpic, p_pic );
2300 }
2301
2302
2303 /*****************************************************************************
2304 * FadeToColorThread: Threadmethod which changes slowly the color
2305 * to a target color defined in p_fadethread struct
2306 * use for: Fade to Pause Color,  and Fade to End Color
2307 *****************************************************************************/
2308 static void *FadeToColorThread(void *obj)
2309 {
2310     fadethread_t *p_fadethread = (fadethread_t *)obj;
2311     filter_sys_t *p_sys = (filter_sys_t *)p_fadethread->p_filter->p_sys;
2312     int i_steps_done = 0;
2313     int i_index;
2314     int i_pause_red;
2315     int i_pause_green;
2316     int i_pause_blue;
2317
2318     int i_src_red;
2319     int i_src_green;
2320     int i_src_blue;
2321
2322     uint8_t *p_source = NULL;
2323
2324     int canc = vlc_savecancel ();
2325     /* initialize AtmoWin for this thread! */
2326     AtmoInitialize(p_fadethread->p_filter , true);
2327
2328     uint8_t *p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
2329     if(p_transfer != NULL) {
2330         /* safe colors as "32bit" Integers to avoid overflows*/
2331         i_pause_red   = p_fadethread->ui_red;
2332         i_pause_blue  = p_fadethread->ui_blue;
2333         i_pause_green = p_fadethread->ui_green;
2334
2335         /*
2336         allocate a temporary buffer for the last send
2337         image size less then 15kb
2338         */
2339         int i_size = 4 * p_sys->i_atmo_width * p_sys->i_atmo_height;
2340         p_source = (uint8_t *)malloc( i_size );
2341         if(p_source != NULL)
2342         {
2343             /*
2344             get a copy of the last transfered image as orign for the
2345             fading steps...
2346             */
2347             memcpy(p_source, p_transfer, i_size);
2348             /* send the same pixel data again... to unlock the buffer! */
2349             AtmoSendPixelData( p_fadethread->p_filter );
2350
2351             while( (!atomic_load (&p_fadethread->abort)) &&
2352                 (i_steps_done < p_fadethread->i_steps))
2353             {
2354                 p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
2355                 if(!p_transfer) break; /* should not happen if it worked
2356                                        one time in the code above! */
2357                 i_steps_done++;
2358                 /*
2359                 move all pixels in the mini image (64x48) one step closer to
2360                 the desired color these loop takes the most time of this
2361                 thread improvements wellcome!
2362                 */
2363                 for(i_index = 0;
2364                     (i_index < i_size) && (!atomic_load (&p_fadethread->abort));
2365                     i_index+=4)
2366                 {
2367                     i_src_blue  = p_source[i_index+0];
2368                     i_src_green = p_source[i_index+1];
2369                     i_src_red   = p_source[i_index+2];
2370                     p_transfer[i_index+0] = (uint8_t) (((
2371                         (i_pause_blue  - i_src_blue)
2372                         * i_steps_done)/p_fadethread->i_steps)
2373                         + i_src_blue);
2374
2375                     p_transfer[i_index+1] = (uint8_t) (((
2376                         (i_pause_green - i_src_green)
2377                         * i_steps_done)/p_fadethread->i_steps)
2378                         + i_src_green);
2379
2380                     p_transfer[i_index+2] = (uint8_t) (((
2381                         (i_pause_red   - i_src_red)
2382                         * i_steps_done)/p_fadethread->i_steps)
2383                         + i_src_red);
2384                 }
2385
2386                 /* send image to lightcontroller */
2387                 AtmoSendPixelData( p_fadethread->p_filter );
2388                 /* is there something like and interruptable sleep inside
2389                 the VLC libaries? inside native win32 I would use an Event
2390                 (CreateEvent) and here an WaitForSingleObject?
2391                 */
2392                 msleep(40000);
2393             }
2394             free(p_source);
2395         } else {
2396             /* in failure of malloc also unlock buffer  */
2397             AtmoSendPixelData(p_fadethread->p_filter);
2398         }
2399     }
2400     /* call indirect to OleUnitialize() for this thread */
2401     AtmoFinalize(p_fadethread->p_filter, 0);
2402     vlc_restorecancel (canc);
2403     return NULL;
2404 }
2405
2406 /*****************************************************************************
2407 * CheckAndStopFadeThread: if there is a fadethread structure left, or running.
2408 ******************************************************************************
2409 * this function will stop the thread ... and waits for its termination
2410 * before removeing the objects from vout_sys_t ...
2411 ******************************************************************************/
2412 static void CheckAndStopFadeThread(filter_t *p_filter)
2413 {
2414     filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2415     vlc_mutex_lock( &p_sys->filter_lock );
2416     if(p_sys->p_fadethread != NULL)
2417     {
2418         msg_Dbg(p_filter, "kill still running fadeing thread...");
2419
2420         atomic_store(&p_sys->p_fadethread->abort, true);
2421
2422         vlc_join(p_sys->p_fadethread->thread, NULL);
2423         free(p_sys->p_fadethread);
2424         p_sys->p_fadethread = NULL;
2425     }
2426     vlc_mutex_unlock( &p_sys->filter_lock );
2427 }
2428
2429 /****************************************************************************
2430 * StateCallback: Callback for the inputs variable "State" to get notified
2431 * about Pause and Continue Playback events.
2432 *****************************************************************************/
2433 static int AtmoSettingsCallback( vlc_object_t *, char const *psz_var,
2434                                  vlc_value_t oldval, vlc_value_t newval,
2435                                  void *p_data )
2436 {
2437     filter_t *p_filter = (filter_t *)p_data;
2438     filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2439
2440     vlc_mutex_lock( &p_sys->filter_lock );
2441
2442     if( !strcmp( psz_var, CFG_PREFIX "showdots" ))
2443     {
2444         p_sys->b_show_dots = newval.b_bool;
2445     }
2446
2447     CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
2448     if(p_atmo_config)
2449     {
2450
2451        msg_Dbg(p_filter, "apply AtmoSettingsCallback %s (int: %"PRId64" -> %"PRId64")",
2452              psz_var,
2453              oldval.i_int,
2454              newval.i_int
2455        );
2456
2457         if( !strcmp( psz_var, CFG_PREFIX "filtermode" ))
2458             p_atmo_config->setLiveViewFilterMode( (AtmoFilterMode)newval.i_int);
2459
2460         else if( !strcmp( psz_var, CFG_PREFIX "percentnew" ))
2461                  p_atmo_config->setLiveViewFilter_PercentNew( newval.i_int );
2462
2463         else if( !strcmp( psz_var, CFG_PREFIX "meanlength" ))
2464                  p_atmo_config->setLiveViewFilter_MeanLength( newval.i_int );
2465
2466         else if( !strcmp( psz_var, CFG_PREFIX "meanthreshold" ))
2467                  p_atmo_config->setLiveViewFilter_MeanThreshold( newval.i_int );
2468
2469         else if( !strcmp( psz_var, CFG_PREFIX "edgeweightning" ))
2470                  p_atmo_config->setLiveView_EdgeWeighting( newval.i_int );
2471
2472         else if( !strcmp( psz_var, CFG_PREFIX "brightness" ))
2473                  p_atmo_config->setLiveView_BrightCorrect( newval.i_int );
2474
2475         else if( !strcmp( psz_var, CFG_PREFIX "darknesslimit" ))
2476                  p_atmo_config->setLiveView_DarknessLimit( newval.i_int );
2477
2478         else if( !strcmp( psz_var, CFG_PREFIX "huewinsize" ))
2479                  p_atmo_config->setLiveView_HueWinSize( newval.i_int );
2480
2481         else if( !strcmp( psz_var, CFG_PREFIX "satwinsize" ))
2482                  p_atmo_config->setLiveView_SatWinSize( newval.i_int );
2483
2484         else if( !strcmp( psz_var, CFG_PREFIX "framedelay" ))
2485                  p_atmo_config->setLiveView_FrameDelay( newval.i_int );
2486
2487         else if( !strcmp( psz_var, CFG_PREFIX "whiteadj" ))
2488                  p_atmo_config->setUseSoftwareWhiteAdj( newval.b_bool );
2489
2490         else if( !strcmp( psz_var, CFG_PREFIX "white-red" ))
2491                  p_atmo_config->setWhiteAdjustment_Red( newval.i_int );
2492
2493         else if( !strcmp( psz_var, CFG_PREFIX "white-green" ))
2494                  p_atmo_config->setWhiteAdjustment_Green( newval.i_int );
2495
2496         else if( !strcmp( psz_var, CFG_PREFIX "white-blue" ))
2497                  p_atmo_config->setWhiteAdjustment_Blue( newval.i_int );
2498
2499     }
2500
2501     vlc_mutex_unlock( &p_sys->filter_lock );
2502
2503     return VLC_SUCCESS;
2504 }
2505
2506 static void AddAtmoSettingsVariablesCallbacks(filter_t *p_filter)
2507 {
2508    var_AddCallback( p_filter, CFG_PREFIX "filtermode",
2509                     AtmoSettingsCallback, p_filter );
2510    var_AddCallback( p_filter, CFG_PREFIX "percentnew",
2511                     AtmoSettingsCallback, p_filter );
2512
2513
2514    var_AddCallback( p_filter, CFG_PREFIX "meanlength",
2515                     AtmoSettingsCallback, p_filter );
2516    var_AddCallback( p_filter, CFG_PREFIX "meanthreshold",
2517                     AtmoSettingsCallback, p_filter );
2518
2519    var_AddCallback( p_filter, CFG_PREFIX "edgeweightning",
2520                     AtmoSettingsCallback, p_filter );
2521    var_AddCallback( p_filter, CFG_PREFIX "brightness",
2522                     AtmoSettingsCallback, p_filter );
2523    var_AddCallback( p_filter, CFG_PREFIX "darknesslimit",
2524                     AtmoSettingsCallback, p_filter );
2525
2526    var_AddCallback( p_filter, CFG_PREFIX "huewinsize",
2527                     AtmoSettingsCallback, p_filter );
2528    var_AddCallback( p_filter, CFG_PREFIX "satwinsize",
2529                     AtmoSettingsCallback, p_filter );
2530    var_AddCallback( p_filter, CFG_PREFIX "framedelay",
2531                     AtmoSettingsCallback, p_filter );
2532
2533
2534    var_AddCallback( p_filter, CFG_PREFIX "whiteadj",
2535                     AtmoSettingsCallback, p_filter );
2536    var_AddCallback( p_filter, CFG_PREFIX "white-red",
2537                     AtmoSettingsCallback, p_filter );
2538    var_AddCallback( p_filter, CFG_PREFIX "white-green",
2539                     AtmoSettingsCallback, p_filter );
2540    var_AddCallback( p_filter, CFG_PREFIX "white-blue",
2541                     AtmoSettingsCallback, p_filter );
2542
2543    var_AddCallback( p_filter, CFG_PREFIX "showdots",
2544                     AtmoSettingsCallback, p_filter );
2545
2546 }
2547
2548 static void DelAtmoSettingsVariablesCallbacks( filter_t *p_filter )
2549 {
2550
2551    var_DelCallback( p_filter, CFG_PREFIX "filtermode",
2552                     AtmoSettingsCallback, p_filter );
2553
2554    var_DelCallback( p_filter, CFG_PREFIX "percentnew",
2555                     AtmoSettingsCallback, p_filter );
2556    var_DelCallback( p_filter, CFG_PREFIX "meanlength",
2557                     AtmoSettingsCallback, p_filter );
2558    var_DelCallback( p_filter, CFG_PREFIX "meanthreshold",
2559                     AtmoSettingsCallback, p_filter );
2560
2561    var_DelCallback( p_filter, CFG_PREFIX "edgeweightning",
2562                     AtmoSettingsCallback, p_filter );
2563    var_DelCallback( p_filter, CFG_PREFIX "brightness",
2564                     AtmoSettingsCallback, p_filter );
2565    var_DelCallback( p_filter, CFG_PREFIX "darknesslimit",
2566                     AtmoSettingsCallback, p_filter );
2567
2568    var_DelCallback( p_filter, CFG_PREFIX "huewinsize",
2569                     AtmoSettingsCallback, p_filter );
2570    var_DelCallback( p_filter, CFG_PREFIX "satwinsize",
2571                     AtmoSettingsCallback, p_filter );
2572    var_DelCallback( p_filter, CFG_PREFIX "framedelay",
2573                     AtmoSettingsCallback, p_filter );
2574
2575
2576    var_DelCallback( p_filter, CFG_PREFIX "whiteadj",
2577                     AtmoSettingsCallback, p_filter );
2578    var_DelCallback( p_filter, CFG_PREFIX "white-red",
2579                     AtmoSettingsCallback, p_filter );
2580    var_DelCallback( p_filter, CFG_PREFIX "white-green",
2581                     AtmoSettingsCallback, p_filter );
2582    var_DelCallback( p_filter, CFG_PREFIX "white-blue",
2583                     AtmoSettingsCallback, p_filter );
2584
2585    var_DelCallback( p_filter, CFG_PREFIX "showdots",
2586                     AtmoSettingsCallback, p_filter );
2587
2588 }
2589
2590
2591 #if defined(__ATMO_DEBUG__)
2592 static void atmo_parse_crop(char *psz_cropconfig,
2593                             video_format_t fmt_in,
2594                             video_format_t fmt_render,
2595                             int &i_visible_width, int &i_visible_height,
2596                             int &i_x_offset, int &i_y_offset )
2597 {
2598     int64_t i_aspect_num, i_aspect_den;
2599     unsigned int i_width, i_height;
2600
2601     i_visible_width  = fmt_in.i_visible_width;
2602     i_visible_height = fmt_in.i_visible_height;
2603     i_x_offset       = fmt_in.i_x_offset;
2604     i_y_offset       = fmt_in.i_y_offset;
2605
2606     char *psz_end = NULL, *psz_parser = strchr( psz_cropconfig, ':' );
2607     if( psz_parser )
2608     {
2609         /* We're using the 3:4 syntax */
2610         i_aspect_num = strtol( psz_cropconfig, &psz_end, 10 );
2611         if( psz_end == psz_cropconfig || !i_aspect_num ) return;
2612
2613         i_aspect_den = strtol( ++psz_parser, &psz_end, 10 );
2614         if( psz_end == psz_parser || !i_aspect_den ) return;
2615
2616         i_width = fmt_in.i_sar_den * fmt_render.i_visible_height *
2617             i_aspect_num / i_aspect_den / fmt_in.i_sar_num;
2618
2619         i_height = fmt_render.i_visible_width*fmt_in.i_sar_num *
2620             i_aspect_den / i_aspect_num / fmt_in.i_sar_den;
2621
2622         if( i_width < fmt_render.i_visible_width )
2623         {
2624             i_x_offset = fmt_render.i_x_offset +
2625                 (fmt_render.i_visible_width - i_width) / 2;
2626             i_visible_width = i_width;
2627         }
2628         else
2629         {
2630             i_y_offset = fmt_render.i_y_offset +
2631                 (fmt_render.i_visible_height - i_height) / 2;
2632             i_visible_height = i_height;
2633         }
2634     }
2635     else
2636     {
2637         psz_parser = strchr( psz_cropconfig, 'x' );
2638         if( psz_parser )
2639         {
2640             /* Maybe we're using the <width>x<height>+<left>+<top> syntax */
2641             unsigned int i_crop_width, i_crop_height, i_crop_top, i_crop_left;
2642
2643             i_crop_width = strtol( psz_cropconfig, &psz_end, 10 );
2644             if( psz_end != psz_parser ) return;
2645
2646             psz_parser = strchr( ++psz_end, '+' );
2647             i_crop_height = strtol( psz_end, &psz_end, 10 );
2648             if( psz_end != psz_parser ) return;
2649
2650             psz_parser = strchr( ++psz_end, '+' );
2651             i_crop_left = strtol( psz_end, &psz_end, 10 );
2652             if( psz_end != psz_parser ) return;
2653
2654             psz_end++;
2655             i_crop_top = strtol( psz_end, &psz_end, 10 );
2656             if( *psz_end != '\0' ) return;
2657
2658             i_width = i_crop_width;
2659             i_visible_width = i_width;
2660
2661             i_height = i_crop_height;
2662             i_visible_height = i_height;
2663
2664             i_x_offset = i_crop_left;
2665             i_y_offset = i_crop_top;
2666         }
2667         else
2668         {
2669             /* Maybe we're using the <left>+<top>+<right>+<bottom> syntax */
2670             unsigned int i_crop_top, i_crop_left, i_crop_bottom, i_crop_right;
2671
2672             psz_parser = strchr( psz_cropconfig, '+' );
2673             i_crop_left = strtol( psz_cropconfig, &psz_end, 10 );
2674             if( psz_end != psz_parser ) return;
2675
2676             psz_parser = strchr( ++psz_end, '+' );
2677             i_crop_top = strtol( psz_end, &psz_end, 10 );
2678             if( psz_end != psz_parser ) return;
2679
2680             psz_parser = strchr( ++psz_end, '+' );
2681             i_crop_right = strtol( psz_end, &psz_end, 10 );
2682             if( psz_end != psz_parser ) return;
2683
2684             psz_end++;
2685             i_crop_bottom = strtol( psz_end, &psz_end, 10 );
2686             if( *psz_end != '\0' ) return;
2687
2688             i_width = fmt_render.i_visible_width -
2689                         i_crop_left -
2690                         i_crop_right;
2691             i_visible_width = i_width;
2692
2693             i_height = fmt_render.i_visible_height -
2694                         i_crop_top -
2695                         i_crop_bottom;
2696             i_visible_height = i_height;
2697
2698             i_x_offset = i_crop_left;
2699             i_y_offset = i_crop_top;
2700         }
2701     }
2702 }
2703 #endif