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