1 /*****************************************************************************
2 * atmo.cpp : "Atmo Light" video filter
3 *****************************************************************************
4 * Copyright (C) 2000-2006 the VideoLAN team
7 * Authors: André Weber (WeberAndre@gmx.de)
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <stdlib.h> /* malloc(), free() */
29 #include <math.h> /* sin(), cos() */
36 // #define __ATMO_DEBUG__
39 #include <vlc_common.h>
40 #include <vlc_plugin.h>
43 #include <vlc_playlist.h>
44 #include <vlc_filter.h>
47 #include "AtmoDynData.h"
48 #include "AtmoLiveView.h"
49 #include "AtmoTools.h"
50 #include "AtmoExternalCaptureInput.h"
51 #include "AtmoConfig.h"
52 #include "AtmoConnection.h"
53 #include "AtmoClassicConnection.h"
56 /*****************************************************************************
58 *****************************************************************************/
59 /* directly to vlc related functions required that the module is accepted */
60 static int CreateFilter ( vlc_object_t * );
61 static void DestroyFilter ( vlc_object_t * );
62 static picture_t * Filter( filter_t *, picture_t *);
64 /* callback for global variable state pause / continue / stop events */
65 static void AddStateVariableCallback( filter_t *);
66 static void DelStateVariableCallback( filter_t *);
67 static int StateCallback(vlc_object_t *, char const *,
68 vlc_value_t, vlc_value_t, void *);
70 /* callback for variable crop-update */
71 static void AddCropVariableCallback( filter_t *);
72 static void DelCropVariableCallback( filter_t *);
73 static int CropCallback(vlc_object_t *, char const *,
74 vlc_value_t, vlc_value_t, void *);
76 /* callback for atmo settings variables whose change
77 should be immediately realized and applied to output
79 static void DelAtmoSettingsVariablesCallbacks(filter_t *);
80 static void AddAtmoSettingsVariablesCallbacks(filter_t *);
81 static int AtmoSettingsCallback(vlc_object_t *, char const *,
82 vlc_value_t, vlc_value_t, void *);
85 #if defined(__ATMO_DEBUG__)
86 static void atmo_parse_crop(char *psz_cropconfig,
87 video_format_t fmt_in,
88 video_format_t fmt_render,
90 int &i_visible_height,
96 /* function to shutdown the fade thread which is started on pause*/
97 static void CheckAndStopFadeThread(filter_t *);
99 /* extracts a small RGB (BGR) Image from an YUV image */
100 static void ExtractMiniImage_YUV(filter_sys_t *, picture_t *, uint8_t *);
102 #if defined(__ATMO_DEBUG__)
103 void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename);
106 /*****************************************************************************
107 * External Prototypes for the AtmoCtrlLib.DLL
108 *****************************************************************************/
110 * if effectmode = emLivePicture then the source could be GDI (Screencapture)
111 * or External - this means another application delivers Pixeldata to AtmoWin
112 * Clientsoftware through AtmoCtrlLib.DLL and the COM Api
115 #define lvsExternal 1
117 #define CLASSIC_ATMO_NUM_ZONES 5
121 strings for settings menus and hints
123 #define MODULE_DESCRIPTION N_ ( \
124 "This module allows to control an so called AtmoLight device "\
125 "connected to your computer.\n"\
126 "AtmoLight is the homegrown version of what Philips calls AmbiLight.\n"\
127 "If you need further information feel free to visit us at\n\n"\
128 "http://www.vdr-wiki.de/wiki/index.php/Atmo-plugin\n"\
129 "http://www.vdr-wiki.de/wiki/index.php/AtmoWin\n\n"\
130 "You can find there detailed descriptions on how to build it for yourself "\
131 "and where to get the required parts.\n" \
132 "You can also have a look at pictures and some movies showing such a device " \
135 #define DRIVER_TEXT N_("Device type")
136 #define DRIVER_LONGTEXT N_("Choose your prefered hardware from " \
137 "the list, or choose AtmoWin Software " \
138 "to delegate processing to the external " \
139 "process - with more options")
141 static const int pi_device_type_values[] = {
143 0, /* use AtmoWinA.exe userspace driver */
145 1, /* AtmoLight classic */
146 2, /* Quattro AtmoLight */
148 4 /* MoMoLight device */
150 static const char *const ppsz_device_type_descriptions[] = {
152 N_("AtmoWin Software"),
154 N_("Classic AtmoLight"),
155 N_("Quattro AtmoLight"),
160 #define DMX_CHANNELS_TEXT N_("Count of AtmoLight channels")
161 #define DMX_CHANNELS_LONGTEXT N_("How many AtmoLight channels, should be " \
162 "emulated with that DMX device")
163 #define DMX_CHBASE_TEXT N_("DMX address for each channel")
164 #define DMX_CHBASE_LONGTEXT N_("Define here the DMX base address for each " \
165 "channel use , or ; to seperate the values")
167 #define MOMO_CHANNELS_TEXT N_("Count of channels")
168 #define MOMO_CHANNELS_LONGTEXT N_("Depending on your MoMoLight hardware " \
169 "choose 3 or 4 channels")
172 # define DEFAULT_DEVICE 0
174 # define DEFAULT_DEVICE 1
177 #if defined( __ATMO_DEBUG__ )
178 # define SAVEFRAMES_TEXT N_("Save Debug Frames")
179 # define SAVEFRAMES_LONGTEXT N_("Write every 128th miniframe to a folder.")
180 # define FRAMEPATH_TEXT N_("Debug Frame Folder")
181 # define FRAMEPATH_LONGTEXT N_("The path where the debugframes " \
185 #define WIDTH_TEXT N_("Extracted Image Width")
186 #define WIDTH_LONGTEXT N_("The width of the mini image for " \
187 "further processing (64 is default)")
189 #define HEIGHT_TEXT N_("Extracted Image Height")
190 #define HEIGHT_LONGTEXT N_("The height of the mini image for " \
191 "further processing (48 is default)")
193 #define SHOW_DOTS_TEXT N_("Mark analyzed pixels")
194 #define SHOW_DOTS_LONGTEXT N_("makes the sample grid visible on screen as "\
197 #define PCOLOR_TEXT N_("Color when paused")
198 #define PCOLOR_LONGTEXT N_("Set the color to show if the user " \
199 "pauses the video. (Have light to get " \
201 #define PCOLOR_RED_TEXT N_("Pause-Red")
202 #define PCOLOR_RED_LONGTEXT N_("Red component of the pause color")
203 #define PCOLOR_GREEN_TEXT N_("Pause-Green")
204 #define PCOLOR_GREEN_LONGTEXT N_("Green component of the pause color")
205 #define PCOLOR_BLUE_TEXT N_("Pause-Blue")
206 #define PCOLOR_BLUE_LONGTEXT N_("Blue component of the pause color")
207 #define FADESTEPS_TEXT N_("Pause-Fadesteps")
208 #define FADESTEPS_LONGTEXT N_("Number of steps to change current color " \
209 "to pause color (each step takes 40ms)")
211 #define ECOLOR_RED_TEXT N_("End-Red")
212 #define ECOLOR_RED_LONGTEXT N_("Red component of the shutdown color")
213 #define ECOLOR_GREEN_TEXT N_("End-Green")
214 #define ECOLOR_GREEN_LONGTEXT N_("Green component of the shutdown color")
215 #define ECOLOR_BLUE_TEXT N_("End-Blue")
216 #define ECOLOR_BLUE_LONGTEXT N_("Blue component of the shutdown color")
217 #define EFADESTEPS_TEXT N_("End-Fadesteps")
218 #define EFADESTEPS_LONGTEXT N_("Number of steps to change current color to " \
219 "end color for dimming up the light in cinema " \
220 "style... (each step takes 40ms)")
222 #define ZONE_TOP_TEXT N_("Number of zones on top")
223 #define ZONE_TOP_LONGTEXT N_("Number of zones on the top of the screen")
224 #define ZONE_BOTTOM_TEXT N_("Number of zones on bottom")
225 #define ZONE_BOTTOM_LONGTEXT N_("Number of zones on the bottom of the screen")
226 #define ZONE_LR_TEXT N_("Zones on left / right side")
227 #define ZONE_LR_LONGTEXT N_("left and right side having allways the " \
228 "same number of zones")
229 #define ZONE_SUMMARY_TEXT N_("Calculate a average zone")
230 #define ZONE_SUMMARY_LONGTEXT N_("it contains the average of all pixels " \
231 "in the sample image (only useful for " \
232 "single channel AtmoLight)")
235 #define USEWHITEADJ_TEXT N_("Use Software White adjust")
236 #define USEWHITEADJ_LONGTEXT N_("Should the buildin driver do a white " \
237 "adjust or your LED stripes? recommend.")
238 #define WHITE_RED_TEXT N_("White Red")
239 #define WHITE_RED_LONGTEXT N_("Red value of a pure white on your "\
241 #define WHITE_GREEN_TEXT N_("White Green")
242 #define WHITE_GREEN_LONGTEXT N_("Green value of a pure white on your "\
244 #define WHITE_BLUE_TEXT N_("White Blue")
245 #define WHITE_BLUE_LONGTEXT N_("Blue value of a pure white on your "\
248 #define SERIALDEV_TEXT N_("Serial Port/Device")
249 #define SERIALDEV_LONGTEXT N_("Name of the serial port where the AtmoLight "\
250 "controller is attached to.\n" \
251 "On Windows usually something like COM1 or " \
252 "COM2. On Linux /dev/ttyS01 f.e.")
254 #define EDGE_TEXT N_("Edge Weightning")
255 #define EDGE_LONGTEXT N_("Increasing this value will result in color "\
256 "more depending on the border of the frame.")
257 #define BRIGHTNESS_TEXT N_("Brightness")
258 #define BRIGHTNESS_LONGTEXT N_("Overall brightness of your LED stripes")
259 #define DARKNESS_TEXT N_("Darkness Limit")
260 #define DARKNESS_LONGTEXT N_("Pixels with a saturation lower than this will "\
261 "be ignored. Should be greater than one for "\
262 "letterboxed videos.")
263 #define HUEWINSIZE_TEXT N_("Hue windowing")
264 #define HUEWINSIZE_LONGTEXT N_("Used for statistics.")
265 #define SATWINSIZE_TEXT N_("Sat windowing")
266 #define SATWINSIZE_LONGTEXT N_("Used for statistics.")
268 #define MEANLENGTH_TEXT N_("Filter length (ms)")
269 #define MEANLENGTH_LONGTEXT N_("Time it takes until a color is completely "\
270 "changed. This prevents flickering.")
271 #define MEANTHRESHOLD_TEXT N_("Filter threshold")
272 #define MEANTHRESHOLD_LONGTEXT N_("How much a color has to be changed for an "\
273 "immediate color change.")
274 #define MEANPERCENTNEW_TEXT N_("Filter Smoothness (in %)")
275 #define MEANPERCENTNEW_LONGTEXT N_("Filter Smoothness")
277 #define FILTERMODE_TEXT N_("Output Color filter mode")
278 #define FILTERMODE_LONGTEXT N_("defines the how the output color should " \
279 "be calculated based on previous color")
281 static const int pi_filtermode_values[] = {
286 static const char *const ppsz_filtermode_descriptions[] = {
292 #define FRAMEDELAY_TEXT N_("Frame delay (ms)")
293 #define FRAMEDELAY_LONGTEXT N_("Helps to get the video output and the light "\
294 "effects in sync. Values around 20ms should " \
298 #define CHANNEL_0_ASSIGN_TEXT N_("Channel 0: summary")
299 #define CHANNEL_1_ASSIGN_TEXT N_("Channel 1: left")
300 #define CHANNEL_2_ASSIGN_TEXT N_("Channel 2: right")
301 #define CHANNEL_3_ASSIGN_TEXT N_("Channel 3: top")
302 #define CHANNEL_4_ASSIGN_TEXT N_("Channel 4: bottom")
304 #define CHANNELASSIGN_LONGTEXT N_("Maps the hardware channel X to logical "\
305 "zone Y to fix wrong wiring :-)")
306 static const int pi_zone_assignment_values[] = {
314 static const char *const ppsz_zone_assignment_descriptions[] = {
316 N_("Zone 4:summary"),
322 #define CHANNELS_ASSIGN_TEXT N_("Channel / Zone Assignment")
323 #define CHANNELS_ASSIGN_LONGTEXT N_("for devices with more than five " \
324 "channels / zones write down here for each channel " \
325 "the zone number to show and seperate the values with " \
326 ", or ; and use -1 to not use some channels. For the " \
327 "classic AtmoLight the sequence 4,3,1,0,2 would set the " \
328 "default channel/zone mapping. " \
329 "Having only two zones on top, and one zone on left and " \
330 "right and no summary zone the mapping for classic " \
331 "AtmoLight would be -1,3,2,1,0")
333 #define ZONE_0_GRADIENT_TEXT N_("Zone 0: Top gradient")
334 #define ZONE_1_GRADIENT_TEXT N_("Zone 1: Right gradient")
335 #define ZONE_2_GRADIENT_TEXT N_("Zone 2: Bottom gradient")
336 #define ZONE_3_GRADIENT_TEXT N_("Zone 3: Left gradient")
337 #define ZONE_4_GRADIENT_TEXT N_("Zone 4: Summary gradient")
338 #define ZONE_X_GRADIENT_LONG_TEXT N_("Defines a small bitmap with 64x48 "\
339 "pixels, containing a grayscale gradient")
341 #define GRADIENT_PATH_TEXT N_("Gradient bitmap searchpath")
342 #define GRADIENT_PATH_LONGTEXT N_("Now prefered option to assign gradient "\
343 "bitmaps, put them as zone_0.bmp, zone_1.bmp etc. into one folder and "\
344 "set the foldername here")
347 # define ATMOWINEXE_TEXT N_("Filename of AtmoWin*.exe")
348 # define ATMOWINEXE_LONGTEXT N_("if you want the AtmoLight control "\
349 "software to be launched by VLC, enter the "\
350 "complete path of AtmoWinA.exe here.")
353 #define CFG_PREFIX "atmo-"
355 /*****************************************************************************
357 *****************************************************************************/
359 set_description( N_("AtmoLight Filter") )
360 set_help( MODULE_DESCRIPTION )
361 set_shortname( N_( "AtmoLight" ))
362 set_category( CAT_VIDEO )
363 set_subcategory( SUBCAT_VIDEO_VFILTER )
365 set_capability( "video filter2", 0 )
368 set_section( N_("Choose Devicetype and Connection" ), 0 )
370 add_integer( CFG_PREFIX "device", DEFAULT_DEVICE, NULL,
371 DRIVER_TEXT, DRIVER_LONGTEXT, false )
372 change_integer_list( pi_device_type_values,
373 ppsz_device_type_descriptions, 0 )
376 add_string(CFG_PREFIX "serialdev", "COM1", NULL,
377 SERIALDEV_TEXT, SERIALDEV_LONGTEXT, false )
379 on win32 the executeable external driver application
380 for automatic start if needed
382 add_file(CFG_PREFIX "atmowinexe", NULL, NULL,
383 ATMOWINEXE_TEXT, ATMOWINEXE_LONGTEXT, false )
385 add_string(CFG_PREFIX "serialdev", "/dev/ttyS01", NULL,
386 SERIALDEV_TEXT, SERIALDEV_LONGTEXT, false )
390 color which is showed if you want durring pausing
391 your movie ... used for both buildin / external
393 set_section( N_("Illuminate the room with this color on pause" ), 0 )
394 add_bool(CFG_PREFIX "usepausecolor", false, NULL,
395 PCOLOR_TEXT, PCOLOR_LONGTEXT, false)
396 add_integer_with_range(CFG_PREFIX "pcolor-red", 0, 0, 255, NULL,
397 PCOLOR_RED_TEXT, PCOLOR_RED_LONGTEXT, false)
398 add_integer_with_range(CFG_PREFIX "pcolor-green", 0, 0, 255, NULL,
399 PCOLOR_GREEN_TEXT, PCOLOR_GREEN_LONGTEXT, false)
400 add_integer_with_range(CFG_PREFIX "pcolor-blue", 192, 0, 255, NULL,
401 PCOLOR_BLUE_TEXT, PCOLOR_BLUE_LONGTEXT, false)
402 add_integer_with_range(CFG_PREFIX "fadesteps", 50, 1, 250, NULL,
403 FADESTEPS_TEXT, FADESTEPS_LONGTEXT, false)
406 color which is showed if you finished watching your movie ...
407 used for both buildin / external
409 set_section( N_("Illuminate the room with this color on shutdown" ), 0 )
410 add_integer_with_range(CFG_PREFIX "ecolor-red", 192, 0, 255, NULL,
411 ECOLOR_RED_TEXT, ECOLOR_RED_LONGTEXT, false)
412 add_integer_with_range(CFG_PREFIX "ecolor-green", 192, 0, 255, NULL,
413 ECOLOR_GREEN_TEXT, ECOLOR_GREEN_LONGTEXT, false)
414 add_integer_with_range(CFG_PREFIX "ecolor-blue", 192, 0, 255, NULL,
415 ECOLOR_BLUE_TEXT, ECOLOR_BLUE_LONGTEXT, false)
416 add_integer_with_range(CFG_PREFIX "efadesteps", 50, 1, 250, NULL,
417 EFADESTEPS_TEXT, EFADESTEPS_LONGTEXT, false)
420 set_section( N_("DMX options" ), 0 )
421 add_integer_with_range(CFG_PREFIX "dmx-channels", 5, 1, 64, NULL,
422 DMX_CHANNELS_TEXT, DMX_CHANNELS_LONGTEXT, false)
423 add_string(CFG_PREFIX "dmx-chbase", "0,3,6,9,12", NULL,
424 DMX_CHBASE_TEXT, DMX_CHBASE_LONGTEXT, false )
426 set_section( N_("MoMoLight options" ), 0 )
427 add_integer_with_range(CFG_PREFIX "momo-channels", 3, 3, 4, NULL,
428 MOMO_CHANNELS_TEXT, MOMO_CHANNELS_LONGTEXT, false)
433 instead of redefining the original AtmoLight zones with gradient
434 bitmaps, we can now define the layout of the zones useing these
435 parameters - the function with the gradient bitmaps would still
436 work (but for most cases its no longer required)
438 short description whats this means - f.e. the classic atmo would
440 zones-top = 1 - zone 0
441 zones-lr = 1 - zone 1 und zone 3
442 zones-bottom = 1 - zone 2
443 zone-summary = true - zone 4
451 the zone numbers will be counted clockwise starting at top / left
452 if you want to split the light at the top, without having a bottom zone
453 (which is my private config)
455 zones-top = 2 - zone 0, zone 1
456 zones-lr = 1 - zone 2 und zone 3
468 set_section( N_("Zone Layout for the build-in Atmo" ), 0 )
469 add_integer_with_range(CFG_PREFIX "zones-top", 1, 0, 16, NULL,
470 ZONE_TOP_TEXT, ZONE_TOP_LONGTEXT, false)
471 add_integer_with_range(CFG_PREFIX "zones-bottom", 1, 0, 16, NULL,
472 ZONE_BOTTOM_TEXT, ZONE_BOTTOM_LONGTEXT, false)
473 add_integer_with_range(CFG_PREFIX "zones-lr", 1, 0, 16, NULL,
474 ZONE_LR_TEXT, ZONE_LR_LONGTEXT, false)
475 add_bool(CFG_PREFIX "zone-summary", false, NULL,
476 ZONE_SUMMARY_TEXT, ZONE_SUMMARY_LONGTEXT, false)
479 settings only for the buildin driver (if external driver app is used
480 these parameters are ignored.)
482 definition of parameters for the buildin filter ...
484 set_section( N_("Settings for the built-in Live Video Processor only" ), 0 )
486 add_integer_with_range(CFG_PREFIX "edgeweightning", 3, 1, 30, NULL,
487 EDGE_TEXT, EDGE_LONGTEXT, false)
489 add_integer_with_range(CFG_PREFIX "brightness", 100, 50, 300, NULL,
490 BRIGHTNESS_TEXT, BRIGHTNESS_LONGTEXT, false)
492 add_integer_with_range(CFG_PREFIX "darknesslimit", 3, 0, 10, NULL,
493 DARKNESS_TEXT, DARKNESS_LONGTEXT, false)
495 add_integer_with_range(CFG_PREFIX "huewinsize", 3, 0, 5, NULL,
496 HUEWINSIZE_TEXT, HUEWINSIZE_LONGTEXT, false)
498 add_integer_with_range(CFG_PREFIX "satwinsize", 3, 0, 5, NULL,
499 SATWINSIZE_TEXT, SATWINSIZE_LONGTEXT, false)
501 add_integer(CFG_PREFIX "filtermode", (int)afmCombined, NULL,
502 FILTERMODE_TEXT, FILTERMODE_LONGTEXT, false )
504 change_integer_list(pi_filtermode_values, ppsz_filtermode_descriptions, NULL )
506 add_integer_with_range(CFG_PREFIX "meanlength", 300, 300, 5000, NULL,
507 MEANLENGTH_TEXT, MEANLENGTH_LONGTEXT, false)
509 add_integer_with_range(CFG_PREFIX "meanthreshold", 40, 1, 100, NULL,
510 MEANTHRESHOLD_TEXT, MEANTHRESHOLD_LONGTEXT, false)
512 add_integer_with_range(CFG_PREFIX "percentnew", 50, 1, 100, NULL,
513 MEANPERCENTNEW_TEXT, MEANPERCENTNEW_LONGTEXT, false)
515 add_integer_with_range(CFG_PREFIX "framedelay", 18, 0, 200, NULL,
516 FRAMEDELAY_TEXT, FRAMEDELAY_LONGTEXT, false)
519 output channel reordering
521 set_section( N_("Change channel assignment (fixes wrong wiring)" ), 0 )
522 add_integer( CFG_PREFIX "channel_0", 4, NULL,
523 CHANNEL_0_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
524 change_integer_list( pi_zone_assignment_values,
525 ppsz_zone_assignment_descriptions, 0 )
527 add_integer( CFG_PREFIX "channel_1", 3, NULL,
528 CHANNEL_1_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
529 change_integer_list( pi_zone_assignment_values,
530 ppsz_zone_assignment_descriptions, 0 )
532 add_integer( CFG_PREFIX "channel_2", 1, NULL,
533 CHANNEL_2_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
534 change_integer_list( pi_zone_assignment_values,
535 ppsz_zone_assignment_descriptions, 0 )
537 add_integer( CFG_PREFIX "channel_3", 0, NULL,
538 CHANNEL_3_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
539 change_integer_list( pi_zone_assignment_values,
540 ppsz_zone_assignment_descriptions, 0 )
542 add_integer( CFG_PREFIX "channel_4", 2, NULL,
543 CHANNEL_4_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
544 change_integer_list( pi_zone_assignment_values,
545 ppsz_zone_assignment_descriptions, 0 )
547 add_string(CFG_PREFIX "channels", NULL, NULL,
548 CHANNELS_ASSIGN_TEXT, CHANNELS_ASSIGN_LONGTEXT, false )
552 LED color white calibration
554 set_section( N_("Adjust the white light to your LED stripes" ), 0 )
555 add_bool(CFG_PREFIX "whiteadj", true, NULL,
556 USEWHITEADJ_TEXT, USEWHITEADJ_LONGTEXT, false)
557 add_integer_with_range(CFG_PREFIX "white-red", 255, 0, 255, NULL,
558 WHITE_RED_TEXT, WHITE_RED_LONGTEXT, false)
560 add_integer_with_range(CFG_PREFIX "white-green", 255, 0, 255, NULL,
561 WHITE_GREEN_TEXT, WHITE_GREEN_LONGTEXT, false)
563 add_integer_with_range(CFG_PREFIX "white-blue", 255, 0, 255, NULL,
564 WHITE_BLUE_TEXT, WHITE_BLUE_LONGTEXT, false)
565 /* end of definition of parameter for the buildin filter ... part 1 */
569 only for buildin (external has own definition) per default the calucation
570 used linear gradients for assigning a priority to the pixel - depending
571 how near they are to the border ...for changing this you can create 64x48
572 Pixel BMP files - which contain your own grayscale... (you can produce funny
573 effects with this...) the images MUST not compressed, should have 24-bit per
574 pixel, or a simple 256 color grayscale palette
576 set_section( N_("Change gradients" ), 0 )
577 add_file(CFG_PREFIX "gradient_zone_0", NULL, NULL,
578 ZONE_0_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
579 add_file(CFG_PREFIX "gradient_zone_1", NULL, NULL,
580 ZONE_1_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
581 add_file(CFG_PREFIX "gradient_zone_2", NULL, NULL,
582 ZONE_2_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
583 add_file(CFG_PREFIX "gradient_zone_3", NULL, NULL,
584 ZONE_3_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
585 add_file(CFG_PREFIX "gradient_zone_4", NULL, NULL,
586 ZONE_4_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
587 add_directory(CFG_PREFIX "gradient_path", NULL, NULL,
588 GRADIENT_PATH_TEXT, GRADIENT_PATH_LONGTEXT, false )
590 #if defined(__ATMO_DEBUG__)
591 add_bool(CFG_PREFIX "saveframes", false, NULL,
592 SAVEFRAMES_TEXT, SAVEFRAMES_LONGTEXT, false)
593 add_string(CFG_PREFIX "framepath", "", NULL,
594 FRAMEPATH_TEXT, FRAMEPATH_LONGTEXT, false )
597 may be later if computers gets more power ;-) than now we increase
598 the samplesize from which we do the stats for output color calculation
600 add_integer_with_range(CFG_PREFIX "width", 64, 64, 512, NULL,
601 WIDTH_TEXT, WIDTH_LONGTEXT, true)
602 add_integer_with_range(CFG_PREFIX "height", 48, 48, 384, NULL,
603 HEIGHT_TEXT, HEIGHT_LONGTEXT, true)
604 add_bool(CFG_PREFIX "showdots", false, NULL,
605 SHOW_DOTS_TEXT, SHOW_DOTS_LONGTEXT, false)
606 add_shortcut( "atmo" )
607 set_callbacks( CreateFilter, DestroyFilter )
611 static const char *const ppsz_filter_options[] = {
665 #if defined(__ATMO_DEBUG__)
682 /*****************************************************************************
683 * fadethread_t: Color Fading Thread
684 *****************************************************************************
685 * changes slowly the color of the output if videostream gets paused...
686 *****************************************************************************
692 /* tell the thread which color should be the target of fading */
696 /* how many steps should happen until this */
701 static void *FadeToColorThread(vlc_object_t *);
704 /*****************************************************************************
705 * filter_sys_t: AtmoLight filter method descriptor
706 *****************************************************************************
707 * It describes the AtmoLight specific properties of an video filter.
708 *****************************************************************************/
712 special for the access of the p_fadethread member all other members
713 need no special protection so far!
715 vlc_mutex_t filter_lock;
718 int32_t i_AtmoOldEffect;
721 int32_t i_device_type;
723 int32_t i_atmo_width;
724 int32_t i_atmo_height;
725 /* used to disable fadeout if less than 50 frames are processed
726 used to avoid long time waiting when switch quickly between
727 deinterlaceing modes, where the output filter chains is rebuild
730 int32_t i_frames_processed;
732 #if defined(__ATMO_DEBUG__)
734 uint32_t ui_frame_counter;
735 char sz_framepath[MAX_PATH];
738 /* light color durring movie pause ... */
739 bool b_usepausecolor;
740 uint8_t ui_pausecolor_red;
741 uint8_t ui_pausecolor_green;
742 uint8_t ui_pausecolor_blue;
745 /* light color on movie finish ... */
746 uint8_t ui_endcolor_red;
747 uint8_t ui_endcolor_green;
748 uint8_t ui_endcolor_blue;
751 fadethread_t *p_fadethread;
753 /* Variables for buildin driver only... */
755 /* is only present and initialized if the internal driver is used*/
756 CAtmoConfig *p_atmo_config;
757 /* storage for temporal settings "volatile" */
758 CAtmoDynData *p_atmo_dyndata;
759 /* initialized for buildin driver with AtmoCreateTransferBuffers */
760 BITMAPINFOHEADER mini_image_format;
761 /* is only use buildin driver! */
762 uint8_t *p_atmo_transfer_buffer;
763 /* end buildin driver */
766 contains the real output size of the video calculated on
767 change event of the variable "crop" from vout
769 int32_t i_crop_x_offset;
770 int32_t i_crop_y_offset;
771 int32_t i_crop_width;
772 int32_t i_crop_height;
774 void (*pf_extract_mini_image) (filter_sys_t *p_sys,
776 uint8_t *p_transfer_dest);
779 /* External Library as wrapper arround COM Stuff */
780 HINSTANCE h_AtmoCtrl;
781 int32_t (*pf_ctrl_atmo_initialize) (void);
782 void (*pf_ctrl_atmo_finalize) (int32_t what);
783 int32_t (*pf_ctrl_atmo_switch_effect) (int32_t);
784 int32_t (*pf_ctrl_atmo_set_live_source) (int32_t);
785 void (*pf_ctrl_atmo_create_transfer_buffers) (int32_t, int32_t,
787 uint8_t* (*pf_ctrl_atmo_lock_transfer_buffer) (void);
788 void (*pf_ctrl_atmo_send_pixel_data) (void);
789 void (*pf_ctrl_atmo_get_image_size)(int32_t *,int32_t *);
794 initialize previously configured Atmo Light environment
795 - if internal is enabled try to access the device on the serial port
796 - if not internal is enabled and we are on win32 try to initialize
797 the previously loaded DLL ...
799 Return Values may be: -1 (failed for some reason - filter will be disabled)
802 static int32_t AtmoInitialize(filter_t *p_filter, bool b_for_thread)
804 filter_sys_t *p_sys = p_filter->p_sys;
805 if(p_sys->p_atmo_config)
807 if(b_for_thread == false)
810 /* setup Output Threads ... */
811 msg_Dbg( p_filter, "open atmo device...");
812 if(CAtmoTools::RecreateConnection(p_sys->p_atmo_dyndata)
817 msg_Err( p_filter,"failed to open atmo device, "\
818 "some other software/driver may use it?");
822 } else if(p_sys->pf_ctrl_atmo_initialize)
824 /* on win32 with active ctrl dll */
825 return p_sys->pf_ctrl_atmo_initialize();
832 prepare the shutdown of the effect threads,
833 for build in filter - close the serialport after finishing the threads...
834 cleanup possible loaded DLL...
836 static void AtmoFinalize(filter_t *p_filter, int32_t what)
838 filter_sys_t *p_sys = p_filter->p_sys;
839 if(p_sys->p_atmo_config)
843 CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
846 p_atmo_dyndata->LockCriticalSection();
848 CAtmoInput *p_input = p_atmo_dyndata->getLiveInput();
849 p_atmo_dyndata->setLiveInput( NULL );
852 p_input->Terminate();
854 msg_Dbg( p_filter, "input thread died peacefully");
857 CThread *p_effect_thread = p_atmo_dyndata->getEffectThread();
858 p_atmo_dyndata->setEffectThread(NULL);
859 if(p_effect_thread != NULL)
862 forced the thread to die...
863 and wait for termination of the thread
865 p_effect_thread->Terminate();
866 delete p_effect_thread;
867 msg_Dbg( p_filter, "effect thread died peacefully");
870 CAtmoPacketQueue *p_queue =
871 p_atmo_dyndata->getLivePacketQueue();
872 p_atmo_dyndata->setLivePacketQueue( NULL );
876 msg_Dbg( p_filter, "packetqueue removed");
880 close serial port if it is open (all OS specific is inside
881 CAtmoSerialConnection implemented / defined)
883 CAtmoConnection *p_atmo_connection =
884 p_atmo_dyndata->getAtmoConnection();
885 p_atmo_dyndata->setAtmoConnection(NULL);
886 if(p_atmo_connection) {
887 p_atmo_connection->CloseConnection();
888 delete p_atmo_connection;
890 p_atmo_dyndata->UnLockCriticalSection();
894 } else if(p_sys->pf_ctrl_atmo_finalize)
896 /* on win32 with active ctrl dll */
897 p_sys->pf_ctrl_atmo_finalize(what);
903 switch the current light effect to LiveView
905 static int32_t AtmoSwitchEffect(filter_t *p_filter, int32_t newMode)
907 filter_sys_t *p_sys = p_filter->p_sys;
909 msg_Dbg( p_filter, "AtmoSwitchEffect %d", newMode );
911 if(p_sys->p_atmo_config)
913 return CAtmoTools::SwitchEffect(p_sys->p_atmo_dyndata, emLivePicture);
915 } else if(p_sys->pf_ctrl_atmo_switch_effect)
917 /* on win32 with active ctrl dll */
918 return p_sys->pf_ctrl_atmo_switch_effect( newMode );
925 set the current live picture source, does only something on win32,
926 with the external libraries - if the buildin effects are used nothing
929 static int32_t AtmoSetLiveSource(filter_t *p_filter, int32_t newSource)
931 filter_sys_t *p_sys = p_filter->p_sys;
933 msg_Dbg( p_filter, "AtmoSetLiveSource %d", newSource );
935 if(p_sys->p_atmo_config)
940 doesnt know different sources so this
941 function call would just do nothing special
945 } else if(p_sys->pf_ctrl_atmo_set_live_source)
947 /* on win32 with active ctrl dll */
948 return p_sys->pf_ctrl_atmo_set_live_source(newSource);
955 setup the pixel transferbuffers which is used to transfer pixeldata from
956 the filter to the effect thread, and possible accross the process
957 boundaries on win32, with the external DLL
959 static void AtmoCreateTransferBuffers(filter_t *p_filter,
961 int32_t bytePerPixel,
965 filter_sys_t *p_sys = p_filter->p_sys;
966 if(p_sys->p_atmo_config)
969 we need a buffer where the image is stored (only for transfer
970 to the processing thread)
972 free( p_sys->p_atmo_transfer_buffer );
974 p_sys->p_atmo_transfer_buffer = (uint8_t *)malloc(bytePerPixel *
977 memset(&p_sys->mini_image_format,0,sizeof(BITMAPINFOHEADER));
979 p_sys->mini_image_format.biSize = sizeof(BITMAPINFOHEADER);
980 p_sys->mini_image_format.biWidth = width;
981 p_sys->mini_image_format.biHeight = height;
982 p_sys->mini_image_format.biBitCount = bytePerPixel*8;
983 p_sys->mini_image_format.biCompression = FourCC;
986 } else if(p_sys->pf_ctrl_atmo_create_transfer_buffers)
988 /* on win32 with active ctrl dll */
989 p_sys->pf_ctrl_atmo_create_transfer_buffers(FourCC,
998 acquire the transfer buffer pointer the buildin version only
999 returns the pointer to the allocated buffer ... the
1000 external version on win32 has to do some COM stuff to lock the
1001 Variant Byte array which is behind the buffer
1003 static uint8_t* AtmoLockTransferBuffer(filter_t *p_filter)
1005 filter_sys_t *p_sys = p_filter->p_sys;
1006 if(p_sys->p_atmo_config)
1008 return p_sys->p_atmo_transfer_buffer;
1010 } else if(p_sys->pf_ctrl_atmo_lock_transfer_buffer)
1012 /* on win32 with active ctrl dll */
1013 return p_sys->pf_ctrl_atmo_lock_transfer_buffer();
1020 send the content of current pixel buffer got with AtmoLockTransferBuffer
1021 to the processing threads
1022 - build in version - will forward the data to AtmoExternalCaptureInput Thread
1023 - win32 external - will do the same, but across the process boundaries via
1024 COM to the AtmoWinA.exe Process
1026 static void AtmoSendPixelData(filter_t *p_filter)
1028 filter_sys_t *p_sys = p_filter->p_sys;
1029 if(p_sys->p_atmo_config && p_sys->p_atmo_transfer_buffer)
1031 CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
1032 if(p_atmo_dyndata &&
1033 (p_atmo_dyndata->getLivePictureSource() == lpsExtern))
1036 the cast will go Ok because we are inside videolan there is only
1037 this kind of effect thread implemented!
1039 CAtmoExternalCaptureInput *p_atmo_external_capture_input_thread =
1040 (CAtmoExternalCaptureInput *)p_atmo_dyndata->getLiveInput();
1042 if(p_atmo_external_capture_input_thread)
1045 the same as above inside videolan only this single kind of
1046 input exists so we can cast without further tests!
1048 this call will do a 1:1 copy of this buffer, and wakeup
1049 the thread from normal sleeping
1051 p_atmo_external_capture_input_thread->
1052 DeliverNewSourceDataPaket(&p_sys->mini_image_format,
1053 p_sys->p_atmo_transfer_buffer);
1057 } else if(p_sys->pf_ctrl_atmo_send_pixel_data)
1059 /* on win32 with active ctrl dll */
1060 p_sys->pf_ctrl_atmo_send_pixel_data();
1064 msg_Warn( p_filter, "AtmoSendPixelData no method");
1069 Shutdown AtmoLight finally - is call from DestroyFilter
1070 does the cleanup restores the effectmode on the external Software
1071 (only win32) and possible setup the final light ...
1073 static void Atmo_Shutdown(filter_t *p_filter)
1075 filter_sys_t *p_sys = p_filter->p_sys;
1077 if(p_sys->b_enabled == true)
1079 msg_Dbg( p_filter, "shut down atmo!");
1081 if there is a still running show pause color thread kill him!
1083 CheckAndStopFadeThread(p_filter);
1085 // perpare spawn fadeing thread
1086 vlc_mutex_lock( &p_sys->filter_lock );
1089 fade to end color (in case of external AtmoWin Software
1090 assume that the static color will equal to this
1091 one to get a soft change and no flash!
1093 p_sys->b_pause_live = true;
1096 p_sys->p_fadethread = (fadethread_t *)vlc_object_create( p_filter,
1097 sizeof(fadethread_t) );
1099 p_sys->p_fadethread->p_filter = p_filter;
1100 p_sys->p_fadethread->ui_red = p_sys->ui_endcolor_red;
1101 p_sys->p_fadethread->ui_green = p_sys->ui_endcolor_green;
1102 p_sys->p_fadethread->ui_blue = p_sys->ui_endcolor_blue;
1103 if(p_sys->i_frames_processed < 50)
1104 p_sys->p_fadethread->i_steps = 1;
1106 p_sys->p_fadethread->i_steps = p_sys->i_endfadesteps;
1108 if( vlc_thread_create( p_sys->p_fadethread,
1109 "AtmoLight fadeing",
1111 VLC_THREAD_PRIORITY_LOW ) )
1113 msg_Err( p_filter, "cannot create FadeToColorThread" );
1114 vlc_object_release( p_sys->p_fadethread );
1115 p_sys->p_fadethread = NULL;
1116 vlc_mutex_unlock( &p_sys->filter_lock );
1120 vlc_mutex_unlock( &p_sys->filter_lock );
1122 /* wait for the thread... */
1123 vlc_thread_join(p_sys->p_fadethread);
1125 vlc_object_release(p_sys->p_fadethread);
1127 p_sys->p_fadethread = NULL;
1131 the following happens only useing the
1132 external AtmoWin Device Software
1134 if( !p_sys->p_atmo_config )
1136 if(p_sys->i_AtmoOldEffect != emLivePicture)
1137 AtmoSwitchEffect( p_filter, p_sys->i_AtmoOldEffect);
1139 AtmoSetLiveSource( p_filter, lvsGDI );
1142 /* close device connection etc. */
1143 AtmoFinalize(p_filter, 1);
1145 /* disable filter method .. */
1146 p_sys->b_enabled = false;
1151 depending on mode setup imagesize to 64x48(classic), or defined
1152 resolution of external atmowin.exe on windows
1154 static void Atmo_SetupImageSize(filter_t *p_filter)
1156 filter_sys_t *p_sys = p_filter->p_sys;
1158 size of extracted image by default 64x48 (other imagesizes are
1159 currently ignored by AtmoWin)
1161 p_sys->i_atmo_width = var_CreateGetIntegerCommand( p_filter,
1162 CFG_PREFIX "width");
1163 p_sys->i_atmo_height = var_CreateGetIntegerCommand( p_filter,
1164 CFG_PREFIX "height");
1166 if(p_sys->p_atmo_config)
1169 } else if(p_sys->pf_ctrl_atmo_get_image_size)
1171 /* on win32 with active ctrl dll */
1172 p_sys->pf_ctrl_atmo_get_image_size( &p_sys->i_atmo_width,
1173 &p_sys->i_atmo_height );
1177 msg_Dbg(p_filter,"sample image size %d * %d pixels", p_sys->i_atmo_width,
1178 p_sys->i_atmo_height);
1182 initialize the zone and channel mapping for the buildin atmolight adapter
1184 static void Atmo_SetupBuildZones(filter_t *p_filter)
1186 filter_sys_t *p_sys = p_filter->p_sys;
1188 p_sys->p_atmo_dyndata->LockCriticalSection();
1190 CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
1193 CAtmoChannelAssignment *p_channel_assignment =
1194 p_atmo_config->getChannelAssignment(0);
1196 // channel 0 - zone 4
1197 p_channel_assignment->setZoneIndex( 0, var_CreateGetIntegerCommand(
1198 p_filter, CFG_PREFIX "channel_0")
1201 // channel 1 - zone 3
1202 p_channel_assignment->setZoneIndex( 1, var_CreateGetIntegerCommand(
1203 p_filter, CFG_PREFIX "channel_1")
1206 // channel 2 - zone 1
1207 p_channel_assignment->setZoneIndex( 2, var_CreateGetIntegerCommand(
1208 p_filter, CFG_PREFIX "channel_2")
1211 // channel 3 - zone 0
1212 p_channel_assignment->setZoneIndex( 3, var_CreateGetIntegerCommand(
1213 p_filter, CFG_PREFIX "channel_3")
1216 // channel 4 - zone 2
1217 p_channel_assignment->setZoneIndex( 4, var_CreateGetIntegerCommand(
1218 p_filter, CFG_PREFIX "channel_4")
1221 char *psz_channels = var_CreateGetStringCommand(
1223 CFG_PREFIX "channels"
1225 if( psz_channels && strlen(psz_channels) > 0 )
1227 msg_Dbg( p_filter, "deal with new zone mapping %s", psz_channels );
1229 char *psz_temp = psz_channels;
1230 char *psz_start = psz_temp;
1233 if(*psz_temp == ',' || *psz_temp == ';')
1238 int zone = atoi( psz_start );
1240 zone >= p_channel_assignment->getSize()) {
1241 msg_Warn( p_filter, "Zone %d out of range -1..%d",
1242 zone, p_channel_assignment->getSize()-1 );
1244 p_channel_assignment->setZoneIndex( channel, zone );
1248 psz_start = psz_temp;
1256 process the rest of the string
1258 if( *psz_start && !*psz_temp )
1260 int zone = atoi( psz_start );
1262 zone >= p_channel_assignment->getSize()) {
1263 msg_Warn( p_filter, "Zone %d out of range -1..%d",
1264 zone, p_channel_assignment->getSize()-1 );
1266 p_channel_assignment->setZoneIndex( channel, zone );
1270 free( psz_channels );
1272 for(int i=0;i< p_channel_assignment->getSize() ;i++)
1273 msg_Info( p_filter, "map zone %d to hardware channel %d",
1274 p_channel_assignment->getZoneIndex( i ),
1277 p_sys->p_atmo_dyndata->getAtmoConnection()
1278 ->SetChannelAssignment( p_channel_assignment );
1285 calculate the default gradients for each zone!
1286 depending on the zone layout set before, this now
1287 supports also multiple gradients on each side
1288 (older versions could do this only with external
1291 p_sys->p_atmo_dyndata->CalculateDefaultZones();
1295 first try to load the old style defined gradient bitmaps
1296 this could only be done for the first five zones
1297 - should be deprecated -
1299 CAtmoZoneDefinition *p_zone;
1300 char psz_gradient_var_name[30];
1301 char *psz_gradient_file;
1302 for(int i=0;i<CLASSIC_ATMO_NUM_ZONES;i++)
1304 sprintf(psz_gradient_var_name, CFG_PREFIX "gradient_zone_%d", i);
1305 psz_gradient_file = var_CreateGetStringCommand(
1307 psz_gradient_var_name
1309 if(psz_gradient_file && strlen(psz_gradient_file)>0)
1311 msg_Dbg( p_filter, "loading gradientfile %s for "\
1312 "zone %d", psz_gradient_file, i);
1314 p_zone = p_atmo_config->getZoneDefinition(i);
1317 int i_res = p_zone->LoadGradientFromBitmap(psz_gradient_file);
1319 if(i_res != ATMO_LOAD_GRADIENT_OK)
1321 msg_Err( p_filter,"failed to load gradient '%s' with "\
1322 "error %d",psz_gradient_file,i_res);
1326 free( psz_gradient_file );
1331 the new approach try to load a gradient bitmap for each zone
1332 from a previously defined folder containing
1337 char *psz_gradient_path = var_CreateGetStringCommand(
1339 CFG_PREFIX "gradient_path"
1341 if( psz_gradient_path && strlen(psz_gradient_path) > 0 )
1343 char *psz_file_name = (char *)malloc( strlen(psz_gradient_path) + 16 );
1344 assert( psz_file_name );
1346 for(int i=0; i < p_atmo_config->getZoneCount(); i++ )
1348 p_zone = p_atmo_config->getZoneDefinition(i);
1352 sprintf(psz_file_name, "%s%szone_%d.bmp",
1353 psz_gradient_path, DIR_SEP, i );
1355 int i_res = p_zone->LoadGradientFromBitmap( psz_file_name );
1357 if( i_res == ATMO_LOAD_GRADIENT_OK )
1359 msg_Dbg( p_filter, "loaded gradientfile %s for "\
1360 "zone %d", psz_file_name, i);
1363 if( (i_res != ATMO_LOAD_GRADIENT_OK) &&
1364 (i_res != ATMO_LOAD_GRADIENT_FILENOTFOND) )
1366 msg_Err( p_filter,"failed to load gradient '%s' with "\
1367 "error %d",psz_file_name,i_res);
1372 free( psz_file_name );
1374 free( psz_gradient_path );
1377 p_sys->p_atmo_dyndata->UnLockCriticalSection();
1381 static void Atmo_SetupConfig(filter_t *p_filter, CAtmoConfig *p_atmo_config)
1384 figuring out the device ports (com-ports, ttys)
1386 char *psz_serialdev = var_CreateGetStringCommand( p_filter,
1387 CFG_PREFIX "serialdev" );
1388 char *psz_temp = psz_serialdev;
1390 if( psz_temp && strlen(psz_temp) > 0 )
1397 msg_Dbg( p_filter, "use port(s) %s",psz_serialdev);
1400 psz_serialdev - may contain up to 4 COM ports for the quattro device
1401 the quattro device is just hack of useing 4 classic devices as one
1402 logical device - thanks that usb-com-ports exists :)
1403 as Seperator I defined , or ; with the hope that these
1404 characters are never part of a device name
1406 while( (psz_token = strsep(&psz_temp, ",;")) != NULL && i_port < 4 )
1409 psz_token may contain spaces we have to trim away
1414 find first none space in string
1416 while( psz_token[i] == 32 ) i++;
1418 contains string only spaces or is empty? skip it
1426 while( psz_token[i] && psz_token[i] != 32 )
1427 psz_token[ j++ ] = psz_token[ i++ ];
1430 msg_Dbg( p_filter, "Serial Device [%d]: %s", i_port, psz_token );
1432 p_atmo_config->setSerialDevice( i_port, psz_token );
1439 msg_Err(p_filter,"no serial devicename(s) set");
1441 free( psz_serialdev );
1444 configuration of light source layout arround the display
1446 p_atmo_config->setZonesTopCount(
1447 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-top")
1449 p_atmo_config->setZonesBottomCount(
1450 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-bottom")
1452 p_atmo_config->setZonesLRCount(
1453 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-lr")
1455 p_atmo_config->setZoneSummary(
1456 var_CreateGetBoolCommand( p_filter, CFG_PREFIX "zone-summary")
1460 p_atmo_config->setLiveViewFilterMode(
1461 (AtmoFilterMode)var_CreateGetIntegerCommand( p_filter,
1462 CFG_PREFIX "filtermode")
1465 p_atmo_config->setLiveViewFilter_PercentNew(
1466 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "percentnew")
1468 p_atmo_config->setLiveViewFilter_MeanLength(
1469 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "meanlength")
1471 p_atmo_config->setLiveViewFilter_MeanThreshold(
1472 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "meanthreshold")
1475 p_atmo_config->setLiveView_EdgeWeighting(
1476 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "edgeweightning")
1478 p_atmo_config->setLiveView_BrightCorrect(
1479 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "brightness")
1481 p_atmo_config->setLiveView_DarknessLimit(
1482 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "darknesslimit")
1484 p_atmo_config->setLiveView_HueWinSize(
1485 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "huewinsize")
1487 p_atmo_config->setLiveView_SatWinSize(
1488 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "satwinsize")
1491 /* currently not required inside vlc */
1492 p_atmo_config->setLiveView_WidescreenMode( 0 );
1494 p_atmo_config->setLiveView_FrameDelay(
1495 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "framedelay")
1499 p_atmo_config->setUseSoftwareWhiteAdj(
1500 var_CreateGetBoolCommand( p_filter, CFG_PREFIX "whiteadj")
1502 p_atmo_config->setWhiteAdjustment_Red(
1503 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-red")
1505 p_atmo_config->setWhiteAdjustment_Green(
1506 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-green")
1508 p_atmo_config->setWhiteAdjustment_Blue(
1509 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-blue")
1513 settings for DMX device only
1515 p_atmo_config->setDMX_RGB_Channels(
1516 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "dmx-channels")
1519 char *psz_chbase = var_CreateGetStringCommand( p_filter,
1520 CFG_PREFIX "dmx-chbase" );
1521 if( psz_chbase && strlen(psz_chbase) > 0 )
1522 p_atmo_config->setDMX_BaseChannels( psz_chbase );
1529 p_atmo_config->setMoMo_Channels(
1530 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "momo-channels")
1536 initialize the filter_sys_t structure with the data from the settings
1537 variables - if the external filter on win32 is enabled try loading the DLL,
1538 if this fails fallback to the buildin software
1540 static void Atmo_SetupParameters(filter_t *p_filter)
1543 filter_sys_t *p_sys = p_filter->p_sys;
1546 /* default filter disabled until DLL loaded and Init Success!*/
1547 p_sys->b_enabled = false;
1549 /* setup default mini image size (may be later a user option) */
1550 p_sys->i_atmo_width = 64;
1551 p_sys->i_atmo_height = 48;
1553 p_sys->i_device_type = var_CreateGetIntegerCommand( p_filter,
1554 CFG_PREFIX "device");
1558 0 => use AtmoWin Software (only win32)
1559 1 => use AtmoClassicConnection (direct)
1560 2 => use AtmoMultiConnection (direct up to four serial ports required)
1561 3 => use AtmoDmxConnection (simple serial DMX Device up to 255 channels)
1567 only on WIN32 the user has the choice between
1568 internal driver and external
1571 if(p_sys->i_device_type == 0) {
1573 /* Load the Com Wrapper Library (source available) */
1574 p_sys->h_AtmoCtrl = LoadLibraryA("AtmoCtrlLib.dll");
1575 if(p_sys->h_AtmoCtrl == NULL)
1578 be clever if the location of atmowina.exe is set
1579 try to load the dll from the same folder :-)
1581 char *psz_path = var_CreateGetStringCommand( p_filter,
1582 CFG_PREFIX "atmowinexe" );
1583 if( psz_path && strlen(psz_path) > 0 )
1585 char *psz_bs = strrchr( psz_path , '\\');
1590 now format a new dll filename with complete path
1592 char *psz_dllname = NULL;
1593 asprintf( &psz_dllname, "%s\\AtmoCtrlLib.dll", psz_path );
1596 msg_Dbg( p_filter, "Try Loading '%s'", psz_dllname );
1597 p_sys->h_AtmoCtrl = LoadLibraryA( psz_dllname );
1599 free( psz_dllname );
1606 if(p_sys->h_AtmoCtrl != NULL)
1608 msg_Dbg( p_filter, "Load Library ok!");
1610 /* importing all required functions I hope*/
1611 p_sys->pf_ctrl_atmo_initialize =
1612 (int32_t (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoInitialize");
1613 if(!p_sys->pf_ctrl_atmo_initialize)
1614 msg_Err( p_filter, "export AtmoInitialize missing.");
1616 p_sys->pf_ctrl_atmo_finalize =
1617 (void (*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoFinalize");
1618 if(!p_sys->pf_ctrl_atmo_finalize)
1619 msg_Err( p_filter, "export AtmoFinalize missing.");
1621 p_sys->pf_ctrl_atmo_switch_effect =
1622 (int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoSwitchEffect");
1623 if(!p_sys->pf_ctrl_atmo_switch_effect)
1624 msg_Err( p_filter, "export AtmoSwitchEffect missing.");
1626 p_sys->pf_ctrl_atmo_set_live_source =
1627 (int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoSetLiveSource");
1628 if(!p_sys->pf_ctrl_atmo_set_live_source)
1629 msg_Err( p_filter, "export AtmoSetLiveSource missing.");
1631 p_sys->pf_ctrl_atmo_create_transfer_buffers =
1632 (void (*)(int32_t, int32_t, int32_t , int32_t))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoCreateTransferBuffers");
1633 if(!p_sys->pf_ctrl_atmo_create_transfer_buffers)
1634 msg_Err( p_filter, "export AtmoCreateTransferBuffers missing.");
1636 p_sys->pf_ctrl_atmo_lock_transfer_buffer=
1637 (uint8_t*(*) (void))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoLockTransferBuffer");
1638 if(!p_sys->pf_ctrl_atmo_lock_transfer_buffer)
1639 msg_Err( p_filter, "export AtmoLockTransferBuffer missing.");
1641 p_sys->pf_ctrl_atmo_send_pixel_data =
1642 (void (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoSendPixelData");
1643 if(!p_sys->pf_ctrl_atmo_send_pixel_data)
1644 msg_Err( p_filter, "export AtmoSendPixelData missing.");
1646 p_sys->pf_ctrl_atmo_get_image_size =
1647 (void (*)(int32_t*,int32_t*))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoWinGetImageSize");
1648 if(!p_sys->pf_ctrl_atmo_get_image_size)
1649 msg_Err( p_filter, "export AtmoWinGetImageSize missing.");
1652 /* the DLL is missing try internal filter ...*/
1653 msg_Warn( p_filter, "AtmoCtrlLib.dll missing fallback to internal atmo classic driver");
1654 p_sys->i_device_type = 1;
1659 if(p_sys->i_device_type >= 1) {
1660 msg_Dbg( p_filter, "try use buildin driver %d ", p_sys->i_device_type );
1662 now we have to read a lof of options from the config dialog
1663 most important the serial device if not set ... we can skip
1664 the rest and disable the filter...
1667 p_sys->p_atmo_config = new CAtmoConfig();
1669 p_sys->p_atmo_dyndata = new CAtmoDynData(
1670 (vlc_object_t *)p_filter,
1671 p_sys->p_atmo_config
1674 Atmo_SetupConfig( p_filter, p_sys->p_atmo_config );
1675 switch(p_sys->i_device_type)
1678 p_sys->p_atmo_config->setConnectionType( actClassicAtmo );
1682 p_sys->p_atmo_config->setConnectionType( actMultiAtmo );
1686 p_sys->p_atmo_config->setConnectionType( actDMX );
1690 p_sys->p_atmo_config->setConnectionType( actMoMoLight );
1694 msg_Warn( p_filter, "invalid device type %d found",
1695 p_sys->i_device_type );
1698 msg_Dbg( p_filter, "buildin driver config set");
1702 switch( p_filter->fmt_in.video.i_chroma )
1704 case VLC_CODEC_I420:
1705 case VLC_CODEC_YV12:
1706 p_sys->pf_extract_mini_image = ExtractMiniImage_YUV;
1709 msg_Warn( p_filter, "InitFilter-unsupported chroma: %4.4s",
1710 (char *)&p_filter->fmt_in.video.i_chroma);
1711 p_sys->pf_extract_mini_image = NULL;
1714 p_sys->i_crop_x_offset = 0;
1715 p_sys->i_crop_y_offset = 0;
1716 p_sys->i_crop_width = p_filter->fmt_in.video.i_visible_width;
1717 p_sys->i_crop_height = p_filter->fmt_in.video.i_visible_height;
1719 msg_Dbg( p_filter, "set default crop %d,%d %dx%d",p_sys->i_crop_x_offset,
1720 p_sys->i_crop_y_offset,
1721 p_sys->i_crop_width,
1722 p_sys->i_crop_height );
1725 for debugging purpose show the samplinggrid on each frame as
1728 p_sys->b_show_dots = var_CreateGetBoolCommand( p_filter,
1729 CFG_PREFIX "showdots"
1732 #if defined(__ATMO_DEBUG__)
1733 /* save debug images to a folder as Bitmap files ? */
1734 p_sys->b_saveframes = var_CreateGetBoolCommand( p_filter,
1735 CFG_PREFIX "saveframes"
1737 msg_Dbg(p_filter,"saveframes = %d", (int)p_sys->b_saveframes);
1740 read debug image folder from config
1742 psz_path = var_CreateGetStringCommand( p_filter, CFG_PREFIX "framepath" );
1743 if(psz_path != NULL)
1745 strcpy(p_sys->sz_framepath, psz_path);
1746 #if defined( WIN32 )
1747 size_t i_strlen = strlen(p_sys->sz_framepath);
1748 if((i_strlen>0) && (p_sys->sz_framepath[i_strlen-1] != '\\'))
1750 p_sys->sz_framepath[i_strlen] = '\\';
1751 p_sys->sz_framepath[i_strlen+1] = 0;
1756 msg_Dbg(p_filter,"saveframesfolder %s",p_sys->sz_framepath);
1761 because atmowin could also be used for lighten up the room - I think if you
1762 pause the video it would be useful to get a little bit more light into to
1763 your living room? - instead switching on a lamp?
1765 p_sys->b_usepausecolor = var_CreateGetBoolCommand( p_filter,
1766 CFG_PREFIX "usepausecolor" );
1767 p_sys->ui_pausecolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1768 CFG_PREFIX "pcolor-red");
1769 p_sys->ui_pausecolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1770 CFG_PREFIX "pcolor-green");
1771 p_sys->ui_pausecolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1772 CFG_PREFIX "pcolor-blue");
1773 p_sys->i_fadesteps = var_CreateGetIntegerCommand( p_filter,
1774 CFG_PREFIX "fadesteps");
1775 if(p_sys->i_fadesteps < 1)
1776 p_sys->i_fadesteps = 1;
1777 msg_Dbg(p_filter,"use pause color %d, RGB: %d, %d, %d, Fadesteps: %d",
1778 (int)p_sys->b_usepausecolor,
1779 p_sys->ui_pausecolor_red,
1780 p_sys->ui_pausecolor_green,
1781 p_sys->ui_pausecolor_blue,
1782 p_sys->i_fadesteps);
1785 this color is use on shutdown of the filter - the define the
1786 final light after playback... may be used to dim up the light -
1787 how it happens in the cinema...
1789 p_sys->ui_endcolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1790 CFG_PREFIX "ecolor-red");
1791 p_sys->ui_endcolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1792 CFG_PREFIX "ecolor-green");
1793 p_sys->ui_endcolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1794 CFG_PREFIX "ecolor-blue");
1795 p_sys->i_endfadesteps = var_CreateGetIntegerCommand( p_filter,
1796 CFG_PREFIX "efadesteps");
1797 if(p_sys->i_endfadesteps < 1)
1798 p_sys->i_endfadesteps = 1;
1799 msg_Dbg(p_filter,"use ende color RGB: %d, %d, %d, Fadesteps: %d",
1800 p_sys->ui_endcolor_red,
1801 p_sys->ui_endcolor_green,
1802 p_sys->ui_endcolor_blue,
1803 p_sys->i_endfadesteps);
1808 if the external DLL was loaded successfully call AtmoInitialize -
1809 (must be done for each thread where you want to use AtmoLight!)
1811 int i = AtmoInitialize(p_filter, false);
1813 #if defined( WIN32 )
1814 if((i != 1) && (p_sys->i_device_type == 0))
1817 COM Server for AtmoLight not running ?
1818 if the exe path is configured try to start the "userspace" driver
1820 psz_path = var_CreateGetStringCommand( p_filter,
1821 CFG_PREFIX "atmowinexe" );
1822 if(psz_path != NULL)
1824 STARTUPINFO startupinfo;
1825 PROCESS_INFORMATION pinfo;
1826 memset(&startupinfo, 0, sizeof(STARTUPINFO));
1827 startupinfo.cb = sizeof(STARTUPINFO);
1828 if(CreateProcess(psz_path, NULL, NULL, NULL,
1829 FALSE, 0, NULL, NULL, &startupinfo, &pinfo) == TRUE)
1831 msg_Dbg(p_filter,"launched AtmoWin from %s",psz_path);
1832 WaitForInputIdle(pinfo.hProcess, 5000);
1834 retry to initialize the library COM ... functionality
1835 after the server was launched
1837 i = AtmoInitialize(p_filter, false);
1839 msg_Err(p_filter,"failed to launch AtmoWin from %s", psz_path);
1846 if(i == 1) /* Init Atmolight success... */
1848 msg_Dbg( p_filter, "AtmoInitialize Ok!");
1851 p_sys->i_atmo_width and p_sys->i_atmo_height
1852 if the external AtmoWinA.exe is used, it may require
1853 a other sample image size than 64 x 48
1854 (this overrides the settings of the filter)
1856 Atmo_SetupImageSize( p_filter );
1859 if( p_sys->i_device_type >= 1 )
1862 AtmoConnection class initialized now we can initialize
1863 the default zone and channel mappings
1865 Atmo_SetupBuildZones( p_filter );
1868 /* Setup Transferbuffers for 64 x 48 , RGB with 32bit Per Pixel */
1869 AtmoCreateTransferBuffers(p_filter, BI_RGB, 4,
1870 p_sys->i_atmo_width,
1871 p_sys->i_atmo_height
1874 /* say the userspace driver that a live mode should be activated
1875 the functions returns the old mode for later restore!
1876 - the buildin driver launches the live view thread in that case
1878 p_sys->i_AtmoOldEffect = AtmoSwitchEffect(p_filter, emLivePicture);
1881 live view can have two differnt source the AtmoWinA
1882 internal GDI Screencapture and the external one - which we
1885 AtmoSetLiveSource(p_filter, lvsExternal);
1887 /* enable other parts only if everything is fine */
1888 p_sys->b_enabled = true;
1890 msg_Dbg( p_filter, "Atmo Filter Enabled Ok!");
1896 /*****************************************************************************
1897 * CreateFilter: allocates AtmoLight video thread output method
1898 *****************************************************************************
1899 * This function allocates and initializes a AtmoLight vout method.
1900 *****************************************************************************/
1901 static int CreateFilter( vlc_object_t *p_this )
1903 filter_t *p_filter = (filter_t *)p_this;
1904 filter_sys_t *p_sys;
1906 /* Allocate structure */
1907 p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) );
1908 p_filter->p_sys = p_sys;
1909 if( p_filter->p_sys == NULL )
1911 /* set all entries to zero */
1912 memset(p_sys, 0, sizeof( filter_sys_t ));
1913 vlc_mutex_init( &p_sys->filter_lock );
1915 msg_Dbg( p_filter, "Create Atmo Filter");
1917 /* further Setup Function pointers for videolan for calling my filter */
1918 p_filter->pf_video_filter = Filter;
1920 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
1923 AddStateVariableCallback(p_filter);
1925 AddCropVariableCallback(p_filter);
1927 AddAtmoSettingsVariablesCallbacks(p_filter);
1929 Atmo_SetupParameters(p_filter);
1937 /*****************************************************************************
1938 * DestroyFilter: destroy AtmoLight video thread output method
1939 *****************************************************************************
1940 * Terminate an output method created by CreateFilter
1941 *****************************************************************************/
1943 static void DestroyFilter( vlc_object_t *p_this )
1945 filter_t *p_filter = (filter_t *)p_this;
1946 filter_sys_t *p_sys = p_filter->p_sys;
1948 msg_Dbg( p_filter, "Destroy Atmo Filter");
1950 DelStateVariableCallback(p_filter);
1951 DelCropVariableCallback(p_filter);
1952 DelAtmoSettingsVariablesCallbacks(p_filter);
1954 Atmo_Shutdown(p_filter);
1956 #if defined( WIN32 )
1957 if(p_sys->h_AtmoCtrl != NULL)
1959 FreeLibrary(p_sys->h_AtmoCtrl);
1963 delete p_sys->p_atmo_dyndata;
1964 delete p_sys->p_atmo_config;
1966 vlc_mutex_destroy( &p_sys->filter_lock );
1973 function stolen from some other videolan source filter ;-)
1974 for the moment RGB is OK... but better would be a direct transformation
1977 static inline void yuv_to_rgb( uint8_t *r, uint8_t *g, uint8_t *b,
1978 uint8_t y1, uint8_t u1, uint8_t v1 )
1980 /* macros used for YUV pixel conversions */
1981 # define SCALEBITS 10
1982 # define ONE_HALF (1 << (SCALEBITS - 1))
1983 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
1984 # define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
1986 int y, cb, cr, r_add, g_add, b_add;
1990 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
1991 g_add = - FIX(0.34414*255.0/224.0) * cb
1992 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
1993 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
1994 y = (y1 - 16) * FIX(255.0/219.0);
1995 *r = CLAMP((y + r_add) >> SCALEBITS);
1996 *g = CLAMP((y + g_add) >> SCALEBITS);
1997 *b = CLAMP((y + b_add) >> SCALEBITS);
1999 /******************************************************************************
2000 * ExtractMiniImage_YUV: extract a small image from the picture as 24-bit RGB
2001 *******************************************************************************
2002 * p_sys is a pointer to
2003 * p_inpic is the source frame
2004 * p_transfer_dest is the target buffer for the picture must be big enough!
2005 * (in win32 enviroment this buffer comes from the external DLL where it is
2006 * create as "variant array" and returned through the AtmoLockTransferbuffer
2008 static void ExtractMiniImage_YUV(filter_sys_t *p_sys,
2010 uint8_t *p_transfer_dest)
2017 uint8_t *p_rgb_dst_line_red;
2018 uint8_t *p_rgb_dst_line_green;
2019 uint8_t *p_rgb_dst_line_blue;
2024 /* calcute Pointers for Storage of B G R (A) */
2025 p_rgb_dst_line_blue = p_transfer_dest;
2026 p_rgb_dst_line_green = p_transfer_dest + 1;
2027 p_rgb_dst_line_red = p_transfer_dest + 2 ;
2029 int i_row_count = p_sys->i_atmo_height + 1;
2030 int i_col_count = p_sys->i_atmo_width + 1;
2031 int i_y_row,i_u_row,i_v_row,i_pixel_row;
2035 /* these two ugly loops extract the small image - goes it faster? how?
2036 the loops are so designed that there is a small border around the extracted
2037 image so we wont get column and row - zero from the frame, and not the most
2038 right and bottom pixels --- which may be clipped on computers useing TV out
2041 TODO: try to find out if the output is clipped through VLC - and try here
2042 to ingore the clipped away area for a better result!
2044 TODO: performance improvement in InitFilter percalculated the offsets of
2045 the lines inside the planes so I can save (i_row_count * 3) 2xMUL and
2046 one time DIV the same could be done for the inner loop I think...
2048 for(i_row = 1; i_row < i_row_count; i_row++)
2050 // calcute the current Lines in the source planes for this outputrow
2051 /* Adresscalcuation pointer to plane Length of one pixelrow in bytes
2052 calculate row now number
2055 p_inpic->format? transform Pixel row into row of plane...
2056 how? simple? fast? good?
2059 /* compute the source pixel row and respect the active cropping */
2060 i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
2061 + p_sys->i_crop_y_offset;
2064 trans for these Pixel row into the row of each plane ..
2065 because planesize can differ from image size
2067 i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
2068 p_inpic->format.i_visible_height;
2070 i_u_row = (i_pixel_row * p_inpic->p[U_PLANE].i_visible_lines) /
2071 p_inpic->format.i_visible_height;
2073 i_v_row = (i_pixel_row * p_inpic->p[V_PLANE].i_visible_lines) /
2074 p_inpic->format.i_visible_height;
2076 /* calculate the pointers to the pixeldata for this row
2079 p_src_y = p_inpic->p[Y_PLANE].p_pixels +
2080 p_inpic->p[Y_PLANE].i_pitch * i_y_row;
2081 p_src_u = p_inpic->p[U_PLANE].p_pixels +
2082 p_inpic->p[U_PLANE].i_pitch * i_u_row;
2083 p_src_v = p_inpic->p[V_PLANE].p_pixels +
2084 p_inpic->p[V_PLANE].i_pitch * i_v_row;
2086 for(i_col = 1; i_col < i_col_count; i_col++)
2088 i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
2089 p_sys->i_crop_x_offset;
2091 trans for these Pixel row into the row of each plane ..
2092 because planesize can differ from image size
2094 i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
2095 p_inpic->format.i_visible_width;
2096 i_xpos_u = (i_pixel_col * p_inpic->p[U_PLANE].i_visible_pitch) /
2097 p_inpic->format.i_visible_width;
2098 i_xpos_v = (i_pixel_col * p_inpic->p[V_PLANE].i_visible_pitch) /
2099 p_inpic->format.i_visible_width;
2101 yuv_to_rgb(p_rgb_dst_line_red,
2102 p_rgb_dst_line_green,
2103 p_rgb_dst_line_blue,
2109 /* +4 because output image should be RGB32 with dword alignment! */
2110 p_rgb_dst_line_red += 4;
2111 p_rgb_dst_line_green += 4;
2112 p_rgb_dst_line_blue += 4;
2116 if(p_sys->b_show_dots)
2118 for(i_row = 1; i_row < i_row_count; i_row++)
2120 i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
2121 + p_sys->i_crop_y_offset;
2123 i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
2124 p_inpic->format.i_visible_height;
2126 p_src_y = p_inpic->p[Y_PLANE].p_pixels +
2127 p_inpic->p[Y_PLANE].i_pitch * i_y_row;
2129 for(i_col = 1; i_col < i_col_count; i_col++)
2131 i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
2132 p_sys->i_crop_x_offset;
2133 i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
2134 p_inpic->format.i_visible_width;
2136 p_src_y[i_xpos_y] = 255;
2144 /******************************************************************************
2145 * SaveBitmap: Saves the content of a transferbuffer as Bitmap to disk
2146 *******************************************************************************
2147 * just for debugging
2148 * p_sys -> configuration if Atmo from there the function will get height and
2150 * p_pixels -> should be the dword aligned BGR(A) image data
2151 * psz_filename -> filename where to store
2153 #if defined(__ATMO_DEBUG__)
2154 void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename)
2156 /* for debug out only used*/
2157 BITMAPINFO bmp_info;
2158 BITMAPFILEHEADER bmp_fileheader;
2161 memset(&bmp_info, 0, sizeof(BITMAPINFO));
2162 bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2163 bmp_info.bmiHeader.biSizeImage = p_sys->i_atmo_height *
2164 p_sys->i_atmo_width * 4;
2165 bmp_info.bmiHeader.biCompression = BI_RGB;
2166 bmp_info.bmiHeader.biWidth = p_sys->i_atmo_width;
2167 bmp_info.bmiHeader.biHeight = -p_sys->i_atmo_height;
2168 bmp_info.bmiHeader.biBitCount = 32;
2169 bmp_info.bmiHeader.biPlanes = 1;
2171 bmp_fileheader.bfReserved1 = 0;
2172 bmp_fileheader.bfReserved2 = 0;
2173 bmp_fileheader.bfSize = sizeof(BITMAPFILEHEADER) +
2174 sizeof(BITMAPINFOHEADER) +
2175 bmp_info.bmiHeader.biSizeImage;
2176 bmp_fileheader.bfType = VLC_TWOCC('B','M');
2177 bmp_fileheader.bfOffBits = sizeof(BITMAPFILEHEADER) +
2178 sizeof(BITMAPINFOHEADER);
2180 fp_bitmap = fopen(psz_filename,"wb");
2181 if( fp_bitmap != NULL)
2183 fwrite(&bmp_fileheader, sizeof(BITMAPFILEHEADER), 1, fp_bitmap);
2184 fwrite(&bmp_info.bmiHeader, sizeof(BITMAPINFOHEADER), 1, fp_bitmap);
2185 fwrite(p_pixels, bmp_info.bmiHeader.biSizeImage, 1, fp_bitmap);
2192 /****************************************************************************
2193 * CreateMiniImage: extracts a 64x48 pixel image from the frame
2194 * (there is a small border arround thats why the loops starts with one
2195 * instead zero) without any interpolation
2196 *****************************************************************************/
2197 static void CreateMiniImage( filter_t *p_filter, picture_t *p_inpic)
2199 filter_sys_t *p_sys = p_filter->p_sys;
2201 pointer to RGB Buffer created in external libary as safe array which
2202 is locked inside AtmoLockTransferBuffer
2204 uint8_t *p_transfer;
2205 #if defined( __ATMO_DEBUG__ )
2206 /* for debug out only used*/
2207 char sz_filename[MAX_PATH];
2211 Lock the before created VarArray (AtmoCreateTransferBuffers)
2212 inside my wrapper library and give me a pointer to the buffer!
2213 below linux a global buffer may be used and protected with a mutex?
2215 p_transfer = AtmoLockTransferBuffer(p_filter);
2216 if(p_transfer == NULL)
2218 msg_Err( p_filter, "AtmoLight no transferbuffer available. "\
2219 "AtmoLight will be disabled!");
2220 p_sys->b_enabled = false;
2225 do the call via pointer to function instead of having a
2228 p_sys->pf_extract_mini_image(p_sys, p_inpic, p_transfer);
2231 #if defined( __ATMO_DEBUG__ )
2233 if debugging enabled save every 128th image to disk
2235 if((p_sys->b_saveframes == true) && (p_sys->sz_framepath[0] != 0 ))
2238 if((p_sys->ui_frame_counter & 127) == 0)
2240 sprintf(sz_filename,"%satmo_dbg_%06u.bmp",p_sys->sz_framepath,
2241 p_sys->ui_frame_counter);
2242 msg_Dbg(p_filter, "SaveFrame %s",sz_filename);
2244 SaveBitmap(p_sys, p_transfer, sz_filename);
2248 msg_Dbg( p_filter, "AtmoFrame %u Time: %d ms", p_sys->ui_frame_counter, mdate() / 1000);
2249 p_sys->ui_frame_counter++;
2252 p_sys->i_frames_processed++;
2255 /* show the colors on the wall */
2256 AtmoSendPixelData( p_filter );
2262 /*****************************************************************************
2263 * Filter: calls the extract method and forwards the incomming picture 1:1
2264 *****************************************************************************
2266 *****************************************************************************/
2268 static picture_t * Filter( filter_t *p_filter, picture_t *p_pic )
2270 filter_sys_t *p_sys = p_filter->p_sys;
2271 if( !p_pic ) return NULL;
2273 vlc_mutex_lock( &p_sys->filter_lock );
2275 if((p_sys->b_enabled == true) &&
2276 (p_sys->pf_extract_mini_image != NULL) &&
2277 (p_sys->b_pause_live == false))
2279 CreateMiniImage(p_filter, p_pic);
2282 vlc_mutex_unlock( &p_sys->filter_lock );
2290 /*****************************************************************************
2291 * FadeToColorThread: Threadmethod which changes slowly the color
2292 * to a target color defined in p_fadethread struct
2293 * use for: Fade to Pause Color, and Fade to End Color
2294 *****************************************************************************/
2295 static void *FadeToColorThread(vlc_object_t *obj)
2297 fadethread_t *p_fadethread = (fadethread_t *)obj;
2298 filter_sys_t *p_sys = (filter_sys_t *)p_fadethread->p_filter->p_sys;
2299 int i_steps_done = 0;
2309 uint8_t *p_source = NULL;
2311 int canc = vlc_savecancel ();
2312 /* initialize AtmoWin for this thread! */
2313 AtmoInitialize(p_fadethread->p_filter , true);
2315 uint8_t *p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
2316 if(p_transfer != NULL) {
2317 /* safe colors as "32bit" Integers to avoid overflows*/
2318 i_pause_red = p_fadethread->ui_red;
2319 i_pause_blue = p_fadethread->ui_blue;
2320 i_pause_green = p_fadethread->ui_green;
2323 allocate a temporary buffer for the last send
2324 image size less then 15kb
2326 int i_size = 4 * p_sys->i_atmo_width * p_sys->i_atmo_height;
2327 p_source = (uint8_t *)malloc( i_size );
2328 if(p_source != NULL)
2331 get a copy of the last transfered image as orign for the
2334 memcpy(p_source, p_transfer, i_size);
2335 /* send the same pixel data again... to unlock the buffer! */
2336 AtmoSendPixelData( p_fadethread->p_filter );
2338 while( (vlc_object_alive (p_fadethread)) &&
2339 (i_steps_done < p_fadethread->i_steps))
2341 p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
2342 if(!p_transfer) break; /* should not happen if it worked
2343 one time in the code above! */
2346 move all pixels in the mini image (64x48) one step closer to
2347 the desired color these loop takes the most time of this
2348 thread improvements wellcome!
2351 (i_index < i_size) && (vlc_object_alive (p_fadethread));
2354 i_src_blue = p_source[i_index+0];
2355 i_src_green = p_source[i_index+1];
2356 i_src_red = p_source[i_index+2];
2357 p_transfer[i_index+0] = (uint8_t) (((
2358 (i_pause_blue - i_src_blue)
2359 * i_steps_done)/p_fadethread->i_steps)
2362 p_transfer[i_index+1] = (uint8_t) (((
2363 (i_pause_green - i_src_green)
2364 * i_steps_done)/p_fadethread->i_steps)
2367 p_transfer[i_index+2] = (uint8_t) (((
2368 (i_pause_red - i_src_red)
2369 * i_steps_done)/p_fadethread->i_steps)
2373 /* send image to lightcontroller */
2374 AtmoSendPixelData( p_fadethread->p_filter );
2375 /* is there something like and interruptable sleep inside
2376 the VLC libaries? inside native win32 I would use an Event
2377 (CreateEvent) and here an WaitForSingleObject?
2383 /* in failure of malloc also unlock buffer */
2384 AtmoSendPixelData(p_fadethread->p_filter);
2387 /* call indirect to OleUnitialize() for this thread */
2388 AtmoFinalize(p_fadethread->p_filter, 0);
2389 vlc_restorecancel (canc);
2393 /*****************************************************************************
2394 * CheckAndStopFadeThread: if there is a fadethread structure left, or running.
2395 ******************************************************************************
2396 * this function will stop the thread ... and waits for its termination
2397 * before removeing the objects from vout_sys_t ...
2398 ******************************************************************************/
2399 static void CheckAndStopFadeThread(filter_t *p_filter)
2401 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2402 vlc_mutex_lock( &p_sys->filter_lock );
2403 if(p_sys->p_fadethread != NULL)
2405 msg_Dbg(p_filter, "kill still running fadeing thread...");
2407 p_sys->p_fadethread->b_die = true;
2409 vlc_thread_join(p_sys->p_fadethread);
2411 vlc_object_release(p_sys->p_fadethread);
2412 p_sys->p_fadethread = NULL;
2414 vlc_mutex_unlock( &p_sys->filter_lock );
2417 /*****************************************************************************
2418 * StateCallback: Callback for the inputs variable "State" to get notified
2419 * about Pause and Continue Playback events.
2420 *****************************************************************************/
2421 static int StateCallback( vlc_object_t *p_this, char const *psz_cmd,
2422 vlc_value_t oldval, vlc_value_t newval,
2425 filter_t *p_filter = (filter_t *)p_data;
2426 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2428 if((p_sys->b_usepausecolor == true) && (p_sys->b_enabled == true))
2430 msg_Dbg(p_filter, "state change from: %d to %d", oldval.i_int,
2433 if((newval.i_int == PAUSE_S) && (oldval.i_int == PLAYING_S))
2435 /* tell the other thread to stop sending images to light
2437 p_sys->b_pause_live = true;
2439 // clean up old thread - should not happen....
2440 CheckAndStopFadeThread( p_filter );
2442 // perpare spawn fadeing thread
2443 vlc_mutex_lock( &p_sys->filter_lock );
2445 launch only a new thread if there is none active!
2446 or waiting for cleanup
2448 if(p_sys->p_fadethread == NULL)
2450 p_sys->p_fadethread = (fadethread_t *)vlc_object_create(
2452 sizeof(fadethread_t) );
2454 p_sys->p_fadethread->p_filter = p_filter;
2455 p_sys->p_fadethread->ui_red = p_sys->ui_pausecolor_red;
2456 p_sys->p_fadethread->ui_green = p_sys->ui_pausecolor_green;
2457 p_sys->p_fadethread->ui_blue = p_sys->ui_pausecolor_blue;
2458 p_sys->p_fadethread->i_steps = p_sys->i_fadesteps;
2460 if( vlc_thread_create( p_sys->p_fadethread,
2461 "AtmoLight fadeing",
2463 VLC_THREAD_PRIORITY_LOW ) )
2465 msg_Err( p_filter, "cannot create FadeToColorThread" );
2466 vlc_object_release( p_sys->p_fadethread );
2467 p_sys->p_fadethread = NULL;
2470 vlc_mutex_unlock( &p_sys->filter_lock );
2473 if((newval.i_int == PLAYING_S) && (oldval.i_int == PAUSE_S))
2475 /* playback continues check thread state */
2476 CheckAndStopFadeThread( p_filter );
2477 /* reactivate the Render function... to do its normal work */
2478 p_sys->b_pause_live = false;
2485 /*****************************************************************************
2486 * AddPlaylistInputThreadStateCallback: Setup call back on "State" Variable
2487 *****************************************************************************
2488 * Add Callback function to the "state" variable of the input thread..
2489 * first find the PlayList and get the input thread from there to attach
2491 *****************************************************************************/
2492 static void AddStateVariableCallback(filter_t *p_filter)
2494 input_thread_t *p_input = playlist_CurrentInput( pl_Get( p_filter ) );
2497 var_AddCallback( p_input, "state", StateCallback, p_filter );
2498 vlc_object_release( p_input );
2502 /*****************************************************************************
2503 * DelPlaylistInputThreadStateCallback: Remove call back on "State" Variable
2504 *****************************************************************************
2505 * Delete the callback function to the "state" variable of the input thread...
2506 * first find the PlayList and get the input thread from there to attach
2507 * my callback? is vlc_object_find the right way for this??
2508 *****************************************************************************/
2509 static void DelStateVariableCallback( filter_t *p_filter )
2511 input_thread_t *p_input = playlist_CurrentInput( pl_Get ( p_filter ) );
2514 var_DelCallback( p_input, "state", StateCallback, p_filter );
2515 vlc_object_release( p_input );
2520 static int CropCallback(vlc_object_t *p_this, char const *psz_cmd,
2521 vlc_value_t oldval, vlc_value_t newval,
2524 vout_thread_t *p_vout = (vout_thread_t *)p_this;
2525 filter_t *p_filter = (filter_t *)p_data;
2526 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2529 //if the handler is attache to crop variable directly!
2530 int i_visible_width, i_visible_height, i_x_offset, i_y_offset;
2531 atmo_parse_crop(newval.psz_string, p_vout->fmt_render,
2533 i_visible_width, i_visible_height,
2534 i_x_offset, i_y_offset);
2535 p_sys->i_crop_x_offset = i_x_offset;
2536 p_sys->i_crop_y_offset = i_y_offset;
2537 p_sys->i_crop_width = i_visible_width;
2538 p_sys->i_crop_height = i_visible_height;
2541 p_sys->i_crop_x_offset = p_vout->fmt_in.i_x_offset;
2542 p_sys->i_crop_y_offset = p_vout->fmt_in.i_y_offset;
2543 p_sys->i_crop_width = p_vout->fmt_in.i_visible_width;
2544 p_sys->i_crop_height = p_vout->fmt_in.i_visible_height;
2546 msg_Dbg(p_filter, "cropping picture %ix%i to %i,%i,%ix%i",
2547 p_vout->fmt_in.i_width,
2548 p_vout->fmt_in.i_height,
2549 p_sys->i_crop_x_offset,
2550 p_sys->i_crop_y_offset,
2551 p_sys->i_crop_width,
2552 p_sys->i_crop_height
2559 static void AddCropVariableCallback( filter_t *p_filter)
2561 vout_thread_t *p_vout = (vout_thread_t *)vlc_object_find( p_filter,
2566 var_AddCallback( p_vout, "crop-update", CropCallback, p_filter );
2567 vlc_object_release( p_vout );
2571 static void DelCropVariableCallback( filter_t *p_filter)
2573 vout_thread_t *p_vout = (vout_thread_t *)vlc_object_find( p_filter,
2578 var_DelCallback( p_vout, "crop-update", CropCallback, p_filter );
2579 vlc_object_release( p_vout );
2584 /****************************************************************************
2585 * StateCallback: Callback for the inputs variable "State" to get notified
2586 * about Pause and Continue Playback events.
2587 *****************************************************************************/
2588 static int AtmoSettingsCallback( vlc_object_t *p_this, char const *psz_var,
2589 vlc_value_t oldval, vlc_value_t newval,
2592 filter_t *p_filter = (filter_t *)p_data;
2593 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2595 vlc_mutex_lock( &p_sys->filter_lock );
2597 if( !strcmp( psz_var, CFG_PREFIX "showdots" ))
2599 p_sys->b_show_dots = newval.b_bool;
2602 CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
2606 msg_Dbg(p_filter, "apply AtmoSettingsCallback %s (int: %d -> %d)",
2612 if( !strcmp( psz_var, CFG_PREFIX "filtermode" ))
2613 p_atmo_config->setLiveViewFilterMode( (AtmoFilterMode)newval.i_int);
2615 else if( !strcmp( psz_var, CFG_PREFIX "percentnew" ))
2616 p_atmo_config->setLiveViewFilter_PercentNew( newval.i_int );
2618 else if( !strcmp( psz_var, CFG_PREFIX "meanlength" ))
2619 p_atmo_config->setLiveViewFilter_MeanLength( newval.i_int );
2621 else if( !strcmp( psz_var, CFG_PREFIX "meanthreshold" ))
2622 p_atmo_config->setLiveViewFilter_MeanThreshold( newval.i_int );
2624 else if( !strcmp( psz_var, CFG_PREFIX "edgeweightning" ))
2625 p_atmo_config->setLiveView_EdgeWeighting( newval.i_int );
2627 else if( !strcmp( psz_var, CFG_PREFIX "brightness" ))
2628 p_atmo_config->setLiveView_BrightCorrect( newval.i_int );
2630 else if( !strcmp( psz_var, CFG_PREFIX "darknesslimit" ))
2631 p_atmo_config->setLiveView_DarknessLimit( newval.i_int );
2633 else if( !strcmp( psz_var, CFG_PREFIX "huewinsize" ))
2634 p_atmo_config->setLiveView_HueWinSize( newval.i_int );
2636 else if( !strcmp( psz_var, CFG_PREFIX "satwinsize" ))
2637 p_atmo_config->setLiveView_SatWinSize( newval.i_int );
2639 else if( !strcmp( psz_var, CFG_PREFIX "framedelay" ))
2640 p_atmo_config->setLiveView_FrameDelay( newval.i_int );
2642 else if( !strcmp( psz_var, CFG_PREFIX "whiteadj" ))
2643 p_atmo_config->setUseSoftwareWhiteAdj( newval.b_bool );
2645 else if( !strcmp( psz_var, CFG_PREFIX "white-red" ))
2646 p_atmo_config->setWhiteAdjustment_Red( newval.i_int );
2648 else if( !strcmp( psz_var, CFG_PREFIX "white-green" ))
2649 p_atmo_config->setWhiteAdjustment_Green( newval.i_int );
2651 else if( !strcmp( psz_var, CFG_PREFIX "white-blue" ))
2652 p_atmo_config->setWhiteAdjustment_Blue( newval.i_int );
2656 vlc_mutex_unlock( &p_sys->filter_lock );
2661 static void AddAtmoSettingsVariablesCallbacks(filter_t *p_filter)
2663 var_AddCallback( p_filter, CFG_PREFIX "filtermode",
2664 AtmoSettingsCallback, p_filter );
2665 var_AddCallback( p_filter, CFG_PREFIX "percentnew",
2666 AtmoSettingsCallback, p_filter );
2669 var_AddCallback( p_filter, CFG_PREFIX "meanlength",
2670 AtmoSettingsCallback, p_filter );
2671 var_AddCallback( p_filter, CFG_PREFIX "meanthreshold",
2672 AtmoSettingsCallback, p_filter );
2674 var_AddCallback( p_filter, CFG_PREFIX "edgeweightning",
2675 AtmoSettingsCallback, p_filter );
2676 var_AddCallback( p_filter, CFG_PREFIX "brightness",
2677 AtmoSettingsCallback, p_filter );
2678 var_AddCallback( p_filter, CFG_PREFIX "darknesslimit",
2679 AtmoSettingsCallback, p_filter );
2681 var_AddCallback( p_filter, CFG_PREFIX "huewinsize",
2682 AtmoSettingsCallback, p_filter );
2683 var_AddCallback( p_filter, CFG_PREFIX "satwinsize",
2684 AtmoSettingsCallback, p_filter );
2685 var_AddCallback( p_filter, CFG_PREFIX "framedelay",
2686 AtmoSettingsCallback, p_filter );
2689 var_AddCallback( p_filter, CFG_PREFIX "whiteadj",
2690 AtmoSettingsCallback, p_filter );
2691 var_AddCallback( p_filter, CFG_PREFIX "white-red",
2692 AtmoSettingsCallback, p_filter );
2693 var_AddCallback( p_filter, CFG_PREFIX "white-green",
2694 AtmoSettingsCallback, p_filter );
2695 var_AddCallback( p_filter, CFG_PREFIX "white-blue",
2696 AtmoSettingsCallback, p_filter );
2698 var_AddCallback( p_filter, CFG_PREFIX "showdots",
2699 AtmoSettingsCallback, p_filter );
2703 static void DelAtmoSettingsVariablesCallbacks( filter_t *p_filter )
2706 var_DelCallback( p_filter, CFG_PREFIX "filtermode",
2707 AtmoSettingsCallback, p_filter );
2709 var_DelCallback( p_filter, CFG_PREFIX "percentnew",
2710 AtmoSettingsCallback, p_filter );
2711 var_DelCallback( p_filter, CFG_PREFIX "meanlength",
2712 AtmoSettingsCallback, p_filter );
2713 var_DelCallback( p_filter, CFG_PREFIX "meanthreshold",
2714 AtmoSettingsCallback, p_filter );
2716 var_DelCallback( p_filter, CFG_PREFIX "edgeweightning",
2717 AtmoSettingsCallback, p_filter );
2718 var_DelCallback( p_filter, CFG_PREFIX "brightness",
2719 AtmoSettingsCallback, p_filter );
2720 var_DelCallback( p_filter, CFG_PREFIX "darknesslimit",
2721 AtmoSettingsCallback, p_filter );
2723 var_DelCallback( p_filter, CFG_PREFIX "huewinsize",
2724 AtmoSettingsCallback, p_filter );
2725 var_DelCallback( p_filter, CFG_PREFIX "satwinsize",
2726 AtmoSettingsCallback, p_filter );
2727 var_DelCallback( p_filter, CFG_PREFIX "framedelay",
2728 AtmoSettingsCallback, p_filter );
2731 var_DelCallback( p_filter, CFG_PREFIX "whiteadj",
2732 AtmoSettingsCallback, p_filter );
2733 var_DelCallback( p_filter, CFG_PREFIX "white-red",
2734 AtmoSettingsCallback, p_filter );
2735 var_DelCallback( p_filter, CFG_PREFIX "white-green",
2736 AtmoSettingsCallback, p_filter );
2737 var_DelCallback( p_filter, CFG_PREFIX "white-blue",
2738 AtmoSettingsCallback, p_filter );
2740 var_DelCallback( p_filter, CFG_PREFIX "showdots",
2741 AtmoSettingsCallback, p_filter );
2746 #if defined(__ATMO_DEBUG__)
2747 static void atmo_parse_crop(char *psz_cropconfig,
2748 video_format_t fmt_in,
2749 video_format_t fmt_render,
2750 int &i_visible_width, int &i_visible_height,
2751 int &i_x_offset, int &i_y_offset )
2753 int64_t i_aspect_num, i_aspect_den;
2754 unsigned int i_width, i_height;
2756 i_visible_width = fmt_in.i_visible_width;
2757 i_visible_height = fmt_in.i_visible_height;
2758 i_x_offset = fmt_in.i_x_offset;
2759 i_y_offset = fmt_in.i_y_offset;
2761 char *psz_end = NULL, *psz_parser = strchr( psz_cropconfig, ':' );
2764 /* We're using the 3:4 syntax */
2765 i_aspect_num = strtol( psz_cropconfig, &psz_end, 10 );
2766 if( psz_end == psz_cropconfig || !i_aspect_num ) return;
2768 i_aspect_den = strtol( ++psz_parser, &psz_end, 10 );
2769 if( psz_end == psz_parser || !i_aspect_den ) return;
2771 i_width = fmt_in.i_sar_den * fmt_render.i_visible_height *
2772 i_aspect_num / i_aspect_den / fmt_in.i_sar_num;
2774 i_height = fmt_render.i_visible_width*fmt_in.i_sar_num *
2775 i_aspect_den / i_aspect_num / fmt_in.i_sar_den;
2777 if( i_width < fmt_render.i_visible_width )
2779 i_x_offset = fmt_render.i_x_offset +
2780 (fmt_render.i_visible_width - i_width) / 2;
2781 i_visible_width = i_width;
2785 i_y_offset = fmt_render.i_y_offset +
2786 (fmt_render.i_visible_height - i_height) / 2;
2787 i_visible_height = i_height;
2792 psz_parser = strchr( psz_cropconfig, 'x' );
2795 /* Maybe we're using the <width>x<height>+<left>+<top> syntax */
2796 unsigned int i_crop_width, i_crop_height, i_crop_top, i_crop_left;
2798 i_crop_width = strtol( psz_cropconfig, &psz_end, 10 );
2799 if( psz_end != psz_parser ) return;
2801 psz_parser = strchr( ++psz_end, '+' );
2802 i_crop_height = strtol( psz_end, &psz_end, 10 );
2803 if( psz_end != psz_parser ) return;
2805 psz_parser = strchr( ++psz_end, '+' );
2806 i_crop_left = strtol( psz_end, &psz_end, 10 );
2807 if( psz_end != psz_parser ) return;
2810 i_crop_top = strtol( psz_end, &psz_end, 10 );
2811 if( *psz_end != '\0' ) return;
2813 i_width = i_crop_width;
2814 i_visible_width = i_width;
2816 i_height = i_crop_height;
2817 i_visible_height = i_height;
2819 i_x_offset = i_crop_left;
2820 i_y_offset = i_crop_top;
2824 /* Maybe we're using the <left>+<top>+<right>+<bottom> syntax */
2825 unsigned int i_crop_top, i_crop_left, i_crop_bottom, i_crop_right;
2827 psz_parser = strchr( psz_cropconfig, '+' );
2828 i_crop_left = strtol( psz_cropconfig, &psz_end, 10 );
2829 if( psz_end != psz_parser ) return;
2831 psz_parser = strchr( ++psz_end, '+' );
2832 i_crop_top = strtol( psz_end, &psz_end, 10 );
2833 if( psz_end != psz_parser ) return;
2835 psz_parser = strchr( ++psz_end, '+' );
2836 i_crop_right = strtol( psz_end, &psz_end, 10 );
2837 if( psz_end != psz_parser ) return;
2840 i_crop_bottom = strtol( psz_end, &psz_end, 10 );
2841 if( *psz_end != '\0' ) return;
2843 i_width = fmt_render.i_visible_width - i_crop_left - i_crop_right;
2844 i_visible_width = i_width;
2846 i_height = fmt_render.i_visible_height - i_crop_top - i_crop_bottom;
2847 i_visible_height = i_height;
2849 i_x_offset = i_crop_left;
2850 i_y_offset = i_crop_top;