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