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