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,"AtmoCreateTransferBuffers");
1655 if(!p_sys->pf_ctrl_atmo_create_transfer_buffers)
1656 msg_Err( p_filter, "export AtmoCreateTransferBuffers missing.");
1658 p_sys->pf_ctrl_atmo_lock_transfer_buffer=
1659 (uint8_t*(*) (void))GetProcAddress(p_sys->h_AtmoCtrl,
1660 "AtmoLockTransferBuffer");
1661 if(!p_sys->pf_ctrl_atmo_lock_transfer_buffer)
1662 msg_Err( p_filter, "export AtmoLockTransferBuffer missing.");
1664 p_sys->pf_ctrl_atmo_send_pixel_data =
1665 (void (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,
1666 "AtmoSendPixelData");
1667 if(!p_sys->pf_ctrl_atmo_send_pixel_data)
1668 msg_Err( p_filter, "export AtmoSendPixelData missing.");
1670 p_sys->pf_ctrl_atmo_get_image_size =
1671 (void (*)(int32_t*,int32_t*))GetProcAddress(p_sys->h_AtmoCtrl,
1672 "AtmoWinGetImageSize");
1673 if(!p_sys->pf_ctrl_atmo_get_image_size)
1674 msg_Err( p_filter, "export AtmoWinGetImageSize missing.");
1677 /* the DLL is missing try internal filter ...*/
1679 "AtmoCtrlLib.dll missing fallback to internal atmo classic driver");
1680 p_sys->i_device_type = 1;
1685 if(p_sys->i_device_type >= 1) {
1686 msg_Dbg( p_filter, "try use buildin driver %d ", p_sys->i_device_type);
1688 now we have to read a lof of options from the config dialog
1689 most important the serial device if not set ... we can skip
1690 the rest and disable the filter...
1693 p_sys->p_atmo_config = new CAtmoConfig();
1695 p_sys->p_atmo_dyndata = new CAtmoDynData(
1696 (vlc_object_t *)p_filter,
1697 p_sys->p_atmo_config
1700 Atmo_SetupConfig( p_filter, p_sys->p_atmo_config );
1701 switch(p_sys->i_device_type)
1704 p_sys->p_atmo_config->setConnectionType( actClassicAtmo );
1708 p_sys->p_atmo_config->setConnectionType( actMultiAtmo );
1712 p_sys->p_atmo_config->setConnectionType( actDMX );
1716 p_sys->p_atmo_config->setConnectionType( actMoMoLight );
1720 p_sys->p_atmo_config->setConnectionType( actFnordlicht );
1724 msg_Warn( p_filter, "invalid device type %d found",
1725 p_sys->i_device_type );
1728 msg_Dbg( p_filter, "buildin driver config set");
1732 switch( p_filter->fmt_in.video.i_chroma )
1734 case VLC_CODEC_I420:
1735 case VLC_CODEC_YV12:
1736 p_sys->pf_extract_mini_image = ExtractMiniImage_YUV;
1739 msg_Warn( p_filter, "InitFilter-unsupported chroma: %4.4s",
1740 (char *)&p_filter->fmt_in.video.i_chroma);
1741 p_sys->pf_extract_mini_image = NULL;
1745 for debugging purpose show the samplinggrid on each frame as
1748 p_sys->b_show_dots = var_CreateGetBoolCommand( p_filter,
1749 CFG_PREFIX "showdots"
1752 #if defined(__ATMO_DEBUG__)
1753 /* save debug images to a folder as Bitmap files ? */
1754 p_sys->b_saveframes = var_CreateGetBoolCommand( p_filter,
1755 CFG_PREFIX "saveframes"
1757 msg_Dbg(p_filter,"saveframes = %d", (int)p_sys->b_saveframes);
1760 read debug image folder from config
1762 psz_path = var_CreateGetStringCommand( p_filter, CFG_PREFIX "framepath" );
1763 if(psz_path != NULL)
1765 strcpy(p_sys->sz_framepath, psz_path);
1766 #if defined( WIN32 )
1767 size_t i_strlen = strlen(p_sys->sz_framepath);
1768 if((i_strlen>0) && (p_sys->sz_framepath[i_strlen-1] != '\\'))
1770 p_sys->sz_framepath[i_strlen] = '\\';
1771 p_sys->sz_framepath[i_strlen+1] = 0;
1776 msg_Dbg(p_filter,"saveframesfolder %s",p_sys->sz_framepath);
1781 because atmowin could also be used for lighten up the room - I think if you
1782 pause the video it would be useful to get a little bit more light into to
1783 your living room? - instead switching on a lamp?
1785 p_sys->b_usepausecolor = var_CreateGetBoolCommand( p_filter,
1786 CFG_PREFIX "usepausecolor" );
1787 p_sys->ui_pausecolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1788 CFG_PREFIX "pcolor-red");
1789 p_sys->ui_pausecolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1790 CFG_PREFIX "pcolor-green");
1791 p_sys->ui_pausecolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1792 CFG_PREFIX "pcolor-blue");
1793 p_sys->i_fadesteps = var_CreateGetIntegerCommand( p_filter,
1794 CFG_PREFIX "fadesteps");
1795 if(p_sys->i_fadesteps < 1)
1796 p_sys->i_fadesteps = 1;
1797 msg_Dbg(p_filter,"use pause color %d, RGB: %d, %d, %d, Fadesteps: %d",
1798 (int)p_sys->b_usepausecolor,
1799 p_sys->ui_pausecolor_red,
1800 p_sys->ui_pausecolor_green,
1801 p_sys->ui_pausecolor_blue,
1802 p_sys->i_fadesteps);
1805 this color is use on shutdown of the filter - the define the
1806 final light after playback... may be used to dim up the light -
1807 how it happens in the cinema...
1809 p_sys->ui_endcolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1810 CFG_PREFIX "ecolor-red");
1811 p_sys->ui_endcolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1812 CFG_PREFIX "ecolor-green");
1813 p_sys->ui_endcolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1814 CFG_PREFIX "ecolor-blue");
1815 p_sys->i_endfadesteps = var_CreateGetIntegerCommand( p_filter,
1816 CFG_PREFIX "efadesteps");
1817 if(p_sys->i_endfadesteps < 1)
1818 p_sys->i_endfadesteps = 1;
1819 msg_Dbg(p_filter,"use ende color RGB: %d, %d, %d, Fadesteps: %d",
1820 p_sys->ui_endcolor_red,
1821 p_sys->ui_endcolor_green,
1822 p_sys->ui_endcolor_blue,
1823 p_sys->i_endfadesteps);
1828 if the external DLL was loaded successfully call AtmoInitialize -
1829 (must be done for each thread where you want to use AtmoLight!)
1831 int i = AtmoInitialize(p_filter, false);
1833 #if defined( WIN32 )
1834 if((i != 1) && (p_sys->i_device_type == 0))
1837 COM Server for AtmoLight not running ?
1838 if the exe path is configured try to start the "userspace" driver
1840 psz_path = var_CreateGetStringCommand( p_filter,
1841 CFG_PREFIX "atmowinexe" );
1842 if(psz_path != NULL)
1844 STARTUPINFO startupinfo;
1845 PROCESS_INFORMATION pinfo;
1846 memset(&startupinfo, 0, sizeof(STARTUPINFO));
1847 startupinfo.cb = sizeof(STARTUPINFO);
1848 if(CreateProcess(psz_path, NULL, NULL, NULL,
1849 FALSE, 0, NULL, NULL, &startupinfo, &pinfo) == TRUE)
1851 msg_Dbg(p_filter,"launched AtmoWin from %s",psz_path);
1852 WaitForInputIdle(pinfo.hProcess, 5000);
1854 retry to initialize the library COM ... functionality
1855 after the server was launched
1857 i = AtmoInitialize(p_filter, false);
1859 msg_Err(p_filter,"failed to launch AtmoWin from %s", psz_path);
1866 if(i == 1) /* Init Atmolight success... */
1868 msg_Dbg( p_filter, "AtmoInitialize Ok!");
1871 p_sys->i_atmo_width and p_sys->i_atmo_height
1872 if the external AtmoWinA.exe is used, it may require
1873 a other sample image size than 64 x 48
1874 (this overrides the settings of the filter)
1876 Atmo_SetupImageSize( p_filter );
1879 if( p_sys->i_device_type >= 1 )
1882 AtmoConnection class initialized now we can initialize
1883 the default zone and channel mappings
1885 Atmo_SetupBuildZones( p_filter );
1888 /* Setup Transferbuffers for 64 x 48 , RGB with 32bit Per Pixel */
1889 AtmoCreateTransferBuffers(p_filter, BI_RGB, 4,
1890 p_sys->i_atmo_width,
1891 p_sys->i_atmo_height
1894 /* say the userspace driver that a live mode should be activated
1895 the functions returns the old mode for later restore!
1896 - the buildin driver launches the live view thread in that case
1898 p_sys->i_AtmoOldEffect = AtmoSwitchEffect(p_filter, emLivePicture);
1901 live view can have two differnt source the AtmoWinA
1902 internal GDI Screencapture and the external one - which we
1905 AtmoSetLiveSource(p_filter, lvsExternal);
1907 /* enable other parts only if everything is fine */
1908 p_sys->b_enabled = true;
1910 msg_Dbg( p_filter, "Atmo Filter Enabled Ok!");
1916 /*****************************************************************************
1917 * CreateFilter: allocates AtmoLight video thread output method
1918 *****************************************************************************
1919 * This function allocates and initializes a AtmoLight vout method.
1920 *****************************************************************************/
1921 static int CreateFilter( vlc_object_t *p_this )
1923 filter_t *p_filter = (filter_t *)p_this;
1924 filter_sys_t *p_sys;
1926 /* Allocate structure */
1927 p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) );
1928 p_filter->p_sys = p_sys;
1929 if( p_filter->p_sys == NULL )
1931 /* set all entries to zero */
1932 memset(p_sys, 0, sizeof( filter_sys_t ));
1933 vlc_mutex_init( &p_sys->filter_lock );
1935 msg_Dbg( p_filter, "Create Atmo Filter");
1937 /* further Setup Function pointers for videolan for calling my filter */
1938 p_filter->pf_video_filter = Filter;
1940 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
1943 AddStateVariableCallback(p_filter);
1945 AddAtmoSettingsVariablesCallbacks(p_filter);
1947 Atmo_SetupParameters(p_filter);
1955 /*****************************************************************************
1956 * DestroyFilter: destroy AtmoLight video thread output method
1957 *****************************************************************************
1958 * Terminate an output method created by CreateFilter
1959 *****************************************************************************/
1961 static void DestroyFilter( vlc_object_t *p_this )
1963 filter_t *p_filter = (filter_t *)p_this;
1964 filter_sys_t *p_sys = p_filter->p_sys;
1966 msg_Dbg( p_filter, "Destroy Atmo Filter");
1968 DelStateVariableCallback(p_filter);
1970 DelAtmoSettingsVariablesCallbacks(p_filter);
1972 Atmo_Shutdown(p_filter);
1974 #if defined( WIN32 )
1975 if(p_sys->h_AtmoCtrl != NULL)
1977 FreeLibrary(p_sys->h_AtmoCtrl);
1981 delete p_sys->p_atmo_dyndata;
1982 delete p_sys->p_atmo_config;
1984 vlc_mutex_destroy( &p_sys->filter_lock );
1991 function stolen from some other videolan source filter ;-)
1992 for the moment RGB is OK... but better would be a direct transformation
1995 static inline void yuv_to_rgb( uint8_t *r, uint8_t *g, uint8_t *b,
1996 uint8_t y1, uint8_t u1, uint8_t v1 )
1998 /* macros used for YUV pixel conversions */
1999 # define SCALEBITS 10
2000 # define ONE_HALF (1 << (SCALEBITS - 1))
2001 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
2002 # define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
2004 int y, cb, cr, r_add, g_add, b_add;
2008 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
2009 g_add = - FIX(0.34414*255.0/224.0) * cb
2010 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
2011 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
2012 y = (y1 - 16) * FIX(255.0/219.0);
2013 *r = CLAMP((y + r_add) >> SCALEBITS);
2014 *g = CLAMP((y + g_add) >> SCALEBITS);
2015 *b = CLAMP((y + b_add) >> SCALEBITS);
2017 /******************************************************************************
2018 * ExtractMiniImage_YUV: extract a small image from the picture as 24-bit RGB
2019 *******************************************************************************
2020 * p_sys is a pointer to
2021 * p_inpic is the source frame
2022 * p_transfer_dest is the target buffer for the picture must be big enough!
2023 * (in win32 enviroment this buffer comes from the external DLL where it is
2024 * create as "variant array" and returned through the AtmoLockTransferbuffer
2026 static void ExtractMiniImage_YUV(filter_sys_t *p_sys,
2028 uint8_t *p_transfer_dest)
2035 uint8_t *p_rgb_dst_line_red;
2036 uint8_t *p_rgb_dst_line_green;
2037 uint8_t *p_rgb_dst_line_blue;
2042 /* calcute Pointers for Storage of B G R (A) */
2043 p_rgb_dst_line_blue = p_transfer_dest;
2044 p_rgb_dst_line_green = p_transfer_dest + 1;
2045 p_rgb_dst_line_red = p_transfer_dest + 2 ;
2047 int i_row_count = p_sys->i_atmo_height + 1;
2048 int i_col_count = p_sys->i_atmo_width + 1;
2049 int i_y_row,i_u_row,i_v_row,i_pixel_row;
2053 /* these two ugly loops extract the small image - goes it faster? how?
2054 the loops are so designed that there is a small border around the extracted
2055 image so we wont get column and row - zero from the frame, and not the most
2056 right and bottom pixels --- which may be clipped on computers useing TV out
2059 TODO: try to find out if the output is clipped through VLC - and try here
2060 to ingore the clipped away area for a better result!
2062 TODO: performance improvement in InitFilter percalculated the offsets of
2063 the lines inside the planes so I can save (i_row_count * 3) 2xMUL and
2064 one time DIV the same could be done for the inner loop I think...
2066 for(i_row = 1; i_row < i_row_count; i_row++)
2068 // calcute the current Lines in the source planes for this outputrow
2069 /* Adresscalcuation pointer to plane Length of one pixelrow in bytes
2070 calculate row now number
2073 p_inpic->format? transform Pixel row into row of plane...
2074 how? simple? fast? good?
2077 /* compute the source pixel row and respect the active cropping */
2078 i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
2079 + p_sys->i_crop_y_offset;
2082 trans for these Pixel row into the row of each plane ..
2083 because planesize can differ from image size
2085 i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
2086 p_inpic->format.i_visible_height;
2088 i_u_row = (i_pixel_row * p_inpic->p[U_PLANE].i_visible_lines) /
2089 p_inpic->format.i_visible_height;
2091 i_v_row = (i_pixel_row * p_inpic->p[V_PLANE].i_visible_lines) /
2092 p_inpic->format.i_visible_height;
2094 /* calculate the pointers to the pixeldata for this row
2097 p_src_y = p_inpic->p[Y_PLANE].p_pixels +
2098 p_inpic->p[Y_PLANE].i_pitch * i_y_row;
2099 p_src_u = p_inpic->p[U_PLANE].p_pixels +
2100 p_inpic->p[U_PLANE].i_pitch * i_u_row;
2101 p_src_v = p_inpic->p[V_PLANE].p_pixels +
2102 p_inpic->p[V_PLANE].i_pitch * i_v_row;
2104 for(i_col = 1; i_col < i_col_count; i_col++)
2106 i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
2107 p_sys->i_crop_x_offset;
2109 trans for these Pixel row into the row of each plane ..
2110 because planesize can differ from image size
2112 i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
2113 p_inpic->format.i_visible_width;
2114 i_xpos_u = (i_pixel_col * p_inpic->p[U_PLANE].i_visible_pitch) /
2115 p_inpic->format.i_visible_width;
2116 i_xpos_v = (i_pixel_col * p_inpic->p[V_PLANE].i_visible_pitch) /
2117 p_inpic->format.i_visible_width;
2119 yuv_to_rgb(p_rgb_dst_line_red,
2120 p_rgb_dst_line_green,
2121 p_rgb_dst_line_blue,
2127 /* +4 because output image should be RGB32 with dword alignment! */
2128 p_rgb_dst_line_red += 4;
2129 p_rgb_dst_line_green += 4;
2130 p_rgb_dst_line_blue += 4;
2134 if(p_sys->b_show_dots)
2136 for(i_row = 1; i_row < i_row_count; i_row++)
2138 i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
2139 + p_sys->i_crop_y_offset;
2141 i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
2142 p_inpic->format.i_visible_height;
2144 p_src_y = p_inpic->p[Y_PLANE].p_pixels +
2145 p_inpic->p[Y_PLANE].i_pitch * i_y_row;
2147 for(i_col = 1; i_col < i_col_count; i_col++)
2149 i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
2150 p_sys->i_crop_x_offset;
2151 i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
2152 p_inpic->format.i_visible_width;
2154 p_src_y[i_xpos_y] = 255;
2162 /******************************************************************************
2163 * SaveBitmap: Saves the content of a transferbuffer as Bitmap to disk
2164 *******************************************************************************
2165 * just for debugging
2166 * p_sys -> configuration if Atmo from there the function will get height and
2168 * p_pixels -> should be the dword aligned BGR(A) image data
2169 * psz_filename -> filename where to store
2171 #if defined(__ATMO_DEBUG__)
2172 void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename)
2174 /* for debug out only used*/
2175 BITMAPINFO bmp_info;
2176 BITMAPFILEHEADER bmp_fileheader;
2179 memset(&bmp_info, 0, sizeof(BITMAPINFO));
2180 bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2181 bmp_info.bmiHeader.biSizeImage = p_sys->i_atmo_height *
2182 p_sys->i_atmo_width * 4;
2183 bmp_info.bmiHeader.biCompression = BI_RGB;
2184 bmp_info.bmiHeader.biWidth = p_sys->i_atmo_width;
2185 bmp_info.bmiHeader.biHeight = -p_sys->i_atmo_height;
2186 bmp_info.bmiHeader.biBitCount = 32;
2187 bmp_info.bmiHeader.biPlanes = 1;
2189 bmp_fileheader.bfReserved1 = 0;
2190 bmp_fileheader.bfReserved2 = 0;
2191 bmp_fileheader.bfSize = sizeof(BITMAPFILEHEADER) +
2192 sizeof(BITMAPINFOHEADER) +
2193 bmp_info.bmiHeader.biSizeImage;
2194 bmp_fileheader.bfType = VLC_TWOCC('B','M');
2195 bmp_fileheader.bfOffBits = sizeof(BITMAPFILEHEADER) +
2196 sizeof(BITMAPINFOHEADER);
2198 fp_bitmap = fopen(psz_filename,"wb");
2199 if( fp_bitmap != NULL)
2201 fwrite(&bmp_fileheader, sizeof(BITMAPFILEHEADER), 1, fp_bitmap);
2202 fwrite(&bmp_info.bmiHeader, sizeof(BITMAPINFOHEADER), 1, fp_bitmap);
2203 fwrite(p_pixels, bmp_info.bmiHeader.biSizeImage, 1, fp_bitmap);
2210 /****************************************************************************
2211 * CreateMiniImage: extracts a 64x48 pixel image from the frame
2212 * (there is a small border arround thats why the loops starts with one
2213 * instead zero) without any interpolation
2214 *****************************************************************************/
2215 static void CreateMiniImage( filter_t *p_filter, picture_t *p_inpic)
2217 filter_sys_t *p_sys = p_filter->p_sys;
2219 pointer to RGB Buffer created in external libary as safe array which
2220 is locked inside AtmoLockTransferBuffer
2222 uint8_t *p_transfer;
2223 #if defined( __ATMO_DEBUG__ )
2224 /* for debug out only used*/
2225 char sz_filename[MAX_PATH];
2229 Lock the before created VarArray (AtmoCreateTransferBuffers)
2230 inside my wrapper library and give me a pointer to the buffer!
2231 below linux a global buffer may be used and protected with a mutex?
2233 p_transfer = AtmoLockTransferBuffer(p_filter);
2234 if(p_transfer == NULL)
2236 msg_Err( p_filter, "AtmoLight no transferbuffer available. "\
2237 "AtmoLight will be disabled!");
2238 p_sys->b_enabled = false;
2243 do the call via pointer to function instead of having a
2246 p_sys->pf_extract_mini_image(p_sys, p_inpic, p_transfer);
2249 #if defined( __ATMO_DEBUG__ )
2251 if debugging enabled save every 128th image to disk
2253 if((p_sys->b_saveframes == true) && (p_sys->sz_framepath[0] != 0 ))
2256 if((p_sys->ui_frame_counter & 127) == 0)
2258 sprintf(sz_filename,"%satmo_dbg_%06u.bmp",p_sys->sz_framepath,
2259 p_sys->ui_frame_counter);
2260 msg_Dbg(p_filter, "SaveFrame %s",sz_filename);
2262 SaveBitmap(p_sys, p_transfer, sz_filename);
2266 msg_Dbg( p_filter, "AtmoFrame %u Time: %d ms", p_sys->ui_frame_counter,
2268 p_sys->ui_frame_counter++;
2271 p_sys->i_frames_processed++;
2274 /* show the colors on the wall */
2275 AtmoSendPixelData( p_filter );
2281 /*****************************************************************************
2282 * Filter: calls the extract method and forwards the incomming picture 1:1
2283 *****************************************************************************
2285 *****************************************************************************/
2287 static picture_t * Filter( filter_t *p_filter, picture_t *p_pic )
2289 filter_sys_t *p_sys = p_filter->p_sys;
2290 if( !p_pic ) return NULL;
2292 vlc_mutex_lock( &p_sys->filter_lock );
2294 if((p_sys->b_enabled == true) &&
2295 (p_sys->pf_extract_mini_image != NULL) &&
2296 (p_sys->b_pause_live == false))
2298 p_sys->i_crop_x_offset = p_filter->fmt_in.video.i_x_offset;
2299 p_sys->i_crop_y_offset = p_filter->fmt_in.video.i_y_offset;
2300 p_sys->i_crop_width = p_filter->fmt_in.video.i_visible_width;
2301 p_sys->i_crop_height = p_filter->fmt_in.video.i_visible_height;
2303 CreateMiniImage(p_filter, p_pic);
2306 vlc_mutex_unlock( &p_sys->filter_lock );
2314 /*****************************************************************************
2315 * FadeToColorThread: Threadmethod which changes slowly the color
2316 * to a target color defined in p_fadethread struct
2317 * use for: Fade to Pause Color, and Fade to End Color
2318 *****************************************************************************/
2319 static void *FadeToColorThread(vlc_object_t *obj)
2321 fadethread_t *p_fadethread = (fadethread_t *)obj;
2322 filter_sys_t *p_sys = (filter_sys_t *)p_fadethread->p_filter->p_sys;
2323 int i_steps_done = 0;
2333 uint8_t *p_source = NULL;
2335 int canc = vlc_savecancel ();
2336 /* initialize AtmoWin for this thread! */
2337 AtmoInitialize(p_fadethread->p_filter , true);
2339 uint8_t *p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
2340 if(p_transfer != NULL) {
2341 /* safe colors as "32bit" Integers to avoid overflows*/
2342 i_pause_red = p_fadethread->ui_red;
2343 i_pause_blue = p_fadethread->ui_blue;
2344 i_pause_green = p_fadethread->ui_green;
2347 allocate a temporary buffer for the last send
2348 image size less then 15kb
2350 int i_size = 4 * p_sys->i_atmo_width * p_sys->i_atmo_height;
2351 p_source = (uint8_t *)malloc( i_size );
2352 if(p_source != NULL)
2355 get a copy of the last transfered image as orign for the
2358 memcpy(p_source, p_transfer, i_size);
2359 /* send the same pixel data again... to unlock the buffer! */
2360 AtmoSendPixelData( p_fadethread->p_filter );
2362 while( (vlc_object_alive (p_fadethread)) &&
2363 (i_steps_done < p_fadethread->i_steps))
2365 p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
2366 if(!p_transfer) break; /* should not happen if it worked
2367 one time in the code above! */
2370 move all pixels in the mini image (64x48) one step closer to
2371 the desired color these loop takes the most time of this
2372 thread improvements wellcome!
2375 (i_index < i_size) && (vlc_object_alive (p_fadethread));
2378 i_src_blue = p_source[i_index+0];
2379 i_src_green = p_source[i_index+1];
2380 i_src_red = p_source[i_index+2];
2381 p_transfer[i_index+0] = (uint8_t) (((
2382 (i_pause_blue - i_src_blue)
2383 * i_steps_done)/p_fadethread->i_steps)
2386 p_transfer[i_index+1] = (uint8_t) (((
2387 (i_pause_green - i_src_green)
2388 * i_steps_done)/p_fadethread->i_steps)
2391 p_transfer[i_index+2] = (uint8_t) (((
2392 (i_pause_red - i_src_red)
2393 * i_steps_done)/p_fadethread->i_steps)
2397 /* send image to lightcontroller */
2398 AtmoSendPixelData( p_fadethread->p_filter );
2399 /* is there something like and interruptable sleep inside
2400 the VLC libaries? inside native win32 I would use an Event
2401 (CreateEvent) and here an WaitForSingleObject?
2407 /* in failure of malloc also unlock buffer */
2408 AtmoSendPixelData(p_fadethread->p_filter);
2411 /* call indirect to OleUnitialize() for this thread */
2412 AtmoFinalize(p_fadethread->p_filter, 0);
2413 vlc_restorecancel (canc);
2417 /*****************************************************************************
2418 * CheckAndStopFadeThread: if there is a fadethread structure left, or running.
2419 ******************************************************************************
2420 * this function will stop the thread ... and waits for its termination
2421 * before removeing the objects from vout_sys_t ...
2422 ******************************************************************************/
2423 static void CheckAndStopFadeThread(filter_t *p_filter)
2425 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2426 vlc_mutex_lock( &p_sys->filter_lock );
2427 if(p_sys->p_fadethread != NULL)
2429 msg_Dbg(p_filter, "kill still running fadeing thread...");
2431 p_sys->p_fadethread->b_die = true;
2433 vlc_thread_join(p_sys->p_fadethread);
2435 vlc_object_release(p_sys->p_fadethread);
2436 p_sys->p_fadethread = NULL;
2438 vlc_mutex_unlock( &p_sys->filter_lock );
2441 /*****************************************************************************
2442 * StateCallback: Callback for the inputs variable "State" to get notified
2443 * about Pause and Continue Playback events.
2444 *****************************************************************************/
2445 static int StateCallback( vlc_object_t *p_this, char const *psz_cmd,
2446 vlc_value_t oldval, vlc_value_t newval,
2449 filter_t *p_filter = (filter_t *)p_data;
2450 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2452 if((p_sys->b_usepausecolor == true) && (p_sys->b_enabled == true))
2454 msg_Dbg(p_filter, "state change from: %d to %d", oldval.i_int,
2457 if((newval.i_int == PAUSE_S) && (oldval.i_int == PLAYING_S))
2459 /* tell the other thread to stop sending images to light
2461 p_sys->b_pause_live = true;
2463 // clean up old thread - should not happen....
2464 CheckAndStopFadeThread( p_filter );
2466 // perpare spawn fadeing thread
2467 vlc_mutex_lock( &p_sys->filter_lock );
2469 launch only a new thread if there is none active!
2470 or waiting for cleanup
2472 if(p_sys->p_fadethread == NULL)
2474 p_sys->p_fadethread = (fadethread_t *)vlc_object_create(
2476 sizeof(fadethread_t) );
2478 p_sys->p_fadethread->p_filter = p_filter;
2479 p_sys->p_fadethread->ui_red = p_sys->ui_pausecolor_red;
2480 p_sys->p_fadethread->ui_green = p_sys->ui_pausecolor_green;
2481 p_sys->p_fadethread->ui_blue = p_sys->ui_pausecolor_blue;
2482 p_sys->p_fadethread->i_steps = p_sys->i_fadesteps;
2484 if( vlc_thread_create( p_sys->p_fadethread,
2485 "AtmoLight fadeing",
2487 VLC_THREAD_PRIORITY_LOW ) )
2489 msg_Err( p_filter, "cannot create FadeToColorThread" );
2490 vlc_object_release( p_sys->p_fadethread );
2491 p_sys->p_fadethread = NULL;
2494 vlc_mutex_unlock( &p_sys->filter_lock );
2497 if((newval.i_int == PLAYING_S) && (oldval.i_int == PAUSE_S))
2499 /* playback continues check thread state */
2500 CheckAndStopFadeThread( p_filter );
2501 /* reactivate the Render function... to do its normal work */
2502 p_sys->b_pause_live = false;
2509 /*****************************************************************************
2510 * AddPlaylistInputThreadStateCallback: Setup call back on "State" Variable
2511 *****************************************************************************
2512 * Add Callback function to the "state" variable of the input thread..
2513 * first find the PlayList and get the input thread from there to attach
2515 *****************************************************************************/
2516 static void AddStateVariableCallback(filter_t *p_filter)
2518 input_thread_t *p_input = playlist_CurrentInput( pl_Get( p_filter ) );
2521 var_AddCallback( p_input, "state", StateCallback, p_filter );
2522 vlc_object_release( p_input );
2526 /*****************************************************************************
2527 * DelPlaylistInputThreadStateCallback: Remove call back on "State" Variable
2528 *****************************************************************************
2529 * Delete the callback function to the "state" variable of the input thread...
2530 * first find the PlayList and get the input thread from there to attach
2531 * my callback? is vlc_object_find the right way for this??
2532 *****************************************************************************/
2533 static void DelStateVariableCallback( filter_t *p_filter )
2535 input_thread_t *p_input = playlist_CurrentInput( pl_Get ( p_filter ) );
2538 var_DelCallback( p_input, "state", StateCallback, p_filter );
2539 vlc_object_release( p_input );
2543 /****************************************************************************
2544 * StateCallback: Callback for the inputs variable "State" to get notified
2545 * about Pause and Continue Playback events.
2546 *****************************************************************************/
2547 static int AtmoSettingsCallback( vlc_object_t *p_this, char const *psz_var,
2548 vlc_value_t oldval, vlc_value_t newval,
2551 filter_t *p_filter = (filter_t *)p_data;
2552 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2554 vlc_mutex_lock( &p_sys->filter_lock );
2556 if( !strcmp( psz_var, CFG_PREFIX "showdots" ))
2558 p_sys->b_show_dots = newval.b_bool;
2561 CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
2565 msg_Dbg(p_filter, "apply AtmoSettingsCallback %s (int: %d -> %d)",
2571 if( !strcmp( psz_var, CFG_PREFIX "filtermode" ))
2572 p_atmo_config->setLiveViewFilterMode( (AtmoFilterMode)newval.i_int);
2574 else if( !strcmp( psz_var, CFG_PREFIX "percentnew" ))
2575 p_atmo_config->setLiveViewFilter_PercentNew( newval.i_int );
2577 else if( !strcmp( psz_var, CFG_PREFIX "meanlength" ))
2578 p_atmo_config->setLiveViewFilter_MeanLength( newval.i_int );
2580 else if( !strcmp( psz_var, CFG_PREFIX "meanthreshold" ))
2581 p_atmo_config->setLiveViewFilter_MeanThreshold( newval.i_int );
2583 else if( !strcmp( psz_var, CFG_PREFIX "edgeweightning" ))
2584 p_atmo_config->setLiveView_EdgeWeighting( newval.i_int );
2586 else if( !strcmp( psz_var, CFG_PREFIX "brightness" ))
2587 p_atmo_config->setLiveView_BrightCorrect( newval.i_int );
2589 else if( !strcmp( psz_var, CFG_PREFIX "darknesslimit" ))
2590 p_atmo_config->setLiveView_DarknessLimit( newval.i_int );
2592 else if( !strcmp( psz_var, CFG_PREFIX "huewinsize" ))
2593 p_atmo_config->setLiveView_HueWinSize( newval.i_int );
2595 else if( !strcmp( psz_var, CFG_PREFIX "satwinsize" ))
2596 p_atmo_config->setLiveView_SatWinSize( newval.i_int );
2598 else if( !strcmp( psz_var, CFG_PREFIX "framedelay" ))
2599 p_atmo_config->setLiveView_FrameDelay( newval.i_int );
2601 else if( !strcmp( psz_var, CFG_PREFIX "whiteadj" ))
2602 p_atmo_config->setUseSoftwareWhiteAdj( newval.b_bool );
2604 else if( !strcmp( psz_var, CFG_PREFIX "white-red" ))
2605 p_atmo_config->setWhiteAdjustment_Red( newval.i_int );
2607 else if( !strcmp( psz_var, CFG_PREFIX "white-green" ))
2608 p_atmo_config->setWhiteAdjustment_Green( newval.i_int );
2610 else if( !strcmp( psz_var, CFG_PREFIX "white-blue" ))
2611 p_atmo_config->setWhiteAdjustment_Blue( newval.i_int );
2615 vlc_mutex_unlock( &p_sys->filter_lock );
2620 static void AddAtmoSettingsVariablesCallbacks(filter_t *p_filter)
2622 var_AddCallback( p_filter, CFG_PREFIX "filtermode",
2623 AtmoSettingsCallback, p_filter );
2624 var_AddCallback( p_filter, CFG_PREFIX "percentnew",
2625 AtmoSettingsCallback, p_filter );
2628 var_AddCallback( p_filter, CFG_PREFIX "meanlength",
2629 AtmoSettingsCallback, p_filter );
2630 var_AddCallback( p_filter, CFG_PREFIX "meanthreshold",
2631 AtmoSettingsCallback, p_filter );
2633 var_AddCallback( p_filter, CFG_PREFIX "edgeweightning",
2634 AtmoSettingsCallback, p_filter );
2635 var_AddCallback( p_filter, CFG_PREFIX "brightness",
2636 AtmoSettingsCallback, p_filter );
2637 var_AddCallback( p_filter, CFG_PREFIX "darknesslimit",
2638 AtmoSettingsCallback, p_filter );
2640 var_AddCallback( p_filter, CFG_PREFIX "huewinsize",
2641 AtmoSettingsCallback, p_filter );
2642 var_AddCallback( p_filter, CFG_PREFIX "satwinsize",
2643 AtmoSettingsCallback, p_filter );
2644 var_AddCallback( p_filter, CFG_PREFIX "framedelay",
2645 AtmoSettingsCallback, p_filter );
2648 var_AddCallback( p_filter, CFG_PREFIX "whiteadj",
2649 AtmoSettingsCallback, p_filter );
2650 var_AddCallback( p_filter, CFG_PREFIX "white-red",
2651 AtmoSettingsCallback, p_filter );
2652 var_AddCallback( p_filter, CFG_PREFIX "white-green",
2653 AtmoSettingsCallback, p_filter );
2654 var_AddCallback( p_filter, CFG_PREFIX "white-blue",
2655 AtmoSettingsCallback, p_filter );
2657 var_AddCallback( p_filter, CFG_PREFIX "showdots",
2658 AtmoSettingsCallback, p_filter );
2662 static void DelAtmoSettingsVariablesCallbacks( filter_t *p_filter )
2665 var_DelCallback( p_filter, CFG_PREFIX "filtermode",
2666 AtmoSettingsCallback, p_filter );
2668 var_DelCallback( p_filter, CFG_PREFIX "percentnew",
2669 AtmoSettingsCallback, p_filter );
2670 var_DelCallback( p_filter, CFG_PREFIX "meanlength",
2671 AtmoSettingsCallback, p_filter );
2672 var_DelCallback( p_filter, CFG_PREFIX "meanthreshold",
2673 AtmoSettingsCallback, p_filter );
2675 var_DelCallback( p_filter, CFG_PREFIX "edgeweightning",
2676 AtmoSettingsCallback, p_filter );
2677 var_DelCallback( p_filter, CFG_PREFIX "brightness",
2678 AtmoSettingsCallback, p_filter );
2679 var_DelCallback( p_filter, CFG_PREFIX "darknesslimit",
2680 AtmoSettingsCallback, p_filter );
2682 var_DelCallback( p_filter, CFG_PREFIX "huewinsize",
2683 AtmoSettingsCallback, p_filter );
2684 var_DelCallback( p_filter, CFG_PREFIX "satwinsize",
2685 AtmoSettingsCallback, p_filter );
2686 var_DelCallback( p_filter, CFG_PREFIX "framedelay",
2687 AtmoSettingsCallback, p_filter );
2690 var_DelCallback( p_filter, CFG_PREFIX "whiteadj",
2691 AtmoSettingsCallback, p_filter );
2692 var_DelCallback( p_filter, CFG_PREFIX "white-red",
2693 AtmoSettingsCallback, p_filter );
2694 var_DelCallback( p_filter, CFG_PREFIX "white-green",
2695 AtmoSettingsCallback, p_filter );
2696 var_DelCallback( p_filter, CFG_PREFIX "white-blue",
2697 AtmoSettingsCallback, p_filter );
2699 var_DelCallback( p_filter, CFG_PREFIX "showdots",
2700 AtmoSettingsCallback, p_filter );
2705 #if defined(__ATMO_DEBUG__)
2706 static void atmo_parse_crop(char *psz_cropconfig,
2707 video_format_t fmt_in,
2708 video_format_t fmt_render,
2709 int &i_visible_width, int &i_visible_height,
2710 int &i_x_offset, int &i_y_offset )
2712 int64_t i_aspect_num, i_aspect_den;
2713 unsigned int i_width, i_height;
2715 i_visible_width = fmt_in.i_visible_width;
2716 i_visible_height = fmt_in.i_visible_height;
2717 i_x_offset = fmt_in.i_x_offset;
2718 i_y_offset = fmt_in.i_y_offset;
2720 char *psz_end = NULL, *psz_parser = strchr( psz_cropconfig, ':' );
2723 /* We're using the 3:4 syntax */
2724 i_aspect_num = strtol( psz_cropconfig, &psz_end, 10 );
2725 if( psz_end == psz_cropconfig || !i_aspect_num ) return;
2727 i_aspect_den = strtol( ++psz_parser, &psz_end, 10 );
2728 if( psz_end == psz_parser || !i_aspect_den ) return;
2730 i_width = fmt_in.i_sar_den * fmt_render.i_visible_height *
2731 i_aspect_num / i_aspect_den / fmt_in.i_sar_num;
2733 i_height = fmt_render.i_visible_width*fmt_in.i_sar_num *
2734 i_aspect_den / i_aspect_num / fmt_in.i_sar_den;
2736 if( i_width < fmt_render.i_visible_width )
2738 i_x_offset = fmt_render.i_x_offset +
2739 (fmt_render.i_visible_width - i_width) / 2;
2740 i_visible_width = i_width;
2744 i_y_offset = fmt_render.i_y_offset +
2745 (fmt_render.i_visible_height - i_height) / 2;
2746 i_visible_height = i_height;
2751 psz_parser = strchr( psz_cropconfig, 'x' );
2754 /* Maybe we're using the <width>x<height>+<left>+<top> syntax */
2755 unsigned int i_crop_width, i_crop_height, i_crop_top, i_crop_left;
2757 i_crop_width = strtol( psz_cropconfig, &psz_end, 10 );
2758 if( psz_end != psz_parser ) return;
2760 psz_parser = strchr( ++psz_end, '+' );
2761 i_crop_height = strtol( psz_end, &psz_end, 10 );
2762 if( psz_end != psz_parser ) return;
2764 psz_parser = strchr( ++psz_end, '+' );
2765 i_crop_left = strtol( psz_end, &psz_end, 10 );
2766 if( psz_end != psz_parser ) return;
2769 i_crop_top = strtol( psz_end, &psz_end, 10 );
2770 if( *psz_end != '\0' ) return;
2772 i_width = i_crop_width;
2773 i_visible_width = i_width;
2775 i_height = i_crop_height;
2776 i_visible_height = i_height;
2778 i_x_offset = i_crop_left;
2779 i_y_offset = i_crop_top;
2783 /* Maybe we're using the <left>+<top>+<right>+<bottom> syntax */
2784 unsigned int i_crop_top, i_crop_left, i_crop_bottom, i_crop_right;
2786 psz_parser = strchr( psz_cropconfig, '+' );
2787 i_crop_left = strtol( psz_cropconfig, &psz_end, 10 );
2788 if( psz_end != psz_parser ) return;
2790 psz_parser = strchr( ++psz_end, '+' );
2791 i_crop_top = strtol( psz_end, &psz_end, 10 );
2792 if( psz_end != psz_parser ) return;
2794 psz_parser = strchr( ++psz_end, '+' );
2795 i_crop_right = strtol( psz_end, &psz_end, 10 );
2796 if( psz_end != psz_parser ) return;
2799 i_crop_bottom = strtol( psz_end, &psz_end, 10 );
2800 if( *psz_end != '\0' ) return;
2802 i_width = fmt_render.i_visible_width -
2805 i_visible_width = i_width;
2807 i_height = fmt_render.i_visible_height -
2810 i_visible_height = i_height;
2812 i_x_offset = i_crop_left;
2813 i_y_offset = i_crop_top;