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