PageRenderTime 71ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/atmo.cpp

https://bitbucket.org/RickDB/atmowin-atmoduino-mod
C++ | 2840 lines | 1814 code | 432 blank | 594 comment | 224 complexity | 1757f4a6a39298d6c7b8beb94bdf23d9 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*****************************************************************************
  2. * atmo.cpp : "Atmo Light" video filter
  3. *****************************************************************************
  4. * Copyright (C) 2000-2006 the VideoLAN team
  5. * $Id: 381928c8d0487de635cc45bbf7ca49acf30f3a72 $
  6. *
  7. * Authors: André Weber (WeberAndre@gmx.de)
  8. *
  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.
  13. *
  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.
  18. *
  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. *****************************************************************************/
  23. #ifdef HAVE_CONFIG_H
  24. # include "config.h"
  25. #endif
  26. /*****************************************************************************
  27. * Preamble
  28. *****************************************************************************/
  29. #define __STDC_FORMAT_MACROS 1
  30. #include <stdlib.h> /* malloc(), free() */
  31. #include <string.h>
  32. #include <math.h> /* sin(), cos() */
  33. #include <assert.h>
  34. // #define __ATMO_DEBUG__
  35. // [:Zs]+$
  36. #include <vlc_common.h>
  37. #include <vlc_plugin.h>
  38. #include <vlc_vout.h>
  39. #include <vlc_playlist.h>
  40. #include <vlc_filter.h>
  41. #include <vlc_atomic.h>
  42. #include "filter_picture.h"
  43. #include "AtmoDefs.h"
  44. #include "AtmoDynData.h"
  45. #include "AtmoLiveView.h"
  46. #include "AtmoTools.h"
  47. #include "AtmoExternalCaptureInput.h"
  48. #include "AtmoConfig.h"
  49. #include "AtmoConnection.h"
  50. #include "AtmoClassicConnection.h"
  51. /*****************************************************************************
  52. * Local prototypes
  53. *****************************************************************************/
  54. /* directly to vlc related functions required that the module is accepted */
  55. static int CreateFilter ( vlc_object_t * );
  56. static void DestroyFilter ( vlc_object_t * );
  57. static picture_t * Filter( filter_t *, picture_t *);
  58. /* callback for global variable state pause / continue / stop events */
  59. static void AddStateVariableCallback( filter_t *);
  60. static void DelStateVariableCallback( filter_t *);
  61. static int StateCallback(vlc_object_t *, char const *,
  62. vlc_value_t, vlc_value_t, void *);
  63. /* callback for atmo settings variables whose change
  64. should be immediately realized and applied to output
  65. */
  66. static void DelAtmoSettingsVariablesCallbacks(filter_t *);
  67. static void AddAtmoSettingsVariablesCallbacks(filter_t *);
  68. static int AtmoSettingsCallback(vlc_object_t *, char const *,
  69. vlc_value_t, vlc_value_t, void *);
  70. #if defined(__ATMO_DEBUG__)
  71. static void atmo_parse_crop(char *psz_cropconfig,
  72. video_format_t fmt_in,
  73. video_format_t fmt_render,
  74. int &i_visible_width,
  75. int &i_visible_height,
  76. int &i_x_offset,
  77. int &i_y_offset );
  78. #endif
  79. /* function to shutdown the fade thread which is started on pause*/
  80. static void CheckAndStopFadeThread(filter_t *);
  81. /* extracts a small RGB (BGR) Image from an YUV image */
  82. static void ExtractMiniImage_YUV(filter_sys_t *, picture_t *, uint8_t *);
  83. #if defined(__ATMO_DEBUG__)
  84. void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename);
  85. #endif
  86. /*****************************************************************************
  87. * External Prototypes for the AtmoCtrlLib.DLL
  88. *****************************************************************************/
  89. /*
  90. * if effectmode = emLivePicture then the source could be GDI (Screencapture)
  91. * or External - this means another application delivers Pixeldata to AtmoWin
  92. * Clientsoftware through AtmoCtrlLib.DLL and the COM Api
  93. */
  94. #define lvsGDI 0
  95. #define lvsExternal 1
  96. #define CLASSIC_ATMO_NUM_ZONES 5
  97. /*
  98. strings for settings menus and hints
  99. */
  100. #define MODULE_DESCRIPTION N_ ( \
  101. "This module allows to control an so called AtmoLight device "\
  102. "connected to your computer.\n"\
  103. "AtmoLight is the homegrown version of what Philips calls AmbiLight.\n"\
  104. "If you need further information feel free to visit us at\n\n"\
  105. "http://www.vdr-wiki.de/wiki/index.php/Atmo-plugin\n"\
  106. "http://www.vdr-wiki.de/wiki/index.php/AtmoWin\n\n"\
  107. "You can find there detailed descriptions on how to build it for yourself "\
  108. "and where to get the required parts.\n" \
  109. "You can also have a look at pictures and some movies showing such a device " \
  110. "in live action.")
  111. #define DRIVER_TEXT N_("Device type")
  112. #define DRIVER_LONGTEXT N_("Choose your preferred hardware from " \
  113. "the list, or choose AtmoWin Software " \
  114. "to delegate processing to the external " \
  115. "process - with more options")
  116. static const int pi_device_type_values[] = {
  117. #if defined( WIN32 )
  118. 0, /* use AtmoWinA.exe userspace driver */
  119. #endif
  120. 1, /* AtmoLight classic */
  121. 2, /* Quattro AtmoLight */
  122. 3, /* DMX Device */
  123. 4, /* MoMoLight device */
  124. 5 /* fnordlicht */
  125. };
  126. static const char *const ppsz_device_type_descriptions[] = {
  127. #if defined( WIN32 )
  128. N_("AtmoWin Software"),
  129. #endif
  130. N_("Classic AtmoLight"),
  131. N_("Quattro AtmoLight"),
  132. N_("DMX"),
  133. N_("MoMoLight"),
  134. N_("fnordlicht")
  135. };
  136. #define DMX_CHANNELS_TEXT N_("Count of AtmoLight channels")
  137. #define DMX_CHANNELS_LONGTEXT N_("How many AtmoLight channels, should be " \
  138. "emulated with that DMX device")
  139. #define DMX_CHBASE_TEXT N_("DMX address for each channel")
  140. #define DMX_CHBASE_LONGTEXT N_("Define here the DMX base address for each " \
  141. "channel use , or ; to separate the values")
  142. #define MOMO_CHANNELS_TEXT N_("Count of channels")
  143. #define MOMO_CHANNELS_LONGTEXT N_("Depending on your MoMoLight hardware " \
  144. "choose 3 or 4 channels")
  145. #define FNORDLICHT_AMOUNT_TEXT N_("Count of fnordlicht's")
  146. #define FNORDLICHT_AMOUNT_LONGTEXT N_("Depending on the amount your " \
  147. "fnordlicht hardware " \
  148. "choose 1 to 254 channels")
  149. #if defined( WIN32 )
  150. # define DEFAULT_DEVICE 0
  151. #else
  152. # define DEFAULT_DEVICE 1
  153. #endif
  154. #if defined( __ATMO_DEBUG__ )
  155. # define SAVEFRAMES_TEXT N_("Save Debug Frames")
  156. # define SAVEFRAMES_LONGTEXT N_("Write every 128th miniframe to a folder.")
  157. # define FRAMEPATH_TEXT N_("Debug Frame Folder")
  158. # define FRAMEPATH_LONGTEXT N_("The path where the debugframes " \
  159. "should be saved")
  160. #endif
  161. #define WIDTH_TEXT N_("Extracted Image Width")
  162. #define WIDTH_LONGTEXT N_("The width of the mini image for " \
  163. "further processing (64 is default)")
  164. #define HEIGHT_TEXT N_("Extracted Image Height")
  165. #define HEIGHT_LONGTEXT N_("The height of the mini image for " \
  166. "further processing (48 is default)")
  167. #define SHOW_DOTS_TEXT N_("Mark analyzed pixels")
  168. #define SHOW_DOTS_LONGTEXT N_("makes the sample grid visible on screen as "\
  169. "white pixels")
  170. #define PCOLOR_TEXT N_("Color when paused")
  171. #define PCOLOR_LONGTEXT N_("Set the color to show if the user " \
  172. "pauses the video. (Have light to get " \
  173. "another beer?)")
  174. #define PCOLOR_RED_TEXT N_("Pause-Red")
  175. #define PCOLOR_RED_LONGTEXT N_("Red component of the pause color")
  176. #define PCOLOR_GREEN_TEXT N_("Pause-Green")
  177. #define PCOLOR_GREEN_LONGTEXT N_("Green component of the pause color")
  178. #define PCOLOR_BLUE_TEXT N_("Pause-Blue")
  179. #define PCOLOR_BLUE_LONGTEXT N_("Blue component of the pause color")
  180. #define FADESTEPS_TEXT N_("Pause-Fadesteps")
  181. #define FADESTEPS_LONGTEXT N_("Number of steps to change current color " \
  182. "to pause color (each step takes 40ms)")
  183. #define ECOLOR_RED_TEXT N_("End-Red")
  184. #define ECOLOR_RED_LONGTEXT N_("Red component of the shutdown color")
  185. #define ECOLOR_GREEN_TEXT N_("End-Green")
  186. #define ECOLOR_GREEN_LONGTEXT N_("Green component of the shutdown color")
  187. #define ECOLOR_BLUE_TEXT N_("End-Blue")
  188. #define ECOLOR_BLUE_LONGTEXT N_("Blue component of the shutdown color")
  189. #define EFADESTEPS_TEXT N_("End-Fadesteps")
  190. #define EFADESTEPS_LONGTEXT N_("Number of steps to change current color to " \
  191. "end color for dimming up the light in cinema " \
  192. "style... (each step takes 40ms)")
  193. #define ZONE_TOP_TEXT N_("Number of zones on top")
  194. #define ZONE_TOP_LONGTEXT N_("Number of zones on the top of the screen")
  195. #define ZONE_BOTTOM_TEXT N_("Number of zones on bottom")
  196. #define ZONE_BOTTOM_LONGTEXT N_("Number of zones on the bottom of the screen")
  197. #define ZONE_LR_TEXT N_("Zones on left / right side")
  198. #define ZONE_LR_LONGTEXT N_("left and right side having allways the " \
  199. "same number of zones")
  200. #define ZONE_SUMMARY_TEXT N_("Calculate a average zone")
  201. #define ZONE_SUMMARY_LONGTEXT N_("it contains the average of all pixels " \
  202. "in the sample image (only useful for " \
  203. "single channel AtmoLight)")
  204. #define USEWHITEADJ_TEXT N_("Use Software White adjust")
  205. #define USEWHITEADJ_LONGTEXT N_("Should the buildin driver do a white " \
  206. "adjust or your LED stripes? recommend.")
  207. #define WHITE_RED_TEXT N_("White Red")
  208. #define WHITE_RED_LONGTEXT N_("Red value of a pure white on your "\
  209. "LED stripes.")
  210. #define WHITE_GREEN_TEXT N_("White Green")
  211. #define WHITE_GREEN_LONGTEXT N_("Green value of a pure white on your "\
  212. "LED stripes.")
  213. #define WHITE_BLUE_TEXT N_("White Blue")
  214. #define WHITE_BLUE_LONGTEXT N_("Blue value of a pure white on your "\
  215. "LED stripes.")
  216. #define SERIALDEV_TEXT N_("Serial Port/Device")
  217. #define SERIALDEV_LONGTEXT N_("Name of the serial port where the AtmoLight "\
  218. "controller is attached to.\n" \
  219. "On Windows usually something like COM1 or " \
  220. "COM2. On Linux /dev/ttyS01 f.e.")
  221. #define EDGE_TEXT N_("Edge Weightning")
  222. #define EDGE_LONGTEXT N_("Increasing this value will result in color "\
  223. "more depending on the border of the frame.")
  224. #define BRIGHTNESS_TEXT N_("Brightness")
  225. #define BRIGHTNESS_LONGTEXT N_("Overall brightness of your LED stripes")
  226. #define DARKNESS_TEXT N_("Darkness Limit")
  227. #define DARKNESS_LONGTEXT N_("Pixels with a saturation lower than this will "\
  228. "be ignored. Should be greater than one for "\
  229. "letterboxed videos.")
  230. #define HUEWINSIZE_TEXT N_("Hue windowing")
  231. #define HUEWINSIZE_LONGTEXT N_("Used for statistics.")
  232. #define SATWINSIZE_TEXT N_("Sat windowing")
  233. #define SATWINSIZE_LONGTEXT N_("Used for statistics.")
  234. #define MEANLENGTH_TEXT N_("Filter length (ms)")
  235. #define MEANLENGTH_LONGTEXT N_("Time it takes until a color is completely "\
  236. "changed. This prevents flickering.")
  237. #define MEANTHRESHOLD_TEXT N_("Filter threshold")
  238. #define MEANTHRESHOLD_LONGTEXT N_("How much a color has to be changed for an "\
  239. "immediate color change.")
  240. #define MEANPERCENTNEW_TEXT N_("Filter Smoothness (in %)")
  241. #define MEANPERCENTNEW_LONGTEXT N_("Filter Smoothness")
  242. #define FILTERMODE_TEXT N_("Output Color filter mode")
  243. #define FILTERMODE_LONGTEXT N_("defines the how the output color should " \
  244. "be calculated based on previous color")
  245. static const int pi_filtermode_values[] = {
  246. (int)afmNoFilter,
  247. (int)afmCombined,
  248. (int)afmPercent
  249. };
  250. static const char *const ppsz_filtermode_descriptions[] = {
  251. N_("No Filtering"),
  252. N_("Combined"),
  253. N_("Percent")
  254. };
  255. #define FRAMEDELAY_TEXT N_("Frame delay (ms)")
  256. #define FRAMEDELAY_LONGTEXT N_("Helps to get the video output and the light "\
  257. "effects in sync. Values around 20ms should " \
  258. "do the trick.")
  259. #define CHANNEL_0_ASSIGN_TEXT N_("Channel 0: summary")
  260. #define CHANNEL_1_ASSIGN_TEXT N_("Channel 1: left")
  261. #define CHANNEL_2_ASSIGN_TEXT N_("Channel 2: right")
  262. #define CHANNEL_3_ASSIGN_TEXT N_("Channel 3: top")
  263. #define CHANNEL_4_ASSIGN_TEXT N_("Channel 4: bottom")
  264. #define CHANNELASSIGN_LONGTEXT N_("Maps the hardware channel X to logical "\
  265. "zone Y to fix wrong wiring :-)")
  266. static const int pi_zone_assignment_values[] = {
  267. -1,
  268. 4,
  269. 3,
  270. 1,
  271. 0,
  272. 2
  273. };
  274. static const char *const ppsz_zone_assignment_descriptions[] = {
  275. N_("disabled"),
  276. N_("Zone 4:summary"),
  277. N_("Zone 3:left"),
  278. N_("Zone 1:right"),
  279. N_("Zone 0:top"),
  280. N_("Zone 2:bottom")
  281. };
  282. #define CHANNELS_ASSIGN_TEXT N_("Channel / Zone Assignment")
  283. #define CHANNELS_ASSIGN_LONGTEXT N_("for devices with more than five " \
  284. "channels / zones write down here for each channel " \
  285. "the zone number to show and separate the values with " \
  286. ", or ; and use -1 to not use some channels. For the " \
  287. "classic AtmoLight the sequence 4,3,1,0,2 would set the " \
  288. "default channel/zone mapping. " \
  289. "Having only two zones on top, and one zone on left and " \
  290. "right and no summary zone the mapping for classic " \
  291. "AtmoLight would be -1,3,2,1,0")
  292. #define ZONE_0_GRADIENT_TEXT N_("Zone 0: Top gradient")
  293. #define ZONE_1_GRADIENT_TEXT N_("Zone 1: Right gradient")
  294. #define ZONE_2_GRADIENT_TEXT N_("Zone 2: Bottom gradient")
  295. #define ZONE_3_GRADIENT_TEXT N_("Zone 3: Left gradient")
  296. #define ZONE_4_GRADIENT_TEXT N_("Zone 4: Summary gradient")
  297. #define ZONE_X_GRADIENT_LONG_TEXT N_("Defines a small bitmap with 64x48 "\
  298. "pixels, containing a grayscale gradient")
  299. #define GRADIENT_PATH_TEXT N_("Gradient bitmap searchpath")
  300. #define GRADIENT_PATH_LONGTEXT N_("Now preferred option to assign gradient "\
  301. "bitmaps, put them as zone_0.bmp, zone_1.bmp etc. into one folder and "\
  302. "set the foldername here")
  303. #if defined( WIN32 )
  304. # define ATMOWINEXE_TEXT N_("Filename of AtmoWin*.exe")
  305. # define ATMOWINEXE_LONGTEXT N_("if you want the AtmoLight control "\
  306. "software to be launched by VLC, enter the "\
  307. "complete path of AtmoWinA.exe here.")
  308. #endif
  309. #define CFG_PREFIX "atmo-"
  310. /*****************************************************************************
  311. * Module descriptor
  312. *****************************************************************************/
  313. vlc_module_begin ()
  314. set_description( N_("AtmoLight Filter") )
  315. set_help( MODULE_DESCRIPTION )
  316. set_shortname( N_( "AtmoLight" ))
  317. set_category( CAT_VIDEO )
  318. set_subcategory( SUBCAT_VIDEO_VFILTER )
  319. set_capability( "video filter2", 0 )
  320. set_section( N_("Choose Devicetype and Connection" ), 0 )
  321. add_integer( CFG_PREFIX "device", DEFAULT_DEVICE,
  322. DRIVER_TEXT, DRIVER_LONGTEXT, false )
  323. change_integer_list( pi_device_type_values,
  324. ppsz_device_type_descriptions )
  325. #if defined(WIN32)
  326. add_string(CFG_PREFIX "serialdev", "COM1",
  327. SERIALDEV_TEXT, SERIALDEV_LONGTEXT, false )
  328. /*
  329. on win32 the executeable external driver application
  330. for automatic start if needed
  331. */
  332. add_loadfile(CFG_PREFIX "atmowinexe", NULL,
  333. ATMOWINEXE_TEXT, ATMOWINEXE_LONGTEXT, false )
  334. #else
  335. add_string(CFG_PREFIX "serialdev", "/dev/ttyUSB0",
  336. SERIALDEV_TEXT, SERIALDEV_LONGTEXT, false )
  337. #endif
  338. /*
  339. color which is showed if you want durring pausing
  340. your movie ... used for both buildin / external
  341. */
  342. set_section( N_("Illuminate the room with this color on pause" ), 0 )
  343. add_bool(CFG_PREFIX "usepausecolor", false,
  344. PCOLOR_TEXT, PCOLOR_LONGTEXT, false)
  345. add_integer_with_range(CFG_PREFIX "pcolor-red", 0, 0, 255,
  346. PCOLOR_RED_TEXT, PCOLOR_RED_LONGTEXT, false)
  347. add_integer_with_range(CFG_PREFIX "pcolor-green", 0, 0, 255,
  348. PCOLOR_GREEN_TEXT, PCOLOR_GREEN_LONGTEXT, false)
  349. add_integer_with_range(CFG_PREFIX "pcolor-blue", 192, 0, 255,
  350. PCOLOR_BLUE_TEXT, PCOLOR_BLUE_LONGTEXT, false)
  351. add_integer_with_range(CFG_PREFIX "fadesteps", 50, 1, 250,
  352. FADESTEPS_TEXT, FADESTEPS_LONGTEXT, false)
  353. /*
  354. color which is showed if you finished watching your movie ...
  355. used for both buildin / external
  356. */
  357. set_section( N_("Illuminate the room with this color on shutdown" ), 0 )
  358. add_integer_with_range(CFG_PREFIX "ecolor-red", 192, 0, 255,
  359. ECOLOR_RED_TEXT, ECOLOR_RED_LONGTEXT, false)
  360. add_integer_with_range(CFG_PREFIX "ecolor-green", 192, 0, 255,
  361. ECOLOR_GREEN_TEXT, ECOLOR_GREEN_LONGTEXT, false)
  362. add_integer_with_range(CFG_PREFIX "ecolor-blue", 192, 0, 255,
  363. ECOLOR_BLUE_TEXT, ECOLOR_BLUE_LONGTEXT, false)
  364. add_integer_with_range(CFG_PREFIX "efadesteps", 50, 1, 250,
  365. EFADESTEPS_TEXT, EFADESTEPS_LONGTEXT, false)
  366. set_section( N_("DMX options" ), 0 )
  367. add_integer_with_range(CFG_PREFIX "dmx-channels", 5, 1, 64,
  368. DMX_CHANNELS_TEXT, DMX_CHANNELS_LONGTEXT, false)
  369. add_string(CFG_PREFIX "dmx-chbase", "0,3,6,9,12",
  370. DMX_CHBASE_TEXT, DMX_CHBASE_LONGTEXT, false )
  371. set_section( N_("MoMoLight options" ), 0 )
  372. add_integer_with_range(CFG_PREFIX "momo-channels", 3, 3, 4,
  373. MOMO_CHANNELS_TEXT, MOMO_CHANNELS_LONGTEXT, false)
  374. /* 2,2,4 means 2 is the default value, 1 minimum amount,
  375. 4 maximum amount
  376. */
  377. set_section( N_("fnordlicht options" ), 0 )
  378. add_integer_with_range(CFG_PREFIX "fnordlicht-amount", 2, 1, 254,
  379. FNORDLICHT_AMOUNT_TEXT,
  380. FNORDLICHT_AMOUNT_LONGTEXT, false)
  381. /*
  382. instead of redefining the original AtmoLight zones with gradient
  383. bitmaps, we can now define the layout of the zones useing these
  384. parameters - the function with the gradient bitmaps would still
  385. work (but for most cases its no longer required)
  386. short description whats this means - f.e. the classic atmo would
  387. have this layout
  388. zones-top = 1 - zone 0
  389. zones-lr = 1 - zone 1 und zone 3
  390. zones-bottom = 1 - zone 2
  391. zone-summary = true - zone 4
  392. Z0
  393. ,------------,
  394. | |
  395. Z3| Z4 | Z1
  396. |____________|
  397. Z2
  398. the zone numbers will be counted clockwise starting at top / left
  399. if you want to split the light at the top, without having a bottom zone
  400. (which is my private config)
  401. zones-top = 2 - zone 0, zone 1
  402. zones-lr = 1 - zone 2 und zone 3
  403. zones-bottom = 0
  404. zone-summary = false
  405. Z0 Z1
  406. ,------------,
  407. | |
  408. Z3| | Z2
  409. |____________|
  410. */
  411. set_section( N_("Zone Layout for the build-in Atmo" ), 0 )
  412. add_integer_with_range(CFG_PREFIX "zones-top", 1, 0, 16,
  413. ZONE_TOP_TEXT, ZONE_TOP_LONGTEXT, false)
  414. add_integer_with_range(CFG_PREFIX "zones-bottom", 1, 0, 16,
  415. ZONE_BOTTOM_TEXT, ZONE_BOTTOM_LONGTEXT, false)
  416. add_integer_with_range(CFG_PREFIX "zones-lr", 1, 0, 16,
  417. ZONE_LR_TEXT, ZONE_LR_LONGTEXT, false)
  418. add_bool(CFG_PREFIX "zone-summary", false,
  419. ZONE_SUMMARY_TEXT, ZONE_SUMMARY_LONGTEXT, false)
  420. /*
  421. settings only for the buildin driver (if external driver app is used
  422. these parameters are ignored.)
  423. definition of parameters for the buildin filter ...
  424. */
  425. set_section( N_("Settings for the built-in Live Video Processor only" ), 0 )
  426. add_integer_with_range(CFG_PREFIX "edgeweightning", 3, 1, 30,
  427. EDGE_TEXT, EDGE_LONGTEXT, false)
  428. add_integer_with_range(CFG_PREFIX "brightness", 100, 50, 300,
  429. BRIGHTNESS_TEXT, BRIGHTNESS_LONGTEXT, false)
  430. add_integer_with_range(CFG_PREFIX "darknesslimit", 3, 0, 10,
  431. DARKNESS_TEXT, DARKNESS_LONGTEXT, false)
  432. add_integer_with_range(CFG_PREFIX "huewinsize", 3, 0, 5,
  433. HUEWINSIZE_TEXT, HUEWINSIZE_LONGTEXT, false)
  434. add_integer_with_range(CFG_PREFIX "satwinsize", 3, 0, 5,
  435. SATWINSIZE_TEXT, SATWINSIZE_LONGTEXT, false)
  436. add_integer(CFG_PREFIX "filtermode", (int)afmCombined,
  437. FILTERMODE_TEXT, FILTERMODE_LONGTEXT, false )
  438. change_integer_list(pi_filtermode_values, ppsz_filtermode_descriptions )
  439. add_integer_with_range(CFG_PREFIX "meanlength", 300, 300, 5000,
  440. MEANLENGTH_TEXT, MEANLENGTH_LONGTEXT, false)
  441. add_integer_with_range(CFG_PREFIX "meanthreshold", 40, 1, 100,
  442. MEANTHRESHOLD_TEXT, MEANTHRESHOLD_LONGTEXT, false)
  443. add_integer_with_range(CFG_PREFIX "percentnew", 50, 1, 100,
  444. MEANPERCENTNEW_TEXT, MEANPERCENTNEW_LONGTEXT, false)
  445. add_integer_with_range(CFG_PREFIX "framedelay", 18, 0, 200,
  446. FRAMEDELAY_TEXT, FRAMEDELAY_LONGTEXT, false)
  447. /*
  448. output channel reordering
  449. */
  450. set_section( N_("Change channel assignment (fixes wrong wiring)" ), 0 )
  451. add_integer( CFG_PREFIX "channel_0", 4,
  452. CHANNEL_0_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
  453. change_integer_list( pi_zone_assignment_values,
  454. ppsz_zone_assignment_descriptions )
  455. add_integer( CFG_PREFIX "channel_1", 3,
  456. CHANNEL_1_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
  457. change_integer_list( pi_zone_assignment_values,
  458. ppsz_zone_assignment_descriptions )
  459. add_integer( CFG_PREFIX "channel_2", 1,
  460. CHANNEL_2_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
  461. change_integer_list( pi_zone_assignment_values,
  462. ppsz_zone_assignment_descriptions )
  463. add_integer( CFG_PREFIX "channel_3", 0,
  464. CHANNEL_3_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
  465. change_integer_list( pi_zone_assignment_values,
  466. ppsz_zone_assignment_descriptions )
  467. add_integer( CFG_PREFIX "channel_4", 2,
  468. CHANNEL_4_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
  469. change_integer_list( pi_zone_assignment_values,
  470. ppsz_zone_assignment_descriptions )
  471. add_string(CFG_PREFIX "channels", "",
  472. CHANNELS_ASSIGN_TEXT, CHANNELS_ASSIGN_LONGTEXT, false )
  473. /*
  474. LED color white calibration
  475. */
  476. set_section( N_("Adjust the white light to your LED stripes" ), 0 )
  477. add_bool(CFG_PREFIX "whiteadj", true,
  478. USEWHITEADJ_TEXT, USEWHITEADJ_LONGTEXT, false)
  479. add_integer_with_range(CFG_PREFIX "white-red", 255, 0, 255,
  480. WHITE_RED_TEXT, WHITE_RED_LONGTEXT, false)
  481. add_integer_with_range(CFG_PREFIX "white-green", 255, 0, 255,
  482. WHITE_GREEN_TEXT, WHITE_GREEN_LONGTEXT, false)
  483. add_integer_with_range(CFG_PREFIX "white-blue", 255, 0, 255,
  484. WHITE_BLUE_TEXT, WHITE_BLUE_LONGTEXT, false)
  485. /* end of definition of parameter for the buildin filter ... part 1 */
  486. /*
  487. only for buildin (external has own definition) per default the calucation
  488. used linear gradients for assigning a priority to the pixel - depending
  489. how near they are to the border ...for changing this you can create 64x48
  490. Pixel BMP files - which contain your own grayscale... (you can produce funny
  491. effects with this...) the images MUST not compressed, should have 24-bit per
  492. pixel, or a simple 256 color grayscale palette
  493. */
  494. set_section( N_("Change gradients" ), 0 )
  495. add_loadfile(CFG_PREFIX "gradient_zone_0", NULL,
  496. ZONE_0_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
  497. add_loadfile(CFG_PREFIX "gradient_zone_1", NULL,
  498. ZONE_1_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
  499. add_loadfile(CFG_PREFIX "gradient_zone_2", NULL,
  500. ZONE_2_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
  501. add_loadfile(CFG_PREFIX "gradient_zone_3", NULL,
  502. ZONE_3_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
  503. add_loadfile(CFG_PREFIX "gradient_zone_4", NULL,
  504. ZONE_4_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
  505. add_directory(CFG_PREFIX "gradient_path", NULL,
  506. GRADIENT_PATH_TEXT, GRADIENT_PATH_LONGTEXT, false )
  507. #if defined(__ATMO_DEBUG__)
  508. add_bool(CFG_PREFIX "saveframes", false,
  509. SAVEFRAMES_TEXT, SAVEFRAMES_LONGTEXT, false)
  510. add_string(CFG_PREFIX "framepath", "",
  511. FRAMEPATH_TEXT, FRAMEPATH_LONGTEXT, false )
  512. #endif
  513. /*
  514. may be later if computers gets more power ;-) than now we increase
  515. the samplesize from which we do the stats for output color calculation
  516. */
  517. add_integer_with_range(CFG_PREFIX "width", 64, 64, 512,
  518. WIDTH_TEXT, WIDTH_LONGTEXT, true)
  519. add_integer_with_range(CFG_PREFIX "height", 48, 48, 384,
  520. HEIGHT_TEXT, HEIGHT_LONGTEXT, true)
  521. add_bool(CFG_PREFIX "showdots", false,
  522. SHOW_DOTS_TEXT, SHOW_DOTS_LONGTEXT, false)
  523. add_shortcut( "atmo" )
  524. set_callbacks( CreateFilter, DestroyFilter )
  525. vlc_module_end ()
  526. static const char *const ppsz_filter_options[] = {
  527. "device",
  528. "serialdev",
  529. "edgeweightning",
  530. "brightness",
  531. "darknesslimit",
  532. "huewinsize",
  533. "satwinsize",
  534. "filtermode",
  535. "meanlength",
  536. "meanthreshold",
  537. "percentnew",
  538. "framedelay",
  539. "zones-top",
  540. "zones-bottom",
  541. "zones-lr",
  542. "zone-summary",
  543. "channel_0",
  544. "channel_1",
  545. "channel_2",
  546. "channel_3",
  547. "channel_4",
  548. "channels",
  549. "whiteadj",
  550. "white-red",
  551. "white-green",
  552. "white-blue",
  553. "usepausecolor",
  554. "pcolor-red",
  555. "pcolor-green",
  556. "pcolor-blue",
  557. "fadesteps",
  558. "ecolor-red",
  559. "ecolor-green",
  560. "ecolor-blue",
  561. "efadesteps",
  562. "dmx-channels",
  563. "dmx-chbase",
  564. "momo-channels",
  565. "fnordlicht-amount",
  566. #if defined(WIN32 )
  567. "atmowinexe",
  568. #endif
  569. #if defined(__ATMO_DEBUG__)
  570. "saveframes" ,
  571. "framepath",
  572. #endif
  573. "width",
  574. "height",
  575. "showdots",
  576. "gradient_zone_0",
  577. "gradient_zone_1",
  578. "gradient_zone_2",
  579. "gradient_zone_3",
  580. "gradient_zone_4",
  581. "gradient_path",
  582. NULL
  583. };
  584. /*****************************************************************************
  585. * fadethread_t: Color Fading Thread
  586. *****************************************************************************
  587. * changes slowly the color of the output if videostream gets paused...
  588. *****************************************************************************
  589. */
  590. typedef struct
  591. {
  592. filter_t *p_filter;
  593. vlc_thread_t thread;
  594. vlc_atomic_t abort;
  595. /* tell the thread which color should be the target of fading */
  596. uint8_t ui_red;
  597. uint8_t ui_green;
  598. uint8_t ui_blue;
  599. /* how many steps should happen until this */
  600. int i_steps;
  601. } fadethread_t;
  602. static void *FadeToColorThread(void *);
  603. /*****************************************************************************
  604. * filter_sys_t: AtmoLight filter method descriptor
  605. *****************************************************************************
  606. * It describes the AtmoLight specific properties of an video filter.
  607. *****************************************************************************/
  608. struct filter_sys_t
  609. {
  610. /*
  611. special for the access of the p_fadethread member all other members
  612. need no special protection so far!
  613. */
  614. vlc_mutex_t filter_lock;
  615. bool b_enabled;
  616. int32_t i_AtmoOldEffect;
  617. bool b_pause_live;
  618. bool b_show_dots;
  619. int32_t i_device_type;
  620. bool b_swap_uv;
  621. int32_t i_atmo_width;
  622. int32_t i_atmo_height;
  623. /* used to disable fadeout if less than 50 frames are processed
  624. used to avoid long time waiting when switch quickly between
  625. deinterlaceing modes, where the output filter chains is rebuild
  626. on each switch
  627. */
  628. int32_t i_frames_processed;
  629. #if defined(__ATMO_DEBUG__)
  630. bool b_saveframes;
  631. uint32_t ui_frame_counter;
  632. char sz_framepath[MAX_PATH];
  633. #endif
  634. /* light color durring movie pause ... */
  635. bool b_usepausecolor;
  636. uint8_t ui_pausecolor_red;
  637. uint8_t ui_pausecolor_green;
  638. uint8_t ui_pausecolor_blue;
  639. int i_fadesteps;
  640. /* light color on movie finish ... */
  641. uint8_t ui_endcolor_red;
  642. uint8_t ui_endcolor_green;
  643. uint8_t ui_endcolor_blue;
  644. int i_endfadesteps;
  645. fadethread_t *p_fadethread;
  646. /* Variables for buildin driver only... */
  647. /* is only present and initialized if the internal driver is used*/
  648. CAtmoConfig *p_atmo_config;
  649. /* storage for temporal settings "volatile" */
  650. CAtmoDynData *p_atmo_dyndata;
  651. /* initialized for buildin driver with AtmoCreateTransferBuffers */
  652. BITMAPINFOHEADER mini_image_format;
  653. /* is only use buildin driver! */
  654. uint8_t *p_atmo_transfer_buffer;
  655. /* end buildin driver */
  656. /*
  657. contains the real output size of the video calculated on
  658. change event of the variable "crop" from vout
  659. */
  660. int32_t i_crop_x_offset;
  661. int32_t i_crop_y_offset;
  662. int32_t i_crop_width;
  663. int32_t i_crop_height;
  664. void (*pf_extract_mini_image) (filter_sys_t *p_sys,
  665. picture_t *p_inpic,
  666. uint8_t *p_transfer_dest);
  667. #if defined( WIN32 )
  668. /* External Library as wrapper arround COM Stuff */
  669. HINSTANCE h_AtmoCtrl;
  670. int32_t (*pf_ctrl_atmo_initialize) (void);
  671. void (*pf_ctrl_atmo_finalize) (int32_t what);
  672. int32_t (*pf_ctrl_atmo_switch_effect) (int32_t);
  673. int32_t (*pf_ctrl_atmo_set_live_source) (int32_t);
  674. void (*pf_ctrl_atmo_create_transfer_buffers) (int32_t, int32_t,
  675. int32_t , int32_t);
  676. uint8_t* (*pf_ctrl_atmo_lock_transfer_buffer) (void);
  677. void (*pf_ctrl_atmo_send_pixel_data) (void);
  678. void (*pf_ctrl_atmo_get_image_size)(int32_t *,int32_t *);
  679. #endif
  680. };
  681. /*
  682. initialize previously configured Atmo Light environment
  683. - if internal is enabled try to access the device on the serial port
  684. - if not internal is enabled and we are on win32 try to initialize
  685. the previously loaded DLL ...
  686. Return Values may be: -1 (failed for some reason - filter will be disabled)
  687. 1 Ok. lets rock
  688. */
  689. static int32_t AtmoInitialize(filter_t *p_filter, bool b_for_thread)
  690. {
  691. filter_sys_t *p_sys = p_filter->p_sys;
  692. if(p_sys->p_atmo_config)
  693. {
  694. if(!b_for_thread)
  695. {
  696. /* open com port */
  697. /* setup Output Threads ... */
  698. msg_Dbg( p_filter, "open atmo device...");
  699. if(CAtmoTools::RecreateConnection(p_sys->p_atmo_dyndata)
  700. == ATMO_TRUE)
  701. {
  702. return 1;
  703. } else {
  704. msg_Err( p_filter,"failed to open atmo device, "\
  705. "some other software/driver may use it?");
  706. }
  707. }
  708. #if defined(WIN32)
  709. } else if(p_sys->pf_ctrl_atmo_initialize)
  710. {
  711. /* on win32 with active ctrl dll */
  712. return p_sys->pf_ctrl_atmo_initialize();
  713. #endif
  714. }
  715. return -1;
  716. }
  717. /*
  718. prepare the shutdown of the effect threads,
  719. for build in filter - close the serialport after finishing the threads...
  720. cleanup possible loaded DLL...
  721. */
  722. static void AtmoFinalize(filter_t *p_filter, int32_t what)
  723. {
  724. filter_sys_t *p_sys = p_filter->p_sys;
  725. if(p_sys->p_atmo_config)
  726. {
  727. if(what == 1)
  728. {
  729. CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
  730. if(p_atmo_dyndata)
  731. {
  732. p_atmo_dyndata->LockCriticalSection();
  733. CAtmoInput *p_input = p_atmo_dyndata->getLiveInput();
  734. p_atmo_dyndata->setLiveInput( NULL );
  735. if(p_input != NULL)
  736. {
  737. p_input->Terminate();
  738. delete p_input;
  739. msg_Dbg( p_filter, "input thread died peacefully");
  740. }
  741. CThread *p_effect_thread = p_atmo_dyndata->getEffectThread();
  742. p_atmo_dyndata->setEffectThread(NULL);
  743. if(p_effect_thread != NULL)
  744. {
  745. /*
  746. forced the thread to die...
  747. and wait for termination of the thread
  748. */
  749. p_effect_thread->Terminate();
  750. delete p_effect_thread;
  751. msg_Dbg( p_filter, "effect thread died peacefully");
  752. }
  753. CAtmoPacketQueue *p_queue =
  754. p_atmo_dyndata->getLivePacketQueue();
  755. p_atmo_dyndata->setLivePacketQueue( NULL );
  756. if(p_queue != NULL)
  757. {
  758. delete p_queue;
  759. msg_Dbg( p_filter, "packetqueue removed");
  760. }
  761. /*
  762. close serial port if it is open (all OS specific is inside
  763. CAtmoSerialConnection implemented / defined)
  764. */
  765. CAtmoConnection *p_atmo_connection =
  766. p_atmo_dyndata->getAtmoConnection();
  767. p_atmo_dyndata->setAtmoConnection(NULL);
  768. if(p_atmo_connection) {
  769. p_atmo_connection->CloseConnection();
  770. delete p_atmo_connection;
  771. }
  772. p_atmo_dyndata->UnLockCriticalSection();
  773. }
  774. }
  775. #if defined(WIN32)
  776. } else if(p_sys->pf_ctrl_atmo_finalize)
  777. {
  778. /* on win32 with active ctrl dll */
  779. p_sys->pf_ctrl_atmo_finalize(what);
  780. #endif
  781. }
  782. }
  783. /*
  784. switch the current light effect to LiveView
  785. */
  786. static int32_t AtmoSwitchEffect(filter_t *p_filter, int32_t newMode)
  787. {
  788. filter_sys_t *p_sys = p_filter->p_sys;
  789. msg_Dbg( p_filter, "AtmoSwitchEffect %d", newMode );
  790. if(p_sys->p_atmo_config)
  791. {
  792. return CAtmoTools::SwitchEffect(p_sys->p_atmo_dyndata, emLivePicture);
  793. #if defined(WIN32)
  794. } else if(p_sys->pf_ctrl_atmo_switch_effect)
  795. {
  796. /* on win32 with active ctrl dll */
  797. return p_sys->pf_ctrl_atmo_switch_effect( newMode );
  798. #endif
  799. }
  800. return emDisabled;
  801. }
  802. /*
  803. set the current live picture source, does only something on win32,
  804. with the external libraries - if the buildin effects are used nothing
  805. happens...
  806. */
  807. static int32_t AtmoSetLiveSource(filter_t *p_filter, int32_t newSource)
  808. {
  809. filter_sys_t *p_sys = p_filter->p_sys;
  810. msg_Dbg( p_filter, "AtmoSetLiveSource %d", newSource );
  811. if(p_sys->p_atmo_config)
  812. {
  813. /*
  814. buildin driver
  815. doesnt know different sources so this
  816. function call would just do nothing special
  817. in this case
  818. */
  819. #if defined(WIN32)
  820. } else if(p_sys->pf_ctrl_atmo_set_live_source)
  821. {
  822. /* on win32 with active ctrl dll */
  823. return p_sys->pf_ctrl_atmo_set_live_source(newSource);
  824. #endif
  825. }
  826. return lvsGDI;
  827. }
  828. /*
  829. setup the pixel transferbuffers which is used to transfer pixeldata from
  830. the filter to the effect thread, and possible accross the process
  831. boundaries on win32, with the external DLL
  832. */
  833. static void AtmoCreateTransferBuffers(filter_t *p_filter,
  834. int32_t FourCC,
  835. int32_t bytePerPixel,
  836. int32_t width,
  837. int32_t height)
  838. {
  839. filter_sys_t *p_sys = p_filter->p_sys;
  840. if(p_sys->p_atmo_config)
  841. {
  842. /*
  843. we need a buffer where the image is stored (only for transfer
  844. to the processing thread)
  845. */
  846. free( p_sys->p_atmo_transfer_buffer );
  847. p_sys->p_atmo_transfer_buffer = (uint8_t *)malloc(bytePerPixel *
  848. width * height);
  849. memset(&p_sys->mini_image_format,0,sizeof(BITMAPINFOHEADER));
  850. p_sys->mini_image_format.biSize = sizeof(BITMAPINFOHEADER);
  851. p_sys->mini_image_format.biWidth = width;
  852. p_sys->mini_image_format.biHeight = height;
  853. p_sys->mini_image_format.biBitCount = bytePerPixel*8;
  854. p_sys->mini_image_format.biCompression = FourCC;
  855. #if defined(WIN32)
  856. } else if(p_sys->pf_ctrl_atmo_create_transfer_buffers)
  857. {
  858. /* on win32 with active ctrl dll */
  859. p_sys->pf_ctrl_atmo_create_transfer_buffers(FourCC,
  860. bytePerPixel,
  861. width,
  862. height);
  863. #endif
  864. }
  865. }
  866. /*
  867. acquire the transfer buffer pointer the buildin version only
  868. returns the pointer to the allocated buffer ... the
  869. external version on win32 has to do some COM stuff to lock the
  870. Variant Byte array which is behind the buffer
  871. */
  872. static uint8_t* AtmoLockTransferBuffer(filter_t *p_filter)
  873. {
  874. filter_sys_t *p_sys = p_filter->p_sys;
  875. if(p_sys->p_atmo_config)
  876. {
  877. return p_sys->p_atmo_transfer_buffer;
  878. #if defined(WIN32)
  879. } else if(p_sys->pf_ctrl_atmo_lock_transfer_buffer)
  880. {
  881. /* on win32 with active ctrl dll */
  882. return p_sys->pf_ctrl_atmo_lock_transfer_buffer();
  883. #endif
  884. }
  885. return NULL;
  886. }
  887. /*
  888. send the content of current pixel buffer got with AtmoLockTransferBuffer
  889. to the processing threads
  890. - build in version - will forward the data to AtmoExternalCaptureInput Thread
  891. - win32 external - will do the same, but across the process boundaries via
  892. COM to the AtmoWinA.exe Process
  893. */
  894. static void AtmoSendPixelData(filter_t *p_filter)
  895. {
  896. filter_sys_t *p_sys = p_filter->p_sys;
  897. if(p_sys->p_atmo_config && p_sys->p_atmo_transfer_buffer)
  898. {
  899. CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
  900. if(p_atmo_dyndata &&
  901. (p_atmo_dyndata->getLivePictureSource() == lpsExtern))
  902. {
  903. /*
  904. the cast will go Ok because we are inside videolan there is only
  905. this kind of effect thread implemented!
  906. */
  907. CAtmoExternalCaptureInput *p_atmo_external_capture_input_thread =
  908. (CAtmoExternalCaptureInput *)p_atmo_dyndata->getLiveInput();
  909. if(p_atmo_external_capture_input_thread)
  910. {
  911. /*
  912. the same as above inside videolan only this single kind of
  913. input exists so we can cast without further tests!
  914. this call will do a 1:1 copy of this buffer, and wakeup
  915. the thread from normal sleeping
  916. */
  917. p_atmo_external_capture_input_thread->
  918. DeliverNewSourceDataPaket(&p_sys->mini_image_format,
  919. p_sys->p_atmo_transfer_buffer);
  920. }
  921. }
  922. #if defined(WIN32)
  923. } else if(p_sys->pf_ctrl_atmo_send_pixel_data)
  924. {
  925. /* on win32 with active ctrl dll */
  926. p_sys->pf_ctrl_atmo_send_pixel_data();
  927. #endif
  928. } else
  929. {
  930. msg_Warn( p_filter, "AtmoSendPixelData no method");
  931. }
  932. }
  933. /*
  934. Shutdown AtmoLight finally - is call from DestroyFilter
  935. does the cleanup restores the effectmode on the external Software
  936. (only win32) and possible setup the final light ...
  937. */
  938. static void Atmo_Shutdown(filter_t *p_filter)
  939. {
  940. filter_sys_t *p_sys = p_filter->p_sys;
  941. if(p_sys->b_enabled)
  942. {
  943. msg_Dbg( p_filter, "shut down atmo!");
  944. /*
  945. if there is a still running show pause color thread kill him!
  946. */
  947. CheckAndStopFadeThread(p_filter);
  948. // perpare spawn fadeing thread
  949. vlc_mutex_lock( &p_sys->filter_lock );
  950. /*
  951. fade to end color (in case of external AtmoWin Software
  952. assume that the static color will equal to this
  953. one to get a soft change and no flash!
  954. */
  955. p_sys->b_pause_live = true;
  956. p_sys->p_fadethread = (fadethread_t *)calloc( 1, sizeof(fadethread_t) );
  957. p_sys->p_fadethread->p_filter = p_filter;
  958. p_sys->p_fadethread->ui_red = p_sys->ui_endcolor_red;
  959. p_sys->p_fadethread->ui_green = p_sys->ui_endcolor_green;
  960. p_sys->p_fadethread->ui_blue = p_sys->ui_endcolor_blue;
  961. if(p_sys->i_frames_processed < 50)
  962. p_sys->p_fadethread->i_steps = 1;
  963. else
  964. p_sys->p_fadethread->i_steps = p_sys->i_endfadesteps;
  965. vlc_atomic_set(&p_sys->p_fadethread->abort, 0);
  966. if( vlc_clone( &p_sys->p_fadethread->thread,
  967. FadeToColorThread,
  968. p_sys->p_fadethread,
  969. VLC_THREAD_PRIORITY_LOW ) )
  970. {
  971. msg_Err( p_filter, "cannot create FadeToColorThread" );
  972. free( p_sys->p_fadethread );
  973. p_sys->p_fadethread = NULL;
  974. vlc_mutex_unlock( &p_sys->filter_lock );
  975. } else {
  976. vlc_mutex_unlock( &p_sys->filter_lock );
  977. /* wait for the thread... */
  978. vlc_join(p_sys->p_fadethread->thread, NULL);
  979. free(p_sys->p_fadethread);
  980. p_sys->p_fadethread = NULL;
  981. }
  982. /*
  983. the following happens only useing the
  984. external AtmoWin Device Software
  985. */
  986. if( !p_sys->p_atmo_config )
  987. {
  988. if(p_sys->i_AtmoOldEffect != emLivePicture)
  989. AtmoSwitchEffect( p_filter, p_sys->i_AtmoOldEffect);
  990. else
  991. AtmoSetLiveSource( p_filter, lvsGDI );
  992. }
  993. /* close device connection etc. */
  994. AtmoFinalize(p_filter, 1);
  995. /* disable filter method .. */
  996. p_sys->b_enabled = false;
  997. }
  998. }
  999. /*
  1000. depending on mode setup imagesize to 64x48(classic), or defined
  1001. resolution of external atmowin.exe on windows
  1002. */
  1003. static void Atmo_SetupImageSize(filter_t *p_filter)
  1004. {
  1005. filter_sys_t *p_sys = p_filter->p_sys;
  1006. /*
  1007. size of extracted image by default 64x48 (other imagesizes are
  1008. currently ignored by AtmoWin)
  1009. */
  1010. p_sys->i_atmo_width = var_CreateGetIntegerCommand( p_filter,
  1011. CFG_PREFIX "width");
  1012. p_sys->i_atmo_height = var_CreateGetIntegerCommand( p_filter,
  1013. CFG_PREFIX "height");
  1014. if(p_sys->p_atmo_config)
  1015. {
  1016. #if defined(WIN32)
  1017. } else if(p_sys->pf_ctrl_atmo_get_image_size)
  1018. {
  1019. /* on win32 with active ctrl dll */
  1020. p_sys->pf_ctrl_atmo_get_image_size( &p_sys->i_atmo_width,
  1021. &p_sys->i_atmo_height );
  1022. #endif
  1023. }
  1024. msg_Dbg(p_filter,"sample image size %d * %d pixels", p_sys->i_atmo_width,
  1025. p_sys->i_atmo_height);
  1026. }
  1027. /*
  1028. initialize the zone and channel mapping for the buildin atmolight adapter
  1029. */
  1030. static void Atmo_SetupBuildZones(filter_t *p_filter)
  1031. {
  1032. filter_sys_t *p_sys = p_filter->p_sys;
  1033. p_sys->p_atmo_dyndata->LockCriticalSection();
  1034. CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
  1035. CAtmoChannelAssignment *p_channel_assignment =
  1036. p_atmo_config->getChannelAssignment(0);
  1037. // channel 0 - zone 4
  1038. p_channel_assignment->setZoneIndex( 0, var_CreateGetIntegerCommand(
  1039. p_filter, CFG_PREFIX "channel_0")
  1040. );
  1041. // channel 1 - zone 3
  1042. p_channel_assignment->setZoneIndex( 1, var_CreateGetIntegerCommand(
  1043. p_filter, CFG_PREFIX "channel_1")
  1044. );
  1045. // channel 2 - zone 1
  1046. p_channel_assignment->setZoneIndex( 2, var_CreateGetIntegerCommand(
  1047. p_filter, CFG_PREFIX "channel_2")
  1048. );
  1049. // channel 3 - zone 0
  1050. p_channel_assignment->setZoneIndex( 3, var_CreateGetIntegerCommand(
  1051. p_filter, CFG_PREFIX "channel_3")
  1052. );
  1053. // channel 4 - zone 2
  1054. p_channel_assignment->setZoneIndex( 4, var_CreateGetIntegerCommand(
  1055. p_filter, CFG_PREFIX "channel_4")
  1056. );
  1057. char *psz_channels = var_CreateGetStringCommand(
  1058. p_filter,
  1059. CFG_PREFIX "channels"
  1060. );
  1061. if( !EMPTY_STR(psz_channels) )
  1062. {
  1063. msg_Dbg( p_filter, "deal with new zone mapping %s", psz_channels );
  1064. int channel = 0;
  1065. char *psz_temp = psz_channels;
  1066. char *psz_start = psz_temp;
  1067. while( *psz_temp )
  1068. {
  1069. if(*psz_temp == ',' || *psz_temp == ';')
  1070. {
  1071. *psz_temp = 0;
  1072. if(*psz_start)
  1073. {
  1074. int zone = atoi( psz_start );
  1075. if( zone < -1 ||
  1076. zone >= p_channel_assignment->getSize()) {
  1077. msg_Warn( p_filter, "Zone %d out of range -1..%d",
  1078. zone, p_channel_assignment->getSize()-1 );
  1079. } else {
  1080. p_channel_assignment->setZoneIndex( channel, zone );
  1081. channel++;
  1082. }
  1083. }
  1084. psz_start = psz_temp;
  1085. psz_start++;
  1086. }
  1087. psz_temp++;
  1088. }
  1089. /*
  1090. process the rest of the string
  1091. */
  1092. if( *psz_start && !*psz_temp )
  1093. {
  1094. int zone = atoi( psz_start );
  1095. if( zone < -1 ||
  1096. zone >= p_channel_assignment->getSize()) {
  1097. msg_Warn( p_filter, "Zone %d out of range -1..%d",
  1098. zone, p_channel_assignment->getSize()-1 );
  1099. } else {
  1100. p_channel_assignment->setZoneIndex( channel, zone );
  1101. }
  1102. }
  1103. }
  1104. free( psz_channels );
  1105. for(int i=0;i< p_channel_assignment->getSize() ;i++)
  1106. msg_Info( p_filter, "map zone %d to hardware channel %d",
  1107. p_channel_assignment->getZoneIndex( i ),
  1108. i
  1109. );
  1110. p_sys->p_atmo_dyndata->getAtmoConnection()
  1111. ->SetChannelAssignment( p_channel_assignment );
  1112. /*
  1113. calculate the default gradients for each zone!
  1114. depending on the zone layout set before, this now
  1115. supports also multiple gradients on each side
  1116. (older versions could do this only with external
  1117. gradient bitmaps)
  1118. */
  1119. p_sys->p_atmo_dyndata->CalculateDefaultZones();
  1120. /*
  1121. first try to load the old style defined gradient bitmaps
  1122. this could only be done for the first five zones
  1123. - should be deprecated -
  1124. */
  1125. CAtmoZoneDefinition *p_zone;
  1126. char psz_gradient_var_name[30];
  1127. char *psz_gradient_file;
  1128. for(int i=0;i<CLASSIC_ATMO_NUM_ZONES;i++)
  1129. {
  1130. sprintf(psz_gradient_var_name, CFG_PREFIX "gradient_zone_%d", i);
  1131. psz_gradient_file = var_CreateGetStringCommand(
  1132. p_filter,
  1133. psz_gradient_var_name
  1134. );
  1135. if( !EMPTY_STR(psz_gradient_file) )
  1136. {
  1137. msg_Dbg( p_filter, "loading gradientfile %s for "\
  1138. "zone %d", psz_gradient_file, i);
  1139. p_zone = p_atmo_config->getZoneDefinition(i);
  1140. if( p_zone )
  1141. {
  1142. int i_res = p_zone->LoadGradientFromBitmap(psz_gradient_file);
  1143. if(i_res != ATMO_LOAD_GRADIENT_OK)
  1144. {
  1145. msg_Err( p_filter,"failed to load gradient '%s' with "\
  1146. "error %d",psz_gradient_file,i_res);
  1147. }
  1148. }
  1149. }
  1150. free( psz_gradient_file );
  1151. }
  1152. /*
  1153. the new approach try to load a gradient bitmap for each zone
  1154. from a previously defined folder containing
  1155. zone_0.bmp
  1156. zone_1.bmp
  1157. zone_2.bmp etc.
  1158. */
  1159. char *psz_gradient_path = var_CreateGetStringCommand(
  1160. p_filter,
  1161. CFG_PREFIX "gradient_path"
  1162. );
  1163. if( EMPTY_STR(psz_gradient_path) )
  1164. {
  1165. char *psz_file_name = (char *)malloc( strlen(psz_gradient_path) + 16 );
  1166. assert( psz_file_name );
  1167. for(int i=0; i < p_atmo_config->getZoneCount(); i++ )
  1168. {
  1169. p_zone = p_atmo_config->getZoneDefinition(i);
  1170. if( p_zone )
  1171. {
  1172. sprintf(psz_file_name, "%s%szone_%d.bmp",
  1173. psz_gradient_path, DIR_SEP, i );
  1174. int i_res = p_zone->LoadGradientFromBitmap( psz_file_name );
  1175. if( i_res == ATMO_LOAD_GRADIENT_OK )
  1176. {
  1177. msg_Dbg( p_filter, "loaded gradientfile %s for "\
  1178. "zone %d", psz_file_name, i);
  1179. }
  1180. if( (i_res != ATMO_LOAD_GRADIENT_OK) &&
  1181. (i_res != ATMO_LOAD_GRADIENT_FILENOTFOND) )
  1182. {
  1183. msg_Err( p_filter,"failed to load gradient '%s' with "\
  1184. "error %d",psz_file_name,i_res);
  1185. }
  1186. }
  1187. }
  1188. free( psz_file_name );
  1189. }
  1190. free( psz_gradient_path );
  1191. p_sys->p_atmo_dyndata->UnLockCriticalSection();
  1192. }
  1193. static void Atmo_SetupConfig(filter_t *p_filter, CAtmoConfig *p_atmo_config)
  1194. {
  1195. /*
  1196. figuring out the device ports (com-ports, ttys)
  1197. */
  1198. char *psz_serialdev = var_CreateGetStringCommand( p_filter,
  1199. CFG_PREFIX "serialdev" );
  1200. char *psz_temp = psz_serialdev;
  1201. if( !EMPTY_STR(psz_serialdev) )
  1202. {
  1203. char *psz_token;
  1204. int i_port = 0;
  1205. int i;
  1206. int j;
  1207. msg_Dbg( p_filter, "use port(s) %s",psz_serialdev);
  1208. /*
  1209. psz_serialdev - may contain up to 4 COM ports for the quattro device
  1210. the quattro device is just hack of useing 4 classic devices as one
  1211. logical device - thanks that usb-com-ports exists :)
  1212. as Seperator I defined , or ; with the hope that these
  1213. characters are never part of a device name
  1214. */
  1215. while( (psz_token = strsep(&psz_temp, ",;")) != NULL && i_port < 4 )
  1216. {
  1217. /*
  1218. psz_token may contain spaces we have to trim away
  1219. */
  1220. i = 0;
  1221. j = 0;
  1222. /*
  1223. find first none space in string
  1224. */
  1225. while( psz_token[i] == 32 ) i++;
  1226. /*
  1227. contains string only spaces or is empty? skip it
  1228. */
  1229. if( !psz_token[i] )
  1230. continue;
  1231. /*
  1232. trim
  1233. */
  1234. while( psz_token[i] && psz_token[i] != 32 )
  1235. psz_token[ j++ ] = psz_token[ i++ ];
  1236. psz_token[j++] = 0;
  1237. msg_Dbg( p_filter, "Serial Device [%d]: %s", i_port, psz_token );
  1238. p_atmo_config->setSerialDevice( i_port, psz_token );
  1239. i_port++;
  1240. }
  1241. }
  1242. else
  1243. {
  1244. msg_Err(p_filter,"no serial devicename(s) set");
  1245. }
  1246. free( psz_serialdev );
  1247. /*
  1248. configuration of light source layout arround the display
  1249. */
  1250. p_atmo_config->setZonesTopCount(
  1251. var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-top")
  1252. );
  1253. p_atmo_config->setZonesBottomCount(
  1254. var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-bottom")
  1255. );
  1256. p_atmo_config->setZonesLRCount(
  1257. var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-lr")
  1258. );
  1259. p_atmo_config->setZoneSummary(
  1260. var_CreateGetBoolCommand( p_filter, CFG_PREFIX "zone-summary")
  1261. );
  1262. p_atmo_config->setLiveViewFilterMode(
  1263. (AtmoFilterMode)var_CreateGetIntegerCommand( p_filter,
  1264. CFG_PREFIX "filtermode")
  1265. );
  1266. p_atmo_config->setLiveViewFilter_PercentNew(
  1267. var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "percentnew")
  1268. );
  1269. p_atmo_config->setLiveViewFilter_MeanLength(
  1270. var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "meanlength")
  1271. );
  1272. p_atmo_config->setLiveViewFilter_MeanThreshold(
  1273. var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "meanthreshold")
  1274. );
  1275. p_atmo_config->setLiveView_EdgeWeighting(
  1276. var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "edgeweightning")
  1277. );
  1278. p_atmo_config->setLiveView_BrightCorrect(
  1279. var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "brightness")
  1280. );
  1281. p_atmo_config->setLiveView_DarknessLimit(
  1282. var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "darknesslimit")
  1283. );
  1284. p_atmo_config->setLiveView_HueWinSize(
  1285. var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "huewinsize")
  1286. );
  1287. p_atmo_config->setLiveView_SatWinSize(
  1288. var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "satwinsize")
  1289. );
  1290. /* currently not required inside vlc */
  1291. p_atmo_config->setLiveView_WidescreenMode( 0 );
  1292. p_atmo_config->setLiveView_FrameDelay(
  1293. var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "framedelay")
  1294. );
  1295. p_atmo_config->setUseSoftwareWhiteAdj(
  1296. var_CreateGetBoolCommand( p_filter, CFG_PREFIX "whiteadj")
  1297. );
  1298. p_atmo_config->setWhiteAdjustment_Red(
  1299. var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-red")
  1300. );
  1301. p_atmo_config->setWhiteAdjustment_Green(
  1302. var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-green")
  1303. );
  1304. p_atmo_config->setWhiteAdjustment_Blue(
  1305. var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-blue")
  1306. );
  1307. /*
  1308. settings for DMX device only
  1309. */
  1310. p_atmo_config->setDMX_RGB_Channels(
  1311. var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "dmx-channels")
  1312. );
  1313. char *psz_chbase = var_CreateGetStringCommand( p_filter,
  1314. CFG_PREFIX "dmx-chbase" );
  1315. if( !EMPTY_STR(psz_chbase) )
  1316. p_atmo_config->setDMX_BaseChannels( psz_chbase );
  1317. free( psz_chbase );
  1318. /*
  1319. momolight options
  1320. */
  1321. p_atmo_config->setMoMo_Channels(
  1322. var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "momo-channels")
  1323. );
  1324. /*
  1325. fnordlicht options
  1326. */
  1327. p_atmo_config->setFnordlicht_Amount(
  1328. var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "fnordlicht-amount")
  1329. );
  1330. }
  1331. /*
  1332. initialize the filter_sys_t structure with the data from the settings
  1333. variables - if the external filter on win32 is enabled try loading the DLL,
  1334. if this fails fallback to the buildin software
  1335. */
  1336. static void Atmo_SetupParameters(filter_t *p_filter)
  1337. {
  1338. filter_sys_t *p_sys = p_filter->p_sys;
  1339. /* default filter disabled until DLL loaded and Init Success!*/
  1340. p_sys->b_enabled = false;
  1341. /* setup default mini image size (may be later a user option) */
  1342. p_sys->i_atmo_width = 64;
  1343. p_sys->i_atmo_height = 48;
  1344. p_sys->i_device_type = var_CreateGetIntegerCommand( p_filter,
  1345. CFG_PREFIX "device");
  1346. /*
  1347. i_device_type
  1348. 0 => use AtmoWin Software (only win32)
  1349. 1 => use AtmoClassicConnection (direct)
  1350. 2 => use AtmoMultiConnection (direct up to four serial ports required)
  1351. 3 => use AtmoDmxConnection (simple serial DMX Device up to 255 channels)
  1352. */
  1353. #if defined(WIN32)
  1354. /*
  1355. only on WIN32 the user has the choice between
  1356. internal driver and external
  1357. */
  1358. if(p_sys->i_device_type == 0) {
  1359. /* Load the Com Wrapper Library (source available) */
  1360. p_sys->h_AtmoCtrl = LoadLibraryA("AtmoCtrlLib.dll");
  1361. if(p_sys->h_AtmoCtrl == NULL)
  1362. {
  1363. /*
  1364. be clever if the location of atmowina.exe is set
  1365. try to load the dll from the same folder :-)
  1366. */
  1367. char *psz_path = var_CreateGetStringCommand( p_filter,
  1368. CFG_PREFIX "atmowinexe" );
  1369. if( !EMPTY_STR(psz_path) )
  1370. {
  1371. char *psz_bs = strrchr( psz_path , '\\');
  1372. if( psz_bs )
  1373. {
  1374. *psz_bs = 0;
  1375. /*
  1376. now format a new dll filename with complete path
  1377. */
  1378. char *psz_dllname = NULL;
  1379. asprintf( &psz_dllname, "%s\\AtmoCtrlLib.dll", psz_path );
  1380. if( psz_dllname )
  1381. {
  1382. msg_Dbg( p_filter, "Try Loading '%s'", psz_dllname );
  1383. p_sys->h_AtmoCtrl = LoadLibraryA( psz_dllname );
  1384. }
  1385. free( psz_dllname );
  1386. }
  1387. }
  1388. free( psz_path );
  1389. }
  1390. if(p_sys->h_AtmoCtrl != NULL)
  1391. {
  1392. msg_Dbg( p_filter, "Load Library ok!");
  1393. /* importing all required functions I hope*/
  1394. p_sys->pf_ctrl_atmo_initialize =
  1395. (int32_t (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,
  1396. "AtmoInitialize");
  1397. if(!p_sys->pf_ctrl_atmo_initialize)
  1398. msg_Err( p_filter, "export AtmoInitialize missing.");
  1399. p_sys->pf_ctrl_atmo_finalize =
  1400. (void (*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,
  1401. "AtmoFinalize");
  1402. if(!p_sys->pf_ctrl_atmo_finalize)
  1403. msg_Err( p_filter, "export AtmoFinalize missing.");
  1404. p_sys->pf_ctrl_atmo_switch_effect =
  1405. (int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,
  1406. "AtmoSwitchEffect");
  1407. if(!p_sys->pf_ctrl_atmo_switch_effect)
  1408. msg_Err( p_filter, "export AtmoSwitchEffect missing.");
  1409. p_sys->pf_ctrl_atmo_set_live_source =
  1410. (int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,
  1411. "AtmoSetLiveSource");
  1412. if(!p_sys->pf_ctrl_atmo_set_live_source)
  1413. msg_Err( p_filter, "export AtmoSetLiveSource missing.");
  1414. p_sys->pf_ctrl_atmo_create_transfer_buffers =
  1415. (void (*)(int32_t, int32_t, int32_t , int32_t))
  1416. GetProcAddress(p_sys->h_AtmoCtrl,"AtmoCreateTransferBuffers");
  1417. if(!p_sys->pf_ctrl_atmo_create_transfer_buffers)
  1418. msg_Err( p_filter, "export AtmoCreateTransferBuffers missing.");
  1419. p_sys->pf_ctrl_atmo_lock_transfer_buffer=
  1420. (uint8_t*(*) (void))GetProcAddress(p_sys->h_AtmoCtrl,
  1421. "AtmoLockTransferBuffer");
  1422. if(!p_sys->pf_ctrl_atmo_lock_transfer_buffer)
  1423. msg_Err( p_filter, "export AtmoLockTransferBuffer missing.");
  1424. p_sys->pf_ctrl_atmo_send_pixel_data =
  1425. (void (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,
  1426. "AtmoSendPixelData");
  1427. if(!p_sys->pf_ctrl_atmo_send_pixel_data)
  1428. msg_Err( p_filter, "export AtmoSendPixelData missing.");
  1429. p_sys->pf_ctrl_atmo_get_image_size =
  1430. (void (*)(int32_t*,int32_t*))GetProcAddress(p_sys->h_AtmoCtrl,
  1431. "AtmoWinGetImageSize");
  1432. if(!p_sys->pf_ctrl_atmo_get_image_size)
  1433. msg_Err( p_filter, "export AtmoWinGetImageSize missing.");
  1434. } else {
  1435. /* the DLL is missing try internal filter ...*/
  1436. msg_Warn( p_filter,
  1437. "AtmoCtrlLib.dll missing fallback to internal atmo classic driver");
  1438. p_sys->i_device_type = 1;
  1439. }
  1440. }
  1441. #endif
  1442. if(p_sys->i_device_type >= 1) {
  1443. msg_Dbg( p_filter, "try use buildin driver %d ", p_sys->i_device_type);
  1444. /*
  1445. now we have to read a lof of options from the config dialog
  1446. most important the serial device if not set ... we can skip
  1447. the rest and disable the filter...
  1448. */
  1449. p_sys->p_atmo_config = new CAtmoConfig();
  1450. p_sys->p_atmo_dyndata = new CAtmoDynData(
  1451. (vlc_object_t *)p_filter,
  1452. p_sys->p_atmo_config
  1453. );
  1454. Atmo_SetupConfig( p_filter, p_sys->p_atmo_config );
  1455. switch(p_sys->i_device_type)
  1456. {
  1457. case 1:
  1458. p_sys->p_atmo_config->setConnectionType( actClassicAtmo );
  1459. break;
  1460. case 2:
  1461. p_sys->p_atmo_config->setConnectionType( actMultiAtmo );
  1462. break;
  1463. case 3:
  1464. p_sys->p_atmo_config->setConnectionType( actDMX );
  1465. break;
  1466. case 4:
  1467. p_sys->p_atmo_config->setConnectionType( actMoMoLight );
  1468. break;
  1469. case 5:
  1470. p_sys->p_atmo_config->setConnectionType( actFnordlicht );
  1471. break;
  1472. default:
  1473. msg_Warn( p_filter, "invalid device type %d found",
  1474. p_sys->i_device_type );
  1475. }
  1476. msg_Dbg( p_filter, "buildin driver config set");
  1477. }
  1478. switch( p_filter->fmt_in.video.i_chroma )
  1479. {
  1480. case VLC_CODEC_I420:
  1481. p_sys->pf_extract_mini_image = ExtractMiniImage_YUV;
  1482. p_sys->b_swap_uv = false;
  1483. break;
  1484. case VLC_CODEC_YV12:
  1485. p_sys->pf_extract_mini_image = ExtractMiniImage_YUV;
  1486. p_sys->b_swap_uv = true;
  1487. break;
  1488. default:
  1489. msg_Warn( p_filter, "InitFilter-unsupported chroma: %4.4s",
  1490. (char *)&p_filter->fmt_in.video.i_chroma);
  1491. p_sys->pf_extract_mini_image = NULL;
  1492. }
  1493. /*
  1494. for debugging purpose show the samplinggrid on each frame as
  1495. white dots
  1496. */
  1497. p_sys->b_show_dots = var_CreateGetBoolCommand( p_filter,
  1498. CFG_PREFIX "showdots"
  1499. );
  1500. #if defined(__ATMO_DEBUG__)
  1501. /* save debug images to a folder as Bitmap files ? */
  1502. p_sys->b_saveframes = var_CreateGetBoolCommand( p_filter,
  1503. CFG_PREFIX "saveframes"
  1504. );
  1505. msg_Dbg(p_filter,"saveframes = %d", (int)p_sys->b_saveframes);
  1506. /*
  1507. read debug image folder from config
  1508. */
  1509. psz_path = var_CreateGetStringCommand( p_filter, CFG_PREFIX "framepath" );
  1510. if(psz_path != NULL)
  1511. {
  1512. strcpy(p_sys->sz_framepath, psz_path);
  1513. #if defined( WIN32 ) || defined( __OS2__ )
  1514. size_t i_strlen = strlen(p_sys->sz_framepath);
  1515. if((i_strlen>0) && (p_sys->sz_framepath[i_strlen-1] != '\\'))
  1516. {
  1517. p_sys->sz_framepath[i_strlen] = '\\';
  1518. p_sys->sz_framepath[i_strlen+1] = 0;
  1519. }
  1520. #endif
  1521. free(psz_path);
  1522. }
  1523. msg_Dbg(p_filter,"saveframesfolder %s",p_sys->sz_framepath);
  1524. #endif
  1525. /*
  1526. because atmowin could also be used for lighten up the room - I think if you
  1527. pause the video it would be useful to get a little bit more light into to
  1528. your living room? - instead switching on a lamp?
  1529. */
  1530. p_sys->b_usepausecolor = var_CreateGetBoolCommand( p_filter,
  1531. CFG_PREFIX "usepausecolor" );
  1532. p_sys->ui_pausecolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
  1533. CFG_PREFIX "pcolor-red");
  1534. p_sys->ui_pausecolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
  1535. CFG_PREFIX "pcolor-green");
  1536. p_sys->ui_pausecolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
  1537. CFG_PREFIX "pcolor-blue");
  1538. p_sys->i_fadesteps = var_CreateGetIntegerCommand( p_filter,
  1539. CFG_PREFIX "fadesteps");
  1540. if(p_sys->i_fadesteps < 1)
  1541. p_sys->i_fadesteps = 1;
  1542. msg_Dbg(p_filter,"use pause color %d, RGB: %d, %d, %d, Fadesteps: %d",
  1543. (int)p_sys->b_usepausecolor,
  1544. p_sys->ui_pausecolor_red,
  1545. p_sys->ui_pausecolor_green,
  1546. p_sys->ui_pausecolor_blue,
  1547. p_sys->i_fadesteps);
  1548. /*
  1549. this color is use on shutdown of the filter - the define the
  1550. final light after playback... may be used to dim up the light -
  1551. how it happens in the cinema...
  1552. */
  1553. p_sys->ui_endcolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
  1554. CFG_PREFIX "ecolor-red");
  1555. p_sys->ui_endcolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
  1556. CFG_PREFIX "ecolor-green");
  1557. p_sys->ui_endcolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
  1558. CFG_PREFIX "ecolor-blue");
  1559. p_sys->i_endfadesteps = var_CreateGetIntegerCommand( p_filter,
  1560. CFG_PREFIX "efadesteps");
  1561. if(p_sys->i_endfadesteps < 1)
  1562. p_sys->i_endfadesteps = 1;
  1563. msg_Dbg(p_filter,"use ende color RGB: %d, %d, %d, Fadesteps: %d",
  1564. p_sys->ui_endcolor_red,
  1565. p_sys->ui_endcolor_green,
  1566. p_sys->ui_endcolor_blue,
  1567. p_sys->i_endfadesteps);
  1568. /*
  1569. if the external DLL was loaded successfully call AtmoInitialize -
  1570. (must be done for each thread where you want to use AtmoLight!)
  1571. */
  1572. int i = AtmoInitialize(p_filter, false);
  1573. #if defined( WIN32 )
  1574. if((i != 1) && (p_sys->i_device_type == 0))
  1575. {
  1576. /*
  1577. COM Server for AtmoLight not running ?
  1578. if the exe path is configured try to start the "userspace" driver
  1579. */
  1580. char *psz_path = var_CreateGetStringCommand( p_filter,
  1581. CFG_PREFIX "atmowinexe" );
  1582. if(psz_path != NULL)
  1583. {
  1584. STARTUPINFO startupinfo;
  1585. PROCESS_INFORMATION pinfo;
  1586. memset(&startupinfo, 0, sizeof(STARTUPINFO));
  1587. startupinfo.cb = sizeof(STARTUPINFO);
  1588. if(CreateProcess(psz_path, NULL, NULL, NULL,
  1589. FALSE, 0, NULL, NULL, &startupinfo, &pinfo) == TRUE)
  1590. {
  1591. msg_Dbg(p_filter,"launched AtmoWin from %s",psz_path);
  1592. WaitForInputIdle(pinfo.hProcess, 5000);
  1593. /*
  1594. retry to initialize the library COM ... functionality
  1595. after the server was launched
  1596. */
  1597. i = AtmoInitialize(p_filter, false);
  1598. } else {
  1599. msg_Err(p_filter,"failed to launch AtmoWin from %s", psz_path);
  1600. }
  1601. free(psz_path);
  1602. }
  1603. }
  1604. #endif
  1605. if(i == 1) /* Init Atmolight success... */
  1606. {
  1607. msg_Dbg( p_filter, "AtmoInitialize Ok!");
  1608. /*
  1609. configure
  1610. p_sys->i_atmo_width and p_sys->i_atmo_height
  1611. if the external AtmoWinA.exe is used, it may require
  1612. a other sample image size than 64 x 48
  1613. (this overrides the settings of the filter)
  1614. */
  1615. Atmo_SetupImageSize( p_filter );
  1616. if( p_sys->i_device_type >= 1 )
  1617. {
  1618. /*
  1619. AtmoConnection class initialized now we can initialize
  1620. the default zone and channel mappings
  1621. */
  1622. Atmo_SetupBuildZones( p_filter );
  1623. }
  1624. /* Setup Transferbuffers for 64 x 48 , RGB with 32bit Per Pixel */
  1625. AtmoCreateTransferBuffers(p_filter, BI_RGB, 4,
  1626. p_sys->i_atmo_width,
  1627. p_sys->i_atmo_height
  1628. );
  1629. /* say the userspace driver that a live mode should be activated
  1630. the functions returns the old mode for later restore!
  1631. - the buildin driver launches the live view thread in that case
  1632. */
  1633. p_sys->i_AtmoOldEffect = AtmoSwitchEffect(p_filter, emLivePicture);
  1634. /*
  1635. live view can have two differnt source the AtmoWinA
  1636. internal GDI Screencapture and the external one - which we
  1637. need here...
  1638. */
  1639. AtmoSetLiveSource(p_filter, lvsExternal);
  1640. /* enable other parts only if everything is fine */
  1641. p_sys->b_enabled = true;
  1642. msg_Dbg( p_filter, "Atmo Filter Enabled Ok!");
  1643. }
  1644. }
  1645. /*****************************************************************************
  1646. * CreateFilter: allocates AtmoLight video thread output method
  1647. *****************************************************************************
  1648. * This function allocates and initializes a AtmoLight vout method.
  1649. *****************************************************************************/
  1650. static int CreateFilter( vlc_object_t *p_this )
  1651. {
  1652. filter_t *p_filter = (filter_t *)p_this;
  1653. filter_sys_t *p_sys;
  1654. /* Allocate structure */
  1655. p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) );
  1656. p_filter->p_sys = p_sys;
  1657. if( p_filter->p_sys == NULL )
  1658. return VLC_ENOMEM;
  1659. /* set all entries to zero */
  1660. memset(p_sys, 0, sizeof( filter_sys_t ));
  1661. vlc_mutex_init( &p_sys->filter_lock );
  1662. msg_Dbg( p_filter, "Create Atmo Filter");
  1663. /* further Setup Function pointers for videolan for calling my filter */
  1664. p_filter->pf_video_filter = Filter;
  1665. config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
  1666. p_filter->p_cfg );
  1667. AddStateVariableCallback(p_filter);
  1668. AddAtmoSettingsVariablesCallbacks(p_filter);
  1669. Atmo_SetupParameters(p_filter);
  1670. return VLC_SUCCESS;
  1671. }
  1672. /*****************************************************************************
  1673. * DestroyFilter: destroy AtmoLight video thread output method
  1674. *****************************************************************************
  1675. * Terminate an output method created by CreateFilter
  1676. *****************************************************************************/
  1677. static void DestroyFilter( vlc_object_t *p_this )
  1678. {
  1679. filter_t *p_filter = (filter_t *)p_this;
  1680. filter_sys_t *p_sys = p_filter->p_sys;
  1681. msg_Dbg( p_filter, "Destroy Atmo Filter");
  1682. DelStateVariableCallback(p_filter);
  1683. DelAtmoSettingsVariablesCallbacks(p_filter);
  1684. Atmo_Shutdown(p_filter);
  1685. #if defined( WIN32 )
  1686. if(p_sys->h_AtmoCtrl != NULL)
  1687. {
  1688. FreeLibrary(p_sys->h_AtmoCtrl);
  1689. }
  1690. #endif
  1691. delete p_sys->p_atmo_dyndata;
  1692. delete p_sys->p_atmo_config;
  1693. vlc_mutex_destroy( &p_sys->filter_lock );
  1694. free( p_sys );
  1695. }
  1696. /*
  1697. function stolen from some other videolan source filter ;-)
  1698. for the moment RGB is OK... but better would be a direct transformation
  1699. from YUV --> HSV
  1700. */
  1701. static inline void yuv_to_rgb( uint8_t *r, uint8_t *g, uint8_t *b,
  1702. uint8_t y1, uint8_t u1, uint8_t v1 )
  1703. {
  1704. /* macros used for YUV pixel conversions */
  1705. # define SCALEBITS 10
  1706. # define ONE_HALF (1 << (SCALEBITS - 1))
  1707. # define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
  1708. # define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
  1709. int y, cb, cr, r_add, g_add, b_add;
  1710. cb = u1 - 128;
  1711. cr = v1 - 128;
  1712. r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
  1713. g_add = - FIX(0.34414*255.0/224.0) * cb
  1714. - FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
  1715. b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
  1716. y = (y1 - 16) * FIX(255.0/219.0);
  1717. *r = CLAMP((y + r_add) >> SCALEBITS);
  1718. *g = CLAMP((y + g_add) >> SCALEBITS);
  1719. *b = CLAMP((y + b_add) >> SCALEBITS);
  1720. }
  1721. /******************************************************************************
  1722. * ExtractMiniImage_YUV: extract a small image from the picture as 24-bit RGB
  1723. *******************************************************************************
  1724. * p_sys is a pointer to
  1725. * p_inpic is the source frame
  1726. * p_transfer_dest is the target buffer for the picture must be big enough!
  1727. * (in win32 environment this buffer comes from the external DLL where it is
  1728. * create as "variant array" and returned through the AtmoLockTransferbuffer
  1729. */
  1730. static void ExtractMiniImage_YUV(filter_sys_t *p_sys,
  1731. picture_t *p_inpic,
  1732. uint8_t *p_transfer_dest)
  1733. {
  1734. int i_col;
  1735. int i_row;
  1736. uint8_t *p_src_y;
  1737. uint8_t *p_src_u;
  1738. uint8_t *p_src_v;
  1739. uint8_t *p_rgb_dst_line_red;
  1740. uint8_t *p_rgb_dst_line_green;
  1741. uint8_t *p_rgb_dst_line_blue;
  1742. int i_xpos_y;
  1743. int i_xpos_u;
  1744. int i_xpos_v;
  1745. /* calcute Pointers for Storage of B G R (A) */
  1746. p_rgb_dst_line_blue = p_transfer_dest;
  1747. p_rgb_dst_line_green = p_transfer_dest + 1;
  1748. p_rgb_dst_line_red = p_transfer_dest + 2 ;
  1749. int i_row_count = p_sys->i_atmo_height + 1;
  1750. int i_col_count = p_sys->i_atmo_width + 1;
  1751. int i_y_row,i_u_row,i_v_row,i_pixel_row;
  1752. int i_pixel_col;
  1753. /* these two ugly loops extract the small image - goes it faster? how?
  1754. the loops are so designed that there is a small border around the extracted
  1755. image so we wont get column and row - zero from the frame, and not the most
  1756. right and bottom pixels --- which may be clipped on computers useing TV out
  1757. - through overscan!
  1758. TODO: try to find out if the output is clipped through VLC - and try here
  1759. to ingore the clipped away area for a better result!
  1760. TODO: performance improvement in InitFilter percalculated the offsets of
  1761. the lines inside the planes so I can save (i_row_count * 3) 2xMUL and
  1762. one time DIV the same could be done for the inner loop I think...
  1763. */
  1764. for(i_row = 1; i_row < i_row_count; i_row++)
  1765. {
  1766. // calcute the current Lines in the source planes for this outputrow
  1767. /* Adresscalcuation pointer to plane Length of one pixelrow in bytes
  1768. calculate row now number
  1769. */
  1770. /*
  1771. p_inpic->format? transform Pixel row into row of plane...
  1772. how? simple? fast? good?
  1773. */
  1774. /* compute the source pixel row and respect the active cropping */
  1775. i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
  1776. + p_sys->i_crop_y_offset;
  1777. /*
  1778. trans for these Pixel row into the row of each plane ..
  1779. because planesize can differ from image size
  1780. */
  1781. i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
  1782. p_inpic->format.i_visible_height;
  1783. i_u_row = (i_pixel_row * p_inpic->p[U_PLANE].i_visible_lines) /
  1784. p_inpic->format.i_visible_height;
  1785. i_v_row = (i_pixel_row * p_inpic->p[V_PLANE].i_visible_lines) /
  1786. p_inpic->format.i_visible_height;
  1787. /* calculate the pointers to the pixeldata for this row
  1788. in each plane
  1789. */
  1790. p_src_y = p_inpic->p[Y_PLANE].p_pixels +
  1791. p_inpic->p[Y_PLANE].i_pitch * i_y_row;
  1792. p_src_u = p_inpic->p[U_PLANE].p_pixels +
  1793. p_inpic->p[U_PLANE].i_pitch * i_u_row;
  1794. p_src_v = p_inpic->p[V_PLANE].p_pixels +
  1795. p_inpic->p[V_PLANE].i_pitch * i_v_row;
  1796. if(p_sys->b_swap_uv)
  1797. {
  1798. /*
  1799. swap u and v plane for YV12 images
  1800. */
  1801. uint8_t *p_temp_plane = p_src_u;
  1802. p_src_u = p_src_v;
  1803. p_src_v = p_temp_plane;
  1804. }
  1805. for(i_col = 1; i_col < i_col_count; i_col++)
  1806. {
  1807. i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
  1808. p_sys->i_crop_x_offset;
  1809. /*
  1810. trans for these Pixel row into the row of each plane ..
  1811. because planesize can differ from image size
  1812. */
  1813. i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
  1814. p_inpic->format.i_visible_width;
  1815. i_xpos_u = (i_pixel_col * p_inpic->p[U_PLANE].i_visible_pitch) /
  1816. p_inpic->format.i_visible_width;
  1817. i_xpos_v = (i_pixel_col * p_inpic->p[V_PLANE].i_visible_pitch) /
  1818. p_inpic->format.i_visible_width;
  1819. yuv_to_rgb(p_rgb_dst_line_red,
  1820. p_rgb_dst_line_green,
  1821. p_rgb_dst_line_blue,
  1822. p_src_y[i_xpos_y],
  1823. p_src_u[i_xpos_u],
  1824. p_src_v[i_xpos_v]);
  1825. /* +4 because output image should be RGB32 with dword alignment! */
  1826. p_rgb_dst_line_red += 4;
  1827. p_rgb_dst_line_green += 4;
  1828. p_rgb_dst_line_blue += 4;
  1829. }
  1830. }
  1831. if(p_sys->b_show_dots)
  1832. {
  1833. for(i_row = 1; i_row < i_row_count; i_row++)
  1834. {
  1835. i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
  1836. + p_sys->i_crop_y_offset;
  1837. i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
  1838. p_inpic->format.i_visible_height;
  1839. p_src_y = p_inpic->p[Y_PLANE].p_pixels +
  1840. p_inpic->p[Y_PLANE].i_pitch * i_y_row;
  1841. for(i_col = 1; i_col < i_col_count; i_col++)
  1842. {
  1843. i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
  1844. p_sys->i_crop_x_offset;
  1845. i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
  1846. p_inpic->format.i_visible_width;
  1847. p_src_y[i_xpos_y] = 255;
  1848. }
  1849. }
  1850. }
  1851. }
  1852. /******************************************************************************
  1853. * SaveBitmap: Saves the content of a transferbuffer as Bitmap to disk
  1854. *******************************************************************************
  1855. * just for debugging
  1856. * p_sys -> configuration if Atmo from there the function will get height and
  1857. * width
  1858. * p_pixels -> should be the dword aligned BGR(A) image data
  1859. * psz_filename -> filename where to store
  1860. */
  1861. #if defined(__ATMO_DEBUG__)
  1862. void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename)
  1863. {
  1864. /* for debug out only used*/
  1865. BITMAPINFO bmp_info;
  1866. BITMAPFILEHEADER bmp_fileheader;
  1867. FILE *fp_bitmap;
  1868. memset(&bmp_info, 0, sizeof(BITMAPINFO));
  1869. bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  1870. bmp_info.bmiHeader.biSizeImage = p_sys->i_atmo_height *
  1871. p_sys->i_atmo_width * 4;
  1872. bmp_info.bmiHeader.biCompression = BI_RGB;
  1873. bmp_info.bmiHeader.biWidth = p_sys->i_atmo_width;
  1874. bmp_info.bmiHeader.biHeight = -p_sys->i_atmo_height;
  1875. bmp_info.bmiHeader.biBitCount = 32;
  1876. bmp_info.bmiHeader.biPlanes = 1;
  1877. bmp_fileheader.bfReserved1 = 0;
  1878. bmp_fileheader.bfReserved2 = 0;
  1879. bmp_fileheader.bfSize = sizeof(BITMAPFILEHEADER) +
  1880. sizeof(BITMAPINFOHEADER) +
  1881. bmp_info.bmiHeader.biSizeImage;
  1882. bmp_fileheader.bfType = VLC_TWOCC('B','M');
  1883. bmp_fileheader.bfOffBits = sizeof(BITMAPFILEHEADER) +
  1884. sizeof(BITMAPINFOHEADER);
  1885. fp_bitmap = fopen(psz_filename,"wb");
  1886. if( fp_bitmap != NULL)
  1887. {
  1888. fwrite(&bmp_fileheader, sizeof(BITMAPFILEHEADER), 1, fp_bitmap);
  1889. fwrite(&bmp_info.bmiHeader, sizeof(BITMAPINFOHEADER), 1, fp_bitmap);
  1890. fwrite(p_pixels, bmp_info.bmiHeader.biSizeImage, 1, fp_bitmap);
  1891. fclose(fp_bitmap);
  1892. }
  1893. }
  1894. #endif
  1895. /****************************************************************************
  1896. * CreateMiniImage: extracts a 64x48 pixel image from the frame
  1897. * (there is a small border arround thats why the loops starts with one
  1898. * instead zero) without any interpolation
  1899. *****************************************************************************/
  1900. static void CreateMiniImage( filter_t *p_filter, picture_t *p_inpic)
  1901. {
  1902. filter_sys_t *p_sys = p_filter->p_sys;
  1903. /*
  1904. pointer to RGB Buffer created in external libary as safe array which
  1905. is locked inside AtmoLockTransferBuffer
  1906. */
  1907. uint8_t *p_transfer;
  1908. #if defined( __ATMO_DEBUG__ )
  1909. /* for debug out only used*/
  1910. char sz_filename[MAX_PATH];
  1911. #endif
  1912. /*
  1913. Lock the before created VarArray (AtmoCreateTransferBuffers)
  1914. inside my wrapper library and give me a pointer to the buffer!
  1915. below linux a global buffer may be used and protected with a mutex?
  1916. */
  1917. p_transfer = AtmoLockTransferBuffer(p_filter);
  1918. if(p_transfer == NULL)
  1919. {
  1920. msg_Err( p_filter, "AtmoLight no transferbuffer available. "\
  1921. "AtmoLight will be disabled!");
  1922. p_sys->b_enabled = false;
  1923. return;
  1924. }
  1925. /*
  1926. do the call via pointer to function instead of having a
  1927. case structure here
  1928. */
  1929. p_sys->pf_extract_mini_image(p_sys, p_inpic, p_transfer);
  1930. #if defined( __ATMO_DEBUG__ )
  1931. /*
  1932. if debugging enabled save every 128th image to disk
  1933. */
  1934. if(p_sys->b_saveframes && p_sys->sz_framepath[0] != 0 )
  1935. {
  1936. if((p_sys->ui_frame_counter & 127) == 0)
  1937. {
  1938. sprintf(sz_filename,"%satmo_dbg_%06u.bmp",p_sys->sz_framepath,
  1939. p_sys->ui_frame_counter);
  1940. msg_Dbg(p_filter, "SaveFrame %s",sz_filename);
  1941. SaveBitmap(p_sys, p_transfer, sz_filename);
  1942. }
  1943. }
  1944. msg_Dbg( p_filter, "AtmoFrame %u Time: %d ms", p_sys->ui_frame_counter,
  1945. mdate() / 1000);
  1946. p_sys->ui_frame_counter++;
  1947. #endif
  1948. p_sys->i_frames_processed++;
  1949. /* show the colors on the wall */
  1950. AtmoSendPixelData( p_filter );
  1951. }
  1952. /*****************************************************************************
  1953. * Filter: calls the extract method and forwards the incomming picture 1:1
  1954. *****************************************************************************
  1955. *
  1956. *****************************************************************************/
  1957. static picture_t * Filter( filter_t *p_filter, picture_t *p_pic )
  1958. {
  1959. filter_sys_t *p_sys = p_filter->p_sys;
  1960. if( !p_pic ) return NULL;
  1961. picture_t *p_outpic = filter_NewPicture( p_filter );
  1962. if( !p_outpic )
  1963. {
  1964. picture_Release( p_pic );
  1965. return NULL;
  1966. }
  1967. picture_CopyPixels( p_outpic, p_pic );
  1968. vlc_mutex_lock( &p_sys->filter_lock );
  1969. if(p_sys->b_enabled && p_sys->pf_extract_mini_image &&
  1970. !p_sys->b_pause_live)
  1971. {
  1972. p_sys->i_crop_x_offset = p_filter->fmt_in.video.i_x_offset;
  1973. p_sys->i_crop_y_offset = p_filter->fmt_in.video.i_y_offset;
  1974. p_sys->i_crop_width = p_filter->fmt_in.video.i_visible_width;
  1975. p_sys->i_crop_height = p_filter->fmt_in.video.i_visible_height;
  1976. CreateMiniImage(p_filter, p_outpic);
  1977. }
  1978. vlc_mutex_unlock( &p_sys->filter_lock );
  1979. return CopyInfoAndRelease( p_outpic, p_pic );
  1980. }
  1981. /*****************************************************************************
  1982. * FadeToColorThread: Threadmethod which changes slowly the color
  1983. * to a target color defined in p_fadethread struct
  1984. * use for: Fade to Pause Color, and Fade to End Color
  1985. *****************************************************************************/
  1986. static void *FadeToColorThread(void *obj)
  1987. {
  1988. fadethread_t *p_fadethread = (fadethread_t *)obj;
  1989. filter_sys_t *p_sys = (filter_sys_t *)p_fadethread->p_filter->p_sys;
  1990. int i_steps_done = 0;
  1991. int i_index;
  1992. int i_pause_red;
  1993. int i_pause_green;
  1994. int i_pause_blue;
  1995. int i_src_red;
  1996. int i_src_green;
  1997. int i_src_blue;
  1998. uint8_t *p_source = NULL;
  1999. int canc = vlc_savecancel ();
  2000. /* initialize AtmoWin for this thread! */
  2001. AtmoInitialize(p_fadethread->p_filter , true);
  2002. uint8_t *p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
  2003. if(p_transfer != NULL) {
  2004. /* safe colors as "32bit" Integers to avoid overflows*/
  2005. i_pause_red = p_fadethread->ui_red;
  2006. i_pause_blue = p_fadethread->ui_blue;
  2007. i_pause_green = p_fadethread->ui_green;
  2008. /*
  2009. allocate a temporary buffer for the last send
  2010. image size less then 15kb
  2011. */
  2012. int i_size = 4 * p_sys->i_atmo_width * p_sys->i_atmo_height;
  2013. p_source = (uint8_t *)malloc( i_size );
  2014. if(p_source != NULL)
  2015. {
  2016. /*
  2017. get a copy of the last transfered image as orign for the
  2018. fading steps...
  2019. */
  2020. memcpy(p_source, p_transfer, i_size);
  2021. /* send the same pixel data again... to unlock the buffer! */
  2022. AtmoSendPixelData( p_fadethread->p_filter );
  2023. while( (!vlc_atomic_get (&p_fadethread->abort)) &&
  2024. (i_steps_done < p_fadethread->i_steps))
  2025. {
  2026. p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
  2027. if(!p_transfer) break; /* should not happen if it worked
  2028. one time in the code above! */
  2029. i_steps_done++;
  2030. /*
  2031. move all pixels in the mini image (64x48) one step closer to
  2032. the desired color these loop takes the most time of this
  2033. thread improvements wellcome!
  2034. */
  2035. for(i_index = 0;
  2036. (i_index < i_size) && (!vlc_atomic_get (&p_fadethread->abort));
  2037. i_index+=4)
  2038. {
  2039. i_src_blue = p_source[i_index+0];
  2040. i_src_green = p_source[i_index+1];
  2041. i_src_red = p_source[i_index+2];
  2042. p_transfer[i_index+0] = (uint8_t) (((
  2043. (i_pause_blue - i_src_blue)
  2044. * i_steps_done)/p_fadethread->i_steps)
  2045. + i_src_blue);
  2046. p_transfer[i_index+1] = (uint8_t) (((
  2047. (i_pause_green - i_src_green)
  2048. * i_steps_done)/p_fadethread->i_steps)
  2049. + i_src_green);
  2050. p_transfer[i_index+2] = (uint8_t) (((
  2051. (i_pause_red - i_src_red)
  2052. * i_steps_done)/p_fadethread->i_steps)
  2053. + i_src_red);
  2054. }
  2055. /* send image to lightcontroller */
  2056. AtmoSendPixelData( p_fadethread->p_filter );
  2057. /* is there something like and interruptable sleep inside
  2058. the VLC libaries? inside native win32 I would use an Event
  2059. (CreateEvent) and here an WaitForSingleObject?
  2060. */
  2061. msleep(40000);
  2062. }
  2063. free(p_source);
  2064. } else {
  2065. /* in failure of malloc also unlock buffer */
  2066. AtmoSendPixelData(p_fadethread->p_filter);
  2067. }
  2068. }
  2069. /* call indirect to OleUnitialize() for this thread */
  2070. AtmoFinalize(p_fadethread->p_filter, 0);
  2071. vlc_restorecancel (canc);
  2072. return NULL;
  2073. }
  2074. /*****************************************************************************
  2075. * CheckAndStopFadeThread: if there is a fadethread structure left, or running.
  2076. ******************************************************************************
  2077. * this function will stop the thread ... and waits for its termination
  2078. * before removeing the objects from vout_sys_t ...
  2079. ******************************************************************************/
  2080. static void CheckAndStopFadeThread(filter_t *p_filter)
  2081. {
  2082. filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
  2083. vlc_mutex_lock( &p_sys->filter_lock );
  2084. if(p_sys->p_fadethread != NULL)
  2085. {
  2086. msg_Dbg(p_filter, "kill still running fadeing thread...");
  2087. vlc_atomic_set(&p_sys->p_fadethread->abort, 1);
  2088. vlc_join(p_sys->p_fadethread->thread, NULL);
  2089. free(p_sys->p_fadethread);
  2090. p_sys->p_fadethread = NULL;
  2091. }
  2092. vlc_mutex_unlock( &p_sys->filter_lock );
  2093. }
  2094. /*****************************************************************************
  2095. * StateCallback: Callback for the inputs variable "State" to get notified
  2096. * about Pause and Continue Playback events.
  2097. *****************************************************************************/
  2098. static int StateCallback( vlc_object_t *, char const *,
  2099. vlc_value_t oldval, vlc_value_t newval,
  2100. void *p_data )
  2101. {
  2102. filter_t *p_filter = (filter_t *)p_data;
  2103. filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
  2104. if(p_sys->b_usepausecolor && p_sys->b_enabled)
  2105. {
  2106. msg_Dbg(p_filter, "state change from: %"PRId64" to %"PRId64, oldval.i_int,
  2107. newval.i_int);
  2108. if((newval.i_int == PAUSE_S) && (oldval.i_int == PLAYING_S))
  2109. {
  2110. /* tell the other thread to stop sending images to light
  2111. controller */
  2112. p_sys->b_pause_live = true;
  2113. // clean up old thread - should not happen....
  2114. CheckAndStopFadeThread( p_filter );
  2115. // perpare spawn fadeing thread
  2116. vlc_mutex_lock( &p_sys->filter_lock );
  2117. /*
  2118. launch only a new thread if there is none active!
  2119. or waiting for cleanup
  2120. */
  2121. if(p_sys->p_fadethread == NULL)
  2122. {
  2123. p_sys->p_fadethread = (fadethread_t *)calloc( 1, sizeof(fadethread_t) );
  2124. p_sys->p_fadethread->p_filter = p_filter;
  2125. p_sys->p_fadethread->ui_red = p_sys->ui_pausecolor_red;
  2126. p_sys->p_fadethread->ui_green = p_sys->ui_pausecolor_green;
  2127. p_sys->p_fadethread->ui_blue = p_sys->ui_pausecolor_blue;
  2128. p_sys->p_fadethread->i_steps = p_sys->i_fadesteps;
  2129. vlc_atomic_set(&p_sys->p_fadethread->abort, 0);
  2130. if( vlc_clone( &p_sys->p_fadethread->thread,
  2131. FadeToColorThread,
  2132. p_sys->p_fadethread,
  2133. VLC_THREAD_PRIORITY_LOW ) )
  2134. {
  2135. msg_Err( p_filter, "cannot create FadeToColorThread" );
  2136. free( p_sys->p_fadethread );
  2137. p_sys->p_fadethread = NULL;
  2138. }
  2139. }
  2140. vlc_mutex_unlock( &p_sys->filter_lock );
  2141. }
  2142. if((newval.i_int == PLAYING_S) && (oldval.i_int == PAUSE_S))
  2143. {
  2144. /* playback continues check thread state */
  2145. CheckAndStopFadeThread( p_filter );
  2146. /* reactivate the Render function... to do its normal work */
  2147. p_sys->b_pause_live = false;
  2148. }
  2149. }
  2150. return VLC_SUCCESS;
  2151. }
  2152. /*****************************************************************************
  2153. * AddPlaylistInputThreadStateCallback: Setup call back on "State" Variable
  2154. *****************************************************************************
  2155. * Add Callback function to the "state" variable of the input thread..
  2156. * first find the PlayList and get the input thread from there to attach
  2157. * my callback?
  2158. *****************************************************************************/
  2159. static void AddStateVariableCallback(filter_t *p_filter)
  2160. {
  2161. input_thread_t *p_input = playlist_CurrentInput( pl_Get( p_filter ) );
  2162. if(p_input)
  2163. {
  2164. var_AddCallback( p_input, "state", StateCallback, p_filter );
  2165. vlc_object_release( p_input );
  2166. }
  2167. }
  2168. /*****************************************************************************
  2169. * DelPlaylistInputThreadStateCallback: Remove call back on "State" Variable
  2170. *****************************************************************************
  2171. * Delete the callback function to the "state" variable of the input thread...
  2172. * first find the PlayList and get the input thread from there to attach
  2173. * my callback.
  2174. *****************************************************************************/
  2175. static void DelStateVariableCallback( filter_t *p_filter )
  2176. {
  2177. input_thread_t *p_input = playlist_CurrentInput( pl_Get ( p_filter ) );
  2178. if(p_input)
  2179. {
  2180. var_DelCallback( p_input, "state", StateCallback, p_filter );
  2181. vlc_object_release( p_input );
  2182. }
  2183. }
  2184. /****************************************************************************
  2185. * StateCallback: Callback for the inputs variable "State" to get notified
  2186. * about Pause and Continue Playback events.
  2187. *****************************************************************************/
  2188. static int AtmoSettingsCallback( vlc_object_t *, char const *psz_var,
  2189. vlc_value_t oldval, vlc_value_t newval,
  2190. void *p_data )
  2191. {
  2192. filter_t *p_filter = (filter_t *)p_data;
  2193. filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
  2194. vlc_mutex_lock( &p_sys->filter_lock );
  2195. if( !strcmp( psz_var, CFG_PREFIX "showdots" ))
  2196. {
  2197. p_sys->b_show_dots = newval.b_bool;
  2198. }
  2199. CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
  2200. if(p_atmo_config)
  2201. {
  2202. msg_Dbg(p_filter, "apply AtmoSettingsCallback %s (int: %"PRId64" -> %"PRId64")",
  2203. psz_var,
  2204. oldval.i_int,
  2205. newval.i_int
  2206. );
  2207. if( !strcmp( psz_var, CFG_PREFIX "filtermode" ))
  2208. p_atmo_config->setLiveViewFilterMode( (AtmoFilterMode)newval.i_int);
  2209. else if( !strcmp( psz_var, CFG_PREFIX "percentnew" ))
  2210. p_atmo_config->setLiveViewFilter_PercentNew( newval.i_int );
  2211. else if( !strcmp( psz_var, CFG_PREFIX "meanlength" ))
  2212. p_atmo_config->setLiveViewFilter_MeanLength( newval.i_int );
  2213. else if( !strcmp( psz_var, CFG_PREFIX "meanthreshold" ))
  2214. p_atmo_config->setLiveViewFilter_MeanThreshold( newval.i_int );
  2215. else if( !strcmp( psz_var, CFG_PREFIX "edgeweightning" ))
  2216. p_atmo_config->setLiveView_EdgeWeighting( newval.i_int );
  2217. else if( !strcmp( psz_var, CFG_PREFIX "brightness" ))
  2218. p_atmo_config->setLiveView_BrightCorrect( newval.i_int );
  2219. else if( !strcmp( psz_var, CFG_PREFIX "darknesslimit" ))
  2220. p_atmo_config->setLiveView_DarknessLimit( newval.i_int );
  2221. else if( !strcmp( psz_var, CFG_PREFIX "huewinsize" ))
  2222. p_atmo_config->setLiveView_HueWinSize( newval.i_int );
  2223. else if( !strcmp( psz_var, CFG_PREFIX "satwinsize" ))
  2224. p_atmo_config->setLiveView_SatWinSize( newval.i_int );
  2225. else if( !strcmp( psz_var, CFG_PREFIX "framedelay" ))
  2226. p_atmo_config->setLiveView_FrameDelay( newval.i_int );
  2227. else if( !strcmp( psz_var, CFG_PREFIX "whiteadj" ))
  2228. p_atmo_config->setUseSoftwareWhiteAdj( newval.b_bool );
  2229. else if( !strcmp( psz_var, CFG_PREFIX "white-red" ))
  2230. p_atmo_config->setWhiteAdjustment_Red( newval.i_int );
  2231. else if( !strcmp( psz_var, CFG_PREFIX "white-green" ))
  2232. p_atmo_config->setWhiteAdjustment_Green( newval.i_int );
  2233. else if( !strcmp( psz_var, CFG_PREFIX "white-blue" ))
  2234. p_atmo_config->setWhiteAdjustment_Blue( newval.i_int );
  2235. }
  2236. vlc_mutex_unlock( &p_sys->filter_lock );
  2237. return VLC_SUCCESS;
  2238. }
  2239. static void AddAtmoSettingsVariablesCallbacks(filter_t *p_filter)
  2240. {
  2241. var_AddCallback( p_filter, CFG_PREFIX "filtermode",
  2242. AtmoSettingsCallback, p_filter );
  2243. var_AddCallback( p_filter, CFG_PREFIX "percentnew",
  2244. AtmoSettingsCallback, p_filter );
  2245. var_AddCallback( p_filter, CFG_PREFIX "meanlength",
  2246. AtmoSettingsCallback, p_filter );
  2247. var_AddCallback( p_filter, CFG_PREFIX "meanthreshold",
  2248. AtmoSettingsCallback, p_filter );
  2249. var_AddCallback( p_filter, CFG_PREFIX "edgeweightning",
  2250. AtmoSettingsCallback, p_filter );
  2251. var_AddCallback( p_filter, CFG_PREFIX "brightness",
  2252. AtmoSettingsCallback, p_filter );
  2253. var_AddCallback( p_filter, CFG_PREFIX "darknesslimit",
  2254. AtmoSettingsCallback, p_filter );
  2255. var_AddCallback( p_filter, CFG_PREFIX "huewinsize",
  2256. AtmoSettingsCallback, p_filter );
  2257. var_AddCallback( p_filter, CFG_PREFIX "satwinsize",
  2258. AtmoSettingsCallback, p_filter );
  2259. var_AddCallback( p_filter, CFG_PREFIX "framedelay",
  2260. AtmoSettingsCallback, p_filter );
  2261. var_AddCallback( p_filter, CFG_PREFIX "whiteadj",
  2262. AtmoSettingsCallback, p_filter );
  2263. var_AddCallback( p_filter, CFG_PREFIX "white-red",
  2264. AtmoSettingsCallback, p_filter );
  2265. var_AddCallback( p_filter, CFG_PREFIX "white-green",
  2266. AtmoSettingsCallback, p_filter );
  2267. var_AddCallback( p_filter, CFG_PREFIX "white-blue",
  2268. AtmoSettingsCallback, p_filter );
  2269. var_AddCallback( p_filter, CFG_PREFIX "showdots",
  2270. AtmoSettingsCallback, p_filter );
  2271. }
  2272. static void DelAtmoSettingsVariablesCallbacks( filter_t *p_filter )
  2273. {
  2274. var_DelCallback( p_filter, CFG_PREFIX "filtermode",
  2275. AtmoSettingsCallback, p_filter );
  2276. var_DelCallback( p_filter, CFG_PREFIX "percentnew",
  2277. AtmoSettingsCallback, p_filter );
  2278. var_DelCallback( p_filter, CFG_PREFIX "meanlength",
  2279. AtmoSettingsCallback, p_filter );
  2280. var_DelCallback( p_filter, CFG_PREFIX "meanthreshold",
  2281. AtmoSettingsCallback, p_filter );
  2282. var_DelCallback( p_filter, CFG_PREFIX "edgeweightning",
  2283. AtmoSettingsCallback, p_filter );
  2284. var_DelCallback( p_filter, CFG_PREFIX "brightness",
  2285. AtmoSettingsCallback, p_filter );
  2286. var_DelCallback( p_filter, CFG_PREFIX "darknesslimit",
  2287. AtmoSettingsCallback, p_filter );
  2288. var_DelCallback( p_filter, CFG_PREFIX "huewinsize",
  2289. AtmoSettingsCallback, p_filter );
  2290. var_DelCallback( p_filter, CFG_PREFIX "satwinsize",
  2291. AtmoSettingsCallback, p_filter );
  2292. var_DelCallback( p_filter, CFG_PREFIX "framedelay",
  2293. AtmoSettingsCallback, p_filter );
  2294. var_DelCallback( p_filter, CFG_PREFIX "whiteadj",
  2295. AtmoSettingsCallback, p_filter );
  2296. var_DelCallback( p_filter, CFG_PREFIX "white-red",
  2297. AtmoSettingsCallback, p_filter );
  2298. var_DelCallback( p_filter, CFG_PREFIX "white-green",
  2299. AtmoSettingsCallback, p_filter );
  2300. var_DelCallback( p_filter, CFG_PREFIX "white-blue",
  2301. AtmoSettingsCallback, p_filter );
  2302. var_DelCallback( p_filter, CFG_PREFIX "showdots",
  2303. AtmoSettingsCallback, p_filter );
  2304. }
  2305. #if defined(__ATMO_DEBUG__)
  2306. static void atmo_parse_crop(char *psz_cropconfig,
  2307. video_format_t fmt_in,
  2308. video_format_t fmt_render,
  2309. int &i_visible_width, int &i_visible_height,
  2310. int &i_x_offset, int &i_y_offset )
  2311. {
  2312. int64_t i_aspect_num, i_aspect_den;
  2313. unsigned int i_width, i_height;
  2314. i_visible_width = fmt_in.i_visible_width;
  2315. i_visible_height = fmt_in.i_visible_height;
  2316. i_x_offset = fmt_in.i_x_offset;
  2317. i_y_offset = fmt_in.i_y_offset;
  2318. char *psz_end = NULL, *psz_parser = strchr( psz_cropconfig, ':' );
  2319. if( psz_parser )
  2320. {
  2321. /* We're using the 3:4 syntax */
  2322. i_aspect_num = strtol( psz_cropconfig, &psz_end, 10 );
  2323. if( psz_end == psz_cropconfig || !i_aspect_num ) return;
  2324. i_aspect_den = strtol( ++psz_parser, &psz_end, 10 );
  2325. if( psz_end == psz_parser || !i_aspect_den ) return;
  2326. i_width = fmt_in.i_sar_den * fmt_render.i_visible_height *
  2327. i_aspect_num / i_aspect_den / fmt_in.i_sar_num;
  2328. i_height = fmt_render.i_visible_width*fmt_in.i_sar_num *
  2329. i_aspect_den / i_aspect_num / fmt_in.i_sar_den;
  2330. if( i_width < fmt_render.i_visible_width )
  2331. {
  2332. i_x_offset = fmt_render.i_x_offset +
  2333. (fmt_render.i_visible_width - i_width) / 2;
  2334. i_visible_width = i_width;
  2335. }
  2336. else
  2337. {
  2338. i_y_offset = fmt_render.i_y_offset +
  2339. (fmt_render.i_visible_height - i_height) / 2;
  2340. i_visible_height = i_height;
  2341. }
  2342. }
  2343. else
  2344. {
  2345. psz_parser = strchr( psz_cropconfig, 'x' );
  2346. if( psz_parser )
  2347. {
  2348. /* Maybe we're using the <width>x<height>+<left>+<top> syntax */
  2349. unsigned int i_crop_width, i_crop_height, i_crop_top, i_crop_left;
  2350. i_crop_width = strtol( psz_cropconfig, &psz_end, 10 );
  2351. if( psz_end != psz_parser ) return;
  2352. psz_parser = strchr( ++psz_end, '+' );
  2353. i_crop_height = strtol( psz_end, &psz_end, 10 );
  2354. if( psz_end != psz_parser ) return;
  2355. psz_parser = strchr( ++psz_end, '+' );
  2356. i_crop_left = strtol( psz_end, &psz_end, 10 );
  2357. if( psz_end != psz_parser ) return;
  2358. psz_end++;
  2359. i_crop_top = strtol( psz_end, &psz_end, 10 );
  2360. if( *psz_end != '\0' ) return;
  2361. i_width = i_crop_width;
  2362. i_visible_width = i_width;
  2363. i_height = i_crop_height;
  2364. i_visible_height = i_height;
  2365. i_x_offset = i_crop_left;
  2366. i_y_offset = i_crop_top;
  2367. }
  2368. else
  2369. {
  2370. /* Maybe we're using the <left>+<top>+<right>+<bottom> syntax */
  2371. unsigned int i_crop_top, i_crop_left, i_crop_bottom, i_crop_right;
  2372. psz_parser = strchr( psz_cropconfig, '+' );
  2373. i_crop_left = strtol( psz_cropconfig, &psz_end, 10 );
  2374. if( psz_end != psz_parser ) return;
  2375. psz_parser = strchr( ++psz_end, '+' );
  2376. i_crop_top = strtol( psz_end, &psz_end, 10 );
  2377. if( psz_end != psz_parser ) return;
  2378. psz_parser = strchr( ++psz_end, '+' );
  2379. i_crop_right = strtol( psz_end, &psz_end, 10 );
  2380. if( psz_end != psz_parser ) return;
  2381. psz_end++;
  2382. i_crop_bottom = strtol( psz_end, &psz_end, 10 );
  2383. if( *psz_end != '\0' ) return;
  2384. i_width = fmt_render.i_visible_width -
  2385. i_crop_left -
  2386. i_crop_right;
  2387. i_visible_width = i_width;
  2388. i_height = fmt_render.i_visible_height -
  2389. i_crop_top -
  2390. i_crop_bottom;
  2391. i_visible_height = i_height;
  2392. i_x_offset = i_crop_left;
  2393. i_y_offset = i_crop_top;
  2394. }
  2395. }
  2396. }
  2397. #endif