1 /*****************************************************************************
2 * atmo.cpp : "Atmo Light" video filter
3 *****************************************************************************
4 * Copyright (C) 2000-2006 VLC authors and VideoLAN
7 * Authors: André Weber (WeberAndre@gmx.de)
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
31 #define __STDC_FORMAT_MACROS 1
32 #include <stdlib.h> /* malloc(), free() */
34 #include <math.h> /* sin(), cos() */
37 // #define __ATMO_DEBUG__
40 #include <vlc_common.h>
41 #include <vlc_plugin.h>
44 #include <vlc_filter.h>
45 #include <vlc_atomic.h>
46 #include <vlc_charset.h>
48 #include "../filter_picture.h"
51 #include "AtmoDynData.h"
52 #include "AtmoLiveView.h"
53 #include "AtmoTools.h"
54 #include "AtmoExternalCaptureInput.h"
55 #include "AtmoConfig.h"
56 #include "AtmoConnection.h"
57 #include "AtmoClassicConnection.h"
60 /*****************************************************************************
62 *****************************************************************************/
63 /* directly to vlc related functions required that the module is accepted */
64 static int CreateFilter ( vlc_object_t * );
65 static void DestroyFilter ( vlc_object_t * );
66 static picture_t * Filter( filter_t *, picture_t *);
68 /* callback for atmo settings variables whose change
69 should be immediately realized and applied to output
71 static void DelAtmoSettingsVariablesCallbacks(filter_t *);
72 static void AddAtmoSettingsVariablesCallbacks(filter_t *);
73 static int AtmoSettingsCallback(vlc_object_t *, char const *,
74 vlc_value_t, vlc_value_t, void *);
77 #if defined(__ATMO_DEBUG__)
78 static void atmo_parse_crop(char *psz_cropconfig,
79 video_format_t fmt_in,
80 video_format_t fmt_render,
82 int &i_visible_height,
88 /* function to shutdown the fade thread which is started on pause*/
89 static void CheckAndStopFadeThread(filter_t *);
91 /* extracts a small RGB (BGR) Image from an YUV image */
92 static void ExtractMiniImage_YUV(filter_sys_t *, picture_t *, uint8_t *);
94 #if defined(__ATMO_DEBUG__)
95 void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename);
98 /*****************************************************************************
99 * External Prototypes for the AtmoCtrlLib.DLL
100 *****************************************************************************/
102 * if effectmode = emLivePicture then the source could be GDI (Screencapture)
103 * or External - this means another application delivers Pixeldata to AtmoWin
104 * Clientsoftware through AtmoCtrlLib.DLL and the COM Api
107 #define lvsExternal 1
109 #define CLASSIC_ATMO_NUM_ZONES 5
113 strings for settings menus and hints
115 #define MODULE_DESCRIPTION N_ ( \
116 "This module allows controlling an so called AtmoLight device "\
117 "connected to your computer.\n"\
118 "AtmoLight is the homegrown version of what Philips calls AmbiLight.\n"\
119 "If you need further information feel free to visit us at\n\n"\
120 "http://www.vdr-wiki.de/wiki/index.php/Atmo-plugin\n"\
121 "http://www.vdr-wiki.de/wiki/index.php/AtmoWin\n\n"\
122 "You can find there detailed descriptions on how to build it for yourself "\
123 "and where to get the required parts.\n" \
124 "You can also have a look at pictures and some movies showing such a device " \
127 #define DRIVER_TEXT N_("Device type")
128 #define DRIVER_LONGTEXT N_("Choose your preferred hardware from " \
129 "the list, or choose AtmoWin Software " \
130 "to delegate processing to the external " \
131 "process - with more options")
133 static const int pi_device_type_values[] = {
134 #if defined( _WIN32 )
135 0, /* use AtmoWinA.exe userspace driver */
137 1, /* AtmoLight classic */
138 2, /* Quattro AtmoLight */
140 4, /* MoMoLight device */
143 static const char *const ppsz_device_type_descriptions[] = {
144 #if defined( _WIN32 )
145 N_("AtmoWin Software"),
147 N_("Classic AtmoLight"),
148 N_("Quattro AtmoLight"),
154 #define DMX_CHANNELS_TEXT N_("Count of AtmoLight channels")
155 #define DMX_CHANNELS_LONGTEXT N_("How many AtmoLight channels, should be " \
156 "emulated with that DMX device")
157 #define DMX_CHBASE_TEXT N_("DMX address for each channel")
158 #define DMX_CHBASE_LONGTEXT N_("Define here the DMX base address for each " \
159 "channel use , or ; to separate the values")
161 #define MOMO_CHANNELS_TEXT N_("Count of channels")
162 #define MOMO_CHANNELS_LONGTEXT N_("Depending on your MoMoLight hardware " \
163 "choose 3 or 4 channels")
165 #define FNORDLICHT_AMOUNT_TEXT N_("Count of fnordlicht's")
166 #define FNORDLICHT_AMOUNT_LONGTEXT N_("Depending on the amount your " \
167 "fnordlicht hardware " \
168 "choose 1 to 254 channels")
170 #if defined( _WIN32 )
171 # define DEFAULT_DEVICE 0
173 # define DEFAULT_DEVICE 1
176 #if defined( __ATMO_DEBUG__ )
177 # define SAVEFRAMES_TEXT N_("Save Debug Frames")
178 # define SAVEFRAMES_LONGTEXT N_("Write every 128th miniframe to a folder.")
179 # define FRAMEPATH_TEXT N_("Debug Frame Folder")
180 # define FRAMEPATH_LONGTEXT N_("The path where the debugframes " \
184 #define WIDTH_TEXT N_("Extracted Image Width")
185 #define WIDTH_LONGTEXT N_("The width of the mini image for " \
186 "further processing (64 is default)")
188 #define HEIGHT_TEXT N_("Extracted Image Height")
189 #define HEIGHT_LONGTEXT N_("The height of the mini image for " \
190 "further processing (48 is default)")
192 #define SHOW_DOTS_TEXT N_("Mark analyzed pixels")
193 #define SHOW_DOTS_LONGTEXT N_("makes the sample grid visible on screen as "\
196 #define PCOLOR_TEXT N_("Color when paused")
197 #define PCOLOR_LONGTEXT N_("Set the color to show if the user " \
198 "pauses the video. (Have light to get " \
200 #define PCOLOR_RED_TEXT N_("Pause-Red")
201 #define PCOLOR_RED_LONGTEXT N_("Red component of the pause color")
202 #define PCOLOR_GREEN_TEXT N_("Pause-Green")
203 #define PCOLOR_GREEN_LONGTEXT N_("Green component of the pause color")
204 #define PCOLOR_BLUE_TEXT N_("Pause-Blue")
205 #define PCOLOR_BLUE_LONGTEXT N_("Blue component of the pause color")
206 #define FADESTEPS_TEXT N_("Pause-Fadesteps")
207 #define FADESTEPS_LONGTEXT N_("Number of steps to change current color " \
208 "to pause color (each step takes 40ms)")
210 #define ECOLOR_RED_TEXT N_("End-Red")
211 #define ECOLOR_RED_LONGTEXT N_("Red component of the shutdown color")
212 #define ECOLOR_GREEN_TEXT N_("End-Green")
213 #define ECOLOR_GREEN_LONGTEXT N_("Green component of the shutdown color")
214 #define ECOLOR_BLUE_TEXT N_("End-Blue")
215 #define ECOLOR_BLUE_LONGTEXT N_("Blue component of the shutdown color")
216 #define EFADESTEPS_TEXT N_("End-Fadesteps")
217 #define EFADESTEPS_LONGTEXT N_("Number of steps to change current color to " \
218 "end color for dimming up the light in cinema " \
219 "style... (each step takes 40ms)")
221 #define ZONE_TOP_TEXT N_("Number of zones on top")
222 #define ZONE_TOP_LONGTEXT N_("Number of zones on the top of the screen")
223 #define ZONE_BOTTOM_TEXT N_("Number of zones on bottom")
224 #define ZONE_BOTTOM_LONGTEXT N_("Number of zones on the bottom of the screen")
225 #define ZONE_LR_TEXT N_("Zones on left / right side")
226 #define ZONE_LR_LONGTEXT N_("left and right side having always the " \
227 "same number of zones")
228 #define ZONE_SUMMARY_TEXT N_("Calculate a average zone")
229 #define ZONE_SUMMARY_LONGTEXT N_("it contains the average of all pixels " \
230 "in the sample image (only useful for " \
231 "single channel AtmoLight)")
234 #define USEWHITEADJ_TEXT N_("Use Software White adjust")
235 #define USEWHITEADJ_LONGTEXT N_("Should the buildin driver do a white " \
236 "adjust or your LED stripes? recommend.")
237 #define WHITE_RED_TEXT N_("White Red")
238 #define WHITE_RED_LONGTEXT N_("Red value of a pure white on your "\
240 #define WHITE_GREEN_TEXT N_("White Green")
241 #define WHITE_GREEN_LONGTEXT N_("Green value of a pure white on your "\
243 #define WHITE_BLUE_TEXT N_("White Blue")
244 #define WHITE_BLUE_LONGTEXT N_("Blue value of a pure white on your "\
247 #define SERIALDEV_TEXT N_("Serial Port/Device")
248 #define SERIALDEV_LONGTEXT N_("Name of the serial port where the AtmoLight "\
249 "controller is attached to.\n" \
250 "On Windows usually something like COM1 or " \
251 "COM2. On Linux /dev/ttyS01 f.e.")
253 #define EDGE_TEXT N_("Edge weightning")
254 #define EDGE_LONGTEXT N_("Increasing this value will result in color "\
255 "more depending on the border of the frame.")
256 #define BRIGHTNESS_TEXT N_("Brightness")
257 #define BRIGHTNESS_LONGTEXT N_("Overall brightness of your LED stripes")
258 #define DARKNESS_TEXT N_("Darkness limit")
259 #define DARKNESS_LONGTEXT N_("Pixels with a saturation lower than this will "\
260 "be ignored. Should be greater than one for "\
261 "letterboxed videos.")
262 #define HUEWINSIZE_TEXT N_("Hue windowing")
263 #define HUEWINSIZE_LONGTEXT N_("Used for statistics.")
264 #define SATWINSIZE_TEXT N_("Sat windowing")
265 #define SATWINSIZE_LONGTEXT N_("Used for statistics.")
267 #define MEANLENGTH_TEXT N_("Filter length (ms)")
268 #define MEANLENGTH_LONGTEXT N_("Time it takes until a color is completely "\
269 "changed. This prevents flickering.")
270 #define MEANTHRESHOLD_TEXT N_("Filter threshold")
271 #define MEANTHRESHOLD_LONGTEXT N_("How much a color has to be changed for an "\
272 "immediate color change.")
273 #define MEANPERCENTNEW_TEXT N_("Filter smoothness (%)")
274 #define MEANPERCENTNEW_LONGTEXT N_("Filter Smoothness")
276 #define FILTERMODE_TEXT N_("Output Color filter mode")
277 #define FILTERMODE_LONGTEXT N_("defines the how the output color should " \
278 "be calculated based on previous color")
280 static const int pi_filtermode_values[] = {
285 static const char *const ppsz_filtermode_descriptions[] = {
291 #define FRAMEDELAY_TEXT N_("Frame delay (ms)")
292 #define FRAMEDELAY_LONGTEXT N_("Helps to get the video output and the light "\
293 "effects in sync. Values around 20ms should " \
297 #define CHANNEL_0_ASSIGN_TEXT N_("Channel 0: summary")
298 #define CHANNEL_1_ASSIGN_TEXT N_("Channel 1: left")
299 #define CHANNEL_2_ASSIGN_TEXT N_("Channel 2: right")
300 #define CHANNEL_3_ASSIGN_TEXT N_("Channel 3: top")
301 #define CHANNEL_4_ASSIGN_TEXT N_("Channel 4: bottom")
303 #define CHANNELASSIGN_LONGTEXT N_("Maps the hardware channel X to logical "\
304 "zone Y to fix wrong wiring :-)")
305 static const int pi_zone_assignment_values[] = {
313 static const char *const ppsz_zone_assignment_descriptions[] = {
315 N_("Zone 4:summary"),
321 #define CHANNELS_ASSIGN_TEXT N_("Channel / Zone Assignment")
322 #define CHANNELS_ASSIGN_LONGTEXT N_("for devices with more than five " \
323 "channels / zones write down here for each channel " \
324 "the zone number to show and separate the values with " \
325 ", or ; and use -1 to not use some channels. For the " \
326 "classic AtmoLight the sequence 4,3,1,0,2 would set the " \
327 "default channel/zone mapping. " \
328 "Having only two zones on top, and one zone on left and " \
329 "right and no summary zone the mapping for classic " \
330 "AtmoLight would be -1,3,2,1,0")
332 #define ZONE_0_GRADIENT_TEXT N_("Zone 0: Top gradient")
333 #define ZONE_1_GRADIENT_TEXT N_("Zone 1: Right gradient")
334 #define ZONE_2_GRADIENT_TEXT N_("Zone 2: Bottom gradient")
335 #define ZONE_3_GRADIENT_TEXT N_("Zone 3: Left gradient")
336 #define ZONE_4_GRADIENT_TEXT N_("Zone 4: Summary gradient")
337 #define ZONE_X_GRADIENT_LONG_TEXT N_("Defines a small bitmap with 64x48 "\
338 "pixels, containing a grayscale gradient")
340 #define GRADIENT_PATH_TEXT N_("Gradient bitmap searchpath")
341 #define GRADIENT_PATH_LONGTEXT N_("Now preferred option to assign gradient "\
342 "bitmaps, put them as zone_0.bmp, zone_1.bmp etc. into one folder and "\
343 "set the foldername here")
345 #if defined( _WIN32 )
346 # define ATMOWINEXE_TEXT N_("Filename of AtmoWin*.exe")
347 # define ATMOWINEXE_LONGTEXT N_("if you want the AtmoLight control "\
348 "software to be launched by VLC, enter the "\
349 "complete path of AtmoWinA.exe here.")
352 #define CFG_PREFIX "atmo-"
354 /*****************************************************************************
356 *****************************************************************************/
358 set_description( N_("AtmoLight Filter") )
359 set_help( MODULE_DESCRIPTION )
360 set_shortname( N_( "AtmoLight" ))
361 set_category( CAT_VIDEO )
362 set_subcategory( SUBCAT_VIDEO_VFILTER )
364 set_capability( "video filter2", 0 )
367 set_section( N_("Choose Devicetype and Connection" ), 0 )
369 add_integer( CFG_PREFIX "device", DEFAULT_DEVICE,
370 DRIVER_TEXT, DRIVER_LONGTEXT, false )
371 change_integer_list( pi_device_type_values,
372 ppsz_device_type_descriptions )
375 add_string(CFG_PREFIX "serialdev", "COM1",
376 SERIALDEV_TEXT, SERIALDEV_LONGTEXT, false )
378 on win32 the executeable external driver application
379 for automatic start if needed
381 add_loadfile(CFG_PREFIX "atmowinexe", NULL,
382 ATMOWINEXE_TEXT, ATMOWINEXE_LONGTEXT, false )
384 add_string(CFG_PREFIX "serialdev", "/dev/ttyUSB0",
385 SERIALDEV_TEXT, SERIALDEV_LONGTEXT, false )
389 color which is showed if you want durring pausing
390 your movie ... used for both buildin / external
392 set_section( N_("Illuminate the room with this color on pause" ), 0 )
393 add_bool(CFG_PREFIX "usepausecolor", false,
394 PCOLOR_TEXT, PCOLOR_LONGTEXT, false)
395 add_integer_with_range(CFG_PREFIX "pcolor-red", 0, 0, 255,
396 PCOLOR_RED_TEXT, PCOLOR_RED_LONGTEXT, false)
397 add_integer_with_range(CFG_PREFIX "pcolor-green", 0, 0, 255,
398 PCOLOR_GREEN_TEXT, PCOLOR_GREEN_LONGTEXT, false)
399 add_integer_with_range(CFG_PREFIX "pcolor-blue", 192, 0, 255,
400 PCOLOR_BLUE_TEXT, PCOLOR_BLUE_LONGTEXT, false)
401 add_integer_with_range(CFG_PREFIX "fadesteps", 50, 1, 250,
402 FADESTEPS_TEXT, FADESTEPS_LONGTEXT, false)
405 color which is showed if you finished watching your movie ...
406 used for both buildin / external
408 set_section( N_("Illuminate the room with this color on shutdown" ), 0 )
409 add_integer_with_range(CFG_PREFIX "ecolor-red", 192, 0, 255,
410 ECOLOR_RED_TEXT, ECOLOR_RED_LONGTEXT, false)
411 add_integer_with_range(CFG_PREFIX "ecolor-green", 192, 0, 255,
412 ECOLOR_GREEN_TEXT, ECOLOR_GREEN_LONGTEXT, false)
413 add_integer_with_range(CFG_PREFIX "ecolor-blue", 192, 0, 255,
414 ECOLOR_BLUE_TEXT, ECOLOR_BLUE_LONGTEXT, false)
415 add_integer_with_range(CFG_PREFIX "efadesteps", 50, 1, 250,
416 EFADESTEPS_TEXT, EFADESTEPS_LONGTEXT, false)
419 set_section( N_("DMX options" ), 0 )
420 add_integer_with_range(CFG_PREFIX "dmx-channels", 5, 1, 64,
421 DMX_CHANNELS_TEXT, DMX_CHANNELS_LONGTEXT, false)
422 add_string(CFG_PREFIX "dmx-chbase", "0,3,6,9,12",
423 DMX_CHBASE_TEXT, DMX_CHBASE_LONGTEXT, false )
425 set_section( N_("MoMoLight options" ), 0 )
426 add_integer_with_range(CFG_PREFIX "momo-channels", 3, 3, 4,
427 MOMO_CHANNELS_TEXT, MOMO_CHANNELS_LONGTEXT, false)
429 /* 2,2,4 means 2 is the default value, 1 minimum amount,
432 set_section( N_("fnordlicht options" ), 0 )
433 add_integer_with_range(CFG_PREFIX "fnordlicht-amount", 2, 1, 254,
434 FNORDLICHT_AMOUNT_TEXT,
435 FNORDLICHT_AMOUNT_LONGTEXT, false)
439 instead of redefining the original AtmoLight zones with gradient
440 bitmaps, we can now define the layout of the zones useing these
441 parameters - the function with the gradient bitmaps would still
442 work (but for most cases its no longer required)
444 short description whats this means - f.e. the classic atmo would
446 zones-top = 1 - zone 0
447 zones-lr = 1 - zone 1 und zone 3
448 zones-bottom = 1 - zone 2
449 zone-summary = true - zone 4
457 the zone numbers will be counted clockwise starting at top / left
458 if you want to split the light at the top, without having a bottom zone
459 (which is my private config)
461 zones-top = 2 - zone 0, zone 1
462 zones-lr = 1 - zone 2 und zone 3
474 set_section( N_("Zone Layout for the build-in Atmo" ), 0 )
475 add_integer_with_range(CFG_PREFIX "zones-top", 1, 0, 16,
476 ZONE_TOP_TEXT, ZONE_TOP_LONGTEXT, false)
477 add_integer_with_range(CFG_PREFIX "zones-bottom", 1, 0, 16,
478 ZONE_BOTTOM_TEXT, ZONE_BOTTOM_LONGTEXT, false)
479 add_integer_with_range(CFG_PREFIX "zones-lr", 1, 0, 16,
480 ZONE_LR_TEXT, ZONE_LR_LONGTEXT, false)
481 add_bool(CFG_PREFIX "zone-summary", false,
482 ZONE_SUMMARY_TEXT, ZONE_SUMMARY_LONGTEXT, false)
485 settings only for the buildin driver (if external driver app is used
486 these parameters are ignored.)
488 definition of parameters for the buildin filter ...
490 set_section( N_("Settings for the built-in Live Video Processor only" ), 0 )
492 add_integer_with_range(CFG_PREFIX "edgeweightning", 3, 1, 30,
493 EDGE_TEXT, EDGE_LONGTEXT, false)
495 add_integer_with_range(CFG_PREFIX "brightness", 100, 50, 300,
496 BRIGHTNESS_TEXT, BRIGHTNESS_LONGTEXT, false)
498 add_integer_with_range(CFG_PREFIX "darknesslimit", 3, 0, 10,
499 DARKNESS_TEXT, DARKNESS_LONGTEXT, false)
501 add_integer_with_range(CFG_PREFIX "huewinsize", 3, 0, 5,
502 HUEWINSIZE_TEXT, HUEWINSIZE_LONGTEXT, false)
504 add_integer_with_range(CFG_PREFIX "satwinsize", 3, 0, 5,
505 SATWINSIZE_TEXT, SATWINSIZE_LONGTEXT, false)
507 add_integer(CFG_PREFIX "filtermode", (int)afmCombined,
508 FILTERMODE_TEXT, FILTERMODE_LONGTEXT, false )
510 change_integer_list(pi_filtermode_values, ppsz_filtermode_descriptions )
512 add_integer_with_range(CFG_PREFIX "meanlength", 300, 300, 5000,
513 MEANLENGTH_TEXT, MEANLENGTH_LONGTEXT, false)
515 add_integer_with_range(CFG_PREFIX "meanthreshold", 40, 1, 100,
516 MEANTHRESHOLD_TEXT, MEANTHRESHOLD_LONGTEXT, false)
518 add_integer_with_range(CFG_PREFIX "percentnew", 50, 1, 100,
519 MEANPERCENTNEW_TEXT, MEANPERCENTNEW_LONGTEXT, false)
521 add_integer_with_range(CFG_PREFIX "framedelay", 18, 0, 200,
522 FRAMEDELAY_TEXT, FRAMEDELAY_LONGTEXT, false)
525 output channel reordering
527 set_section( N_("Change channel assignment (fixes wrong wiring)" ), 0 )
528 add_integer( CFG_PREFIX "channel_0", 4,
529 CHANNEL_0_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
530 change_integer_list( pi_zone_assignment_values,
531 ppsz_zone_assignment_descriptions )
533 add_integer( CFG_PREFIX "channel_1", 3,
534 CHANNEL_1_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
535 change_integer_list( pi_zone_assignment_values,
536 ppsz_zone_assignment_descriptions )
538 add_integer( CFG_PREFIX "channel_2", 1,
539 CHANNEL_2_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
540 change_integer_list( pi_zone_assignment_values,
541 ppsz_zone_assignment_descriptions )
543 add_integer( CFG_PREFIX "channel_3", 0,
544 CHANNEL_3_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
545 change_integer_list( pi_zone_assignment_values,
546 ppsz_zone_assignment_descriptions )
548 add_integer( CFG_PREFIX "channel_4", 2,
549 CHANNEL_4_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
550 change_integer_list( pi_zone_assignment_values,
551 ppsz_zone_assignment_descriptions )
553 add_string(CFG_PREFIX "channels", "",
554 CHANNELS_ASSIGN_TEXT, CHANNELS_ASSIGN_LONGTEXT, false )
558 LED color white calibration
560 set_section( N_("Adjust the white light to your LED stripes" ), 0 )
561 add_bool(CFG_PREFIX "whiteadj", true,
562 USEWHITEADJ_TEXT, USEWHITEADJ_LONGTEXT, false)
563 add_integer_with_range(CFG_PREFIX "white-red", 255, 0, 255,
564 WHITE_RED_TEXT, WHITE_RED_LONGTEXT, false)
566 add_integer_with_range(CFG_PREFIX "white-green", 255, 0, 255,
567 WHITE_GREEN_TEXT, WHITE_GREEN_LONGTEXT, false)
569 add_integer_with_range(CFG_PREFIX "white-blue", 255, 0, 255,
570 WHITE_BLUE_TEXT, WHITE_BLUE_LONGTEXT, false)
571 /* end of definition of parameter for the buildin filter ... part 1 */
575 only for buildin (external has own definition) per default the calucation
576 used linear gradients for assigning a priority to the pixel - depending
577 how near they are to the border ...for changing this you can create 64x48
578 Pixel BMP files - which contain your own grayscale... (you can produce funny
579 effects with this...) the images MUST not compressed, should have 24-bit per
580 pixel, or a simple 256 color grayscale palette
582 set_section( N_("Change gradients" ), 0 )
583 add_loadfile(CFG_PREFIX "gradient_zone_0", NULL,
584 ZONE_0_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
585 add_loadfile(CFG_PREFIX "gradient_zone_1", NULL,
586 ZONE_1_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
587 add_loadfile(CFG_PREFIX "gradient_zone_2", NULL,
588 ZONE_2_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
589 add_loadfile(CFG_PREFIX "gradient_zone_3", NULL,
590 ZONE_3_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
591 add_loadfile(CFG_PREFIX "gradient_zone_4", NULL,
592 ZONE_4_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
593 add_directory(CFG_PREFIX "gradient_path", NULL,
594 GRADIENT_PATH_TEXT, GRADIENT_PATH_LONGTEXT, false )
596 #if defined(__ATMO_DEBUG__)
597 add_bool(CFG_PREFIX "saveframes", false,
598 SAVEFRAMES_TEXT, SAVEFRAMES_LONGTEXT, false)
599 add_string(CFG_PREFIX "framepath", "",
600 FRAMEPATH_TEXT, FRAMEPATH_LONGTEXT, false )
603 may be later if computers gets more power ;-) than now we increase
604 the samplesize from which we do the stats for output color calculation
606 add_integer_with_range(CFG_PREFIX "width", 64, 64, 512,
607 WIDTH_TEXT, WIDTH_LONGTEXT, true)
608 add_integer_with_range(CFG_PREFIX "height", 48, 48, 384,
609 HEIGHT_TEXT, HEIGHT_LONGTEXT, true)
610 add_bool(CFG_PREFIX "showdots", false,
611 SHOW_DOTS_TEXT, SHOW_DOTS_LONGTEXT, false)
612 add_shortcut( "atmo" )
613 set_callbacks( CreateFilter, DestroyFilter )
617 static const char *const ppsz_filter_options[] = {
672 #if defined(__ATMO_DEBUG__)
689 /*****************************************************************************
690 * fadethread_t: Color Fading Thread
691 *****************************************************************************
692 * changes slowly the color of the output if videostream gets paused...
693 *****************************************************************************
701 /* tell the thread which color should be the target of fading */
705 /* how many steps should happen until this */
710 static void *FadeToColorThread(void *);
713 /*****************************************************************************
714 * filter_sys_t: AtmoLight filter method descriptor
715 *****************************************************************************
716 * It describes the AtmoLight specific properties of an video filter.
717 *****************************************************************************/
721 special for the access of the p_fadethread member all other members
722 need no special protection so far!
724 vlc_mutex_t filter_lock;
727 int32_t i_AtmoOldEffect;
730 int32_t i_device_type;
734 int32_t i_atmo_width;
735 int32_t i_atmo_height;
736 /* used to disable fadeout if less than 50 frames are processed
737 used to avoid long time waiting when switch quickly between
738 deinterlaceing modes, where the output filter chains is rebuild
741 int32_t i_frames_processed;
743 #if defined(__ATMO_DEBUG__)
745 uint32_t ui_frame_counter;
746 char sz_framepath[MAX_PATH];
749 /* light color on movie finish ... */
750 uint8_t ui_endcolor_red;
751 uint8_t ui_endcolor_green;
752 uint8_t ui_endcolor_blue;
755 fadethread_t *p_fadethread;
757 /* Variables for buildin driver only... */
759 /* is only present and initialized if the internal driver is used*/
760 CAtmoConfig *p_atmo_config;
761 /* storage for temporal settings "volatile" */
762 CAtmoDynData *p_atmo_dyndata;
763 /* initialized for buildin driver with AtmoCreateTransferBuffers */
764 VLC_BITMAPINFOHEADER mini_image_format;
765 /* is only use buildin driver! */
766 uint8_t *p_atmo_transfer_buffer;
767 /* end buildin driver */
770 contains the real output size of the video calculated on
771 change event of the variable "crop" from vout
773 int32_t i_crop_x_offset;
774 int32_t i_crop_y_offset;
775 int32_t i_crop_width;
776 int32_t i_crop_height;
778 void (*pf_extract_mini_image) (filter_sys_t *p_sys,
780 uint8_t *p_transfer_dest);
782 #if defined( _WIN32 )
783 /* External Library as wrapper arround COM Stuff */
784 HINSTANCE h_AtmoCtrl;
785 int32_t (*pf_ctrl_atmo_initialize) (void);
786 void (*pf_ctrl_atmo_finalize) (int32_t what);
787 int32_t (*pf_ctrl_atmo_switch_effect) (int32_t);
788 int32_t (*pf_ctrl_atmo_set_live_source) (int32_t);
789 void (*pf_ctrl_atmo_create_transfer_buffers) (int32_t, int32_t,
791 uint8_t* (*pf_ctrl_atmo_lock_transfer_buffer) (void);
792 void (*pf_ctrl_atmo_send_pixel_data) (void);
793 void (*pf_ctrl_atmo_get_image_size)(int32_t *,int32_t *);
798 initialize previously configured Atmo Light environment
799 - if internal is enabled try to access the device on the serial port
800 - if not internal is enabled and we are on win32 try to initialize
801 the previously loaded DLL ...
803 Return Values may be: -1 (failed for some reason - filter will be disabled)
806 static int32_t AtmoInitialize(filter_t *p_filter, bool b_for_thread)
808 filter_sys_t *p_sys = p_filter->p_sys;
809 if(p_sys->p_atmo_config)
814 /* setup Output Threads ... */
815 msg_Dbg( p_filter, "open atmo device...");
816 if(CAtmoTools::RecreateConnection(p_sys->p_atmo_dyndata)
821 msg_Err( p_filter,"failed to open atmo device, "\
822 "some other software/driver may use it?");
826 } else if(p_sys->pf_ctrl_atmo_initialize)
828 /* on win32 with active ctrl dll */
829 return p_sys->pf_ctrl_atmo_initialize();
836 prepare the shutdown of the effect threads,
837 for build in filter - close the serialport after finishing the threads...
838 cleanup possible loaded DLL...
840 static void AtmoFinalize(filter_t *p_filter, int32_t what)
842 filter_sys_t *p_sys = p_filter->p_sys;
843 if(p_sys->p_atmo_config)
847 CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
850 p_atmo_dyndata->LockCriticalSection();
852 CAtmoInput *p_input = p_atmo_dyndata->getLiveInput();
853 p_atmo_dyndata->setLiveInput( NULL );
856 p_input->Terminate();
858 msg_Dbg( p_filter, "input thread died peacefully");
861 CThread *p_effect_thread = p_atmo_dyndata->getEffectThread();
862 p_atmo_dyndata->setEffectThread(NULL);
863 if(p_effect_thread != NULL)
866 forced the thread to die...
867 and wait for termination of the thread
869 p_effect_thread->Terminate();
870 delete p_effect_thread;
871 msg_Dbg( p_filter, "effect thread died peacefully");
874 CAtmoPacketQueue *p_queue =
875 p_atmo_dyndata->getLivePacketQueue();
876 p_atmo_dyndata->setLivePacketQueue( NULL );
880 msg_Dbg( p_filter, "packetqueue removed");
884 close serial port if it is open (all OS specific is inside
885 CAtmoSerialConnection implemented / defined)
887 CAtmoConnection *p_atmo_connection =
888 p_atmo_dyndata->getAtmoConnection();
889 p_atmo_dyndata->setAtmoConnection(NULL);
890 if(p_atmo_connection) {
891 p_atmo_connection->CloseConnection();
892 delete p_atmo_connection;
894 p_atmo_dyndata->UnLockCriticalSection();
898 } else if(p_sys->pf_ctrl_atmo_finalize)
900 /* on win32 with active ctrl dll */
901 p_sys->pf_ctrl_atmo_finalize(what);
907 switch the current light effect to LiveView
909 static int32_t AtmoSwitchEffect(filter_t *p_filter, int32_t newMode)
911 filter_sys_t *p_sys = p_filter->p_sys;
913 msg_Dbg( p_filter, "AtmoSwitchEffect %d", newMode );
915 if(p_sys->p_atmo_config)
917 return CAtmoTools::SwitchEffect(p_sys->p_atmo_dyndata, emLivePicture);
919 } else if(p_sys->pf_ctrl_atmo_switch_effect)
921 /* on win32 with active ctrl dll */
922 return p_sys->pf_ctrl_atmo_switch_effect( newMode );
929 set the current live picture source, does only something on win32,
930 with the external libraries - if the buildin effects are used nothing
933 static int32_t AtmoSetLiveSource(filter_t *p_filter, int32_t newSource)
935 filter_sys_t *p_sys = p_filter->p_sys;
937 msg_Dbg( p_filter, "AtmoSetLiveSource %d", newSource );
939 if(p_sys->p_atmo_config)
944 doesnt know different sources so this
945 function call would just do nothing special
949 } else if(p_sys->pf_ctrl_atmo_set_live_source)
951 /* on win32 with active ctrl dll */
952 return p_sys->pf_ctrl_atmo_set_live_source(newSource);
959 setup the pixel transferbuffers which is used to transfer pixeldata from
960 the filter to the effect thread, and possible accross the process
961 boundaries on win32, with the external DLL
963 static void AtmoCreateTransferBuffers(filter_t *p_filter,
965 int32_t bytePerPixel,
969 filter_sys_t *p_sys = p_filter->p_sys;
970 if(p_sys->p_atmo_config)
973 we need a buffer where the image is stored (only for transfer
974 to the processing thread)
976 free( p_sys->p_atmo_transfer_buffer );
978 p_sys->p_atmo_transfer_buffer = (uint8_t *)malloc(bytePerPixel *
981 memset(&p_sys->mini_image_format,0,sizeof(VLC_BITMAPINFOHEADER));
983 p_sys->mini_image_format.biSize = sizeof(VLC_BITMAPINFOHEADER);
984 p_sys->mini_image_format.biWidth = width;
985 p_sys->mini_image_format.biHeight = height;
986 p_sys->mini_image_format.biBitCount = bytePerPixel*8;
987 p_sys->mini_image_format.biCompression = FourCC;
990 } else if(p_sys->pf_ctrl_atmo_create_transfer_buffers)
992 /* on win32 with active ctrl dll */
993 p_sys->pf_ctrl_atmo_create_transfer_buffers(FourCC,
1002 acquire the transfer buffer pointer the buildin version only
1003 returns the pointer to the allocated buffer ... the
1004 external version on win32 has to do some COM stuff to lock the
1005 Variant Byte array which is behind the buffer
1007 static uint8_t* AtmoLockTransferBuffer(filter_t *p_filter)
1009 filter_sys_t *p_sys = p_filter->p_sys;
1010 if(p_sys->p_atmo_config)
1012 return p_sys->p_atmo_transfer_buffer;
1014 } else if(p_sys->pf_ctrl_atmo_lock_transfer_buffer)
1016 /* on win32 with active ctrl dll */
1017 return p_sys->pf_ctrl_atmo_lock_transfer_buffer();
1024 send the content of current pixel buffer got with AtmoLockTransferBuffer
1025 to the processing threads
1026 - build in version - will forward the data to AtmoExternalCaptureInput Thread
1027 - win32 external - will do the same, but across the process boundaries via
1028 COM to the AtmoWinA.exe Process
1030 static void AtmoSendPixelData(filter_t *p_filter)
1032 filter_sys_t *p_sys = p_filter->p_sys;
1033 if(p_sys->p_atmo_config && p_sys->p_atmo_transfer_buffer)
1035 CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
1036 if(p_atmo_dyndata &&
1037 (p_atmo_dyndata->getLivePictureSource() == lpsExtern))
1040 the cast will go Ok because we are inside videolan there is only
1041 this kind of effect thread implemented!
1043 CAtmoExternalCaptureInput *p_atmo_external_capture_input_thread =
1044 (CAtmoExternalCaptureInput *)p_atmo_dyndata->getLiveInput();
1046 if(p_atmo_external_capture_input_thread)
1049 the same as above inside videolan only this single kind of
1050 input exists so we can cast without further tests!
1052 this call will do a 1:1 copy of this buffer, and wakeup
1053 the thread from normal sleeping
1055 p_atmo_external_capture_input_thread->
1056 DeliverNewSourceDataPaket(&p_sys->mini_image_format,
1057 p_sys->p_atmo_transfer_buffer);
1061 } else if(p_sys->pf_ctrl_atmo_send_pixel_data)
1063 /* on win32 with active ctrl dll */
1064 p_sys->pf_ctrl_atmo_send_pixel_data();
1068 msg_Warn( p_filter, "AtmoSendPixelData no method");
1073 Shutdown AtmoLight finally - is call from DestroyFilter
1074 does the cleanup restores the effectmode on the external Software
1075 (only win32) and possible setup the final light ...
1077 static void Atmo_Shutdown(filter_t *p_filter)
1079 filter_sys_t *p_sys = p_filter->p_sys;
1081 if(p_sys->b_enabled)
1083 msg_Dbg( p_filter, "shut down atmo!");
1085 if there is a still running show pause color thread kill him!
1087 CheckAndStopFadeThread(p_filter);
1089 // perpare spawn fadeing thread
1090 vlc_mutex_lock( &p_sys->filter_lock );
1093 fade to end color (in case of external AtmoWin Software
1094 assume that the static color will equal to this
1095 one to get a soft change and no flash!
1097 p_sys->b_pause_live = true;
1100 p_sys->p_fadethread = (fadethread_t *)calloc( 1, sizeof(fadethread_t) );
1101 p_sys->p_fadethread->p_filter = p_filter;
1102 p_sys->p_fadethread->ui_red = p_sys->ui_endcolor_red;
1103 p_sys->p_fadethread->ui_green = p_sys->ui_endcolor_green;
1104 p_sys->p_fadethread->ui_blue = p_sys->ui_endcolor_blue;
1105 if(p_sys->i_frames_processed < 50)
1106 p_sys->p_fadethread->i_steps = 1;
1108 p_sys->p_fadethread->i_steps = p_sys->i_endfadesteps;
1109 atomic_store(&p_sys->p_fadethread->abort, false);
1111 if( vlc_clone( &p_sys->p_fadethread->thread,
1113 p_sys->p_fadethread,
1114 VLC_THREAD_PRIORITY_LOW ) )
1116 msg_Err( p_filter, "cannot create FadeToColorThread" );
1117 free( p_sys->p_fadethread );
1118 p_sys->p_fadethread = NULL;
1119 vlc_mutex_unlock( &p_sys->filter_lock );
1123 vlc_mutex_unlock( &p_sys->filter_lock );
1125 /* wait for the thread... */
1126 vlc_join(p_sys->p_fadethread->thread, NULL);
1128 free(p_sys->p_fadethread);
1130 p_sys->p_fadethread = NULL;
1134 the following happens only useing the
1135 external AtmoWin Device Software
1137 if( !p_sys->p_atmo_config )
1139 if(p_sys->i_AtmoOldEffect != emLivePicture)
1140 AtmoSwitchEffect( p_filter, p_sys->i_AtmoOldEffect);
1142 AtmoSetLiveSource( p_filter, lvsGDI );
1145 /* close device connection etc. */
1146 AtmoFinalize(p_filter, 1);
1148 /* disable filter method .. */
1149 p_sys->b_enabled = false;
1154 depending on mode setup imagesize to 64x48(classic), or defined
1155 resolution of external atmowin.exe on windows
1157 static void Atmo_SetupImageSize(filter_t *p_filter)
1159 filter_sys_t *p_sys = p_filter->p_sys;
1161 size of extracted image by default 64x48 (other imagesizes are
1162 currently ignored by AtmoWin)
1164 p_sys->i_atmo_width = var_CreateGetIntegerCommand( p_filter,
1165 CFG_PREFIX "width");
1166 p_sys->i_atmo_height = var_CreateGetIntegerCommand( p_filter,
1167 CFG_PREFIX "height");
1169 if(p_sys->p_atmo_config)
1172 } else if(p_sys->pf_ctrl_atmo_get_image_size)
1174 /* on win32 with active ctrl dll */
1175 p_sys->pf_ctrl_atmo_get_image_size( &p_sys->i_atmo_width,
1176 &p_sys->i_atmo_height );
1180 msg_Dbg(p_filter,"sample image size %d * %d pixels", p_sys->i_atmo_width,
1181 p_sys->i_atmo_height);
1185 initialize the zone and channel mapping for the buildin atmolight adapter
1187 static void Atmo_SetupBuildZones(filter_t *p_filter)
1189 filter_sys_t *p_sys = p_filter->p_sys;
1191 p_sys->p_atmo_dyndata->LockCriticalSection();
1193 CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
1196 CAtmoChannelAssignment *p_channel_assignment =
1197 p_atmo_config->getChannelAssignment(0);
1199 // channel 0 - zone 4
1200 p_channel_assignment->setZoneIndex( 0, var_CreateGetIntegerCommand(
1201 p_filter, CFG_PREFIX "channel_0")
1204 // channel 1 - zone 3
1205 p_channel_assignment->setZoneIndex( 1, var_CreateGetIntegerCommand(
1206 p_filter, CFG_PREFIX "channel_1")
1209 // channel 2 - zone 1
1210 p_channel_assignment->setZoneIndex( 2, var_CreateGetIntegerCommand(
1211 p_filter, CFG_PREFIX "channel_2")
1214 // channel 3 - zone 0
1215 p_channel_assignment->setZoneIndex( 3, var_CreateGetIntegerCommand(
1216 p_filter, CFG_PREFIX "channel_3")
1219 // channel 4 - zone 2
1220 p_channel_assignment->setZoneIndex( 4, var_CreateGetIntegerCommand(
1221 p_filter, CFG_PREFIX "channel_4")
1224 char *psz_channels = var_CreateGetStringCommand(
1226 CFG_PREFIX "channels"
1228 if( !EMPTY_STR(psz_channels) )
1230 msg_Dbg( p_filter, "deal with new zone mapping %s", psz_channels );
1232 char *psz_temp = psz_channels;
1233 char *psz_start = psz_temp;
1236 if(*psz_temp == ',' || *psz_temp == ';')
1241 int zone = atoi( psz_start );
1243 zone >= p_channel_assignment->getSize()) {
1244 msg_Warn( p_filter, "Zone %d out of range -1..%d",
1245 zone, p_channel_assignment->getSize()-1 );
1247 p_channel_assignment->setZoneIndex( channel, zone );
1251 psz_start = psz_temp;
1259 process the rest of the string
1261 if( *psz_start && !*psz_temp )
1263 int zone = atoi( psz_start );
1265 zone >= p_channel_assignment->getSize()) {
1266 msg_Warn( p_filter, "Zone %d out of range -1..%d",
1267 zone, p_channel_assignment->getSize()-1 );
1269 p_channel_assignment->setZoneIndex( channel, zone );
1273 free( psz_channels );
1275 for(int i=0;i< p_channel_assignment->getSize() ;i++)
1276 msg_Info( p_filter, "map zone %d to hardware channel %d",
1277 p_channel_assignment->getZoneIndex( i ),
1280 p_sys->p_atmo_dyndata->getAtmoConnection()
1281 ->SetChannelAssignment( p_channel_assignment );
1288 calculate the default gradients for each zone!
1289 depending on the zone layout set before, this now
1290 supports also multiple gradients on each side
1291 (older versions could do this only with external
1294 p_sys->p_atmo_dyndata->CalculateDefaultZones();
1298 first try to load the old style defined gradient bitmaps
1299 this could only be done for the first five zones
1300 - should be deprecated -
1302 CAtmoZoneDefinition *p_zone;
1303 char psz_gradient_var_name[30];
1304 char *psz_gradient_file;
1305 for(int i=0;i<CLASSIC_ATMO_NUM_ZONES;i++)
1307 sprintf(psz_gradient_var_name, CFG_PREFIX "gradient_zone_%d", i);
1308 psz_gradient_file = var_CreateGetStringCommand(
1310 psz_gradient_var_name
1312 if( !EMPTY_STR(psz_gradient_file) )
1314 msg_Dbg( p_filter, "loading gradientfile %s for "\
1315 "zone %d", psz_gradient_file, i);
1317 p_zone = p_atmo_config->getZoneDefinition(i);
1320 int i_res = p_zone->LoadGradientFromBitmap(psz_gradient_file);
1322 if(i_res != ATMO_LOAD_GRADIENT_OK)
1324 msg_Err( p_filter,"failed to load gradient '%s' with "\
1325 "error %d",psz_gradient_file,i_res);
1329 free( psz_gradient_file );
1334 the new approach try to load a gradient bitmap for each zone
1335 from a previously defined folder containing
1340 char *psz_gradient_path = var_CreateGetStringCommand(
1342 CFG_PREFIX "gradient_path"
1344 if( EMPTY_STR(psz_gradient_path) )
1346 char *psz_file_name = (char *)malloc( strlen(psz_gradient_path) + 16 );
1347 assert( psz_file_name );
1349 for(int i=0; i < p_atmo_config->getZoneCount(); i++ )
1351 p_zone = p_atmo_config->getZoneDefinition(i);
1355 sprintf(psz_file_name, "%s%szone_%d.bmp",
1356 psz_gradient_path, DIR_SEP, i );
1358 int i_res = p_zone->LoadGradientFromBitmap( psz_file_name );
1360 if( i_res == ATMO_LOAD_GRADIENT_OK )
1362 msg_Dbg( p_filter, "loaded gradientfile %s for "\
1363 "zone %d", psz_file_name, i);
1366 if( (i_res != ATMO_LOAD_GRADIENT_OK) &&
1367 (i_res != ATMO_LOAD_GRADIENT_FILENOTFOND) )
1369 msg_Err( p_filter,"failed to load gradient '%s' with "\
1370 "error %d",psz_file_name,i_res);
1375 free( psz_file_name );
1377 free( psz_gradient_path );
1380 p_sys->p_atmo_dyndata->UnLockCriticalSection();
1384 static void Atmo_SetupConfig(filter_t *p_filter, CAtmoConfig *p_atmo_config)
1387 figuring out the device ports (com-ports, ttys)
1389 char *psz_serialdev = var_CreateGetStringCommand( p_filter,
1390 CFG_PREFIX "serialdev" );
1391 char *psz_temp = psz_serialdev;
1393 if( !EMPTY_STR(psz_serialdev) )
1400 msg_Dbg( p_filter, "use port(s) %s",psz_serialdev);
1403 psz_serialdev - may contain up to 4 COM ports for the quattro device
1404 the quattro device is just hack of useing 4 classic devices as one
1405 logical device - thanks that usb-com-ports exists :)
1406 as Seperator I defined , or ; with the hope that these
1407 characters are never part of a device name
1409 while( (psz_token = strsep(&psz_temp, ",;")) != NULL && i_port < 4 )
1412 psz_token may contain spaces we have to trim away
1417 find first none space in string
1419 while( psz_token[i] == 32 ) i++;
1421 contains string only spaces or is empty? skip it
1429 while( psz_token[i] && psz_token[i] != 32 )
1430 psz_token[ j++ ] = psz_token[ i++ ];
1433 msg_Dbg( p_filter, "Serial Device [%d]: %s", i_port, psz_token );
1435 p_atmo_config->setSerialDevice( i_port, psz_token );
1442 msg_Err(p_filter,"no serial devicename(s) set");
1444 free( psz_serialdev );
1447 configuration of light source layout arround the display
1449 p_atmo_config->setZonesTopCount(
1450 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-top")
1452 p_atmo_config->setZonesBottomCount(
1453 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-bottom")
1455 p_atmo_config->setZonesLRCount(
1456 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-lr")
1458 p_atmo_config->setZoneSummary(
1459 var_CreateGetBoolCommand( p_filter, CFG_PREFIX "zone-summary")
1463 p_atmo_config->setLiveViewFilterMode(
1464 (AtmoFilterMode)var_CreateGetIntegerCommand( p_filter,
1465 CFG_PREFIX "filtermode")
1468 p_atmo_config->setLiveViewFilter_PercentNew(
1469 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "percentnew")
1471 p_atmo_config->setLiveViewFilter_MeanLength(
1472 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "meanlength")
1474 p_atmo_config->setLiveViewFilter_MeanThreshold(
1475 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "meanthreshold")
1478 p_atmo_config->setLiveView_EdgeWeighting(
1479 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "edgeweightning")
1481 p_atmo_config->setLiveView_BrightCorrect(
1482 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "brightness")
1484 p_atmo_config->setLiveView_DarknessLimit(
1485 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "darknesslimit")
1487 p_atmo_config->setLiveView_HueWinSize(
1488 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "huewinsize")
1490 p_atmo_config->setLiveView_SatWinSize(
1491 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "satwinsize")
1494 /* currently not required inside vlc */
1495 p_atmo_config->setLiveView_WidescreenMode( 0 );
1497 p_atmo_config->setLiveView_FrameDelay(
1498 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "framedelay")
1502 p_atmo_config->setUseSoftwareWhiteAdj(
1503 var_CreateGetBoolCommand( p_filter, CFG_PREFIX "whiteadj")
1505 p_atmo_config->setWhiteAdjustment_Red(
1506 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-red")
1508 p_atmo_config->setWhiteAdjustment_Green(
1509 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-green")
1511 p_atmo_config->setWhiteAdjustment_Blue(
1512 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-blue")
1516 settings for DMX device only
1518 p_atmo_config->setDMX_RGB_Channels(
1519 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "dmx-channels")
1522 char *psz_chbase = var_CreateGetStringCommand( p_filter,
1523 CFG_PREFIX "dmx-chbase" );
1524 if( !EMPTY_STR(psz_chbase) )
1525 p_atmo_config->setDMX_BaseChannels( psz_chbase );
1532 p_atmo_config->setMoMo_Channels(
1533 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "momo-channels")
1539 p_atmo_config->setFnordlicht_Amount(
1540 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "fnordlicht-amount")
1547 initialize the filter_sys_t structure with the data from the settings
1548 variables - if the external filter on win32 is enabled try loading the DLL,
1549 if this fails fallback to the buildin software
1551 static void Atmo_SetupParameters(filter_t *p_filter)
1553 filter_sys_t *p_sys = p_filter->p_sys;
1556 /* default filter disabled until DLL loaded and Init Success!*/
1557 p_sys->b_enabled = false;
1559 /* setup default mini image size (may be later a user option) */
1560 p_sys->i_atmo_width = 64;
1561 p_sys->i_atmo_height = 48;
1563 p_sys->i_device_type = var_CreateGetIntegerCommand( p_filter,
1564 CFG_PREFIX "device");
1568 0 => use AtmoWin Software (only win32)
1569 1 => use AtmoClassicConnection (direct)
1570 2 => use AtmoMultiConnection (direct up to four serial ports required)
1571 3 => use AtmoDmxConnection (simple serial DMX Device up to 255 channels)
1577 only on _WIN32 the user has the choice between
1578 internal driver and external
1581 if(p_sys->i_device_type == 0) {
1583 /* Load the Com Wrapper Library (source available) */
1584 p_sys->h_AtmoCtrl = LoadLibraryA("AtmoCtrlLib.dll");
1585 if(p_sys->h_AtmoCtrl == NULL)
1588 be clever if the location of atmowin.exe is set
1589 try to load the dll from the same folder :-)
1591 char *psz_path = var_CreateGetStringCommand( p_filter,
1592 CFG_PREFIX "atmowinexe" );
1593 if( !EMPTY_STR(psz_path) )
1595 char *psz_bs = strrchr( psz_path , '\\');
1600 now format a new dll filename with complete path
1602 char *psz_dllname = NULL;
1603 asprintf( &psz_dllname, "%s\\AtmoCtrlLib.dll", psz_path );
1606 msg_Dbg( p_filter, "Try Loading '%s'", psz_dllname );
1607 TCHAR* ptsz_dllname = ToT(psz_dllname);
1608 p_sys->h_AtmoCtrl = LoadLibrary( ptsz_dllname );
1611 free( psz_dllname );
1618 if(p_sys->h_AtmoCtrl != NULL)
1620 msg_Dbg( p_filter, "Load Library ok!");
1622 /* importing all required functions I hope*/
1623 p_sys->pf_ctrl_atmo_initialize =
1624 (int32_t (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,
1626 if(!p_sys->pf_ctrl_atmo_initialize)
1627 msg_Err( p_filter, "export AtmoInitialize missing.");
1629 p_sys->pf_ctrl_atmo_finalize =
1630 (void (*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,
1632 if(!p_sys->pf_ctrl_atmo_finalize)
1633 msg_Err( p_filter, "export AtmoFinalize missing.");
1635 p_sys->pf_ctrl_atmo_switch_effect =
1636 (int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,
1637 "AtmoSwitchEffect");
1638 if(!p_sys->pf_ctrl_atmo_switch_effect)
1639 msg_Err( p_filter, "export AtmoSwitchEffect missing.");
1641 p_sys->pf_ctrl_atmo_set_live_source =
1642 (int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,
1643 "AtmoSetLiveSource");
1644 if(!p_sys->pf_ctrl_atmo_set_live_source)
1645 msg_Err( p_filter, "export AtmoSetLiveSource missing.");
1647 p_sys->pf_ctrl_atmo_create_transfer_buffers =
1648 (void (*)(int32_t, int32_t, int32_t , int32_t))
1649 GetProcAddress(p_sys->h_AtmoCtrl,"AtmoCreateTransferBuffers");
1650 if(!p_sys->pf_ctrl_atmo_create_transfer_buffers)
1651 msg_Err( p_filter, "export AtmoCreateTransferBuffers missing.");
1653 p_sys->pf_ctrl_atmo_lock_transfer_buffer=
1654 (uint8_t*(*) (void))GetProcAddress(p_sys->h_AtmoCtrl,
1655 "AtmoLockTransferBuffer");
1656 if(!p_sys->pf_ctrl_atmo_lock_transfer_buffer)
1657 msg_Err( p_filter, "export AtmoLockTransferBuffer missing.");
1659 p_sys->pf_ctrl_atmo_send_pixel_data =
1660 (void (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,
1661 "AtmoSendPixelData");
1662 if(!p_sys->pf_ctrl_atmo_send_pixel_data)
1663 msg_Err( p_filter, "export AtmoSendPixelData missing.");
1665 p_sys->pf_ctrl_atmo_get_image_size =
1666 (void (*)(int32_t*,int32_t*))GetProcAddress(p_sys->h_AtmoCtrl,
1667 "AtmoWinGetImageSize");
1668 if(!p_sys->pf_ctrl_atmo_get_image_size)
1669 msg_Err( p_filter, "export AtmoWinGetImageSize missing.");
1672 /* the DLL is missing try internal filter ...*/
1674 "AtmoCtrlLib.dll missing fallback to internal atmo classic driver");
1675 p_sys->i_device_type = 1;
1680 if(p_sys->i_device_type >= 1) {
1681 msg_Dbg( p_filter, "try use buildin driver %d ", p_sys->i_device_type);
1683 now we have to read a lof of options from the config dialog
1684 most important the serial device if not set ... we can skip
1685 the rest and disable the filter...
1688 p_sys->p_atmo_config = new CAtmoConfig();
1690 p_sys->p_atmo_dyndata = new CAtmoDynData(
1691 (vlc_object_t *)p_filter,
1692 p_sys->p_atmo_config
1695 Atmo_SetupConfig( p_filter, p_sys->p_atmo_config );
1696 switch(p_sys->i_device_type)
1699 p_sys->p_atmo_config->setConnectionType( actClassicAtmo );
1703 p_sys->p_atmo_config->setConnectionType( actMultiAtmo );
1707 p_sys->p_atmo_config->setConnectionType( actDMX );
1711 p_sys->p_atmo_config->setConnectionType( actMoMoLight );
1715 p_sys->p_atmo_config->setConnectionType( actFnordlicht );
1719 msg_Warn( p_filter, "invalid device type %d found",
1720 p_sys->i_device_type );
1723 msg_Dbg( p_filter, "buildin driver config set");
1727 switch( p_filter->fmt_in.video.i_chroma )
1729 case VLC_CODEC_I420:
1730 p_sys->pf_extract_mini_image = ExtractMiniImage_YUV;
1731 p_sys->b_swap_uv = false;
1733 case VLC_CODEC_YV12:
1734 p_sys->pf_extract_mini_image = ExtractMiniImage_YUV;
1735 p_sys->b_swap_uv = true;
1738 msg_Warn( p_filter, "InitFilter-unsupported chroma: %4.4s",
1739 (char *)&p_filter->fmt_in.video.i_chroma);
1740 p_sys->pf_extract_mini_image = NULL;
1744 for debugging purpose show the samplinggrid on each frame as
1747 p_sys->b_show_dots = var_CreateGetBoolCommand( p_filter,
1748 CFG_PREFIX "showdots"
1751 #if defined(__ATMO_DEBUG__)
1752 /* save debug images to a folder as Bitmap files ? */
1753 p_sys->b_saveframes = var_CreateGetBoolCommand( p_filter,
1754 CFG_PREFIX "saveframes"
1756 msg_Dbg(p_filter,"saveframes = %d", (int)p_sys->b_saveframes);
1759 read debug image folder from config
1761 psz_path = var_CreateGetStringCommand( p_filter, CFG_PREFIX "framepath" );
1762 if(psz_path != NULL)
1764 strcpy(p_sys->sz_framepath, psz_path);
1765 #if defined( _WIN32 ) || defined( __OS2__ )
1766 size_t i_strlen = strlen(p_sys->sz_framepath);
1767 if((i_strlen>0) && (p_sys->sz_framepath[i_strlen-1] != '\\'))
1769 p_sys->sz_framepath[i_strlen] = '\\';
1770 p_sys->sz_framepath[i_strlen+1] = 0;
1775 msg_Dbg(p_filter,"saveframesfolder %s",p_sys->sz_framepath);
1780 this color is use on shutdown of the filter - the define the
1781 final light after playback... may be used to dim up the light -
1782 how it happens in the cinema...
1784 p_sys->ui_endcolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1785 CFG_PREFIX "ecolor-red");
1786 p_sys->ui_endcolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1787 CFG_PREFIX "ecolor-green");
1788 p_sys->ui_endcolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
1789 CFG_PREFIX "ecolor-blue");
1790 p_sys->i_endfadesteps = var_CreateGetIntegerCommand( p_filter,
1791 CFG_PREFIX "efadesteps");
1792 if(p_sys->i_endfadesteps < 1)
1793 p_sys->i_endfadesteps = 1;
1794 msg_Dbg(p_filter,"use ende color RGB: %d, %d, %d, Fadesteps: %d",
1795 p_sys->ui_endcolor_red,
1796 p_sys->ui_endcolor_green,
1797 p_sys->ui_endcolor_blue,
1798 p_sys->i_endfadesteps);
1803 if the external DLL was loaded successfully call AtmoInitialize -
1804 (must be done for each thread where you want to use AtmoLight!)
1806 int i = AtmoInitialize(p_filter, false);
1808 #if defined( _WIN32 )
1809 if((i != 1) && (p_sys->i_device_type == 0))
1812 COM Server for AtmoLight not running ?
1813 if the exe path is configured try to start the "userspace" driver
1815 char *psz_path = var_CreateGetStringCommand( p_filter,
1816 CFG_PREFIX "atmowinexe" );
1817 LPTSTR ptsz_path = ToT(psz_path);
1818 if(psz_path != NULL)
1820 STARTUPINFO startupinfo;
1821 PROCESS_INFORMATION pinfo;
1822 memset(&startupinfo, 0, sizeof(STARTUPINFO));
1823 startupinfo.cb = sizeof(STARTUPINFO);
1824 if(CreateProcess(ptsz_path, NULL, NULL, NULL,
1825 FALSE, 0, NULL, NULL, &startupinfo, &pinfo) == TRUE)
1827 msg_Dbg(p_filter,"launched AtmoWin from %s", psz_path);
1828 WaitForInputIdle(pinfo.hProcess, 5000);
1830 retry to initialize the library COM ... functionality
1831 after the server was launched
1833 i = AtmoInitialize(p_filter, false);
1835 msg_Err(p_filter,"failed to launch AtmoWin from %s", psz_path);
1843 if(i == 1) /* Init Atmolight success... */
1845 msg_Dbg( p_filter, "AtmoInitialize Ok!");
1848 p_sys->i_atmo_width and p_sys->i_atmo_height
1849 if the external AtmoWinA.exe is used, it may require
1850 a other sample image size than 64 x 48
1851 (this overrides the settings of the filter)
1853 Atmo_SetupImageSize( p_filter );
1856 if( p_sys->i_device_type >= 1 )
1859 AtmoConnection class initialized now we can initialize
1860 the default zone and channel mappings
1862 Atmo_SetupBuildZones( p_filter );
1865 /* Setup Transferbuffers for 64 x 48 , RGB with 32bit Per Pixel */
1866 AtmoCreateTransferBuffers(p_filter, BI_RGB, 4,
1867 p_sys->i_atmo_width,
1868 p_sys->i_atmo_height
1871 /* say the userspace driver that a live mode should be activated
1872 the functions returns the old mode for later restore!
1873 - the buildin driver launches the live view thread in that case
1875 p_sys->i_AtmoOldEffect = AtmoSwitchEffect(p_filter, emLivePicture);
1878 live view can have two differnt source the AtmoWinA
1879 internal GDI Screencapture and the external one - which we
1882 AtmoSetLiveSource(p_filter, lvsExternal);
1884 /* enable other parts only if everything is fine */
1885 p_sys->b_enabled = true;
1887 msg_Dbg( p_filter, "Atmo Filter Enabled Ok!");
1893 /*****************************************************************************
1894 * CreateFilter: allocates AtmoLight video thread output method
1895 *****************************************************************************
1896 * This function allocates and initializes a AtmoLight vout method.
1897 *****************************************************************************/
1898 static int CreateFilter( vlc_object_t *p_this )
1900 filter_t *p_filter = (filter_t *)p_this;
1901 filter_sys_t *p_sys;
1903 /* Allocate structure */
1904 p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) );
1905 p_filter->p_sys = p_sys;
1906 if( p_filter->p_sys == NULL )
1908 /* set all entries to zero */
1909 memset(p_sys, 0, sizeof( filter_sys_t ));
1910 vlc_mutex_init( &p_sys->filter_lock );
1912 msg_Dbg( p_filter, "Create Atmo Filter");
1914 /* further Setup Function pointers for videolan for calling my filter */
1915 p_filter->pf_video_filter = Filter;
1917 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
1920 AddAtmoSettingsVariablesCallbacks(p_filter);
1922 Atmo_SetupParameters(p_filter);
1930 /*****************************************************************************
1931 * DestroyFilter: destroy AtmoLight video thread output method
1932 *****************************************************************************
1933 * Terminate an output method created by CreateFilter
1934 *****************************************************************************/
1936 static void DestroyFilter( vlc_object_t *p_this )
1938 filter_t *p_filter = (filter_t *)p_this;
1939 filter_sys_t *p_sys = p_filter->p_sys;
1941 msg_Dbg( p_filter, "Destroy Atmo Filter");
1943 DelAtmoSettingsVariablesCallbacks(p_filter);
1945 Atmo_Shutdown(p_filter);
1947 #if defined( _WIN32 )
1948 if(p_sys->h_AtmoCtrl != NULL)
1950 FreeLibrary(p_sys->h_AtmoCtrl);
1954 delete p_sys->p_atmo_dyndata;
1955 delete p_sys->p_atmo_config;
1957 vlc_mutex_destroy( &p_sys->filter_lock );
1964 function stolen from some other videolan source filter ;-)
1965 for the moment RGB is OK... but better would be a direct transformation
1968 static inline void yuv_to_rgb( uint8_t *r, uint8_t *g, uint8_t *b,
1969 uint8_t y1, uint8_t u1, uint8_t v1 )
1971 /* macros used for YUV pixel conversions */
1972 # define SCALEBITS 10
1973 # define ONE_HALF (1 << (SCALEBITS - 1))
1974 # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
1975 # define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
1977 int y, cb, cr, r_add, g_add, b_add;
1981 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
1982 g_add = - FIX(0.34414*255.0/224.0) * cb
1983 - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
1984 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
1985 y = (y1 - 16) * FIX(255.0/219.0);
1986 *r = CLAMP((y + r_add) >> SCALEBITS);
1987 *g = CLAMP((y + g_add) >> SCALEBITS);
1988 *b = CLAMP((y + b_add) >> SCALEBITS);
1990 /******************************************************************************
1991 * ExtractMiniImage_YUV: extract a small image from the picture as 24-bit RGB
1992 *******************************************************************************
1993 * p_sys is a pointer to
1994 * p_inpic is the source frame
1995 * p_transfer_dest is the target buffer for the picture must be big enough!
1996 * (in win32 environment this buffer comes from the external DLL where it is
1997 * create as "variant array" and returned through the AtmoLockTransferbuffer
1999 static void ExtractMiniImage_YUV(filter_sys_t *p_sys,
2001 uint8_t *p_transfer_dest)
2008 uint8_t *p_rgb_dst_line_red;
2009 uint8_t *p_rgb_dst_line_green;
2010 uint8_t *p_rgb_dst_line_blue;
2015 /* calcute Pointers for Storage of B G R (A) */
2016 p_rgb_dst_line_blue = p_transfer_dest;
2017 p_rgb_dst_line_green = p_transfer_dest + 1;
2018 p_rgb_dst_line_red = p_transfer_dest + 2 ;
2020 int i_row_count = p_sys->i_atmo_height + 1;
2021 int i_col_count = p_sys->i_atmo_width + 1;
2022 int i_y_row,i_u_row,i_v_row,i_pixel_row;
2026 /* these two ugly loops extract the small image - goes it faster? how?
2027 the loops are so designed that there is a small border around the extracted
2028 image so we won't get column and row - zero from the frame, and not the most
2029 right and bottom pixels --- which may be clipped on computers useing TV out
2032 TODO: try to find out if the output is clipped through VLC - and try here
2033 to ingore the clipped away area for a better result!
2035 TODO: performance improvement in InitFilter percalculated the offsets of
2036 the lines inside the planes so I can save (i_row_count * 3) 2xMUL and
2037 one time DIV the same could be done for the inner loop I think...
2039 for(i_row = 1; i_row < i_row_count; i_row++)
2041 // calcute the current Lines in the source planes for this outputrow
2042 /* Adresscalcuation pointer to plane Length of one pixelrow in bytes
2043 calculate row now number
2046 p_inpic->format? transform Pixel row into row of plane...
2047 how? simple? fast? good?
2050 /* compute the source pixel row and respect the active cropping */
2051 i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
2052 + p_sys->i_crop_y_offset;
2055 trans for these Pixel row into the row of each plane ..
2056 because planesize can differ from image size
2058 i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
2059 p_inpic->format.i_visible_height;
2061 i_u_row = (i_pixel_row * p_inpic->p[U_PLANE].i_visible_lines) /
2062 p_inpic->format.i_visible_height;
2064 i_v_row = (i_pixel_row * p_inpic->p[V_PLANE].i_visible_lines) /
2065 p_inpic->format.i_visible_height;
2067 /* calculate the pointers to the pixeldata for this row
2070 p_src_y = p_inpic->p[Y_PLANE].p_pixels +
2071 p_inpic->p[Y_PLANE].i_pitch * i_y_row;
2072 p_src_u = p_inpic->p[U_PLANE].p_pixels +
2073 p_inpic->p[U_PLANE].i_pitch * i_u_row;
2074 p_src_v = p_inpic->p[V_PLANE].p_pixels +
2075 p_inpic->p[V_PLANE].i_pitch * i_v_row;
2077 if(p_sys->b_swap_uv)
2080 swap u and v plane for YV12 images
2082 uint8_t *p_temp_plane = p_src_u;
2084 p_src_v = p_temp_plane;
2087 for(i_col = 1; i_col < i_col_count; i_col++)
2089 i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
2090 p_sys->i_crop_x_offset;
2092 trans for these Pixel row into the row of each plane ..
2093 because planesize can differ from image size
2095 i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
2096 p_inpic->format.i_visible_width;
2097 i_xpos_u = (i_pixel_col * p_inpic->p[U_PLANE].i_visible_pitch) /
2098 p_inpic->format.i_visible_width;
2099 i_xpos_v = (i_pixel_col * p_inpic->p[V_PLANE].i_visible_pitch) /
2100 p_inpic->format.i_visible_width;
2102 yuv_to_rgb(p_rgb_dst_line_red,
2103 p_rgb_dst_line_green,
2104 p_rgb_dst_line_blue,
2110 /* +4 because output image should be RGB32 with dword alignment! */
2111 p_rgb_dst_line_red += 4;
2112 p_rgb_dst_line_green += 4;
2113 p_rgb_dst_line_blue += 4;
2117 if(p_sys->b_show_dots)
2119 for(i_row = 1; i_row < i_row_count; i_row++)
2121 i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
2122 + p_sys->i_crop_y_offset;
2124 i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
2125 p_inpic->format.i_visible_height;
2127 p_src_y = p_inpic->p[Y_PLANE].p_pixels +
2128 p_inpic->p[Y_PLANE].i_pitch * i_y_row;
2130 for(i_col = 1; i_col < i_col_count; i_col++)
2132 i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
2133 p_sys->i_crop_x_offset;
2134 i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
2135 p_inpic->format.i_visible_width;
2137 p_src_y[i_xpos_y] = 255;
2145 /******************************************************************************
2146 * SaveBitmap: Saves the content of a transferbuffer as Bitmap to disk
2147 *******************************************************************************
2148 * just for debugging
2149 * p_sys -> configuration if Atmo from there the function will get height and
2151 * p_pixels -> should be the dword aligned BGR(A) image data
2152 * psz_filename -> filename where to store
2154 #if defined(__ATMO_DEBUG__)
2155 void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename)
2157 /* for debug out only used*/
2158 VLC_BITMAPINFO bmp_info;
2159 BITMAPFILEHEADER bmp_fileheader;
2162 memset(&bmp_info, 0, sizeof(VLC_BITMAPINFO));
2163 bmp_info.bmiHeader.biSize = sizeof(VLC_BITMAPINFOHEADER);
2164 bmp_info.bmiHeader.biSizeImage = p_sys->i_atmo_height *
2165 p_sys->i_atmo_width * 4;
2166 bmp_info.bmiHeader.biCompression = BI_RGB;
2167 bmp_info.bmiHeader.biWidth = p_sys->i_atmo_width;
2168 bmp_info.bmiHeader.biHeight = -p_sys->i_atmo_height;
2169 bmp_info.bmiHeader.biBitCount = 32;
2170 bmp_info.bmiHeader.biPlanes = 1;
2172 bmp_fileheader.bfReserved1 = 0;
2173 bmp_fileheader.bfReserved2 = 0;
2174 bmp_fileheader.bfSize = sizeof(BITMAPFILEHEADER) +
2175 sizeof(VLC_BITMAPINFOHEADER) +
2176 bmp_info.bmiHeader.biSizeImage;
2177 bmp_fileheader.bfType = VLC_TWOCC('B','M');
2178 bmp_fileheader.bfOffBits = sizeof(BITMAPFILEHEADER) +
2179 sizeof(VLC_BITMAPINFOHEADER);
2181 fp_bitmap = fopen(psz_filename,"wb");
2182 if( fp_bitmap != NULL)
2184 fwrite(&bmp_fileheader, sizeof(BITMAPFILEHEADER), 1, fp_bitmap);
2185 fwrite(&bmp_info.bmiHeader, sizeof(VLC_BITMAPINFOHEADER), 1, fp_bitmap);
2186 fwrite(p_pixels, bmp_info.bmiHeader.biSizeImage, 1, fp_bitmap);
2193 /****************************************************************************
2194 * CreateMiniImage: extracts a 64x48 pixel image from the frame
2195 * (there is a small border arround thats why the loops starts with one
2196 * instead zero) without any interpolation
2197 *****************************************************************************/
2198 static void CreateMiniImage( filter_t *p_filter, picture_t *p_inpic)
2200 filter_sys_t *p_sys = p_filter->p_sys;
2202 pointer to RGB Buffer created in external libary as safe array which
2203 is locked inside AtmoLockTransferBuffer
2205 uint8_t *p_transfer;
2206 #if defined( __ATMO_DEBUG__ )
2207 /* for debug out only used*/
2208 char sz_filename[MAX_PATH];
2212 Lock the before created VarArray (AtmoCreateTransferBuffers)
2213 inside my wrapper library and give me a pointer to the buffer!
2214 below linux a global buffer may be used and protected with a mutex?
2216 p_transfer = AtmoLockTransferBuffer(p_filter);
2217 if(p_transfer == NULL)
2219 msg_Err( p_filter, "AtmoLight no transferbuffer available. "\
2220 "AtmoLight will be disabled!");
2221 p_sys->b_enabled = false;
2226 do the call via pointer to function instead of having a
2229 p_sys->pf_extract_mini_image(p_sys, p_inpic, p_transfer);
2232 #if defined( __ATMO_DEBUG__ )
2234 if debugging enabled save every 128th image to disk
2236 if(p_sys->b_saveframes && p_sys->sz_framepath[0] != 0 )
2239 if((p_sys->ui_frame_counter & 127) == 0)
2241 sprintf(sz_filename,"%satmo_dbg_%06u.bmp",p_sys->sz_framepath,
2242 p_sys->ui_frame_counter);
2243 msg_Dbg(p_filter, "SaveFrame %s",sz_filename);
2245 SaveBitmap(p_sys, p_transfer, sz_filename);
2249 msg_Dbg( p_filter, "AtmoFrame %u Time: %d ms", p_sys->ui_frame_counter,
2251 p_sys->ui_frame_counter++;
2254 p_sys->i_frames_processed++;
2257 /* show the colors on the wall */
2258 AtmoSendPixelData( p_filter );
2264 /*****************************************************************************
2265 * Filter: calls the extract method and forwards the incomming picture 1:1
2266 *****************************************************************************
2268 *****************************************************************************/
2270 static picture_t * Filter( filter_t *p_filter, picture_t *p_pic )
2272 filter_sys_t *p_sys = p_filter->p_sys;
2273 if( !p_pic ) return NULL;
2275 picture_t *p_outpic = filter_NewPicture( p_filter );
2278 picture_Release( p_pic );
2281 picture_CopyPixels( p_outpic, p_pic );
2283 vlc_mutex_lock( &p_sys->filter_lock );
2285 if(p_sys->b_enabled && p_sys->pf_extract_mini_image &&
2286 !p_sys->b_pause_live)
2288 p_sys->i_crop_x_offset = p_filter->fmt_in.video.i_x_offset;
2289 p_sys->i_crop_y_offset = p_filter->fmt_in.video.i_y_offset;
2290 p_sys->i_crop_width = p_filter->fmt_in.video.i_visible_width;
2291 p_sys->i_crop_height = p_filter->fmt_in.video.i_visible_height;
2293 CreateMiniImage(p_filter, p_outpic);
2296 vlc_mutex_unlock( &p_sys->filter_lock );
2299 return CopyInfoAndRelease( p_outpic, p_pic );
2303 /*****************************************************************************
2304 * FadeToColorThread: Threadmethod which changes slowly the color
2305 * to a target color defined in p_fadethread struct
2306 * use for: Fade to Pause Color, and Fade to End Color
2307 *****************************************************************************/
2308 static void *FadeToColorThread(void *obj)
2310 fadethread_t *p_fadethread = (fadethread_t *)obj;
2311 filter_sys_t *p_sys = (filter_sys_t *)p_fadethread->p_filter->p_sys;
2312 int i_steps_done = 0;
2322 uint8_t *p_source = NULL;
2324 int canc = vlc_savecancel ();
2325 /* initialize AtmoWin for this thread! */
2326 AtmoInitialize(p_fadethread->p_filter , true);
2328 uint8_t *p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
2329 if(p_transfer != NULL) {
2330 /* safe colors as "32bit" Integers to avoid overflows*/
2331 i_pause_red = p_fadethread->ui_red;
2332 i_pause_blue = p_fadethread->ui_blue;
2333 i_pause_green = p_fadethread->ui_green;
2336 allocate a temporary buffer for the last send
2337 image size less then 15kb
2339 int i_size = 4 * p_sys->i_atmo_width * p_sys->i_atmo_height;
2340 p_source = (uint8_t *)malloc( i_size );
2341 if(p_source != NULL)
2344 get a copy of the last transfered image as orign for the
2347 memcpy(p_source, p_transfer, i_size);
2348 /* send the same pixel data again... to unlock the buffer! */
2349 AtmoSendPixelData( p_fadethread->p_filter );
2351 while( (!atomic_load (&p_fadethread->abort)) &&
2352 (i_steps_done < p_fadethread->i_steps))
2354 p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
2355 if(!p_transfer) break; /* should not happen if it worked
2356 one time in the code above! */
2359 move all pixels in the mini image (64x48) one step closer to
2360 the desired color these loop takes the most time of this
2361 thread improvements wellcome!
2364 (i_index < i_size) && (!atomic_load (&p_fadethread->abort));
2367 i_src_blue = p_source[i_index+0];
2368 i_src_green = p_source[i_index+1];
2369 i_src_red = p_source[i_index+2];
2370 p_transfer[i_index+0] = (uint8_t) (((
2371 (i_pause_blue - i_src_blue)
2372 * i_steps_done)/p_fadethread->i_steps)
2375 p_transfer[i_index+1] = (uint8_t) (((
2376 (i_pause_green - i_src_green)
2377 * i_steps_done)/p_fadethread->i_steps)
2380 p_transfer[i_index+2] = (uint8_t) (((
2381 (i_pause_red - i_src_red)
2382 * i_steps_done)/p_fadethread->i_steps)
2386 /* send image to lightcontroller */
2387 AtmoSendPixelData( p_fadethread->p_filter );
2388 /* is there something like and interruptable sleep inside
2389 the VLC libaries? inside native win32 I would use an Event
2390 (CreateEvent) and here an WaitForSingleObject?
2396 /* in failure of malloc also unlock buffer */
2397 AtmoSendPixelData(p_fadethread->p_filter);
2400 /* call indirect to OleUnitialize() for this thread */
2401 AtmoFinalize(p_fadethread->p_filter, 0);
2402 vlc_restorecancel (canc);
2406 /*****************************************************************************
2407 * CheckAndStopFadeThread: if there is a fadethread structure left, or running.
2408 ******************************************************************************
2409 * this function will stop the thread ... and waits for its termination
2410 * before removeing the objects from vout_sys_t ...
2411 ******************************************************************************/
2412 static void CheckAndStopFadeThread(filter_t *p_filter)
2414 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2415 vlc_mutex_lock( &p_sys->filter_lock );
2416 if(p_sys->p_fadethread != NULL)
2418 msg_Dbg(p_filter, "kill still running fadeing thread...");
2420 atomic_store(&p_sys->p_fadethread->abort, true);
2422 vlc_join(p_sys->p_fadethread->thread, NULL);
2423 free(p_sys->p_fadethread);
2424 p_sys->p_fadethread = NULL;
2426 vlc_mutex_unlock( &p_sys->filter_lock );
2429 /****************************************************************************
2430 * StateCallback: Callback for the inputs variable "State" to get notified
2431 * about Pause and Continue Playback events.
2432 *****************************************************************************/
2433 static int AtmoSettingsCallback( vlc_object_t *, char const *psz_var,
2434 vlc_value_t oldval, vlc_value_t newval,
2437 filter_t *p_filter = (filter_t *)p_data;
2438 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
2440 vlc_mutex_lock( &p_sys->filter_lock );
2442 if( !strcmp( psz_var, CFG_PREFIX "showdots" ))
2444 p_sys->b_show_dots = newval.b_bool;
2447 CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
2451 msg_Dbg(p_filter, "apply AtmoSettingsCallback %s (int: %" PRId64 " -> %" PRId64 ")",
2457 if( !strcmp( psz_var, CFG_PREFIX "filtermode" ))
2458 p_atmo_config->setLiveViewFilterMode( (AtmoFilterMode)newval.i_int);
2460 else if( !strcmp( psz_var, CFG_PREFIX "percentnew" ))
2461 p_atmo_config->setLiveViewFilter_PercentNew( newval.i_int );
2463 else if( !strcmp( psz_var, CFG_PREFIX "meanlength" ))
2464 p_atmo_config->setLiveViewFilter_MeanLength( newval.i_int );
2466 else if( !strcmp( psz_var, CFG_PREFIX "meanthreshold" ))
2467 p_atmo_config->setLiveViewFilter_MeanThreshold( newval.i_int );
2469 else if( !strcmp( psz_var, CFG_PREFIX "edgeweightning" ))
2470 p_atmo_config->setLiveView_EdgeWeighting( newval.i_int );
2472 else if( !strcmp( psz_var, CFG_PREFIX "brightness" ))
2473 p_atmo_config->setLiveView_BrightCorrect( newval.i_int );
2475 else if( !strcmp( psz_var, CFG_PREFIX "darknesslimit" ))
2476 p_atmo_config->setLiveView_DarknessLimit( newval.i_int );
2478 else if( !strcmp( psz_var, CFG_PREFIX "huewinsize" ))
2479 p_atmo_config->setLiveView_HueWinSize( newval.i_int );
2481 else if( !strcmp( psz_var, CFG_PREFIX "satwinsize" ))
2482 p_atmo_config->setLiveView_SatWinSize( newval.i_int );
2484 else if( !strcmp( psz_var, CFG_PREFIX "framedelay" ))
2485 p_atmo_config->setLiveView_FrameDelay( newval.i_int );
2487 else if( !strcmp( psz_var, CFG_PREFIX "whiteadj" ))
2488 p_atmo_config->setUseSoftwareWhiteAdj( newval.b_bool );
2490 else if( !strcmp( psz_var, CFG_PREFIX "white-red" ))
2491 p_atmo_config->setWhiteAdjustment_Red( newval.i_int );
2493 else if( !strcmp( psz_var, CFG_PREFIX "white-green" ))
2494 p_atmo_config->setWhiteAdjustment_Green( newval.i_int );
2496 else if( !strcmp( psz_var, CFG_PREFIX "white-blue" ))
2497 p_atmo_config->setWhiteAdjustment_Blue( newval.i_int );
2501 vlc_mutex_unlock( &p_sys->filter_lock );
2506 static void AddAtmoSettingsVariablesCallbacks(filter_t *p_filter)
2508 var_AddCallback( p_filter, CFG_PREFIX "filtermode",
2509 AtmoSettingsCallback, p_filter );
2510 var_AddCallback( p_filter, CFG_PREFIX "percentnew",
2511 AtmoSettingsCallback, p_filter );
2514 var_AddCallback( p_filter, CFG_PREFIX "meanlength",
2515 AtmoSettingsCallback, p_filter );
2516 var_AddCallback( p_filter, CFG_PREFIX "meanthreshold",
2517 AtmoSettingsCallback, p_filter );
2519 var_AddCallback( p_filter, CFG_PREFIX "edgeweightning",
2520 AtmoSettingsCallback, p_filter );
2521 var_AddCallback( p_filter, CFG_PREFIX "brightness",
2522 AtmoSettingsCallback, p_filter );
2523 var_AddCallback( p_filter, CFG_PREFIX "darknesslimit",
2524 AtmoSettingsCallback, p_filter );
2526 var_AddCallback( p_filter, CFG_PREFIX "huewinsize",
2527 AtmoSettingsCallback, p_filter );
2528 var_AddCallback( p_filter, CFG_PREFIX "satwinsize",
2529 AtmoSettingsCallback, p_filter );
2530 var_AddCallback( p_filter, CFG_PREFIX "framedelay",
2531 AtmoSettingsCallback, p_filter );
2534 var_AddCallback( p_filter, CFG_PREFIX "whiteadj",
2535 AtmoSettingsCallback, p_filter );
2536 var_AddCallback( p_filter, CFG_PREFIX "white-red",
2537 AtmoSettingsCallback, p_filter );
2538 var_AddCallback( p_filter, CFG_PREFIX "white-green",
2539 AtmoSettingsCallback, p_filter );
2540 var_AddCallback( p_filter, CFG_PREFIX "white-blue",
2541 AtmoSettingsCallback, p_filter );
2543 var_AddCallback( p_filter, CFG_PREFIX "showdots",
2544 AtmoSettingsCallback, p_filter );
2548 static void DelAtmoSettingsVariablesCallbacks( filter_t *p_filter )
2551 var_DelCallback( p_filter, CFG_PREFIX "filtermode",
2552 AtmoSettingsCallback, p_filter );
2554 var_DelCallback( p_filter, CFG_PREFIX "percentnew",
2555 AtmoSettingsCallback, p_filter );
2556 var_DelCallback( p_filter, CFG_PREFIX "meanlength",
2557 AtmoSettingsCallback, p_filter );
2558 var_DelCallback( p_filter, CFG_PREFIX "meanthreshold",
2559 AtmoSettingsCallback, p_filter );
2561 var_DelCallback( p_filter, CFG_PREFIX "edgeweightning",
2562 AtmoSettingsCallback, p_filter );
2563 var_DelCallback( p_filter, CFG_PREFIX "brightness",
2564 AtmoSettingsCallback, p_filter );
2565 var_DelCallback( p_filter, CFG_PREFIX "darknesslimit",
2566 AtmoSettingsCallback, p_filter );
2568 var_DelCallback( p_filter, CFG_PREFIX "huewinsize",
2569 AtmoSettingsCallback, p_filter );
2570 var_DelCallback( p_filter, CFG_PREFIX "satwinsize",
2571 AtmoSettingsCallback, p_filter );
2572 var_DelCallback( p_filter, CFG_PREFIX "framedelay",
2573 AtmoSettingsCallback, p_filter );
2576 var_DelCallback( p_filter, CFG_PREFIX "whiteadj",
2577 AtmoSettingsCallback, p_filter );
2578 var_DelCallback( p_filter, CFG_PREFIX "white-red",
2579 AtmoSettingsCallback, p_filter );
2580 var_DelCallback( p_filter, CFG_PREFIX "white-green",
2581 AtmoSettingsCallback, p_filter );
2582 var_DelCallback( p_filter, CFG_PREFIX "white-blue",
2583 AtmoSettingsCallback, p_filter );
2585 var_DelCallback( p_filter, CFG_PREFIX "showdots",
2586 AtmoSettingsCallback, p_filter );
2591 #if defined(__ATMO_DEBUG__)
2592 static void atmo_parse_crop(char *psz_cropconfig,
2593 video_format_t fmt_in,
2594 video_format_t fmt_render,
2595 int &i_visible_width, int &i_visible_height,
2596 int &i_x_offset, int &i_y_offset )
2598 int64_t i_aspect_num, i_aspect_den;
2599 unsigned int i_width, i_height;
2601 i_visible_width = fmt_in.i_visible_width;
2602 i_visible_height = fmt_in.i_visible_height;
2603 i_x_offset = fmt_in.i_x_offset;
2604 i_y_offset = fmt_in.i_y_offset;
2606 char *psz_end = NULL, *psz_parser = strchr( psz_cropconfig, ':' );
2609 /* We're using the 3:4 syntax */
2610 i_aspect_num = strtol( psz_cropconfig, &psz_end, 10 );
2611 if( psz_end == psz_cropconfig || !i_aspect_num ) return;
2613 i_aspect_den = strtol( ++psz_parser, &psz_end, 10 );
2614 if( psz_end == psz_parser || !i_aspect_den ) return;
2616 i_width = fmt_in.i_sar_den * fmt_render.i_visible_height *
2617 i_aspect_num / i_aspect_den / fmt_in.i_sar_num;
2619 i_height = fmt_render.i_visible_width*fmt_in.i_sar_num *
2620 i_aspect_den / i_aspect_num / fmt_in.i_sar_den;
2622 if( i_width < fmt_render.i_visible_width )
2624 i_x_offset = fmt_render.i_x_offset +
2625 (fmt_render.i_visible_width - i_width) / 2;
2626 i_visible_width = i_width;
2630 i_y_offset = fmt_render.i_y_offset +
2631 (fmt_render.i_visible_height - i_height) / 2;
2632 i_visible_height = i_height;
2637 psz_parser = strchr( psz_cropconfig, 'x' );
2640 /* Maybe we're using the <width>x<height>+<left>+<top> syntax */
2641 unsigned int i_crop_width, i_crop_height, i_crop_top, i_crop_left;
2643 i_crop_width = strtol( psz_cropconfig, &psz_end, 10 );
2644 if( psz_end != psz_parser ) return;
2646 psz_parser = strchr( ++psz_end, '+' );
2647 i_crop_height = strtol( psz_end, &psz_end, 10 );
2648 if( psz_end != psz_parser ) return;
2650 psz_parser = strchr( ++psz_end, '+' );
2651 i_crop_left = strtol( psz_end, &psz_end, 10 );
2652 if( psz_end != psz_parser ) return;
2655 i_crop_top = strtol( psz_end, &psz_end, 10 );
2656 if( *psz_end != '\0' ) return;
2658 i_width = i_crop_width;
2659 i_visible_width = i_width;
2661 i_height = i_crop_height;
2662 i_visible_height = i_height;
2664 i_x_offset = i_crop_left;
2665 i_y_offset = i_crop_top;
2669 /* Maybe we're using the <left>+<top>+<right>+<bottom> syntax */
2670 unsigned int i_crop_top, i_crop_left, i_crop_bottom, i_crop_right;
2672 psz_parser = strchr( psz_cropconfig, '+' );
2673 i_crop_left = strtol( psz_cropconfig, &psz_end, 10 );
2674 if( psz_end != psz_parser ) return;
2676 psz_parser = strchr( ++psz_end, '+' );
2677 i_crop_top = strtol( psz_end, &psz_end, 10 );
2678 if( psz_end != psz_parser ) return;
2680 psz_parser = strchr( ++psz_end, '+' );
2681 i_crop_right = strtol( psz_end, &psz_end, 10 );
2682 if( psz_end != psz_parser ) return;
2685 i_crop_bottom = strtol( psz_end, &psz_end, 10 );
2686 if( *psz_end != '\0' ) return;
2688 i_width = fmt_render.i_visible_width -
2691 i_visible_width = i_width;
2693 i_height = fmt_render.i_visible_height -
2696 i_visible_height = i_height;
2698 i_x_offset = i_crop_left;
2699 i_y_offset = i_crop_top;