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>
47 #include "filter_picture.h"
50 #include "AtmoDynData.h"
51 #include "AtmoLiveView.h"
52 #include "AtmoTools.h"
53 #include "AtmoExternalCaptureInput.h"
54 #include "AtmoConfig.h"
55 #include "AtmoConnection.h"
56 #include "AtmoClassicConnection.h"
59 /*****************************************************************************
61 *****************************************************************************/
62 /* directly to vlc related functions required that the module is accepted */
63 static int CreateFilter ( vlc_object_t * );
64 static void DestroyFilter ( vlc_object_t * );
65 static picture_t * Filter( filter_t *, picture_t *);
67 /* callback for global variable state pause / continue / stop events */
68 static void AddStateVariableCallback( filter_t *);
69 static void DelStateVariableCallback( filter_t *);
70 static int StateCallback(vlc_object_t *, char const *,
71 vlc_value_t, vlc_value_t, void *);
73 /* callback for atmo settings variables whose change
74 should be immediately realized and applied to output
76 static void DelAtmoSettingsVariablesCallbacks(filter_t *);
77 static void AddAtmoSettingsVariablesCallbacks(filter_t *);
78 static int AtmoSettingsCallback(vlc_object_t *, char const *,
79 vlc_value_t, vlc_value_t, void *);
82 #if defined(__ATMO_DEBUG__)
83 static void atmo_parse_crop(char *psz_cropconfig,
84 video_format_t fmt_in,
85 video_format_t fmt_render,
87 int &i_visible_height,
93 /* function to shutdown the fade thread which is started on pause*/
94 static void CheckAndStopFadeThread(filter_t *);
96 /* extracts a small RGB (BGR) Image from an YUV image */
97 static void ExtractMiniImage_YUV(filter_sys_t *, picture_t *, uint8_t *);
99 #if defined(__ATMO_DEBUG__)
100 void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename);
103 /*****************************************************************************
104 * External Prototypes for the AtmoCtrlLib.DLL
105 *****************************************************************************/
107 * if effectmode = emLivePicture then the source could be GDI (Screencapture)
108 * or External - this means another application delivers Pixeldata to AtmoWin
109 * Clientsoftware through AtmoCtrlLib.DLL and the COM Api
112 #define lvsExternal 1
114 #define CLASSIC_ATMO_NUM_ZONES 5
118 strings for settings menus and hints
120 #define MODULE_DESCRIPTION N_ ( \
121 "This module allows to control an so called AtmoLight device "\
122 "connected to your computer.\n"\
123 "AtmoLight is the homegrown version of what Philips calls AmbiLight.\n"\
124 "If you need further information feel free to visit us at\n\n"\
125 "http://www.vdr-wiki.de/wiki/index.php/Atmo-plugin\n"\
126 "http://www.vdr-wiki.de/wiki/index.php/AtmoWin\n\n"\
127 "You can find there detailed descriptions on how to build it for yourself "\
128 "and where to get the required parts.\n" \
129 "You can also have a look at pictures and some movies showing such a device " \
132 #define DRIVER_TEXT N_("Device type")
133 #define DRIVER_LONGTEXT N_("Choose your preferred hardware from " \
134 "the list, or choose AtmoWin Software " \
135 "to delegate processing to the external " \
136 "process - with more options")
138 static const int pi_device_type_values[] = {
140 0, /* use AtmoWinA.exe userspace driver */
142 1, /* AtmoLight classic */
143 2, /* Quattro AtmoLight */
145 4, /* MoMoLight device */
148 static const char *const ppsz_device_type_descriptions[] = {
150 N_("AtmoWin Software"),
152 N_("Classic AtmoLight"),
153 N_("Quattro AtmoLight"),
159 #define DMX_CHANNELS_TEXT N_("Count of AtmoLight channels")
160 #define DMX_CHANNELS_LONGTEXT N_("How many AtmoLight channels, should be " \
161 "emulated with that DMX device")
162 #define DMX_CHBASE_TEXT N_("DMX address for each channel")
163 #define DMX_CHBASE_LONGTEXT N_("Define here the DMX base address for each " \
164 "channel use , or ; to separate the values")
166 #define MOMO_CHANNELS_TEXT N_("Count of channels")
167 #define MOMO_CHANNELS_LONGTEXT N_("Depending on your MoMoLight hardware " \
168 "choose 3 or 4 channels")
170 #define FNORDLICHT_AMOUNT_TEXT N_("Count of fnordlicht's")
171 #define FNORDLICHT_AMOUNT_LONGTEXT N_("Depending on the amount your " \
172 "fnordlicht hardware " \
173 "choose 1 to 254 channels")
176 # define DEFAULT_DEVICE 0
178 # define DEFAULT_DEVICE 1
181 #if defined( __ATMO_DEBUG__ )
182 # define SAVEFRAMES_TEXT N_("Save Debug Frames")
183 # define SAVEFRAMES_LONGTEXT N_("Write every 128th miniframe to a folder.")
184 # define FRAMEPATH_TEXT N_("Debug Frame Folder")
185 # define FRAMEPATH_LONGTEXT N_("The path where the debugframes " \
189 #define WIDTH_TEXT N_("Extracted Image Width")
190 #define WIDTH_LONGTEXT N_("The width of the mini image for " \
191 "further processing (64 is default)")
193 #define HEIGHT_TEXT N_("Extracted Image Height")
194 #define HEIGHT_LONGTEXT N_("The height of the mini image for " \
195 "further processing (48 is default)")
197 #define SHOW_DOTS_TEXT N_("Mark analyzed pixels")
198 #define SHOW_DOTS_LONGTEXT N_("makes the sample grid visible on screen as "\
201 #define PCOLOR_TEXT N_("Color when paused")
202 #define PCOLOR_LONGTEXT N_("Set the color to show if the user " \
203 "pauses the video. (Have light to get " \
205 #define PCOLOR_RED_TEXT N_("Pause-Red")
206 #define PCOLOR_RED_LONGTEXT N_("Red component of the pause color")
207 #define PCOLOR_GREEN_TEXT N_("Pause-Green")
208 #define PCOLOR_GREEN_LONGTEXT N_("Green component of the pause color")
209 #define PCOLOR_BLUE_TEXT N_("Pause-Blue")
210 #define PCOLOR_BLUE_LONGTEXT N_("Blue component of the pause color")
211 #define FADESTEPS_TEXT N_("Pause-Fadesteps")
212 #define FADESTEPS_LONGTEXT N_("Number of steps to change current color " \
213 "to pause color (each step takes 40ms)")
215 #define ECOLOR_RED_TEXT N_("End-Red")
216 #define ECOLOR_RED_LONGTEXT N_("Red component of the shutdown color")
217 #define ECOLOR_GREEN_TEXT N_("End-Green")
218 #define ECOLOR_GREEN_LONGTEXT N_("Green component of the shutdown color")
219 #define ECOLOR_BLUE_TEXT N_("End-Blue")
220 #define ECOLOR_BLUE_LONGTEXT N_("Blue component of the shutdown color")
221 #define EFADESTEPS_TEXT N_("End-Fadesteps")
222 #define EFADESTEPS_LONGTEXT N_("Number of steps to change current color to " \
223 "end color for dimming up the light in cinema " \
224 "style... (each step takes 40ms)")
226 #define ZONE_TOP_TEXT N_("Number of zones on top")
227 #define ZONE_TOP_LONGTEXT N_("Number of zones on the top of the screen")
228 #define ZONE_BOTTOM_TEXT N_("Number of zones on bottom")
229 #define ZONE_BOTTOM_LONGTEXT N_("Number of zones on the bottom of the screen")
230 #define ZONE_LR_TEXT N_("Zones on left / right side")
231 #define ZONE_LR_LONGTEXT N_("left and right side having allways the " \
232 "same number of zones")
233 #define ZONE_SUMMARY_TEXT N_("Calculate a average zone")
234 #define ZONE_SUMMARY_LONGTEXT N_("it contains the average of all pixels " \
235 "in the sample image (only useful for " \
236 "single channel AtmoLight)")
239 #define USEWHITEADJ_TEXT N_("Use Software White adjust")
240 #define USEWHITEADJ_LONGTEXT N_("Should the buildin driver do a white " \
241 "adjust or your LED stripes? recommend.")
242 #define WHITE_RED_TEXT N_("White Red")
243 #define WHITE_RED_LONGTEXT N_("Red value of a pure white on your "\
245 #define WHITE_GREEN_TEXT N_("White Green")
246 #define WHITE_GREEN_LONGTEXT N_("Green value of a pure white on your "\
248 #define WHITE_BLUE_TEXT N_("White Blue")
249 #define WHITE_BLUE_LONGTEXT N_("Blue value of a pure white on your "\
252 #define SERIALDEV_TEXT N_("Serial Port/Device")
253 #define SERIALDEV_LONGTEXT N_("Name of the serial port where the AtmoLight "\
254 "controller is attached to.\n" \
255 "On Windows usually something like COM1 or " \
256 "COM2. On Linux /dev/ttyS01 f.e.")
258 #define EDGE_TEXT N_("Edge Weightning")
259 #define EDGE_LONGTEXT N_("Increasing this value will result in color "\
260 "more depending on the border of the frame.")
261 #define BRIGHTNESS_TEXT N_("Brightness")
262 #define BRIGHTNESS_LONGTEXT N_("Overall brightness of your LED stripes")
263 #define DARKNESS_TEXT N_("Darkness Limit")
264 #define DARKNESS_LONGTEXT N_("Pixels with a saturation lower than this will "\
265 "be ignored. Should be greater than one for "\
266 "letterboxed videos.")
267 #define HUEWINSIZE_TEXT N_("Hue windowing")
268 #define HUEWINSIZE_LONGTEXT N_("Used for statistics.")
269 #define SATWINSIZE_TEXT N_("Sat windowing")
270 #define SATWINSIZE_LONGTEXT N_("Used for statistics.")
272 #define MEANLENGTH_TEXT N_("Filter length (ms)")
273 #define MEANLENGTH_LONGTEXT N_("Time it takes until a color is completely "\
274 "changed. This prevents flickering.")
275 #define MEANTHRESHOLD_TEXT N_("Filter threshold")
276 #define MEANTHRESHOLD_LONGTEXT N_("How much a color has to be changed for an "\
277 "immediate color change.")
278 #define MEANPERCENTNEW_TEXT N_("Filter Smoothness (in %)")
279 #define MEANPERCENTNEW_LONGTEXT N_("Filter Smoothness")
281 #define FILTERMODE_TEXT N_("Output Color filter mode")
282 #define FILTERMODE_LONGTEXT N_("defines the how the output color should " \
283 "be calculated based on previous color")
285 static const int pi_filtermode_values[] = {
290 static const char *const ppsz_filtermode_descriptions[] = {
296 #define FRAMEDELAY_TEXT N_("Frame delay (ms)")
297 #define FRAMEDELAY_LONGTEXT N_("Helps to get the video output and the light "\
298 "effects in sync. Values around 20ms should " \
302 #define CHANNEL_0_ASSIGN_TEXT N_("Channel 0: summary")
303 #define CHANNEL_1_ASSIGN_TEXT N_("Channel 1: left")
304 #define CHANNEL_2_ASSIGN_TEXT N_("Channel 2: right")
305 #define CHANNEL_3_ASSIGN_TEXT N_("Channel 3: top")
306 #define CHANNEL_4_ASSIGN_TEXT N_("Channel 4: bottom")
308 #define CHANNELASSIGN_LONGTEXT N_("Maps the hardware channel X to logical "\
309 "zone Y to fix wrong wiring :-)")
310 static const int pi_zone_assignment_values[] = {
318 static const char *const ppsz_zone_assignment_descriptions[] = {
320 N_("Zone 4:summary"),
326 #define CHANNELS_ASSIGN_TEXT N_("Channel / Zone Assignment")
327 #define CHANNELS_ASSIGN_LONGTEXT N_("for devices with more than five " \
328 "channels / zones write down here for each channel " \
329 "the zone number to show and separate the values with " \
330 ", or ; and use -1 to not use some channels. For the " \
331 "classic AtmoLight the sequence 4,3,1,0,2 would set the " \
332 "default channel/zone mapping. " \
333 "Having only two zones on top, and one zone on left and " \
334 "right and no summary zone the mapping for classic " \
335 "AtmoLight would be -1,3,2,1,0")
337 #define ZONE_0_GRADIENT_TEXT N_("Zone 0: Top gradient")
338 #define ZONE_1_GRADIENT_TEXT N_("Zone 1: Right gradient")
339 #define ZONE_2_GRADIENT_TEXT N_("Zone 2: Bottom gradient")
340 #define ZONE_3_GRADIENT_TEXT N_("Zone 3: Left gradient")
341 #define ZONE_4_GRADIENT_TEXT N_("Zone 4: Summary gradient")
342 #define ZONE_X_GRADIENT_LONG_TEXT N_("Defines a small bitmap with 64x48 "\
343 "pixels, containing a grayscale gradient")
345 #define GRADIENT_PATH_TEXT N_("Gradient bitmap searchpath")
346 #define GRADIENT_PATH_LONGTEXT N_("Now preferred option to assign gradient "\
347 "bitmaps, put them as zone_0.bmp, zone_1.bmp etc. into one folder and "\
348 "set the foldername here")
351 # define ATMOWINEXE_TEXT N_("Filename of AtmoWin*.exe")
352 # define ATMOWINEXE_LONGTEXT N_("if you want the AtmoLight control "\
353 "software to be launched by VLC, enter the "\
354 "complete path of AtmoWinA.exe here.")
357 #define CFG_PREFIX "atmo-"
359 /*****************************************************************************
361 *****************************************************************************/
363 set_description( N_("AtmoLight Filter") )
364 set_help( MODULE_DESCRIPTION )
365 set_shortname( N_( "AtmoLight" ))
366 set_category( CAT_VIDEO )
367 set_subcategory( SUBCAT_VIDEO_VFILTER )
369 set_capability( "video filter2", 0 )
372 set_section( N_("Choose Devicetype and Connection" ), 0 )
374 add_integer( CFG_PREFIX "device", DEFAULT_DEVICE,
375 DRIVER_TEXT, DRIVER_LONGTEXT, false )
376 change_integer_list( pi_device_type_values,
377 ppsz_device_type_descriptions )
380 add_string(CFG_PREFIX "serialdev", "COM1",
381 SERIALDEV_TEXT, SERIALDEV_LONGTEXT, false )
383 on win32 the executeable external driver application
384 for automatic start if needed
386 add_loadfile(CFG_PREFIX "atmowinexe", NULL,
387 ATMOWINEXE_TEXT, ATMOWINEXE_LONGTEXT, false )
389 add_string(CFG_PREFIX "serialdev", "/dev/ttyUSB0",
390 SERIALDEV_TEXT, SERIALDEV_LONGTEXT, false )
394 color which is showed if you want durring pausing
395 your movie ... used for both buildin / external
397 set_section( N_("Illuminate the room with this color on pause" ), 0 )
398 add_bool(CFG_PREFIX "usepausecolor", false,
399 PCOLOR_TEXT, PCOLOR_LONGTEXT, false)
400 add_integer_with_range(CFG_PREFIX "pcolor-red", 0, 0, 255,
401 PCOLOR_RED_TEXT, PCOLOR_RED_LONGTEXT, false)
402 add_integer_with_range(CFG_PREFIX "pcolor-green", 0, 0, 255,
403 PCOLOR_GREEN_TEXT, PCOLOR_GREEN_LONGTEXT, false)
404 add_integer_with_range(CFG_PREFIX "pcolor-blue", 192, 0, 255,
405 PCOLOR_BLUE_TEXT, PCOLOR_BLUE_LONGTEXT, false)
406 add_integer_with_range(CFG_PREFIX "fadesteps", 50, 1, 250,
407 FADESTEPS_TEXT, FADESTEPS_LONGTEXT, false)
410 color which is showed if you finished watching your movie ...
411 used for both buildin / external
413 set_section( N_("Illuminate the room with this color on shutdown" ), 0 )
414 add_integer_with_range(CFG_PREFIX "ecolor-red", 192, 0, 255,
415 ECOLOR_RED_TEXT, ECOLOR_RED_LONGTEXT, false)
416 add_integer_with_range(CFG_PREFIX "ecolor-green", 192, 0, 255,
417 ECOLOR_GREEN_TEXT, ECOLOR_GREEN_LONGTEXT, false)
418 add_integer_with_range(CFG_PREFIX "ecolor-blue", 192, 0, 255,
419 ECOLOR_BLUE_TEXT, ECOLOR_BLUE_LONGTEXT, false)
420 add_integer_with_range(CFG_PREFIX "efadesteps", 50, 1, 250,
421 EFADESTEPS_TEXT, EFADESTEPS_LONGTEXT, false)
424 set_section( N_("DMX options" ), 0 )
425 add_integer_with_range(CFG_PREFIX "dmx-channels", 5, 1, 64,
426 DMX_CHANNELS_TEXT, DMX_CHANNELS_LONGTEXT, false)
427 add_string(CFG_PREFIX "dmx-chbase", "0,3,6,9,12",
428 DMX_CHBASE_TEXT, DMX_CHBASE_LONGTEXT, false )
430 set_section( N_("MoMoLight options" ), 0 )
431 add_integer_with_range(CFG_PREFIX "momo-channels", 3, 3, 4,
432 MOMO_CHANNELS_TEXT, MOMO_CHANNELS_LONGTEXT, false)
434 /* 2,2,4 means 2 is the default value, 1 minimum amount,
437 set_section( N_("fnordlicht options" ), 0 )
438 add_integer_with_range(CFG_PREFIX "fnordlicht-amount", 2, 1, 254,
439 FNORDLICHT_AMOUNT_TEXT,
440 FNORDLICHT_AMOUNT_LONGTEXT, false)
444 instead of redefining the original AtmoLight zones with gradient
445 bitmaps, we can now define the layout of the zones useing these
446 parameters - the function with the gradient bitmaps would still
447 work (but for most cases its no longer required)
449 short description whats this means - f.e. the classic atmo would
451 zones-top = 1 - zone 0
452 zones-lr = 1 - zone 1 und zone 3
453 zones-bottom = 1 - zone 2
454 zone-summary = true - zone 4
462 the zone numbers will be counted clockwise starting at top / left
463 if you want to split the light at the top, without having a bottom zone
464 (which is my private config)
466 zones-top = 2 - zone 0, zone 1
467 zones-lr = 1 - zone 2 und zone 3
479 set_section( N_("Zone Layout for the build-in Atmo" ), 0 )
480 add_integer_with_range(CFG_PREFIX "zones-top", 1, 0, 16,
481 ZONE_TOP_TEXT, ZONE_TOP_LONGTEXT, false)
482 add_integer_with_range(CFG_PREFIX "zones-bottom", 1, 0, 16,
483 ZONE_BOTTOM_TEXT, ZONE_BOTTOM_LONGTEXT, false)
484 add_integer_with_range(CFG_PREFIX "zones-lr", 1, 0, 16,
485 ZONE_LR_TEXT, ZONE_LR_LONGTEXT, false)
486 add_bool(CFG_PREFIX "zone-summary", false,
487 ZONE_SUMMARY_TEXT, ZONE_SUMMARY_LONGTEXT, false)
490 settings only for the buildin driver (if external driver app is used
491 these parameters are ignored.)
493 definition of parameters for the buildin filter ...
495 set_section( N_("Settings for the built-in Live Video Processor only" ), 0 )
497 add_integer_with_range(CFG_PREFIX "edgeweightning", 3, 1, 30,
498 EDGE_TEXT, EDGE_LONGTEXT, false)
500 add_integer_with_range(CFG_PREFIX "brightness", 100, 50, 300,
501 BRIGHTNESS_TEXT, BRIGHTNESS_LONGTEXT, false)
503 add_integer_with_range(CFG_PREFIX "darknesslimit", 3, 0, 10,
504 DARKNESS_TEXT, DARKNESS_LONGTEXT, false)
506 add_integer_with_range(CFG_PREFIX "huewinsize", 3, 0, 5,
507 HUEWINSIZE_TEXT, HUEWINSIZE_LONGTEXT, false)
509 add_integer_with_range(CFG_PREFIX "satwinsize", 3, 0, 5,
510 SATWINSIZE_TEXT, SATWINSIZE_LONGTEXT, false)
512 add_integer(CFG_PREFIX "filtermode", (int)afmCombined,
513 FILTERMODE_TEXT, FILTERMODE_LONGTEXT, false )
515 change_integer_list(pi_filtermode_values, ppsz_filtermode_descriptions )
517 add_integer_with_range(CFG_PREFIX "meanlength", 300, 300, 5000,
518 MEANLENGTH_TEXT, MEANLENGTH_LONGTEXT, false)
520 add_integer_with_range(CFG_PREFIX "meanthreshold", 40, 1, 100,
521 MEANTHRESHOLD_TEXT, MEANTHRESHOLD_LONGTEXT, false)
523 add_integer_with_range(CFG_PREFIX "percentnew", 50, 1, 100,
524 MEANPERCENTNEW_TEXT, MEANPERCENTNEW_LONGTEXT, false)
526 add_integer_with_range(CFG_PREFIX "framedelay", 18, 0, 200,
527 FRAMEDELAY_TEXT, FRAMEDELAY_LONGTEXT, false)
530 output channel reordering
532 set_section( N_("Change channel assignment (fixes wrong wiring)" ), 0 )
533 add_integer( CFG_PREFIX "channel_0", 4,
534 CHANNEL_0_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
535 change_integer_list( pi_zone_assignment_values,
536 ppsz_zone_assignment_descriptions )
538 add_integer( CFG_PREFIX "channel_1", 3,
539 CHANNEL_1_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
540 change_integer_list( pi_zone_assignment_values,
541 ppsz_zone_assignment_descriptions )
543 add_integer( CFG_PREFIX "channel_2", 1,
544 CHANNEL_2_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
545 change_integer_list( pi_zone_assignment_values,
546 ppsz_zone_assignment_descriptions )
548 add_integer( CFG_PREFIX "channel_3", 0,
549 CHANNEL_3_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
550 change_integer_list( pi_zone_assignment_values,
551 ppsz_zone_assignment_descriptions )
553 add_integer( CFG_PREFIX "channel_4", 2,
554 CHANNEL_4_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
555 change_integer_list( pi_zone_assignment_values,
556 ppsz_zone_assignment_descriptions )
558 add_string(CFG_PREFIX "channels", "",
559 CHANNELS_ASSIGN_TEXT, CHANNELS_ASSIGN_LONGTEXT, false )
563 LED color white calibration
565 set_section( N_("Adjust the white light to your LED stripes" ), 0 )
566 add_bool(CFG_PREFIX "whiteadj", true,
567 USEWHITEADJ_TEXT, USEWHITEADJ_LONGTEXT, false)
568 add_integer_with_range(CFG_PREFIX "white-red", 255, 0, 255,
569 WHITE_RED_TEXT, WHITE_RED_LONGTEXT, false)
571 add_integer_with_range(CFG_PREFIX "white-green", 255, 0, 255,
572 WHITE_GREEN_TEXT, WHITE_GREEN_LONGTEXT, false)
574 add_integer_with_range(CFG_PREFIX "white-blue", 255, 0, 255,
575 WHITE_BLUE_TEXT, WHITE_BLUE_LONGTEXT, false)
576 /* end of definition of parameter for the buildin filter ... part 1 */
580 only for buildin (external has own definition) per default the calucation
581 used linear gradients for assigning a priority to the pixel - depending
582 how near they are to the border ...for changing this you can create 64x48
583 Pixel BMP files - which contain your own grayscale... (you can produce funny
584 effects with this...) the images MUST not compressed, should have 24-bit per
585 pixel, or a simple 256 color grayscale palette
587 set_section( N_("Change gradients" ), 0 )
588 add_loadfile(CFG_PREFIX "gradient_zone_0", NULL,
589 ZONE_0_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
590 add_loadfile(CFG_PREFIX "gradient_zone_1", NULL,
591 ZONE_1_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
592 add_loadfile(CFG_PREFIX "gradient_zone_2", NULL,
593 ZONE_2_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
594 add_loadfile(CFG_PREFIX "gradient_zone_3", NULL,
595 ZONE_3_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
596 add_loadfile(CFG_PREFIX "gradient_zone_4", NULL,
597 ZONE_4_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
598 add_directory(CFG_PREFIX "gradient_path", NULL,
599 GRADIENT_PATH_TEXT, GRADIENT_PATH_LONGTEXT, false )
601 #if defined(__ATMO_DEBUG__)
602 add_bool(CFG_PREFIX "saveframes", false,
603 SAVEFRAMES_TEXT, SAVEFRAMES_LONGTEXT, false)
604 add_string(CFG_PREFIX "framepath", "",
605 FRAMEPATH_TEXT, FRAMEPATH_LONGTEXT, false )
608 may be later if computers gets more power ;-) than now we increase
609 the samplesize from which we do the stats for output color calculation
611 add_integer_with_range(CFG_PREFIX "width", 64, 64, 512,
612 WIDTH_TEXT, WIDTH_LONGTEXT, true)
613 add_integer_with_range(CFG_PREFIX "height", 48, 48, 384,
614 HEIGHT_TEXT, HEIGHT_LONGTEXT, true)
615 add_bool(CFG_PREFIX "showdots", false,
616 SHOW_DOTS_TEXT, SHOW_DOTS_LONGTEXT, false)
617 add_shortcut( "atmo" )
618 set_callbacks( CreateFilter, DestroyFilter )
622 static const char *const ppsz_filter_options[] = {
677 #if defined(__ATMO_DEBUG__)
694 /*****************************************************************************
695 * fadethread_t: Color Fading Thread
696 *****************************************************************************
697 * changes slowly the color of the output if videostream gets paused...
698 *****************************************************************************
704 /* tell the thread which color should be the target of fading */
708 /* how many steps should happen until this */
713 static void *FadeToColorThread(vlc_object_t *);
716 /*****************************************************************************
717 * filter_sys_t: AtmoLight filter method descriptor
718 *****************************************************************************
719 * It describes the AtmoLight specific properties of an video filter.
720 *****************************************************************************/
724 special for the access of the p_fadethread member all other members
725 need no special protection so far!
727 vlc_mutex_t filter_lock;
730 int32_t i_AtmoOldEffect;
733 int32_t i_device_type;
735 int32_t i_atmo_width;
736 int32_t i_atmo_height;
737 /* used to disable fadeout if less than 50 frames are processed
738 used to avoid long time waiting when switch quickly between
739 deinterlaceing modes, where the output filter chains is rebuild
742 int32_t i_frames_processed;
744 #if defined(__ATMO_DEBUG__)
746 uint32_t ui_frame_counter;
747 char sz_framepath[MAX_PATH];
750 /* light color durring movie pause ... */
751 bool b_usepausecolor;
752 uint8_t ui_pausecolor_red;
753 uint8_t ui_pausecolor_green;
754 uint8_t ui_pausecolor_blue;
757 /* light color on movie finish ... */
758 uint8_t ui_endcolor_red;
759 uint8_t ui_endcolor_green;
760 uint8_t ui_endcolor_blue;
763 fadethread_t *p_fadethread;
765 /* Variables for buildin driver only... */
767 /* is only present and initialized if the internal driver is used*/
768 CAtmoConfig *p_atmo_config;
769 /* storage for temporal settings "volatile" */
770 CAtmoDynData *p_atmo_dyndata;
771 /* initialized for buildin driver with AtmoCreateTransferBuffers */
772 BITMAPINFOHEADER mini_image_format;
773 /* is only use buildin driver! */
774 uint8_t *p_atmo_transfer_buffer;
775 /* end buildin driver */
778 contains the real output size of the video calculated on
779 change event of the variable "crop" from vout
781 int32_t i_crop_x_offset;
782 int32_t i_crop_y_offset;
783 int32_t i_crop_width;
784 int32_t i_crop_height;
786 void (*pf_extract_mini_image) (filter_sys_t *p_sys,
788 uint8_t *p_transfer_dest);
791 /* External Library as wrapper arround COM Stuff */
792 HINSTANCE h_AtmoCtrl;
793 int32_t (*pf_ctrl_atmo_initialize) (void);
794 void (*pf_ctrl_atmo_finalize) (int32_t what);
795 int32_t (*pf_ctrl_atmo_switch_effect) (int32_t);
796 int32_t (*pf_ctrl_atmo_set_live_source) (int32_t);
797 void (*pf_ctrl_atmo_create_transfer_buffers) (int32_t, int32_t,
799 uint8_t* (*pf_ctrl_atmo_lock_transfer_buffer) (void);
800 void (*pf_ctrl_atmo_send_pixel_data) (void);
801 void (*pf_ctrl_atmo_get_image_size)(int32_t *,int32_t *);
806 initialize previously configured Atmo Light environment
807 - if internal is enabled try to access the device on the serial port
808 - if not internal is enabled and we are on win32 try to initialize
809 the previously loaded DLL ...
811 Return Values may be: -1 (failed for some reason - filter will be disabled)
814 static int32_t AtmoInitialize(filter_t *p_filter, bool b_for_thread)
816 filter_sys_t *p_sys = p_filter->p_sys;
817 if(p_sys->p_atmo_config)
822 /* setup Output Threads ... */
823 msg_Dbg( p_filter, "open atmo device...");
824 if(CAtmoTools::RecreateConnection(p_sys->p_atmo_dyndata)
829 msg_Err( p_filter,"failed to open atmo device, "\
830 "some other software/driver may use it?");
834 } else if(p_sys->pf_ctrl_atmo_initialize)
836 /* on win32 with active ctrl dll */
837 return p_sys->pf_ctrl_atmo_initialize();
844 prepare the shutdown of the effect threads,
845 for build in filter - close the serialport after finishing the threads...
846 cleanup possible loaded DLL...
848 static void AtmoFinalize(filter_t *p_filter, int32_t what)
850 filter_sys_t *p_sys = p_filter->p_sys;
851 if(p_sys->p_atmo_config)
855 CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
858 p_atmo_dyndata->LockCriticalSection();
860 CAtmoInput *p_input = p_atmo_dyndata->getLiveInput();
861 p_atmo_dyndata->setLiveInput( NULL );
864 p_input->Terminate();
866 msg_Dbg( p_filter, "input thread died peacefully");
869 CThread *p_effect_thread = p_atmo_dyndata->getEffectThread();
870 p_atmo_dyndata->setEffectThread(NULL);
871 if(p_effect_thread != NULL)
874 forced the thread to die...
875 and wait for termination of the thread
877 p_effect_thread->Terminate();
878 delete p_effect_thread;
879 msg_Dbg( p_filter, "effect thread died peacefully");
882 CAtmoPacketQueue *p_queue =
883 p_atmo_dyndata->getLivePacketQueue();
884 p_atmo_dyndata->setLivePacketQueue( NULL );
888 msg_Dbg( p_filter, "packetqueue removed");
892 close serial port if it is open (all OS specific is inside
893 CAtmoSerialConnection implemented / defined)
895 CAtmoConnection *p_atmo_connection =
896 p_atmo_dyndata->getAtmoConnection();
897 p_atmo_dyndata->setAtmoConnection(NULL);
898 if(p_atmo_connection) {
899 p_atmo_connection->CloseConnection();
900 delete p_atmo_connection;
902 p_atmo_dyndata->UnLockCriticalSection();
906 } else if(p_sys->pf_ctrl_atmo_finalize)
908 /* on win32 with active ctrl dll */
909 p_sys->pf_ctrl_atmo_finalize(what);
915 switch the current light effect to LiveView
917 static int32_t AtmoSwitchEffect(filter_t *p_filter, int32_t newMode)
919 filter_sys_t *p_sys = p_filter->p_sys;
921 msg_Dbg( p_filter, "AtmoSwitchEffect %d", newMode );
923 if(p_sys->p_atmo_config)
925 return CAtmoTools::SwitchEffect(p_sys->p_atmo_dyndata, emLivePicture);
927 } else if(p_sys->pf_ctrl_atmo_switch_effect)
929 /* on win32 with active ctrl dll */
930 return p_sys->pf_ctrl_atmo_switch_effect( newMode );
937 set the current live picture source, does only something on win32,
938 with the external libraries - if the buildin effects are used nothing
941 static int32_t AtmoSetLiveSource(filter_t *p_filter, int32_t newSource)
943 filter_sys_t *p_sys = p_filter->p_sys;
945 msg_Dbg( p_filter, "AtmoSetLiveSource %d", newSource );
947 if(p_sys->p_atmo_config)
952 doesnt know different sources so this
953 function call would just do nothing special
957 } else if(p_sys->pf_ctrl_atmo_set_live_source)
959 /* on win32 with active ctrl dll */
960 return p_sys->pf_ctrl_atmo_set_live_source(newSource);
967 setup the pixel transferbuffers which is used to transfer pixeldata from
968 the filter to the effect thread, and possible accross the process
969 boundaries on win32, with the external DLL
971 static void AtmoCreateTransferBuffers(filter_t *p_filter,
973 int32_t bytePerPixel,
977 filter_sys_t *p_sys = p_filter->p_sys;
978 if(p_sys->p_atmo_config)
981 we need a buffer where the image is stored (only for transfer
982 to the processing thread)
984 free( p_sys->p_atmo_transfer_buffer );
986 p_sys->p_atmo_transfer_buffer = (uint8_t *)malloc(bytePerPixel *
989 memset(&p_sys->mini_image_format,0,sizeof(BITMAPINFOHEADER));
991 p_sys->mini_image_format.biSize = sizeof(BITMAPINFOHEADER);
992 p_sys->mini_image_format.biWidth = width;
993 p_sys->mini_image_format.biHeight = height;
994 p_sys->mini_image_format.biBitCount = bytePerPixel*8;
995 p_sys->mini_image_format.biCompression = FourCC;
998 } else if(p_sys->pf_ctrl_atmo_create_transfer_buffers)
1000 /* on win32 with active ctrl dll */
1001 p_sys->pf_ctrl_atmo_create_transfer_buffers(FourCC,
1010 acquire the transfer buffer pointer the buildin version only
1011 returns the pointer to the allocated buffer ... the
1012 external version on win32 has to do some COM stuff to lock the
1013 Variant Byte array which is behind the buffer
1015 static uint8_t* AtmoLockTransferBuffer(filter_t *p_filter)
1017 filter_sys_t *p_sys = p_filter->p_sys;
1018 if(p_sys->p_atmo_config)
1020 return p_sys->p_atmo_transfer_buffer;
1022 } else if(p_sys->pf_ctrl_atmo_lock_transfer_buffer)
1024 /* on win32 with active ctrl dll */
1025 return p_sys->pf_ctrl_atmo_lock_transfer_buffer();
1032 send the content of current pixel buffer got with AtmoLockTransferBuffer
1033 to the processing threads
1034 - build in version - will forward the data to AtmoExternalCaptureInput Thread
1035 - win32 external - will do the same, but across the process boundaries via
1036 COM to the AtmoWinA.exe Process
1038 static void AtmoSendPixelData(filter_t *p_filter)
1040 filter_sys_t *p_sys = p_filter->p_sys;
1041 if(p_sys->p_atmo_config && p_sys->p_atmo_transfer_buffer)
1043 CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
1044 if(p_atmo_dyndata &&
1045 (p_atmo_dyndata->getLivePictureSource() == lpsExtern))
1048 the cast will go Ok because we are inside videolan there is only
1049 this kind of effect thread implemented!
1051 CAtmoExternalCaptureInput *p_atmo_external_capture_input_thread =
1052 (CAtmoExternalCaptureInput *)p_atmo_dyndata->getLiveInput();
1054 if(p_atmo_external_capture_input_thread)
1057 the same as above inside videolan only this single kind of
1058 input exists so we can cast without further tests!
1060 this call will do a 1:1 copy of this buffer, and wakeup
1061 the thread from normal sleeping
1063 p_atmo_external_capture_input_thread->
1064 DeliverNewSourceDataPaket(&p_sys->mini_image_format,
1065 p_sys->p_atmo_transfer_buffer);
1069 } else if(p_sys->pf_ctrl_atmo_send_pixel_data)
1071 /* on win32 with active ctrl dll */
1072 p_sys->pf_ctrl_atmo_send_pixel_data();
1076 msg_Warn( p_filter, "AtmoSendPixelData no method");
1081 Shutdown AtmoLight finally - is call from DestroyFilter
1082 does the cleanup restores the effectmode on the external Software
1083 (only win32) and possible setup the final light ...
1085 static void Atmo_Shutdown(filter_t *p_filter)
1087 filter_sys_t *p_sys = p_filter->p_sys;
1089 if(p_sys->b_enabled)
1091 msg_Dbg( p_filter, "shut down atmo!");
1093 if there is a still running show pause color thread kill him!
1095 CheckAndStopFadeThread(p_filter);
1097 // perpare spawn fadeing thread
1098 vlc_mutex_lock( &p_sys->filter_lock );
1101 fade to end color (in case of external AtmoWin Software
1102 assume that the static color will equal to this
1103 one to get a soft change and no flash!
1105 p_sys->b_pause_live = true;
1108 p_sys->p_fadethread = (fadethread_t *)vlc_object_create( p_filter,
1109 sizeof(fadethread_t) );
1111 p_sys->p_fadethread->p_filter = p_filter;
1112 p_sys->p_fadethread->ui_red = p_sys->ui_endcolor_red;
1113 p_sys->p_fadethread->ui_green = p_sys->ui_endcolor_green;
1114 p_sys->p_fadethread->ui_blue = p_sys->ui_endcolor_blue;
1115 if(p_sys->i_frames_processed < 50)
1116 p_sys->p_fadethread->i_steps = 1;
1118 p_sys->p_fadethread->i_steps = p_sys->i_endfadesteps;
1120 if( vlc_thread_create( p_sys->p_fadethread,
1122 VLC_THREAD_PRIORITY_LOW ) )
1124 msg_Err( p_filter, "cannot create FadeToColorThread" );
1125 vlc_object_release( p_sys->p_fadethread );
1126 p_sys->p_fadethread = NULL;
1127 vlc_mutex_unlock( &p_sys->filter_lock );
1131 vlc_mutex_unlock( &p_sys->filter_lock );
1133 /* wait for the thread... */
1134 vlc_thread_join(p_sys->p_fadethread);
1136 vlc_object_release(p_sys->p_fadethread);
1138 p_sys->p_fadethread = NULL;
1142 the following happens only useing the
1143 external AtmoWin Device Software
1145 if( !p_sys->p_atmo_config )
1147 if(p_sys->i_AtmoOldEffect != emLivePicture)
1148 AtmoSwitchEffect( p_filter, p_sys->i_AtmoOldEffect);
1150 AtmoSetLiveSource( p_filter, lvsGDI );
1153 /* close device connection etc. */
1154 AtmoFinalize(p_filter, 1);
1156 /* disable filter method .. */
1157 p_sys->b_enabled = false;
1162 depending on mode setup imagesize to 64x48(classic), or defined
1163 resolution of external atmowin.exe on windows
1165 static void Atmo_SetupImageSize(filter_t *p_filter)
1167 filter_sys_t *p_sys = p_filter->p_sys;
1169 size of extracted image by default 64x48 (other imagesizes are
1170 currently ignored by AtmoWin)
1172 p_sys->i_atmo_width = var_CreateGetIntegerCommand( p_filter,
1173 CFG_PREFIX "width");
1174 p_sys->i_atmo_height = var_CreateGetIntegerCommand( p_filter,
1175 CFG_PREFIX "height");
1177 if(p_sys->p_atmo_config)
1180 } else if(p_sys->pf_ctrl_atmo_get_image_size)
1182 /* on win32 with active ctrl dll */
1183 p_sys->pf_ctrl_atmo_get_image_size( &p_sys->i_atmo_width,
1184 &p_sys->i_atmo_height );
1188 msg_Dbg(p_filter,"sample image size %d * %d pixels", p_sys->i_atmo_width,
1189 p_sys->i_atmo_height);
1193 initialize the zone and channel mapping for the buildin atmolight adapter
1195 static void Atmo_SetupBuildZones(filter_t *p_filter)
1197 filter_sys_t *p_sys = p_filter->p_sys;
1199 p_sys->p_atmo_dyndata->LockCriticalSection();
1201 CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
1204 CAtmoChannelAssignment *p_channel_assignment =
1205 p_atmo_config->getChannelAssignment(0);
1207 // channel 0 - zone 4
1208 p_channel_assignment->setZoneIndex( 0, var_CreateGetIntegerCommand(
1209 p_filter, CFG_PREFIX "channel_0")
1212 // channel 1 - zone 3
1213 p_channel_assignment->setZoneIndex( 1, var_CreateGetIntegerCommand(
1214 p_filter, CFG_PREFIX "channel_1")
1217 // channel 2 - zone 1
1218 p_channel_assignment->setZoneIndex( 2, var_CreateGetIntegerCommand(
1219 p_filter, CFG_PREFIX "channel_2")
1222 // channel 3 - zone 0
1223 p_channel_assignment->setZoneIndex( 3, var_CreateGetIntegerCommand(
1224 p_filter, CFG_PREFIX "channel_3")
1227 // channel 4 - zone 2
1228 p_channel_assignment->setZoneIndex( 4, var_CreateGetIntegerCommand(
1229 p_filter, CFG_PREFIX "channel_4")
1232 char *psz_channels = var_CreateGetStringCommand(
1234 CFG_PREFIX "channels"
1236 if( !EMPTY_STR(psz_channels) )
1238 msg_Dbg( p_filter, "deal with new zone mapping %s", psz_channels );
1240 char *psz_temp = psz_channels;
1241 char *psz_start = psz_temp;
1244 if(*psz_temp == ',' || *psz_temp == ';')
1249 int zone = atoi( psz_start );
1251 zone >= p_channel_assignment->getSize()) {
1252 msg_Warn( p_filter, "Zone %d out of range -1..%d",
1253 zone, p_channel_assignment->getSize()-1 );
1255 p_channel_assignment->setZoneIndex( channel, zone );
1259 psz_start = psz_temp;
1267 process the rest of the string
1269 if( *psz_start && !*psz_temp )
1271 int zone = atoi( psz_start );
1273 zone >= p_channel_assignment->getSize()) {
1274 msg_Warn( p_filter, "Zone %d out of range -1..%d",
1275 zone, p_channel_assignment->getSize()-1 );
1277 p_channel_assignment->setZoneIndex( channel, zone );
1281 free( psz_channels );
1283 for(int i=0;i< p_channel_assignment->getSize() ;i++)
1284 msg_Info( p_filter, "map zone %d to hardware channel %d",
1285 p_channel_assignment->getZoneIndex( i ),
1288 p_sys->p_atmo_dyndata->getAtmoConnection()
1289 ->SetChannelAssignment( p_channel_assignment );
1296 calculate the default gradients for each zone!
1297 depending on the zone layout set before, this now
1298 supports also multiple gradients on each side
1299 (older versions could do this only with external
1302 p_sys->p_atmo_dyndata->CalculateDefaultZones();
1306 first try to load the old style defined gradient bitmaps
1307 this could only be done for the first five zones
1308 - should be deprecated -
1310 CAtmoZoneDefinition *p_zone;
1311 char psz_gradient_var_name[30];
1312 char *psz_gradient_file;
1313 for(int i=0;i<CLASSIC_ATMO_NUM_ZONES;i++)
1315 sprintf(psz_gradient_var_name, CFG_PREFIX "gradient_zone_%d", i);
1316 psz_gradient_file = var_CreateGetStringCommand(
1318 psz_gradient_var_name
1320 if( !EMPTY_STR(psz_gradient_file) )
1322 msg_Dbg( p_filter, "loading gradientfile %s for "\
1323 "zone %d", psz_gradient_file, i);
1325 p_zone = p_atmo_config->getZoneDefinition(i);
1328 int i_res = p_zone->LoadGradientFromBitmap(psz_gradient_file);
1330 if(i_res != ATMO_LOAD_GRADIENT_OK)
1332 msg_Err( p_filter,"failed to load gradient '%s' with "\
1333 "error %d",psz_gradient_file,i_res);
1337 free( psz_gradient_file );
1342 the new approach try to load a gradient bitmap for each zone
1343 from a previously defined folder containing
1348 char *psz_gradient_path = var_CreateGetStringCommand(
1350 CFG_PREFIX "gradient_path"
1352 if( EMPTY_STR(psz_gradient_path) )
1354 char *psz_file_name = (char *)malloc( strlen(psz_gradient_path) + 16 );
1355 assert( psz_file_name );
1357 for(int i=0; i < p_atmo_config->getZoneCount(); i++ )
1359 p_zone = p_atmo_config->getZoneDefinition(i);
1363 sprintf(psz_file_name, "%s%szone_%d.bmp",
1364 psz_gradient_path, DIR_SEP, i );
1366 int i_res = p_zone->LoadGradientFromBitmap( psz_file_name );
1368 if( i_res == ATMO_LOAD_GRADIENT_OK )
1370 msg_Dbg( p_filter, "loaded gradientfile %s for "\
1371 "zone %d", psz_file_name, i);
1374 if( (i_res != ATMO_LOAD_GRADIENT_OK) &&
1375 (i_res != ATMO_LOAD_GRADIENT_FILENOTFOND) )
1377 msg_Err( p_filter,"failed to load gradient '%s' with "\
1378 "error %d",psz_file_name,i_res);
1383 free( psz_file_name );
1385 free( psz_gradient_path );
1388 p_sys->p_atmo_dyndata->UnLockCriticalSection();
1392 static void Atmo_SetupConfig(filter_t *p_filter, CAtmoConfig *p_atmo_config)
1395 figuring out the device ports (com-ports, ttys)
1397 char *psz_serialdev = var_CreateGetStringCommand( p_filter,
1398 CFG_PREFIX "serialdev" );
1399 char *psz_temp = psz_serialdev;
1401 if( !EMPTY_STR(psz_serialdev) )
1408 msg_Dbg( p_filter, "use port(s) %s",psz_serialdev);
1411 psz_serialdev - may contain up to 4 COM ports for the quattro device
1412 the quattro device is just hack of useing 4 classic devices as one
1413 logical device - thanks that usb-com-ports exists :)
1414 as Seperator I defined , or ; with the hope that these
1415 characters are never part of a device name
1417 while( (psz_token = strsep(&psz_temp, ",;")) != NULL && i_port < 4 )
1420 psz_token may contain spaces we have to trim away
1425 find first none space in string
1427 while( psz_token[i] == 32 ) i++;
1429 contains string only spaces or is empty? skip it
1437 while( psz_token[i] && psz_token[i] != 32 )
1438 psz_token[ j++ ] = psz_token[ i++ ];
1441 msg_Dbg( p_filter, "Serial Device [%d]: %s", i_port, psz_token );
1443 p_atmo_config->setSerialDevice( i_port, psz_token );
1450 msg_Err(p_filter,"no serial devicename(s) set");
1452 free( psz_serialdev );
1455 configuration of light source layout arround the display
1457 p_atmo_config->setZonesTopCount(
1458 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-top")
1460 p_atmo_config->setZonesBottomCount(
1461 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-bottom")
1463 p_atmo_config->setZonesLRCount(
1464 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-lr")
1466 p_atmo_config->setZoneSummary(
1467 var_CreateGetBoolCommand( p_filter, CFG_PREFIX "zone-summary")
1471 p_atmo_config->setLiveViewFilterMode(
1472 (AtmoFilterMode)var_CreateGetIntegerCommand( p_filter,
1473 CFG_PREFIX "filtermode")
1476 p_atmo_config->setLiveViewFilter_PercentNew(
1477 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "percentnew")
1479 p_atmo_config->setLiveViewFilter_MeanLength(
1480 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "meanlength")
1482 p_atmo_config->setLiveViewFilter_MeanThreshold(
1483 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "meanthreshold")
1486 p_atmo_config->setLiveView_EdgeWeighting(
1487 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "edgeweightning")
1489 p_atmo_config->setLiveView_BrightCorrect(
1490 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "brightness")
1492 p_atmo_config->setLiveView_DarknessLimit(
1493 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "darknesslimit")
1495 p_atmo_config->setLiveView_HueWinSize(
1496 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "huewinsize")
1498 p_atmo_config->setLiveView_SatWinSize(
1499 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "satwinsize")
1502 /* currently not required inside vlc */
1503 p_atmo_config->setLiveView_WidescreenMode( 0 );
1505 p_atmo_config->setLiveView_FrameDelay(
1506 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "framedelay")
1510 p_atmo_config->setUseSoftwareWhiteAdj(
1511 var_CreateGetBoolCommand( p_filter, CFG_PREFIX "whiteadj")
1513 p_atmo_config->setWhiteAdjustment_Red(
1514 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-red")
1516 p_atmo_config->setWhiteAdjustment_Green(
1517 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-green")
1519 p_atmo_config->setWhiteAdjustment_Blue(
1520 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-blue")
1524 settings for DMX device only
1526 p_atmo_config->setDMX_RGB_Channels(
1527 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "dmx-channels")
1530 char *psz_chbase = var_CreateGetStringCommand( p_filter,
1531 CFG_PREFIX "dmx-chbase" );
1532 if( !EMPTY_STR(psz_chbase) )
1533 p_atmo_config->setDMX_BaseChannels( psz_chbase );
1540 p_atmo_config->setMoMo_Channels(
1541 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "momo-channels")
1547 p_atmo_config->setFnordlicht_Amount(
1548 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "fnordlicht-amount")
1555 initialize the filter_sys_t structure with the data from the settings
1556 variables - if the external filter on win32 is enabled try loading the DLL,
1557 if this fails fallback to the buildin software
1559 static void Atmo_SetupParameters(filter_t *p_filter)
1562 filter_sys_t *p_sys = p_filter->p_sys;
1565 /* default filter disabled until DLL loaded and Init Success!*/
1566 p_sys->b_enabled = false;
1568 /* setup default mini image size (may be later a user option) */
1569 p_sys->i_atmo_width = 64;
1570 p_sys->i_atmo_height = 48;
1572 p_sys->i_device_type = var_CreateGetIntegerCommand( p_filter,
1573 CFG_PREFIX "device");
1577 0 => use AtmoWin Software (only win32)
1578 1 => use AtmoClassicConnection (direct)
1579 2 => use AtmoMultiConnection (direct up to four serial ports required)
1580 3 => use AtmoDmxConnection (simple serial DMX Device up to 255 channels)
1586 only on WIN32 the user has the choice between
1587 internal driver and external
1590 if(p_sys->i_device_type == 0) {
1592 /* Load the Com Wrapper Library (source available) */
1593 p_sys->h_AtmoCtrl = LoadLibraryA("AtmoCtrlLib.dll");
1594 if(p_sys->h_AtmoCtrl == NULL)
1597 be clever if the location of atmowina.exe is set
1598 try to load the dll from the same folder :-)
1600 char *psz_path = var_CreateGetStringCommand( p_filter,
1601 CFG_PREFIX "atmowinexe" );
1602 if( !EMPTY_STR(psz_path) )
1604 char *psz_bs = strrchr( psz_path , '\\');
1609 now format a new dll filename with complete path
1611 char *psz_dllname = NULL;
1612 asprintf( &psz_dllname, "%s\\AtmoCtrlLib.dll", psz_path );
1615 msg_Dbg( p_filter, "Try Loading '%s'", psz_dllname );
1616 p_sys->h_AtmoCtrl = LoadLibraryA( psz_dllname );
1618 free( psz_dllname );
1625 if(p_sys->h_AtmoCtrl != NULL)
1627 msg_Dbg( p_filter, "Load Library ok!");
1629 /* importing all required functions I hope*/
1630 p_sys->pf_ctrl_atmo_initialize =
1631 (int32_t (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,
1633 if(!p_sys->pf_ctrl_atmo_initialize)
1634 msg_Err( p_filter, "export AtmoInitialize missing.");
1636 p_sys->pf_ctrl_atmo_finalize =
1637 (void (*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,
1639 if(!p_sys->pf_ctrl_atmo_finalize)
1640 msg_Err( p_filter, "export AtmoFinalize missing.");
1642 p_sys->pf_ctrl_atmo_switch_effect =
1643 (int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,
1644 "AtmoSwitchEffect");
1645 if(!p_sys->pf_ctrl_atmo_switch_effect)
1646 msg_Err( p_filter, "export AtmoSwitchEffect missing.");
1648 p_sys->pf_ctrl_atmo_set_live_source =
1649 (int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,
1650 "AtmoSetLiveSource");
1651 if(!p_sys->pf_ctrl_atmo_set_live_source)
1652 msg_Err( p_filter, "export AtmoSetLiveSource missing.");
1654 p_sys->pf_ctrl_atmo_create_transfer_buffers =
1655 (void (*)(int32_t, int32_t, int32_t , int32_t))
1656 GetProcAddress(p_sys->h_AtmoCtrl,"AtmoCreateTransferBuffers");
1657 if(!p_sys->pf_ctrl_atmo_create_transfer_buffers)
1658 msg_Err( p_filter, "export AtmoCreateTransferBuffers missing.");
1660 p_sys->pf_ctrl_atmo_lock_transfer_buffer=
1661 (uint8_t*(*) (void))GetProcAddress(p_sys->h_AtmoCtrl,
1662 "AtmoLockTransferBuffer");
1663 if(!p_sys->pf_ctrl_atmo_lock_transfer_buffer)
1664 msg_Err( p_filter, "export AtmoLockTransferBuffer missing.");
1666 p_sys->pf_ctrl_atmo_send_pixel_data =
1667 (void (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,
1668 "AtmoSendPixelData");
1669 if(!p_sys->pf_ctrl_atmo_send_pixel_data)
1670 msg_Err( p_filter, "export AtmoSendPixelData missing.");
1672 p_sys->pf_ctrl_atmo_get_image_size =
1673 (void (*)(int32_t*,int32_t*))GetProcAddress(p_sys->h_AtmoCtrl,
1674 "AtmoWinGetImageSize");
1675 if(!p_sys->pf_ctrl_atmo_get_image_size)
1676 msg_Err( p_filter, "export AtmoWinGetImageSize missing.");
1679 /* the DLL is missing try internal filter ...*/
1681 "AtmoCtrlLib.dll missing fallback to internal atmo classic driver");
1682 p_sys->i_device_type = 1;
1687 if(p_sys->i_device_type >= 1) {
1688 msg_Dbg( p_filter, "try use buildin driver %d ", p_sys->i_device_type);
1690 now we have to read a lof of options from the config dialog
1691 most important the serial device if not set ... we can skip
1692 the rest and disable the filter...
1695 p_sys->p_atmo_config = new CAtmoConfig();
1697 p_sys->p_atmo_dyndata = new CAtmoDynData(
1698 (vlc_object_t *)p_filter,
1699 p_sys->p_atmo_config
1702 Atmo_SetupConfig( p_filter, p_sys->p_atmo_config );
1703 switch(p_sys->i_device_type)
1706 p_sys->p_atmo_config->setConnectionType( actClassicAtmo );
1710 p_sys->p_atmo_config->setConnectionType( actMultiAtmo );
1714 p_sys->p_atmo_config->setConnectionType( actDMX );
1718 p_sys->p_atmo_config->setConnectionType( actMoMoLight );
1722 p_sys->p_atmo_config->setConnectionType( actFnordlicht );
1726 msg_Warn( p_filter, "invalid device type %d found",
1727 p_sys->i_device_type );
1730 msg_Dbg( p_filter, "buildin driver config set");
1734 switch( p_filter->fmt_in.video.i_chroma )
1736 case VLC_CODEC_I420:
1737 case VLC_CODEC_YV12:
1738 p_sys->pf_extract_mini_image = ExtractMiniImage_YUV;
1741 msg_Warn( p_filter, "InitFilter-unsupported chroma: %4.4s",
1742 (char *)&p_filter->fmt_in.video.i_chroma);
1743 p_sys->pf_extract_mini_image = NULL;
1747 for debugging purpose show the samplinggrid on each frame as
1750 p_sys->b_show_dots = var_CreateGetBoolCommand( p_filter,
1751 CFG_PREFIX "showdots"
1754 #if defined(__ATMO_DEBUG__)
1755 /* save debug images to a folder as Bitmap files ? */
1756 p_sys->b_saveframes = var_CreateGetBoolCommand( p_filter,
1757 CFG_PREFIX "saveframes"
1759 msg_Dbg(p_filter,"saveframes = %d", (int)p_sys->b_saveframes);
1762 read debug image folder from config
1764 psz_path = var_CreateGetStringCommand( p_filter, CFG_PREFIX "framepath" );
1765 if(psz_path != NULL)
1767 strcpy(p_sys->sz_framepath, psz_path);
1768 #if defined( WIN32 ) || defined( __OS2__ )
1769 size_t i_strlen = strlen(p_sys->sz_framepath);
1770 if((i_strlen>0) && (p_sys->sz_framepath[i_strlen-1] != '\\'))
1772 p_sys->sz_framepath[i_strlen] = '\\';
1773 p_sys->sz_framepath[i_strlen+1] = 0;
1778 msg_Dbg(p_filter,"saveframesfolder %s",p_sys->sz_framepath);
1783 because atmowin could also be used for lighten up the room - I think if you
1784 pause the video it would be useful to get a little bit more light into to
1785 your living room? - instead switching on a lamp?
1787 p_sys->b_usepausecolor = var_CreateGetBoolCommand( p_filter,
1788 CFG_PREFIX "usepausecolor" );
1789 p_sys->ui_pausecolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1790 CFG_PREFIX "pcolor-red");
1791 p_sys->ui_pausecolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1792 CFG_PREFIX "pcolor-green");
1793 p_sys->ui_pausecolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1794 CFG_PREFIX "pcolor-blue");
1795 p_sys->i_fadesteps = var_CreateGetIntegerCommand( p_filter,
1796 CFG_PREFIX "fadesteps");
1797 if(p_sys->i_fadesteps < 1)
1798 p_sys->i_fadesteps = 1;
1799 msg_Dbg(p_filter,"use pause color %d, RGB: %d, %d, %d, Fadesteps: %d",
1800 (int)p_sys->b_usepausecolor,
1801 p_sys->ui_pausecolor_red,
1802 p_sys->ui_pausecolor_green,
1803 p_sys->ui_pausecolor_blue,
1804 p_sys->i_fadesteps);
1807 this color is use on shutdown of the filter - the define the
1808 final light after playback... may be used to dim up the light -
1809 how it happens in the cinema...
1811 p_sys->ui_endcolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1812 CFG_PREFIX "ecolor-red");
1813 p_sys->ui_endcolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1814 CFG_PREFIX "ecolor-green");
1815 p_sys->ui_endcolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1816 CFG_PREFIX "ecolor-blue");
1817 p_sys->i_endfadesteps = var_CreateGetIntegerCommand( p_filter,
1818 CFG_PREFIX "efadesteps");
1819 if(p_sys->i_endfadesteps < 1)
1820 p_sys->i_endfadesteps = 1;
1821 msg_Dbg(p_filter,"use ende color RGB: %d, %d, %d, Fadesteps: %d",
1822 p_sys->ui_endcolor_red,
1823 p_sys->ui_endcolor_green,
1824 p_sys->ui_endcolor_blue,
1825 p_sys->i_endfadesteps);
1830 if the external DLL was loaded successfully call AtmoInitialize -
1831 (must be done for each thread where you want to use AtmoLight!)
1833 int i = AtmoInitialize(p_filter, false);
1835 #if defined( WIN32 )
1836 if((i != 1) && (p_sys->i_device_type == 0))
1839 COM Server for AtmoLight not running ?
1840 if the exe path is configured try to start the "userspace" driver
1842 psz_path = var_CreateGetStringCommand( p_filter,
1843 CFG_PREFIX "atmowinexe" );
1844 if(psz_path != NULL)
1846 STARTUPINFO startupinfo;
1847 PROCESS_INFORMATION pinfo;
1848 memset(&startupinfo, 0, sizeof(STARTUPINFO));
1849 startupinfo.cb = sizeof(STARTUPINFO);
1850 if(CreateProcess(psz_path, NULL, NULL, NULL,
1851 FALSE, 0, NULL, NULL, &startupinfo, &pinfo) == TRUE)
1853 msg_Dbg(p_filter,"launched AtmoWin from %s",psz_path);
1854 WaitForInputIdle(pinfo.hProcess, 5000);
1856 retry to initialize the library COM ... functionality
1857 after the server was launched
1859 i = AtmoInitialize(p_filter, false);
1861 msg_Err(p_filter,"failed to launch AtmoWin from %s", psz_path);
1868 if(i == 1) /* Init Atmolight success... */
1870 msg_Dbg( p_filter, "AtmoInitialize Ok!");
1873 p_sys->i_atmo_width and p_sys->i_atmo_height
1874 if the external AtmoWinA.exe is used, it may require
1875 a other sample image size than 64 x 48
1876 (this overrides the settings of the filter)
1878 Atmo_SetupImageSize( p_filter );
1881 if( p_sys->i_device_type >= 1 )
1884 AtmoConnection class initialized now we can initialize
1885 the default zone and channel mappings
1887 Atmo_SetupBuildZones( p_filter );
1890 /* Setup Transferbuffers for 64 x 48 , RGB with 32bit Per Pixel */
1891 AtmoCreateTransferBuffers(p_filter, BI_RGB, 4,
1892 p_sys->i_atmo_width,
1893 p_sys->i_atmo_height
1896 /* say the userspace driver that a live mode should be activated
1897 the functions returns the old mode for later restore!
1898 - the buildin driver launches the live view thread in that case
1900 p_sys->i_AtmoOldEffect = AtmoSwitchEffect(p_filter, emLivePicture);
1903 live view can have two differnt source the AtmoWinA
1904 internal GDI Screencapture and the external one - which we
1907 AtmoSetLiveSource(p_filter, lvsExternal);
1909 /* enable other parts only if everything is fine */
1910 p_sys->b_enabled = true;
1912 msg_Dbg( p_filter, "Atmo Filter Enabled Ok!");
1918 /*****************************************************************************
1919 * CreateFilter: allocates AtmoLight video thread output method
1920 *****************************************************************************
1921 * This function allocates and initializes a AtmoLight vout method.
1922 *****************************************************************************/
1923 static int CreateFilter( vlc_object_t *p_this )
1925 filter_t *p_filter = (filter_t *)p_this;
1926 filter_sys_t *p_sys;
1928 /* Allocate structure */
1929 p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) );
1930 p_filter->p_sys = p_sys;
1931 if( p_filter->p_sys == NULL )
1933 /* set all entries to zero */
1934 memset(p_sys, 0, sizeof( filter_sys_t ));
1935 vlc_mutex_init( &p_sys->filter_lock );
1937 msg_Dbg( p_filter, "Create Atmo Filter");
1939 /* further Setup Function pointers for videolan for calling my filter */
1940 p_filter->pf_video_filter = Filter;
1942 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
1945 AddStateVariableCallback(p_filter);
1947 AddAtmoSettingsVariablesCallbacks(p_filter);
1949 Atmo_SetupParameters(p_filter);
1957 /*****************************************************************************
1958 * DestroyFilter: destroy AtmoLight video thread output method
1959 *****************************************************************************
1960 * Terminate an output method created by CreateFilter
1961 *****************************************************************************/
1963 static void DestroyFilter( vlc_object_t *p_this )
1965 filter_t *p_filter = (filter_t *)p_this;
1966 filter_sys_t *p_sys = p_filter->p_sys;
1968 msg_Dbg( p_filter, "Destroy Atmo Filter");
1970 DelStateVariableCallback(p_filter);
1972 DelAtmoSettingsVariablesCallbacks(p_filter);
1974 Atmo_Shutdown(p_filter);
1976 #if defined( WIN32 )
1977 if(p_sys->h_AtmoCtrl != NULL)
1979 FreeLibrary(p_sys->h_AtmoCtrl);
1983 delete p_sys->p_atmo_dyndata;
1984 delete p_sys->p_atmo_config;
1986 vlc_mutex_destroy( &p_sys->filter_lock );
1993 function stolen from some other videolan source filter ;-)
1994 for the moment RGB is OK... but better would be a direct transformation
1997 static inline void yuv_to_rgb( uint8_t *r, uint8_t *g, uint8_t *b,
1998 uint8_t y1, uint8_t u1, uint8_t v1 )
2000 /* macros used for YUV pixel conversions */
2001 # define SCALEBITS 10
2002 # define ONE_HALF (1 << (SCALEBITS - 1))
2003 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
2004 # define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
2006 int y, cb, cr, r_add, g_add, b_add;
2010 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
2011 g_add = - FIX(0.34414*255.0/224.0) * cb
2012 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
2013 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
2014 y = (y1 - 16) * FIX(255.0/219.0);
2015 *r = CLAMP((y + r_add) >> SCALEBITS);
2016 *g = CLAMP((y + g_add) >> SCALEBITS);
2017 *b = CLAMP((y + b_add) >> SCALEBITS);
2019 /******************************************************************************
2020 * ExtractMiniImage_YUV: extract a small image from the picture as 24-bit RGB
2021 *******************************************************************************
2022 * p_sys is a pointer to
2023 * p_inpic is the source frame
2024 * p_transfer_dest is the target buffer for the picture must be big enough!
2025 * (in win32 environment this buffer comes from the external DLL where it is
2026 * create as "variant array" and returned through the AtmoLockTransferbuffer
2028 static void ExtractMiniImage_YUV(filter_sys_t *p_sys,
2030 uint8_t *p_transfer_dest)
2037 uint8_t *p_rgb_dst_line_red;
2038 uint8_t *p_rgb_dst_line_green;
2039 uint8_t *p_rgb_dst_line_blue;
2044 /* calcute Pointers for Storage of B G R (A) */
2045 p_rgb_dst_line_blue = p_transfer_dest;
2046 p_rgb_dst_line_green = p_transfer_dest + 1;
2047 p_rgb_dst_line_red = p_transfer_dest + 2 ;
2049 int i_row_count = p_sys->i_atmo_height + 1;
2050 int i_col_count = p_sys->i_atmo_width + 1;
2051 int i_y_row,i_u_row,i_v_row,i_pixel_row;
2055 /* these two ugly loops extract the small image - goes it faster? how?
2056 the loops are so designed that there is a small border around the extracted
2057 image so we wont get column and row - zero from the frame, and not the most
2058 right and bottom pixels --- which may be clipped on computers useing TV out
2061 TODO: try to find out if the output is clipped through VLC - and try here
2062 to ingore the clipped away area for a better result!
2064 TODO: performance improvement in InitFilter percalculated the offsets of
2065 the lines inside the planes so I can save (i_row_count * 3) 2xMUL and
2066 one time DIV the same could be done for the inner loop I think...
2068 for(i_row = 1; i_row < i_row_count; i_row++)
2070 // calcute the current Lines in the source planes for this outputrow
2071 /* Adresscalcuation pointer to plane Length of one pixelrow in bytes
2072 calculate row now number
2075 p_inpic->format? transform Pixel row into row of plane...
2076 how? simple? fast? good?
2079 /* compute the source pixel row and respect the active cropping */
2080 i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
2081 + p_sys->i_crop_y_offset;
2084 trans for these Pixel row into the row of each plane ..
2085 because planesize can differ from image size
2087 i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
2088 p_inpic->format.i_visible_height;
2090 i_u_row = (i_pixel_row * p_inpic->p[U_PLANE].i_visible_lines) /
2091 p_inpic->format.i_visible_height;
2093 i_v_row = (i_pixel_row * p_inpic->p[V_PLANE].i_visible_lines) /
2094 p_inpic->format.i_visible_height;
2096 /* calculate the pointers to the pixeldata for this row
2099 p_src_y = p_inpic->p[Y_PLANE].p_pixels +
2100 p_inpic->p[Y_PLANE].i_pitch * i_y_row;
2101 p_src_u = p_inpic->p[U_PLANE].p_pixels +
2102 p_inpic->p[U_PLANE].i_pitch * i_u_row;
2103 p_src_v = p_inpic->p[V_PLANE].p_pixels +
2104 p_inpic->p[V_PLANE].i_pitch * i_v_row;
2106 for(i_col = 1; i_col < i_col_count; i_col++)
2108 i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
2109 p_sys->i_crop_x_offset;
2111 trans for these Pixel row into the row of each plane ..
2112 because planesize can differ from image size
2114 i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
2115 p_inpic->format.i_visible_width;
2116 i_xpos_u = (i_pixel_col * p_inpic->p[U_PLANE].i_visible_pitch) /
2117 p_inpic->format.i_visible_width;
2118 i_xpos_v = (i_pixel_col * p_inpic->p[V_PLANE].i_visible_pitch) /
2119 p_inpic->format.i_visible_width;
2121 yuv_to_rgb(p_rgb_dst_line_red,
2122 p_rgb_dst_line_green,
2123 p_rgb_dst_line_blue,
2129 /* +4 because output image should be RGB32 with dword alignment! */
2130 p_rgb_dst_line_red += 4;
2131 p_rgb_dst_line_green += 4;
2132 p_rgb_dst_line_blue += 4;
2136 if(p_sys->b_show_dots)
2138 for(i_row = 1; i_row < i_row_count; i_row++)
2140 i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
2141 + p_sys->i_crop_y_offset;
2143 i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
2144 p_inpic->format.i_visible_height;
2146 p_src_y = p_inpic->p[Y_PLANE].p_pixels +
2147 p_inpic->p[Y_PLANE].i_pitch * i_y_row;
2149 for(i_col = 1; i_col < i_col_count; i_col++)
2151 i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
2152 p_sys->i_crop_x_offset;
2153 i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
2154 p_inpic->format.i_visible_width;
2156 p_src_y[i_xpos_y] = 255;
2164 /******************************************************************************
2165 * SaveBitmap: Saves the content of a transferbuffer as Bitmap to disk
2166 *******************************************************************************
2167 * just for debugging
2168 * p_sys -> configuration if Atmo from there the function will get height and
2170 * p_pixels -> should be the dword aligned BGR(A) image data
2171 * psz_filename -> filename where to store
2173 #if defined(__ATMO_DEBUG__)
2174 void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename)
2176 /* for debug out only used*/
2177 BITMAPINFO bmp_info;
2178 BITMAPFILEHEADER bmp_fileheader;
2181 memset(&bmp_info, 0, sizeof(BITMAPINFO));
2182 bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2183 bmp_info.bmiHeader.biSizeImage = p_sys->i_atmo_height *
2184 p_sys->i_atmo_width * 4;
2185 bmp_info.bmiHeader.biCompression = BI_RGB;
2186 bmp_info.bmiHeader.biWidth = p_sys->i_atmo_width;
2187 bmp_info.bmiHeader.biHeight = -p_sys->i_atmo_height;
2188 bmp_info.bmiHeader.biBitCount = 32;
2189 bmp_info.bmiHeader.biPlanes = 1;
2191 bmp_fileheader.bfReserved1 = 0;
2192 bmp_fileheader.bfReserved2 = 0;
2193 bmp_fileheader.bfSize = sizeof(BITMAPFILEHEADER) +
2194 sizeof(BITMAPINFOHEADER) +
2195 bmp_info.bmiHeader.biSizeImage;
2196 bmp_fileheader.bfType = VLC_TWOCC('B','M');
2197 bmp_fileheader.bfOffBits = sizeof(BITMAPFILEHEADER) +
2198 sizeof(BITMAPINFOHEADER);
2200 fp_bitmap = fopen(psz_filename,"wb");
2201 if( fp_bitmap != NULL)
2203 fwrite(&bmp_fileheader, sizeof(BITMAPFILEHEADER), 1, fp_bitmap);
2204 fwrite(&bmp_info.bmiHeader, sizeof(BITMAPINFOHEADER), 1, fp_bitmap);
2205 fwrite(p_pixels, bmp_info.bmiHeader.biSizeImage, 1, fp_bitmap);
2212 /****************************************************************************
2213 * CreateMiniImage: extracts a 64x48 pixel image from the frame
2214 * (there is a small border arround thats why the loops starts with one
2215 * instead zero) without any interpolation
2216 *****************************************************************************/
2217 static void CreateMiniImage( filter_t *p_filter, picture_t *p_inpic)
2219 filter_sys_t *p_sys = p_filter->p_sys;
2221 pointer to RGB Buffer created in external libary as safe array which
2222 is locked inside AtmoLockTransferBuffer
2224 uint8_t *p_transfer;
2225 #if defined( __ATMO_DEBUG__ )
2226 /* for debug out only used*/
2227 char sz_filename[MAX_PATH];
2231 Lock the before created VarArray (AtmoCreateTransferBuffers)
2232 inside my wrapper library and give me a pointer to the buffer!
2233 below linux a global buffer may be used and protected with a mutex?
2235 p_transfer = AtmoLockTransferBuffer(p_filter);
2236 if(p_transfer == NULL)
2238 msg_Err( p_filter, "AtmoLight no transferbuffer available. "\
2239 "AtmoLight will be disabled!");
2240 p_sys->b_enabled = false;
2245 do the call via pointer to function instead of having a
2248 p_sys->pf_extract_mini_image(p_sys, p_inpic, p_transfer);
2251 #if defined( __ATMO_DEBUG__ )
2253 if debugging enabled save every 128th image to disk
2255 if(p_sys->b_saveframes && p_sys->sz_framepath[0] != 0 )
2258 if((p_sys->ui_frame_counter & 127) == 0)
2260 sprintf(sz_filename,"%satmo_dbg_%06u.bmp",p_sys->sz_framepath,
2261 p_sys->ui_frame_counter);
2262 msg_Dbg(p_filter, "SaveFrame %s",sz_filename);
2264 SaveBitmap(p_sys, p_transfer, sz_filename);
2268 msg_Dbg( p_filter, "AtmoFrame %u Time: %d ms", p_sys->ui_frame_counter,
2270 p_sys->ui_frame_counter++;
2273 p_sys->i_frames_processed++;
2276 /* show the colors on the wall */
2277 AtmoSendPixelData( p_filter );
2283 /*****************************************************************************
2284 * Filter: calls the extract method and forwards the incomming picture 1:1
2285 *****************************************************************************
2287 *****************************************************************************/
2289 static picture_t * Filter( filter_t *p_filter, picture_t *p_pic )
2291 filter_sys_t *p_sys = p_filter->p_sys;
2292 if( !p_pic ) return NULL;
2294 picture_t *p_outpic = filter_NewPicture( p_filter );
2297 picture_Release( p_pic );
2300 picture_CopyPixels( p_outpic, p_pic );
2302 vlc_mutex_lock( &p_sys->filter_lock );
2304 if(p_sys->b_enabled && p_sys->pf_extract_mini_image &&
2305 !p_sys->b_pause_live)
2307 p_sys->i_crop_x_offset = p_filter->fmt_in.video.i_x_offset;
2308 p_sys->i_crop_y_offset = p_filter->fmt_in.video.i_y_offset;
2309 p_sys->i_crop_width = p_filter->fmt_in.video.i_visible_width;
2310 p_sys->i_crop_height = p_filter->fmt_in.video.i_visible_height;
2312 CreateMiniImage(p_filter, p_outpic);
2315 vlc_mutex_unlock( &p_sys->filter_lock );
2318 return CopyInfoAndRelease( p_outpic, p_pic );
2322 /*****************************************************************************
2323 * FadeToColorThread: Threadmethod which changes slowly the color
2324 * to a target color defined in p_fadethread struct
2325 * use for: Fade to Pause Color, and Fade to End Color
2326 *****************************************************************************/
2327 static void *FadeToColorThread(vlc_object_t *obj)
2329 fadethread_t *p_fadethread = (fadethread_t *)obj;
2330 filter_sys_t *p_sys = (filter_sys_t *)p_fadethread->p_filter->p_sys;
2331 int i_steps_done = 0;
2341 uint8_t *p_source = NULL;
2343 int canc = vlc_savecancel ();
2344 /* initialize AtmoWin for this thread! */
2345 AtmoInitialize(p_fadethread->p_filter , true);
2347 uint8_t *p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
2348 if(p_transfer != NULL) {
2349 /* safe colors as "32bit" Integers to avoid overflows*/
2350 i_pause_red = p_fadethread->ui_red;
2351 i_pause_blue = p_fadethread->ui_blue;
2352 i_pause_green = p_fadethread->ui_green;
2355 allocate a temporary buffer for the last send
2356 image size less then 15kb
2358 int i_size = 4 * p_sys->i_atmo_width * p_sys->i_atmo_height;
2359 p_source = (uint8_t *)malloc( i_size );
2360 if(p_source != NULL)
2363 get a copy of the last transfered image as orign for the
2366 memcpy(p_source, p_transfer, i_size);
2367 /* send the same pixel data again... to unlock the buffer! */
2368 AtmoSendPixelData( p_fadethread->p_filter );
2370 while( (vlc_object_alive (p_fadethread)) &&
2371 (i_steps_done < p_fadethread->i_steps))
2373 p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
2374 if(!p_transfer) break; /* should not happen if it worked
2375 one time in the code above! */
2378 move all pixels in the mini image (64x48) one step closer to
2379 the desired color these loop takes the most time of this
2380 thread improvements wellcome!
2383 (i_index < i_size) && (vlc_object_alive (p_fadethread));
2386 i_src_blue = p_source[i_index+0];
2387 i_src_green = p_source[i_index+1];
2388 i_src_red = p_source[i_index+2];
2389 p_transfer[i_index+0] = (uint8_t) (((
2390 (i_pause_blue - i_src_blue)
2391 * i_steps_done)/p_fadethread->i_steps)
2394 p_transfer[i_index+1] = (uint8_t) (((
2395 (i_pause_green - i_src_green)
2396 * i_steps_done)/p_fadethread->i_steps)
2399 p_transfer[i_index+2] = (uint8_t) (((
2400 (i_pause_red - i_src_red)
2401 * i_steps_done)/p_fadethread->i_steps)
2405 /* send image to lightcontroller */
2406 AtmoSendPixelData( p_fadethread->p_filter );
2407 /* is there something like and interruptable sleep inside
2408 the VLC libaries? inside native win32 I would use an Event
2409 (CreateEvent) and here an WaitForSingleObject?
2415 /* in failure of malloc also unlock buffer */
2416 AtmoSendPixelData(p_fadethread->p_filter);
2419 /* call indirect to OleUnitialize() for this thread */
2420 AtmoFinalize(p_fadethread->p_filter, 0);
2421 vlc_restorecancel (canc);
2425 /*****************************************************************************
2426 * CheckAndStopFadeThread: if there is a fadethread structure left, or running.
2427 ******************************************************************************
2428 * this function will stop the thread ... and waits for its termination
2429 * before removeing the objects from vout_sys_t ...
2430 ******************************************************************************/
2431 static void CheckAndStopFadeThread(filter_t *p_filter)
2433 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2434 vlc_mutex_lock( &p_sys->filter_lock );
2435 if(p_sys->p_fadethread != NULL)
2437 msg_Dbg(p_filter, "kill still running fadeing thread...");
2439 p_sys->p_fadethread->b_die = true;
2441 vlc_thread_join(p_sys->p_fadethread);
2443 vlc_object_release(p_sys->p_fadethread);
2444 p_sys->p_fadethread = NULL;
2446 vlc_mutex_unlock( &p_sys->filter_lock );
2449 /*****************************************************************************
2450 * StateCallback: Callback for the inputs variable "State" to get notified
2451 * about Pause and Continue Playback events.
2452 *****************************************************************************/
2453 static int StateCallback( vlc_object_t *p_this, char const *psz_cmd,
2454 vlc_value_t oldval, vlc_value_t newval,
2457 filter_t *p_filter = (filter_t *)p_data;
2458 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2460 if(p_sys->b_usepausecolor && p_sys->b_enabled)
2462 msg_Dbg(p_filter, "state change from: %"PRId64" to %"PRId64, oldval.i_int,
2465 if((newval.i_int == PAUSE_S) && (oldval.i_int == PLAYING_S))
2467 /* tell the other thread to stop sending images to light
2469 p_sys->b_pause_live = true;
2471 // clean up old thread - should not happen....
2472 CheckAndStopFadeThread( p_filter );
2474 // perpare spawn fadeing thread
2475 vlc_mutex_lock( &p_sys->filter_lock );
2477 launch only a new thread if there is none active!
2478 or waiting for cleanup
2480 if(p_sys->p_fadethread == NULL)
2482 p_sys->p_fadethread = (fadethread_t *)vlc_object_create(
2484 sizeof(fadethread_t) );
2486 p_sys->p_fadethread->p_filter = p_filter;
2487 p_sys->p_fadethread->ui_red = p_sys->ui_pausecolor_red;
2488 p_sys->p_fadethread->ui_green = p_sys->ui_pausecolor_green;
2489 p_sys->p_fadethread->ui_blue = p_sys->ui_pausecolor_blue;
2490 p_sys->p_fadethread->i_steps = p_sys->i_fadesteps;
2492 if( vlc_thread_create( p_sys->p_fadethread,
2494 VLC_THREAD_PRIORITY_LOW ) )
2496 msg_Err( p_filter, "cannot create FadeToColorThread" );
2497 vlc_object_release( p_sys->p_fadethread );
2498 p_sys->p_fadethread = NULL;
2501 vlc_mutex_unlock( &p_sys->filter_lock );
2504 if((newval.i_int == PLAYING_S) && (oldval.i_int == PAUSE_S))
2506 /* playback continues check thread state */
2507 CheckAndStopFadeThread( p_filter );
2508 /* reactivate the Render function... to do its normal work */
2509 p_sys->b_pause_live = false;
2516 /*****************************************************************************
2517 * AddPlaylistInputThreadStateCallback: Setup call back on "State" Variable
2518 *****************************************************************************
2519 * Add Callback function to the "state" variable of the input thread..
2520 * first find the PlayList and get the input thread from there to attach
2522 *****************************************************************************/
2523 static void AddStateVariableCallback(filter_t *p_filter)
2525 input_thread_t *p_input = playlist_CurrentInput( pl_Get( p_filter ) );
2528 var_AddCallback( p_input, "state", StateCallback, p_filter );
2529 vlc_object_release( p_input );
2533 /*****************************************************************************
2534 * DelPlaylistInputThreadStateCallback: Remove call back on "State" Variable
2535 *****************************************************************************
2536 * Delete the callback function to the "state" variable of the input thread...
2537 * first find the PlayList and get the input thread from there to attach
2539 *****************************************************************************/
2540 static void DelStateVariableCallback( filter_t *p_filter )
2542 input_thread_t *p_input = playlist_CurrentInput( pl_Get ( p_filter ) );
2545 var_DelCallback( p_input, "state", StateCallback, p_filter );
2546 vlc_object_release( p_input );
2550 /****************************************************************************
2551 * StateCallback: Callback for the inputs variable "State" to get notified
2552 * about Pause and Continue Playback events.
2553 *****************************************************************************/
2554 static int AtmoSettingsCallback( vlc_object_t *p_this, char const *psz_var,
2555 vlc_value_t oldval, vlc_value_t newval,
2558 filter_t *p_filter = (filter_t *)p_data;
2559 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2561 vlc_mutex_lock( &p_sys->filter_lock );
2563 if( !strcmp( psz_var, CFG_PREFIX "showdots" ))
2565 p_sys->b_show_dots = newval.b_bool;
2568 CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
2572 msg_Dbg(p_filter, "apply AtmoSettingsCallback %s (int: %"PRId64" -> %"PRId64")",
2578 if( !strcmp( psz_var, CFG_PREFIX "filtermode" ))
2579 p_atmo_config->setLiveViewFilterMode( (AtmoFilterMode)newval.i_int);
2581 else if( !strcmp( psz_var, CFG_PREFIX "percentnew" ))
2582 p_atmo_config->setLiveViewFilter_PercentNew( newval.i_int );
2584 else if( !strcmp( psz_var, CFG_PREFIX "meanlength" ))
2585 p_atmo_config->setLiveViewFilter_MeanLength( newval.i_int );
2587 else if( !strcmp( psz_var, CFG_PREFIX "meanthreshold" ))
2588 p_atmo_config->setLiveViewFilter_MeanThreshold( newval.i_int );
2590 else if( !strcmp( psz_var, CFG_PREFIX "edgeweightning" ))
2591 p_atmo_config->setLiveView_EdgeWeighting( newval.i_int );
2593 else if( !strcmp( psz_var, CFG_PREFIX "brightness" ))
2594 p_atmo_config->setLiveView_BrightCorrect( newval.i_int );
2596 else if( !strcmp( psz_var, CFG_PREFIX "darknesslimit" ))
2597 p_atmo_config->setLiveView_DarknessLimit( newval.i_int );
2599 else if( !strcmp( psz_var, CFG_PREFIX "huewinsize" ))
2600 p_atmo_config->setLiveView_HueWinSize( newval.i_int );
2602 else if( !strcmp( psz_var, CFG_PREFIX "satwinsize" ))
2603 p_atmo_config->setLiveView_SatWinSize( newval.i_int );
2605 else if( !strcmp( psz_var, CFG_PREFIX "framedelay" ))
2606 p_atmo_config->setLiveView_FrameDelay( newval.i_int );
2608 else if( !strcmp( psz_var, CFG_PREFIX "whiteadj" ))
2609 p_atmo_config->setUseSoftwareWhiteAdj( newval.b_bool );
2611 else if( !strcmp( psz_var, CFG_PREFIX "white-red" ))
2612 p_atmo_config->setWhiteAdjustment_Red( newval.i_int );
2614 else if( !strcmp( psz_var, CFG_PREFIX "white-green" ))
2615 p_atmo_config->setWhiteAdjustment_Green( newval.i_int );
2617 else if( !strcmp( psz_var, CFG_PREFIX "white-blue" ))
2618 p_atmo_config->setWhiteAdjustment_Blue( newval.i_int );
2622 vlc_mutex_unlock( &p_sys->filter_lock );
2627 static void AddAtmoSettingsVariablesCallbacks(filter_t *p_filter)
2629 var_AddCallback( p_filter, CFG_PREFIX "filtermode",
2630 AtmoSettingsCallback, p_filter );
2631 var_AddCallback( p_filter, CFG_PREFIX "percentnew",
2632 AtmoSettingsCallback, p_filter );
2635 var_AddCallback( p_filter, CFG_PREFIX "meanlength",
2636 AtmoSettingsCallback, p_filter );
2637 var_AddCallback( p_filter, CFG_PREFIX "meanthreshold",
2638 AtmoSettingsCallback, p_filter );
2640 var_AddCallback( p_filter, CFG_PREFIX "edgeweightning",
2641 AtmoSettingsCallback, p_filter );
2642 var_AddCallback( p_filter, CFG_PREFIX "brightness",
2643 AtmoSettingsCallback, p_filter );
2644 var_AddCallback( p_filter, CFG_PREFIX "darknesslimit",
2645 AtmoSettingsCallback, p_filter );
2647 var_AddCallback( p_filter, CFG_PREFIX "huewinsize",
2648 AtmoSettingsCallback, p_filter );
2649 var_AddCallback( p_filter, CFG_PREFIX "satwinsize",
2650 AtmoSettingsCallback, p_filter );
2651 var_AddCallback( p_filter, CFG_PREFIX "framedelay",
2652 AtmoSettingsCallback, p_filter );
2655 var_AddCallback( p_filter, CFG_PREFIX "whiteadj",
2656 AtmoSettingsCallback, p_filter );
2657 var_AddCallback( p_filter, CFG_PREFIX "white-red",
2658 AtmoSettingsCallback, p_filter );
2659 var_AddCallback( p_filter, CFG_PREFIX "white-green",
2660 AtmoSettingsCallback, p_filter );
2661 var_AddCallback( p_filter, CFG_PREFIX "white-blue",
2662 AtmoSettingsCallback, p_filter );
2664 var_AddCallback( p_filter, CFG_PREFIX "showdots",
2665 AtmoSettingsCallback, p_filter );
2669 static void DelAtmoSettingsVariablesCallbacks( filter_t *p_filter )
2672 var_DelCallback( p_filter, CFG_PREFIX "filtermode",
2673 AtmoSettingsCallback, p_filter );
2675 var_DelCallback( p_filter, CFG_PREFIX "percentnew",
2676 AtmoSettingsCallback, p_filter );
2677 var_DelCallback( p_filter, CFG_PREFIX "meanlength",
2678 AtmoSettingsCallback, p_filter );
2679 var_DelCallback( p_filter, CFG_PREFIX "meanthreshold",
2680 AtmoSettingsCallback, p_filter );
2682 var_DelCallback( p_filter, CFG_PREFIX "edgeweightning",
2683 AtmoSettingsCallback, p_filter );
2684 var_DelCallback( p_filter, CFG_PREFIX "brightness",
2685 AtmoSettingsCallback, p_filter );
2686 var_DelCallback( p_filter, CFG_PREFIX "darknesslimit",
2687 AtmoSettingsCallback, p_filter );
2689 var_DelCallback( p_filter, CFG_PREFIX "huewinsize",
2690 AtmoSettingsCallback, p_filter );
2691 var_DelCallback( p_filter, CFG_PREFIX "satwinsize",
2692 AtmoSettingsCallback, p_filter );
2693 var_DelCallback( p_filter, CFG_PREFIX "framedelay",
2694 AtmoSettingsCallback, p_filter );
2697 var_DelCallback( p_filter, CFG_PREFIX "whiteadj",
2698 AtmoSettingsCallback, p_filter );
2699 var_DelCallback( p_filter, CFG_PREFIX "white-red",
2700 AtmoSettingsCallback, p_filter );
2701 var_DelCallback( p_filter, CFG_PREFIX "white-green",
2702 AtmoSettingsCallback, p_filter );
2703 var_DelCallback( p_filter, CFG_PREFIX "white-blue",
2704 AtmoSettingsCallback, p_filter );
2706 var_DelCallback( p_filter, CFG_PREFIX "showdots",
2707 AtmoSettingsCallback, p_filter );
2712 #if defined(__ATMO_DEBUG__)
2713 static void atmo_parse_crop(char *psz_cropconfig,
2714 video_format_t fmt_in,
2715 video_format_t fmt_render,
2716 int &i_visible_width, int &i_visible_height,
2717 int &i_x_offset, int &i_y_offset )
2719 int64_t i_aspect_num, i_aspect_den;
2720 unsigned int i_width, i_height;
2722 i_visible_width = fmt_in.i_visible_width;
2723 i_visible_height = fmt_in.i_visible_height;
2724 i_x_offset = fmt_in.i_x_offset;
2725 i_y_offset = fmt_in.i_y_offset;
2727 char *psz_end = NULL, *psz_parser = strchr( psz_cropconfig, ':' );
2730 /* We're using the 3:4 syntax */
2731 i_aspect_num = strtol( psz_cropconfig, &psz_end, 10 );
2732 if( psz_end == psz_cropconfig || !i_aspect_num ) return;
2734 i_aspect_den = strtol( ++psz_parser, &psz_end, 10 );
2735 if( psz_end == psz_parser || !i_aspect_den ) return;
2737 i_width = fmt_in.i_sar_den * fmt_render.i_visible_height *
2738 i_aspect_num / i_aspect_den / fmt_in.i_sar_num;
2740 i_height = fmt_render.i_visible_width*fmt_in.i_sar_num *
2741 i_aspect_den / i_aspect_num / fmt_in.i_sar_den;
2743 if( i_width < fmt_render.i_visible_width )
2745 i_x_offset = fmt_render.i_x_offset +
2746 (fmt_render.i_visible_width - i_width) / 2;
2747 i_visible_width = i_width;
2751 i_y_offset = fmt_render.i_y_offset +
2752 (fmt_render.i_visible_height - i_height) / 2;
2753 i_visible_height = i_height;
2758 psz_parser = strchr( psz_cropconfig, 'x' );
2761 /* Maybe we're using the <width>x<height>+<left>+<top> syntax */
2762 unsigned int i_crop_width, i_crop_height, i_crop_top, i_crop_left;
2764 i_crop_width = strtol( psz_cropconfig, &psz_end, 10 );
2765 if( psz_end != psz_parser ) return;
2767 psz_parser = strchr( ++psz_end, '+' );
2768 i_crop_height = strtol( psz_end, &psz_end, 10 );
2769 if( psz_end != psz_parser ) return;
2771 psz_parser = strchr( ++psz_end, '+' );
2772 i_crop_left = strtol( psz_end, &psz_end, 10 );
2773 if( psz_end != psz_parser ) return;
2776 i_crop_top = strtol( psz_end, &psz_end, 10 );
2777 if( *psz_end != '\0' ) return;
2779 i_width = i_crop_width;
2780 i_visible_width = i_width;
2782 i_height = i_crop_height;
2783 i_visible_height = i_height;
2785 i_x_offset = i_crop_left;
2786 i_y_offset = i_crop_top;
2790 /* Maybe we're using the <left>+<top>+<right>+<bottom> syntax */
2791 unsigned int i_crop_top, i_crop_left, i_crop_bottom, i_crop_right;
2793 psz_parser = strchr( psz_cropconfig, '+' );
2794 i_crop_left = strtol( psz_cropconfig, &psz_end, 10 );
2795 if( psz_end != psz_parser ) return;
2797 psz_parser = strchr( ++psz_end, '+' );
2798 i_crop_top = strtol( psz_end, &psz_end, 10 );
2799 if( psz_end != psz_parser ) return;
2801 psz_parser = strchr( ++psz_end, '+' );
2802 i_crop_right = strtol( psz_end, &psz_end, 10 );
2803 if( psz_end != psz_parser ) return;
2806 i_crop_bottom = strtol( psz_end, &psz_end, 10 );
2807 if( *psz_end != '\0' ) return;
2809 i_width = fmt_render.i_visible_width -
2812 i_visible_width = i_width;
2814 i_height = fmt_render.i_visible_height -
2817 i_visible_height = i_height;
2819 i_x_offset = i_crop_left;
2820 i_y_offset = i_crop_top;