1 /*****************************************************************************
2 * atmo.cpp : "Atmo Light" video filter
3 *****************************************************************************
4 * Copyright (C) 2000-2006 the VideoLAN team
7 * Authors: André Weber (WeberAndre@gmx.de)
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #define __STDC_FORMAT_MACROS 1
28 #include <stdlib.h> /* malloc(), free() */
30 #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, NULL,
401 PCOLOR_RED_TEXT, PCOLOR_RED_LONGTEXT, false)
402 add_integer_with_range(CFG_PREFIX "pcolor-green", 0, 0, 255, NULL,
403 PCOLOR_GREEN_TEXT, PCOLOR_GREEN_LONGTEXT, false)
404 add_integer_with_range(CFG_PREFIX "pcolor-blue", 192, 0, 255, NULL,
405 PCOLOR_BLUE_TEXT, PCOLOR_BLUE_LONGTEXT, false)
406 add_integer_with_range(CFG_PREFIX "fadesteps", 50, 1, 250, NULL,
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, NULL,
415 ECOLOR_RED_TEXT, ECOLOR_RED_LONGTEXT, false)
416 add_integer_with_range(CFG_PREFIX "ecolor-green", 192, 0, 255, NULL,
417 ECOLOR_GREEN_TEXT, ECOLOR_GREEN_LONGTEXT, false)
418 add_integer_with_range(CFG_PREFIX "ecolor-blue", 192, 0, 255, NULL,
419 ECOLOR_BLUE_TEXT, ECOLOR_BLUE_LONGTEXT, false)
420 add_integer_with_range(CFG_PREFIX "efadesteps", 50, 1, 250, NULL,
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, NULL,
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, NULL,
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, NULL,
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, NULL,
481 ZONE_TOP_TEXT, ZONE_TOP_LONGTEXT, false)
482 add_integer_with_range(CFG_PREFIX "zones-bottom", 1, 0, 16, NULL,
483 ZONE_BOTTOM_TEXT, ZONE_BOTTOM_LONGTEXT, false)
484 add_integer_with_range(CFG_PREFIX "zones-lr", 1, 0, 16, NULL,
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, NULL,
498 EDGE_TEXT, EDGE_LONGTEXT, false)
500 add_integer_with_range(CFG_PREFIX "brightness", 100, 50, 300, NULL,
501 BRIGHTNESS_TEXT, BRIGHTNESS_LONGTEXT, false)
503 add_integer_with_range(CFG_PREFIX "darknesslimit", 3, 0, 10, NULL,
504 DARKNESS_TEXT, DARKNESS_LONGTEXT, false)
506 add_integer_with_range(CFG_PREFIX "huewinsize", 3, 0, 5, NULL,
507 HUEWINSIZE_TEXT, HUEWINSIZE_LONGTEXT, false)
509 add_integer_with_range(CFG_PREFIX "satwinsize", 3, 0, 5, NULL,
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, NULL,
518 MEANLENGTH_TEXT, MEANLENGTH_LONGTEXT, false)
520 add_integer_with_range(CFG_PREFIX "meanthreshold", 40, 1, 100, NULL,
521 MEANTHRESHOLD_TEXT, MEANTHRESHOLD_LONGTEXT, false)
523 add_integer_with_range(CFG_PREFIX "percentnew", 50, 1, 100, NULL,
524 MEANPERCENTNEW_TEXT, MEANPERCENTNEW_LONGTEXT, false)
526 add_integer_with_range(CFG_PREFIX "framedelay", 18, 0, 200, NULL,
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, NULL,
569 WHITE_RED_TEXT, WHITE_RED_LONGTEXT, false)
571 add_integer_with_range(CFG_PREFIX "white-green", 255, 0, 255, NULL,
572 WHITE_GREEN_TEXT, WHITE_GREEN_LONGTEXT, false)
574 add_integer_with_range(CFG_PREFIX "white-blue", 255, 0, 255, NULL,
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, NULL,
612 WIDTH_TEXT, WIDTH_LONGTEXT, true)
613 add_integer_with_range(CFG_PREFIX "height", 48, 48, 384, NULL,
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)
819 if(b_for_thread == false)
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 == true)
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,
1121 "AtmoLight fadeing",
1123 VLC_THREAD_PRIORITY_LOW ) )
1125 msg_Err( p_filter, "cannot create FadeToColorThread" );
1126 vlc_object_release( p_sys->p_fadethread );
1127 p_sys->p_fadethread = NULL;
1128 vlc_mutex_unlock( &p_sys->filter_lock );
1132 vlc_mutex_unlock( &p_sys->filter_lock );
1134 /* wait for the thread... */
1135 vlc_thread_join(p_sys->p_fadethread);
1137 vlc_object_release(p_sys->p_fadethread);
1139 p_sys->p_fadethread = NULL;
1143 the following happens only useing the
1144 external AtmoWin Device Software
1146 if( !p_sys->p_atmo_config )
1148 if(p_sys->i_AtmoOldEffect != emLivePicture)
1149 AtmoSwitchEffect( p_filter, p_sys->i_AtmoOldEffect);
1151 AtmoSetLiveSource( p_filter, lvsGDI );
1154 /* close device connection etc. */
1155 AtmoFinalize(p_filter, 1);
1157 /* disable filter method .. */
1158 p_sys->b_enabled = false;
1163 depending on mode setup imagesize to 64x48(classic), or defined
1164 resolution of external atmowin.exe on windows
1166 static void Atmo_SetupImageSize(filter_t *p_filter)
1168 filter_sys_t *p_sys = p_filter->p_sys;
1170 size of extracted image by default 64x48 (other imagesizes are
1171 currently ignored by AtmoWin)
1173 p_sys->i_atmo_width = var_CreateGetIntegerCommand( p_filter,
1174 CFG_PREFIX "width");
1175 p_sys->i_atmo_height = var_CreateGetIntegerCommand( p_filter,
1176 CFG_PREFIX "height");
1178 if(p_sys->p_atmo_config)
1181 } else if(p_sys->pf_ctrl_atmo_get_image_size)
1183 /* on win32 with active ctrl dll */
1184 p_sys->pf_ctrl_atmo_get_image_size( &p_sys->i_atmo_width,
1185 &p_sys->i_atmo_height );
1189 msg_Dbg(p_filter,"sample image size %d * %d pixels", p_sys->i_atmo_width,
1190 p_sys->i_atmo_height);
1194 initialize the zone and channel mapping for the buildin atmolight adapter
1196 static void Atmo_SetupBuildZones(filter_t *p_filter)
1198 filter_sys_t *p_sys = p_filter->p_sys;
1200 p_sys->p_atmo_dyndata->LockCriticalSection();
1202 CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
1205 CAtmoChannelAssignment *p_channel_assignment =
1206 p_atmo_config->getChannelAssignment(0);
1208 // channel 0 - zone 4
1209 p_channel_assignment->setZoneIndex( 0, var_CreateGetIntegerCommand(
1210 p_filter, CFG_PREFIX "channel_0")
1213 // channel 1 - zone 3
1214 p_channel_assignment->setZoneIndex( 1, var_CreateGetIntegerCommand(
1215 p_filter, CFG_PREFIX "channel_1")
1218 // channel 2 - zone 1
1219 p_channel_assignment->setZoneIndex( 2, var_CreateGetIntegerCommand(
1220 p_filter, CFG_PREFIX "channel_2")
1223 // channel 3 - zone 0
1224 p_channel_assignment->setZoneIndex( 3, var_CreateGetIntegerCommand(
1225 p_filter, CFG_PREFIX "channel_3")
1228 // channel 4 - zone 2
1229 p_channel_assignment->setZoneIndex( 4, var_CreateGetIntegerCommand(
1230 p_filter, CFG_PREFIX "channel_4")
1233 char *psz_channels = var_CreateGetStringCommand(
1235 CFG_PREFIX "channels"
1237 if( !EMPTY_STR(psz_channels) )
1239 msg_Dbg( p_filter, "deal with new zone mapping %s", psz_channels );
1241 char *psz_temp = psz_channels;
1242 char *psz_start = psz_temp;
1245 if(*psz_temp == ',' || *psz_temp == ';')
1250 int zone = atoi( psz_start );
1252 zone >= p_channel_assignment->getSize()) {
1253 msg_Warn( p_filter, "Zone %d out of range -1..%d",
1254 zone, p_channel_assignment->getSize()-1 );
1256 p_channel_assignment->setZoneIndex( channel, zone );
1260 psz_start = psz_temp;
1268 process the rest of the string
1270 if( *psz_start && !*psz_temp )
1272 int zone = atoi( psz_start );
1274 zone >= p_channel_assignment->getSize()) {
1275 msg_Warn( p_filter, "Zone %d out of range -1..%d",
1276 zone, p_channel_assignment->getSize()-1 );
1278 p_channel_assignment->setZoneIndex( channel, zone );
1282 free( psz_channels );
1284 for(int i=0;i< p_channel_assignment->getSize() ;i++)
1285 msg_Info( p_filter, "map zone %d to hardware channel %d",
1286 p_channel_assignment->getZoneIndex( i ),
1289 p_sys->p_atmo_dyndata->getAtmoConnection()
1290 ->SetChannelAssignment( p_channel_assignment );
1297 calculate the default gradients for each zone!
1298 depending on the zone layout set before, this now
1299 supports also multiple gradients on each side
1300 (older versions could do this only with external
1303 p_sys->p_atmo_dyndata->CalculateDefaultZones();
1307 first try to load the old style defined gradient bitmaps
1308 this could only be done for the first five zones
1309 - should be deprecated -
1311 CAtmoZoneDefinition *p_zone;
1312 char psz_gradient_var_name[30];
1313 char *psz_gradient_file;
1314 for(int i=0;i<CLASSIC_ATMO_NUM_ZONES;i++)
1316 sprintf(psz_gradient_var_name, CFG_PREFIX "gradient_zone_%d", i);
1317 psz_gradient_file = var_CreateGetStringCommand(
1319 psz_gradient_var_name
1321 if( !EMPTY_STR(psz_gradient_file) )
1323 msg_Dbg( p_filter, "loading gradientfile %s for "\
1324 "zone %d", psz_gradient_file, i);
1326 p_zone = p_atmo_config->getZoneDefinition(i);
1329 int i_res = p_zone->LoadGradientFromBitmap(psz_gradient_file);
1331 if(i_res != ATMO_LOAD_GRADIENT_OK)
1333 msg_Err( p_filter,"failed to load gradient '%s' with "\
1334 "error %d",psz_gradient_file,i_res);
1338 free( psz_gradient_file );
1343 the new approach try to load a gradient bitmap for each zone
1344 from a previously defined folder containing
1349 char *psz_gradient_path = var_CreateGetStringCommand(
1351 CFG_PREFIX "gradient_path"
1353 if( EMPTY_STR(psz_gradient_path) )
1355 char *psz_file_name = (char *)malloc( strlen(psz_gradient_path) + 16 );
1356 assert( psz_file_name );
1358 for(int i=0; i < p_atmo_config->getZoneCount(); i++ )
1360 p_zone = p_atmo_config->getZoneDefinition(i);
1364 sprintf(psz_file_name, "%s%szone_%d.bmp",
1365 psz_gradient_path, DIR_SEP, i );
1367 int i_res = p_zone->LoadGradientFromBitmap( psz_file_name );
1369 if( i_res == ATMO_LOAD_GRADIENT_OK )
1371 msg_Dbg( p_filter, "loaded gradientfile %s for "\
1372 "zone %d", psz_file_name, i);
1375 if( (i_res != ATMO_LOAD_GRADIENT_OK) &&
1376 (i_res != ATMO_LOAD_GRADIENT_FILENOTFOND) )
1378 msg_Err( p_filter,"failed to load gradient '%s' with "\
1379 "error %d",psz_file_name,i_res);
1384 free( psz_file_name );
1386 free( psz_gradient_path );
1389 p_sys->p_atmo_dyndata->UnLockCriticalSection();
1393 static void Atmo_SetupConfig(filter_t *p_filter, CAtmoConfig *p_atmo_config)
1396 figuring out the device ports (com-ports, ttys)
1398 char *psz_serialdev = var_CreateGetStringCommand( p_filter,
1399 CFG_PREFIX "serialdev" );
1400 char *psz_temp = psz_serialdev;
1402 if( !EMPTY_STR(psz_serialdev) )
1409 msg_Dbg( p_filter, "use port(s) %s",psz_serialdev);
1412 psz_serialdev - may contain up to 4 COM ports for the quattro device
1413 the quattro device is just hack of useing 4 classic devices as one
1414 logical device - thanks that usb-com-ports exists :)
1415 as Seperator I defined , or ; with the hope that these
1416 characters are never part of a device name
1418 while( (psz_token = strsep(&psz_temp, ",;")) != NULL && i_port < 4 )
1421 psz_token may contain spaces we have to trim away
1426 find first none space in string
1428 while( psz_token[i] == 32 ) i++;
1430 contains string only spaces or is empty? skip it
1438 while( psz_token[i] && psz_token[i] != 32 )
1439 psz_token[ j++ ] = psz_token[ i++ ];
1442 msg_Dbg( p_filter, "Serial Device [%d]: %s", i_port, psz_token );
1444 p_atmo_config->setSerialDevice( i_port, psz_token );
1451 msg_Err(p_filter,"no serial devicename(s) set");
1453 free( psz_serialdev );
1456 configuration of light source layout arround the display
1458 p_atmo_config->setZonesTopCount(
1459 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-top")
1461 p_atmo_config->setZonesBottomCount(
1462 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-bottom")
1464 p_atmo_config->setZonesLRCount(
1465 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-lr")
1467 p_atmo_config->setZoneSummary(
1468 var_CreateGetBoolCommand( p_filter, CFG_PREFIX "zone-summary")
1472 p_atmo_config->setLiveViewFilterMode(
1473 (AtmoFilterMode)var_CreateGetIntegerCommand( p_filter,
1474 CFG_PREFIX "filtermode")
1477 p_atmo_config->setLiveViewFilter_PercentNew(
1478 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "percentnew")
1480 p_atmo_config->setLiveViewFilter_MeanLength(
1481 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "meanlength")
1483 p_atmo_config->setLiveViewFilter_MeanThreshold(
1484 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "meanthreshold")
1487 p_atmo_config->setLiveView_EdgeWeighting(
1488 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "edgeweightning")
1490 p_atmo_config->setLiveView_BrightCorrect(
1491 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "brightness")
1493 p_atmo_config->setLiveView_DarknessLimit(
1494 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "darknesslimit")
1496 p_atmo_config->setLiveView_HueWinSize(
1497 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "huewinsize")
1499 p_atmo_config->setLiveView_SatWinSize(
1500 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "satwinsize")
1503 /* currently not required inside vlc */
1504 p_atmo_config->setLiveView_WidescreenMode( 0 );
1506 p_atmo_config->setLiveView_FrameDelay(
1507 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "framedelay")
1511 p_atmo_config->setUseSoftwareWhiteAdj(
1512 var_CreateGetBoolCommand( p_filter, CFG_PREFIX "whiteadj")
1514 p_atmo_config->setWhiteAdjustment_Red(
1515 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-red")
1517 p_atmo_config->setWhiteAdjustment_Green(
1518 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-green")
1520 p_atmo_config->setWhiteAdjustment_Blue(
1521 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-blue")
1525 settings for DMX device only
1527 p_atmo_config->setDMX_RGB_Channels(
1528 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "dmx-channels")
1531 char *psz_chbase = var_CreateGetStringCommand( p_filter,
1532 CFG_PREFIX "dmx-chbase" );
1533 if( !EMPTY_STR(psz_chbase) )
1534 p_atmo_config->setDMX_BaseChannels( psz_chbase );
1541 p_atmo_config->setMoMo_Channels(
1542 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "momo-channels")
1548 p_atmo_config->setFnordlicht_Amount(
1549 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "fnordlicht-amount")
1556 initialize the filter_sys_t structure with the data from the settings
1557 variables - if the external filter on win32 is enabled try loading the DLL,
1558 if this fails fallback to the buildin software
1560 static void Atmo_SetupParameters(filter_t *p_filter)
1563 filter_sys_t *p_sys = p_filter->p_sys;
1566 /* default filter disabled until DLL loaded and Init Success!*/
1567 p_sys->b_enabled = false;
1569 /* setup default mini image size (may be later a user option) */
1570 p_sys->i_atmo_width = 64;
1571 p_sys->i_atmo_height = 48;
1573 p_sys->i_device_type = var_CreateGetIntegerCommand( p_filter,
1574 CFG_PREFIX "device");
1578 0 => use AtmoWin Software (only win32)
1579 1 => use AtmoClassicConnection (direct)
1580 2 => use AtmoMultiConnection (direct up to four serial ports required)
1581 3 => use AtmoDmxConnection (simple serial DMX Device up to 255 channels)
1587 only on WIN32 the user has the choice between
1588 internal driver and external
1591 if(p_sys->i_device_type == 0) {
1593 /* Load the Com Wrapper Library (source available) */
1594 p_sys->h_AtmoCtrl = LoadLibraryA("AtmoCtrlLib.dll");
1595 if(p_sys->h_AtmoCtrl == NULL)
1598 be clever if the location of atmowina.exe is set
1599 try to load the dll from the same folder :-)
1601 char *psz_path = var_CreateGetStringCommand( p_filter,
1602 CFG_PREFIX "atmowinexe" );
1603 if( !EMPTY_STR(psz_path) )
1605 char *psz_bs = strrchr( psz_path , '\\');
1610 now format a new dll filename with complete path
1612 char *psz_dllname = NULL;
1613 asprintf( &psz_dllname, "%s\\AtmoCtrlLib.dll", psz_path );
1616 msg_Dbg( p_filter, "Try Loading '%s'", psz_dllname );
1617 p_sys->h_AtmoCtrl = LoadLibraryA( psz_dllname );
1619 free( psz_dllname );
1626 if(p_sys->h_AtmoCtrl != NULL)
1628 msg_Dbg( p_filter, "Load Library ok!");
1630 /* importing all required functions I hope*/
1631 p_sys->pf_ctrl_atmo_initialize =
1632 (int32_t (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,
1634 if(!p_sys->pf_ctrl_atmo_initialize)
1635 msg_Err( p_filter, "export AtmoInitialize missing.");
1637 p_sys->pf_ctrl_atmo_finalize =
1638 (void (*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,
1640 if(!p_sys->pf_ctrl_atmo_finalize)
1641 msg_Err( p_filter, "export AtmoFinalize missing.");
1643 p_sys->pf_ctrl_atmo_switch_effect =
1644 (int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,
1645 "AtmoSwitchEffect");
1646 if(!p_sys->pf_ctrl_atmo_switch_effect)
1647 msg_Err( p_filter, "export AtmoSwitchEffect missing.");
1649 p_sys->pf_ctrl_atmo_set_live_source =
1650 (int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,
1651 "AtmoSetLiveSource");
1652 if(!p_sys->pf_ctrl_atmo_set_live_source)
1653 msg_Err( p_filter, "export AtmoSetLiveSource missing.");
1655 p_sys->pf_ctrl_atmo_create_transfer_buffers =
1656 (void (*)(int32_t, int32_t, int32_t , int32_t))
1657 GetProcAddress(p_sys->h_AtmoCtrl,"AtmoCreateTransferBuffers");
1658 if(!p_sys->pf_ctrl_atmo_create_transfer_buffers)
1659 msg_Err( p_filter, "export AtmoCreateTransferBuffers missing.");
1661 p_sys->pf_ctrl_atmo_lock_transfer_buffer=
1662 (uint8_t*(*) (void))GetProcAddress(p_sys->h_AtmoCtrl,
1663 "AtmoLockTransferBuffer");
1664 if(!p_sys->pf_ctrl_atmo_lock_transfer_buffer)
1665 msg_Err( p_filter, "export AtmoLockTransferBuffer missing.");
1667 p_sys->pf_ctrl_atmo_send_pixel_data =
1668 (void (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,
1669 "AtmoSendPixelData");
1670 if(!p_sys->pf_ctrl_atmo_send_pixel_data)
1671 msg_Err( p_filter, "export AtmoSendPixelData missing.");
1673 p_sys->pf_ctrl_atmo_get_image_size =
1674 (void (*)(int32_t*,int32_t*))GetProcAddress(p_sys->h_AtmoCtrl,
1675 "AtmoWinGetImageSize");
1676 if(!p_sys->pf_ctrl_atmo_get_image_size)
1677 msg_Err( p_filter, "export AtmoWinGetImageSize missing.");
1680 /* the DLL is missing try internal filter ...*/
1682 "AtmoCtrlLib.dll missing fallback to internal atmo classic driver");
1683 p_sys->i_device_type = 1;
1688 if(p_sys->i_device_type >= 1) {
1689 msg_Dbg( p_filter, "try use buildin driver %d ", p_sys->i_device_type);
1691 now we have to read a lof of options from the config dialog
1692 most important the serial device if not set ... we can skip
1693 the rest and disable the filter...
1696 p_sys->p_atmo_config = new CAtmoConfig();
1698 p_sys->p_atmo_dyndata = new CAtmoDynData(
1699 (vlc_object_t *)p_filter,
1700 p_sys->p_atmo_config
1703 Atmo_SetupConfig( p_filter, p_sys->p_atmo_config );
1704 switch(p_sys->i_device_type)
1707 p_sys->p_atmo_config->setConnectionType( actClassicAtmo );
1711 p_sys->p_atmo_config->setConnectionType( actMultiAtmo );
1715 p_sys->p_atmo_config->setConnectionType( actDMX );
1719 p_sys->p_atmo_config->setConnectionType( actMoMoLight );
1723 p_sys->p_atmo_config->setConnectionType( actFnordlicht );
1727 msg_Warn( p_filter, "invalid device type %d found",
1728 p_sys->i_device_type );
1731 msg_Dbg( p_filter, "buildin driver config set");
1735 switch( p_filter->fmt_in.video.i_chroma )
1737 case VLC_CODEC_I420:
1738 case VLC_CODEC_YV12:
1739 p_sys->pf_extract_mini_image = ExtractMiniImage_YUV;
1742 msg_Warn( p_filter, "InitFilter-unsupported chroma: %4.4s",
1743 (char *)&p_filter->fmt_in.video.i_chroma);
1744 p_sys->pf_extract_mini_image = NULL;
1748 for debugging purpose show the samplinggrid on each frame as
1751 p_sys->b_show_dots = var_CreateGetBoolCommand( p_filter,
1752 CFG_PREFIX "showdots"
1755 #if defined(__ATMO_DEBUG__)
1756 /* save debug images to a folder as Bitmap files ? */
1757 p_sys->b_saveframes = var_CreateGetBoolCommand( p_filter,
1758 CFG_PREFIX "saveframes"
1760 msg_Dbg(p_filter,"saveframes = %d", (int)p_sys->b_saveframes);
1763 read debug image folder from config
1765 psz_path = var_CreateGetStringCommand( p_filter, CFG_PREFIX "framepath" );
1766 if(psz_path != NULL)
1768 strcpy(p_sys->sz_framepath, psz_path);
1769 #if defined( WIN32 )
1770 size_t i_strlen = strlen(p_sys->sz_framepath);
1771 if((i_strlen>0) && (p_sys->sz_framepath[i_strlen-1] != '\\'))
1773 p_sys->sz_framepath[i_strlen] = '\\';
1774 p_sys->sz_framepath[i_strlen+1] = 0;
1779 msg_Dbg(p_filter,"saveframesfolder %s",p_sys->sz_framepath);
1784 because atmowin could also be used for lighten up the room - I think if you
1785 pause the video it would be useful to get a little bit more light into to
1786 your living room? - instead switching on a lamp?
1788 p_sys->b_usepausecolor = var_CreateGetBoolCommand( p_filter,
1789 CFG_PREFIX "usepausecolor" );
1790 p_sys->ui_pausecolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1791 CFG_PREFIX "pcolor-red");
1792 p_sys->ui_pausecolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1793 CFG_PREFIX "pcolor-green");
1794 p_sys->ui_pausecolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1795 CFG_PREFIX "pcolor-blue");
1796 p_sys->i_fadesteps = var_CreateGetIntegerCommand( p_filter,
1797 CFG_PREFIX "fadesteps");
1798 if(p_sys->i_fadesteps < 1)
1799 p_sys->i_fadesteps = 1;
1800 msg_Dbg(p_filter,"use pause color %d, RGB: %d, %d, %d, Fadesteps: %d",
1801 (int)p_sys->b_usepausecolor,
1802 p_sys->ui_pausecolor_red,
1803 p_sys->ui_pausecolor_green,
1804 p_sys->ui_pausecolor_blue,
1805 p_sys->i_fadesteps);
1808 this color is use on shutdown of the filter - the define the
1809 final light after playback... may be used to dim up the light -
1810 how it happens in the cinema...
1812 p_sys->ui_endcolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1813 CFG_PREFIX "ecolor-red");
1814 p_sys->ui_endcolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1815 CFG_PREFIX "ecolor-green");
1816 p_sys->ui_endcolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1817 CFG_PREFIX "ecolor-blue");
1818 p_sys->i_endfadesteps = var_CreateGetIntegerCommand( p_filter,
1819 CFG_PREFIX "efadesteps");
1820 if(p_sys->i_endfadesteps < 1)
1821 p_sys->i_endfadesteps = 1;
1822 msg_Dbg(p_filter,"use ende color RGB: %d, %d, %d, Fadesteps: %d",
1823 p_sys->ui_endcolor_red,
1824 p_sys->ui_endcolor_green,
1825 p_sys->ui_endcolor_blue,
1826 p_sys->i_endfadesteps);
1831 if the external DLL was loaded successfully call AtmoInitialize -
1832 (must be done for each thread where you want to use AtmoLight!)
1834 int i = AtmoInitialize(p_filter, false);
1836 #if defined( WIN32 )
1837 if((i != 1) && (p_sys->i_device_type == 0))
1840 COM Server for AtmoLight not running ?
1841 if the exe path is configured try to start the "userspace" driver
1843 psz_path = var_CreateGetStringCommand( p_filter,
1844 CFG_PREFIX "atmowinexe" );
1845 if(psz_path != NULL)
1847 STARTUPINFO startupinfo;
1848 PROCESS_INFORMATION pinfo;
1849 memset(&startupinfo, 0, sizeof(STARTUPINFO));
1850 startupinfo.cb = sizeof(STARTUPINFO);
1851 if(CreateProcess(psz_path, NULL, NULL, NULL,
1852 FALSE, 0, NULL, NULL, &startupinfo, &pinfo) == TRUE)
1854 msg_Dbg(p_filter,"launched AtmoWin from %s",psz_path);
1855 WaitForInputIdle(pinfo.hProcess, 5000);
1857 retry to initialize the library COM ... functionality
1858 after the server was launched
1860 i = AtmoInitialize(p_filter, false);
1862 msg_Err(p_filter,"failed to launch AtmoWin from %s", psz_path);
1869 if(i == 1) /* Init Atmolight success... */
1871 msg_Dbg( p_filter, "AtmoInitialize Ok!");
1874 p_sys->i_atmo_width and p_sys->i_atmo_height
1875 if the external AtmoWinA.exe is used, it may require
1876 a other sample image size than 64 x 48
1877 (this overrides the settings of the filter)
1879 Atmo_SetupImageSize( p_filter );
1882 if( p_sys->i_device_type >= 1 )
1885 AtmoConnection class initialized now we can initialize
1886 the default zone and channel mappings
1888 Atmo_SetupBuildZones( p_filter );
1891 /* Setup Transferbuffers for 64 x 48 , RGB with 32bit Per Pixel */
1892 AtmoCreateTransferBuffers(p_filter, BI_RGB, 4,
1893 p_sys->i_atmo_width,
1894 p_sys->i_atmo_height
1897 /* say the userspace driver that a live mode should be activated
1898 the functions returns the old mode for later restore!
1899 - the buildin driver launches the live view thread in that case
1901 p_sys->i_AtmoOldEffect = AtmoSwitchEffect(p_filter, emLivePicture);
1904 live view can have two differnt source the AtmoWinA
1905 internal GDI Screencapture and the external one - which we
1908 AtmoSetLiveSource(p_filter, lvsExternal);
1910 /* enable other parts only if everything is fine */
1911 p_sys->b_enabled = true;
1913 msg_Dbg( p_filter, "Atmo Filter Enabled Ok!");
1919 /*****************************************************************************
1920 * CreateFilter: allocates AtmoLight video thread output method
1921 *****************************************************************************
1922 * This function allocates and initializes a AtmoLight vout method.
1923 *****************************************************************************/
1924 static int CreateFilter( vlc_object_t *p_this )
1926 filter_t *p_filter = (filter_t *)p_this;
1927 filter_sys_t *p_sys;
1929 /* Allocate structure */
1930 p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) );
1931 p_filter->p_sys = p_sys;
1932 if( p_filter->p_sys == NULL )
1934 /* set all entries to zero */
1935 memset(p_sys, 0, sizeof( filter_sys_t ));
1936 vlc_mutex_init( &p_sys->filter_lock );
1938 msg_Dbg( p_filter, "Create Atmo Filter");
1940 /* further Setup Function pointers for videolan for calling my filter */
1941 p_filter->pf_video_filter = Filter;
1943 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
1946 AddStateVariableCallback(p_filter);
1948 AddAtmoSettingsVariablesCallbacks(p_filter);
1950 Atmo_SetupParameters(p_filter);
1958 /*****************************************************************************
1959 * DestroyFilter: destroy AtmoLight video thread output method
1960 *****************************************************************************
1961 * Terminate an output method created by CreateFilter
1962 *****************************************************************************/
1964 static void DestroyFilter( vlc_object_t *p_this )
1966 filter_t *p_filter = (filter_t *)p_this;
1967 filter_sys_t *p_sys = p_filter->p_sys;
1969 msg_Dbg( p_filter, "Destroy Atmo Filter");
1971 DelStateVariableCallback(p_filter);
1973 DelAtmoSettingsVariablesCallbacks(p_filter);
1975 Atmo_Shutdown(p_filter);
1977 #if defined( WIN32 )
1978 if(p_sys->h_AtmoCtrl != NULL)
1980 FreeLibrary(p_sys->h_AtmoCtrl);
1984 delete p_sys->p_atmo_dyndata;
1985 delete p_sys->p_atmo_config;
1987 vlc_mutex_destroy( &p_sys->filter_lock );
1994 function stolen from some other videolan source filter ;-)
1995 for the moment RGB is OK... but better would be a direct transformation
1998 static inline void yuv_to_rgb( uint8_t *r, uint8_t *g, uint8_t *b,
1999 uint8_t y1, uint8_t u1, uint8_t v1 )
2001 /* macros used for YUV pixel conversions */
2002 # define SCALEBITS 10
2003 # define ONE_HALF (1 << (SCALEBITS - 1))
2004 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
2005 # define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
2007 int y, cb, cr, r_add, g_add, b_add;
2011 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
2012 g_add = - FIX(0.34414*255.0/224.0) * cb
2013 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
2014 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
2015 y = (y1 - 16) * FIX(255.0/219.0);
2016 *r = CLAMP((y + r_add) >> SCALEBITS);
2017 *g = CLAMP((y + g_add) >> SCALEBITS);
2018 *b = CLAMP((y + b_add) >> SCALEBITS);
2020 /******************************************************************************
2021 * ExtractMiniImage_YUV: extract a small image from the picture as 24-bit RGB
2022 *******************************************************************************
2023 * p_sys is a pointer to
2024 * p_inpic is the source frame
2025 * p_transfer_dest is the target buffer for the picture must be big enough!
2026 * (in win32 environment this buffer comes from the external DLL where it is
2027 * create as "variant array" and returned through the AtmoLockTransferbuffer
2029 static void ExtractMiniImage_YUV(filter_sys_t *p_sys,
2031 uint8_t *p_transfer_dest)
2038 uint8_t *p_rgb_dst_line_red;
2039 uint8_t *p_rgb_dst_line_green;
2040 uint8_t *p_rgb_dst_line_blue;
2045 /* calcute Pointers for Storage of B G R (A) */
2046 p_rgb_dst_line_blue = p_transfer_dest;
2047 p_rgb_dst_line_green = p_transfer_dest + 1;
2048 p_rgb_dst_line_red = p_transfer_dest + 2 ;
2050 int i_row_count = p_sys->i_atmo_height + 1;
2051 int i_col_count = p_sys->i_atmo_width + 1;
2052 int i_y_row,i_u_row,i_v_row,i_pixel_row;
2056 /* these two ugly loops extract the small image - goes it faster? how?
2057 the loops are so designed that there is a small border around the extracted
2058 image so we wont get column and row - zero from the frame, and not the most
2059 right and bottom pixels --- which may be clipped on computers useing TV out
2062 TODO: try to find out if the output is clipped through VLC - and try here
2063 to ingore the clipped away area for a better result!
2065 TODO: performance improvement in InitFilter percalculated the offsets of
2066 the lines inside the planes so I can save (i_row_count * 3) 2xMUL and
2067 one time DIV the same could be done for the inner loop I think...
2069 for(i_row = 1; i_row < i_row_count; i_row++)
2071 // calcute the current Lines in the source planes for this outputrow
2072 /* Adresscalcuation pointer to plane Length of one pixelrow in bytes
2073 calculate row now number
2076 p_inpic->format? transform Pixel row into row of plane...
2077 how? simple? fast? good?
2080 /* compute the source pixel row and respect the active cropping */
2081 i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
2082 + p_sys->i_crop_y_offset;
2085 trans for these Pixel row into the row of each plane ..
2086 because planesize can differ from image size
2088 i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
2089 p_inpic->format.i_visible_height;
2091 i_u_row = (i_pixel_row * p_inpic->p[U_PLANE].i_visible_lines) /
2092 p_inpic->format.i_visible_height;
2094 i_v_row = (i_pixel_row * p_inpic->p[V_PLANE].i_visible_lines) /
2095 p_inpic->format.i_visible_height;
2097 /* calculate the pointers to the pixeldata for this row
2100 p_src_y = p_inpic->p[Y_PLANE].p_pixels +
2101 p_inpic->p[Y_PLANE].i_pitch * i_y_row;
2102 p_src_u = p_inpic->p[U_PLANE].p_pixels +
2103 p_inpic->p[U_PLANE].i_pitch * i_u_row;
2104 p_src_v = p_inpic->p[V_PLANE].p_pixels +
2105 p_inpic->p[V_PLANE].i_pitch * i_v_row;
2107 for(i_col = 1; i_col < i_col_count; i_col++)
2109 i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
2110 p_sys->i_crop_x_offset;
2112 trans for these Pixel row into the row of each plane ..
2113 because planesize can differ from image size
2115 i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
2116 p_inpic->format.i_visible_width;
2117 i_xpos_u = (i_pixel_col * p_inpic->p[U_PLANE].i_visible_pitch) /
2118 p_inpic->format.i_visible_width;
2119 i_xpos_v = (i_pixel_col * p_inpic->p[V_PLANE].i_visible_pitch) /
2120 p_inpic->format.i_visible_width;
2122 yuv_to_rgb(p_rgb_dst_line_red,
2123 p_rgb_dst_line_green,
2124 p_rgb_dst_line_blue,
2130 /* +4 because output image should be RGB32 with dword alignment! */
2131 p_rgb_dst_line_red += 4;
2132 p_rgb_dst_line_green += 4;
2133 p_rgb_dst_line_blue += 4;
2137 if(p_sys->b_show_dots)
2139 for(i_row = 1; i_row < i_row_count; i_row++)
2141 i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
2142 + p_sys->i_crop_y_offset;
2144 i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
2145 p_inpic->format.i_visible_height;
2147 p_src_y = p_inpic->p[Y_PLANE].p_pixels +
2148 p_inpic->p[Y_PLANE].i_pitch * i_y_row;
2150 for(i_col = 1; i_col < i_col_count; i_col++)
2152 i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
2153 p_sys->i_crop_x_offset;
2154 i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
2155 p_inpic->format.i_visible_width;
2157 p_src_y[i_xpos_y] = 255;
2165 /******************************************************************************
2166 * SaveBitmap: Saves the content of a transferbuffer as Bitmap to disk
2167 *******************************************************************************
2168 * just for debugging
2169 * p_sys -> configuration if Atmo from there the function will get height and
2171 * p_pixels -> should be the dword aligned BGR(A) image data
2172 * psz_filename -> filename where to store
2174 #if defined(__ATMO_DEBUG__)
2175 void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename)
2177 /* for debug out only used*/
2178 BITMAPINFO bmp_info;
2179 BITMAPFILEHEADER bmp_fileheader;
2182 memset(&bmp_info, 0, sizeof(BITMAPINFO));
2183 bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2184 bmp_info.bmiHeader.biSizeImage = p_sys->i_atmo_height *
2185 p_sys->i_atmo_width * 4;
2186 bmp_info.bmiHeader.biCompression = BI_RGB;
2187 bmp_info.bmiHeader.biWidth = p_sys->i_atmo_width;
2188 bmp_info.bmiHeader.biHeight = -p_sys->i_atmo_height;
2189 bmp_info.bmiHeader.biBitCount = 32;
2190 bmp_info.bmiHeader.biPlanes = 1;
2192 bmp_fileheader.bfReserved1 = 0;
2193 bmp_fileheader.bfReserved2 = 0;
2194 bmp_fileheader.bfSize = sizeof(BITMAPFILEHEADER) +
2195 sizeof(BITMAPINFOHEADER) +
2196 bmp_info.bmiHeader.biSizeImage;
2197 bmp_fileheader.bfType = VLC_TWOCC('B','M');
2198 bmp_fileheader.bfOffBits = sizeof(BITMAPFILEHEADER) +
2199 sizeof(BITMAPINFOHEADER);
2201 fp_bitmap = fopen(psz_filename,"wb");
2202 if( fp_bitmap != NULL)
2204 fwrite(&bmp_fileheader, sizeof(BITMAPFILEHEADER), 1, fp_bitmap);
2205 fwrite(&bmp_info.bmiHeader, sizeof(BITMAPINFOHEADER), 1, fp_bitmap);
2206 fwrite(p_pixels, bmp_info.bmiHeader.biSizeImage, 1, fp_bitmap);
2213 /****************************************************************************
2214 * CreateMiniImage: extracts a 64x48 pixel image from the frame
2215 * (there is a small border arround thats why the loops starts with one
2216 * instead zero) without any interpolation
2217 *****************************************************************************/
2218 static void CreateMiniImage( filter_t *p_filter, picture_t *p_inpic)
2220 filter_sys_t *p_sys = p_filter->p_sys;
2222 pointer to RGB Buffer created in external libary as safe array which
2223 is locked inside AtmoLockTransferBuffer
2225 uint8_t *p_transfer;
2226 #if defined( __ATMO_DEBUG__ )
2227 /* for debug out only used*/
2228 char sz_filename[MAX_PATH];
2232 Lock the before created VarArray (AtmoCreateTransferBuffers)
2233 inside my wrapper library and give me a pointer to the buffer!
2234 below linux a global buffer may be used and protected with a mutex?
2236 p_transfer = AtmoLockTransferBuffer(p_filter);
2237 if(p_transfer == NULL)
2239 msg_Err( p_filter, "AtmoLight no transferbuffer available. "\
2240 "AtmoLight will be disabled!");
2241 p_sys->b_enabled = false;
2246 do the call via pointer to function instead of having a
2249 p_sys->pf_extract_mini_image(p_sys, p_inpic, p_transfer);
2252 #if defined( __ATMO_DEBUG__ )
2254 if debugging enabled save every 128th image to disk
2256 if((p_sys->b_saveframes == true) && (p_sys->sz_framepath[0] != 0 ))
2259 if((p_sys->ui_frame_counter & 127) == 0)
2261 sprintf(sz_filename,"%satmo_dbg_%06u.bmp",p_sys->sz_framepath,
2262 p_sys->ui_frame_counter);
2263 msg_Dbg(p_filter, "SaveFrame %s",sz_filename);
2265 SaveBitmap(p_sys, p_transfer, sz_filename);
2269 msg_Dbg( p_filter, "AtmoFrame %u Time: %d ms", p_sys->ui_frame_counter,
2271 p_sys->ui_frame_counter++;
2274 p_sys->i_frames_processed++;
2277 /* show the colors on the wall */
2278 AtmoSendPixelData( p_filter );
2284 /*****************************************************************************
2285 * Filter: calls the extract method and forwards the incomming picture 1:1
2286 *****************************************************************************
2288 *****************************************************************************/
2290 static picture_t * Filter( filter_t *p_filter, picture_t *p_pic )
2292 filter_sys_t *p_sys = p_filter->p_sys;
2293 if( !p_pic ) return NULL;
2295 picture_t *p_outpic = filter_NewPicture( p_filter );
2298 picture_Release( p_pic );
2301 picture_CopyPixels( p_outpic, p_pic );
2303 vlc_mutex_lock( &p_sys->filter_lock );
2305 if((p_sys->b_enabled == true) &&
2306 (p_sys->pf_extract_mini_image != NULL) &&
2307 (p_sys->b_pause_live == false))
2309 p_sys->i_crop_x_offset = p_filter->fmt_in.video.i_x_offset;
2310 p_sys->i_crop_y_offset = p_filter->fmt_in.video.i_y_offset;
2311 p_sys->i_crop_width = p_filter->fmt_in.video.i_visible_width;
2312 p_sys->i_crop_height = p_filter->fmt_in.video.i_visible_height;
2314 CreateMiniImage(p_filter, p_outpic);
2317 vlc_mutex_unlock( &p_sys->filter_lock );
2320 return CopyInfoAndRelease( p_outpic, p_pic );
2324 /*****************************************************************************
2325 * FadeToColorThread: Threadmethod which changes slowly the color
2326 * to a target color defined in p_fadethread struct
2327 * use for: Fade to Pause Color, and Fade to End Color
2328 *****************************************************************************/
2329 static void *FadeToColorThread(vlc_object_t *obj)
2331 fadethread_t *p_fadethread = (fadethread_t *)obj;
2332 filter_sys_t *p_sys = (filter_sys_t *)p_fadethread->p_filter->p_sys;
2333 int i_steps_done = 0;
2343 uint8_t *p_source = NULL;
2345 int canc = vlc_savecancel ();
2346 /* initialize AtmoWin for this thread! */
2347 AtmoInitialize(p_fadethread->p_filter , true);
2349 uint8_t *p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
2350 if(p_transfer != NULL) {
2351 /* safe colors as "32bit" Integers to avoid overflows*/
2352 i_pause_red = p_fadethread->ui_red;
2353 i_pause_blue = p_fadethread->ui_blue;
2354 i_pause_green = p_fadethread->ui_green;
2357 allocate a temporary buffer for the last send
2358 image size less then 15kb
2360 int i_size = 4 * p_sys->i_atmo_width * p_sys->i_atmo_height;
2361 p_source = (uint8_t *)malloc( i_size );
2362 if(p_source != NULL)
2365 get a copy of the last transfered image as orign for the
2368 memcpy(p_source, p_transfer, i_size);
2369 /* send the same pixel data again... to unlock the buffer! */
2370 AtmoSendPixelData( p_fadethread->p_filter );
2372 while( (vlc_object_alive (p_fadethread)) &&
2373 (i_steps_done < p_fadethread->i_steps))
2375 p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
2376 if(!p_transfer) break; /* should not happen if it worked
2377 one time in the code above! */
2380 move all pixels in the mini image (64x48) one step closer to
2381 the desired color these loop takes the most time of this
2382 thread improvements wellcome!
2385 (i_index < i_size) && (vlc_object_alive (p_fadethread));
2388 i_src_blue = p_source[i_index+0];
2389 i_src_green = p_source[i_index+1];
2390 i_src_red = p_source[i_index+2];
2391 p_transfer[i_index+0] = (uint8_t) (((
2392 (i_pause_blue - i_src_blue)
2393 * i_steps_done)/p_fadethread->i_steps)
2396 p_transfer[i_index+1] = (uint8_t) (((
2397 (i_pause_green - i_src_green)
2398 * i_steps_done)/p_fadethread->i_steps)
2401 p_transfer[i_index+2] = (uint8_t) (((
2402 (i_pause_red - i_src_red)
2403 * i_steps_done)/p_fadethread->i_steps)
2407 /* send image to lightcontroller */
2408 AtmoSendPixelData( p_fadethread->p_filter );
2409 /* is there something like and interruptable sleep inside
2410 the VLC libaries? inside native win32 I would use an Event
2411 (CreateEvent) and here an WaitForSingleObject?
2417 /* in failure of malloc also unlock buffer */
2418 AtmoSendPixelData(p_fadethread->p_filter);
2421 /* call indirect to OleUnitialize() for this thread */
2422 AtmoFinalize(p_fadethread->p_filter, 0);
2423 vlc_restorecancel (canc);
2427 /*****************************************************************************
2428 * CheckAndStopFadeThread: if there is a fadethread structure left, or running.
2429 ******************************************************************************
2430 * this function will stop the thread ... and waits for its termination
2431 * before removeing the objects from vout_sys_t ...
2432 ******************************************************************************/
2433 static void CheckAndStopFadeThread(filter_t *p_filter)
2435 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2436 vlc_mutex_lock( &p_sys->filter_lock );
2437 if(p_sys->p_fadethread != NULL)
2439 msg_Dbg(p_filter, "kill still running fadeing thread...");
2441 p_sys->p_fadethread->b_die = true;
2443 vlc_thread_join(p_sys->p_fadethread);
2445 vlc_object_release(p_sys->p_fadethread);
2446 p_sys->p_fadethread = NULL;
2448 vlc_mutex_unlock( &p_sys->filter_lock );
2451 /*****************************************************************************
2452 * StateCallback: Callback for the inputs variable "State" to get notified
2453 * about Pause and Continue Playback events.
2454 *****************************************************************************/
2455 static int StateCallback( vlc_object_t *p_this, char const *psz_cmd,
2456 vlc_value_t oldval, vlc_value_t newval,
2459 filter_t *p_filter = (filter_t *)p_data;
2460 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2462 if((p_sys->b_usepausecolor == true) && (p_sys->b_enabled == true))
2464 msg_Dbg(p_filter, "state change from: %"PRId64" to %"PRId64, oldval.i_int,
2467 if((newval.i_int == PAUSE_S) && (oldval.i_int == PLAYING_S))
2469 /* tell the other thread to stop sending images to light
2471 p_sys->b_pause_live = true;
2473 // clean up old thread - should not happen....
2474 CheckAndStopFadeThread( p_filter );
2476 // perpare spawn fadeing thread
2477 vlc_mutex_lock( &p_sys->filter_lock );
2479 launch only a new thread if there is none active!
2480 or waiting for cleanup
2482 if(p_sys->p_fadethread == NULL)
2484 p_sys->p_fadethread = (fadethread_t *)vlc_object_create(
2486 sizeof(fadethread_t) );
2488 p_sys->p_fadethread->p_filter = p_filter;
2489 p_sys->p_fadethread->ui_red = p_sys->ui_pausecolor_red;
2490 p_sys->p_fadethread->ui_green = p_sys->ui_pausecolor_green;
2491 p_sys->p_fadethread->ui_blue = p_sys->ui_pausecolor_blue;
2492 p_sys->p_fadethread->i_steps = p_sys->i_fadesteps;
2494 if( vlc_thread_create( p_sys->p_fadethread,
2495 "AtmoLight fadeing",
2497 VLC_THREAD_PRIORITY_LOW ) )
2499 msg_Err( p_filter, "cannot create FadeToColorThread" );
2500 vlc_object_release( p_sys->p_fadethread );
2501 p_sys->p_fadethread = NULL;
2504 vlc_mutex_unlock( &p_sys->filter_lock );
2507 if((newval.i_int == PLAYING_S) && (oldval.i_int == PAUSE_S))
2509 /* playback continues check thread state */
2510 CheckAndStopFadeThread( p_filter );
2511 /* reactivate the Render function... to do its normal work */
2512 p_sys->b_pause_live = false;
2519 /*****************************************************************************
2520 * AddPlaylistInputThreadStateCallback: Setup call back on "State" Variable
2521 *****************************************************************************
2522 * Add Callback function to the "state" variable of the input thread..
2523 * first find the PlayList and get the input thread from there to attach
2525 *****************************************************************************/
2526 static void AddStateVariableCallback(filter_t *p_filter)
2528 input_thread_t *p_input = playlist_CurrentInput( pl_Get( p_filter ) );
2531 var_AddCallback( p_input, "state", StateCallback, p_filter );
2532 vlc_object_release( p_input );
2536 /*****************************************************************************
2537 * DelPlaylistInputThreadStateCallback: Remove call back on "State" Variable
2538 *****************************************************************************
2539 * Delete the callback function to the "state" variable of the input thread...
2540 * first find the PlayList and get the input thread from there to attach
2541 * my callback? is vlc_object_find the right way for this??
2542 *****************************************************************************/
2543 static void DelStateVariableCallback( filter_t *p_filter )
2545 input_thread_t *p_input = playlist_CurrentInput( pl_Get ( p_filter ) );
2548 var_DelCallback( p_input, "state", StateCallback, p_filter );
2549 vlc_object_release( p_input );
2553 /****************************************************************************
2554 * StateCallback: Callback for the inputs variable "State" to get notified
2555 * about Pause and Continue Playback events.
2556 *****************************************************************************/
2557 static int AtmoSettingsCallback( vlc_object_t *p_this, char const *psz_var,
2558 vlc_value_t oldval, vlc_value_t newval,
2561 filter_t *p_filter = (filter_t *)p_data;
2562 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2564 vlc_mutex_lock( &p_sys->filter_lock );
2566 if( !strcmp( psz_var, CFG_PREFIX "showdots" ))
2568 p_sys->b_show_dots = newval.b_bool;
2571 CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
2575 msg_Dbg(p_filter, "apply AtmoSettingsCallback %s (int: %"PRId64" -> %"PRId64")",
2581 if( !strcmp( psz_var, CFG_PREFIX "filtermode" ))
2582 p_atmo_config->setLiveViewFilterMode( (AtmoFilterMode)newval.i_int);
2584 else if( !strcmp( psz_var, CFG_PREFIX "percentnew" ))
2585 p_atmo_config->setLiveViewFilter_PercentNew( newval.i_int );
2587 else if( !strcmp( psz_var, CFG_PREFIX "meanlength" ))
2588 p_atmo_config->setLiveViewFilter_MeanLength( newval.i_int );
2590 else if( !strcmp( psz_var, CFG_PREFIX "meanthreshold" ))
2591 p_atmo_config->setLiveViewFilter_MeanThreshold( newval.i_int );
2593 else if( !strcmp( psz_var, CFG_PREFIX "edgeweightning" ))
2594 p_atmo_config->setLiveView_EdgeWeighting( newval.i_int );
2596 else if( !strcmp( psz_var, CFG_PREFIX "brightness" ))
2597 p_atmo_config->setLiveView_BrightCorrect( newval.i_int );
2599 else if( !strcmp( psz_var, CFG_PREFIX "darknesslimit" ))
2600 p_atmo_config->setLiveView_DarknessLimit( newval.i_int );
2602 else if( !strcmp( psz_var, CFG_PREFIX "huewinsize" ))
2603 p_atmo_config->setLiveView_HueWinSize( newval.i_int );
2605 else if( !strcmp( psz_var, CFG_PREFIX "satwinsize" ))
2606 p_atmo_config->setLiveView_SatWinSize( newval.i_int );
2608 else if( !strcmp( psz_var, CFG_PREFIX "framedelay" ))
2609 p_atmo_config->setLiveView_FrameDelay( newval.i_int );
2611 else if( !strcmp( psz_var, CFG_PREFIX "whiteadj" ))
2612 p_atmo_config->setUseSoftwareWhiteAdj( newval.b_bool );
2614 else if( !strcmp( psz_var, CFG_PREFIX "white-red" ))
2615 p_atmo_config->setWhiteAdjustment_Red( newval.i_int );
2617 else if( !strcmp( psz_var, CFG_PREFIX "white-green" ))
2618 p_atmo_config->setWhiteAdjustment_Green( newval.i_int );
2620 else if( !strcmp( psz_var, CFG_PREFIX "white-blue" ))
2621 p_atmo_config->setWhiteAdjustment_Blue( newval.i_int );
2625 vlc_mutex_unlock( &p_sys->filter_lock );
2630 static void AddAtmoSettingsVariablesCallbacks(filter_t *p_filter)
2632 var_AddCallback( p_filter, CFG_PREFIX "filtermode",
2633 AtmoSettingsCallback, p_filter );
2634 var_AddCallback( p_filter, CFG_PREFIX "percentnew",
2635 AtmoSettingsCallback, p_filter );
2638 var_AddCallback( p_filter, CFG_PREFIX "meanlength",
2639 AtmoSettingsCallback, p_filter );
2640 var_AddCallback( p_filter, CFG_PREFIX "meanthreshold",
2641 AtmoSettingsCallback, p_filter );
2643 var_AddCallback( p_filter, CFG_PREFIX "edgeweightning",
2644 AtmoSettingsCallback, p_filter );
2645 var_AddCallback( p_filter, CFG_PREFIX "brightness",
2646 AtmoSettingsCallback, p_filter );
2647 var_AddCallback( p_filter, CFG_PREFIX "darknesslimit",
2648 AtmoSettingsCallback, p_filter );
2650 var_AddCallback( p_filter, CFG_PREFIX "huewinsize",
2651 AtmoSettingsCallback, p_filter );
2652 var_AddCallback( p_filter, CFG_PREFIX "satwinsize",
2653 AtmoSettingsCallback, p_filter );
2654 var_AddCallback( p_filter, CFG_PREFIX "framedelay",
2655 AtmoSettingsCallback, p_filter );
2658 var_AddCallback( p_filter, CFG_PREFIX "whiteadj",
2659 AtmoSettingsCallback, p_filter );
2660 var_AddCallback( p_filter, CFG_PREFIX "white-red",
2661 AtmoSettingsCallback, p_filter );
2662 var_AddCallback( p_filter, CFG_PREFIX "white-green",
2663 AtmoSettingsCallback, p_filter );
2664 var_AddCallback( p_filter, CFG_PREFIX "white-blue",
2665 AtmoSettingsCallback, p_filter );
2667 var_AddCallback( p_filter, CFG_PREFIX "showdots",
2668 AtmoSettingsCallback, p_filter );
2672 static void DelAtmoSettingsVariablesCallbacks( filter_t *p_filter )
2675 var_DelCallback( p_filter, CFG_PREFIX "filtermode",
2676 AtmoSettingsCallback, p_filter );
2678 var_DelCallback( p_filter, CFG_PREFIX "percentnew",
2679 AtmoSettingsCallback, p_filter );
2680 var_DelCallback( p_filter, CFG_PREFIX "meanlength",
2681 AtmoSettingsCallback, p_filter );
2682 var_DelCallback( p_filter, CFG_PREFIX "meanthreshold",
2683 AtmoSettingsCallback, p_filter );
2685 var_DelCallback( p_filter, CFG_PREFIX "edgeweightning",
2686 AtmoSettingsCallback, p_filter );
2687 var_DelCallback( p_filter, CFG_PREFIX "brightness",
2688 AtmoSettingsCallback, p_filter );
2689 var_DelCallback( p_filter, CFG_PREFIX "darknesslimit",
2690 AtmoSettingsCallback, p_filter );
2692 var_DelCallback( p_filter, CFG_PREFIX "huewinsize",
2693 AtmoSettingsCallback, p_filter );
2694 var_DelCallback( p_filter, CFG_PREFIX "satwinsize",
2695 AtmoSettingsCallback, p_filter );
2696 var_DelCallback( p_filter, CFG_PREFIX "framedelay",
2697 AtmoSettingsCallback, p_filter );
2700 var_DelCallback( p_filter, CFG_PREFIX "whiteadj",
2701 AtmoSettingsCallback, p_filter );
2702 var_DelCallback( p_filter, CFG_PREFIX "white-red",
2703 AtmoSettingsCallback, p_filter );
2704 var_DelCallback( p_filter, CFG_PREFIX "white-green",
2705 AtmoSettingsCallback, p_filter );
2706 var_DelCallback( p_filter, CFG_PREFIX "white-blue",
2707 AtmoSettingsCallback, p_filter );
2709 var_DelCallback( p_filter, CFG_PREFIX "showdots",
2710 AtmoSettingsCallback, p_filter );
2715 #if defined(__ATMO_DEBUG__)
2716 static void atmo_parse_crop(char *psz_cropconfig,
2717 video_format_t fmt_in,
2718 video_format_t fmt_render,
2719 int &i_visible_width, int &i_visible_height,
2720 int &i_x_offset, int &i_y_offset )
2722 int64_t i_aspect_num, i_aspect_den;
2723 unsigned int i_width, i_height;
2725 i_visible_width = fmt_in.i_visible_width;
2726 i_visible_height = fmt_in.i_visible_height;
2727 i_x_offset = fmt_in.i_x_offset;
2728 i_y_offset = fmt_in.i_y_offset;
2730 char *psz_end = NULL, *psz_parser = strchr( psz_cropconfig, ':' );
2733 /* We're using the 3:4 syntax */
2734 i_aspect_num = strtol( psz_cropconfig, &psz_end, 10 );
2735 if( psz_end == psz_cropconfig || !i_aspect_num ) return;
2737 i_aspect_den = strtol( ++psz_parser, &psz_end, 10 );
2738 if( psz_end == psz_parser || !i_aspect_den ) return;
2740 i_width = fmt_in.i_sar_den * fmt_render.i_visible_height *
2741 i_aspect_num / i_aspect_den / fmt_in.i_sar_num;
2743 i_height = fmt_render.i_visible_width*fmt_in.i_sar_num *
2744 i_aspect_den / i_aspect_num / fmt_in.i_sar_den;
2746 if( i_width < fmt_render.i_visible_width )
2748 i_x_offset = fmt_render.i_x_offset +
2749 (fmt_render.i_visible_width - i_width) / 2;
2750 i_visible_width = i_width;
2754 i_y_offset = fmt_render.i_y_offset +
2755 (fmt_render.i_visible_height - i_height) / 2;
2756 i_visible_height = i_height;
2761 psz_parser = strchr( psz_cropconfig, 'x' );
2764 /* Maybe we're using the <width>x<height>+<left>+<top> syntax */
2765 unsigned int i_crop_width, i_crop_height, i_crop_top, i_crop_left;
2767 i_crop_width = strtol( psz_cropconfig, &psz_end, 10 );
2768 if( psz_end != psz_parser ) return;
2770 psz_parser = strchr( ++psz_end, '+' );
2771 i_crop_height = strtol( psz_end, &psz_end, 10 );
2772 if( psz_end != psz_parser ) return;
2774 psz_parser = strchr( ++psz_end, '+' );
2775 i_crop_left = strtol( psz_end, &psz_end, 10 );
2776 if( psz_end != psz_parser ) return;
2779 i_crop_top = strtol( psz_end, &psz_end, 10 );
2780 if( *psz_end != '\0' ) return;
2782 i_width = i_crop_width;
2783 i_visible_width = i_width;
2785 i_height = i_crop_height;
2786 i_visible_height = i_height;
2788 i_x_offset = i_crop_left;
2789 i_y_offset = i_crop_top;
2793 /* Maybe we're using the <left>+<top>+<right>+<bottom> syntax */
2794 unsigned int i_crop_top, i_crop_left, i_crop_bottom, i_crop_right;
2796 psz_parser = strchr( psz_cropconfig, '+' );
2797 i_crop_left = strtol( psz_cropconfig, &psz_end, 10 );
2798 if( psz_end != psz_parser ) return;
2800 psz_parser = strchr( ++psz_end, '+' );
2801 i_crop_top = strtol( psz_end, &psz_end, 10 );
2802 if( psz_end != psz_parser ) return;
2804 psz_parser = strchr( ++psz_end, '+' );
2805 i_crop_right = strtol( psz_end, &psz_end, 10 );
2806 if( psz_end != psz_parser ) return;
2809 i_crop_bottom = strtol( psz_end, &psz_end, 10 );
2810 if( *psz_end != '\0' ) return;
2812 i_width = fmt_render.i_visible_width -
2815 i_visible_width = i_width;
2817 i_height = fmt_render.i_visible_height -
2820 i_visible_height = i_height;
2822 i_x_offset = i_crop_left;
2823 i_y_offset = i_crop_top;