]> git.sesse.net Git - vlc/blob - modules/video_filter/atmo/atmo.cpp
Remove unnedeeded msg_Error.
[vlc] / modules / video_filter / atmo / atmo.cpp
1 /*****************************************************************************
2 * atmo.cpp : "Atmo Light" video filter
3 *****************************************************************************
4 * Copyright (C) 2000-2006 the VideoLAN team
5 * $Id$
6 *
7 * Authors: AndrĂ© Weber (WeberAndre@gmx.de)
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
23
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <string.h>
29 #include <math.h>                                            /* sin(), cos() */
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 // #define __ATMO_DEBUG__
36 // [:Zs]+$
37 #include <vlc_common.h>
38 #include <vlc_plugin.h>
39 #include <vlc_vout.h>
40
41 #include <vlc_playlist.h>
42 #include "vlc_filter.h"
43
44 #include "AtmoDefs.h"
45 #include "AtmoDynData.h"
46 #include "AtmoLiveView.h"
47 #include "AtmoTools.h"
48 #include "AtmoExternalCaptureInput.h"
49 #include "AtmoConfig.h"
50 #include "AtmoConnection.h"
51 #include "AtmoSerialConnection.h"
52
53
54 /*****************************************************************************
55 * Local prototypes
56 *****************************************************************************/
57 /* directly to vlc related functions required that the module is accepted */
58 static int  CreateFilter    ( vlc_object_t * );
59 static void DestroyFilter   ( vlc_object_t * );
60 static picture_t * Filter( filter_t *, picture_t *);
61
62 /* callback for global variable state pause / continue / stop events */
63 static void AddStateVariableCallback( filter_t *);
64 static void DelStateVariableCallback( filter_t *);
65 static int StateCallback(vlc_object_t *, char const *,
66                          vlc_value_t, vlc_value_t, void *);
67
68 /* callback for variable crop-update */
69 static void AddCropVariableCallback( filter_t *);
70 static void DelCropVariableCallback( filter_t *);
71 static int CropCallback(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
116 /*
117 strings for settings menus and hints
118 */
119 #define MODULE_DESCRIPTION N_ ( \
120  "This module allows to control an so called AtmoLight device which "\
121  "is connected to your computer.\n"\
122  "AtmoLight is the homebrew version of that what Philips calls AmbiLight.\n"\
123  "If you need further informations feel free to visit us at\n\n"\
124  "http://www.vdr-wiki.de/wiki/index.php/Atmo-plugin\n"\
125  "http://www.vdr-wiki.de/wiki/index.php/AtmoWin\n\n"\
126  "there you will find detailed descriptions how to build it for your self and "\
127  "where you can get the required parts and so on.\n There you can also see "\
128  "pictures and some movies showing such a device in live action...")
129
130
131
132 #if defined( __ATMO_DEBUG__ )
133 #   define SAVEFRAMES_TEXT     N_("Save Debug Frames")
134 #   define SAVEFRAMES_LONGTEXT N_("Writes every 128th miniframe to a folder.")
135 #   define FRAMEPATH_TEXT      N_("Debug Frame Folder")
136 #   define FRAMEPATH_LONGTEXT  N_("defines the path where the debugframes " \
137                                   "should be saved")
138 #endif
139
140 #define WIDTH_TEXT             N_("Extracted Image Width")
141 #define WIDTH_LONGTEXT         N_("defines the width of the mini image for " \
142                                   "further processing (64 is default)")
143
144 #define HEIGHT_TEXT            N_("Extracted Image Height")
145 #define HEIGHT_LONGTEXT        N_("defines the height of the mini image for " \
146                                   "further processing (48 is default)")
147
148 #define PCOLOR_TEXT            N_("use Pause Color")
149 #define PCOLOR_LONGTEXT        N_("use the color defined below if the user " \
150                           "paused the video.(have light to get another beer?)")
151 #define PCOLOR_RED_TEXT        N_("Pause-Red")
152 #define PCOLOR_RED_LONGTEXT    N_("the red component of pause color")
153 #define PCOLOR_GREEN_TEXT      N_("Pause-Green")
154 #define PCOLOR_GREEN_LONGTEXT  N_("the green component of pause color")
155 #define PCOLOR_BLUE_TEXT       N_("Pause-Blue")
156 #define PCOLOR_BLUE_LONGTEXT   N_("the blue component of pause color")
157 #define FADESTEPS_TEXT         N_("Pause-Fadesteps")
158 #define FADESTEPS_LONGTEXT     N_("Number of steps to change current color " \
159                                   "to pause color (each step takes 40ms)")
160
161 #define ECOLOR_RED_TEXT        N_("End-Red")
162 #define ECOLOR_RED_LONGTEXT    N_("the red component of the shutdown color")
163 #define ECOLOR_GREEN_TEXT      N_("End-Green")
164 #define ECOLOR_GREEN_LONGTEXT  N_("the green component of the shutdown color")
165 #define ECOLOR_BLUE_TEXT       N_("End-Blue")
166 #define ECOLOR_BLUE_LONGTEXT   N_("the blue component of the shutdown color")
167 #define EFADESTEPS_TEXT        N_("End-Fadesteps")
168 #define EFADESTEPS_LONGTEXT  N_("Number of steps to change current color to " \
169                              "end color for dimming up the light in cinema " \
170                              "style... (each step takes 40ms)")
171
172 #define USEWHITEADJ_TEXT       N_("Use Software White adjust")
173 #define USEWHITEADJ_LONGTEXT   N_("Should the buildin driver do a white " \
174                                   "adjust or you LED stripes? recommend.")
175 #define WHITE_RED_TEXT         N_("White Red")
176 #define WHITE_RED_LONGTEXT     N_("Red value of a pure white on your "\
177                                   "LED stripes.")
178 #define WHITE_GREEN_TEXT       N_("White Green")
179 #define WHITE_GREEN_LONGTEXT   N_("Green value of a pure white on your "\
180                                   "LED stripes.")
181 #define WHITE_BLUE_TEXT        N_("White Blue")
182 #define WHITE_BLUE_LONGTEXT    N_("Blue value of a pure white on your "\
183                                   "LED stripes.")
184
185 #define SERIALDEV_TEXT         N_("Serial Port/Device")
186 #define SERIALDEV_LONGTEXT   N_("Name of the serial port where the AtmoLight "\
187                        "controller is attached to\n on Windows usually "\
188                        "something like COM1 or COM2 on Linux /dev/ttyS01 f.e.")
189
190 #define EDGE_TEXT            N_("Edge Weightning")
191 #define EDGE_LONGTEXT        N_("increasing this value will result in color "\
192                                 "more depending on the border of the frame")
193 #define BRIGHTNESS_TEXT     N_("Brightness")
194 #define BRIGHTNESS_LONGTEXT N_("overall Brightness of you LED stripes")
195 #define DARKNESS_TEXT       N_("Darkness Limit")
196 #define DARKNESS_LONGTEXT   N_("pixels with a saturation lower than this will "\
197                                "be ignored should be greater than one for "\
198                                "letterboxed videos")
199 #define HUEWINSIZE_TEXT     N_("Hue windowing")
200 #define HUEWINSIZE_LONGTEXT N_("used for statistics")
201 #define SATWINSIZE_TEXT     N_("Sat windowing")
202 #define SATWINSIZE_LONGTEXT N_("used for statistics")
203
204 #define MEANLENGTH_TEXT     N_("Filter length (ms)")
205 #define MEANLENGTH_LONGTEXT N_("Time it takes until a color is complete "\
206                                 "changed, removes flickering")
207 #define MEANTHRESHOLD_TEXT     N_("Filter threshold")
208 #define MEANTHRESHOLD_LONGTEXT N_("How much a color must changed, for an "\
209                                   "imediate color change")
210 #define MEANPERCENTNEW_TEXT     N_("Filter Smoothness %")
211 #define MEANPERCENTNEW_LONGTEXT N_("Filter Smoothness")
212
213 #define FILTERMODE_TEXT        N_("Filtermode")
214 #define FILTERMODE_LONGTEXT    N_("kind of filtering which should be use to "\
215                                   "calcuate the color output")
216 static int pi_filtermode_values[] = {
217        (int)afmNoFilter,
218        (int)afmCombined,
219        (int)afmPercent
220 };
221 static const char *ppsz_filtermode_descriptions[] = {
222         N_("No Filtering"),
223         N_("Combined"),
224         N_("Percent")
225 };
226
227 #define FRAMEDELAY_TEXT       N_("Framedelay")
228 #define FRAMEDELAY_LONGTEXT   N_("helps to get video out and light effects "\
229                              "insync values around 20ms should do the trick")
230
231
232 #define CHANNEL_0_ASSIGN_TEXT N_("Channel summary")
233 #define CHANNEL_1_ASSIGN_TEXT N_("Channel left")
234 #define CHANNEL_2_ASSIGN_TEXT N_("Channel right")
235 #define CHANNEL_3_ASSIGN_TEXT N_("Channel top")
236 #define CHANNEL_4_ASSIGN_TEXT N_("Channel bottom")
237
238 #define CHANNELASSIGN_LONGTEXT N_("maps the hardware channel X to logical "\
239                                   "channel Y to fix wrong wiring:-)")
240 static int pi_channel_assignment_values[] = {
241     -1,
242      0,
243      1,
244      2,
245      3,
246      4
247 };
248 static const char *ppsz_channel_assignment_descriptions[] = {
249         N_("disabled"),
250         N_("summary"),
251         N_("left"),
252         N_("right"),
253         N_("top"),
254         N_("bottom")
255 };
256
257 #define ZONE_0_GRADIENT_TEXT N_("summary gradient")
258 #define ZONE_1_GRADIENT_TEXT N_("left gradient")
259 #define ZONE_2_GRADIENT_TEXT N_("right gradient")
260 #define ZONE_3_GRADIENT_TEXT N_("top gradient")
261 #define ZONE_4_GRADIENT_TEXT N_("bottom gradient")
262 #define ZONE_X_GRADIENT_LONG_TEXT N_("defines a small bitmap with 64x48 "\
263                                      "pixels, containing a grayscale gradient")
264
265 #if defined( WIN32 )
266 #   define ATMOWINEXE_TEXT      N_("Filename of AtmoWinA.exe")
267 #   define ATMOWINEXE_LONGTEXT  N_("if you wan't that the AtmoLight control "\
268                                    "software is launched by\nVLC enter the "\
269                                    "complete Filename of AtmoWinA.exe here")
270 #   define USEBUILDIN_TEXT      N_("Use buildin AtmoLight")
271 #   define USEBUILDIN_LONGTEXT N_("VideoLan will directly use your AtmoLight "\
272                                   "hardware without running the external "\
273                                   "AtmoWinA.exe Userspace driver.")
274 #endif
275
276 #define CFG_PREFIX "atmo-"
277
278 /*****************************************************************************
279 * Module descriptor
280 *****************************************************************************/
281 vlc_module_begin();
282 set_description( N_("AtmoLight Filter") );
283 set_help( MODULE_DESCRIPTION );
284 set_shortname( N_( "AtmoLight" ));
285 set_capability( "video filter2", 0 );
286
287 set_category( CAT_VIDEO );
288 set_subcategory( SUBCAT_VIDEO_VFILTER );
289
290 #if defined(WIN32)
291 set_section( N_("Choose between the buildin AtmoLight "\
292                  "driver or the external" ), 0 );
293
294 /*
295     only on win32 exists the option to use the buildin driver or
296     the more flexible external driver application
297 */
298 add_bool(CFG_PREFIX "usebuildin", true, NULL,
299          USEBUILDIN_TEXT, USEBUILDIN_LONGTEXT, false);
300 add_string(CFG_PREFIX "serialdev", "COM1", NULL,
301            SERIALDEV_TEXT, SERIALDEV_LONGTEXT, false );
302
303 /*
304     on win32 the executeable external driver application
305     for automatic start if needed
306 */
307 add_file(CFG_PREFIX "atmowinexe", NULL, NULL,
308          ATMOWINEXE_TEXT, ATMOWINEXE_LONGTEXT, false );
309 #else
310 set_section( N_("Enter connection of your AtmoLight hardware" ), 0 );
311 add_string(CFG_PREFIX "serialdev", "/dev/ttyS01", NULL,
312            SERIALDEV_TEXT, SERIALDEV_LONGTEXT, false );
313 #endif
314
315 /*
316     color which is showed if you want durring pausing
317     your movie ... used for both buildin / external
318 */
319 set_section( N_("Illuminate the room with this color on pause" ), 0 );
320 add_bool(CFG_PREFIX "usepausecolor", false, NULL,
321          PCOLOR_TEXT, PCOLOR_LONGTEXT, false);
322 add_integer_with_range(CFG_PREFIX "pcolor-red",   0, 0, 255, NULL,
323                        PCOLOR_RED_TEXT, PCOLOR_RED_LONGTEXT, false);
324 add_integer_with_range(CFG_PREFIX "pcolor-green", 0, 0, 255, NULL,
325                        PCOLOR_GREEN_TEXT, PCOLOR_GREEN_LONGTEXT, false);
326 add_integer_with_range(CFG_PREFIX "pcolor-blue",  192, 0, 255, NULL,
327                        PCOLOR_BLUE_TEXT, PCOLOR_BLUE_LONGTEXT, false);
328 add_integer_with_range(CFG_PREFIX "fadesteps", 50, 1, 250, NULL,
329                        FADESTEPS_TEXT, FADESTEPS_LONGTEXT, false);
330
331 /*
332     color which is showed if you finished watching your movie ...
333     used for both buildin / external
334 */
335 set_section( N_("Illuminate the room with this color on shutdown" ), 0 );
336 add_integer_with_range(CFG_PREFIX "ecolor-red",   192, 0, 255, NULL,
337                        ECOLOR_RED_TEXT,   ECOLOR_RED_LONGTEXT,   false);
338 add_integer_with_range(CFG_PREFIX "ecolor-green", 192, 0, 255, NULL,
339                        ECOLOR_GREEN_TEXT, ECOLOR_GREEN_LONGTEXT, false);
340 add_integer_with_range(CFG_PREFIX "ecolor-blue",  192, 0, 255, NULL,
341                        ECOLOR_BLUE_TEXT,  ECOLOR_BLUE_LONGTEXT,  false);
342 add_integer_with_range(CFG_PREFIX "efadesteps",    50, 1, 250, NULL,
343                        EFADESTEPS_TEXT,   EFADESTEPS_LONGTEXT,    false);
344
345 /*
346  settings only for the buildin driver (if external driver app is used
347  these parameters are ignored.)
348
349  definition of parameters for the buildin filter ...
350 */
351 set_section( N_("Settings only for buildin Live Video Processor" ), 0 );
352
353 add_integer_with_range(CFG_PREFIX "EdgeWeightning",   8, 1, 30, NULL,
354                        EDGE_TEXT, EDGE_LONGTEXT, false);
355
356 add_integer_with_range(CFG_PREFIX "Brightness",   100, 50, 300, NULL,
357                        BRIGHTNESS_TEXT, BRIGHTNESS_LONGTEXT, false);
358
359 add_integer_with_range(CFG_PREFIX "DarknessLimit",   5, 0, 10, NULL,
360                        DARKNESS_TEXT, DARKNESS_LONGTEXT, false);
361
362 add_integer_with_range(CFG_PREFIX "HueWinSize",   3, 0, 5, NULL,
363                        HUEWINSIZE_TEXT, HUEWINSIZE_LONGTEXT, false);
364
365 add_integer_with_range(CFG_PREFIX "SatWinSize",   3, 0, 5, NULL,
366                        SATWINSIZE_TEXT, SATWINSIZE_LONGTEXT, false);
367
368 add_integer(CFG_PREFIX "filtermode", (int)afmCombined, NULL,
369             FILTERMODE_TEXT, FILTERMODE_LONGTEXT, false );
370
371 change_integer_list(pi_filtermode_values, ppsz_filtermode_descriptions, 0 );
372
373 add_integer_with_range(CFG_PREFIX "MeanLength",    300, 300, 5000, NULL,
374                        MEANLENGTH_TEXT, MEANLENGTH_LONGTEXT, false);
375
376 add_integer_with_range(CFG_PREFIX "MeanThreshold",  40, 1, 100, NULL,
377                        MEANTHRESHOLD_TEXT, MEANTHRESHOLD_LONGTEXT, false);
378
379 add_integer_with_range(CFG_PREFIX "PercentNew", 50, 1, 100, NULL,
380                       MEANPERCENTNEW_TEXT, MEANPERCENTNEW_LONGTEXT, false);
381
382 add_integer_with_range(CFG_PREFIX "FrameDelay", 18, 0, 35, NULL,
383                        FRAMEDELAY_TEXT, FRAMEDELAY_LONGTEXT, false);
384
385 /*
386   output channel reordering
387 */
388 set_section( N_("Change channel assignment (fixes wrong wiring)" ), 0 );
389 add_integer( CFG_PREFIX "channel_0", 0, NULL,
390             CHANNEL_0_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false );
391 change_integer_list( pi_channel_assignment_values,
392                      ppsz_channel_assignment_descriptions, 0 );
393
394 add_integer( CFG_PREFIX "channel_1", 1, NULL,
395             CHANNEL_1_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false );
396 change_integer_list( pi_channel_assignment_values,
397                      ppsz_channel_assignment_descriptions, 0 );
398
399 add_integer( CFG_PREFIX "channel_2", 2, NULL,
400             CHANNEL_2_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false );
401 change_integer_list( pi_channel_assignment_values,
402                      ppsz_channel_assignment_descriptions, 0 );
403
404 add_integer( CFG_PREFIX "channel_3", 3, NULL,
405             CHANNEL_3_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false );
406 change_integer_list( pi_channel_assignment_values,
407                      ppsz_channel_assignment_descriptions, 0 );
408
409 add_integer( CFG_PREFIX "channel_4", 4, NULL,
410             CHANNEL_4_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false );
411 change_integer_list( pi_channel_assignment_values,
412                      ppsz_channel_assignment_descriptions, 0 );
413
414 /*
415   LED color white calibration
416 */
417 set_section( N_("Adjust the white light to your LED stripes" ), 0 );
418 add_bool(CFG_PREFIX "whiteadj", true, NULL,
419          USEWHITEADJ_TEXT, USEWHITEADJ_LONGTEXT, false);
420 add_integer_with_range(CFG_PREFIX "white-red",   255, 0, 255, NULL,
421                        WHITE_RED_TEXT,   WHITE_RED_LONGTEXT,   false);
422
423 add_integer_with_range(CFG_PREFIX "white-green", 255, 0, 255, NULL,
424                        WHITE_GREEN_TEXT, WHITE_GREEN_LONGTEXT, false);
425
426 add_integer_with_range(CFG_PREFIX "white-blue",  255, 0, 255, NULL,
427                        WHITE_BLUE_TEXT,  WHITE_BLUE_LONGTEXT,  false);
428 /* end of definition of parameter for the buildin filter ... part 1 */
429
430
431 /*
432 only for buildin (external has own definition) per default the calucation
433 used linear gradients for assigning a priority to the pixel - depending
434 how near they are to the border ...for changing this you can create 64x48
435 Pixel BMP files - which contain your own grayscale... (you can produce funny
436 effects with this...) the images MUST not compressed, should have 24-bit per
437 pixel, or a simple 256 color grayscale palette
438 */
439 set_section( N_("Change gradients" ), 0 );
440 add_file(CFG_PREFIX "gradient_zone_0", NULL, NULL,
441          ZONE_0_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true );
442 add_file(CFG_PREFIX "gradient_zone_1", NULL, NULL,
443          ZONE_1_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true );
444 add_file(CFG_PREFIX "gradient_zone_2", NULL, NULL,
445          ZONE_2_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true );
446 add_file(CFG_PREFIX "gradient_zone_3", NULL, NULL,
447          ZONE_3_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true );
448 add_file(CFG_PREFIX "gradient_zone_4", NULL, NULL,
449          ZONE_4_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true );
450
451
452 #if defined(__ATMO_DEBUG__)
453 add_bool(CFG_PREFIX "saveframes", false, NULL,
454          SAVEFRAMES_TEXT, SAVEFRAMES_LONGTEXT, false);
455 add_string(CFG_PREFIX "framepath", "", NULL,
456            FRAMEPATH_TEXT, FRAMEPATH_LONGTEXT, false );
457 #endif
458 /*
459    may be later if computers gets more power ;-) than now we increase
460    the samplesize from which we do the stats for output color calculation
461 */
462 add_integer_with_range(CFG_PREFIX "width",  64, 64, 512, NULL,
463                        WIDTH_TEXT,  WIDTH_LONGTEXT, true);
464 add_integer_with_range(CFG_PREFIX "height", 48, 48, 384, NULL,
465                        HEIGHT_TEXT,  HEIGHT_LONGTEXT, true);
466
467 add_shortcut( "atmo" );
468 set_callbacks( CreateFilter, DestroyFilter  );
469 vlc_module_end();
470
471
472 static const char *const ppsz_filter_options[] = {
473 #if defined(WIN32)
474         "usebuildin",
475 #endif
476         "serialdev",
477
478
479         "EdgeWeightning",
480         "Brightness",
481         "DarknessLimit",
482         "HueWinSize",
483         "SatWinSize",
484
485         "filtermode",
486
487         "MeanLength",
488         "MeanThreshold",
489         "PercentNew",
490         "FrameDelay",
491
492         "channel_0",
493         "channel_1",
494         "channel_2",
495         "channel_3",
496         "channel_4",
497
498         "whiteadj",
499         "white-red",
500         "white-green",
501         "white-blue",
502
503         "usepausecolor",
504         "pcolor-red",
505         "pcolor-green",
506         "pcolor-blue",
507         "fadesteps",
508
509         "ecolor-red",
510         "ecolor-green",
511         "ecolor-blue",
512         "efadesteps",
513
514
515 #if defined(WIN32 )
516         "usebuildin",
517         "atmowinexe",
518 #endif
519 #if defined(__ATMO_DEBUG__)
520         "saveframes" ,
521         "framepath",
522 #endif
523         "width",
524         "height",
525         "gradient_zone_0",
526         "gradient_zone_1",
527         "gradient_zone_2",
528         "gradient_zone_3",
529         "gradient_zone_4",
530         NULL
531 };
532
533
534 /*****************************************************************************
535 * fadethread_t: Color Fading Thread
536 *****************************************************************************
537 * changes slowly the color of the output if videostream gets paused...
538 *****************************************************************************
539 */
540 typedef struct
541 {
542     VLC_COMMON_MEMBERS
543         filter_t *p_filter;
544     /* tell the thread which color should be the target of fading */
545     uint8_t ui_red;
546     uint8_t ui_green;
547     uint8_t ui_blue;
548     /* how many steps should happen until this */
549     int i_steps;
550
551 } fadethread_t;
552
553 static void FadeToColorThread(fadethread_t *p_fadethread);
554
555
556 /*****************************************************************************
557 * filter_sys_t: AtmoLight filter method descriptor
558 *****************************************************************************
559 * It describes the AtmoLight specific properties of an video filter.
560 *****************************************************************************/
561 struct filter_sys_t
562 {
563     /*
564     special for the access of the p_fadethread member all other members
565     need no special protection so far!
566     */
567     vlc_mutex_t filter_lock;
568
569     bool b_enabled;
570     int32_t i_AtmoOldEffect;
571     bool b_pause_live;
572
573     int32_t i_atmo_width;
574     int32_t i_atmo_height;
575
576 #if defined(__ATMO_DEBUG__)
577     bool  b_saveframes;
578     int i_framecounter;
579     char sz_framepath[MAX_PATH];
580 #endif
581
582     /* light color durring movie pause ... */
583     bool  b_usepausecolor;
584     uint8_t ui_pausecolor_red;
585     uint8_t ui_pausecolor_green;
586     uint8_t ui_pausecolor_blue;
587     int i_fadesteps;
588
589     /* light color on movie finish ... */
590     uint8_t ui_endcolor_red;
591     uint8_t ui_endcolor_green;
592     uint8_t ui_endcolor_blue;
593     int i_endfadesteps;
594
595     fadethread_t *p_fadethread;
596
597     /* Variables for buildin driver only... */
598
599     /* is only present and initialized if the internal driver is used*/
600     CAtmoConfig *p_atmo_config;
601     /* storage for temporal settings "volatile" */
602     CAtmoDynData *p_atmo_dyndata;
603     /* initialized for buildin driver with AtmoCreateTransferBuffers */
604     BITMAPINFOHEADER mini_image_format;
605     /* is only use buildin driver! */
606     uint8_t *p_atmo_transfer_buffer;
607     /* end buildin driver */
608
609     /*
610     contains the real output size of the video calculated on
611     change event of the variable "crop" from vout
612     */
613     int32_t i_crop_x_offset;
614     int32_t i_crop_y_offset;
615     int32_t i_crop_width;
616     int32_t i_crop_height;
617
618     void (*pf_extract_mini_image) (filter_sys_t *p_sys,
619         picture_t *p_inpic,
620         uint8_t *p_transfer_dest);
621
622 #if defined( WIN32 )
623     /* External Library as wrapper arround COM Stuff */
624     HINSTANCE h_AtmoCtrl;
625     int32_t (*pf_ctrl_atmo_initialize) (void);
626     void (*pf_ctrl_atmo_finalize) (int32_t what);
627     int32_t (*pf_ctrl_atmo_switch_effect) (int32_t);
628     int32_t (*pf_ctrl_atmo_set_live_source) (int32_t);
629     void (*pf_ctrl_atmo_create_transfer_buffers) (int32_t, int32_t,
630                                                   int32_t , int32_t);
631     uint8_t* (*pf_ctrl_atmo_lock_transfer_buffer) (void);
632     void (*pf_ctrl_atmo_send_pixel_data) (void);
633 #endif
634 };
635
636 /*
637 initialize previously configured Atmo Light environment
638 - if internal is enabled try to access the device on the serial port
639 - if not internal is enabled and we are on win32 try to initialize
640 the previously loaded DLL ...
641
642 Return Values may be: -1 (failed for some reason - filter will be disabled)
643 1 Ok. lets rock
644 */
645 static int32_t AtmoInitialize(filter_t *p_filter, bool b_for_thread)
646 {
647     filter_sys_t *p_sys = p_filter->p_sys;
648     if(p_sys->p_atmo_config)
649     {
650         if(b_for_thread == false)
651         {
652             /* open com port */
653             /* setup Output Threads ... */
654             msg_Dbg( p_filter, "open serial connection %s",
655                 p_sys->p_atmo_config->getSerialDevice());
656
657             if(CAtmoTools::RecreateConnection(p_sys->p_atmo_dyndata) == ATMO_TRUE)
658             {
659                 msg_Dbg( p_filter, "start live view thread ...");
660                 CAtmoTools::SwitchEffect(p_sys->p_atmo_dyndata, emLivePicture);
661                 msg_Dbg( p_filter, "live view thread launched...");
662                 return 1;
663
664             } else {
665                 msg_Err( p_filter,"failed to open serial device? some other software/driver may use it?");
666             }
667         }
668 #if defined(WIN32)
669     } else if(p_sys->pf_ctrl_atmo_initialize)
670     {
671         /* on win32 with active ctrl dll */
672         return p_sys->pf_ctrl_atmo_initialize();
673 #endif
674     }
675     return -1;
676 }
677
678 /*
679 prepare the shutdown of the effect threads,
680 for build in filter - close the serialport after finishing the threads...
681 cleanup possible loaded DLL...
682 */
683 static void AtmoFinalize(filter_t *p_filter, int32_t what)
684 {
685     filter_sys_t *p_sys = p_filter->p_sys;
686     if(p_sys->p_atmo_config)
687     {
688         if(what == 1)
689         {
690             CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
691             if(p_atmo_dyndata)
692             {
693                 p_atmo_dyndata->LockCriticalSection();
694
695                 CThread *p_effect_thread = p_atmo_dyndata->getEffectThread();
696                 p_atmo_dyndata->setEffectThread(NULL);
697                 if(p_effect_thread != NULL)
698                 {
699                     /*
700                     forced the thread to die...
701                     and wait for termination of the thread
702                     */
703                     p_effect_thread->Terminate();
704                     delete p_effect_thread;
705                     msg_Dbg( p_filter, "effect thread died peacefully");
706                 }
707
708                 /*
709                 close serial port if it is open (all OS specific is inside
710                 CAtmoSerialConnection implemented / defined)
711                 */
712                 CAtmoConnection *p_atmo_connection =
713                                  p_atmo_dyndata->getAtmoConnection();
714                 p_atmo_dyndata->setAtmoConnection(NULL);
715                 if(p_atmo_connection) {
716                     p_atmo_connection->CloseConnection();
717                     delete p_atmo_connection;
718                 }
719                 p_atmo_dyndata->UnLockCriticalSection();
720             }
721         }
722 #if defined(WIN32)
723     } else if(p_sys->pf_ctrl_atmo_finalize)
724     {
725         /* on win32 with active ctrl dll */
726         p_sys->pf_ctrl_atmo_finalize(what);
727 #endif
728     }
729 }
730
731 /*
732 switch the current light effect - does only something on win32, with the
733 external  libraries - if the buildin effects are used nothing happens
734 */
735 static int32_t AtmoSwitchEffect(filter_t *p_filter, int32_t newMode)
736 {
737     filter_sys_t *p_sys = p_filter->p_sys;
738     if(p_sys->p_atmo_config)
739     {
740         /*
741         buildin driver
742
743         doesnt know different modes for effects so this
744         function call would just do nothing special
745         in this case
746         */
747
748 #if defined(WIN32)
749     } else if(p_sys->pf_ctrl_atmo_switch_effect)
750     {
751         /* on win32 with active ctrl dll */
752         return p_sys->pf_ctrl_atmo_switch_effect(newMode);
753 #endif
754     }
755     return emDisabled;
756 }
757
758 /*
759 set the current live picture source, does only something on win32,
760 with the external libraries - if the buildin effects are used nothing
761 happens...
762 */
763 static int32_t AtmoSetLiveSource(filter_t *p_filter, int32_t newSource)
764 {
765     filter_sys_t *p_sys = p_filter->p_sys;
766     if(p_sys->p_atmo_config)
767     {
768         /*
769         buildin driver
770
771         doesnt know different sources so this
772         function call would just do nothing special
773         in this case
774         */
775 #if defined(WIN32)
776     } else if(p_sys->pf_ctrl_atmo_set_live_source)
777     {
778         /* on win32 with active ctrl dll */
779         return p_sys->pf_ctrl_atmo_set_live_source(newSource);
780 #endif
781     }
782     return lvsGDI;
783 }
784
785 /*
786 setup the pixel transferbuffers which is used to transfer pixeldata from
787 the filter to the effect thread, and possible accross the process
788 boundaries on win32, with the external DLL
789 */
790 static void AtmoCreateTransferBuffers(filter_t *p_filter,
791                                       int32_t FourCC,
792                                       int32_t bytePerPixel,
793                                       int32_t width,
794                                       int32_t height)
795 {
796     filter_sys_t *p_sys = p_filter->p_sys;
797     if(p_sys->p_atmo_config)
798     {
799         /*
800         we need a buffer where the image is stored (only for transfer
801         to the processing thread)
802         */
803         if(p_sys->p_atmo_transfer_buffer)
804             free(p_sys->p_atmo_transfer_buffer);
805
806         p_sys->p_atmo_transfer_buffer = (uint8_t *)malloc(bytePerPixel *
807                                                           width *  height);
808
809         memset(&p_sys->mini_image_format,0,sizeof(BITMAPINFOHEADER));
810
811         p_sys->mini_image_format.biSize = sizeof(BITMAPINFOHEADER);
812         p_sys->mini_image_format.biWidth = width;
813         p_sys->mini_image_format.biHeight = height;
814         p_sys->mini_image_format.biBitCount = bytePerPixel*8;
815         p_sys->mini_image_format.biCompression = FourCC;
816
817 #if defined(WIN32)
818     } else if(p_sys->pf_ctrl_atmo_create_transfer_buffers)
819     {
820         /* on win32 with active ctrl dll */
821         p_sys->pf_ctrl_atmo_create_transfer_buffers(FourCC,
822             bytePerPixel,
823             width,
824             height);
825 #endif
826     }
827 }
828
829 /*
830 acquire the transfer buffer pointer the buildin version only
831 returns the pointer to the allocated buffer ... the
832 external version on win32 has to do some COM stuff to lock the
833 Variant Byte array which is behind the buffer
834 */
835 static uint8_t* AtmoLockTransferBuffer(filter_t *p_filter)
836 {
837     filter_sys_t *p_sys = p_filter->p_sys;
838     if(p_sys->p_atmo_config)
839     {
840         return p_sys->p_atmo_transfer_buffer;
841 #if defined(WIN32)
842     } else if(p_sys->pf_ctrl_atmo_lock_transfer_buffer)
843     {
844         /* on win32 with active ctrl dll */
845         return p_sys->pf_ctrl_atmo_lock_transfer_buffer();
846 #endif
847     }
848     return NULL;
849 }
850
851 /*
852 send the content of current pixel buffer got with AtmoLockTransferBuffer
853 to the processing threads
854 - build in version - will forward the data to AtmoExternalCaptureInput Thread
855 - win32 external - will do the same, but across the process boundaries via
856 COM to the AtmoWinA.exe Process
857 */
858 static void AtmoSendPixelData(filter_t *p_filter)
859 {
860     filter_sys_t *p_sys = p_filter->p_sys;
861     if(p_sys->p_atmo_config && p_sys->p_atmo_transfer_buffer)
862     {
863         CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
864         if(p_atmo_dyndata)
865         {
866             /*
867             the cast will go Ok because we are inside videolan there is only
868             this kind of effect thread implemented!
869             */
870
871             CAtmoLiveView *p_atmo_live_view_thread =
872                 (CAtmoLiveView *)p_atmo_dyndata->getEffectThread();
873             if(p_atmo_live_view_thread)
874             {
875                 /*
876                 the same as above inside videolan only this single kind of
877                 input exists so we can cast without further tests!
878                 */
879                 CAtmoExternalCaptureInput *p_atmo_external_capture_input_thread =
880                     (CAtmoExternalCaptureInput *)p_atmo_live_view_thread->getAtmoInput();
881                 if(p_atmo_external_capture_input_thread)
882                 {
883                     /*
884                     this call will do a 1:1 copy of this buffer, and wakeup
885                     the thread from normal sleeping
886                     */
887                     p_atmo_external_capture_input_thread->
888                         DeliverNewSourceDataPaket(&p_sys->mini_image_format,
889                         p_sys->p_atmo_transfer_buffer);
890                 }
891             }
892         }
893 #if defined(WIN32)
894     } else if(p_sys->pf_ctrl_atmo_send_pixel_data)
895     {
896         /* on win32 with active ctrl dll */
897         p_sys->pf_ctrl_atmo_send_pixel_data();
898 #endif
899     }
900 }
901
902 /*
903     Shutdown AtmoLight finally - is call from DestroyFilter
904     does the cleanup restores the effectmode on the external Software
905     (only win32) and possible setup the final light ...
906 */
907 static void Atmo_Shutdown(filter_t *p_filter)
908 {
909     filter_sys_t *p_sys = p_filter->p_sys;
910
911     if(p_sys->b_enabled == true)
912     {
913         /*
914         if there is a still running show pause color thread kill him!
915         */
916         CheckAndStopFadeThread(p_filter);
917
918         if(p_sys->p_atmo_config || (p_sys->i_AtmoOldEffect == emStaticColor))
919         {
920             /*
921             fade to end color (in case of external AtmoWin Software
922             assume that the static color will equal to this
923             one to get a soft change and no flash!
924             */
925             p_sys->b_pause_live = true;
926
927             // perpare spawn fadeing thread
928             vlc_mutex_lock( &p_sys->filter_lock );
929
930             p_sys->p_fadethread = (fadethread_t *)vlc_object_create( p_filter,
931                                                         sizeof(fadethread_t) );
932
933             p_sys->p_fadethread->p_filter = p_filter;
934             p_sys->p_fadethread->ui_red   = p_sys->ui_endcolor_red;
935             p_sys->p_fadethread->ui_green = p_sys->ui_endcolor_green;
936             p_sys->p_fadethread->ui_blue  = p_sys->ui_endcolor_blue;
937             p_sys->p_fadethread->i_steps  = p_sys->i_endfadesteps;
938
939             if( vlc_thread_create( p_sys->p_fadethread,
940                 "AtmoLight fadeing",
941                 FadeToColorThread,
942                 VLC_THREAD_PRIORITY_LOW,
943                 false ) )
944             {
945                 msg_Err( p_filter, "cannot create FadeToColorThread" );
946                 vlc_object_release( p_sys->p_fadethread );
947                 p_sys->p_fadethread = NULL;
948                 vlc_mutex_unlock( &p_sys->filter_lock );
949
950             } else {
951
952                 vlc_mutex_unlock( &p_sys->filter_lock );
953
954                 /* wait for the thread... */
955                 vlc_thread_join(p_sys->p_fadethread);
956
957                 vlc_object_release(p_sys->p_fadethread);
958
959                 p_sys->p_fadethread = NULL;
960             }
961         }
962
963         if(p_sys->i_AtmoOldEffect != emLivePicture)
964             AtmoSwitchEffect(p_filter, p_sys->i_AtmoOldEffect);
965         else
966             AtmoSetLiveSource(p_filter, lvsGDI);
967
968         AtmoFinalize(p_filter, 1);
969
970         /* disable filter method .. */
971         p_sys->b_enabled = false;
972     }
973 }
974
975 /*
976 initialize the filter_sys_t structure with the data from the settings
977 variables - if the external filter on win32 is enabled try loading the DLL,
978 if this fails fallback to the buildin software
979 */
980 static void Atmo_SetupParameters(filter_t *p_filter)
981 {
982     bool b_use_buildin_driver = true;
983     char *psz_path;
984     filter_sys_t *p_sys =  p_filter->p_sys;
985
986
987     /* default filter disabled until DLL loaded and Init Success!*/
988     p_sys->b_enabled             = false;
989
990     /* setup default mini image size (may be later a user option) */
991     p_sys->i_atmo_width          = 64;
992     p_sys->i_atmo_height         = 48;
993
994
995     vlc_mutex_init( &p_sys->filter_lock );
996
997
998 #if defined(WIN32)
999     /*
1000     only on WIN32 the user has the choice between
1001     internal driver and external
1002     */
1003     b_use_buildin_driver = var_CreateGetBoolCommand( p_filter,
1004         CFG_PREFIX "usebuildin" );
1005
1006     if(b_use_buildin_driver == false) {
1007
1008         /* Load the Com Wrapper Library (source available) */
1009         p_sys->h_AtmoCtrl = LoadLibraryA("AtmoCtrlLib.dll");
1010         if(p_sys->h_AtmoCtrl != NULL)
1011         {
1012             msg_Dbg( p_filter, "LoadLibrary('AtmoCtrlLib.dll'); Success");
1013
1014             /* importing all required functions I hope*/
1015             p_sys->pf_ctrl_atmo_initialize =
1016                 (int32_t (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoInitialize");
1017             if(!p_sys->pf_ctrl_atmo_initialize)
1018                 msg_Err( p_filter, "export AtmoInitialize missing.");
1019
1020             p_sys->pf_ctrl_atmo_finalize =
1021                 (void (*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoFinalize");
1022             if(!p_sys->pf_ctrl_atmo_finalize)
1023                 msg_Err( p_filter, "export AtmoFinalize missing.");
1024
1025             p_sys->pf_ctrl_atmo_switch_effect =
1026                 (int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoSwitchEffect");
1027             if(!p_sys->pf_ctrl_atmo_switch_effect)
1028                 msg_Err( p_filter, "export AtmoSwitchEffect missing.");
1029
1030             p_sys->pf_ctrl_atmo_set_live_source =
1031                 (int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoSetLiveSource");
1032             if(!p_sys->pf_ctrl_atmo_set_live_source)
1033                 msg_Err( p_filter, "export AtmoSetLiveSource missing.");
1034
1035             p_sys->pf_ctrl_atmo_create_transfer_buffers =
1036                 (void (*)(int32_t, int32_t, int32_t , int32_t))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoCreateTransferBuffers");
1037             if(!p_sys->pf_ctrl_atmo_create_transfer_buffers)
1038                 msg_Err( p_filter, "export AtmoCreateTransferBuffers missing.");
1039
1040             p_sys->pf_ctrl_atmo_lock_transfer_buffer=
1041                 (uint8_t*(*) (void))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoLockTransferBuffer");
1042             if(!p_sys->pf_ctrl_atmo_lock_transfer_buffer)
1043                 msg_Err( p_filter, "export AtmoLockTransferBuffer missing.");
1044
1045             p_sys->pf_ctrl_atmo_send_pixel_data =
1046                 (void (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoSendPixelData");
1047             if(!p_sys->pf_ctrl_atmo_send_pixel_data)
1048                 msg_Err( p_filter, "export AtmoSendPixelData missing.");
1049         } else {
1050             /* the DLL is missing try internal filter ...*/
1051             msg_Warn( p_filter, "AtmoCtrlLib.dll missing fallback to internal driver");
1052             b_use_buildin_driver = true;
1053         }
1054     }
1055 #endif
1056
1057
1058     if(b_use_buildin_driver == true) {
1059         msg_Dbg( p_filter, "use buildin driver");
1060         /*
1061         now we have to read a lof of options from the config dialog
1062         most important the serial device if not set ... we can skip
1063         the rest and disable the filter...
1064         */
1065         char *psz_serialdev = var_CreateGetStringCommand( p_filter,
1066                                                       CFG_PREFIX "serialdev" );
1067         if(psz_serialdev && (strlen(psz_serialdev)>0)) {
1068             msg_Dbg( p_filter, "use buildin driver on port %s",psz_serialdev);
1069
1070             p_sys->p_atmo_config = new CAtmoConfig();
1071
1072             p_sys->p_atmo_config->setSerialDevice(psz_serialdev);
1073
1074             p_sys->p_atmo_config->setLiveViewFilterMode(
1075                 (AtmoFilterMode)var_CreateGetIntegerCommand( p_filter,
1076                                                        CFG_PREFIX "filtermode")
1077                 );
1078
1079             p_sys->p_atmo_config->setLiveViewFilter_PercentNew(
1080                 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "PercentNew")
1081                 );
1082             p_sys->p_atmo_config->setLiveViewFilter_MeanLength(
1083                 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "MeanLength")
1084                 );
1085             p_sys->p_atmo_config->setLiveViewFilter_MeanThreshold(
1086                 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "MeanThreshold")
1087                 );
1088
1089             p_sys->p_atmo_config->setLiveView_EdgeWeighting(
1090                 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "EdgeWeightning")
1091                 );
1092             p_sys->p_atmo_config->setLiveView_BrightCorrect(
1093                 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "Brightness")
1094                 );
1095             p_sys->p_atmo_config->setLiveView_DarknessLimit(
1096                 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "DarknessLimit")
1097                 );
1098             p_sys->p_atmo_config->setLiveView_HueWinSize(
1099                 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "HueWinSize")
1100                 );
1101             p_sys->p_atmo_config->setLiveView_SatWinSize(
1102                 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "SatWinSize")
1103                 );
1104
1105             /* currently not required inside vlc */
1106             p_sys->p_atmo_config->setLiveView_WidescreenMode( 0 );
1107
1108             p_sys->p_atmo_config->setLiveView_FrameDelay(
1109                 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "FrameDelay")
1110                 );
1111
1112
1113             p_sys->p_atmo_config->setUseSoftwareWhiteAdj(
1114                 var_CreateGetBoolCommand( p_filter, CFG_PREFIX "whiteadj")
1115                 );
1116             p_sys->p_atmo_config->setWhiteAdjustment_Red(
1117                 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-red")
1118                 );
1119             p_sys->p_atmo_config->setWhiteAdjustment_Green(
1120                 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-green")
1121                 );
1122             p_sys->p_atmo_config->setWhiteAdjustment_Blue(
1123                 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-blue")
1124                 );
1125
1126             tChannelAssignment *p_channel_assignment =
1127                                  p_sys->p_atmo_config->getChannelAssignment(0);
1128
1129             p_channel_assignment->mappings[0] = var_CreateGetIntegerCommand(
1130                                              p_filter, CFG_PREFIX "channel_0");
1131
1132             p_channel_assignment->mappings[1] = var_CreateGetIntegerCommand(
1133                                              p_filter, CFG_PREFIX "channel_1");
1134
1135             p_channel_assignment->mappings[2] = var_CreateGetIntegerCommand(
1136                                              p_filter, CFG_PREFIX "channel_2");
1137
1138             p_channel_assignment->mappings[3] = var_CreateGetIntegerCommand(
1139                                              p_filter, CFG_PREFIX "channel_3");
1140
1141             p_channel_assignment->mappings[4] = var_CreateGetIntegerCommand(
1142                                              p_filter, CFG_PREFIX "channel_4");
1143
1144             for(int i=0;i<ATMO_NUM_CHANNELS;i++)
1145                 msg_Dbg( p_filter, "map software channel %d to hardware channel %d",
1146                 p_channel_assignment->mappings[i],
1147                 i
1148                 );
1149
1150             // gradient_zone_0
1151             char psz_gradient_var_name[30];
1152             char *psz_gradient_file;
1153             for(int i=0;i<ATMO_NUM_CHANNELS;i++)
1154             {
1155                 sprintf(psz_gradient_var_name, CFG_PREFIX "gradient_zone_%d", i);
1156                 psz_gradient_file = var_CreateGetStringCommand(
1157                     p_filter,
1158                     psz_gradient_var_name
1159                     );
1160                 if(psz_gradient_file && strlen(psz_gradient_file)>0)
1161                 {
1162                     msg_Dbg( p_filter, "loading gradientfile %s for "\
1163                                        "zone %d", psz_gradient_file, i);
1164
1165                     int i_res = p_sys->p_atmo_config->getZoneDefinition(i)->
1166                                 LoadGradientFromBitmap(psz_gradient_file);
1167
1168                     if(i_res != ATMO_LOAD_GRADIENT_OK)
1169                     {
1170                         msg_Err( p_filter,"failed to load gradient '%s' with "\
1171                                           "error %d",psz_gradient_file,i_res);
1172                     }
1173                 }
1174                 delete psz_gradient_file;
1175             }
1176
1177             p_sys->p_atmo_dyndata = new CAtmoDynData((vlc_object_t *)p_filter,
1178                 p_sys->p_atmo_config
1179                 );
1180
1181             msg_Dbg( p_filter, "buildin driver initialized");
1182
1183             free(psz_serialdev);
1184         } else {
1185             msg_Err(p_filter,"no serial devicename set");
1186         }
1187     }
1188
1189     switch( p_filter->fmt_in.video.i_chroma )
1190     {
1191     case VLC_FOURCC('I','4','2','0'):
1192     case VLC_FOURCC('I','Y','U','V'):
1193     case VLC_FOURCC('Y','V','1','2'):
1194     case VLC_FOURCC('Y','V','1','6'):
1195     case VLC_FOURCC('Y','V','U','9'):
1196         // simple enough? Dionoea?
1197         p_sys->pf_extract_mini_image = ExtractMiniImage_YUV;
1198         break;
1199     default:
1200         msg_Dbg( p_filter, "InitFilter-unsupported chroma: %4.4s",
1201                             (char *)&p_filter->fmt_in.video.i_chroma);
1202         p_sys->pf_extract_mini_image = NULL;
1203     }
1204
1205     p_sys->i_crop_x_offset  = 0;
1206     p_sys->i_crop_y_offset  = 0;
1207     p_sys->i_crop_width     = p_filter->fmt_in.video.i_visible_width;
1208     p_sys->i_crop_height    = p_filter->fmt_in.video.i_visible_height;
1209
1210     msg_Dbg( p_filter, "set default crop %d,%d %dx%d",p_sys->i_crop_x_offset,
1211         p_sys->i_crop_y_offset,
1212         p_sys->i_crop_width,
1213         p_sys->i_crop_height );
1214
1215
1216 #if defined(__ATMO_DEBUG__)
1217     /* save debug images to a folder as Bitmap files ? */
1218     p_sys->b_saveframes  = var_CreateGetBoolCommand( p_filter,
1219         CFG_PREFIX "saveframes"
1220         );
1221     msg_Dbg(p_filter,"saveframes = %d", (int)p_sys->b_saveframes);
1222
1223     /*
1224     read debug image folder from config
1225     */
1226     psz_path = var_CreateGetStringCommand( p_filter, CFG_PREFIX "framepath" );
1227     if(psz_path != NULL)
1228     {
1229         strcpy(p_sys->sz_framepath, psz_path);
1230 #if defined( WIN32 )
1231         size_t i_strlen = strlen(p_sys->sz_framepath);
1232         if((i_strlen>0) && (p_sys->sz_framepath[i_strlen-1] != '\\'))
1233         {
1234             p_sys->sz_framepath[i_strlen] = '\\';
1235             p_sys->sz_framepath[i_strlen+1] = 0;
1236         }
1237 #endif
1238         free(psz_path);
1239     }
1240     msg_Dbg(p_filter,"saveframesfolder %s",p_sys->sz_framepath);
1241 #endif
1242
1243     /*
1244        size of extracted image by default 64x48 (other imagesizes are
1245        currently ignored by AtmoWin)
1246     */
1247     p_sys->i_atmo_width  = var_CreateGetIntegerCommand( p_filter,
1248         CFG_PREFIX "width");
1249     p_sys->i_atmo_height = var_CreateGetIntegerCommand( p_filter,
1250         CFG_PREFIX "height");
1251     msg_Dbg(p_filter,"mini image size %d * %d pixels", p_sys->i_atmo_width,
1252         p_sys->i_atmo_height);
1253
1254     /*
1255     because atmowin could also be used for lighten up the room - I think if you
1256     pause the video it would be useful to get a little bit more light into to
1257     your living room? - instead switching on a lamp?
1258     */
1259     p_sys->b_usepausecolor = var_CreateGetBoolCommand( p_filter,
1260         CFG_PREFIX "usepausecolor" );
1261     p_sys->ui_pausecolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1262         CFG_PREFIX "pcolor-red");
1263     p_sys->ui_pausecolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1264         CFG_PREFIX "pcolor-green");
1265     p_sys->ui_pausecolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1266         CFG_PREFIX "pcolor-blue");
1267     p_sys->i_fadesteps = var_CreateGetIntegerCommand( p_filter,
1268         CFG_PREFIX "fadesteps");
1269     if(p_sys->i_fadesteps < 1)
1270         p_sys->i_fadesteps = 1;
1271     msg_Dbg(p_filter,"use pause color %d, RGB: %d, %d, %d, Fadesteps: %d",
1272         (int)p_sys->b_usepausecolor,
1273         p_sys->ui_pausecolor_red,
1274         p_sys->ui_pausecolor_green,
1275         p_sys->ui_pausecolor_blue,
1276         p_sys->i_fadesteps);
1277
1278     /*
1279     this color is use on shutdown of the filter - the define the
1280     final light after playback... may be used to dim up the light -
1281     how it happens in the cinema...
1282     */
1283     p_sys->ui_endcolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1284         CFG_PREFIX "ecolor-red");
1285     p_sys->ui_endcolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1286         CFG_PREFIX "ecolor-green");
1287     p_sys->ui_endcolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1288         CFG_PREFIX "ecolor-blue");
1289     p_sys->i_endfadesteps = var_CreateGetIntegerCommand( p_filter,
1290         CFG_PREFIX "efadesteps");
1291     if(p_sys->i_endfadesteps < 1)
1292         p_sys->i_endfadesteps = 1;
1293     msg_Dbg(p_filter,"use ende color RGB: %d, %d, %d, Fadesteps: %d",
1294         p_sys->ui_endcolor_red,
1295         p_sys->ui_endcolor_green,
1296         p_sys->ui_endcolor_blue,
1297         p_sys->i_endfadesteps);
1298
1299     /* if the external DLL was loaded successfully call AtmoInitialize -
1300     (must be done for each thread where you wan't to use AtmoLight!
1301     */
1302     int i = AtmoInitialize(p_filter, false);
1303 #if defined( WIN32 )
1304     if((i != 1) && !b_use_buildin_driver)
1305     {
1306         /* COM Server for AtmoLight not running ?
1307         if the exe path is configured try to start the "userspace" driver
1308         */
1309         psz_path = var_CreateGetStringCommand( p_filter,
1310                                                CFG_PREFIX "atmowinexe" );
1311         if(psz_path != NULL)
1312         {
1313             STARTUPINFO startupinfo;
1314             PROCESS_INFORMATION pinfo;
1315             memset(&startupinfo, 0, sizeof(STARTUPINFO));
1316             startupinfo.cb = sizeof(STARTUPINFO);
1317             if(CreateProcess(psz_path, NULL, NULL, NULL,
1318                 FALSE, 0, NULL, NULL, &startupinfo, &pinfo) == TRUE)
1319             {
1320                 msg_Dbg(p_filter,"launched AtmoWin from %s",psz_path);
1321                 WaitForInputIdle(pinfo.hProcess, 5000);
1322                 /*
1323                 retry to initialize the library COM ... functionality
1324                 after the server was launched
1325                 */
1326                 i = AtmoInitialize(p_filter, false);
1327             } else {
1328                 msg_Err(p_filter,"failed to launch AtmoWin from %s", psz_path);
1329             }
1330             free(psz_path);
1331         }
1332     }
1333 #endif
1334
1335     if(i == 1) /* Init Atmolight success... */
1336     {
1337         msg_Dbg( p_filter, "AtmoInitialize Ok!");
1338
1339         /* Setup Transferbuffers for 64 x 48 , RGB with 32bit Per Pixel */
1340         AtmoCreateTransferBuffers(p_filter, BI_RGB, 4,
1341             p_sys->i_atmo_width,
1342             p_sys->i_atmo_height
1343             );
1344
1345         /* say the userspace driver that a live mode should be activated
1346         the functions returns the old mode for later restore!
1347         */
1348         p_sys->i_AtmoOldEffect = AtmoSwitchEffect(p_filter, emLivePicture);
1349
1350         /*
1351         live view can have two differnt source the AtmoWinA
1352         internal GDI Screencapture and the external one - which we
1353         need here...
1354         */
1355         AtmoSetLiveSource(p_filter, lvsExternal);
1356
1357         /* enable other parts only if everything is fine */
1358         p_sys->b_enabled = true;
1359     }
1360
1361 }
1362
1363
1364 /*****************************************************************************
1365 * CreateFilter: allocates AtmoLight video thread output method
1366 *****************************************************************************
1367 * This function allocates and initializes a AtmoLight vout method.
1368 *****************************************************************************/
1369 static int CreateFilter( vlc_object_t *p_this )
1370 {
1371     filter_t *p_filter = (filter_t *)p_this;
1372     filter_sys_t *p_sys;
1373
1374     /* Allocate structure */
1375     p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) );
1376     p_filter->p_sys = p_sys;
1377     if( p_filter->p_sys == NULL )
1378         return VLC_ENOMEM;
1379     /* set all entries to zero */
1380     memset(p_sys, 0, sizeof( filter_sys_t ));
1381
1382     /* further Setup Function pointers for videolan for calling my filter */
1383     p_filter->pf_video_filter = Filter;
1384
1385     config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
1386                        p_filter->p_cfg );
1387
1388     AddStateVariableCallback(p_filter);
1389
1390     AddCropVariableCallback(p_filter);
1391
1392     AddAtmoSettingsVariablesCallbacks(p_filter);
1393
1394     Atmo_SetupParameters(p_filter);
1395
1396
1397     return VLC_SUCCESS;
1398 }
1399
1400
1401
1402 /*****************************************************************************
1403 * DestroyFilter: destroy AtmoLight video thread output method
1404 *****************************************************************************
1405 * Terminate an output method created by CreateFilter
1406 *****************************************************************************/
1407
1408 static void DestroyFilter( vlc_object_t *p_this )
1409 {
1410     filter_t *p_filter = (filter_t *)p_this;
1411     filter_sys_t *p_sys =  p_filter->p_sys;
1412
1413     DelStateVariableCallback(p_filter);
1414     DelCropVariableCallback(p_filter);
1415     DelAtmoSettingsVariablesCallbacks(p_filter);
1416
1417     Atmo_Shutdown(p_filter);
1418
1419 #if defined( WIN32 )
1420     if(p_sys->h_AtmoCtrl != NULL)
1421     {
1422         FreeLibrary(p_sys->h_AtmoCtrl);
1423     }
1424 #endif
1425
1426     delete p_sys->p_atmo_dyndata;
1427     delete p_sys->p_atmo_config;
1428
1429     vlc_mutex_destroy( &p_sys->filter_lock );
1430
1431     free( p_sys );
1432 }
1433
1434
1435 /*
1436 function stolen from some other videolan source filter ;-)
1437 for the moment RGB is OK... but better would be a direct transformation
1438 from YUV --> HSV
1439 */
1440 static inline void yuv_to_rgb( uint8_t *r, uint8_t *g, uint8_t *b,
1441                               uint8_t y1, uint8_t u1, uint8_t v1 )
1442 {
1443     /* macros used for YUV pixel conversions */
1444 #   define SCALEBITS 10
1445 #   define ONE_HALF  (1 << (SCALEBITS - 1))
1446 #   define FIX(x)    ((int) ((x) * (1<<SCALEBITS) + 0.5))
1447 #   define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
1448
1449     int y, cb, cr, r_add, g_add, b_add;
1450
1451     cb = u1 - 128;
1452     cr = v1 - 128;
1453     r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
1454     g_add = - FIX(0.34414*255.0/224.0) * cb
1455         - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
1456     b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
1457     y = (y1 - 16) * FIX(255.0/219.0);
1458     *r = CLAMP((y + r_add) >> SCALEBITS);
1459     *g = CLAMP((y + g_add) >> SCALEBITS);
1460     *b = CLAMP((y + b_add) >> SCALEBITS);
1461 }
1462 /******************************************************************************
1463 * ExtractMiniImage_YUV: extract a small image from the picture as 24-bit RGB
1464 *******************************************************************************
1465 * p_sys is a pointer to
1466 * p_inpic is the source frame
1467 * p_transfer_dest is the target buffer for the picture must be big enough!
1468 * (in win32 enviroment this buffer comes from the external DLL where it is
1469 * create as "variant array" and returned through the AtmoLockTransferbuffer
1470 */
1471 static void ExtractMiniImage_YUV(filter_sys_t *p_sys,
1472                                  picture_t *p_inpic,
1473                                  uint8_t *p_transfer_dest)
1474 {
1475     int i_col;
1476     int i_row;
1477     uint8_t *p_src_y;
1478     uint8_t *p_src_u;
1479     uint8_t *p_src_v;
1480     uint8_t *p_rgb_dst_line_red;
1481     uint8_t *p_rgb_dst_line_green;
1482     uint8_t *p_rgb_dst_line_blue;
1483     int i_xpos_y;
1484     int i_xpos_u;
1485     int i_xpos_v;
1486
1487     /* calcute Pointers for Storage of B G R (A) */
1488     p_rgb_dst_line_blue      = p_transfer_dest;
1489     p_rgb_dst_line_green     = p_transfer_dest + 1;
1490     p_rgb_dst_line_red       = p_transfer_dest + 2 ;
1491
1492     int i_row_count = p_sys->i_atmo_height + 1;
1493     int i_col_count = p_sys->i_atmo_width + 1;
1494     int i_y_row,i_u_row,i_v_row,i_pixel_row;
1495     int i_pixel_col;
1496
1497
1498     /*  these two ugly loops extract the small image - goes it faster? how?
1499     the loops are so designed that there is a small border around the extracted
1500     image so we wont get column and row - zero from the frame, and not the most
1501     right and bottom pixels --- which may be clipped on computers useing TV out
1502     - through overscan!
1503
1504     TODO: try to find out if the output is clipped through VLC - and try here
1505     to ingore the clipped away area for a better result!
1506
1507     TODO: performance improvement in InitFilter percalculated the offsets of
1508     the lines inside the planes so I can save (i_row_count * 3) 2xMUL and
1509     one time DIV the same could be done for the inner loop I think...
1510     */
1511     for(i_row = 1; i_row < i_row_count; i_row++)
1512     {
1513         // calcute the current Lines in the source planes for this outputrow
1514         /*  Adresscalcuation  pointer to plane  Length of one pixelrow in bytes
1515         calculate row now number
1516         */
1517         /*
1518            p_inpic->format? transform Pixel row into row of plane...
1519            how? simple? fast? good?
1520         */
1521
1522         /* compute the source pixel row and respect the active cropping */
1523         i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
1524             + p_sys->i_crop_y_offset;
1525
1526         /*
1527         trans for these Pixel row into the row of each plane ..
1528         because planesize can differ from image size
1529         */
1530         i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
1531             p_inpic->format.i_visible_height;
1532
1533         i_u_row = (i_pixel_row * p_inpic->p[U_PLANE].i_visible_lines) /
1534             p_inpic->format.i_visible_height;
1535
1536         i_v_row = (i_pixel_row * p_inpic->p[V_PLANE].i_visible_lines) /
1537             p_inpic->format.i_visible_height;
1538
1539         /* calculate  the pointers to the pixeldata for this row
1540            in each plane
1541         */
1542         p_src_y = p_inpic->p[Y_PLANE].p_pixels +
1543             p_inpic->p[Y_PLANE].i_pitch * i_y_row;
1544         p_src_u = p_inpic->p[U_PLANE].p_pixels +
1545             p_inpic->p[U_PLANE].i_pitch * i_u_row;
1546         p_src_v = p_inpic->p[V_PLANE].p_pixels +
1547             p_inpic->p[V_PLANE].i_pitch * i_v_row;
1548
1549         for(i_col = 1; i_col < i_col_count; i_col++)
1550         {
1551             i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
1552                 p_sys->i_crop_x_offset;
1553             /*
1554             trans for these Pixel row into the row of each plane ..
1555             because planesize can differ from image size
1556             */
1557             i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
1558                 p_inpic->format.i_visible_width;
1559             i_xpos_u = (i_pixel_col * p_inpic->p[U_PLANE].i_visible_pitch) /
1560                 p_inpic->format.i_visible_width;
1561             i_xpos_v = (i_pixel_col * p_inpic->p[V_PLANE].i_visible_pitch) /
1562                 p_inpic->format.i_visible_width;
1563
1564             yuv_to_rgb(p_rgb_dst_line_red,
1565                 p_rgb_dst_line_green,
1566                 p_rgb_dst_line_blue,
1567
1568                 p_src_y[i_xpos_y],
1569                 p_src_u[i_xpos_u],
1570                 p_src_v[i_xpos_v]);
1571
1572             /* +4 because output image should be RGB32 with dword alignment! */
1573             p_rgb_dst_line_red   += 4;
1574             p_rgb_dst_line_green += 4;
1575             p_rgb_dst_line_blue  += 4;
1576         }
1577     }
1578 }
1579
1580
1581 /******************************************************************************
1582 * SaveBitmap: Saves the content of a transferbuffer as Bitmap to disk
1583 *******************************************************************************
1584 * just for debugging
1585 * p_sys -> configuration if Atmo from there the function will get height and
1586 *          width
1587 * p_pixels -> should be the dword aligned BGR(A) image data
1588 * psz_filename -> filename where to store
1589 */
1590 #if defined(__ATMO_DEBUG__)
1591 void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename)
1592 {
1593     /* for debug out only used*/
1594     BITMAPINFO bmp_info;
1595     BITMAPFILEHEADER  bmp_fileheader;
1596     FILE *fp_bitmap;
1597
1598     memset(&bmp_info, 0, sizeof(BITMAPINFO));
1599     bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1600     bmp_info.bmiHeader.biSizeImage   = p_sys->i_atmo_height *
1601                                        p_sys->i_atmo_width * 4;
1602     bmp_info.bmiHeader.biCompression = BI_RGB;
1603     bmp_info.bmiHeader.biWidth        = p_sys->i_atmo_width;
1604     bmp_info.bmiHeader.biHeight       = -p_sys->i_atmo_height;
1605     bmp_info.bmiHeader.biBitCount     = 32;
1606     bmp_info.bmiHeader.biPlanes       = 1;
1607
1608     bmp_fileheader.bfReserved1 = 0;
1609     bmp_fileheader.bfReserved2 = 0;
1610     bmp_fileheader.bfSize = sizeof(BITMAPFILEHEADER) +
1611                             sizeof(BITMAPINFOHEADER) +
1612                             bmp_info.bmiHeader.biSizeImage;
1613     bmp_fileheader.bfType = VLC_TWOCC('M','B');
1614     bmp_fileheader.bfOffBits = sizeof(BITMAPFILEHEADER) +
1615                                sizeof(BITMAPINFOHEADER);
1616
1617     fp_bitmap = fopen(psz_filename,"wb");
1618     if( fp_bitmap != NULL)
1619     {
1620         fwrite(&bmp_fileheader, sizeof(BITMAPFILEHEADER), 1, fp_bitmap);
1621         fwrite(&bmp_info.bmiHeader, sizeof(BITMAPINFOHEADER), 1, fp_bitmap);
1622         fwrite(p_pixels, bmp_info.bmiHeader.biSizeImage, 1, fp_bitmap);
1623         fclose(fp_bitmap);
1624     }
1625 }
1626 #endif
1627
1628
1629 /****************************************************************************
1630 * CreateMiniImage: extracts a 64x48 pixel image from the frame
1631 * (there is a small border arround thats why the loops starts with one
1632 * instead zero) without any interpolation
1633 *****************************************************************************/
1634 static void CreateMiniImage( filter_t *p_filter, picture_t *p_inpic)
1635 {
1636     filter_sys_t *p_sys = p_filter->p_sys;
1637     /*
1638     pointer to RGB Buffer created in external libary as safe array which
1639     is locked inside AtmoLockTransferBuffer
1640     */
1641     uint8_t *p_transfer = NULL;
1642 #if defined( __ATMO_DEBUG__ )
1643     /* for debug out only used*/
1644     char sz_filename[MAX_PATH];
1645 #endif
1646
1647     /*
1648     Lock the before created VarArray (AtmoCreateTransferBuffers)
1649     inside my wrapper library and give me a pointer to the buffer!
1650     below linux a global buffer may be used and protected with a mutex?
1651     */
1652     p_transfer = AtmoLockTransferBuffer(p_filter);
1653     if(p_transfer == NULL)
1654     {
1655         msg_Err( p_filter, "AtmoLight no transferbuffer available. "\
1656                            "AtmoLight will be disabled!");
1657         p_sys->b_enabled = false;
1658         return;
1659     }
1660
1661     /*
1662     do the call via pointer to function instead of having a
1663     case structure here
1664     */
1665     p_sys->pf_extract_mini_image(p_sys, p_inpic, p_transfer);
1666
1667
1668 #if defined( __ATMO_DEBUG__ )
1669     /*
1670     if debugging enabled save every 128th image to disk
1671     */
1672     if((p_sys->b_saveframes == true) && (p_sys->sz_framepath[0] != 0 ))
1673     {
1674
1675         if((p_sys->i_framecounter & 127) == 0)
1676         {
1677             sprintf(sz_filename,"%satmo_dbg_%06d.bmp",p_sys->sz_framepath,
1678                 p_sys->i_framecounter);
1679             msg_Dbg(p_filter, "SaveFrame %s",sz_filename);
1680
1681             SaveBitmap(p_sys, p_transfer, sz_filename);
1682         }
1683         p_sys->i_framecounter++;
1684     }
1685 #endif
1686
1687     /* show the colors on the wall */
1688     AtmoSendPixelData(p_filter);
1689 }
1690
1691
1692
1693
1694 /*****************************************************************************
1695 * Filter: calls the extract method and forwards the incomming picture 1:1
1696 *****************************************************************************
1697 *
1698 *****************************************************************************/
1699
1700 static picture_t * Filter( filter_t *p_filter, picture_t *p_pic )
1701 {
1702     filter_sys_t *p_sys = p_filter->p_sys;
1703     if( !p_pic ) return NULL;
1704
1705     if((p_sys->b_enabled == true) &&
1706         (p_sys->pf_extract_mini_image != NULL) &&
1707         (p_sys->b_pause_live == false))
1708     {
1709         CreateMiniImage(p_filter, p_pic);
1710     }
1711
1712     return p_pic;
1713 }
1714
1715
1716 /*****************************************************************************
1717 * FadeToColorThread: Threadmethod which changes slowly the color
1718 * to a target color defined in p_fadethread struct
1719 * use for: Fade to Pause Color,  and Fade to End Color
1720 *****************************************************************************/
1721 static void FadeToColorThread(fadethread_t *p_fadethread)
1722 {
1723     filter_sys_t *p_sys = (filter_sys_t *)p_fadethread->p_filter->p_sys;
1724     int i_steps_done = 0;
1725     int i_index;
1726     int i_pause_red;
1727     int i_pause_green;
1728     int i_pause_blue;
1729
1730     int i_src_red;
1731     int i_src_green;
1732     int i_src_blue;
1733
1734     vlc_thread_ready( p_fadethread );
1735
1736     uint8_t *p_source = NULL;
1737
1738     /* initialize AtmoWin for this thread! */
1739     AtmoInitialize(p_fadethread->p_filter , true);
1740
1741     uint8_t *p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
1742     if(p_transfer != NULL) {
1743         /* safe colors as "32bit" Integers to avoid overflows*/
1744         i_pause_red   = p_fadethread->ui_red;
1745         i_pause_blue  = p_fadethread->ui_blue;
1746         i_pause_green = p_fadethread->ui_green;
1747
1748         /*
1749         allocate a temporary buffer for the last send
1750         image size less then 15kb
1751         */
1752         int i_size = 4 * p_sys->i_atmo_width * p_sys->i_atmo_height;
1753         p_source = (uint8_t *)malloc( i_size );
1754         if(p_source != NULL)
1755         {
1756             /*
1757             get a copy of the last transfered image as orign for the
1758             fading steps...
1759             */
1760             memcpy(p_source, p_transfer, i_size);
1761             /* send the same pixel data again... to unlock the buffer! */
1762             AtmoSendPixelData( p_fadethread->p_filter );
1763
1764             while( (!p_fadethread->b_die) &&
1765                 (i_steps_done < p_fadethread->i_steps))
1766             {
1767                 p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
1768                 if(!p_transfer) break; /* should not happen if it worked
1769                                        one time in the code above! */
1770                 i_steps_done++;
1771                 /*
1772                 move all pixels in the mini image (64x48) one step closer to
1773                 the desired color these loop takes the most time of this
1774                 thread improvements wellcome!
1775                 */
1776                 for(i_index = 0;
1777                     (i_index < i_size) && (!p_fadethread->b_die);
1778                     i_index+=4)
1779                 {
1780                     i_src_blue  = p_source[i_index+0];
1781                     i_src_green = p_source[i_index+1];
1782                     i_src_red   = p_source[i_index+2];
1783                     p_transfer[i_index+0] = (uint8_t) (((
1784                         (i_pause_blue  - i_src_blue)
1785                         * i_steps_done)/p_fadethread->i_steps)
1786                         + i_src_blue);
1787
1788                     p_transfer[i_index+1] = (uint8_t) (((
1789                         (i_pause_green - i_src_green)
1790                         * i_steps_done)/p_fadethread->i_steps)
1791                         + i_src_green);
1792
1793                     p_transfer[i_index+2] = (uint8_t) (((
1794                         (i_pause_red   - i_src_red)
1795                         * i_steps_done)/p_fadethread->i_steps)
1796                         + i_src_red);
1797                 }
1798
1799                 /* send image to lightcontroller */
1800                 AtmoSendPixelData( p_fadethread->p_filter );
1801                 /* is there something like and interruptable sleep inside
1802                 the VLC libaries? inside native win32 I would use an Event
1803                 (CreateEvent) and here an WaitForSingleObject?
1804                 */
1805                 if(p_fadethread->b_die) break;
1806                 msleep(10000);
1807                 if(p_fadethread->b_die) break;
1808                 msleep(10000);
1809                 if(p_fadethread->b_die) break;
1810                 msleep(10000);
1811                 if(p_fadethread->b_die) break;
1812                 msleep(10000);
1813             }
1814             free(p_source);
1815         } else {
1816             /* in failure of malloc also unlock buffer  */
1817             AtmoSendPixelData(p_fadethread->p_filter);
1818         }
1819     }
1820     /* call indirect to OleUnitialize() for this thread */
1821     AtmoFinalize(p_fadethread->p_filter, 0);
1822 }
1823
1824 /*****************************************************************************
1825 * CheckAndStopFadeThread: if there is a fadethread structure left, or running.
1826 ******************************************************************************
1827 * this function will stop the thread ... and waits for its termination
1828 * before removeing the objects from vout_sys_t ...
1829 ******************************************************************************/
1830 static void CheckAndStopFadeThread(filter_t *p_filter)
1831 {
1832     filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
1833     vlc_mutex_lock( &p_sys->filter_lock );
1834     if(p_sys->p_fadethread != NULL)
1835     {
1836         msg_Dbg(p_filter, "kill still running fadeing thread...");
1837
1838         p_sys->p_fadethread->b_die = true;
1839
1840         vlc_thread_join(p_sys->p_fadethread);
1841
1842         vlc_object_release(p_sys->p_fadethread);
1843         p_sys->p_fadethread = NULL;
1844     }
1845     vlc_mutex_unlock( &p_sys->filter_lock );
1846 }
1847
1848 /*****************************************************************************
1849 * StateCallback: Callback for the inputs variable "State" to get notified
1850 * about Pause and Continue Playback events.
1851 *****************************************************************************/
1852 static int StateCallback( vlc_object_t *p_this, char const *psz_cmd,
1853                          vlc_value_t oldval, vlc_value_t newval,
1854                          void *p_data )
1855 {
1856     filter_t *p_filter = (filter_t *)p_data;
1857     filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
1858
1859     if((p_sys->b_usepausecolor == true) && (p_sys->b_enabled == true))
1860     {
1861         msg_Dbg(p_filter, "state change from: %d to %d", oldval.i_int,
1862             newval.i_int);
1863
1864         if((newval.i_int == PAUSE_S) && (oldval.i_int == PLAYING_S))
1865         {
1866             /* tell the other thread to stop sending images to light
1867                controller */
1868             p_sys->b_pause_live = true;
1869
1870             // ggf. alten Thread abräumen should not happen....
1871             CheckAndStopFadeThread(p_filter);
1872
1873             // perpare spawn fadeing thread
1874             vlc_mutex_lock( &p_sys->filter_lock );
1875             /*
1876             launch only a new thread if there is none active!
1877             or waiting for cleanup
1878             */
1879             if(p_sys->p_fadethread == NULL)
1880             {
1881                 p_sys->p_fadethread = (fadethread_t *)vlc_object_create(
1882                      p_filter,
1883                      sizeof(fadethread_t) );
1884
1885                 p_sys->p_fadethread->p_filter = p_filter;
1886                 p_sys->p_fadethread->ui_red   = p_sys->ui_pausecolor_red;
1887                 p_sys->p_fadethread->ui_green = p_sys->ui_pausecolor_green;
1888                 p_sys->p_fadethread->ui_blue  = p_sys->ui_pausecolor_blue;
1889                 p_sys->p_fadethread->i_steps  = p_sys->i_fadesteps;
1890
1891                 if( vlc_thread_create( p_sys->p_fadethread,
1892                     "AtmoLight fadeing",
1893                     FadeToColorThread,
1894                     VLC_THREAD_PRIORITY_LOW,
1895                     false) )
1896                 {
1897                     msg_Err( p_filter, "cannot create FadeToColorThread" );
1898                     vlc_object_release( p_sys->p_fadethread );
1899                     p_sys->p_fadethread = NULL;
1900                 }
1901             }
1902             vlc_mutex_unlock( &p_sys->filter_lock );
1903         }
1904
1905         if((newval.i_int == PLAYING_S) && (oldval.i_int == PAUSE_S))
1906         {
1907             /* playback continues check thread state */
1908             CheckAndStopFadeThread(p_filter);
1909             /* reactivate the Render function... to do its normal work */
1910             p_sys->b_pause_live = false;
1911         }
1912     }
1913
1914     return VLC_SUCCESS;
1915 }
1916
1917 /*****************************************************************************
1918 * AddPlaylistInputThreadStateCallback: Setup call back on "State" Variable
1919 *****************************************************************************
1920 * Add Callback function to the "state" variable of the input thread..
1921 * first find the PlayList and get the input thread from there to attach
1922 * my callback? is vlc_object_find the right way for this??
1923 *****************************************************************************/
1924 static void AddStateVariableCallback(filter_t *p_filter)
1925 {
1926     playlist_t *p_playlist = pl_Yield( p_filter );
1927     input_thread_t *p_input = p_playlist->p_input;
1928     if(p_input)
1929     {
1930         var_AddCallback( p_input, "state", StateCallback, p_filter );
1931     }
1932     vlc_object_release( p_playlist );
1933 }
1934
1935 /*****************************************************************************
1936 * DelPlaylistInputThreadStateCallback: Remove call back on "State" Variable
1937 *****************************************************************************
1938 * Delete the callback function to the "state" variable of the input thread...
1939 * first find the PlayList and get the input thread from there to attach
1940 * my callback? is vlc_object_find the right way for this??
1941 *****************************************************************************/
1942 static void DelStateVariableCallback( filter_t *p_filter )
1943 {
1944     playlist_t *p_playlist = pl_Yield( p_filter );
1945     input_thread_t *p_input = p_playlist->p_input;
1946     if(p_input)
1947     {
1948         var_DelCallback( p_input, "state", StateCallback, p_filter );
1949     }
1950     vlc_object_release( p_playlist );
1951 }
1952
1953
1954 static int CropCallback(vlc_object_t *p_this, char const *psz_cmd,
1955                         vlc_value_t oldval, vlc_value_t newval,
1956                         void *p_data)
1957 {
1958     vout_thread_t *p_vout = (vout_thread_t *)p_this;
1959     filter_t *p_filter = (filter_t *)p_data;
1960     filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
1961
1962     /*
1963     //if the handler is attache to crop variable directly!
1964     int i_visible_width, i_visible_height, i_x_offset, i_y_offset;
1965     atmo_parse_crop(newval.psz_string, p_vout->fmt_render,
1966     p_vout->fmt_render,
1967     i_visible_width, i_visible_height,
1968     i_x_offset, i_y_offset);
1969     p_sys->i_crop_x_offset  = i_x_offset;
1970     p_sys->i_crop_y_offset  = i_y_offset;
1971     p_sys->i_crop_width     = i_visible_width;
1972     p_sys->i_crop_height    = i_visible_height;
1973     */
1974
1975     p_sys->i_crop_x_offset  = p_vout->fmt_in.i_x_offset;
1976     p_sys->i_crop_y_offset  = p_vout->fmt_in.i_y_offset;
1977     p_sys->i_crop_width     = p_vout->fmt_in.i_visible_width;
1978     p_sys->i_crop_height    = p_vout->fmt_in.i_visible_height;
1979
1980     msg_Dbg(p_filter, "cropping picture %ix%i to %i,%i,%ix%i",
1981         p_vout->fmt_in.i_width,
1982         p_vout->fmt_in.i_height,
1983         p_sys->i_crop_x_offset,
1984         p_sys->i_crop_y_offset,
1985         p_sys->i_crop_width,
1986         p_sys->i_crop_height
1987         );
1988
1989     return VLC_SUCCESS;
1990 }
1991
1992
1993 static void AddCropVariableCallback( filter_t *p_filter)
1994 {
1995     vout_thread_t *p_vout = (vout_thread_t *)vlc_object_find( p_filter,
1996         VLC_OBJECT_VOUT,
1997         FIND_ANYWHERE );
1998     if( p_vout )
1999     {
2000         var_AddCallback( p_vout, "crop-update", CropCallback, p_filter );
2001         vlc_object_release( p_vout );
2002     }
2003 }
2004
2005 static void DelCropVariableCallback( filter_t *p_filter)
2006 {
2007     vout_thread_t *p_vout = (vout_thread_t *)vlc_object_find( p_filter,
2008         VLC_OBJECT_VOUT,
2009         FIND_ANYWHERE );
2010     if( p_vout )
2011     {
2012         var_DelCallback( p_vout, "crop-update", CropCallback, p_filter );
2013         vlc_object_release( p_vout );
2014     }
2015 }
2016
2017
2018 /****************************************************************************
2019 * StateCallback: Callback for the inputs variable "State" to get notified
2020 * about Pause and Continue Playback events.
2021 *****************************************************************************/
2022 static int AtmoSettingsCallback( vlc_object_t *p_this, char const *psz_var,
2023                                  vlc_value_t oldval, vlc_value_t newval,
2024                                  void *p_data )
2025 {
2026     filter_t *p_filter = (filter_t *)p_data;
2027     filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2028
2029     CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
2030     if(p_atmo_config)
2031     {
2032
2033        msg_Dbg(p_filter, "apply AtmoSettingsCallback %s (int: %d -> %d)",
2034              psz_var,
2035              oldval.i_int,
2036              newval.i_int
2037        );
2038
2039         if( !strcmp( psz_var, CFG_PREFIX "filtermode" ))
2040             p_atmo_config->setLiveViewFilterMode( (AtmoFilterMode)newval.i_int);
2041
2042         else if( !strcmp( psz_var, CFG_PREFIX "PercentNew" ))
2043                  p_atmo_config->setLiveViewFilter_PercentNew( newval.i_int );
2044
2045         else if( !strcmp( psz_var, CFG_PREFIX "MeanLength" ))
2046                  p_atmo_config->setLiveViewFilter_MeanLength( newval.i_int );
2047
2048         else if( !strcmp( psz_var, CFG_PREFIX "MeanThreshold" ))
2049                  p_atmo_config->setLiveViewFilter_MeanThreshold( newval.i_int );
2050
2051         else if( !strcmp( psz_var, CFG_PREFIX "EdgeWeightning" ))
2052                  p_atmo_config->setLiveView_EdgeWeighting( newval.i_int );
2053
2054         else if( !strcmp( psz_var, CFG_PREFIX "Brightness" ))
2055                  p_atmo_config->setLiveView_BrightCorrect( newval.i_int );
2056
2057         else if( !strcmp( psz_var, CFG_PREFIX "DarknessLimit" ))
2058                  p_atmo_config->setLiveView_DarknessLimit( newval.i_int );
2059
2060         else if( !strcmp( psz_var, CFG_PREFIX "HueWinSize" ))
2061                  p_atmo_config->setLiveView_HueWinSize( newval.i_int );
2062
2063         else if( !strcmp( psz_var, CFG_PREFIX "SatWinSize" ))
2064                  p_atmo_config->setLiveView_SatWinSize( newval.i_int );
2065
2066         else if( !strcmp( psz_var, CFG_PREFIX "FrameDelay" ))
2067                  p_atmo_config->setLiveView_FrameDelay( newval.i_int );
2068
2069         else if( !strcmp( psz_var, CFG_PREFIX "whiteadj" ))
2070                  p_atmo_config->setUseSoftwareWhiteAdj( newval.b_bool );
2071
2072         else if( !strcmp( psz_var, CFG_PREFIX "white-red" ))
2073                  p_atmo_config->setWhiteAdjustment_Red( newval.i_int );
2074
2075         else if( !strcmp( psz_var, CFG_PREFIX "white-green" ))
2076                  p_atmo_config->setWhiteAdjustment_Green( newval.i_int );
2077
2078         else if( !strcmp( psz_var, CFG_PREFIX "white-blue" ))
2079                  p_atmo_config->setWhiteAdjustment_Blue( newval.i_int );
2080
2081     }
2082     return VLC_SUCCESS;
2083 }
2084
2085 static void AddAtmoSettingsVariablesCallbacks(filter_t *p_filter)
2086 {
2087    var_AddCallback( p_filter, CFG_PREFIX "filtermode",
2088                     AtmoSettingsCallback, p_filter );
2089    var_AddCallback( p_filter, CFG_PREFIX "PercentNew",
2090                     AtmoSettingsCallback, p_filter );
2091
2092
2093    var_AddCallback( p_filter, CFG_PREFIX "MeanLength",
2094                     AtmoSettingsCallback, p_filter );
2095    var_AddCallback( p_filter, CFG_PREFIX "MeanThreshold",
2096                     AtmoSettingsCallback, p_filter );
2097
2098    var_AddCallback( p_filter, CFG_PREFIX "EdgeWeightning",
2099                     AtmoSettingsCallback, p_filter );
2100    var_AddCallback( p_filter, CFG_PREFIX "Brightness",
2101                     AtmoSettingsCallback, p_filter );
2102    var_AddCallback( p_filter, CFG_PREFIX "DarknessLimit",
2103                     AtmoSettingsCallback, p_filter );
2104
2105    var_AddCallback( p_filter, CFG_PREFIX "HueWinSize",
2106                     AtmoSettingsCallback, p_filter );
2107    var_AddCallback( p_filter, CFG_PREFIX "SatWinSize",
2108                     AtmoSettingsCallback, p_filter );
2109    var_AddCallback( p_filter, CFG_PREFIX "FrameDelay",
2110                     AtmoSettingsCallback, p_filter );
2111
2112
2113    var_AddCallback( p_filter, CFG_PREFIX "whiteadj",
2114                     AtmoSettingsCallback, p_filter );
2115    var_AddCallback( p_filter, CFG_PREFIX "white-red",
2116                     AtmoSettingsCallback, p_filter );
2117    var_AddCallback( p_filter, CFG_PREFIX "white-green",
2118                     AtmoSettingsCallback, p_filter );
2119    var_AddCallback( p_filter, CFG_PREFIX "white-blue",
2120                     AtmoSettingsCallback, p_filter );
2121 }
2122
2123 static void DelAtmoSettingsVariablesCallbacks( filter_t *p_filter )
2124 {
2125
2126    var_DelCallback( p_filter, CFG_PREFIX "filtermode",
2127                     AtmoSettingsCallback, p_filter );
2128
2129    var_DelCallback( p_filter, CFG_PREFIX "PercentNew",
2130                     AtmoSettingsCallback, p_filter );
2131    var_DelCallback( p_filter, CFG_PREFIX "MeanLength",
2132                     AtmoSettingsCallback, p_filter );
2133    var_DelCallback( p_filter, CFG_PREFIX "MeanThreshold",
2134                     AtmoSettingsCallback, p_filter );
2135
2136    var_DelCallback( p_filter, CFG_PREFIX "EdgeWeightning",
2137                     AtmoSettingsCallback, p_filter );
2138    var_DelCallback( p_filter, CFG_PREFIX "Brightness",
2139                     AtmoSettingsCallback, p_filter );
2140    var_DelCallback( p_filter, CFG_PREFIX "DarknessLimit",
2141                     AtmoSettingsCallback, p_filter );
2142
2143    var_DelCallback( p_filter, CFG_PREFIX "HueWinSize",
2144                     AtmoSettingsCallback, p_filter );
2145    var_DelCallback( p_filter, CFG_PREFIX "SatWinSize",
2146                     AtmoSettingsCallback, p_filter );
2147    var_DelCallback( p_filter, CFG_PREFIX "FrameDelay",
2148                     AtmoSettingsCallback, p_filter );
2149
2150
2151    var_DelCallback( p_filter, CFG_PREFIX "whiteadj",
2152                     AtmoSettingsCallback, p_filter );
2153    var_DelCallback( p_filter, CFG_PREFIX "white-red",
2154                     AtmoSettingsCallback, p_filter );
2155    var_DelCallback( p_filter, CFG_PREFIX "white-green",
2156                     AtmoSettingsCallback, p_filter );
2157    var_DelCallback( p_filter, CFG_PREFIX "white-blue",
2158                     AtmoSettingsCallback, p_filter );
2159
2160 }
2161
2162
2163 #if defined(__ATMO_DEBUG__)
2164 static void atmo_parse_crop(char *psz_cropconfig,
2165                             video_format_t fmt_in,
2166                             video_format_t fmt_render,
2167                             int &i_visible_width, int &i_visible_height,
2168                             int &i_x_offset, int &i_y_offset )
2169 {
2170     int64_t i_aspect_num, i_aspect_den;
2171     unsigned int i_width, i_height;
2172
2173     i_visible_width  = fmt_in.i_visible_width;
2174     i_visible_height = fmt_in.i_visible_height;
2175     i_x_offset       = fmt_in.i_x_offset;
2176     i_y_offset       = fmt_in.i_y_offset;
2177
2178     char *psz_end = NULL, *psz_parser = strchr( psz_cropconfig, ':' );
2179     if( psz_parser )
2180     {
2181         /* We're using the 3:4 syntax */
2182         i_aspect_num = strtol( psz_cropconfig, &psz_end, 10 );
2183         if( psz_end == psz_cropconfig || !i_aspect_num ) return;
2184
2185         i_aspect_den = strtol( ++psz_parser, &psz_end, 10 );
2186         if( psz_end == psz_parser || !i_aspect_den ) return;
2187
2188         i_width = fmt_in.i_sar_den * fmt_render.i_visible_height *
2189             i_aspect_num / i_aspect_den / fmt_in.i_sar_num;
2190
2191         i_height = fmt_render.i_visible_width*fmt_in.i_sar_num *
2192             i_aspect_den / i_aspect_num / fmt_in.i_sar_den;
2193
2194         if( i_width < fmt_render.i_visible_width )
2195         {
2196             i_x_offset = fmt_render.i_x_offset +
2197                 (fmt_render.i_visible_width - i_width) / 2;
2198             i_visible_width = i_width;
2199         }
2200         else
2201         {
2202             i_y_offset = fmt_render.i_y_offset +
2203                 (fmt_render.i_visible_height - i_height) / 2;
2204             i_visible_height = i_height;
2205         }
2206     }
2207     else
2208     {
2209         psz_parser = strchr( psz_cropconfig, 'x' );
2210         if( psz_parser )
2211         {
2212             /* Maybe we're using the <width>x<height>+<left>+<top> syntax */
2213             unsigned int i_crop_width, i_crop_height, i_crop_top, i_crop_left;
2214
2215             i_crop_width = strtol( psz_cropconfig, &psz_end, 10 );
2216             if( psz_end != psz_parser ) return;
2217
2218             psz_parser = strchr( ++psz_end, '+' );
2219             i_crop_height = strtol( psz_end, &psz_end, 10 );
2220             if( psz_end != psz_parser ) return;
2221
2222             psz_parser = strchr( ++psz_end, '+' );
2223             i_crop_left = strtol( psz_end, &psz_end, 10 );
2224             if( psz_end != psz_parser ) return;
2225
2226             psz_end++;
2227             i_crop_top = strtol( psz_end, &psz_end, 10 );
2228             if( *psz_end != '\0' ) return;
2229
2230             i_width = i_crop_width;
2231             i_visible_width = i_width;
2232
2233             i_height = i_crop_height;
2234             i_visible_height = i_height;
2235
2236             i_x_offset = i_crop_left;
2237             i_y_offset = i_crop_top;
2238         }
2239         else
2240         {
2241             /* Maybe we're using the <left>+<top>+<right>+<bottom> syntax */
2242             unsigned int i_crop_top, i_crop_left, i_crop_bottom, i_crop_right;
2243
2244             psz_parser = strchr( psz_cropconfig, '+' );
2245             i_crop_left = strtol( psz_cropconfig, &psz_end, 10 );
2246             if( psz_end != psz_parser ) return;
2247
2248             psz_parser = strchr( ++psz_end, '+' );
2249             i_crop_top = strtol( psz_end, &psz_end, 10 );
2250             if( psz_end != psz_parser ) return;
2251
2252             psz_parser = strchr( ++psz_end, '+' );
2253             i_crop_right = strtol( psz_end, &psz_end, 10 );
2254             if( psz_end != psz_parser ) return;
2255
2256             psz_end++;
2257             i_crop_bottom = strtol( psz_end, &psz_end, 10 );
2258             if( *psz_end != '\0' ) return;
2259
2260             i_width = fmt_render.i_visible_width - i_crop_left - i_crop_right;
2261             i_visible_width = i_width;
2262
2263             i_height = fmt_render.i_visible_height - i_crop_top - i_crop_bottom;
2264             i_visible_height = i_height;
2265
2266             i_x_offset = i_crop_left;
2267             i_y_offset = i_crop_top;
2268         }
2269     }
2270 }
2271 #endif