1 /*****************************************************************************
2 * atmo.cpp : "Atmo Light" video filter
3 *****************************************************************************
4 * Copyright (C) 2000-2006 the VideoLAN team
7 * Authors: André Weber (WeberAndre@gmx.de)
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <stdlib.h> /* malloc(), free() */
29 #include <math.h> /* sin(), cos() */
36 // #define __ATMO_DEBUG__
39 #include <vlc_common.h>
40 #include <vlc_plugin.h>
43 #include <vlc_playlist.h>
44 #include <vlc_filter.h>
47 #include "AtmoDynData.h"
48 #include "AtmoLiveView.h"
49 #include "AtmoTools.h"
50 #include "AtmoExternalCaptureInput.h"
51 #include "AtmoConfig.h"
52 #include "AtmoConnection.h"
53 #include "AtmoClassicConnection.h"
56 /*****************************************************************************
58 *****************************************************************************/
59 /* directly to vlc related functions required that the module is accepted */
60 static int CreateFilter ( vlc_object_t * );
61 static void DestroyFilter ( vlc_object_t * );
62 static picture_t * Filter( filter_t *, picture_t *);
64 /* callback for global variable state pause / continue / stop events */
65 static void AddStateVariableCallback( filter_t *);
66 static void DelStateVariableCallback( filter_t *);
67 static int StateCallback(vlc_object_t *, char const *,
68 vlc_value_t, vlc_value_t, void *);
70 /* callback for atmo settings variables whose change
71 should be immediately realized and applied to output
73 static void DelAtmoSettingsVariablesCallbacks(filter_t *);
74 static void AddAtmoSettingsVariablesCallbacks(filter_t *);
75 static int AtmoSettingsCallback(vlc_object_t *, char const *,
76 vlc_value_t, vlc_value_t, void *);
79 #if defined(__ATMO_DEBUG__)
80 static void atmo_parse_crop(char *psz_cropconfig,
81 video_format_t fmt_in,
82 video_format_t fmt_render,
84 int &i_visible_height,
90 /* function to shutdown the fade thread which is started on pause*/
91 static void CheckAndStopFadeThread(filter_t *);
93 /* extracts a small RGB (BGR) Image from an YUV image */
94 static void ExtractMiniImage_YUV(filter_sys_t *, picture_t *, uint8_t *);
96 #if defined(__ATMO_DEBUG__)
97 void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename);
100 /*****************************************************************************
101 * External Prototypes for the AtmoCtrlLib.DLL
102 *****************************************************************************/
104 * if effectmode = emLivePicture then the source could be GDI (Screencapture)
105 * or External - this means another application delivers Pixeldata to AtmoWin
106 * Clientsoftware through AtmoCtrlLib.DLL and the COM Api
109 #define lvsExternal 1
111 #define CLASSIC_ATMO_NUM_ZONES 5
115 strings for settings menus and hints
117 #define MODULE_DESCRIPTION N_ ( \
118 "This module allows to control an so called AtmoLight device "\
119 "connected to your computer.\n"\
120 "AtmoLight is the homegrown version of what Philips calls AmbiLight.\n"\
121 "If you need further information feel free to visit us at\n\n"\
122 "http://www.vdr-wiki.de/wiki/index.php/Atmo-plugin\n"\
123 "http://www.vdr-wiki.de/wiki/index.php/AtmoWin\n\n"\
124 "You can find there detailed descriptions on how to build it for yourself "\
125 "and where to get the required parts.\n" \
126 "You can also have a look at pictures and some movies showing such a device " \
129 #define DRIVER_TEXT N_("Device type")
130 #define DRIVER_LONGTEXT N_("Choose your prefered hardware from " \
131 "the list, or choose AtmoWin Software " \
132 "to delegate processing to the external " \
133 "process - with more options")
135 static const int pi_device_type_values[] = {
137 0, /* use AtmoWinA.exe userspace driver */
139 1, /* AtmoLight classic */
140 2, /* Quattro AtmoLight */
142 4, /* MoMoLight device */
145 static const char *const ppsz_device_type_descriptions[] = {
147 N_("AtmoWin Software"),
149 N_("Classic AtmoLight"),
150 N_("Quattro AtmoLight"),
156 #define DMX_CHANNELS_TEXT N_("Count of AtmoLight channels")
157 #define DMX_CHANNELS_LONGTEXT N_("How many AtmoLight channels, should be " \
158 "emulated with that DMX device")
159 #define DMX_CHBASE_TEXT N_("DMX address for each channel")
160 #define DMX_CHBASE_LONGTEXT N_("Define here the DMX base address for each " \
161 "channel use , or ; to seperate the values")
163 #define MOMO_CHANNELS_TEXT N_("Count of channels")
164 #define MOMO_CHANNELS_LONGTEXT N_("Depending on your MoMoLight hardware " \
165 "choose 3 or 4 channels")
167 #define FNORDLICHT_AMOUNT_TEXT N_("Count of fnordlicht's")
168 #define FNORDLICHT_AMOUNT_LONGTEXT N_("Depending on the amount your " \
169 "fnordlicht hardware " \
170 "choose 1 to 4 channels")
173 # define DEFAULT_DEVICE 0
175 # define DEFAULT_DEVICE 1
178 #if defined( __ATMO_DEBUG__ )
179 # define SAVEFRAMES_TEXT N_("Save Debug Frames")
180 # define SAVEFRAMES_LONGTEXT N_("Write every 128th miniframe to a folder.")
181 # define FRAMEPATH_TEXT N_("Debug Frame Folder")
182 # define FRAMEPATH_LONGTEXT N_("The path where the debugframes " \
186 #define WIDTH_TEXT N_("Extracted Image Width")
187 #define WIDTH_LONGTEXT N_("The width of the mini image for " \
188 "further processing (64 is default)")
190 #define HEIGHT_TEXT N_("Extracted Image Height")
191 #define HEIGHT_LONGTEXT N_("The height of the mini image for " \
192 "further processing (48 is default)")
194 #define SHOW_DOTS_TEXT N_("Mark analyzed pixels")
195 #define SHOW_DOTS_LONGTEXT N_("makes the sample grid visible on screen as "\
198 #define PCOLOR_TEXT N_("Color when paused")
199 #define PCOLOR_LONGTEXT N_("Set the color to show if the user " \
200 "pauses the video. (Have light to get " \
202 #define PCOLOR_RED_TEXT N_("Pause-Red")
203 #define PCOLOR_RED_LONGTEXT N_("Red component of the pause color")
204 #define PCOLOR_GREEN_TEXT N_("Pause-Green")
205 #define PCOLOR_GREEN_LONGTEXT N_("Green component of the pause color")
206 #define PCOLOR_BLUE_TEXT N_("Pause-Blue")
207 #define PCOLOR_BLUE_LONGTEXT N_("Blue component of the pause color")
208 #define FADESTEPS_TEXT N_("Pause-Fadesteps")
209 #define FADESTEPS_LONGTEXT N_("Number of steps to change current color " \
210 "to pause color (each step takes 40ms)")
212 #define ECOLOR_RED_TEXT N_("End-Red")
213 #define ECOLOR_RED_LONGTEXT N_("Red component of the shutdown color")
214 #define ECOLOR_GREEN_TEXT N_("End-Green")
215 #define ECOLOR_GREEN_LONGTEXT N_("Green component of the shutdown color")
216 #define ECOLOR_BLUE_TEXT N_("End-Blue")
217 #define ECOLOR_BLUE_LONGTEXT N_("Blue component of the shutdown color")
218 #define EFADESTEPS_TEXT N_("End-Fadesteps")
219 #define EFADESTEPS_LONGTEXT N_("Number of steps to change current color to " \
220 "end color for dimming up the light in cinema " \
221 "style... (each step takes 40ms)")
223 #define ZONE_TOP_TEXT N_("Number of zones on top")
224 #define ZONE_TOP_LONGTEXT N_("Number of zones on the top of the screen")
225 #define ZONE_BOTTOM_TEXT N_("Number of zones on bottom")
226 #define ZONE_BOTTOM_LONGTEXT N_("Number of zones on the bottom of the screen")
227 #define ZONE_LR_TEXT N_("Zones on left / right side")
228 #define ZONE_LR_LONGTEXT N_("left and right side having allways the " \
229 "same number of zones")
230 #define ZONE_SUMMARY_TEXT N_("Calculate a average zone")
231 #define ZONE_SUMMARY_LONGTEXT N_("it contains the average of all pixels " \
232 "in the sample image (only useful for " \
233 "single channel AtmoLight)")
236 #define USEWHITEADJ_TEXT N_("Use Software White adjust")
237 #define USEWHITEADJ_LONGTEXT N_("Should the buildin driver do a white " \
238 "adjust or your LED stripes? recommend.")
239 #define WHITE_RED_TEXT N_("White Red")
240 #define WHITE_RED_LONGTEXT N_("Red value of a pure white on your "\
242 #define WHITE_GREEN_TEXT N_("White Green")
243 #define WHITE_GREEN_LONGTEXT N_("Green value of a pure white on your "\
245 #define WHITE_BLUE_TEXT N_("White Blue")
246 #define WHITE_BLUE_LONGTEXT N_("Blue value of a pure white on your "\
249 #define SERIALDEV_TEXT N_("Serial Port/Device")
250 #define SERIALDEV_LONGTEXT N_("Name of the serial port where the AtmoLight "\
251 "controller is attached to.\n" \
252 "On Windows usually something like COM1 or " \
253 "COM2. On Linux /dev/ttyS01 f.e.")
255 #define EDGE_TEXT N_("Edge Weightning")
256 #define EDGE_LONGTEXT N_("Increasing this value will result in color "\
257 "more depending on the border of the frame.")
258 #define BRIGHTNESS_TEXT N_("Brightness")
259 #define BRIGHTNESS_LONGTEXT N_("Overall brightness of your LED stripes")
260 #define DARKNESS_TEXT N_("Darkness Limit")
261 #define DARKNESS_LONGTEXT N_("Pixels with a saturation lower than this will "\
262 "be ignored. Should be greater than one for "\
263 "letterboxed videos.")
264 #define HUEWINSIZE_TEXT N_("Hue windowing")
265 #define HUEWINSIZE_LONGTEXT N_("Used for statistics.")
266 #define SATWINSIZE_TEXT N_("Sat windowing")
267 #define SATWINSIZE_LONGTEXT N_("Used for statistics.")
269 #define MEANLENGTH_TEXT N_("Filter length (ms)")
270 #define MEANLENGTH_LONGTEXT N_("Time it takes until a color is completely "\
271 "changed. This prevents flickering.")
272 #define MEANTHRESHOLD_TEXT N_("Filter threshold")
273 #define MEANTHRESHOLD_LONGTEXT N_("How much a color has to be changed for an "\
274 "immediate color change.")
275 #define MEANPERCENTNEW_TEXT N_("Filter Smoothness (in %)")
276 #define MEANPERCENTNEW_LONGTEXT N_("Filter Smoothness")
278 #define FILTERMODE_TEXT N_("Output Color filter mode")
279 #define FILTERMODE_LONGTEXT N_("defines the how the output color should " \
280 "be calculated based on previous color")
282 static const int pi_filtermode_values[] = {
287 static const char *const ppsz_filtermode_descriptions[] = {
293 #define FRAMEDELAY_TEXT N_("Frame delay (ms)")
294 #define FRAMEDELAY_LONGTEXT N_("Helps to get the video output and the light "\
295 "effects in sync. Values around 20ms should " \
299 #define CHANNEL_0_ASSIGN_TEXT N_("Channel 0: summary")
300 #define CHANNEL_1_ASSIGN_TEXT N_("Channel 1: left")
301 #define CHANNEL_2_ASSIGN_TEXT N_("Channel 2: right")
302 #define CHANNEL_3_ASSIGN_TEXT N_("Channel 3: top")
303 #define CHANNEL_4_ASSIGN_TEXT N_("Channel 4: bottom")
305 #define CHANNELASSIGN_LONGTEXT N_("Maps the hardware channel X to logical "\
306 "zone Y to fix wrong wiring :-)")
307 static const int pi_zone_assignment_values[] = {
315 static const char *const ppsz_zone_assignment_descriptions[] = {
317 N_("Zone 4:summary"),
323 #define CHANNELS_ASSIGN_TEXT N_("Channel / Zone Assignment")
324 #define CHANNELS_ASSIGN_LONGTEXT N_("for devices with more than five " \
325 "channels / zones write down here for each channel " \
326 "the zone number to show and seperate the values with " \
327 ", or ; and use -1 to not use some channels. For the " \
328 "classic AtmoLight the sequence 4,3,1,0,2 would set the " \
329 "default channel/zone mapping. " \
330 "Having only two zones on top, and one zone on left and " \
331 "right and no summary zone the mapping for classic " \
332 "AtmoLight would be -1,3,2,1,0")
334 #define ZONE_0_GRADIENT_TEXT N_("Zone 0: Top gradient")
335 #define ZONE_1_GRADIENT_TEXT N_("Zone 1: Right gradient")
336 #define ZONE_2_GRADIENT_TEXT N_("Zone 2: Bottom gradient")
337 #define ZONE_3_GRADIENT_TEXT N_("Zone 3: Left gradient")
338 #define ZONE_4_GRADIENT_TEXT N_("Zone 4: Summary gradient")
339 #define ZONE_X_GRADIENT_LONG_TEXT N_("Defines a small bitmap with 64x48 "\
340 "pixels, containing a grayscale gradient")
342 #define GRADIENT_PATH_TEXT N_("Gradient bitmap searchpath")
343 #define GRADIENT_PATH_LONGTEXT N_("Now prefered option to assign gradient "\
344 "bitmaps, put them as zone_0.bmp, zone_1.bmp etc. into one folder and "\
345 "set the foldername here")
348 # define ATMOWINEXE_TEXT N_("Filename of AtmoWin*.exe")
349 # define ATMOWINEXE_LONGTEXT N_("if you want the AtmoLight control "\
350 "software to be launched by VLC, enter the "\
351 "complete path of AtmoWinA.exe here.")
354 #define CFG_PREFIX "atmo-"
356 /*****************************************************************************
358 *****************************************************************************/
360 set_description( N_("AtmoLight Filter") )
361 set_help( MODULE_DESCRIPTION )
362 set_shortname( N_( "AtmoLight" ))
363 set_category( CAT_VIDEO )
364 set_subcategory( SUBCAT_VIDEO_VFILTER )
366 set_capability( "video filter2", 0 )
369 set_section( N_("Choose Devicetype and Connection" ), 0 )
371 add_integer( CFG_PREFIX "device", DEFAULT_DEVICE, NULL,
372 DRIVER_TEXT, DRIVER_LONGTEXT, false )
373 change_integer_list( pi_device_type_values,
374 ppsz_device_type_descriptions, 0 )
377 add_string(CFG_PREFIX "serialdev", "COM1", NULL,
378 SERIALDEV_TEXT, SERIALDEV_LONGTEXT, false )
380 on win32 the executeable external driver application
381 for automatic start if needed
383 add_file(CFG_PREFIX "atmowinexe", NULL, NULL,
384 ATMOWINEXE_TEXT, ATMOWINEXE_LONGTEXT, false )
386 add_string(CFG_PREFIX "serialdev", "/dev/ttyUSB0", NULL,
387 SERIALDEV_TEXT, SERIALDEV_LONGTEXT, false )
391 color which is showed if you want durring pausing
392 your movie ... used for both buildin / external
394 set_section( N_("Illuminate the room with this color on pause" ), 0 )
395 add_bool(CFG_PREFIX "usepausecolor", false, NULL,
396 PCOLOR_TEXT, PCOLOR_LONGTEXT, false)
397 add_integer_with_range(CFG_PREFIX "pcolor-red", 0, 0, 255, NULL,
398 PCOLOR_RED_TEXT, PCOLOR_RED_LONGTEXT, false)
399 add_integer_with_range(CFG_PREFIX "pcolor-green", 0, 0, 255, NULL,
400 PCOLOR_GREEN_TEXT, PCOLOR_GREEN_LONGTEXT, false)
401 add_integer_with_range(CFG_PREFIX "pcolor-blue", 192, 0, 255, NULL,
402 PCOLOR_BLUE_TEXT, PCOLOR_BLUE_LONGTEXT, false)
403 add_integer_with_range(CFG_PREFIX "fadesteps", 50, 1, 250, NULL,
404 FADESTEPS_TEXT, FADESTEPS_LONGTEXT, false)
407 color which is showed if you finished watching your movie ...
408 used for both buildin / external
410 set_section( N_("Illuminate the room with this color on shutdown" ), 0 )
411 add_integer_with_range(CFG_PREFIX "ecolor-red", 192, 0, 255, NULL,
412 ECOLOR_RED_TEXT, ECOLOR_RED_LONGTEXT, false)
413 add_integer_with_range(CFG_PREFIX "ecolor-green", 192, 0, 255, NULL,
414 ECOLOR_GREEN_TEXT, ECOLOR_GREEN_LONGTEXT, false)
415 add_integer_with_range(CFG_PREFIX "ecolor-blue", 192, 0, 255, NULL,
416 ECOLOR_BLUE_TEXT, ECOLOR_BLUE_LONGTEXT, false)
417 add_integer_with_range(CFG_PREFIX "efadesteps", 50, 1, 250, NULL,
418 EFADESTEPS_TEXT, EFADESTEPS_LONGTEXT, false)
421 set_section( N_("DMX options" ), 0 )
422 add_integer_with_range(CFG_PREFIX "dmx-channels", 5, 1, 64, NULL,
423 DMX_CHANNELS_TEXT, DMX_CHANNELS_LONGTEXT, false)
424 add_string(CFG_PREFIX "dmx-chbase", "0,3,6,9,12", NULL,
425 DMX_CHBASE_TEXT, DMX_CHBASE_LONGTEXT, false )
427 set_section( N_("MoMoLight options" ), 0 )
428 add_integer_with_range(CFG_PREFIX "momo-channels", 3, 3, 4, NULL,
429 MOMO_CHANNELS_TEXT, MOMO_CHANNELS_LONGTEXT, false)
431 /* 2,2,4 means 2 is the default value, 1 minimum amount,
434 set_section( N_("fnordlicht options" ), 0 )
435 add_integer_with_range(CFG_PREFIX "fnordlicht-amount", 2, 1, 4, NULL,
436 FNORDLICHT_AMOUNT_TEXT,
437 FNORDLICHT_AMOUNT_LONGTEXT, false)
441 instead of redefining the original AtmoLight zones with gradient
442 bitmaps, we can now define the layout of the zones useing these
443 parameters - the function with the gradient bitmaps would still
444 work (but for most cases its no longer required)
446 short description whats this means - f.e. the classic atmo would
448 zones-top = 1 - zone 0
449 zones-lr = 1 - zone 1 und zone 3
450 zones-bottom = 1 - zone 2
451 zone-summary = true - zone 4
459 the zone numbers will be counted clockwise starting at top / left
460 if you want to split the light at the top, without having a bottom zone
461 (which is my private config)
463 zones-top = 2 - zone 0, zone 1
464 zones-lr = 1 - zone 2 und zone 3
476 set_section( N_("Zone Layout for the build-in Atmo" ), 0 )
477 add_integer_with_range(CFG_PREFIX "zones-top", 1, 0, 16, NULL,
478 ZONE_TOP_TEXT, ZONE_TOP_LONGTEXT, false)
479 add_integer_with_range(CFG_PREFIX "zones-bottom", 1, 0, 16, NULL,
480 ZONE_BOTTOM_TEXT, ZONE_BOTTOM_LONGTEXT, false)
481 add_integer_with_range(CFG_PREFIX "zones-lr", 1, 0, 16, NULL,
482 ZONE_LR_TEXT, ZONE_LR_LONGTEXT, false)
483 add_bool(CFG_PREFIX "zone-summary", false, NULL,
484 ZONE_SUMMARY_TEXT, ZONE_SUMMARY_LONGTEXT, false)
487 settings only for the buildin driver (if external driver app is used
488 these parameters are ignored.)
490 definition of parameters for the buildin filter ...
492 set_section( N_("Settings for the built-in Live Video Processor only" ), 0 )
494 add_integer_with_range(CFG_PREFIX "edgeweightning", 3, 1, 30, NULL,
495 EDGE_TEXT, EDGE_LONGTEXT, false)
497 add_integer_with_range(CFG_PREFIX "brightness", 100, 50, 300, NULL,
498 BRIGHTNESS_TEXT, BRIGHTNESS_LONGTEXT, false)
500 add_integer_with_range(CFG_PREFIX "darknesslimit", 3, 0, 10, NULL,
501 DARKNESS_TEXT, DARKNESS_LONGTEXT, false)
503 add_integer_with_range(CFG_PREFIX "huewinsize", 3, 0, 5, NULL,
504 HUEWINSIZE_TEXT, HUEWINSIZE_LONGTEXT, false)
506 add_integer_with_range(CFG_PREFIX "satwinsize", 3, 0, 5, NULL,
507 SATWINSIZE_TEXT, SATWINSIZE_LONGTEXT, false)
509 add_integer(CFG_PREFIX "filtermode", (int)afmCombined, NULL,
510 FILTERMODE_TEXT, FILTERMODE_LONGTEXT, false )
512 change_integer_list(pi_filtermode_values, ppsz_filtermode_descriptions, NULL )
514 add_integer_with_range(CFG_PREFIX "meanlength", 300, 300, 5000, NULL,
515 MEANLENGTH_TEXT, MEANLENGTH_LONGTEXT, false)
517 add_integer_with_range(CFG_PREFIX "meanthreshold", 40, 1, 100, NULL,
518 MEANTHRESHOLD_TEXT, MEANTHRESHOLD_LONGTEXT, false)
520 add_integer_with_range(CFG_PREFIX "percentnew", 50, 1, 100, NULL,
521 MEANPERCENTNEW_TEXT, MEANPERCENTNEW_LONGTEXT, false)
523 add_integer_with_range(CFG_PREFIX "framedelay", 18, 0, 200, NULL,
524 FRAMEDELAY_TEXT, FRAMEDELAY_LONGTEXT, false)
527 output channel reordering
529 set_section( N_("Change channel assignment (fixes wrong wiring)" ), 0 )
530 add_integer( CFG_PREFIX "channel_0", 4, NULL,
531 CHANNEL_0_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
532 change_integer_list( pi_zone_assignment_values,
533 ppsz_zone_assignment_descriptions, 0 )
535 add_integer( CFG_PREFIX "channel_1", 3, NULL,
536 CHANNEL_1_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
537 change_integer_list( pi_zone_assignment_values,
538 ppsz_zone_assignment_descriptions, 0 )
540 add_integer( CFG_PREFIX "channel_2", 1, NULL,
541 CHANNEL_2_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
542 change_integer_list( pi_zone_assignment_values,
543 ppsz_zone_assignment_descriptions, 0 )
545 add_integer( CFG_PREFIX "channel_3", 0, NULL,
546 CHANNEL_3_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
547 change_integer_list( pi_zone_assignment_values,
548 ppsz_zone_assignment_descriptions, 0 )
550 add_integer( CFG_PREFIX "channel_4", 2, NULL,
551 CHANNEL_4_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
552 change_integer_list( pi_zone_assignment_values,
553 ppsz_zone_assignment_descriptions, 0 )
555 add_string(CFG_PREFIX "channels", NULL, NULL,
556 CHANNELS_ASSIGN_TEXT, CHANNELS_ASSIGN_LONGTEXT, false )
560 LED color white calibration
562 set_section( N_("Adjust the white light to your LED stripes" ), 0 )
563 add_bool(CFG_PREFIX "whiteadj", true, NULL,
564 USEWHITEADJ_TEXT, USEWHITEADJ_LONGTEXT, false)
565 add_integer_with_range(CFG_PREFIX "white-red", 255, 0, 255, NULL,
566 WHITE_RED_TEXT, WHITE_RED_LONGTEXT, false)
568 add_integer_with_range(CFG_PREFIX "white-green", 255, 0, 255, NULL,
569 WHITE_GREEN_TEXT, WHITE_GREEN_LONGTEXT, false)
571 add_integer_with_range(CFG_PREFIX "white-blue", 255, 0, 255, NULL,
572 WHITE_BLUE_TEXT, WHITE_BLUE_LONGTEXT, false)
573 /* end of definition of parameter for the buildin filter ... part 1 */
577 only for buildin (external has own definition) per default the calucation
578 used linear gradients for assigning a priority to the pixel - depending
579 how near they are to the border ...for changing this you can create 64x48
580 Pixel BMP files - which contain your own grayscale... (you can produce funny
581 effects with this...) the images MUST not compressed, should have 24-bit per
582 pixel, or a simple 256 color grayscale palette
584 set_section( N_("Change gradients" ), 0 )
585 add_file(CFG_PREFIX "gradient_zone_0", NULL, NULL,
586 ZONE_0_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
587 add_file(CFG_PREFIX "gradient_zone_1", NULL, NULL,
588 ZONE_1_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
589 add_file(CFG_PREFIX "gradient_zone_2", NULL, NULL,
590 ZONE_2_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
591 add_file(CFG_PREFIX "gradient_zone_3", NULL, NULL,
592 ZONE_3_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
593 add_file(CFG_PREFIX "gradient_zone_4", NULL, NULL,
594 ZONE_4_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
595 add_directory(CFG_PREFIX "gradient_path", NULL, NULL,
596 GRADIENT_PATH_TEXT, GRADIENT_PATH_LONGTEXT, false )
598 #if defined(__ATMO_DEBUG__)
599 add_bool(CFG_PREFIX "saveframes", false, NULL,
600 SAVEFRAMES_TEXT, SAVEFRAMES_LONGTEXT, false)
601 add_string(CFG_PREFIX "framepath", "", NULL,
602 FRAMEPATH_TEXT, FRAMEPATH_LONGTEXT, false )
605 may be later if computers gets more power ;-) than now we increase
606 the samplesize from which we do the stats for output color calculation
608 add_integer_with_range(CFG_PREFIX "width", 64, 64, 512, NULL,
609 WIDTH_TEXT, WIDTH_LONGTEXT, true)
610 add_integer_with_range(CFG_PREFIX "height", 48, 48, 384, NULL,
611 HEIGHT_TEXT, HEIGHT_LONGTEXT, true)
612 add_bool(CFG_PREFIX "showdots", false, NULL,
613 SHOW_DOTS_TEXT, SHOW_DOTS_LONGTEXT, false)
614 add_shortcut( "atmo" )
615 set_callbacks( CreateFilter, DestroyFilter )
619 static const char *const ppsz_filter_options[] = {
674 #if defined(__ATMO_DEBUG__)
691 /*****************************************************************************
692 * fadethread_t: Color Fading Thread
693 *****************************************************************************
694 * changes slowly the color of the output if videostream gets paused...
695 *****************************************************************************
701 /* tell the thread which color should be the target of fading */
705 /* how many steps should happen until this */
710 static void *FadeToColorThread(vlc_object_t *);
713 /*****************************************************************************
714 * filter_sys_t: AtmoLight filter method descriptor
715 *****************************************************************************
716 * It describes the AtmoLight specific properties of an video filter.
717 *****************************************************************************/
721 special for the access of the p_fadethread member all other members
722 need no special protection so far!
724 vlc_mutex_t filter_lock;
727 int32_t i_AtmoOldEffect;
730 int32_t i_device_type;
732 int32_t i_atmo_width;
733 int32_t i_atmo_height;
734 /* used to disable fadeout if less than 50 frames are processed
735 used to avoid long time waiting when switch quickly between
736 deinterlaceing modes, where the output filter chains is rebuild
739 int32_t i_frames_processed;
741 #if defined(__ATMO_DEBUG__)
743 uint32_t ui_frame_counter;
744 char sz_framepath[MAX_PATH];
747 /* light color durring movie pause ... */
748 bool b_usepausecolor;
749 uint8_t ui_pausecolor_red;
750 uint8_t ui_pausecolor_green;
751 uint8_t ui_pausecolor_blue;
754 /* light color on movie finish ... */
755 uint8_t ui_endcolor_red;
756 uint8_t ui_endcolor_green;
757 uint8_t ui_endcolor_blue;
760 fadethread_t *p_fadethread;
762 /* Variables for buildin driver only... */
764 /* is only present and initialized if the internal driver is used*/
765 CAtmoConfig *p_atmo_config;
766 /* storage for temporal settings "volatile" */
767 CAtmoDynData *p_atmo_dyndata;
768 /* initialized for buildin driver with AtmoCreateTransferBuffers */
769 BITMAPINFOHEADER mini_image_format;
770 /* is only use buildin driver! */
771 uint8_t *p_atmo_transfer_buffer;
772 /* end buildin driver */
775 contains the real output size of the video calculated on
776 change event of the variable "crop" from vout
778 int32_t i_crop_x_offset;
779 int32_t i_crop_y_offset;
780 int32_t i_crop_width;
781 int32_t i_crop_height;
783 void (*pf_extract_mini_image) (filter_sys_t *p_sys,
785 uint8_t *p_transfer_dest);
788 /* External Library as wrapper arround COM Stuff */
789 HINSTANCE h_AtmoCtrl;
790 int32_t (*pf_ctrl_atmo_initialize) (void);
791 void (*pf_ctrl_atmo_finalize) (int32_t what);
792 int32_t (*pf_ctrl_atmo_switch_effect) (int32_t);
793 int32_t (*pf_ctrl_atmo_set_live_source) (int32_t);
794 void (*pf_ctrl_atmo_create_transfer_buffers) (int32_t, int32_t,
796 uint8_t* (*pf_ctrl_atmo_lock_transfer_buffer) (void);
797 void (*pf_ctrl_atmo_send_pixel_data) (void);
798 void (*pf_ctrl_atmo_get_image_size)(int32_t *,int32_t *);
803 initialize previously configured Atmo Light environment
804 - if internal is enabled try to access the device on the serial port
805 - if not internal is enabled and we are on win32 try to initialize
806 the previously loaded DLL ...
808 Return Values may be: -1 (failed for some reason - filter will be disabled)
811 static int32_t AtmoInitialize(filter_t *p_filter, bool b_for_thread)
813 filter_sys_t *p_sys = p_filter->p_sys;
814 if(p_sys->p_atmo_config)
816 if(b_for_thread == false)
819 /* setup Output Threads ... */
820 msg_Dbg( p_filter, "open atmo device...");
821 if(CAtmoTools::RecreateConnection(p_sys->p_atmo_dyndata)
826 msg_Err( p_filter,"failed to open atmo device, "\
827 "some other software/driver may use it?");
831 } else if(p_sys->pf_ctrl_atmo_initialize)
833 /* on win32 with active ctrl dll */
834 return p_sys->pf_ctrl_atmo_initialize();
841 prepare the shutdown of the effect threads,
842 for build in filter - close the serialport after finishing the threads...
843 cleanup possible loaded DLL...
845 static void AtmoFinalize(filter_t *p_filter, int32_t what)
847 filter_sys_t *p_sys = p_filter->p_sys;
848 if(p_sys->p_atmo_config)
852 CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
855 p_atmo_dyndata->LockCriticalSection();
857 CAtmoInput *p_input = p_atmo_dyndata->getLiveInput();
858 p_atmo_dyndata->setLiveInput( NULL );
861 p_input->Terminate();
863 msg_Dbg( p_filter, "input thread died peacefully");
866 CThread *p_effect_thread = p_atmo_dyndata->getEffectThread();
867 p_atmo_dyndata->setEffectThread(NULL);
868 if(p_effect_thread != NULL)
871 forced the thread to die...
872 and wait for termination of the thread
874 p_effect_thread->Terminate();
875 delete p_effect_thread;
876 msg_Dbg( p_filter, "effect thread died peacefully");
879 CAtmoPacketQueue *p_queue =
880 p_atmo_dyndata->getLivePacketQueue();
881 p_atmo_dyndata->setLivePacketQueue( NULL );
885 msg_Dbg( p_filter, "packetqueue removed");
889 close serial port if it is open (all OS specific is inside
890 CAtmoSerialConnection implemented / defined)
892 CAtmoConnection *p_atmo_connection =
893 p_atmo_dyndata->getAtmoConnection();
894 p_atmo_dyndata->setAtmoConnection(NULL);
895 if(p_atmo_connection) {
896 p_atmo_connection->CloseConnection();
897 delete p_atmo_connection;
899 p_atmo_dyndata->UnLockCriticalSection();
903 } else if(p_sys->pf_ctrl_atmo_finalize)
905 /* on win32 with active ctrl dll */
906 p_sys->pf_ctrl_atmo_finalize(what);
912 switch the current light effect to LiveView
914 static int32_t AtmoSwitchEffect(filter_t *p_filter, int32_t newMode)
916 filter_sys_t *p_sys = p_filter->p_sys;
918 msg_Dbg( p_filter, "AtmoSwitchEffect %d", newMode );
920 if(p_sys->p_atmo_config)
922 return CAtmoTools::SwitchEffect(p_sys->p_atmo_dyndata, emLivePicture);
924 } else if(p_sys->pf_ctrl_atmo_switch_effect)
926 /* on win32 with active ctrl dll */
927 return p_sys->pf_ctrl_atmo_switch_effect( newMode );
934 set the current live picture source, does only something on win32,
935 with the external libraries - if the buildin effects are used nothing
938 static int32_t AtmoSetLiveSource(filter_t *p_filter, int32_t newSource)
940 filter_sys_t *p_sys = p_filter->p_sys;
942 msg_Dbg( p_filter, "AtmoSetLiveSource %d", newSource );
944 if(p_sys->p_atmo_config)
949 doesnt know different sources so this
950 function call would just do nothing special
954 } else if(p_sys->pf_ctrl_atmo_set_live_source)
956 /* on win32 with active ctrl dll */
957 return p_sys->pf_ctrl_atmo_set_live_source(newSource);
964 setup the pixel transferbuffers which is used to transfer pixeldata from
965 the filter to the effect thread, and possible accross the process
966 boundaries on win32, with the external DLL
968 static void AtmoCreateTransferBuffers(filter_t *p_filter,
970 int32_t bytePerPixel,
974 filter_sys_t *p_sys = p_filter->p_sys;
975 if(p_sys->p_atmo_config)
978 we need a buffer where the image is stored (only for transfer
979 to the processing thread)
981 free( p_sys->p_atmo_transfer_buffer );
983 p_sys->p_atmo_transfer_buffer = (uint8_t *)malloc(bytePerPixel *
986 memset(&p_sys->mini_image_format,0,sizeof(BITMAPINFOHEADER));
988 p_sys->mini_image_format.biSize = sizeof(BITMAPINFOHEADER);
989 p_sys->mini_image_format.biWidth = width;
990 p_sys->mini_image_format.biHeight = height;
991 p_sys->mini_image_format.biBitCount = bytePerPixel*8;
992 p_sys->mini_image_format.biCompression = FourCC;
995 } else if(p_sys->pf_ctrl_atmo_create_transfer_buffers)
997 /* on win32 with active ctrl dll */
998 p_sys->pf_ctrl_atmo_create_transfer_buffers(FourCC,
1007 acquire the transfer buffer pointer the buildin version only
1008 returns the pointer to the allocated buffer ... the
1009 external version on win32 has to do some COM stuff to lock the
1010 Variant Byte array which is behind the buffer
1012 static uint8_t* AtmoLockTransferBuffer(filter_t *p_filter)
1014 filter_sys_t *p_sys = p_filter->p_sys;
1015 if(p_sys->p_atmo_config)
1017 return p_sys->p_atmo_transfer_buffer;
1019 } else if(p_sys->pf_ctrl_atmo_lock_transfer_buffer)
1021 /* on win32 with active ctrl dll */
1022 return p_sys->pf_ctrl_atmo_lock_transfer_buffer();
1029 send the content of current pixel buffer got with AtmoLockTransferBuffer
1030 to the processing threads
1031 - build in version - will forward the data to AtmoExternalCaptureInput Thread
1032 - win32 external - will do the same, but across the process boundaries via
1033 COM to the AtmoWinA.exe Process
1035 static void AtmoSendPixelData(filter_t *p_filter)
1037 filter_sys_t *p_sys = p_filter->p_sys;
1038 if(p_sys->p_atmo_config && p_sys->p_atmo_transfer_buffer)
1040 CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
1041 if(p_atmo_dyndata &&
1042 (p_atmo_dyndata->getLivePictureSource() == lpsExtern))
1045 the cast will go Ok because we are inside videolan there is only
1046 this kind of effect thread implemented!
1048 CAtmoExternalCaptureInput *p_atmo_external_capture_input_thread =
1049 (CAtmoExternalCaptureInput *)p_atmo_dyndata->getLiveInput();
1051 if(p_atmo_external_capture_input_thread)
1054 the same as above inside videolan only this single kind of
1055 input exists so we can cast without further tests!
1057 this call will do a 1:1 copy of this buffer, and wakeup
1058 the thread from normal sleeping
1060 p_atmo_external_capture_input_thread->
1061 DeliverNewSourceDataPaket(&p_sys->mini_image_format,
1062 p_sys->p_atmo_transfer_buffer);
1066 } else if(p_sys->pf_ctrl_atmo_send_pixel_data)
1068 /* on win32 with active ctrl dll */
1069 p_sys->pf_ctrl_atmo_send_pixel_data();
1073 msg_Warn( p_filter, "AtmoSendPixelData no method");
1078 Shutdown AtmoLight finally - is call from DestroyFilter
1079 does the cleanup restores the effectmode on the external Software
1080 (only win32) and possible setup the final light ...
1082 static void Atmo_Shutdown(filter_t *p_filter)
1084 filter_sys_t *p_sys = p_filter->p_sys;
1086 if(p_sys->b_enabled == true)
1088 msg_Dbg( p_filter, "shut down atmo!");
1090 if there is a still running show pause color thread kill him!
1092 CheckAndStopFadeThread(p_filter);
1094 // perpare spawn fadeing thread
1095 vlc_mutex_lock( &p_sys->filter_lock );
1098 fade to end color (in case of external AtmoWin Software
1099 assume that the static color will equal to this
1100 one to get a soft change and no flash!
1102 p_sys->b_pause_live = true;
1105 p_sys->p_fadethread = (fadethread_t *)vlc_object_create( p_filter,
1106 sizeof(fadethread_t) );
1108 p_sys->p_fadethread->p_filter = p_filter;
1109 p_sys->p_fadethread->ui_red = p_sys->ui_endcolor_red;
1110 p_sys->p_fadethread->ui_green = p_sys->ui_endcolor_green;
1111 p_sys->p_fadethread->ui_blue = p_sys->ui_endcolor_blue;
1112 if(p_sys->i_frames_processed < 50)
1113 p_sys->p_fadethread->i_steps = 1;
1115 p_sys->p_fadethread->i_steps = p_sys->i_endfadesteps;
1117 if( vlc_thread_create( p_sys->p_fadethread,
1118 "AtmoLight fadeing",
1120 VLC_THREAD_PRIORITY_LOW ) )
1122 msg_Err( p_filter, "cannot create FadeToColorThread" );
1123 vlc_object_release( p_sys->p_fadethread );
1124 p_sys->p_fadethread = NULL;
1125 vlc_mutex_unlock( &p_sys->filter_lock );
1129 vlc_mutex_unlock( &p_sys->filter_lock );
1131 /* wait for the thread... */
1132 vlc_thread_join(p_sys->p_fadethread);
1134 vlc_object_release(p_sys->p_fadethread);
1136 p_sys->p_fadethread = NULL;
1140 the following happens only useing the
1141 external AtmoWin Device Software
1143 if( !p_sys->p_atmo_config )
1145 if(p_sys->i_AtmoOldEffect != emLivePicture)
1146 AtmoSwitchEffect( p_filter, p_sys->i_AtmoOldEffect);
1148 AtmoSetLiveSource( p_filter, lvsGDI );
1151 /* close device connection etc. */
1152 AtmoFinalize(p_filter, 1);
1154 /* disable filter method .. */
1155 p_sys->b_enabled = false;
1160 depending on mode setup imagesize to 64x48(classic), or defined
1161 resolution of external atmowin.exe on windows
1163 static void Atmo_SetupImageSize(filter_t *p_filter)
1165 filter_sys_t *p_sys = p_filter->p_sys;
1167 size of extracted image by default 64x48 (other imagesizes are
1168 currently ignored by AtmoWin)
1170 p_sys->i_atmo_width = var_CreateGetIntegerCommand( p_filter,
1171 CFG_PREFIX "width");
1172 p_sys->i_atmo_height = var_CreateGetIntegerCommand( p_filter,
1173 CFG_PREFIX "height");
1175 if(p_sys->p_atmo_config)
1178 } else if(p_sys->pf_ctrl_atmo_get_image_size)
1180 /* on win32 with active ctrl dll */
1181 p_sys->pf_ctrl_atmo_get_image_size( &p_sys->i_atmo_width,
1182 &p_sys->i_atmo_height );
1186 msg_Dbg(p_filter,"sample image size %d * %d pixels", p_sys->i_atmo_width,
1187 p_sys->i_atmo_height);
1191 initialize the zone and channel mapping for the buildin atmolight adapter
1193 static void Atmo_SetupBuildZones(filter_t *p_filter)
1195 filter_sys_t *p_sys = p_filter->p_sys;
1197 p_sys->p_atmo_dyndata->LockCriticalSection();
1199 CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
1202 CAtmoChannelAssignment *p_channel_assignment =
1203 p_atmo_config->getChannelAssignment(0);
1205 // channel 0 - zone 4
1206 p_channel_assignment->setZoneIndex( 0, var_CreateGetIntegerCommand(
1207 p_filter, CFG_PREFIX "channel_0")
1210 // channel 1 - zone 3
1211 p_channel_assignment->setZoneIndex( 1, var_CreateGetIntegerCommand(
1212 p_filter, CFG_PREFIX "channel_1")
1215 // channel 2 - zone 1
1216 p_channel_assignment->setZoneIndex( 2, var_CreateGetIntegerCommand(
1217 p_filter, CFG_PREFIX "channel_2")
1220 // channel 3 - zone 0
1221 p_channel_assignment->setZoneIndex( 3, var_CreateGetIntegerCommand(
1222 p_filter, CFG_PREFIX "channel_3")
1225 // channel 4 - zone 2
1226 p_channel_assignment->setZoneIndex( 4, var_CreateGetIntegerCommand(
1227 p_filter, CFG_PREFIX "channel_4")
1230 char *psz_channels = var_CreateGetStringCommand(
1232 CFG_PREFIX "channels"
1234 if( psz_channels && strlen(psz_channels) > 0 )
1236 msg_Dbg( p_filter, "deal with new zone mapping %s", psz_channels );
1238 char *psz_temp = psz_channels;
1239 char *psz_start = psz_temp;
1242 if(*psz_temp == ',' || *psz_temp == ';')
1247 int zone = atoi( psz_start );
1249 zone >= p_channel_assignment->getSize()) {
1250 msg_Warn( p_filter, "Zone %d out of range -1..%d",
1251 zone, p_channel_assignment->getSize()-1 );
1253 p_channel_assignment->setZoneIndex( channel, zone );
1257 psz_start = psz_temp;
1265 process the rest of the string
1267 if( *psz_start && !*psz_temp )
1269 int zone = atoi( psz_start );
1271 zone >= p_channel_assignment->getSize()) {
1272 msg_Warn( p_filter, "Zone %d out of range -1..%d",
1273 zone, p_channel_assignment->getSize()-1 );
1275 p_channel_assignment->setZoneIndex( channel, zone );
1279 free( psz_channels );
1281 for(int i=0;i< p_channel_assignment->getSize() ;i++)
1282 msg_Info( p_filter, "map zone %d to hardware channel %d",
1283 p_channel_assignment->getZoneIndex( i ),
1286 p_sys->p_atmo_dyndata->getAtmoConnection()
1287 ->SetChannelAssignment( p_channel_assignment );
1294 calculate the default gradients for each zone!
1295 depending on the zone layout set before, this now
1296 supports also multiple gradients on each side
1297 (older versions could do this only with external
1300 p_sys->p_atmo_dyndata->CalculateDefaultZones();
1304 first try to load the old style defined gradient bitmaps
1305 this could only be done for the first five zones
1306 - should be deprecated -
1308 CAtmoZoneDefinition *p_zone;
1309 char psz_gradient_var_name[30];
1310 char *psz_gradient_file;
1311 for(int i=0;i<CLASSIC_ATMO_NUM_ZONES;i++)
1313 sprintf(psz_gradient_var_name, CFG_PREFIX "gradient_zone_%d", i);
1314 psz_gradient_file = var_CreateGetStringCommand(
1316 psz_gradient_var_name
1318 if(psz_gradient_file && strlen(psz_gradient_file)>0)
1320 msg_Dbg( p_filter, "loading gradientfile %s for "\
1321 "zone %d", psz_gradient_file, i);
1323 p_zone = p_atmo_config->getZoneDefinition(i);
1326 int i_res = p_zone->LoadGradientFromBitmap(psz_gradient_file);
1328 if(i_res != ATMO_LOAD_GRADIENT_OK)
1330 msg_Err( p_filter,"failed to load gradient '%s' with "\
1331 "error %d",psz_gradient_file,i_res);
1335 free( psz_gradient_file );
1340 the new approach try to load a gradient bitmap for each zone
1341 from a previously defined folder containing
1346 char *psz_gradient_path = var_CreateGetStringCommand(
1348 CFG_PREFIX "gradient_path"
1350 if( psz_gradient_path && strlen(psz_gradient_path) > 0 )
1352 char *psz_file_name = (char *)malloc( strlen(psz_gradient_path) + 16 );
1353 assert( psz_file_name );
1355 for(int i=0; i < p_atmo_config->getZoneCount(); i++ )
1357 p_zone = p_atmo_config->getZoneDefinition(i);
1361 sprintf(psz_file_name, "%s%szone_%d.bmp",
1362 psz_gradient_path, DIR_SEP, i );
1364 int i_res = p_zone->LoadGradientFromBitmap( psz_file_name );
1366 if( i_res == ATMO_LOAD_GRADIENT_OK )
1368 msg_Dbg( p_filter, "loaded gradientfile %s for "\
1369 "zone %d", psz_file_name, i);
1372 if( (i_res != ATMO_LOAD_GRADIENT_OK) &&
1373 (i_res != ATMO_LOAD_GRADIENT_FILENOTFOND) )
1375 msg_Err( p_filter,"failed to load gradient '%s' with "\
1376 "error %d",psz_file_name,i_res);
1381 free( psz_file_name );
1383 free( psz_gradient_path );
1386 p_sys->p_atmo_dyndata->UnLockCriticalSection();
1390 static void Atmo_SetupConfig(filter_t *p_filter, CAtmoConfig *p_atmo_config)
1393 figuring out the device ports (com-ports, ttys)
1395 char *psz_serialdev = var_CreateGetStringCommand( p_filter,
1396 CFG_PREFIX "serialdev" );
1397 char *psz_temp = psz_serialdev;
1399 if( psz_temp && strlen(psz_temp) > 0 )
1406 msg_Dbg( p_filter, "use port(s) %s",psz_serialdev);
1409 psz_serialdev - may contain up to 4 COM ports for the quattro device
1410 the quattro device is just hack of useing 4 classic devices as one
1411 logical device - thanks that usb-com-ports exists :)
1412 as Seperator I defined , or ; with the hope that these
1413 characters are never part of a device name
1415 while( (psz_token = strsep(&psz_temp, ",;")) != NULL && i_port < 4 )
1418 psz_token may contain spaces we have to trim away
1423 find first none space in string
1425 while( psz_token[i] == 32 ) i++;
1427 contains string only spaces or is empty? skip it
1435 while( psz_token[i] && psz_token[i] != 32 )
1436 psz_token[ j++ ] = psz_token[ i++ ];
1439 msg_Dbg( p_filter, "Serial Device [%d]: %s", i_port, psz_token );
1441 p_atmo_config->setSerialDevice( i_port, psz_token );
1448 msg_Err(p_filter,"no serial devicename(s) set");
1450 free( psz_serialdev );
1453 configuration of light source layout arround the display
1455 p_atmo_config->setZonesTopCount(
1456 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-top")
1458 p_atmo_config->setZonesBottomCount(
1459 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-bottom")
1461 p_atmo_config->setZonesLRCount(
1462 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-lr")
1464 p_atmo_config->setZoneSummary(
1465 var_CreateGetBoolCommand( p_filter, CFG_PREFIX "zone-summary")
1469 p_atmo_config->setLiveViewFilterMode(
1470 (AtmoFilterMode)var_CreateGetIntegerCommand( p_filter,
1471 CFG_PREFIX "filtermode")
1474 p_atmo_config->setLiveViewFilter_PercentNew(
1475 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "percentnew")
1477 p_atmo_config->setLiveViewFilter_MeanLength(
1478 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "meanlength")
1480 p_atmo_config->setLiveViewFilter_MeanThreshold(
1481 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "meanthreshold")
1484 p_atmo_config->setLiveView_EdgeWeighting(
1485 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "edgeweightning")
1487 p_atmo_config->setLiveView_BrightCorrect(
1488 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "brightness")
1490 p_atmo_config->setLiveView_DarknessLimit(
1491 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "darknesslimit")
1493 p_atmo_config->setLiveView_HueWinSize(
1494 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "huewinsize")
1496 p_atmo_config->setLiveView_SatWinSize(
1497 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "satwinsize")
1500 /* currently not required inside vlc */
1501 p_atmo_config->setLiveView_WidescreenMode( 0 );
1503 p_atmo_config->setLiveView_FrameDelay(
1504 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "framedelay")
1508 p_atmo_config->setUseSoftwareWhiteAdj(
1509 var_CreateGetBoolCommand( p_filter, CFG_PREFIX "whiteadj")
1511 p_atmo_config->setWhiteAdjustment_Red(
1512 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-red")
1514 p_atmo_config->setWhiteAdjustment_Green(
1515 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-green")
1517 p_atmo_config->setWhiteAdjustment_Blue(
1518 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-blue")
1522 settings for DMX device only
1524 p_atmo_config->setDMX_RGB_Channels(
1525 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "dmx-channels")
1528 char *psz_chbase = var_CreateGetStringCommand( p_filter,
1529 CFG_PREFIX "dmx-chbase" );
1530 if( psz_chbase && strlen(psz_chbase) > 0 )
1531 p_atmo_config->setDMX_BaseChannels( psz_chbase );
1538 p_atmo_config->setMoMo_Channels(
1539 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "momo-channels")
1545 p_atmo_config->setFnordlicht_Amount(
1546 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "fnordlicht-amount")
1553 initialize the filter_sys_t structure with the data from the settings
1554 variables - if the external filter on win32 is enabled try loading the DLL,
1555 if this fails fallback to the buildin software
1557 static void Atmo_SetupParameters(filter_t *p_filter)
1560 filter_sys_t *p_sys = p_filter->p_sys;
1563 /* default filter disabled until DLL loaded and Init Success!*/
1564 p_sys->b_enabled = false;
1566 /* setup default mini image size (may be later a user option) */
1567 p_sys->i_atmo_width = 64;
1568 p_sys->i_atmo_height = 48;
1570 p_sys->i_device_type = var_CreateGetIntegerCommand( p_filter,
1571 CFG_PREFIX "device");
1575 0 => use AtmoWin Software (only win32)
1576 1 => use AtmoClassicConnection (direct)
1577 2 => use AtmoMultiConnection (direct up to four serial ports required)
1578 3 => use AtmoDmxConnection (simple serial DMX Device up to 255 channels)
1584 only on WIN32 the user has the choice between
1585 internal driver and external
1588 if(p_sys->i_device_type == 0) {
1590 /* Load the Com Wrapper Library (source available) */
1591 p_sys->h_AtmoCtrl = LoadLibraryA("AtmoCtrlLib.dll");
1592 if(p_sys->h_AtmoCtrl == NULL)
1595 be clever if the location of atmowina.exe is set
1596 try to load the dll from the same folder :-)
1598 char *psz_path = var_CreateGetStringCommand( p_filter,
1599 CFG_PREFIX "atmowinexe" );
1600 if( psz_path && strlen(psz_path) > 0 )
1602 char *psz_bs = strrchr( psz_path , '\\');
1607 now format a new dll filename with complete path
1609 char *psz_dllname = NULL;
1610 asprintf( &psz_dllname, "%s\\AtmoCtrlLib.dll", psz_path );
1613 msg_Dbg( p_filter, "Try Loading '%s'", psz_dllname );
1614 p_sys->h_AtmoCtrl = LoadLibraryA( psz_dllname );
1616 free( psz_dllname );
1623 if(p_sys->h_AtmoCtrl != NULL)
1625 msg_Dbg( p_filter, "Load Library ok!");
1627 /* importing all required functions I hope*/
1628 p_sys->pf_ctrl_atmo_initialize =
1629 (int32_t (*)(void))GetProcAddress( p_sys->h_AtmoCtrl,
1631 if(!p_sys->pf_ctrl_atmo_initialize)
1632 msg_Err( p_filter, "export AtmoInitialize missing.");
1634 p_sys->pf_ctrl_atmo_finalize =
1635 (void (*)(int32_t))GetProcAddress( p_sys->h_AtmoCtrl,
1637 if(!p_sys->pf_ctrl_atmo_finalize)
1638 msg_Err( p_filter, "export AtmoFinalize missing.");
1640 p_sys->pf_ctrl_atmo_switch_effect =
1641 (int32_t(*)(int32_t))GetProcAddress( p_sys->h_AtmoCtrl,
1642 "AtmoSwitchEffect" );
1643 if(!p_sys->pf_ctrl_atmo_switch_effect)
1644 msg_Err( p_filter, "export AtmoSwitchEffect missing.");
1646 p_sys->pf_ctrl_atmo_set_live_source =
1647 (int32_t(*)(int32_t))GetProcAddress( p_sys->h_AtmoCtrl,
1648 "AtmoSetLiveSource" );
1649 if(!p_sys->pf_ctrl_atmo_set_live_source)
1650 msg_Err( p_filter, "export AtmoSetLiveSource missing.");
1652 p_sys->pf_ctrl_atmo_create_transfer_buffers =
1653 (void (*)(int32_t, int32_t, int32_t , int32_t))
1654 GetProcAddress( p_sys->h_AtmoCtrl,
1655 "AtmoCreateTransferBuffers" );
1656 if(!p_sys->pf_ctrl_atmo_create_transfer_buffers)
1657 msg_Err( p_filter, "export AtmoCreateTransferBuffers missing.");
1659 p_sys->pf_ctrl_atmo_lock_transfer_buffer=
1660 (uint8_t*(*) (void))GetProcAddress( p_sys->h_AtmoCtrl,
1661 "AtmoLockTransferBuffer");
1662 if(!p_sys->pf_ctrl_atmo_lock_transfer_buffer)
1663 msg_Err( p_filter, "export AtmoLockTransferBuffer missing.");
1665 p_sys->pf_ctrl_atmo_send_pixel_data =
1666 (void (*)(void))GetProcAddress( p_sys->h_AtmoCtrl,
1667 "AtmoSendPixelData");
1668 if(!p_sys->pf_ctrl_atmo_send_pixel_data)
1669 msg_Err( p_filter, "export AtmoSendPixelData missing.");
1671 p_sys->pf_ctrl_atmo_get_image_size =
1672 (void (*)(int32_t*,int32_t*))GetProcAddress( p_sys->h_AtmoCtrl,
1673 "AtmoWinGetImageSize");
1674 if(!p_sys->pf_ctrl_atmo_get_image_size)
1675 msg_Err( p_filter, "export AtmoWinGetImageSize missing.");
1678 /* the DLL is missing try internal filter ...*/
1680 "AtmoCtrlLib.dll missing fallback to internal atmo classic driver" );
1681 p_sys->i_device_type = 1;
1686 if(p_sys->i_device_type >= 1) {
1687 msg_Dbg( p_filter, "try use buildin driver %d ", p_sys->i_device_type );
1689 now we have to read a lof of options from the config dialog
1690 most important the serial device if not set ... we can skip
1691 the rest and disable the filter...
1694 p_sys->p_atmo_config = new CAtmoConfig();
1696 p_sys->p_atmo_dyndata = new CAtmoDynData(
1697 (vlc_object_t *)p_filter,
1698 p_sys->p_atmo_config
1701 Atmo_SetupConfig( p_filter, p_sys->p_atmo_config );
1702 switch(p_sys->i_device_type)
1705 p_sys->p_atmo_config->setConnectionType( actClassicAtmo );
1709 p_sys->p_atmo_config->setConnectionType( actMultiAtmo );
1713 p_sys->p_atmo_config->setConnectionType( actDMX );
1717 p_sys->p_atmo_config->setConnectionType( actMoMoLight );
1721 p_sys->p_atmo_config->setConnectionType( actFnordlicht );
1725 msg_Warn( p_filter, "invalid device type %d found",
1726 p_sys->i_device_type );
1729 msg_Dbg( p_filter, "buildin driver config set");
1733 switch( p_filter->fmt_in.video.i_chroma )
1735 case VLC_CODEC_I420:
1736 case VLC_CODEC_YV12:
1737 p_sys->pf_extract_mini_image = ExtractMiniImage_YUV;
1740 msg_Warn( p_filter, "InitFilter-unsupported chroma: %4.4s",
1741 (char *)&p_filter->fmt_in.video.i_chroma);
1742 p_sys->pf_extract_mini_image = NULL;
1746 for debugging purpose show the samplinggrid on each frame as
1749 p_sys->b_show_dots = var_CreateGetBoolCommand( p_filter,
1750 CFG_PREFIX "showdots"
1753 #if defined(__ATMO_DEBUG__)
1754 /* save debug images to a folder as Bitmap files ? */
1755 p_sys->b_saveframes = var_CreateGetBoolCommand( p_filter,
1756 CFG_PREFIX "saveframes"
1758 msg_Dbg(p_filter,"saveframes = %d", (int)p_sys->b_saveframes);
1761 read debug image folder from config
1763 psz_path = var_CreateGetStringCommand( p_filter, CFG_PREFIX "framepath" );
1764 if(psz_path != NULL)
1766 strcpy(p_sys->sz_framepath, psz_path);
1767 #if defined( WIN32 )
1768 size_t i_strlen = strlen(p_sys->sz_framepath);
1769 if((i_strlen>0) && (p_sys->sz_framepath[i_strlen-1] != '\\'))
1771 p_sys->sz_framepath[i_strlen] = '\\';
1772 p_sys->sz_framepath[i_strlen+1] = 0;
1777 msg_Dbg(p_filter,"saveframesfolder %s",p_sys->sz_framepath);
1782 because atmowin could also be used for lighten up the room - I think if you
1783 pause the video it would be useful to get a little bit more light into to
1784 your living room? - instead switching on a lamp?
1786 p_sys->b_usepausecolor = var_CreateGetBoolCommand( p_filter,
1787 CFG_PREFIX "usepausecolor" );
1788 p_sys->ui_pausecolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1789 CFG_PREFIX "pcolor-red");
1790 p_sys->ui_pausecolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1791 CFG_PREFIX "pcolor-green");
1792 p_sys->ui_pausecolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1793 CFG_PREFIX "pcolor-blue");
1794 p_sys->i_fadesteps = var_CreateGetIntegerCommand( p_filter,
1795 CFG_PREFIX "fadesteps");
1796 if(p_sys->i_fadesteps < 1)
1797 p_sys->i_fadesteps = 1;
1798 msg_Dbg(p_filter,"use pause color %d, RGB: %d, %d, %d, Fadesteps: %d",
1799 (int)p_sys->b_usepausecolor,
1800 p_sys->ui_pausecolor_red,
1801 p_sys->ui_pausecolor_green,
1802 p_sys->ui_pausecolor_blue,
1803 p_sys->i_fadesteps);
1806 this color is use on shutdown of the filter - the define the
1807 final light after playback... may be used to dim up the light -
1808 how it happens in the cinema...
1810 p_sys->ui_endcolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1811 CFG_PREFIX "ecolor-red");
1812 p_sys->ui_endcolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1813 CFG_PREFIX "ecolor-green");
1814 p_sys->ui_endcolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1815 CFG_PREFIX "ecolor-blue");
1816 p_sys->i_endfadesteps = var_CreateGetIntegerCommand( p_filter,
1817 CFG_PREFIX "efadesteps");
1818 if(p_sys->i_endfadesteps < 1)
1819 p_sys->i_endfadesteps = 1;
1820 msg_Dbg(p_filter,"use ende color RGB: %d, %d, %d, Fadesteps: %d",
1821 p_sys->ui_endcolor_red,
1822 p_sys->ui_endcolor_green,
1823 p_sys->ui_endcolor_blue,
1824 p_sys->i_endfadesteps);
1829 if the external DLL was loaded successfully call AtmoInitialize -
1830 (must be done for each thread where you want to use AtmoLight!)
1832 int i = AtmoInitialize(p_filter, false);
1834 #if defined( WIN32 )
1835 if((i != 1) && (p_sys->i_device_type == 0))
1838 COM Server for AtmoLight not running ?
1839 if the exe path is configured try to start the "userspace" driver
1841 psz_path = var_CreateGetStringCommand( p_filter,
1842 CFG_PREFIX "atmowinexe" );
1843 if(psz_path != NULL)
1845 STARTUPINFO startupinfo;
1846 PROCESS_INFORMATION pinfo;
1847 memset(&startupinfo, 0, sizeof(STARTUPINFO));
1848 startupinfo.cb = sizeof(STARTUPINFO);
1849 if(CreateProcess(psz_path, NULL, NULL, NULL,
1850 FALSE, 0, NULL, NULL, &startupinfo, &pinfo) == TRUE)
1852 msg_Dbg(p_filter,"launched AtmoWin from %s",psz_path);
1853 WaitForInputIdle(pinfo.hProcess, 5000);
1855 retry to initialize the library COM ... functionality
1856 after the server was launched
1858 i = AtmoInitialize(p_filter, false);
1860 msg_Err(p_filter,"failed to launch AtmoWin from %s", psz_path);
1867 if(i == 1) /* Init Atmolight success... */
1869 msg_Dbg( p_filter, "AtmoInitialize Ok!");
1872 p_sys->i_atmo_width and p_sys->i_atmo_height
1873 if the external AtmoWinA.exe is used, it may require
1874 a other sample image size than 64 x 48
1875 (this overrides the settings of the filter)
1877 Atmo_SetupImageSize( p_filter );
1880 if( p_sys->i_device_type >= 1 )
1883 AtmoConnection class initialized now we can initialize
1884 the default zone and channel mappings
1886 Atmo_SetupBuildZones( p_filter );
1889 /* Setup Transferbuffers for 64 x 48 , RGB with 32bit Per Pixel */
1890 AtmoCreateTransferBuffers(p_filter, BI_RGB, 4,
1891 p_sys->i_atmo_width,
1892 p_sys->i_atmo_height
1895 /* say the userspace driver that a live mode should be activated
1896 the functions returns the old mode for later restore!
1897 - the buildin driver launches the live view thread in that case
1899 p_sys->i_AtmoOldEffect = AtmoSwitchEffect(p_filter, emLivePicture);
1902 live view can have two differnt source the AtmoWinA
1903 internal GDI Screencapture and the external one - which we
1906 AtmoSetLiveSource(p_filter, lvsExternal);
1908 /* enable other parts only if everything is fine */
1909 p_sys->b_enabled = true;
1911 msg_Dbg( p_filter, "Atmo Filter Enabled Ok!");
1917 /*****************************************************************************
1918 * CreateFilter: allocates AtmoLight video thread output method
1919 *****************************************************************************
1920 * This function allocates and initializes a AtmoLight vout method.
1921 *****************************************************************************/
1922 static int CreateFilter( vlc_object_t *p_this )
1924 filter_t *p_filter = (filter_t *)p_this;
1925 filter_sys_t *p_sys;
1927 /* Allocate structure */
1928 p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) );
1929 p_filter->p_sys = p_sys;
1930 if( p_filter->p_sys == NULL )
1932 /* set all entries to zero */
1933 memset(p_sys, 0, sizeof( filter_sys_t ));
1934 vlc_mutex_init( &p_sys->filter_lock );
1936 msg_Dbg( p_filter, "Create Atmo Filter");
1938 /* further Setup Function pointers for videolan for calling my filter */
1939 p_filter->pf_video_filter = Filter;
1941 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
1944 AddStateVariableCallback(p_filter);
1946 AddAtmoSettingsVariablesCallbacks(p_filter);
1948 Atmo_SetupParameters(p_filter);
1956 /*****************************************************************************
1957 * DestroyFilter: destroy AtmoLight video thread output method
1958 *****************************************************************************
1959 * Terminate an output method created by CreateFilter
1960 *****************************************************************************/
1962 static void DestroyFilter( vlc_object_t *p_this )
1964 filter_t *p_filter = (filter_t *)p_this;
1965 filter_sys_t *p_sys = p_filter->p_sys;
1967 msg_Dbg( p_filter, "Destroy Atmo Filter");
1969 DelStateVariableCallback(p_filter);
1971 DelAtmoSettingsVariablesCallbacks(p_filter);
1973 Atmo_Shutdown(p_filter);
1975 #if defined( WIN32 )
1976 if(p_sys->h_AtmoCtrl != NULL)
1978 FreeLibrary(p_sys->h_AtmoCtrl);
1982 delete p_sys->p_atmo_dyndata;
1983 delete p_sys->p_atmo_config;
1985 vlc_mutex_destroy( &p_sys->filter_lock );
1992 function stolen from some other videolan source filter ;-)
1993 for the moment RGB is OK... but better would be a direct transformation
1996 static inline void yuv_to_rgb( uint8_t *r, uint8_t *g, uint8_t *b,
1997 uint8_t y1, uint8_t u1, uint8_t v1 )
1999 /* macros used for YUV pixel conversions */
2000 # define SCALEBITS 10
2001 # define ONE_HALF (1 << (SCALEBITS - 1))
2002 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
2003 # define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
2005 int y, cb, cr, r_add, g_add, b_add;
2009 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
2010 g_add = - FIX(0.34414*255.0/224.0) * cb
2011 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
2012 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
2013 y = (y1 - 16) * FIX(255.0/219.0);
2014 *r = CLAMP((y + r_add) >> SCALEBITS);
2015 *g = CLAMP((y + g_add) >> SCALEBITS);
2016 *b = CLAMP((y + b_add) >> SCALEBITS);
2018 /******************************************************************************
2019 * ExtractMiniImage_YUV: extract a small image from the picture as 24-bit RGB
2020 *******************************************************************************
2021 * p_sys is a pointer to
2022 * p_inpic is the source frame
2023 * p_transfer_dest is the target buffer for the picture must be big enough!
2024 * (in win32 enviroment this buffer comes from the external DLL where it is
2025 * create as "variant array" and returned through the AtmoLockTransferbuffer
2027 static void ExtractMiniImage_YUV(filter_sys_t *p_sys,
2029 uint8_t *p_transfer_dest)
2036 uint8_t *p_rgb_dst_line_red;
2037 uint8_t *p_rgb_dst_line_green;
2038 uint8_t *p_rgb_dst_line_blue;
2043 /* calcute Pointers for Storage of B G R (A) */
2044 p_rgb_dst_line_blue = p_transfer_dest;
2045 p_rgb_dst_line_green = p_transfer_dest + 1;
2046 p_rgb_dst_line_red = p_transfer_dest + 2 ;
2048 int i_row_count = p_sys->i_atmo_height + 1;
2049 int i_col_count = p_sys->i_atmo_width + 1;
2050 int i_y_row,i_u_row,i_v_row,i_pixel_row;
2054 /* these two ugly loops extract the small image - goes it faster? how?
2055 the loops are so designed that there is a small border around the extracted
2056 image so we wont get column and row - zero from the frame, and not the most
2057 right and bottom pixels --- which may be clipped on computers useing TV out
2060 TODO: try to find out if the output is clipped through VLC - and try here
2061 to ingore the clipped away area for a better result!
2063 TODO: performance improvement in InitFilter percalculated the offsets of
2064 the lines inside the planes so I can save (i_row_count * 3) 2xMUL and
2065 one time DIV the same could be done for the inner loop I think...
2067 for(i_row = 1; i_row < i_row_count; i_row++)
2069 // calcute the current Lines in the source planes for this outputrow
2070 /* Adresscalcuation pointer to plane Length of one pixelrow in bytes
2071 calculate row now number
2074 p_inpic->format? transform Pixel row into row of plane...
2075 how? simple? fast? good?
2078 /* compute the source pixel row and respect the active cropping */
2079 i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
2080 + p_sys->i_crop_y_offset;
2083 trans for these Pixel row into the row of each plane ..
2084 because planesize can differ from image size
2086 i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
2087 p_inpic->format.i_visible_height;
2089 i_u_row = (i_pixel_row * p_inpic->p[U_PLANE].i_visible_lines) /
2090 p_inpic->format.i_visible_height;
2092 i_v_row = (i_pixel_row * p_inpic->p[V_PLANE].i_visible_lines) /
2093 p_inpic->format.i_visible_height;
2095 /* calculate the pointers to the pixeldata for this row
2098 p_src_y = p_inpic->p[Y_PLANE].p_pixels +
2099 p_inpic->p[Y_PLANE].i_pitch * i_y_row;
2100 p_src_u = p_inpic->p[U_PLANE].p_pixels +
2101 p_inpic->p[U_PLANE].i_pitch * i_u_row;
2102 p_src_v = p_inpic->p[V_PLANE].p_pixels +
2103 p_inpic->p[V_PLANE].i_pitch * i_v_row;
2105 for(i_col = 1; i_col < i_col_count; i_col++)
2107 i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
2108 p_sys->i_crop_x_offset;
2110 trans for these Pixel row into the row of each plane ..
2111 because planesize can differ from image size
2113 i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
2114 p_inpic->format.i_visible_width;
2115 i_xpos_u = (i_pixel_col * p_inpic->p[U_PLANE].i_visible_pitch) /
2116 p_inpic->format.i_visible_width;
2117 i_xpos_v = (i_pixel_col * p_inpic->p[V_PLANE].i_visible_pitch) /
2118 p_inpic->format.i_visible_width;
2120 yuv_to_rgb(p_rgb_dst_line_red,
2121 p_rgb_dst_line_green,
2122 p_rgb_dst_line_blue,
2128 /* +4 because output image should be RGB32 with dword alignment! */
2129 p_rgb_dst_line_red += 4;
2130 p_rgb_dst_line_green += 4;
2131 p_rgb_dst_line_blue += 4;
2135 if(p_sys->b_show_dots)
2137 for(i_row = 1; i_row < i_row_count; i_row++)
2139 i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
2140 + p_sys->i_crop_y_offset;
2142 i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
2143 p_inpic->format.i_visible_height;
2145 p_src_y = p_inpic->p[Y_PLANE].p_pixels +
2146 p_inpic->p[Y_PLANE].i_pitch * i_y_row;
2148 for(i_col = 1; i_col < i_col_count; i_col++)
2150 i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
2151 p_sys->i_crop_x_offset;
2152 i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
2153 p_inpic->format.i_visible_width;
2155 p_src_y[i_xpos_y] = 255;
2163 /******************************************************************************
2164 * SaveBitmap: Saves the content of a transferbuffer as Bitmap to disk
2165 *******************************************************************************
2166 * just for debugging
2167 * p_sys -> configuration if Atmo from there the function will get height and
2169 * p_pixels -> should be the dword aligned BGR(A) image data
2170 * psz_filename -> filename where to store
2172 #if defined(__ATMO_DEBUG__)
2173 void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename)
2175 /* for debug out only used*/
2176 BITMAPINFO bmp_info;
2177 BITMAPFILEHEADER bmp_fileheader;
2180 memset(&bmp_info, 0, sizeof(BITMAPINFO));
2181 bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2182 bmp_info.bmiHeader.biSizeImage = p_sys->i_atmo_height *
2183 p_sys->i_atmo_width * 4;
2184 bmp_info.bmiHeader.biCompression = BI_RGB;
2185 bmp_info.bmiHeader.biWidth = p_sys->i_atmo_width;
2186 bmp_info.bmiHeader.biHeight = -p_sys->i_atmo_height;
2187 bmp_info.bmiHeader.biBitCount = 32;
2188 bmp_info.bmiHeader.biPlanes = 1;
2190 bmp_fileheader.bfReserved1 = 0;
2191 bmp_fileheader.bfReserved2 = 0;
2192 bmp_fileheader.bfSize = sizeof(BITMAPFILEHEADER) +
2193 sizeof(BITMAPINFOHEADER) +
2194 bmp_info.bmiHeader.biSizeImage;
2195 bmp_fileheader.bfType = VLC_TWOCC('B','M');
2196 bmp_fileheader.bfOffBits = sizeof(BITMAPFILEHEADER) +
2197 sizeof(BITMAPINFOHEADER);
2199 fp_bitmap = fopen(psz_filename,"wb");
2200 if( fp_bitmap != NULL)
2202 fwrite(&bmp_fileheader, sizeof(BITMAPFILEHEADER), 1, fp_bitmap);
2203 fwrite(&bmp_info.bmiHeader, sizeof(BITMAPINFOHEADER), 1, fp_bitmap);
2204 fwrite(p_pixels, bmp_info.bmiHeader.biSizeImage, 1, fp_bitmap);
2211 /****************************************************************************
2212 * CreateMiniImage: extracts a 64x48 pixel image from the frame
2213 * (there is a small border arround thats why the loops starts with one
2214 * instead zero) without any interpolation
2215 *****************************************************************************/
2216 static void CreateMiniImage( filter_t *p_filter, picture_t *p_inpic)
2218 filter_sys_t *p_sys = p_filter->p_sys;
2220 pointer to RGB Buffer created in external libary as safe array which
2221 is locked inside AtmoLockTransferBuffer
2223 uint8_t *p_transfer;
2224 #if defined( __ATMO_DEBUG__ )
2225 /* for debug out only used*/
2226 char sz_filename[MAX_PATH];
2230 Lock the before created VarArray (AtmoCreateTransferBuffers)
2231 inside my wrapper library and give me a pointer to the buffer!
2232 below linux a global buffer may be used and protected with a mutex?
2234 p_transfer = AtmoLockTransferBuffer(p_filter);
2235 if(p_transfer == NULL)
2237 msg_Err( p_filter, "AtmoLight no transferbuffer available. "\
2238 "AtmoLight will be disabled!");
2239 p_sys->b_enabled = false;
2244 do the call via pointer to function instead of having a
2247 p_sys->pf_extract_mini_image(p_sys, p_inpic, p_transfer);
2250 #if defined( __ATMO_DEBUG__ )
2252 if debugging enabled save every 128th image to disk
2254 if((p_sys->b_saveframes == true) && (p_sys->sz_framepath[0] != 0 ))
2257 if((p_sys->ui_frame_counter & 127) == 0)
2259 sprintf(sz_filename,"%satmo_dbg_%06u.bmp",p_sys->sz_framepath,
2260 p_sys->ui_frame_counter);
2261 msg_Dbg(p_filter, "SaveFrame %s",sz_filename);
2263 SaveBitmap(p_sys, p_transfer, sz_filename);
2267 msg_Dbg( p_filter, "AtmoFrame %u Time: %d ms", p_sys->ui_frame_counter,
2269 p_sys->ui_frame_counter++;
2272 p_sys->i_frames_processed++;
2275 /* show the colors on the wall */
2276 AtmoSendPixelData( p_filter );
2282 /*****************************************************************************
2283 * Filter: calls the extract method and forwards the incomming picture 1:1
2284 *****************************************************************************
2286 *****************************************************************************/
2288 static picture_t * Filter( filter_t *p_filter, picture_t *p_pic )
2290 filter_sys_t *p_sys = p_filter->p_sys;
2291 if( !p_pic ) return NULL;
2293 vlc_mutex_lock( &p_sys->filter_lock );
2295 if((p_sys->b_enabled == true) &&
2296 (p_sys->pf_extract_mini_image != NULL) &&
2297 (p_sys->b_pause_live == false))
2299 p_sys->i_crop_x_offset = p_filter->fmt_in.video.i_x_offset;
2300 p_sys->i_crop_y_offset = p_filter->fmt_in.video.i_y_offset;
2301 p_sys->i_crop_width = p_filter->fmt_in.video.i_visible_width;
2302 p_sys->i_crop_height = p_filter->fmt_in.video.i_visible_height;
2304 CreateMiniImage(p_filter, p_pic);
2307 vlc_mutex_unlock( &p_sys->filter_lock );
2315 /*****************************************************************************
2316 * FadeToColorThread: Threadmethod which changes slowly the color
2317 * to a target color defined in p_fadethread struct
2318 * use for: Fade to Pause Color, and Fade to End Color
2319 *****************************************************************************/
2320 static void *FadeToColorThread(vlc_object_t *obj)
2322 fadethread_t *p_fadethread = (fadethread_t *)obj;
2323 filter_sys_t *p_sys = (filter_sys_t *)p_fadethread->p_filter->p_sys;
2324 int i_steps_done = 0;
2334 uint8_t *p_source = NULL;
2336 int canc = vlc_savecancel ();
2337 /* initialize AtmoWin for this thread! */
2338 AtmoInitialize(p_fadethread->p_filter , true);
2340 uint8_t *p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
2341 if(p_transfer != NULL) {
2342 /* safe colors as "32bit" Integers to avoid overflows*/
2343 i_pause_red = p_fadethread->ui_red;
2344 i_pause_blue = p_fadethread->ui_blue;
2345 i_pause_green = p_fadethread->ui_green;
2348 allocate a temporary buffer for the last send
2349 image size less then 15kb
2351 int i_size = 4 * p_sys->i_atmo_width * p_sys->i_atmo_height;
2352 p_source = (uint8_t *)malloc( i_size );
2353 if(p_source != NULL)
2356 get a copy of the last transfered image as orign for the
2359 memcpy(p_source, p_transfer, i_size);
2360 /* send the same pixel data again... to unlock the buffer! */
2361 AtmoSendPixelData( p_fadethread->p_filter );
2363 while( (vlc_object_alive (p_fadethread)) &&
2364 (i_steps_done < p_fadethread->i_steps))
2366 p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
2367 if(!p_transfer) break; /* should not happen if it worked
2368 one time in the code above! */
2371 move all pixels in the mini image (64x48) one step closer to
2372 the desired color these loop takes the most time of this
2373 thread improvements wellcome!
2376 (i_index < i_size) && (vlc_object_alive (p_fadethread));
2379 i_src_blue = p_source[i_index+0];
2380 i_src_green = p_source[i_index+1];
2381 i_src_red = p_source[i_index+2];
2382 p_transfer[i_index+0] = (uint8_t) (((
2383 (i_pause_blue - i_src_blue)
2384 * i_steps_done)/p_fadethread->i_steps)
2387 p_transfer[i_index+1] = (uint8_t) (((
2388 (i_pause_green - i_src_green)
2389 * i_steps_done)/p_fadethread->i_steps)
2392 p_transfer[i_index+2] = (uint8_t) (((
2393 (i_pause_red - i_src_red)
2394 * i_steps_done)/p_fadethread->i_steps)
2398 /* send image to lightcontroller */
2399 AtmoSendPixelData( p_fadethread->p_filter );
2400 /* is there something like and interruptable sleep inside
2401 the VLC libaries? inside native win32 I would use an Event
2402 (CreateEvent) and here an WaitForSingleObject?
2408 /* in failure of malloc also unlock buffer */
2409 AtmoSendPixelData(p_fadethread->p_filter);
2412 /* call indirect to OleUnitialize() for this thread */
2413 AtmoFinalize(p_fadethread->p_filter, 0);
2414 vlc_restorecancel (canc);
2418 /*****************************************************************************
2419 * CheckAndStopFadeThread: if there is a fadethread structure left, or running.
2420 ******************************************************************************
2421 * this function will stop the thread ... and waits for its termination
2422 * before removeing the objects from vout_sys_t ...
2423 ******************************************************************************/
2424 static void CheckAndStopFadeThread(filter_t *p_filter)
2426 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2427 vlc_mutex_lock( &p_sys->filter_lock );
2428 if(p_sys->p_fadethread != NULL)
2430 msg_Dbg(p_filter, "kill still running fadeing thread...");
2432 p_sys->p_fadethread->b_die = true;
2434 vlc_thread_join(p_sys->p_fadethread);
2436 vlc_object_release(p_sys->p_fadethread);
2437 p_sys->p_fadethread = NULL;
2439 vlc_mutex_unlock( &p_sys->filter_lock );
2442 /*****************************************************************************
2443 * StateCallback: Callback for the inputs variable "State" to get notified
2444 * about Pause and Continue Playback events.
2445 *****************************************************************************/
2446 static int StateCallback( vlc_object_t *p_this, char const *psz_cmd,
2447 vlc_value_t oldval, vlc_value_t newval,
2450 filter_t *p_filter = (filter_t *)p_data;
2451 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2453 if((p_sys->b_usepausecolor == true) && (p_sys->b_enabled == true))
2455 msg_Dbg(p_filter, "state change from: %d to %d", oldval.i_int,
2458 if((newval.i_int == PAUSE_S) && (oldval.i_int == PLAYING_S))
2460 /* tell the other thread to stop sending images to light
2462 p_sys->b_pause_live = true;
2464 // clean up old thread - should not happen....
2465 CheckAndStopFadeThread( p_filter );
2467 // perpare spawn fadeing thread
2468 vlc_mutex_lock( &p_sys->filter_lock );
2470 launch only a new thread if there is none active!
2471 or waiting for cleanup
2473 if(p_sys->p_fadethread == NULL)
2475 p_sys->p_fadethread = (fadethread_t *)vlc_object_create(
2477 sizeof(fadethread_t) );
2479 p_sys->p_fadethread->p_filter = p_filter;
2480 p_sys->p_fadethread->ui_red = p_sys->ui_pausecolor_red;
2481 p_sys->p_fadethread->ui_green = p_sys->ui_pausecolor_green;
2482 p_sys->p_fadethread->ui_blue = p_sys->ui_pausecolor_blue;
2483 p_sys->p_fadethread->i_steps = p_sys->i_fadesteps;
2485 if( vlc_thread_create( p_sys->p_fadethread,
2486 "AtmoLight fadeing",
2488 VLC_THREAD_PRIORITY_LOW ) )
2490 msg_Err( p_filter, "cannot create FadeToColorThread" );
2491 vlc_object_release( p_sys->p_fadethread );
2492 p_sys->p_fadethread = NULL;
2495 vlc_mutex_unlock( &p_sys->filter_lock );
2498 if((newval.i_int == PLAYING_S) && (oldval.i_int == PAUSE_S))
2500 /* playback continues check thread state */
2501 CheckAndStopFadeThread( p_filter );
2502 /* reactivate the Render function... to do its normal work */
2503 p_sys->b_pause_live = false;
2510 /*****************************************************************************
2511 * AddPlaylistInputThreadStateCallback: Setup call back on "State" Variable
2512 *****************************************************************************
2513 * Add Callback function to the "state" variable of the input thread..
2514 * first find the PlayList and get the input thread from there to attach
2516 *****************************************************************************/
2517 static void AddStateVariableCallback(filter_t *p_filter)
2519 input_thread_t *p_input = playlist_CurrentInput( pl_Get( p_filter ) );
2522 var_AddCallback( p_input, "state", StateCallback, p_filter );
2523 vlc_object_release( p_input );
2527 /*****************************************************************************
2528 * DelPlaylistInputThreadStateCallback: Remove call back on "State" Variable
2529 *****************************************************************************
2530 * Delete the callback function to the "state" variable of the input thread...
2531 * first find the PlayList and get the input thread from there to attach
2532 * my callback? is vlc_object_find the right way for this??
2533 *****************************************************************************/
2534 static void DelStateVariableCallback( filter_t *p_filter )
2536 input_thread_t *p_input = playlist_CurrentInput( pl_Get ( p_filter ) );
2539 var_DelCallback( p_input, "state", StateCallback, p_filter );
2540 vlc_object_release( p_input );
2544 /****************************************************************************
2545 * StateCallback: Callback for the inputs variable "State" to get notified
2546 * about Pause and Continue Playback events.
2547 *****************************************************************************/
2548 static int AtmoSettingsCallback( vlc_object_t *p_this, char const *psz_var,
2549 vlc_value_t oldval, vlc_value_t newval,
2552 filter_t *p_filter = (filter_t *)p_data;
2553 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2555 vlc_mutex_lock( &p_sys->filter_lock );
2557 if( !strcmp( psz_var, CFG_PREFIX "showdots" ))
2559 p_sys->b_show_dots = newval.b_bool;
2562 CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
2566 msg_Dbg(p_filter, "apply AtmoSettingsCallback %s (int: %d -> %d)",
2572 if( !strcmp( psz_var, CFG_PREFIX "filtermode" ))
2573 p_atmo_config->setLiveViewFilterMode( (AtmoFilterMode)newval.i_int );
2575 else if( !strcmp( psz_var, CFG_PREFIX "percentnew" ))
2576 p_atmo_config->setLiveViewFilter_PercentNew( newval.i_int );
2578 else if( !strcmp( psz_var, CFG_PREFIX "meanlength" ))
2579 p_atmo_config->setLiveViewFilter_MeanLength( newval.i_int );
2581 else if( !strcmp( psz_var, CFG_PREFIX "meanthreshold" ))
2582 p_atmo_config->setLiveViewFilter_MeanThreshold( newval.i_int );
2584 else if( !strcmp( psz_var, CFG_PREFIX "edgeweightning" ))
2585 p_atmo_config->setLiveView_EdgeWeighting( newval.i_int );
2587 else if( !strcmp( psz_var, CFG_PREFIX "brightness" ))
2588 p_atmo_config->setLiveView_BrightCorrect( newval.i_int );
2590 else if( !strcmp( psz_var, CFG_PREFIX "darknesslimit" ))
2591 p_atmo_config->setLiveView_DarknessLimit( newval.i_int );
2593 else if( !strcmp( psz_var, CFG_PREFIX "huewinsize" ))
2594 p_atmo_config->setLiveView_HueWinSize( newval.i_int );
2596 else if( !strcmp( psz_var, CFG_PREFIX "satwinsize" ))
2597 p_atmo_config->setLiveView_SatWinSize( newval.i_int );
2599 else if( !strcmp( psz_var, CFG_PREFIX "framedelay" ))
2600 p_atmo_config->setLiveView_FrameDelay( newval.i_int );
2602 else if( !strcmp( psz_var, CFG_PREFIX "whiteadj" ))
2603 p_atmo_config->setUseSoftwareWhiteAdj( newval.b_bool );
2605 else if( !strcmp( psz_var, CFG_PREFIX "white-red" ))
2606 p_atmo_config->setWhiteAdjustment_Red( newval.i_int );
2608 else if( !strcmp( psz_var, CFG_PREFIX "white-green" ))
2609 p_atmo_config->setWhiteAdjustment_Green( newval.i_int );
2611 else if( !strcmp( psz_var, CFG_PREFIX "white-blue" ))
2612 p_atmo_config->setWhiteAdjustment_Blue( newval.i_int );
2616 vlc_mutex_unlock( &p_sys->filter_lock );
2621 static void AddAtmoSettingsVariablesCallbacks(filter_t *p_filter)
2623 var_AddCallback( p_filter, CFG_PREFIX "filtermode",
2624 AtmoSettingsCallback, p_filter );
2625 var_AddCallback( p_filter, CFG_PREFIX "percentnew",
2626 AtmoSettingsCallback, p_filter );
2629 var_AddCallback( p_filter, CFG_PREFIX "meanlength",
2630 AtmoSettingsCallback, p_filter );
2631 var_AddCallback( p_filter, CFG_PREFIX "meanthreshold",
2632 AtmoSettingsCallback, p_filter );
2634 var_AddCallback( p_filter, CFG_PREFIX "edgeweightning",
2635 AtmoSettingsCallback, p_filter );
2636 var_AddCallback( p_filter, CFG_PREFIX "brightness",
2637 AtmoSettingsCallback, p_filter );
2638 var_AddCallback( p_filter, CFG_PREFIX "darknesslimit",
2639 AtmoSettingsCallback, p_filter );
2641 var_AddCallback( p_filter, CFG_PREFIX "huewinsize",
2642 AtmoSettingsCallback, p_filter );
2643 var_AddCallback( p_filter, CFG_PREFIX "satwinsize",
2644 AtmoSettingsCallback, p_filter );
2645 var_AddCallback( p_filter, CFG_PREFIX "framedelay",
2646 AtmoSettingsCallback, p_filter );
2649 var_AddCallback( p_filter, CFG_PREFIX "whiteadj",
2650 AtmoSettingsCallback, p_filter );
2651 var_AddCallback( p_filter, CFG_PREFIX "white-red",
2652 AtmoSettingsCallback, p_filter );
2653 var_AddCallback( p_filter, CFG_PREFIX "white-green",
2654 AtmoSettingsCallback, p_filter );
2655 var_AddCallback( p_filter, CFG_PREFIX "white-blue",
2656 AtmoSettingsCallback, p_filter );
2658 var_AddCallback( p_filter, CFG_PREFIX "showdots",
2659 AtmoSettingsCallback, p_filter );
2663 static void DelAtmoSettingsVariablesCallbacks( filter_t *p_filter )
2666 var_DelCallback( p_filter, CFG_PREFIX "filtermode",
2667 AtmoSettingsCallback, p_filter );
2669 var_DelCallback( p_filter, CFG_PREFIX "percentnew",
2670 AtmoSettingsCallback, p_filter );
2671 var_DelCallback( p_filter, CFG_PREFIX "meanlength",
2672 AtmoSettingsCallback, p_filter );
2673 var_DelCallback( p_filter, CFG_PREFIX "meanthreshold",
2674 AtmoSettingsCallback, p_filter );
2676 var_DelCallback( p_filter, CFG_PREFIX "edgeweightning",
2677 AtmoSettingsCallback, p_filter );
2678 var_DelCallback( p_filter, CFG_PREFIX "brightness",
2679 AtmoSettingsCallback, p_filter );
2680 var_DelCallback( p_filter, CFG_PREFIX "darknesslimit",
2681 AtmoSettingsCallback, p_filter );
2683 var_DelCallback( p_filter, CFG_PREFIX "huewinsize",
2684 AtmoSettingsCallback, p_filter );
2685 var_DelCallback( p_filter, CFG_PREFIX "satwinsize",
2686 AtmoSettingsCallback, p_filter );
2687 var_DelCallback( p_filter, CFG_PREFIX "framedelay",
2688 AtmoSettingsCallback, p_filter );
2691 var_DelCallback( p_filter, CFG_PREFIX "whiteadj",
2692 AtmoSettingsCallback, p_filter );
2693 var_DelCallback( p_filter, CFG_PREFIX "white-red",
2694 AtmoSettingsCallback, p_filter );
2695 var_DelCallback( p_filter, CFG_PREFIX "white-green",
2696 AtmoSettingsCallback, p_filter );
2697 var_DelCallback( p_filter, CFG_PREFIX "white-blue",
2698 AtmoSettingsCallback, p_filter );
2700 var_DelCallback( p_filter, CFG_PREFIX "showdots",
2701 AtmoSettingsCallback, p_filter );
2706 #if defined(__ATMO_DEBUG__)
2707 static void atmo_parse_crop(char *psz_cropconfig,
2708 video_format_t fmt_in,
2709 video_format_t fmt_render,
2710 int &i_visible_width, int &i_visible_height,
2711 int &i_x_offset, int &i_y_offset )
2713 int64_t i_aspect_num, i_aspect_den;
2714 unsigned int i_width, i_height;
2716 i_visible_width = fmt_in.i_visible_width;
2717 i_visible_height = fmt_in.i_visible_height;
2718 i_x_offset = fmt_in.i_x_offset;
2719 i_y_offset = fmt_in.i_y_offset;
2721 char *psz_end = NULL, *psz_parser = strchr( psz_cropconfig, ':' );
2724 /* We're using the 3:4 syntax */
2725 i_aspect_num = strtol( psz_cropconfig, &psz_end, 10 );
2726 if( psz_end == psz_cropconfig || !i_aspect_num ) return;
2728 i_aspect_den = strtol( ++psz_parser, &psz_end, 10 );
2729 if( psz_end == psz_parser || !i_aspect_den ) return;
2731 i_width = fmt_in.i_sar_den * fmt_render.i_visible_height *
2732 i_aspect_num / i_aspect_den / fmt_in.i_sar_num;
2734 i_height = fmt_render.i_visible_width*fmt_in.i_sar_num *
2735 i_aspect_den / i_aspect_num / fmt_in.i_sar_den;
2737 if( i_width < fmt_render.i_visible_width )
2739 i_x_offset = fmt_render.i_x_offset +
2740 (fmt_render.i_visible_width - i_width) / 2;
2741 i_visible_width = i_width;
2745 i_y_offset = fmt_render.i_y_offset +
2746 (fmt_render.i_visible_height - i_height) / 2;
2747 i_visible_height = i_height;
2752 psz_parser = strchr( psz_cropconfig, 'x' );
2755 /* Maybe we're using the <width>x<height>+<left>+<top> syntax */
2756 unsigned int i_crop_width, i_crop_height, i_crop_top, i_crop_left;
2758 i_crop_width = strtol( psz_cropconfig, &psz_end, 10 );
2759 if( psz_end != psz_parser ) return;
2761 psz_parser = strchr( ++psz_end, '+' );
2762 i_crop_height = strtol( psz_end, &psz_end, 10 );
2763 if( psz_end != psz_parser ) return;
2765 psz_parser = strchr( ++psz_end, '+' );
2766 i_crop_left = strtol( psz_end, &psz_end, 10 );
2767 if( psz_end != psz_parser ) return;
2770 i_crop_top = strtol( psz_end, &psz_end, 10 );
2771 if( *psz_end != '\0' ) return;
2773 i_width = i_crop_width;
2774 i_visible_width = i_width;
2776 i_height = i_crop_height;
2777 i_visible_height = i_height;
2779 i_x_offset = i_crop_left;
2780 i_y_offset = i_crop_top;
2784 /* Maybe we're using the <left>+<top>+<right>+<bottom> syntax */
2785 unsigned int i_crop_top, i_crop_left, i_crop_bottom, i_crop_right;
2787 psz_parser = strchr( psz_cropconfig, '+' );
2788 i_crop_left = strtol( psz_cropconfig, &psz_end, 10 );
2789 if( psz_end != psz_parser ) return;
2791 psz_parser = strchr( ++psz_end, '+' );
2792 i_crop_top = strtol( psz_end, &psz_end, 10 );
2793 if( psz_end != psz_parser ) return;
2795 psz_parser = strchr( ++psz_end, '+' );
2796 i_crop_right = strtol( psz_end, &psz_end, 10 );
2797 if( psz_end != psz_parser ) return;
2800 i_crop_bottom = strtol( psz_end, &psz_end, 10 );
2801 if( *psz_end != '\0' ) return;
2803 i_width = fmt_render.i_visible_width -
2806 i_visible_width = i_width;
2808 i_height = fmt_render.i_visible_height -
2811 i_visible_height = i_height;
2813 i_x_offset = i_crop_left;
2814 i_y_offset = i_crop_top;