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 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
31 #define __STDC_FORMAT_MACROS 1
32 #include <stdlib.h> /* malloc(), free() */
34 #include <math.h> /* sin(), cos() */
37 // #define __ATMO_DEBUG__
40 #include <vlc_common.h>
41 #include <vlc_plugin.h>
44 #include <vlc_playlist.h>
45 #include <vlc_filter.h>
46 #include <vlc_atomic.h>
48 #include "filter_picture.h"
51 #include "AtmoDynData.h"
52 #include "AtmoLiveView.h"
53 #include "AtmoTools.h"
54 #include "AtmoExternalCaptureInput.h"
55 #include "AtmoConfig.h"
56 #include "AtmoConnection.h"
57 #include "AtmoClassicConnection.h"
60 /*****************************************************************************
62 *****************************************************************************/
63 /* directly to vlc related functions required that the module is accepted */
64 static int CreateFilter ( vlc_object_t * );
65 static void DestroyFilter ( vlc_object_t * );
66 static picture_t * Filter( filter_t *, picture_t *);
68 /* callback for global variable state pause / continue / stop events */
69 static void AddStateVariableCallback( filter_t *);
70 static void DelStateVariableCallback( filter_t *);
71 static int StateCallback(vlc_object_t *, char const *,
72 vlc_value_t, vlc_value_t, void *);
74 /* callback for atmo settings variables whose change
75 should be immediately realized and applied to output
77 static void DelAtmoSettingsVariablesCallbacks(filter_t *);
78 static void AddAtmoSettingsVariablesCallbacks(filter_t *);
79 static int AtmoSettingsCallback(vlc_object_t *, char const *,
80 vlc_value_t, vlc_value_t, void *);
83 #if defined(__ATMO_DEBUG__)
84 static void atmo_parse_crop(char *psz_cropconfig,
85 video_format_t fmt_in,
86 video_format_t fmt_render,
88 int &i_visible_height,
94 /* function to shutdown the fade thread which is started on pause*/
95 static void CheckAndStopFadeThread(filter_t *);
97 /* extracts a small RGB (BGR) Image from an YUV image */
98 static void ExtractMiniImage_YUV(filter_sys_t *, picture_t *, uint8_t *);
100 #if defined(__ATMO_DEBUG__)
101 void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename);
104 /*****************************************************************************
105 * External Prototypes for the AtmoCtrlLib.DLL
106 *****************************************************************************/
108 * if effectmode = emLivePicture then the source could be GDI (Screencapture)
109 * or External - this means another application delivers Pixeldata to AtmoWin
110 * Clientsoftware through AtmoCtrlLib.DLL and the COM Api
113 #define lvsExternal 1
115 #define CLASSIC_ATMO_NUM_ZONES 5
119 strings for settings menus and hints
121 #define MODULE_DESCRIPTION N_ ( \
122 "This module allows controlling an so called AtmoLight device "\
123 "connected to your computer.\n"\
124 "AtmoLight is the homegrown version of what Philips calls AmbiLight.\n"\
125 "If you need further information feel free to visit us at\n\n"\
126 "http://www.vdr-wiki.de/wiki/index.php/Atmo-plugin\n"\
127 "http://www.vdr-wiki.de/wiki/index.php/AtmoWin\n\n"\
128 "You can find there detailed descriptions on how to build it for yourself "\
129 "and where to get the required parts.\n" \
130 "You can also have a look at pictures and some movies showing such a device " \
133 #define DRIVER_TEXT N_("Device type")
134 #define DRIVER_LONGTEXT N_("Choose your preferred hardware from " \
135 "the list, or choose AtmoWin Software " \
136 "to delegate processing to the external " \
137 "process - with more options")
139 static const int pi_device_type_values[] = {
141 0, /* use AtmoWinA.exe userspace driver */
143 1, /* AtmoLight classic */
144 2, /* Quattro AtmoLight */
146 4, /* MoMoLight device */
149 static const char *const ppsz_device_type_descriptions[] = {
151 N_("AtmoWin Software"),
153 N_("Classic AtmoLight"),
154 N_("Quattro AtmoLight"),
160 #define DMX_CHANNELS_TEXT N_("Count of AtmoLight channels")
161 #define DMX_CHANNELS_LONGTEXT N_("How many AtmoLight channels, should be " \
162 "emulated with that DMX device")
163 #define DMX_CHBASE_TEXT N_("DMX address for each channel")
164 #define DMX_CHBASE_LONGTEXT N_("Define here the DMX base address for each " \
165 "channel use , or ; to separate the values")
167 #define MOMO_CHANNELS_TEXT N_("Count of channels")
168 #define MOMO_CHANNELS_LONGTEXT N_("Depending on your MoMoLight hardware " \
169 "choose 3 or 4 channels")
171 #define FNORDLICHT_AMOUNT_TEXT N_("Count of fnordlicht's")
172 #define FNORDLICHT_AMOUNT_LONGTEXT N_("Depending on the amount your " \
173 "fnordlicht hardware " \
174 "choose 1 to 254 channels")
177 # define DEFAULT_DEVICE 0
179 # define DEFAULT_DEVICE 1
182 #if defined( __ATMO_DEBUG__ )
183 # define SAVEFRAMES_TEXT N_("Save Debug Frames")
184 # define SAVEFRAMES_LONGTEXT N_("Write every 128th miniframe to a folder.")
185 # define FRAMEPATH_TEXT N_("Debug Frame Folder")
186 # define FRAMEPATH_LONGTEXT N_("The path where the debugframes " \
190 #define WIDTH_TEXT N_("Extracted Image Width")
191 #define WIDTH_LONGTEXT N_("The width of the mini image for " \
192 "further processing (64 is default)")
194 #define HEIGHT_TEXT N_("Extracted Image Height")
195 #define HEIGHT_LONGTEXT N_("The height of the mini image for " \
196 "further processing (48 is default)")
198 #define SHOW_DOTS_TEXT N_("Mark analyzed pixels")
199 #define SHOW_DOTS_LONGTEXT N_("makes the sample grid visible on screen as "\
202 #define PCOLOR_TEXT N_("Color when paused")
203 #define PCOLOR_LONGTEXT N_("Set the color to show if the user " \
204 "pauses the video. (Have light to get " \
206 #define PCOLOR_RED_TEXT N_("Pause-Red")
207 #define PCOLOR_RED_LONGTEXT N_("Red component of the pause color")
208 #define PCOLOR_GREEN_TEXT N_("Pause-Green")
209 #define PCOLOR_GREEN_LONGTEXT N_("Green component of the pause color")
210 #define PCOLOR_BLUE_TEXT N_("Pause-Blue")
211 #define PCOLOR_BLUE_LONGTEXT N_("Blue component of the pause color")
212 #define FADESTEPS_TEXT N_("Pause-Fadesteps")
213 #define FADESTEPS_LONGTEXT N_("Number of steps to change current color " \
214 "to pause color (each step takes 40ms)")
216 #define ECOLOR_RED_TEXT N_("End-Red")
217 #define ECOLOR_RED_LONGTEXT N_("Red component of the shutdown color")
218 #define ECOLOR_GREEN_TEXT N_("End-Green")
219 #define ECOLOR_GREEN_LONGTEXT N_("Green component of the shutdown color")
220 #define ECOLOR_BLUE_TEXT N_("End-Blue")
221 #define ECOLOR_BLUE_LONGTEXT N_("Blue component of the shutdown color")
222 #define EFADESTEPS_TEXT N_("End-Fadesteps")
223 #define EFADESTEPS_LONGTEXT N_("Number of steps to change current color to " \
224 "end color for dimming up the light in cinema " \
225 "style... (each step takes 40ms)")
227 #define ZONE_TOP_TEXT N_("Number of zones on top")
228 #define ZONE_TOP_LONGTEXT N_("Number of zones on the top of the screen")
229 #define ZONE_BOTTOM_TEXT N_("Number of zones on bottom")
230 #define ZONE_BOTTOM_LONGTEXT N_("Number of zones on the bottom of the screen")
231 #define ZONE_LR_TEXT N_("Zones on left / right side")
232 #define ZONE_LR_LONGTEXT N_("left and right side having always the " \
233 "same number of zones")
234 #define ZONE_SUMMARY_TEXT N_("Calculate a average zone")
235 #define ZONE_SUMMARY_LONGTEXT N_("it contains the average of all pixels " \
236 "in the sample image (only useful for " \
237 "single channel AtmoLight)")
240 #define USEWHITEADJ_TEXT N_("Use Software White adjust")
241 #define USEWHITEADJ_LONGTEXT N_("Should the buildin driver do a white " \
242 "adjust or your LED stripes? recommend.")
243 #define WHITE_RED_TEXT N_("White Red")
244 #define WHITE_RED_LONGTEXT N_("Red value of a pure white on your "\
246 #define WHITE_GREEN_TEXT N_("White Green")
247 #define WHITE_GREEN_LONGTEXT N_("Green value of a pure white on your "\
249 #define WHITE_BLUE_TEXT N_("White Blue")
250 #define WHITE_BLUE_LONGTEXT N_("Blue value of a pure white on your "\
253 #define SERIALDEV_TEXT N_("Serial Port/Device")
254 #define SERIALDEV_LONGTEXT N_("Name of the serial port where the AtmoLight "\
255 "controller is attached to.\n" \
256 "On Windows usually something like COM1 or " \
257 "COM2. On Linux /dev/ttyS01 f.e.")
259 #define EDGE_TEXT N_("Edge Weightning")
260 #define EDGE_LONGTEXT N_("Increasing this value will result in color "\
261 "more depending on the border of the frame.")
262 #define BRIGHTNESS_TEXT N_("Brightness")
263 #define BRIGHTNESS_LONGTEXT N_("Overall brightness of your LED stripes")
264 #define DARKNESS_TEXT N_("Darkness Limit")
265 #define DARKNESS_LONGTEXT N_("Pixels with a saturation lower than this will "\
266 "be ignored. Should be greater than one for "\
267 "letterboxed videos.")
268 #define HUEWINSIZE_TEXT N_("Hue windowing")
269 #define HUEWINSIZE_LONGTEXT N_("Used for statistics.")
270 #define SATWINSIZE_TEXT N_("Sat windowing")
271 #define SATWINSIZE_LONGTEXT N_("Used for statistics.")
273 #define MEANLENGTH_TEXT N_("Filter length (ms)")
274 #define MEANLENGTH_LONGTEXT N_("Time it takes until a color is completely "\
275 "changed. This prevents flickering.")
276 #define MEANTHRESHOLD_TEXT N_("Filter threshold")
277 #define MEANTHRESHOLD_LONGTEXT N_("How much a color has to be changed for an "\
278 "immediate color change.")
279 #define MEANPERCENTNEW_TEXT N_("Filter Smoothness (in %)")
280 #define MEANPERCENTNEW_LONGTEXT N_("Filter Smoothness")
282 #define FILTERMODE_TEXT N_("Output Color filter mode")
283 #define FILTERMODE_LONGTEXT N_("defines the how the output color should " \
284 "be calculated based on previous color")
286 static const int pi_filtermode_values[] = {
291 static const char *const ppsz_filtermode_descriptions[] = {
297 #define FRAMEDELAY_TEXT N_("Frame delay (ms)")
298 #define FRAMEDELAY_LONGTEXT N_("Helps to get the video output and the light "\
299 "effects in sync. Values around 20ms should " \
303 #define CHANNEL_0_ASSIGN_TEXT N_("Channel 0: summary")
304 #define CHANNEL_1_ASSIGN_TEXT N_("Channel 1: left")
305 #define CHANNEL_2_ASSIGN_TEXT N_("Channel 2: right")
306 #define CHANNEL_3_ASSIGN_TEXT N_("Channel 3: top")
307 #define CHANNEL_4_ASSIGN_TEXT N_("Channel 4: bottom")
309 #define CHANNELASSIGN_LONGTEXT N_("Maps the hardware channel X to logical "\
310 "zone Y to fix wrong wiring :-)")
311 static const int pi_zone_assignment_values[] = {
319 static const char *const ppsz_zone_assignment_descriptions[] = {
321 N_("Zone 4:summary"),
327 #define CHANNELS_ASSIGN_TEXT N_("Channel / Zone Assignment")
328 #define CHANNELS_ASSIGN_LONGTEXT N_("for devices with more than five " \
329 "channels / zones write down here for each channel " \
330 "the zone number to show and separate the values with " \
331 ", or ; and use -1 to not use some channels. For the " \
332 "classic AtmoLight the sequence 4,3,1,0,2 would set the " \
333 "default channel/zone mapping. " \
334 "Having only two zones on top, and one zone on left and " \
335 "right and no summary zone the mapping for classic " \
336 "AtmoLight would be -1,3,2,1,0")
338 #define ZONE_0_GRADIENT_TEXT N_("Zone 0: Top gradient")
339 #define ZONE_1_GRADIENT_TEXT N_("Zone 1: Right gradient")
340 #define ZONE_2_GRADIENT_TEXT N_("Zone 2: Bottom gradient")
341 #define ZONE_3_GRADIENT_TEXT N_("Zone 3: Left gradient")
342 #define ZONE_4_GRADIENT_TEXT N_("Zone 4: Summary gradient")
343 #define ZONE_X_GRADIENT_LONG_TEXT N_("Defines a small bitmap with 64x48 "\
344 "pixels, containing a grayscale gradient")
346 #define GRADIENT_PATH_TEXT N_("Gradient bitmap searchpath")
347 #define GRADIENT_PATH_LONGTEXT N_("Now preferred option to assign gradient "\
348 "bitmaps, put them as zone_0.bmp, zone_1.bmp etc. into one folder and "\
349 "set the foldername here")
352 # define ATMOWINEXE_TEXT N_("Filename of AtmoWin*.exe")
353 # define ATMOWINEXE_LONGTEXT N_("if you want the AtmoLight control "\
354 "software to be launched by VLC, enter the "\
355 "complete path of AtmoWinA.exe here.")
358 #define CFG_PREFIX "atmo-"
360 /*****************************************************************************
362 *****************************************************************************/
364 set_description( N_("AtmoLight Filter") )
365 set_help( MODULE_DESCRIPTION )
366 set_shortname( N_( "AtmoLight" ))
367 set_category( CAT_VIDEO )
368 set_subcategory( SUBCAT_VIDEO_VFILTER )
370 set_capability( "video filter2", 0 )
373 set_section( N_("Choose Devicetype and Connection" ), 0 )
375 add_integer( CFG_PREFIX "device", DEFAULT_DEVICE,
376 DRIVER_TEXT, DRIVER_LONGTEXT, false )
377 change_integer_list( pi_device_type_values,
378 ppsz_device_type_descriptions )
381 add_string(CFG_PREFIX "serialdev", "COM1",
382 SERIALDEV_TEXT, SERIALDEV_LONGTEXT, false )
384 on win32 the executeable external driver application
385 for automatic start if needed
387 add_loadfile(CFG_PREFIX "atmowinexe", NULL,
388 ATMOWINEXE_TEXT, ATMOWINEXE_LONGTEXT, false )
390 add_string(CFG_PREFIX "serialdev", "/dev/ttyUSB0",
391 SERIALDEV_TEXT, SERIALDEV_LONGTEXT, false )
395 color which is showed if you want durring pausing
396 your movie ... used for both buildin / external
398 set_section( N_("Illuminate the room with this color on pause" ), 0 )
399 add_bool(CFG_PREFIX "usepausecolor", false,
400 PCOLOR_TEXT, PCOLOR_LONGTEXT, false)
401 add_integer_with_range(CFG_PREFIX "pcolor-red", 0, 0, 255,
402 PCOLOR_RED_TEXT, PCOLOR_RED_LONGTEXT, false)
403 add_integer_with_range(CFG_PREFIX "pcolor-green", 0, 0, 255,
404 PCOLOR_GREEN_TEXT, PCOLOR_GREEN_LONGTEXT, false)
405 add_integer_with_range(CFG_PREFIX "pcolor-blue", 192, 0, 255,
406 PCOLOR_BLUE_TEXT, PCOLOR_BLUE_LONGTEXT, false)
407 add_integer_with_range(CFG_PREFIX "fadesteps", 50, 1, 250,
408 FADESTEPS_TEXT, FADESTEPS_LONGTEXT, false)
411 color which is showed if you finished watching your movie ...
412 used for both buildin / external
414 set_section( N_("Illuminate the room with this color on shutdown" ), 0 )
415 add_integer_with_range(CFG_PREFIX "ecolor-red", 192, 0, 255,
416 ECOLOR_RED_TEXT, ECOLOR_RED_LONGTEXT, false)
417 add_integer_with_range(CFG_PREFIX "ecolor-green", 192, 0, 255,
418 ECOLOR_GREEN_TEXT, ECOLOR_GREEN_LONGTEXT, false)
419 add_integer_with_range(CFG_PREFIX "ecolor-blue", 192, 0, 255,
420 ECOLOR_BLUE_TEXT, ECOLOR_BLUE_LONGTEXT, false)
421 add_integer_with_range(CFG_PREFIX "efadesteps", 50, 1, 250,
422 EFADESTEPS_TEXT, EFADESTEPS_LONGTEXT, false)
425 set_section( N_("DMX options" ), 0 )
426 add_integer_with_range(CFG_PREFIX "dmx-channels", 5, 1, 64,
427 DMX_CHANNELS_TEXT, DMX_CHANNELS_LONGTEXT, false)
428 add_string(CFG_PREFIX "dmx-chbase", "0,3,6,9,12",
429 DMX_CHBASE_TEXT, DMX_CHBASE_LONGTEXT, false )
431 set_section( N_("MoMoLight options" ), 0 )
432 add_integer_with_range(CFG_PREFIX "momo-channels", 3, 3, 4,
433 MOMO_CHANNELS_TEXT, MOMO_CHANNELS_LONGTEXT, false)
435 /* 2,2,4 means 2 is the default value, 1 minimum amount,
438 set_section( N_("fnordlicht options" ), 0 )
439 add_integer_with_range(CFG_PREFIX "fnordlicht-amount", 2, 1, 254,
440 FNORDLICHT_AMOUNT_TEXT,
441 FNORDLICHT_AMOUNT_LONGTEXT, false)
445 instead of redefining the original AtmoLight zones with gradient
446 bitmaps, we can now define the layout of the zones useing these
447 parameters - the function with the gradient bitmaps would still
448 work (but for most cases its no longer required)
450 short description whats this means - f.e. the classic atmo would
452 zones-top = 1 - zone 0
453 zones-lr = 1 - zone 1 und zone 3
454 zones-bottom = 1 - zone 2
455 zone-summary = true - zone 4
463 the zone numbers will be counted clockwise starting at top / left
464 if you want to split the light at the top, without having a bottom zone
465 (which is my private config)
467 zones-top = 2 - zone 0, zone 1
468 zones-lr = 1 - zone 2 und zone 3
480 set_section( N_("Zone Layout for the build-in Atmo" ), 0 )
481 add_integer_with_range(CFG_PREFIX "zones-top", 1, 0, 16,
482 ZONE_TOP_TEXT, ZONE_TOP_LONGTEXT, false)
483 add_integer_with_range(CFG_PREFIX "zones-bottom", 1, 0, 16,
484 ZONE_BOTTOM_TEXT, ZONE_BOTTOM_LONGTEXT, false)
485 add_integer_with_range(CFG_PREFIX "zones-lr", 1, 0, 16,
486 ZONE_LR_TEXT, ZONE_LR_LONGTEXT, false)
487 add_bool(CFG_PREFIX "zone-summary", false,
488 ZONE_SUMMARY_TEXT, ZONE_SUMMARY_LONGTEXT, false)
491 settings only for the buildin driver (if external driver app is used
492 these parameters are ignored.)
494 definition of parameters for the buildin filter ...
496 set_section( N_("Settings for the built-in Live Video Processor only" ), 0 )
498 add_integer_with_range(CFG_PREFIX "edgeweightning", 3, 1, 30,
499 EDGE_TEXT, EDGE_LONGTEXT, false)
501 add_integer_with_range(CFG_PREFIX "brightness", 100, 50, 300,
502 BRIGHTNESS_TEXT, BRIGHTNESS_LONGTEXT, false)
504 add_integer_with_range(CFG_PREFIX "darknesslimit", 3, 0, 10,
505 DARKNESS_TEXT, DARKNESS_LONGTEXT, false)
507 add_integer_with_range(CFG_PREFIX "huewinsize", 3, 0, 5,
508 HUEWINSIZE_TEXT, HUEWINSIZE_LONGTEXT, false)
510 add_integer_with_range(CFG_PREFIX "satwinsize", 3, 0, 5,
511 SATWINSIZE_TEXT, SATWINSIZE_LONGTEXT, false)
513 add_integer(CFG_PREFIX "filtermode", (int)afmCombined,
514 FILTERMODE_TEXT, FILTERMODE_LONGTEXT, false )
516 change_integer_list(pi_filtermode_values, ppsz_filtermode_descriptions )
518 add_integer_with_range(CFG_PREFIX "meanlength", 300, 300, 5000,
519 MEANLENGTH_TEXT, MEANLENGTH_LONGTEXT, false)
521 add_integer_with_range(CFG_PREFIX "meanthreshold", 40, 1, 100,
522 MEANTHRESHOLD_TEXT, MEANTHRESHOLD_LONGTEXT, false)
524 add_integer_with_range(CFG_PREFIX "percentnew", 50, 1, 100,
525 MEANPERCENTNEW_TEXT, MEANPERCENTNEW_LONGTEXT, false)
527 add_integer_with_range(CFG_PREFIX "framedelay", 18, 0, 200,
528 FRAMEDELAY_TEXT, FRAMEDELAY_LONGTEXT, false)
531 output channel reordering
533 set_section( N_("Change channel assignment (fixes wrong wiring)" ), 0 )
534 add_integer( CFG_PREFIX "channel_0", 4,
535 CHANNEL_0_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
536 change_integer_list( pi_zone_assignment_values,
537 ppsz_zone_assignment_descriptions )
539 add_integer( CFG_PREFIX "channel_1", 3,
540 CHANNEL_1_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
541 change_integer_list( pi_zone_assignment_values,
542 ppsz_zone_assignment_descriptions )
544 add_integer( CFG_PREFIX "channel_2", 1,
545 CHANNEL_2_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
546 change_integer_list( pi_zone_assignment_values,
547 ppsz_zone_assignment_descriptions )
549 add_integer( CFG_PREFIX "channel_3", 0,
550 CHANNEL_3_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
551 change_integer_list( pi_zone_assignment_values,
552 ppsz_zone_assignment_descriptions )
554 add_integer( CFG_PREFIX "channel_4", 2,
555 CHANNEL_4_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
556 change_integer_list( pi_zone_assignment_values,
557 ppsz_zone_assignment_descriptions )
559 add_string(CFG_PREFIX "channels", "",
560 CHANNELS_ASSIGN_TEXT, CHANNELS_ASSIGN_LONGTEXT, false )
564 LED color white calibration
566 set_section( N_("Adjust the white light to your LED stripes" ), 0 )
567 add_bool(CFG_PREFIX "whiteadj", true,
568 USEWHITEADJ_TEXT, USEWHITEADJ_LONGTEXT, false)
569 add_integer_with_range(CFG_PREFIX "white-red", 255, 0, 255,
570 WHITE_RED_TEXT, WHITE_RED_LONGTEXT, false)
572 add_integer_with_range(CFG_PREFIX "white-green", 255, 0, 255,
573 WHITE_GREEN_TEXT, WHITE_GREEN_LONGTEXT, false)
575 add_integer_with_range(CFG_PREFIX "white-blue", 255, 0, 255,
576 WHITE_BLUE_TEXT, WHITE_BLUE_LONGTEXT, false)
577 /* end of definition of parameter for the buildin filter ... part 1 */
581 only for buildin (external has own definition) per default the calucation
582 used linear gradients for assigning a priority to the pixel - depending
583 how near they are to the border ...for changing this you can create 64x48
584 Pixel BMP files - which contain your own grayscale... (you can produce funny
585 effects with this...) the images MUST not compressed, should have 24-bit per
586 pixel, or a simple 256 color grayscale palette
588 set_section( N_("Change gradients" ), 0 )
589 add_loadfile(CFG_PREFIX "gradient_zone_0", NULL,
590 ZONE_0_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
591 add_loadfile(CFG_PREFIX "gradient_zone_1", NULL,
592 ZONE_1_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
593 add_loadfile(CFG_PREFIX "gradient_zone_2", NULL,
594 ZONE_2_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
595 add_loadfile(CFG_PREFIX "gradient_zone_3", NULL,
596 ZONE_3_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
597 add_loadfile(CFG_PREFIX "gradient_zone_4", NULL,
598 ZONE_4_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
599 add_directory(CFG_PREFIX "gradient_path", NULL,
600 GRADIENT_PATH_TEXT, GRADIENT_PATH_LONGTEXT, false )
602 #if defined(__ATMO_DEBUG__)
603 add_bool(CFG_PREFIX "saveframes", false,
604 SAVEFRAMES_TEXT, SAVEFRAMES_LONGTEXT, false)
605 add_string(CFG_PREFIX "framepath", "",
606 FRAMEPATH_TEXT, FRAMEPATH_LONGTEXT, false )
609 may be later if computers gets more power ;-) than now we increase
610 the samplesize from which we do the stats for output color calculation
612 add_integer_with_range(CFG_PREFIX "width", 64, 64, 512,
613 WIDTH_TEXT, WIDTH_LONGTEXT, true)
614 add_integer_with_range(CFG_PREFIX "height", 48, 48, 384,
615 HEIGHT_TEXT, HEIGHT_LONGTEXT, true)
616 add_bool(CFG_PREFIX "showdots", false,
617 SHOW_DOTS_TEXT, SHOW_DOTS_LONGTEXT, false)
618 add_shortcut( "atmo" )
619 set_callbacks( CreateFilter, DestroyFilter )
623 static const char *const ppsz_filter_options[] = {
678 #if defined(__ATMO_DEBUG__)
695 /*****************************************************************************
696 * fadethread_t: Color Fading Thread
697 *****************************************************************************
698 * changes slowly the color of the output if videostream gets paused...
699 *****************************************************************************
707 /* tell the thread which color should be the target of fading */
711 /* how many steps should happen until this */
716 static void *FadeToColorThread(void *);
719 /*****************************************************************************
720 * filter_sys_t: AtmoLight filter method descriptor
721 *****************************************************************************
722 * It describes the AtmoLight specific properties of an video filter.
723 *****************************************************************************/
727 special for the access of the p_fadethread member all other members
728 need no special protection so far!
730 vlc_mutex_t filter_lock;
733 int32_t i_AtmoOldEffect;
736 int32_t i_device_type;
740 int32_t i_atmo_width;
741 int32_t i_atmo_height;
742 /* used to disable fadeout if less than 50 frames are processed
743 used to avoid long time waiting when switch quickly between
744 deinterlaceing modes, where the output filter chains is rebuild
747 int32_t i_frames_processed;
749 #if defined(__ATMO_DEBUG__)
751 uint32_t ui_frame_counter;
752 char sz_framepath[MAX_PATH];
755 /* light color durring movie pause ... */
756 bool b_usepausecolor;
757 uint8_t ui_pausecolor_red;
758 uint8_t ui_pausecolor_green;
759 uint8_t ui_pausecolor_blue;
762 /* light color on movie finish ... */
763 uint8_t ui_endcolor_red;
764 uint8_t ui_endcolor_green;
765 uint8_t ui_endcolor_blue;
768 fadethread_t *p_fadethread;
770 /* Variables for buildin driver only... */
772 /* is only present and initialized if the internal driver is used*/
773 CAtmoConfig *p_atmo_config;
774 /* storage for temporal settings "volatile" */
775 CAtmoDynData *p_atmo_dyndata;
776 /* initialized for buildin driver with AtmoCreateTransferBuffers */
777 BITMAPINFOHEADER mini_image_format;
778 /* is only use buildin driver! */
779 uint8_t *p_atmo_transfer_buffer;
780 /* end buildin driver */
783 contains the real output size of the video calculated on
784 change event of the variable "crop" from vout
786 int32_t i_crop_x_offset;
787 int32_t i_crop_y_offset;
788 int32_t i_crop_width;
789 int32_t i_crop_height;
791 void (*pf_extract_mini_image) (filter_sys_t *p_sys,
793 uint8_t *p_transfer_dest);
796 /* External Library as wrapper arround COM Stuff */
797 HINSTANCE h_AtmoCtrl;
798 int32_t (*pf_ctrl_atmo_initialize) (void);
799 void (*pf_ctrl_atmo_finalize) (int32_t what);
800 int32_t (*pf_ctrl_atmo_switch_effect) (int32_t);
801 int32_t (*pf_ctrl_atmo_set_live_source) (int32_t);
802 void (*pf_ctrl_atmo_create_transfer_buffers) (int32_t, int32_t,
804 uint8_t* (*pf_ctrl_atmo_lock_transfer_buffer) (void);
805 void (*pf_ctrl_atmo_send_pixel_data) (void);
806 void (*pf_ctrl_atmo_get_image_size)(int32_t *,int32_t *);
811 initialize previously configured Atmo Light environment
812 - if internal is enabled try to access the device on the serial port
813 - if not internal is enabled and we are on win32 try to initialize
814 the previously loaded DLL ...
816 Return Values may be: -1 (failed for some reason - filter will be disabled)
819 static int32_t AtmoInitialize(filter_t *p_filter, bool b_for_thread)
821 filter_sys_t *p_sys = p_filter->p_sys;
822 if(p_sys->p_atmo_config)
827 /* setup Output Threads ... */
828 msg_Dbg( p_filter, "open atmo device...");
829 if(CAtmoTools::RecreateConnection(p_sys->p_atmo_dyndata)
834 msg_Err( p_filter,"failed to open atmo device, "\
835 "some other software/driver may use it?");
839 } else if(p_sys->pf_ctrl_atmo_initialize)
841 /* on win32 with active ctrl dll */
842 return p_sys->pf_ctrl_atmo_initialize();
849 prepare the shutdown of the effect threads,
850 for build in filter - close the serialport after finishing the threads...
851 cleanup possible loaded DLL...
853 static void AtmoFinalize(filter_t *p_filter, int32_t what)
855 filter_sys_t *p_sys = p_filter->p_sys;
856 if(p_sys->p_atmo_config)
860 CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
863 p_atmo_dyndata->LockCriticalSection();
865 CAtmoInput *p_input = p_atmo_dyndata->getLiveInput();
866 p_atmo_dyndata->setLiveInput( NULL );
869 p_input->Terminate();
871 msg_Dbg( p_filter, "input thread died peacefully");
874 CThread *p_effect_thread = p_atmo_dyndata->getEffectThread();
875 p_atmo_dyndata->setEffectThread(NULL);
876 if(p_effect_thread != NULL)
879 forced the thread to die...
880 and wait for termination of the thread
882 p_effect_thread->Terminate();
883 delete p_effect_thread;
884 msg_Dbg( p_filter, "effect thread died peacefully");
887 CAtmoPacketQueue *p_queue =
888 p_atmo_dyndata->getLivePacketQueue();
889 p_atmo_dyndata->setLivePacketQueue( NULL );
893 msg_Dbg( p_filter, "packetqueue removed");
897 close serial port if it is open (all OS specific is inside
898 CAtmoSerialConnection implemented / defined)
900 CAtmoConnection *p_atmo_connection =
901 p_atmo_dyndata->getAtmoConnection();
902 p_atmo_dyndata->setAtmoConnection(NULL);
903 if(p_atmo_connection) {
904 p_atmo_connection->CloseConnection();
905 delete p_atmo_connection;
907 p_atmo_dyndata->UnLockCriticalSection();
911 } else if(p_sys->pf_ctrl_atmo_finalize)
913 /* on win32 with active ctrl dll */
914 p_sys->pf_ctrl_atmo_finalize(what);
920 switch the current light effect to LiveView
922 static int32_t AtmoSwitchEffect(filter_t *p_filter, int32_t newMode)
924 filter_sys_t *p_sys = p_filter->p_sys;
926 msg_Dbg( p_filter, "AtmoSwitchEffect %d", newMode );
928 if(p_sys->p_atmo_config)
930 return CAtmoTools::SwitchEffect(p_sys->p_atmo_dyndata, emLivePicture);
932 } else if(p_sys->pf_ctrl_atmo_switch_effect)
934 /* on win32 with active ctrl dll */
935 return p_sys->pf_ctrl_atmo_switch_effect( newMode );
942 set the current live picture source, does only something on win32,
943 with the external libraries - if the buildin effects are used nothing
946 static int32_t AtmoSetLiveSource(filter_t *p_filter, int32_t newSource)
948 filter_sys_t *p_sys = p_filter->p_sys;
950 msg_Dbg( p_filter, "AtmoSetLiveSource %d", newSource );
952 if(p_sys->p_atmo_config)
957 doesnt know different sources so this
958 function call would just do nothing special
962 } else if(p_sys->pf_ctrl_atmo_set_live_source)
964 /* on win32 with active ctrl dll */
965 return p_sys->pf_ctrl_atmo_set_live_source(newSource);
972 setup the pixel transferbuffers which is used to transfer pixeldata from
973 the filter to the effect thread, and possible accross the process
974 boundaries on win32, with the external DLL
976 static void AtmoCreateTransferBuffers(filter_t *p_filter,
978 int32_t bytePerPixel,
982 filter_sys_t *p_sys = p_filter->p_sys;
983 if(p_sys->p_atmo_config)
986 we need a buffer where the image is stored (only for transfer
987 to the processing thread)
989 free( p_sys->p_atmo_transfer_buffer );
991 p_sys->p_atmo_transfer_buffer = (uint8_t *)malloc(bytePerPixel *
994 memset(&p_sys->mini_image_format,0,sizeof(BITMAPINFOHEADER));
996 p_sys->mini_image_format.biSize = sizeof(BITMAPINFOHEADER);
997 p_sys->mini_image_format.biWidth = width;
998 p_sys->mini_image_format.biHeight = height;
999 p_sys->mini_image_format.biBitCount = bytePerPixel*8;
1000 p_sys->mini_image_format.biCompression = FourCC;
1003 } else if(p_sys->pf_ctrl_atmo_create_transfer_buffers)
1005 /* on win32 with active ctrl dll */
1006 p_sys->pf_ctrl_atmo_create_transfer_buffers(FourCC,
1015 acquire the transfer buffer pointer the buildin version only
1016 returns the pointer to the allocated buffer ... the
1017 external version on win32 has to do some COM stuff to lock the
1018 Variant Byte array which is behind the buffer
1020 static uint8_t* AtmoLockTransferBuffer(filter_t *p_filter)
1022 filter_sys_t *p_sys = p_filter->p_sys;
1023 if(p_sys->p_atmo_config)
1025 return p_sys->p_atmo_transfer_buffer;
1027 } else if(p_sys->pf_ctrl_atmo_lock_transfer_buffer)
1029 /* on win32 with active ctrl dll */
1030 return p_sys->pf_ctrl_atmo_lock_transfer_buffer();
1037 send the content of current pixel buffer got with AtmoLockTransferBuffer
1038 to the processing threads
1039 - build in version - will forward the data to AtmoExternalCaptureInput Thread
1040 - win32 external - will do the same, but across the process boundaries via
1041 COM to the AtmoWinA.exe Process
1043 static void AtmoSendPixelData(filter_t *p_filter)
1045 filter_sys_t *p_sys = p_filter->p_sys;
1046 if(p_sys->p_atmo_config && p_sys->p_atmo_transfer_buffer)
1048 CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
1049 if(p_atmo_dyndata &&
1050 (p_atmo_dyndata->getLivePictureSource() == lpsExtern))
1053 the cast will go Ok because we are inside videolan there is only
1054 this kind of effect thread implemented!
1056 CAtmoExternalCaptureInput *p_atmo_external_capture_input_thread =
1057 (CAtmoExternalCaptureInput *)p_atmo_dyndata->getLiveInput();
1059 if(p_atmo_external_capture_input_thread)
1062 the same as above inside videolan only this single kind of
1063 input exists so we can cast without further tests!
1065 this call will do a 1:1 copy of this buffer, and wakeup
1066 the thread from normal sleeping
1068 p_atmo_external_capture_input_thread->
1069 DeliverNewSourceDataPaket(&p_sys->mini_image_format,
1070 p_sys->p_atmo_transfer_buffer);
1074 } else if(p_sys->pf_ctrl_atmo_send_pixel_data)
1076 /* on win32 with active ctrl dll */
1077 p_sys->pf_ctrl_atmo_send_pixel_data();
1081 msg_Warn( p_filter, "AtmoSendPixelData no method");
1086 Shutdown AtmoLight finally - is call from DestroyFilter
1087 does the cleanup restores the effectmode on the external Software
1088 (only win32) and possible setup the final light ...
1090 static void Atmo_Shutdown(filter_t *p_filter)
1092 filter_sys_t *p_sys = p_filter->p_sys;
1094 if(p_sys->b_enabled)
1096 msg_Dbg( p_filter, "shut down atmo!");
1098 if there is a still running show pause color thread kill him!
1100 CheckAndStopFadeThread(p_filter);
1102 // perpare spawn fadeing thread
1103 vlc_mutex_lock( &p_sys->filter_lock );
1106 fade to end color (in case of external AtmoWin Software
1107 assume that the static color will equal to this
1108 one to get a soft change and no flash!
1110 p_sys->b_pause_live = true;
1113 p_sys->p_fadethread = (fadethread_t *)calloc( 1, sizeof(fadethread_t) );
1114 p_sys->p_fadethread->p_filter = p_filter;
1115 p_sys->p_fadethread->ui_red = p_sys->ui_endcolor_red;
1116 p_sys->p_fadethread->ui_green = p_sys->ui_endcolor_green;
1117 p_sys->p_fadethread->ui_blue = p_sys->ui_endcolor_blue;
1118 if(p_sys->i_frames_processed < 50)
1119 p_sys->p_fadethread->i_steps = 1;
1121 p_sys->p_fadethread->i_steps = p_sys->i_endfadesteps;
1122 vlc_atomic_set(&p_sys->p_fadethread->abort, 0);
1124 if( vlc_clone( &p_sys->p_fadethread->thread,
1126 p_sys->p_fadethread,
1127 VLC_THREAD_PRIORITY_LOW ) )
1129 msg_Err( p_filter, "cannot create FadeToColorThread" );
1130 free( p_sys->p_fadethread );
1131 p_sys->p_fadethread = NULL;
1132 vlc_mutex_unlock( &p_sys->filter_lock );
1136 vlc_mutex_unlock( &p_sys->filter_lock );
1138 /* wait for the thread... */
1139 vlc_join(p_sys->p_fadethread->thread, NULL);
1141 free(p_sys->p_fadethread);
1143 p_sys->p_fadethread = NULL;
1147 the following happens only useing the
1148 external AtmoWin Device Software
1150 if( !p_sys->p_atmo_config )
1152 if(p_sys->i_AtmoOldEffect != emLivePicture)
1153 AtmoSwitchEffect( p_filter, p_sys->i_AtmoOldEffect);
1155 AtmoSetLiveSource( p_filter, lvsGDI );
1158 /* close device connection etc. */
1159 AtmoFinalize(p_filter, 1);
1161 /* disable filter method .. */
1162 p_sys->b_enabled = false;
1167 depending on mode setup imagesize to 64x48(classic), or defined
1168 resolution of external atmowin.exe on windows
1170 static void Atmo_SetupImageSize(filter_t *p_filter)
1172 filter_sys_t *p_sys = p_filter->p_sys;
1174 size of extracted image by default 64x48 (other imagesizes are
1175 currently ignored by AtmoWin)
1177 p_sys->i_atmo_width = var_CreateGetIntegerCommand( p_filter,
1178 CFG_PREFIX "width");
1179 p_sys->i_atmo_height = var_CreateGetIntegerCommand( p_filter,
1180 CFG_PREFIX "height");
1182 if(p_sys->p_atmo_config)
1185 } else if(p_sys->pf_ctrl_atmo_get_image_size)
1187 /* on win32 with active ctrl dll */
1188 p_sys->pf_ctrl_atmo_get_image_size( &p_sys->i_atmo_width,
1189 &p_sys->i_atmo_height );
1193 msg_Dbg(p_filter,"sample image size %d * %d pixels", p_sys->i_atmo_width,
1194 p_sys->i_atmo_height);
1198 initialize the zone and channel mapping for the buildin atmolight adapter
1200 static void Atmo_SetupBuildZones(filter_t *p_filter)
1202 filter_sys_t *p_sys = p_filter->p_sys;
1204 p_sys->p_atmo_dyndata->LockCriticalSection();
1206 CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
1209 CAtmoChannelAssignment *p_channel_assignment =
1210 p_atmo_config->getChannelAssignment(0);
1212 // channel 0 - zone 4
1213 p_channel_assignment->setZoneIndex( 0, var_CreateGetIntegerCommand(
1214 p_filter, CFG_PREFIX "channel_0")
1217 // channel 1 - zone 3
1218 p_channel_assignment->setZoneIndex( 1, var_CreateGetIntegerCommand(
1219 p_filter, CFG_PREFIX "channel_1")
1222 // channel 2 - zone 1
1223 p_channel_assignment->setZoneIndex( 2, var_CreateGetIntegerCommand(
1224 p_filter, CFG_PREFIX "channel_2")
1227 // channel 3 - zone 0
1228 p_channel_assignment->setZoneIndex( 3, var_CreateGetIntegerCommand(
1229 p_filter, CFG_PREFIX "channel_3")
1232 // channel 4 - zone 2
1233 p_channel_assignment->setZoneIndex( 4, var_CreateGetIntegerCommand(
1234 p_filter, CFG_PREFIX "channel_4")
1237 char *psz_channels = var_CreateGetStringCommand(
1239 CFG_PREFIX "channels"
1241 if( !EMPTY_STR(psz_channels) )
1243 msg_Dbg( p_filter, "deal with new zone mapping %s", psz_channels );
1245 char *psz_temp = psz_channels;
1246 char *psz_start = psz_temp;
1249 if(*psz_temp == ',' || *psz_temp == ';')
1254 int zone = atoi( psz_start );
1256 zone >= p_channel_assignment->getSize()) {
1257 msg_Warn( p_filter, "Zone %d out of range -1..%d",
1258 zone, p_channel_assignment->getSize()-1 );
1260 p_channel_assignment->setZoneIndex( channel, zone );
1264 psz_start = psz_temp;
1272 process the rest of the string
1274 if( *psz_start && !*psz_temp )
1276 int zone = atoi( psz_start );
1278 zone >= p_channel_assignment->getSize()) {
1279 msg_Warn( p_filter, "Zone %d out of range -1..%d",
1280 zone, p_channel_assignment->getSize()-1 );
1282 p_channel_assignment->setZoneIndex( channel, zone );
1286 free( psz_channels );
1288 for(int i=0;i< p_channel_assignment->getSize() ;i++)
1289 msg_Info( p_filter, "map zone %d to hardware channel %d",
1290 p_channel_assignment->getZoneIndex( i ),
1293 p_sys->p_atmo_dyndata->getAtmoConnection()
1294 ->SetChannelAssignment( p_channel_assignment );
1301 calculate the default gradients for each zone!
1302 depending on the zone layout set before, this now
1303 supports also multiple gradients on each side
1304 (older versions could do this only with external
1307 p_sys->p_atmo_dyndata->CalculateDefaultZones();
1311 first try to load the old style defined gradient bitmaps
1312 this could only be done for the first five zones
1313 - should be deprecated -
1315 CAtmoZoneDefinition *p_zone;
1316 char psz_gradient_var_name[30];
1317 char *psz_gradient_file;
1318 for(int i=0;i<CLASSIC_ATMO_NUM_ZONES;i++)
1320 sprintf(psz_gradient_var_name, CFG_PREFIX "gradient_zone_%d", i);
1321 psz_gradient_file = var_CreateGetStringCommand(
1323 psz_gradient_var_name
1325 if( !EMPTY_STR(psz_gradient_file) )
1327 msg_Dbg( p_filter, "loading gradientfile %s for "\
1328 "zone %d", psz_gradient_file, i);
1330 p_zone = p_atmo_config->getZoneDefinition(i);
1333 int i_res = p_zone->LoadGradientFromBitmap(psz_gradient_file);
1335 if(i_res != ATMO_LOAD_GRADIENT_OK)
1337 msg_Err( p_filter,"failed to load gradient '%s' with "\
1338 "error %d",psz_gradient_file,i_res);
1342 free( psz_gradient_file );
1347 the new approach try to load a gradient bitmap for each zone
1348 from a previously defined folder containing
1353 char *psz_gradient_path = var_CreateGetStringCommand(
1355 CFG_PREFIX "gradient_path"
1357 if( EMPTY_STR(psz_gradient_path) )
1359 char *psz_file_name = (char *)malloc( strlen(psz_gradient_path) + 16 );
1360 assert( psz_file_name );
1362 for(int i=0; i < p_atmo_config->getZoneCount(); i++ )
1364 p_zone = p_atmo_config->getZoneDefinition(i);
1368 sprintf(psz_file_name, "%s%szone_%d.bmp",
1369 psz_gradient_path, DIR_SEP, i );
1371 int i_res = p_zone->LoadGradientFromBitmap( psz_file_name );
1373 if( i_res == ATMO_LOAD_GRADIENT_OK )
1375 msg_Dbg( p_filter, "loaded gradientfile %s for "\
1376 "zone %d", psz_file_name, i);
1379 if( (i_res != ATMO_LOAD_GRADIENT_OK) &&
1380 (i_res != ATMO_LOAD_GRADIENT_FILENOTFOND) )
1382 msg_Err( p_filter,"failed to load gradient '%s' with "\
1383 "error %d",psz_file_name,i_res);
1388 free( psz_file_name );
1390 free( psz_gradient_path );
1393 p_sys->p_atmo_dyndata->UnLockCriticalSection();
1397 static void Atmo_SetupConfig(filter_t *p_filter, CAtmoConfig *p_atmo_config)
1400 figuring out the device ports (com-ports, ttys)
1402 char *psz_serialdev = var_CreateGetStringCommand( p_filter,
1403 CFG_PREFIX "serialdev" );
1404 char *psz_temp = psz_serialdev;
1406 if( !EMPTY_STR(psz_serialdev) )
1413 msg_Dbg( p_filter, "use port(s) %s",psz_serialdev);
1416 psz_serialdev - may contain up to 4 COM ports for the quattro device
1417 the quattro device is just hack of useing 4 classic devices as one
1418 logical device - thanks that usb-com-ports exists :)
1419 as Seperator I defined , or ; with the hope that these
1420 characters are never part of a device name
1422 while( (psz_token = strsep(&psz_temp, ",;")) != NULL && i_port < 4 )
1425 psz_token may contain spaces we have to trim away
1430 find first none space in string
1432 while( psz_token[i] == 32 ) i++;
1434 contains string only spaces or is empty? skip it
1442 while( psz_token[i] && psz_token[i] != 32 )
1443 psz_token[ j++ ] = psz_token[ i++ ];
1446 msg_Dbg( p_filter, "Serial Device [%d]: %s", i_port, psz_token );
1448 p_atmo_config->setSerialDevice( i_port, psz_token );
1455 msg_Err(p_filter,"no serial devicename(s) set");
1457 free( psz_serialdev );
1460 configuration of light source layout arround the display
1462 p_atmo_config->setZonesTopCount(
1463 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-top")
1465 p_atmo_config->setZonesBottomCount(
1466 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-bottom")
1468 p_atmo_config->setZonesLRCount(
1469 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-lr")
1471 p_atmo_config->setZoneSummary(
1472 var_CreateGetBoolCommand( p_filter, CFG_PREFIX "zone-summary")
1476 p_atmo_config->setLiveViewFilterMode(
1477 (AtmoFilterMode)var_CreateGetIntegerCommand( p_filter,
1478 CFG_PREFIX "filtermode")
1481 p_atmo_config->setLiveViewFilter_PercentNew(
1482 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "percentnew")
1484 p_atmo_config->setLiveViewFilter_MeanLength(
1485 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "meanlength")
1487 p_atmo_config->setLiveViewFilter_MeanThreshold(
1488 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "meanthreshold")
1491 p_atmo_config->setLiveView_EdgeWeighting(
1492 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "edgeweightning")
1494 p_atmo_config->setLiveView_BrightCorrect(
1495 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "brightness")
1497 p_atmo_config->setLiveView_DarknessLimit(
1498 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "darknesslimit")
1500 p_atmo_config->setLiveView_HueWinSize(
1501 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "huewinsize")
1503 p_atmo_config->setLiveView_SatWinSize(
1504 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "satwinsize")
1507 /* currently not required inside vlc */
1508 p_atmo_config->setLiveView_WidescreenMode( 0 );
1510 p_atmo_config->setLiveView_FrameDelay(
1511 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "framedelay")
1515 p_atmo_config->setUseSoftwareWhiteAdj(
1516 var_CreateGetBoolCommand( p_filter, CFG_PREFIX "whiteadj")
1518 p_atmo_config->setWhiteAdjustment_Red(
1519 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-red")
1521 p_atmo_config->setWhiteAdjustment_Green(
1522 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-green")
1524 p_atmo_config->setWhiteAdjustment_Blue(
1525 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-blue")
1529 settings for DMX device only
1531 p_atmo_config->setDMX_RGB_Channels(
1532 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "dmx-channels")
1535 char *psz_chbase = var_CreateGetStringCommand( p_filter,
1536 CFG_PREFIX "dmx-chbase" );
1537 if( !EMPTY_STR(psz_chbase) )
1538 p_atmo_config->setDMX_BaseChannels( psz_chbase );
1545 p_atmo_config->setMoMo_Channels(
1546 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "momo-channels")
1552 p_atmo_config->setFnordlicht_Amount(
1553 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "fnordlicht-amount")
1560 initialize the filter_sys_t structure with the data from the settings
1561 variables - if the external filter on win32 is enabled try loading the DLL,
1562 if this fails fallback to the buildin software
1564 static void Atmo_SetupParameters(filter_t *p_filter)
1566 filter_sys_t *p_sys = p_filter->p_sys;
1569 /* default filter disabled until DLL loaded and Init Success!*/
1570 p_sys->b_enabled = false;
1572 /* setup default mini image size (may be later a user option) */
1573 p_sys->i_atmo_width = 64;
1574 p_sys->i_atmo_height = 48;
1576 p_sys->i_device_type = var_CreateGetIntegerCommand( p_filter,
1577 CFG_PREFIX "device");
1581 0 => use AtmoWin Software (only win32)
1582 1 => use AtmoClassicConnection (direct)
1583 2 => use AtmoMultiConnection (direct up to four serial ports required)
1584 3 => use AtmoDmxConnection (simple serial DMX Device up to 255 channels)
1590 only on WIN32 the user has the choice between
1591 internal driver and external
1594 if(p_sys->i_device_type == 0) {
1596 /* Load the Com Wrapper Library (source available) */
1597 p_sys->h_AtmoCtrl = LoadLibraryA("AtmoCtrlLib.dll");
1598 if(p_sys->h_AtmoCtrl == NULL)
1601 be clever if the location of atmowina.exe is set
1602 try to load the dll from the same folder :-)
1604 char *psz_path = var_CreateGetStringCommand( p_filter,
1605 CFG_PREFIX "atmowinexe" );
1606 if( !EMPTY_STR(psz_path) )
1608 char *psz_bs = strrchr( psz_path , '\\');
1613 now format a new dll filename with complete path
1615 char *psz_dllname = NULL;
1616 asprintf( &psz_dllname, "%s\\AtmoCtrlLib.dll", psz_path );
1619 msg_Dbg( p_filter, "Try Loading '%s'", psz_dllname );
1620 p_sys->h_AtmoCtrl = LoadLibraryA( psz_dllname );
1622 free( psz_dllname );
1629 if(p_sys->h_AtmoCtrl != NULL)
1631 msg_Dbg( p_filter, "Load Library ok!");
1633 /* importing all required functions I hope*/
1634 p_sys->pf_ctrl_atmo_initialize =
1635 (int32_t (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,
1637 if(!p_sys->pf_ctrl_atmo_initialize)
1638 msg_Err( p_filter, "export AtmoInitialize missing.");
1640 p_sys->pf_ctrl_atmo_finalize =
1641 (void (*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,
1643 if(!p_sys->pf_ctrl_atmo_finalize)
1644 msg_Err( p_filter, "export AtmoFinalize missing.");
1646 p_sys->pf_ctrl_atmo_switch_effect =
1647 (int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,
1648 "AtmoSwitchEffect");
1649 if(!p_sys->pf_ctrl_atmo_switch_effect)
1650 msg_Err( p_filter, "export AtmoSwitchEffect missing.");
1652 p_sys->pf_ctrl_atmo_set_live_source =
1653 (int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,
1654 "AtmoSetLiveSource");
1655 if(!p_sys->pf_ctrl_atmo_set_live_source)
1656 msg_Err( p_filter, "export AtmoSetLiveSource missing.");
1658 p_sys->pf_ctrl_atmo_create_transfer_buffers =
1659 (void (*)(int32_t, int32_t, int32_t , int32_t))
1660 GetProcAddress(p_sys->h_AtmoCtrl,"AtmoCreateTransferBuffers");
1661 if(!p_sys->pf_ctrl_atmo_create_transfer_buffers)
1662 msg_Err( p_filter, "export AtmoCreateTransferBuffers missing.");
1664 p_sys->pf_ctrl_atmo_lock_transfer_buffer=
1665 (uint8_t*(*) (void))GetProcAddress(p_sys->h_AtmoCtrl,
1666 "AtmoLockTransferBuffer");
1667 if(!p_sys->pf_ctrl_atmo_lock_transfer_buffer)
1668 msg_Err( p_filter, "export AtmoLockTransferBuffer missing.");
1670 p_sys->pf_ctrl_atmo_send_pixel_data =
1671 (void (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,
1672 "AtmoSendPixelData");
1673 if(!p_sys->pf_ctrl_atmo_send_pixel_data)
1674 msg_Err( p_filter, "export AtmoSendPixelData missing.");
1676 p_sys->pf_ctrl_atmo_get_image_size =
1677 (void (*)(int32_t*,int32_t*))GetProcAddress(p_sys->h_AtmoCtrl,
1678 "AtmoWinGetImageSize");
1679 if(!p_sys->pf_ctrl_atmo_get_image_size)
1680 msg_Err( p_filter, "export AtmoWinGetImageSize missing.");
1683 /* the DLL is missing try internal filter ...*/
1685 "AtmoCtrlLib.dll missing fallback to internal atmo classic driver");
1686 p_sys->i_device_type = 1;
1691 if(p_sys->i_device_type >= 1) {
1692 msg_Dbg( p_filter, "try use buildin driver %d ", p_sys->i_device_type);
1694 now we have to read a lof of options from the config dialog
1695 most important the serial device if not set ... we can skip
1696 the rest and disable the filter...
1699 p_sys->p_atmo_config = new CAtmoConfig();
1701 p_sys->p_atmo_dyndata = new CAtmoDynData(
1702 (vlc_object_t *)p_filter,
1703 p_sys->p_atmo_config
1706 Atmo_SetupConfig( p_filter, p_sys->p_atmo_config );
1707 switch(p_sys->i_device_type)
1710 p_sys->p_atmo_config->setConnectionType( actClassicAtmo );
1714 p_sys->p_atmo_config->setConnectionType( actMultiAtmo );
1718 p_sys->p_atmo_config->setConnectionType( actDMX );
1722 p_sys->p_atmo_config->setConnectionType( actMoMoLight );
1726 p_sys->p_atmo_config->setConnectionType( actFnordlicht );
1730 msg_Warn( p_filter, "invalid device type %d found",
1731 p_sys->i_device_type );
1734 msg_Dbg( p_filter, "buildin driver config set");
1738 switch( p_filter->fmt_in.video.i_chroma )
1740 case VLC_CODEC_I420:
1741 p_sys->pf_extract_mini_image = ExtractMiniImage_YUV;
1742 p_sys->b_swap_uv = false;
1744 case VLC_CODEC_YV12:
1745 p_sys->pf_extract_mini_image = ExtractMiniImage_YUV;
1746 p_sys->b_swap_uv = true;
1749 msg_Warn( p_filter, "InitFilter-unsupported chroma: %4.4s",
1750 (char *)&p_filter->fmt_in.video.i_chroma);
1751 p_sys->pf_extract_mini_image = NULL;
1755 for debugging purpose show the samplinggrid on each frame as
1758 p_sys->b_show_dots = var_CreateGetBoolCommand( p_filter,
1759 CFG_PREFIX "showdots"
1762 #if defined(__ATMO_DEBUG__)
1763 /* save debug images to a folder as Bitmap files ? */
1764 p_sys->b_saveframes = var_CreateGetBoolCommand( p_filter,
1765 CFG_PREFIX "saveframes"
1767 msg_Dbg(p_filter,"saveframes = %d", (int)p_sys->b_saveframes);
1770 read debug image folder from config
1772 psz_path = var_CreateGetStringCommand( p_filter, CFG_PREFIX "framepath" );
1773 if(psz_path != NULL)
1775 strcpy(p_sys->sz_framepath, psz_path);
1776 #if defined( WIN32 ) || defined( __OS2__ )
1777 size_t i_strlen = strlen(p_sys->sz_framepath);
1778 if((i_strlen>0) && (p_sys->sz_framepath[i_strlen-1] != '\\'))
1780 p_sys->sz_framepath[i_strlen] = '\\';
1781 p_sys->sz_framepath[i_strlen+1] = 0;
1786 msg_Dbg(p_filter,"saveframesfolder %s",p_sys->sz_framepath);
1791 because atmowin could also be used for lighten up the room - I think if you
1792 pause the video it would be useful to get a little bit more light into to
1793 your living room? - instead switching on a lamp?
1795 p_sys->b_usepausecolor = var_CreateGetBoolCommand( p_filter,
1796 CFG_PREFIX "usepausecolor" );
1797 p_sys->ui_pausecolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1798 CFG_PREFIX "pcolor-red");
1799 p_sys->ui_pausecolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1800 CFG_PREFIX "pcolor-green");
1801 p_sys->ui_pausecolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1802 CFG_PREFIX "pcolor-blue");
1803 p_sys->i_fadesteps = var_CreateGetIntegerCommand( p_filter,
1804 CFG_PREFIX "fadesteps");
1805 if(p_sys->i_fadesteps < 1)
1806 p_sys->i_fadesteps = 1;
1807 msg_Dbg(p_filter,"use pause color %d, RGB: %d, %d, %d, Fadesteps: %d",
1808 (int)p_sys->b_usepausecolor,
1809 p_sys->ui_pausecolor_red,
1810 p_sys->ui_pausecolor_green,
1811 p_sys->ui_pausecolor_blue,
1812 p_sys->i_fadesteps);
1815 this color is use on shutdown of the filter - the define the
1816 final light after playback... may be used to dim up the light -
1817 how it happens in the cinema...
1819 p_sys->ui_endcolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1820 CFG_PREFIX "ecolor-red");
1821 p_sys->ui_endcolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1822 CFG_PREFIX "ecolor-green");
1823 p_sys->ui_endcolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1824 CFG_PREFIX "ecolor-blue");
1825 p_sys->i_endfadesteps = var_CreateGetIntegerCommand( p_filter,
1826 CFG_PREFIX "efadesteps");
1827 if(p_sys->i_endfadesteps < 1)
1828 p_sys->i_endfadesteps = 1;
1829 msg_Dbg(p_filter,"use ende color RGB: %d, %d, %d, Fadesteps: %d",
1830 p_sys->ui_endcolor_red,
1831 p_sys->ui_endcolor_green,
1832 p_sys->ui_endcolor_blue,
1833 p_sys->i_endfadesteps);
1838 if the external DLL was loaded successfully call AtmoInitialize -
1839 (must be done for each thread where you want to use AtmoLight!)
1841 int i = AtmoInitialize(p_filter, false);
1843 #if defined( WIN32 )
1844 if((i != 1) && (p_sys->i_device_type == 0))
1847 COM Server for AtmoLight not running ?
1848 if the exe path is configured try to start the "userspace" driver
1850 char *psz_path = var_CreateGetStringCommand( p_filter,
1851 CFG_PREFIX "atmowinexe" );
1852 if(psz_path != NULL)
1854 STARTUPINFO startupinfo;
1855 PROCESS_INFORMATION pinfo;
1856 memset(&startupinfo, 0, sizeof(STARTUPINFO));
1857 startupinfo.cb = sizeof(STARTUPINFO);
1858 if(CreateProcess(psz_path, NULL, NULL, NULL,
1859 FALSE, 0, NULL, NULL, &startupinfo, &pinfo) == TRUE)
1861 msg_Dbg(p_filter,"launched AtmoWin from %s",psz_path);
1862 WaitForInputIdle(pinfo.hProcess, 5000);
1864 retry to initialize the library COM ... functionality
1865 after the server was launched
1867 i = AtmoInitialize(p_filter, false);
1869 msg_Err(p_filter,"failed to launch AtmoWin from %s", psz_path);
1876 if(i == 1) /* Init Atmolight success... */
1878 msg_Dbg( p_filter, "AtmoInitialize Ok!");
1881 p_sys->i_atmo_width and p_sys->i_atmo_height
1882 if the external AtmoWinA.exe is used, it may require
1883 a other sample image size than 64 x 48
1884 (this overrides the settings of the filter)
1886 Atmo_SetupImageSize( p_filter );
1889 if( p_sys->i_device_type >= 1 )
1892 AtmoConnection class initialized now we can initialize
1893 the default zone and channel mappings
1895 Atmo_SetupBuildZones( p_filter );
1898 /* Setup Transferbuffers for 64 x 48 , RGB with 32bit Per Pixel */
1899 AtmoCreateTransferBuffers(p_filter, BI_RGB, 4,
1900 p_sys->i_atmo_width,
1901 p_sys->i_atmo_height
1904 /* say the userspace driver that a live mode should be activated
1905 the functions returns the old mode for later restore!
1906 - the buildin driver launches the live view thread in that case
1908 p_sys->i_AtmoOldEffect = AtmoSwitchEffect(p_filter, emLivePicture);
1911 live view can have two differnt source the AtmoWinA
1912 internal GDI Screencapture and the external one - which we
1915 AtmoSetLiveSource(p_filter, lvsExternal);
1917 /* enable other parts only if everything is fine */
1918 p_sys->b_enabled = true;
1920 msg_Dbg( p_filter, "Atmo Filter Enabled Ok!");
1926 /*****************************************************************************
1927 * CreateFilter: allocates AtmoLight video thread output method
1928 *****************************************************************************
1929 * This function allocates and initializes a AtmoLight vout method.
1930 *****************************************************************************/
1931 static int CreateFilter( vlc_object_t *p_this )
1933 filter_t *p_filter = (filter_t *)p_this;
1934 filter_sys_t *p_sys;
1936 /* Allocate structure */
1937 p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) );
1938 p_filter->p_sys = p_sys;
1939 if( p_filter->p_sys == NULL )
1941 /* set all entries to zero */
1942 memset(p_sys, 0, sizeof( filter_sys_t ));
1943 vlc_mutex_init( &p_sys->filter_lock );
1945 msg_Dbg( p_filter, "Create Atmo Filter");
1947 /* further Setup Function pointers for videolan for calling my filter */
1948 p_filter->pf_video_filter = Filter;
1950 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
1953 AddStateVariableCallback(p_filter);
1955 AddAtmoSettingsVariablesCallbacks(p_filter);
1957 Atmo_SetupParameters(p_filter);
1965 /*****************************************************************************
1966 * DestroyFilter: destroy AtmoLight video thread output method
1967 *****************************************************************************
1968 * Terminate an output method created by CreateFilter
1969 *****************************************************************************/
1971 static void DestroyFilter( vlc_object_t *p_this )
1973 filter_t *p_filter = (filter_t *)p_this;
1974 filter_sys_t *p_sys = p_filter->p_sys;
1976 msg_Dbg( p_filter, "Destroy Atmo Filter");
1978 DelStateVariableCallback(p_filter);
1980 DelAtmoSettingsVariablesCallbacks(p_filter);
1982 Atmo_Shutdown(p_filter);
1984 #if defined( WIN32 )
1985 if(p_sys->h_AtmoCtrl != NULL)
1987 FreeLibrary(p_sys->h_AtmoCtrl);
1991 delete p_sys->p_atmo_dyndata;
1992 delete p_sys->p_atmo_config;
1994 vlc_mutex_destroy( &p_sys->filter_lock );
2001 function stolen from some other videolan source filter ;-)
2002 for the moment RGB is OK... but better would be a direct transformation
2005 static inline void yuv_to_rgb( uint8_t *r, uint8_t *g, uint8_t *b,
2006 uint8_t y1, uint8_t u1, uint8_t v1 )
2008 /* macros used for YUV pixel conversions */
2009 # define SCALEBITS 10
2010 # define ONE_HALF (1 << (SCALEBITS - 1))
2011 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
2012 # define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
2014 int y, cb, cr, r_add, g_add, b_add;
2018 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
2019 g_add = - FIX(0.34414*255.0/224.0) * cb
2020 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
2021 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
2022 y = (y1 - 16) * FIX(255.0/219.0);
2023 *r = CLAMP((y + r_add) >> SCALEBITS);
2024 *g = CLAMP((y + g_add) >> SCALEBITS);
2025 *b = CLAMP((y + b_add) >> SCALEBITS);
2027 /******************************************************************************
2028 * ExtractMiniImage_YUV: extract a small image from the picture as 24-bit RGB
2029 *******************************************************************************
2030 * p_sys is a pointer to
2031 * p_inpic is the source frame
2032 * p_transfer_dest is the target buffer for the picture must be big enough!
2033 * (in win32 environment this buffer comes from the external DLL where it is
2034 * create as "variant array" and returned through the AtmoLockTransferbuffer
2036 static void ExtractMiniImage_YUV(filter_sys_t *p_sys,
2038 uint8_t *p_transfer_dest)
2045 uint8_t *p_rgb_dst_line_red;
2046 uint8_t *p_rgb_dst_line_green;
2047 uint8_t *p_rgb_dst_line_blue;
2052 /* calcute Pointers for Storage of B G R (A) */
2053 p_rgb_dst_line_blue = p_transfer_dest;
2054 p_rgb_dst_line_green = p_transfer_dest + 1;
2055 p_rgb_dst_line_red = p_transfer_dest + 2 ;
2057 int i_row_count = p_sys->i_atmo_height + 1;
2058 int i_col_count = p_sys->i_atmo_width + 1;
2059 int i_y_row,i_u_row,i_v_row,i_pixel_row;
2063 /* these two ugly loops extract the small image - goes it faster? how?
2064 the loops are so designed that there is a small border around the extracted
2065 image so we wont get column and row - zero from the frame, and not the most
2066 right and bottom pixels --- which may be clipped on computers useing TV out
2069 TODO: try to find out if the output is clipped through VLC - and try here
2070 to ingore the clipped away area for a better result!
2072 TODO: performance improvement in InitFilter percalculated the offsets of
2073 the lines inside the planes so I can save (i_row_count * 3) 2xMUL and
2074 one time DIV the same could be done for the inner loop I think...
2076 for(i_row = 1; i_row < i_row_count; i_row++)
2078 // calcute the current Lines in the source planes for this outputrow
2079 /* Adresscalcuation pointer to plane Length of one pixelrow in bytes
2080 calculate row now number
2083 p_inpic->format? transform Pixel row into row of plane...
2084 how? simple? fast? good?
2087 /* compute the source pixel row and respect the active cropping */
2088 i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
2089 + p_sys->i_crop_y_offset;
2092 trans for these Pixel row into the row of each plane ..
2093 because planesize can differ from image size
2095 i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
2096 p_inpic->format.i_visible_height;
2098 i_u_row = (i_pixel_row * p_inpic->p[U_PLANE].i_visible_lines) /
2099 p_inpic->format.i_visible_height;
2101 i_v_row = (i_pixel_row * p_inpic->p[V_PLANE].i_visible_lines) /
2102 p_inpic->format.i_visible_height;
2104 /* calculate the pointers to the pixeldata for this row
2107 p_src_y = p_inpic->p[Y_PLANE].p_pixels +
2108 p_inpic->p[Y_PLANE].i_pitch * i_y_row;
2109 p_src_u = p_inpic->p[U_PLANE].p_pixels +
2110 p_inpic->p[U_PLANE].i_pitch * i_u_row;
2111 p_src_v = p_inpic->p[V_PLANE].p_pixels +
2112 p_inpic->p[V_PLANE].i_pitch * i_v_row;
2114 if(p_sys->b_swap_uv)
2117 swap u and v plane for YV12 images
2119 uint8_t *p_temp_plane = p_src_u;
2121 p_src_v = p_temp_plane;
2124 for(i_col = 1; i_col < i_col_count; i_col++)
2126 i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
2127 p_sys->i_crop_x_offset;
2129 trans for these Pixel row into the row of each plane ..
2130 because planesize can differ from image size
2132 i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
2133 p_inpic->format.i_visible_width;
2134 i_xpos_u = (i_pixel_col * p_inpic->p[U_PLANE].i_visible_pitch) /
2135 p_inpic->format.i_visible_width;
2136 i_xpos_v = (i_pixel_col * p_inpic->p[V_PLANE].i_visible_pitch) /
2137 p_inpic->format.i_visible_width;
2139 yuv_to_rgb(p_rgb_dst_line_red,
2140 p_rgb_dst_line_green,
2141 p_rgb_dst_line_blue,
2147 /* +4 because output image should be RGB32 with dword alignment! */
2148 p_rgb_dst_line_red += 4;
2149 p_rgb_dst_line_green += 4;
2150 p_rgb_dst_line_blue += 4;
2154 if(p_sys->b_show_dots)
2156 for(i_row = 1; i_row < i_row_count; i_row++)
2158 i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
2159 + p_sys->i_crop_y_offset;
2161 i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
2162 p_inpic->format.i_visible_height;
2164 p_src_y = p_inpic->p[Y_PLANE].p_pixels +
2165 p_inpic->p[Y_PLANE].i_pitch * i_y_row;
2167 for(i_col = 1; i_col < i_col_count; i_col++)
2169 i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
2170 p_sys->i_crop_x_offset;
2171 i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
2172 p_inpic->format.i_visible_width;
2174 p_src_y[i_xpos_y] = 255;
2182 /******************************************************************************
2183 * SaveBitmap: Saves the content of a transferbuffer as Bitmap to disk
2184 *******************************************************************************
2185 * just for debugging
2186 * p_sys -> configuration if Atmo from there the function will get height and
2188 * p_pixels -> should be the dword aligned BGR(A) image data
2189 * psz_filename -> filename where to store
2191 #if defined(__ATMO_DEBUG__)
2192 void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename)
2194 /* for debug out only used*/
2195 BITMAPINFO bmp_info;
2196 BITMAPFILEHEADER bmp_fileheader;
2199 memset(&bmp_info, 0, sizeof(BITMAPINFO));
2200 bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2201 bmp_info.bmiHeader.biSizeImage = p_sys->i_atmo_height *
2202 p_sys->i_atmo_width * 4;
2203 bmp_info.bmiHeader.biCompression = BI_RGB;
2204 bmp_info.bmiHeader.biWidth = p_sys->i_atmo_width;
2205 bmp_info.bmiHeader.biHeight = -p_sys->i_atmo_height;
2206 bmp_info.bmiHeader.biBitCount = 32;
2207 bmp_info.bmiHeader.biPlanes = 1;
2209 bmp_fileheader.bfReserved1 = 0;
2210 bmp_fileheader.bfReserved2 = 0;
2211 bmp_fileheader.bfSize = sizeof(BITMAPFILEHEADER) +
2212 sizeof(BITMAPINFOHEADER) +
2213 bmp_info.bmiHeader.biSizeImage;
2214 bmp_fileheader.bfType = VLC_TWOCC('B','M');
2215 bmp_fileheader.bfOffBits = sizeof(BITMAPFILEHEADER) +
2216 sizeof(BITMAPINFOHEADER);
2218 fp_bitmap = fopen(psz_filename,"wb");
2219 if( fp_bitmap != NULL)
2221 fwrite(&bmp_fileheader, sizeof(BITMAPFILEHEADER), 1, fp_bitmap);
2222 fwrite(&bmp_info.bmiHeader, sizeof(BITMAPINFOHEADER), 1, fp_bitmap);
2223 fwrite(p_pixels, bmp_info.bmiHeader.biSizeImage, 1, fp_bitmap);
2230 /****************************************************************************
2231 * CreateMiniImage: extracts a 64x48 pixel image from the frame
2232 * (there is a small border arround thats why the loops starts with one
2233 * instead zero) without any interpolation
2234 *****************************************************************************/
2235 static void CreateMiniImage( filter_t *p_filter, picture_t *p_inpic)
2237 filter_sys_t *p_sys = p_filter->p_sys;
2239 pointer to RGB Buffer created in external libary as safe array which
2240 is locked inside AtmoLockTransferBuffer
2242 uint8_t *p_transfer;
2243 #if defined( __ATMO_DEBUG__ )
2244 /* for debug out only used*/
2245 char sz_filename[MAX_PATH];
2249 Lock the before created VarArray (AtmoCreateTransferBuffers)
2250 inside my wrapper library and give me a pointer to the buffer!
2251 below linux a global buffer may be used and protected with a mutex?
2253 p_transfer = AtmoLockTransferBuffer(p_filter);
2254 if(p_transfer == NULL)
2256 msg_Err( p_filter, "AtmoLight no transferbuffer available. "\
2257 "AtmoLight will be disabled!");
2258 p_sys->b_enabled = false;
2263 do the call via pointer to function instead of having a
2266 p_sys->pf_extract_mini_image(p_sys, p_inpic, p_transfer);
2269 #if defined( __ATMO_DEBUG__ )
2271 if debugging enabled save every 128th image to disk
2273 if(p_sys->b_saveframes && p_sys->sz_framepath[0] != 0 )
2276 if((p_sys->ui_frame_counter & 127) == 0)
2278 sprintf(sz_filename,"%satmo_dbg_%06u.bmp",p_sys->sz_framepath,
2279 p_sys->ui_frame_counter);
2280 msg_Dbg(p_filter, "SaveFrame %s",sz_filename);
2282 SaveBitmap(p_sys, p_transfer, sz_filename);
2286 msg_Dbg( p_filter, "AtmoFrame %u Time: %d ms", p_sys->ui_frame_counter,
2288 p_sys->ui_frame_counter++;
2291 p_sys->i_frames_processed++;
2294 /* show the colors on the wall */
2295 AtmoSendPixelData( p_filter );
2301 /*****************************************************************************
2302 * Filter: calls the extract method and forwards the incomming picture 1:1
2303 *****************************************************************************
2305 *****************************************************************************/
2307 static picture_t * Filter( filter_t *p_filter, picture_t *p_pic )
2309 filter_sys_t *p_sys = p_filter->p_sys;
2310 if( !p_pic ) return NULL;
2312 picture_t *p_outpic = filter_NewPicture( p_filter );
2315 picture_Release( p_pic );
2318 picture_CopyPixels( p_outpic, p_pic );
2320 vlc_mutex_lock( &p_sys->filter_lock );
2322 if(p_sys->b_enabled && p_sys->pf_extract_mini_image &&
2323 !p_sys->b_pause_live)
2325 p_sys->i_crop_x_offset = p_filter->fmt_in.video.i_x_offset;
2326 p_sys->i_crop_y_offset = p_filter->fmt_in.video.i_y_offset;
2327 p_sys->i_crop_width = p_filter->fmt_in.video.i_visible_width;
2328 p_sys->i_crop_height = p_filter->fmt_in.video.i_visible_height;
2330 CreateMiniImage(p_filter, p_outpic);
2333 vlc_mutex_unlock( &p_sys->filter_lock );
2336 return CopyInfoAndRelease( p_outpic, p_pic );
2340 /*****************************************************************************
2341 * FadeToColorThread: Threadmethod which changes slowly the color
2342 * to a target color defined in p_fadethread struct
2343 * use for: Fade to Pause Color, and Fade to End Color
2344 *****************************************************************************/
2345 static void *FadeToColorThread(void *obj)
2347 fadethread_t *p_fadethread = (fadethread_t *)obj;
2348 filter_sys_t *p_sys = (filter_sys_t *)p_fadethread->p_filter->p_sys;
2349 int i_steps_done = 0;
2359 uint8_t *p_source = NULL;
2361 int canc = vlc_savecancel ();
2362 /* initialize AtmoWin for this thread! */
2363 AtmoInitialize(p_fadethread->p_filter , true);
2365 uint8_t *p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
2366 if(p_transfer != NULL) {
2367 /* safe colors as "32bit" Integers to avoid overflows*/
2368 i_pause_red = p_fadethread->ui_red;
2369 i_pause_blue = p_fadethread->ui_blue;
2370 i_pause_green = p_fadethread->ui_green;
2373 allocate a temporary buffer for the last send
2374 image size less then 15kb
2376 int i_size = 4 * p_sys->i_atmo_width * p_sys->i_atmo_height;
2377 p_source = (uint8_t *)malloc( i_size );
2378 if(p_source != NULL)
2381 get a copy of the last transfered image as orign for the
2384 memcpy(p_source, p_transfer, i_size);
2385 /* send the same pixel data again... to unlock the buffer! */
2386 AtmoSendPixelData( p_fadethread->p_filter );
2388 while( (!vlc_atomic_get (&p_fadethread->abort)) &&
2389 (i_steps_done < p_fadethread->i_steps))
2391 p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
2392 if(!p_transfer) break; /* should not happen if it worked
2393 one time in the code above! */
2396 move all pixels in the mini image (64x48) one step closer to
2397 the desired color these loop takes the most time of this
2398 thread improvements wellcome!
2401 (i_index < i_size) && (!vlc_atomic_get (&p_fadethread->abort));
2404 i_src_blue = p_source[i_index+0];
2405 i_src_green = p_source[i_index+1];
2406 i_src_red = p_source[i_index+2];
2407 p_transfer[i_index+0] = (uint8_t) (((
2408 (i_pause_blue - i_src_blue)
2409 * i_steps_done)/p_fadethread->i_steps)
2412 p_transfer[i_index+1] = (uint8_t) (((
2413 (i_pause_green - i_src_green)
2414 * i_steps_done)/p_fadethread->i_steps)
2417 p_transfer[i_index+2] = (uint8_t) (((
2418 (i_pause_red - i_src_red)
2419 * i_steps_done)/p_fadethread->i_steps)
2423 /* send image to lightcontroller */
2424 AtmoSendPixelData( p_fadethread->p_filter );
2425 /* is there something like and interruptable sleep inside
2426 the VLC libaries? inside native win32 I would use an Event
2427 (CreateEvent) and here an WaitForSingleObject?
2433 /* in failure of malloc also unlock buffer */
2434 AtmoSendPixelData(p_fadethread->p_filter);
2437 /* call indirect to OleUnitialize() for this thread */
2438 AtmoFinalize(p_fadethread->p_filter, 0);
2439 vlc_restorecancel (canc);
2443 /*****************************************************************************
2444 * CheckAndStopFadeThread: if there is a fadethread structure left, or running.
2445 ******************************************************************************
2446 * this function will stop the thread ... and waits for its termination
2447 * before removeing the objects from vout_sys_t ...
2448 ******************************************************************************/
2449 static void CheckAndStopFadeThread(filter_t *p_filter)
2451 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2452 vlc_mutex_lock( &p_sys->filter_lock );
2453 if(p_sys->p_fadethread != NULL)
2455 msg_Dbg(p_filter, "kill still running fadeing thread...");
2457 vlc_atomic_set(&p_sys->p_fadethread->abort, 1);
2459 vlc_join(p_sys->p_fadethread->thread, NULL);
2460 free(p_sys->p_fadethread);
2461 p_sys->p_fadethread = NULL;
2463 vlc_mutex_unlock( &p_sys->filter_lock );
2466 /*****************************************************************************
2467 * StateCallback: Callback for the inputs variable "State" to get notified
2468 * about Pause and Continue Playback events.
2469 *****************************************************************************/
2470 static int StateCallback( vlc_object_t *, char const *,
2471 vlc_value_t oldval, vlc_value_t newval,
2474 filter_t *p_filter = (filter_t *)p_data;
2475 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2477 if(p_sys->b_usepausecolor && p_sys->b_enabled)
2479 msg_Dbg(p_filter, "state change from: %"PRId64" to %"PRId64, oldval.i_int,
2482 if((newval.i_int == PAUSE_S) && (oldval.i_int == PLAYING_S))
2484 /* tell the other thread to stop sending images to light
2486 p_sys->b_pause_live = true;
2488 // clean up old thread - should not happen....
2489 CheckAndStopFadeThread( p_filter );
2491 // perpare spawn fadeing thread
2492 vlc_mutex_lock( &p_sys->filter_lock );
2494 launch only a new thread if there is none active!
2495 or waiting for cleanup
2497 if(p_sys->p_fadethread == NULL)
2499 p_sys->p_fadethread = (fadethread_t *)calloc( 1, sizeof(fadethread_t) );
2500 p_sys->p_fadethread->p_filter = p_filter;
2501 p_sys->p_fadethread->ui_red = p_sys->ui_pausecolor_red;
2502 p_sys->p_fadethread->ui_green = p_sys->ui_pausecolor_green;
2503 p_sys->p_fadethread->ui_blue = p_sys->ui_pausecolor_blue;
2504 p_sys->p_fadethread->i_steps = p_sys->i_fadesteps;
2505 vlc_atomic_set(&p_sys->p_fadethread->abort, 0);
2507 if( vlc_clone( &p_sys->p_fadethread->thread,
2509 p_sys->p_fadethread,
2510 VLC_THREAD_PRIORITY_LOW ) )
2512 msg_Err( p_filter, "cannot create FadeToColorThread" );
2513 free( p_sys->p_fadethread );
2514 p_sys->p_fadethread = NULL;
2517 vlc_mutex_unlock( &p_sys->filter_lock );
2520 if((newval.i_int == PLAYING_S) && (oldval.i_int == PAUSE_S))
2522 /* playback continues check thread state */
2523 CheckAndStopFadeThread( p_filter );
2524 /* reactivate the Render function... to do its normal work */
2525 p_sys->b_pause_live = false;
2532 /*****************************************************************************
2533 * AddPlaylistInputThreadStateCallback: Setup call back on "State" Variable
2534 *****************************************************************************
2535 * Add Callback function to the "state" variable of the input thread..
2536 * first find the PlayList and get the input thread from there to attach
2538 *****************************************************************************/
2539 static void AddStateVariableCallback(filter_t *p_filter)
2541 input_thread_t *p_input = playlist_CurrentInput( pl_Get( p_filter ) );
2544 var_AddCallback( p_input, "state", StateCallback, p_filter );
2545 vlc_object_release( p_input );
2549 /*****************************************************************************
2550 * DelPlaylistInputThreadStateCallback: Remove call back on "State" Variable
2551 *****************************************************************************
2552 * Delete the callback function to the "state" variable of the input thread...
2553 * first find the PlayList and get the input thread from there to attach
2555 *****************************************************************************/
2556 static void DelStateVariableCallback( filter_t *p_filter )
2558 input_thread_t *p_input = playlist_CurrentInput( pl_Get ( p_filter ) );
2561 var_DelCallback( p_input, "state", StateCallback, p_filter );
2562 vlc_object_release( p_input );
2566 /****************************************************************************
2567 * StateCallback: Callback for the inputs variable "State" to get notified
2568 * about Pause and Continue Playback events.
2569 *****************************************************************************/
2570 static int AtmoSettingsCallback( vlc_object_t *, char const *psz_var,
2571 vlc_value_t oldval, vlc_value_t newval,
2574 filter_t *p_filter = (filter_t *)p_data;
2575 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2577 vlc_mutex_lock( &p_sys->filter_lock );
2579 if( !strcmp( psz_var, CFG_PREFIX "showdots" ))
2581 p_sys->b_show_dots = newval.b_bool;
2584 CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
2588 msg_Dbg(p_filter, "apply AtmoSettingsCallback %s (int: %"PRId64" -> %"PRId64")",
2594 if( !strcmp( psz_var, CFG_PREFIX "filtermode" ))
2595 p_atmo_config->setLiveViewFilterMode( (AtmoFilterMode)newval.i_int);
2597 else if( !strcmp( psz_var, CFG_PREFIX "percentnew" ))
2598 p_atmo_config->setLiveViewFilter_PercentNew( newval.i_int );
2600 else if( !strcmp( psz_var, CFG_PREFIX "meanlength" ))
2601 p_atmo_config->setLiveViewFilter_MeanLength( newval.i_int );
2603 else if( !strcmp( psz_var, CFG_PREFIX "meanthreshold" ))
2604 p_atmo_config->setLiveViewFilter_MeanThreshold( newval.i_int );
2606 else if( !strcmp( psz_var, CFG_PREFIX "edgeweightning" ))
2607 p_atmo_config->setLiveView_EdgeWeighting( newval.i_int );
2609 else if( !strcmp( psz_var, CFG_PREFIX "brightness" ))
2610 p_atmo_config->setLiveView_BrightCorrect( newval.i_int );
2612 else if( !strcmp( psz_var, CFG_PREFIX "darknesslimit" ))
2613 p_atmo_config->setLiveView_DarknessLimit( newval.i_int );
2615 else if( !strcmp( psz_var, CFG_PREFIX "huewinsize" ))
2616 p_atmo_config->setLiveView_HueWinSize( newval.i_int );
2618 else if( !strcmp( psz_var, CFG_PREFIX "satwinsize" ))
2619 p_atmo_config->setLiveView_SatWinSize( newval.i_int );
2621 else if( !strcmp( psz_var, CFG_PREFIX "framedelay" ))
2622 p_atmo_config->setLiveView_FrameDelay( newval.i_int );
2624 else if( !strcmp( psz_var, CFG_PREFIX "whiteadj" ))
2625 p_atmo_config->setUseSoftwareWhiteAdj( newval.b_bool );
2627 else if( !strcmp( psz_var, CFG_PREFIX "white-red" ))
2628 p_atmo_config->setWhiteAdjustment_Red( newval.i_int );
2630 else if( !strcmp( psz_var, CFG_PREFIX "white-green" ))
2631 p_atmo_config->setWhiteAdjustment_Green( newval.i_int );
2633 else if( !strcmp( psz_var, CFG_PREFIX "white-blue" ))
2634 p_atmo_config->setWhiteAdjustment_Blue( newval.i_int );
2638 vlc_mutex_unlock( &p_sys->filter_lock );
2643 static void AddAtmoSettingsVariablesCallbacks(filter_t *p_filter)
2645 var_AddCallback( p_filter, CFG_PREFIX "filtermode",
2646 AtmoSettingsCallback, p_filter );
2647 var_AddCallback( p_filter, CFG_PREFIX "percentnew",
2648 AtmoSettingsCallback, p_filter );
2651 var_AddCallback( p_filter, CFG_PREFIX "meanlength",
2652 AtmoSettingsCallback, p_filter );
2653 var_AddCallback( p_filter, CFG_PREFIX "meanthreshold",
2654 AtmoSettingsCallback, p_filter );
2656 var_AddCallback( p_filter, CFG_PREFIX "edgeweightning",
2657 AtmoSettingsCallback, p_filter );
2658 var_AddCallback( p_filter, CFG_PREFIX "brightness",
2659 AtmoSettingsCallback, p_filter );
2660 var_AddCallback( p_filter, CFG_PREFIX "darknesslimit",
2661 AtmoSettingsCallback, p_filter );
2663 var_AddCallback( p_filter, CFG_PREFIX "huewinsize",
2664 AtmoSettingsCallback, p_filter );
2665 var_AddCallback( p_filter, CFG_PREFIX "satwinsize",
2666 AtmoSettingsCallback, p_filter );
2667 var_AddCallback( p_filter, CFG_PREFIX "framedelay",
2668 AtmoSettingsCallback, p_filter );
2671 var_AddCallback( p_filter, CFG_PREFIX "whiteadj",
2672 AtmoSettingsCallback, p_filter );
2673 var_AddCallback( p_filter, CFG_PREFIX "white-red",
2674 AtmoSettingsCallback, p_filter );
2675 var_AddCallback( p_filter, CFG_PREFIX "white-green",
2676 AtmoSettingsCallback, p_filter );
2677 var_AddCallback( p_filter, CFG_PREFIX "white-blue",
2678 AtmoSettingsCallback, p_filter );
2680 var_AddCallback( p_filter, CFG_PREFIX "showdots",
2681 AtmoSettingsCallback, p_filter );
2685 static void DelAtmoSettingsVariablesCallbacks( filter_t *p_filter )
2688 var_DelCallback( p_filter, CFG_PREFIX "filtermode",
2689 AtmoSettingsCallback, p_filter );
2691 var_DelCallback( p_filter, CFG_PREFIX "percentnew",
2692 AtmoSettingsCallback, p_filter );
2693 var_DelCallback( p_filter, CFG_PREFIX "meanlength",
2694 AtmoSettingsCallback, p_filter );
2695 var_DelCallback( p_filter, CFG_PREFIX "meanthreshold",
2696 AtmoSettingsCallback, p_filter );
2698 var_DelCallback( p_filter, CFG_PREFIX "edgeweightning",
2699 AtmoSettingsCallback, p_filter );
2700 var_DelCallback( p_filter, CFG_PREFIX "brightness",
2701 AtmoSettingsCallback, p_filter );
2702 var_DelCallback( p_filter, CFG_PREFIX "darknesslimit",
2703 AtmoSettingsCallback, p_filter );
2705 var_DelCallback( p_filter, CFG_PREFIX "huewinsize",
2706 AtmoSettingsCallback, p_filter );
2707 var_DelCallback( p_filter, CFG_PREFIX "satwinsize",
2708 AtmoSettingsCallback, p_filter );
2709 var_DelCallback( p_filter, CFG_PREFIX "framedelay",
2710 AtmoSettingsCallback, p_filter );
2713 var_DelCallback( p_filter, CFG_PREFIX "whiteadj",
2714 AtmoSettingsCallback, p_filter );
2715 var_DelCallback( p_filter, CFG_PREFIX "white-red",
2716 AtmoSettingsCallback, p_filter );
2717 var_DelCallback( p_filter, CFG_PREFIX "white-green",
2718 AtmoSettingsCallback, p_filter );
2719 var_DelCallback( p_filter, CFG_PREFIX "white-blue",
2720 AtmoSettingsCallback, p_filter );
2722 var_DelCallback( p_filter, CFG_PREFIX "showdots",
2723 AtmoSettingsCallback, p_filter );
2728 #if defined(__ATMO_DEBUG__)
2729 static void atmo_parse_crop(char *psz_cropconfig,
2730 video_format_t fmt_in,
2731 video_format_t fmt_render,
2732 int &i_visible_width, int &i_visible_height,
2733 int &i_x_offset, int &i_y_offset )
2735 int64_t i_aspect_num, i_aspect_den;
2736 unsigned int i_width, i_height;
2738 i_visible_width = fmt_in.i_visible_width;
2739 i_visible_height = fmt_in.i_visible_height;
2740 i_x_offset = fmt_in.i_x_offset;
2741 i_y_offset = fmt_in.i_y_offset;
2743 char *psz_end = NULL, *psz_parser = strchr( psz_cropconfig, ':' );
2746 /* We're using the 3:4 syntax */
2747 i_aspect_num = strtol( psz_cropconfig, &psz_end, 10 );
2748 if( psz_end == psz_cropconfig || !i_aspect_num ) return;
2750 i_aspect_den = strtol( ++psz_parser, &psz_end, 10 );
2751 if( psz_end == psz_parser || !i_aspect_den ) return;
2753 i_width = fmt_in.i_sar_den * fmt_render.i_visible_height *
2754 i_aspect_num / i_aspect_den / fmt_in.i_sar_num;
2756 i_height = fmt_render.i_visible_width*fmt_in.i_sar_num *
2757 i_aspect_den / i_aspect_num / fmt_in.i_sar_den;
2759 if( i_width < fmt_render.i_visible_width )
2761 i_x_offset = fmt_render.i_x_offset +
2762 (fmt_render.i_visible_width - i_width) / 2;
2763 i_visible_width = i_width;
2767 i_y_offset = fmt_render.i_y_offset +
2768 (fmt_render.i_visible_height - i_height) / 2;
2769 i_visible_height = i_height;
2774 psz_parser = strchr( psz_cropconfig, 'x' );
2777 /* Maybe we're using the <width>x<height>+<left>+<top> syntax */
2778 unsigned int i_crop_width, i_crop_height, i_crop_top, i_crop_left;
2780 i_crop_width = strtol( psz_cropconfig, &psz_end, 10 );
2781 if( psz_end != psz_parser ) return;
2783 psz_parser = strchr( ++psz_end, '+' );
2784 i_crop_height = strtol( psz_end, &psz_end, 10 );
2785 if( psz_end != psz_parser ) return;
2787 psz_parser = strchr( ++psz_end, '+' );
2788 i_crop_left = strtol( psz_end, &psz_end, 10 );
2789 if( psz_end != psz_parser ) return;
2792 i_crop_top = strtol( psz_end, &psz_end, 10 );
2793 if( *psz_end != '\0' ) return;
2795 i_width = i_crop_width;
2796 i_visible_width = i_width;
2798 i_height = i_crop_height;
2799 i_visible_height = i_height;
2801 i_x_offset = i_crop_left;
2802 i_y_offset = i_crop_top;
2806 /* Maybe we're using the <left>+<top>+<right>+<bottom> syntax */
2807 unsigned int i_crop_top, i_crop_left, i_crop_bottom, i_crop_right;
2809 psz_parser = strchr( psz_cropconfig, '+' );
2810 i_crop_left = strtol( psz_cropconfig, &psz_end, 10 );
2811 if( psz_end != psz_parser ) return;
2813 psz_parser = strchr( ++psz_end, '+' );
2814 i_crop_top = strtol( psz_end, &psz_end, 10 );
2815 if( psz_end != psz_parser ) return;
2817 psz_parser = strchr( ++psz_end, '+' );
2818 i_crop_right = strtol( psz_end, &psz_end, 10 );
2819 if( psz_end != psz_parser ) return;
2822 i_crop_bottom = strtol( psz_end, &psz_end, 10 );
2823 if( *psz_end != '\0' ) return;
2825 i_width = fmt_render.i_visible_width -
2828 i_visible_width = i_width;
2830 i_height = fmt_render.i_visible_height -
2833 i_visible_height = i_height;
2835 i_x_offset = i_crop_left;
2836 i_y_offset = i_crop_top;