mirror of
https://code.videolan.org/videolan/vlc
synced 2024-09-04 09:11:33 +02:00
2284 lines
83 KiB
C++
2284 lines
83 KiB
C++
/*****************************************************************************
|
|
* atmo.cpp : "Atmo Light" video filter
|
|
*****************************************************************************
|
|
* Copyright (C) 2000-2006 the VideoLAN team
|
|
* $Id$
|
|
*
|
|
* Authors: André Weber (WeberAndre@gmx.de)
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* Preamble
|
|
*****************************************************************************/
|
|
#include <stdlib.h> /* malloc(), free() */
|
|
#include <string.h>
|
|
#include <math.h> /* sin(), cos() */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
// #define __ATMO_DEBUG__
|
|
// [:Zs]+$
|
|
#include <vlc/vlc.h>
|
|
#include <vlc_vout.h>
|
|
|
|
#include <vlc_playlist.h>
|
|
#include "vlc_filter.h"
|
|
|
|
#include "AtmoDefs.h"
|
|
#include "AtmoDynData.h"
|
|
#include "AtmoLiveView.h"
|
|
#include "AtmoTools.h"
|
|
#include "AtmoExternalCaptureInput.h"
|
|
#include "AtmoConfig.h"
|
|
#include "AtmoConnection.h"
|
|
#include "AtmoSerialConnection.h"
|
|
|
|
|
|
/*****************************************************************************
|
|
* Local prototypes
|
|
*****************************************************************************/
|
|
/* directly to vlc related functions required that the module is accepted */
|
|
static int CreateFilter ( vlc_object_t * );
|
|
static void DestroyFilter ( vlc_object_t * );
|
|
static picture_t * Filter( filter_t *, picture_t *);
|
|
|
|
/* callback for global variable state pause / continue / stop events */
|
|
static void AddStateVariableCallback( filter_t *);
|
|
static void DelStateVariableCallback( filter_t *);
|
|
static int StateCallback(vlc_object_t *, char const *,
|
|
vlc_value_t, vlc_value_t, void *);
|
|
|
|
/* callback for variable crop-update */
|
|
static void AddCropVariableCallback( filter_t *);
|
|
static void DelCropVariableCallback( filter_t *);
|
|
static int CropCallback(vlc_object_t *, char const *,
|
|
vlc_value_t, vlc_value_t, void *);
|
|
|
|
/* callback for atmo settings variables whose change
|
|
should be immediately realized and applied to output
|
|
*/
|
|
static void DelAtmoSettingsVariablesCallbacks(filter_t *);
|
|
static void AddAtmoSettingsVariablesCallbacks(filter_t *);
|
|
static int AtmoSettingsCallback(vlc_object_t *, char const *,
|
|
vlc_value_t, vlc_value_t, void *);
|
|
|
|
|
|
#if defined(__ATMO_DEBUG__)
|
|
static void atmo_parse_crop(char *psz_cropconfig,
|
|
video_format_t fmt_in,
|
|
video_format_t fmt_render,
|
|
int &i_visible_width,
|
|
int &i_visible_height,
|
|
int &i_x_offset,
|
|
int &i_y_offset );
|
|
#endif
|
|
|
|
|
|
/* function to shutdown the fade thread which is started on pause*/
|
|
static void CheckAndStopFadeThread(filter_t *);
|
|
|
|
/* extracts a small RGB (BGR) Image from an YUV image */
|
|
static void ExtractMiniImage_YUV(filter_sys_t *, picture_t *, uint8_t *);
|
|
|
|
#if defined(__ATMO_DEBUG__)
|
|
void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename);
|
|
#endif
|
|
|
|
/*****************************************************************************
|
|
* External Prototypes for the AtmoCtrlLib.DLL
|
|
*****************************************************************************/
|
|
/*
|
|
* if effectmode = emLivePicture then the source could be GDI (Screencapture)
|
|
* or External - this means another application delivers Pixeldata to AtmoWin
|
|
* Clientsoftware through AtmoCtrlLib.DLL and the COM Api
|
|
*/
|
|
#define lvsGDI 0
|
|
#define lvsExternal 1
|
|
|
|
|
|
/*
|
|
strings for settings menus and hints
|
|
*/
|
|
#define MODULE_DESCRIPTION N_ ( \
|
|
"This module allows to control an so called AtmoLight device which "\
|
|
"is connected to your computer.\n"\
|
|
"AtmoLight is the homebrew version of that what Philips calls AmbiLight.\n"\
|
|
"If you need further informations feel free to visit us at\n\n"\
|
|
"http://www.vdr-wiki.de/wiki/index.php/Atmo-plugin\n"\
|
|
"http://www.vdr-wiki.de/wiki/index.php/AtmoWin\n\n"\
|
|
"there you will find detailed descriptions how to build it for your self and "\
|
|
"where you can get the required parts and so on.\n There you can also see "\
|
|
"pictures and some movies showing such a device in live action...")
|
|
|
|
|
|
|
|
#if defined( __ATMO_DEBUG__ )
|
|
# define SAVEFRAMES_TEXT N_("Save Debug Frames")
|
|
# define SAVEFRAMES_LONGTEXT N_("Writes every 128th miniframe to a folder.")
|
|
# define FRAMEPATH_TEXT N_("Debug Frame Folder")
|
|
# define FRAMEPATH_LONGTEXT N_("defines the path where the debugframes " \
|
|
"should be saved")
|
|
#endif
|
|
|
|
#define WIDTH_TEXT N_("Extracted Image Width")
|
|
#define WIDTH_LONGTEXT N_("defines the width of the mini image for " \
|
|
"further processing (64 is default)")
|
|
|
|
#define HEIGHT_TEXT N_("Extracted Image Height")
|
|
#define HEIGHT_LONGTEXT N_("defines the height of the mini image for " \
|
|
"further processing (48 is default)")
|
|
|
|
#define PCOLOR_TEXT N_("use Pause Color")
|
|
#define PCOLOR_LONGTEXT N_("use the color defined below if the user " \
|
|
"paused the video.(have light to get another beer?)")
|
|
#define PCOLOR_RED_TEXT N_("Pause-Red")
|
|
#define PCOLOR_RED_LONGTEXT N_("the red component of pause color")
|
|
#define PCOLOR_GREEN_TEXT N_("Pause-Green")
|
|
#define PCOLOR_GREEN_LONGTEXT N_("the green component of pause color")
|
|
#define PCOLOR_BLUE_TEXT N_("Pause-Blue")
|
|
#define PCOLOR_BLUE_LONGTEXT N_("the blue component of pause color")
|
|
#define FADESTEPS_TEXT N_("Pause-Fadesteps")
|
|
#define FADESTEPS_LONGTEXT N_("Number of steps to change current color " \
|
|
"to pause color (each step takes 40ms)")
|
|
|
|
#define ECOLOR_RED_TEXT N_("End-Red")
|
|
#define ECOLOR_RED_LONGTEXT N_("the red component of the shutdown color")
|
|
#define ECOLOR_GREEN_TEXT N_("End-Green")
|
|
#define ECOLOR_GREEN_LONGTEXT N_("the green component of the shutdown color")
|
|
#define ECOLOR_BLUE_TEXT N_("End-Blue")
|
|
#define ECOLOR_BLUE_LONGTEXT N_("the blue component of the shutdown color")
|
|
#define EFADESTEPS_TEXT N_("End-Fadesteps")
|
|
#define EFADESTEPS_LONGTEXT N_("Number of steps to change current color to " \
|
|
"end color for dimming up the light in cinema " \
|
|
"style... (each step takes 40ms)")
|
|
|
|
#define USEWHITEADJ_TEXT N_("Use Software White adjust")
|
|
#define USEWHITEADJ_LONGTEXT N_("Should the buildin driver do a white " \
|
|
"adjust or you LED stripes? recommend.")
|
|
#define WHITE_RED_TEXT N_("White Red")
|
|
#define WHITE_RED_LONGTEXT N_("Red value of a pure white on your "\
|
|
"LED stripes.")
|
|
#define WHITE_GREEN_TEXT N_("White Green")
|
|
#define WHITE_GREEN_LONGTEXT N_("Green value of a pure white on your "\
|
|
"LED stripes.")
|
|
#define WHITE_BLUE_TEXT N_("White Blue")
|
|
#define WHITE_BLUE_LONGTEXT N_("Blue value of a pure white on your "\
|
|
"LED stripes.")
|
|
|
|
#define SERIALDEV_TEXT N_("Serial Port/Device")
|
|
#define SERIALDEV_LONGTEXT N_("Name of the serial port where the AtmoLight "\
|
|
"controller is attached to\n on Windows usually "\
|
|
"something like COM1 or COM2 on Linux /dev/ttyS01 f.e.")
|
|
|
|
#define EDGE_TEXT N_("Edge Weightning")
|
|
#define EDGE_LONGTEXT N_("increasing this value will result in color "\
|
|
"more depending on the border of the frame")
|
|
#define BRIGHTNESS_TEXT N_("Brightness")
|
|
#define BRIGHTNESS_LONGTEXT N_("overall Brightness of you LED stripes")
|
|
#define DARKNESS_TEXT N_("Darkness Limit")
|
|
#define DARKNESS_LONGTEXT N_("pixels with a saturation lower than this will "\
|
|
"be ignored should be greater than one for "\
|
|
"letterboxed videos")
|
|
#define HUEWINSIZE_TEXT N_("Hue windowing")
|
|
#define HUEWINSIZE_LONGTEXT N_("used for statistics")
|
|
#define SATWINSIZE_TEXT N_("Sat windowing")
|
|
#define SATWINSIZE_LONGTEXT N_("used for statistics")
|
|
|
|
#define MEANLENGTH_TEXT N_("Filter length (ms)")
|
|
#define MEANLENGTH_LONGTEXT N_("Time it takes until a color is complete "\
|
|
"changed, removes flickering")
|
|
#define MEANTHRESHOLD_TEXT N_("Filter threshold")
|
|
#define MEANTHRESHOLD_LONGTEXT N_("How much a color must changed, for an "\
|
|
"imediate color change")
|
|
#define MEANPERCENTNEW_TEXT N_("Filter Smoothness %")
|
|
#define MEANPERCENTNEW_LONGTEXT N_("Filter Smoothness")
|
|
|
|
#define FILTERMODE_TEXT N_("Filtermode")
|
|
#define FILTERMODE_LONGTEXT N_("kind of filtering which should be use to "\
|
|
"calcuate the color output")
|
|
static int pi_filtermode_values[] = {
|
|
(int)afmNoFilter,
|
|
(int)afmCombined,
|
|
(int)afmPercent
|
|
};
|
|
static const char *ppsz_filtermode_descriptions[] = {
|
|
N_("No Filtering"),
|
|
N_("Combined"),
|
|
N_("Percent")
|
|
};
|
|
|
|
#define FRAMEDELAY_TEXT N_("Framedelay")
|
|
#define FRAMEDELAY_LONGTEXT N_("helps to get video out and light effects "\
|
|
"insync values around 20ms should do the trick")
|
|
|
|
|
|
#define CHANNEL_0_ASSIGN_TEXT N_("Channel summary")
|
|
#define CHANNEL_1_ASSIGN_TEXT N_("Channel left")
|
|
#define CHANNEL_2_ASSIGN_TEXT N_("Channel right")
|
|
#define CHANNEL_3_ASSIGN_TEXT N_("Channel top")
|
|
#define CHANNEL_4_ASSIGN_TEXT N_("Channel bottom")
|
|
|
|
#define CHANNELASSIGN_LONGTEXT N_("maps the hardware channel X to logical "\
|
|
"channel Y to fix wrong wiring:-)")
|
|
static int pi_channel_assignment_values[] = {
|
|
-1,
|
|
0,
|
|
1,
|
|
2,
|
|
3,
|
|
4
|
|
};
|
|
static const char *ppsz_channel_assignment_descriptions[] = {
|
|
N_("disabled"),
|
|
N_("summary"),
|
|
N_("left"),
|
|
N_("right"),
|
|
N_("top"),
|
|
N_("bottom")
|
|
};
|
|
|
|
#define ZONE_0_GRADIENT_TEXT N_("summary gradient")
|
|
#define ZONE_1_GRADIENT_TEXT N_("left gradient")
|
|
#define ZONE_2_GRADIENT_TEXT N_("right gradient")
|
|
#define ZONE_3_GRADIENT_TEXT N_("top gradient")
|
|
#define ZONE_4_GRADIENT_TEXT N_("bottom gradient")
|
|
#define ZONE_X_GRADIENT_LONG_TEXT N_("defines a small bitmap with 64x48 "\
|
|
"pixels, containing a grayscale gradient")
|
|
|
|
#if defined( WIN32 )
|
|
# define ATMOWINEXE_TEXT N_("Filename of AtmoWinA.exe")
|
|
# define ATMOWINEXE_LONGTEXT N_("if you wan't that the AtmoLight control "\
|
|
"software is launched by\nVLC enter the "\
|
|
"complete Filename of AtmoWinA.exe here")
|
|
# define USEBUILDIN_TEXT N_("Use buildin AtmoLight")
|
|
# define USEBUILDIN_LONGTEXT N_("VideoLan will directly use your AtmoLight "\
|
|
"hardware without running the external "\
|
|
"AtmoWinA.exe Userspace driver.")
|
|
#endif
|
|
|
|
#define CFG_PREFIX "atmo-"
|
|
|
|
/*****************************************************************************
|
|
* Module descriptor
|
|
*****************************************************************************/
|
|
vlc_module_begin();
|
|
set_description( _("AtmoLight Filter") );
|
|
set_help( MODULE_DESCRIPTION );
|
|
set_shortname( _( "AtmoLight" ));
|
|
set_capability( "video filter2", 0 );
|
|
|
|
set_category( CAT_VIDEO );
|
|
set_subcategory( SUBCAT_VIDEO_VFILTER );
|
|
|
|
#if defined(WIN32)
|
|
set_section( N_("Choose between the buildin AtmoLight "\
|
|
"driver or the external" ), 0 );
|
|
|
|
/*
|
|
only on win32 exists the option to use the buildin driver or
|
|
the more flexible external driver application
|
|
*/
|
|
add_bool(CFG_PREFIX "usebuildin", true, NULL,
|
|
USEBUILDIN_TEXT, USEBUILDIN_LONGTEXT, false);
|
|
add_string(CFG_PREFIX "serialdev", "COM1", NULL,
|
|
SERIALDEV_TEXT, SERIALDEV_LONGTEXT, false );
|
|
|
|
/*
|
|
on win32 the executeable external driver application
|
|
for automatic start if needed
|
|
*/
|
|
add_file(CFG_PREFIX "atmowinexe", NULL, NULL,
|
|
ATMOWINEXE_TEXT, ATMOWINEXE_LONGTEXT, false );
|
|
#else
|
|
set_section( N_("Enter connection of your AtmoLight hardware" ), 0 );
|
|
add_string(CFG_PREFIX "serialdev", "/dev/ttyS01", NULL,
|
|
SERIALDEV_TEXT, SERIALDEV_LONGTEXT, false );
|
|
#endif
|
|
|
|
/*
|
|
color which is showed if you want durring pausing
|
|
your movie ... used for both buildin / external
|
|
*/
|
|
set_section( N_("Illuminate the room with this color on pause" ), 0 );
|
|
add_bool(CFG_PREFIX "usepausecolor", false, NULL,
|
|
PCOLOR_TEXT, PCOLOR_LONGTEXT, false);
|
|
add_integer_with_range(CFG_PREFIX "pcolor-red", 0, 0, 255, NULL,
|
|
PCOLOR_RED_TEXT, PCOLOR_RED_LONGTEXT, false);
|
|
add_integer_with_range(CFG_PREFIX "pcolor-green", 0, 0, 255, NULL,
|
|
PCOLOR_GREEN_TEXT, PCOLOR_GREEN_LONGTEXT, false);
|
|
add_integer_with_range(CFG_PREFIX "pcolor-blue", 192, 0, 255, NULL,
|
|
PCOLOR_BLUE_TEXT, PCOLOR_BLUE_LONGTEXT, false);
|
|
add_integer_with_range(CFG_PREFIX "fadesteps", 50, 1, 250, NULL,
|
|
FADESTEPS_TEXT, FADESTEPS_LONGTEXT, false);
|
|
|
|
/*
|
|
color which is showed if you finished watching your movie ...
|
|
used for both buildin / external
|
|
*/
|
|
set_section( N_("Illuminate the room with this color on shutdown" ), 0 );
|
|
add_integer_with_range(CFG_PREFIX "ecolor-red", 192, 0, 255, NULL,
|
|
ECOLOR_RED_TEXT, ECOLOR_RED_LONGTEXT, false);
|
|
add_integer_with_range(CFG_PREFIX "ecolor-green", 192, 0, 255, NULL,
|
|
ECOLOR_GREEN_TEXT, ECOLOR_GREEN_LONGTEXT, false);
|
|
add_integer_with_range(CFG_PREFIX "ecolor-blue", 192, 0, 255, NULL,
|
|
ECOLOR_BLUE_TEXT, ECOLOR_BLUE_LONGTEXT, false);
|
|
add_integer_with_range(CFG_PREFIX "efadesteps", 50, 1, 250, NULL,
|
|
EFADESTEPS_TEXT, EFADESTEPS_LONGTEXT, false);
|
|
|
|
/*
|
|
settings only for the buildin driver (if external driver app is used
|
|
these parameters are ignored.)
|
|
|
|
definition of parameters for the buildin filter ...
|
|
*/
|
|
set_section( N_("Settings only for buildin Live Video Processor" ), 0 );
|
|
|
|
add_integer_with_range(CFG_PREFIX "EdgeWeightning", 8, 1, 30, NULL,
|
|
EDGE_TEXT, EDGE_LONGTEXT, false);
|
|
|
|
add_integer_with_range(CFG_PREFIX "Brightness", 100, 50, 300, NULL,
|
|
BRIGHTNESS_TEXT, BRIGHTNESS_LONGTEXT, false);
|
|
|
|
add_integer_with_range(CFG_PREFIX "DarknessLimit", 5, 0, 10, NULL,
|
|
DARKNESS_TEXT, DARKNESS_LONGTEXT, false);
|
|
|
|
add_integer_with_range(CFG_PREFIX "HueWinSize", 3, 0, 5, NULL,
|
|
HUEWINSIZE_TEXT, HUEWINSIZE_LONGTEXT, false);
|
|
|
|
add_integer_with_range(CFG_PREFIX "SatWinSize", 3, 0, 5, NULL,
|
|
SATWINSIZE_TEXT, SATWINSIZE_LONGTEXT, false);
|
|
|
|
add_integer(CFG_PREFIX "filtermode", (int)afmCombined, NULL,
|
|
FILTERMODE_TEXT, FILTERMODE_LONGTEXT, false );
|
|
|
|
change_integer_list(pi_filtermode_values, ppsz_filtermode_descriptions, 0 );
|
|
|
|
add_integer_with_range(CFG_PREFIX "MeanLength", 300, 300, 5000, NULL,
|
|
MEANLENGTH_TEXT, MEANLENGTH_LONGTEXT, false);
|
|
|
|
add_integer_with_range(CFG_PREFIX "MeanThreshold", 40, 1, 100, NULL,
|
|
MEANTHRESHOLD_TEXT, MEANTHRESHOLD_LONGTEXT, false);
|
|
|
|
add_integer_with_range(CFG_PREFIX "PercentNew", 50, 1, 100, NULL,
|
|
MEANPERCENTNEW_TEXT, MEANPERCENTNEW_LONGTEXT, false);
|
|
|
|
add_integer_with_range(CFG_PREFIX "FrameDelay", 18, 0, 35, NULL,
|
|
FRAMEDELAY_TEXT, FRAMEDELAY_LONGTEXT, false);
|
|
|
|
/*
|
|
output channel reordering
|
|
*/
|
|
set_section( N_("Change channel assignment (fixes wrong wiring)" ), 0 );
|
|
add_integer( CFG_PREFIX "channel_0", 0, NULL,
|
|
CHANNEL_0_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false );
|
|
change_integer_list( pi_channel_assignment_values,
|
|
ppsz_channel_assignment_descriptions, 0 );
|
|
|
|
add_integer( CFG_PREFIX "channel_1", 1, NULL,
|
|
CHANNEL_1_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false );
|
|
change_integer_list( pi_channel_assignment_values,
|
|
ppsz_channel_assignment_descriptions, 0 );
|
|
|
|
add_integer( CFG_PREFIX "channel_2", 2, NULL,
|
|
CHANNEL_2_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false );
|
|
change_integer_list( pi_channel_assignment_values,
|
|
ppsz_channel_assignment_descriptions, 0 );
|
|
|
|
add_integer( CFG_PREFIX "channel_3", 3, NULL,
|
|
CHANNEL_3_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false );
|
|
change_integer_list( pi_channel_assignment_values,
|
|
ppsz_channel_assignment_descriptions, 0 );
|
|
|
|
add_integer( CFG_PREFIX "channel_4", 4, NULL,
|
|
CHANNEL_4_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false );
|
|
change_integer_list( pi_channel_assignment_values,
|
|
ppsz_channel_assignment_descriptions, 0 );
|
|
|
|
/*
|
|
LED color white calibration
|
|
*/
|
|
set_section( N_("Adjust the white light to your LED stripes" ), 0 );
|
|
add_bool(CFG_PREFIX "whiteadj", true, NULL,
|
|
USEWHITEADJ_TEXT, USEWHITEADJ_LONGTEXT, false);
|
|
add_integer_with_range(CFG_PREFIX "white-red", 255, 0, 255, NULL,
|
|
WHITE_RED_TEXT, WHITE_RED_LONGTEXT, false);
|
|
|
|
add_integer_with_range(CFG_PREFIX "white-green", 255, 0, 255, NULL,
|
|
WHITE_GREEN_TEXT, WHITE_GREEN_LONGTEXT, false);
|
|
|
|
add_integer_with_range(CFG_PREFIX "white-blue", 255, 0, 255, NULL,
|
|
WHITE_BLUE_TEXT, WHITE_BLUE_LONGTEXT, false);
|
|
/* end of definition of parameter for the buildin filter ... part 1 */
|
|
|
|
|
|
/*
|
|
only for buildin (external has own definition) per default the calucation
|
|
used linear gradients for assigning a priority to the pixel - depending
|
|
how near they are to the border ...for changing this you can create 64x48
|
|
Pixel BMP files - which contain your own grayscale... (you can produce funny
|
|
effects with this...) the images MUST not compressed, should have 24-bit per
|
|
pixel, or a simple 256 color grayscale palette
|
|
*/
|
|
set_section( N_("Change gradients" ), 0 );
|
|
add_file(CFG_PREFIX "gradient_zone_0", NULL, NULL,
|
|
ZONE_0_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true );
|
|
add_file(CFG_PREFIX "gradient_zone_1", NULL, NULL,
|
|
ZONE_1_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true );
|
|
add_file(CFG_PREFIX "gradient_zone_2", NULL, NULL,
|
|
ZONE_2_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true );
|
|
add_file(CFG_PREFIX "gradient_zone_3", NULL, NULL,
|
|
ZONE_3_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true );
|
|
add_file(CFG_PREFIX "gradient_zone_4", NULL, NULL,
|
|
ZONE_4_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true );
|
|
|
|
|
|
#if defined(__ATMO_DEBUG__)
|
|
add_bool(CFG_PREFIX "saveframes", false, NULL,
|
|
SAVEFRAMES_TEXT, SAVEFRAMES_LONGTEXT, false);
|
|
add_string(CFG_PREFIX "framepath", "", NULL,
|
|
FRAMEPATH_TEXT, FRAMEPATH_LONGTEXT, false );
|
|
#endif
|
|
/*
|
|
may be later if computers gets more power ;-) than now we increase
|
|
the samplesize from which we do the stats for output color calculation
|
|
*/
|
|
add_integer_with_range(CFG_PREFIX "width", 64, 64, 512, NULL,
|
|
WIDTH_TEXT, WIDTH_LONGTEXT, true);
|
|
add_integer_with_range(CFG_PREFIX "height", 48, 48, 384, NULL,
|
|
HEIGHT_TEXT, HEIGHT_LONGTEXT, true);
|
|
|
|
add_shortcut( "atmo" );
|
|
set_callbacks( CreateFilter, DestroyFilter );
|
|
vlc_module_end();
|
|
|
|
|
|
static const char *ppsz_filter_options[] = {
|
|
#if defined(WIN32)
|
|
"usebuildin",
|
|
#endif
|
|
"serialdev",
|
|
|
|
|
|
"EdgeWeightning",
|
|
"Brightness",
|
|
"DarknessLimit",
|
|
"HueWinSize",
|
|
"SatWinSize",
|
|
|
|
"filtermode",
|
|
|
|
"MeanLength",
|
|
"MeanThreshold",
|
|
"PercentNew",
|
|
"FrameDelay",
|
|
|
|
"channel_0",
|
|
"channel_1",
|
|
"channel_2",
|
|
"channel_3",
|
|
"channel_4",
|
|
|
|
"whiteadj",
|
|
"white-red",
|
|
"white-green",
|
|
"white-blue",
|
|
|
|
"usepausecolor",
|
|
"pcolor-red",
|
|
"pcolor-green",
|
|
"pcolor-blue",
|
|
"fadesteps",
|
|
|
|
"ecolor-red",
|
|
"ecolor-green",
|
|
"ecolor-blue",
|
|
"efadesteps",
|
|
|
|
|
|
#if defined(WIN32 )
|
|
"usebuildin",
|
|
"atmowinexe",
|
|
#endif
|
|
#if defined(__ATMO_DEBUG__)
|
|
"saveframes" ,
|
|
"framepath",
|
|
#endif
|
|
"width",
|
|
"height",
|
|
"gradient_zone_0",
|
|
"gradient_zone_1",
|
|
"gradient_zone_2",
|
|
"gradient_zone_3",
|
|
"gradient_zone_4",
|
|
NULL
|
|
};
|
|
|
|
|
|
/*****************************************************************************
|
|
* fadethread_t: Color Fading Thread
|
|
*****************************************************************************
|
|
* changes slowly the color of the output if videostream gets paused...
|
|
*****************************************************************************
|
|
*/
|
|
typedef struct
|
|
{
|
|
VLC_COMMON_MEMBERS
|
|
filter_t *p_filter;
|
|
/* tell the thread which color should be the target of fading */
|
|
uint8_t ui_red;
|
|
uint8_t ui_green;
|
|
uint8_t ui_blue;
|
|
/* how many steps should happen until this */
|
|
int i_steps;
|
|
|
|
} fadethread_t;
|
|
|
|
static void FadeToColorThread(fadethread_t *p_fadethread);
|
|
|
|
|
|
/*****************************************************************************
|
|
* filter_sys_t: AtmoLight filter method descriptor
|
|
*****************************************************************************
|
|
* It describes the AtmoLight specific properties of an video filter.
|
|
*****************************************************************************/
|
|
struct filter_sys_t
|
|
{
|
|
/*
|
|
special for the access of the p_fadethread member all other members
|
|
need no special protection so far!
|
|
*/
|
|
vlc_mutex_t filter_lock;
|
|
|
|
bool b_enabled;
|
|
int32_t i_AtmoOldEffect;
|
|
bool b_pause_live;
|
|
|
|
int32_t i_atmo_width;
|
|
int32_t i_atmo_height;
|
|
|
|
#if defined(__ATMO_DEBUG__)
|
|
bool b_saveframes;
|
|
int i_framecounter;
|
|
char sz_framepath[MAX_PATH];
|
|
#endif
|
|
|
|
/* light color durring movie pause ... */
|
|
bool b_usepausecolor;
|
|
uint8_t ui_pausecolor_red;
|
|
uint8_t ui_pausecolor_green;
|
|
uint8_t ui_pausecolor_blue;
|
|
int i_fadesteps;
|
|
|
|
/* light color on movie finish ... */
|
|
uint8_t ui_endcolor_red;
|
|
uint8_t ui_endcolor_green;
|
|
uint8_t ui_endcolor_blue;
|
|
int i_endfadesteps;
|
|
|
|
fadethread_t *p_fadethread;
|
|
|
|
/* Variables for buildin driver only... */
|
|
|
|
/* is only present and initialized if the internal driver is used*/
|
|
CAtmoConfig *p_atmo_config;
|
|
/* storage for temporal settings "volatile" */
|
|
CAtmoDynData *p_atmo_dyndata;
|
|
/* initialized for buildin driver with AtmoCreateTransferBuffers */
|
|
BITMAPINFOHEADER mini_image_format;
|
|
/* is only use buildin driver! */
|
|
uint8_t *p_atmo_transfer_buffer;
|
|
/* end buildin driver */
|
|
|
|
/*
|
|
contains the real output size of the video calculated on
|
|
change event of the variable "crop" from vout
|
|
*/
|
|
int32_t i_crop_x_offset;
|
|
int32_t i_crop_y_offset;
|
|
int32_t i_crop_width;
|
|
int32_t i_crop_height;
|
|
|
|
void (*pf_extract_mini_image) (filter_sys_t *p_sys,
|
|
picture_t *p_inpic,
|
|
uint8_t *p_transfer_dest);
|
|
|
|
#if defined( WIN32 )
|
|
/* External Library as wrapper arround COM Stuff */
|
|
HINSTANCE h_AtmoCtrl;
|
|
int32_t (*pf_ctrl_atmo_initialize) (void);
|
|
void (*pf_ctrl_atmo_finalize) (int32_t what);
|
|
int32_t (*pf_ctrl_atmo_switch_effect) (int32_t);
|
|
int32_t (*pf_ctrl_atmo_set_live_source) (int32_t);
|
|
void (*pf_ctrl_atmo_create_transfer_buffers) (int32_t, int32_t,
|
|
int32_t , int32_t);
|
|
uint8_t* (*pf_ctrl_atmo_lock_transfer_buffer) (void);
|
|
void (*pf_ctrl_atmo_send_pixel_data) (void);
|
|
#endif
|
|
};
|
|
|
|
/*
|
|
initialize previously configured Atmo Light environment
|
|
- if internal is enabled try to access the device on the serial port
|
|
- if not internal is enabled and we are on win32 try to initialize
|
|
the previously loaded DLL ...
|
|
|
|
Return Values may be: -1 (failed for some reason - filter will be disabled)
|
|
1 Ok. lets rock
|
|
*/
|
|
static int32_t AtmoInitialize(filter_t *p_filter, bool b_for_thread)
|
|
{
|
|
filter_sys_t *p_sys = p_filter->p_sys;
|
|
if(p_sys->p_atmo_config)
|
|
{
|
|
if(b_for_thread == false)
|
|
{
|
|
/* open com port */
|
|
/* setup Output Threads ... */
|
|
msg_Dbg( p_filter, "open serial connection %s",
|
|
p_sys->p_atmo_config->getSerialDevice());
|
|
|
|
if(CAtmoTools::RecreateConnection(p_sys->p_atmo_dyndata) == ATMO_TRUE)
|
|
{
|
|
msg_Dbg( p_filter, "start live view thread ...");
|
|
CAtmoTools::SwitchEffect(p_sys->p_atmo_dyndata, emLivePicture);
|
|
msg_Dbg( p_filter, "live view thread launched...");
|
|
return 1;
|
|
|
|
} else {
|
|
msg_Err( p_filter,"failed to open serial device? some other software/driver may use it?");
|
|
}
|
|
}
|
|
#if defined(WIN32)
|
|
} else if(p_sys->pf_ctrl_atmo_initialize)
|
|
{
|
|
/* on win32 with active ctrl dll */
|
|
return p_sys->pf_ctrl_atmo_initialize();
|
|
#endif
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
prepare the shutdown of the effect threads,
|
|
for build in filter - close the serialport after finishing the threads...
|
|
cleanup possible loaded DLL...
|
|
*/
|
|
static void AtmoFinalize(filter_t *p_filter, int32_t what)
|
|
{
|
|
filter_sys_t *p_sys = p_filter->p_sys;
|
|
if(p_sys->p_atmo_config)
|
|
{
|
|
if(what == 1)
|
|
{
|
|
CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
|
|
if(p_atmo_dyndata)
|
|
{
|
|
p_atmo_dyndata->LockCriticalSection();
|
|
|
|
CThread *p_effect_thread = p_atmo_dyndata->getEffectThread();
|
|
p_atmo_dyndata->setEffectThread(NULL);
|
|
if(p_effect_thread != NULL)
|
|
{
|
|
/*
|
|
forced the thread to die...
|
|
and wait for termination of the thread
|
|
*/
|
|
p_effect_thread->Terminate();
|
|
delete p_effect_thread;
|
|
msg_Dbg( p_filter, "effect thread died peacefully");
|
|
}
|
|
|
|
/*
|
|
close serial port if it is open (all OS specific is inside
|
|
CAtmoSerialConnection implemented / defined)
|
|
*/
|
|
CAtmoConnection *p_atmo_connection =
|
|
p_atmo_dyndata->getAtmoConnection();
|
|
p_atmo_dyndata->setAtmoConnection(NULL);
|
|
if(p_atmo_connection) {
|
|
p_atmo_connection->CloseConnection();
|
|
delete p_atmo_connection;
|
|
}
|
|
p_atmo_dyndata->UnLockCriticalSection();
|
|
}
|
|
}
|
|
#if defined(WIN32)
|
|
} else if(p_sys->pf_ctrl_atmo_finalize)
|
|
{
|
|
/* on win32 with active ctrl dll */
|
|
p_sys->pf_ctrl_atmo_finalize(what);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*
|
|
switch the current light effect - does only something on win32, with the
|
|
external libraries - if the buildin effects are used nothing happens
|
|
*/
|
|
static int32_t AtmoSwitchEffect(filter_t *p_filter, int32_t newMode)
|
|
{
|
|
filter_sys_t *p_sys = p_filter->p_sys;
|
|
if(p_sys->p_atmo_config)
|
|
{
|
|
/*
|
|
buildin driver
|
|
|
|
doesnt know different modes for effects so this
|
|
function call would just do nothing special
|
|
in this case
|
|
*/
|
|
|
|
#if defined(WIN32)
|
|
} else if(p_sys->pf_ctrl_atmo_switch_effect)
|
|
{
|
|
/* on win32 with active ctrl dll */
|
|
return p_sys->pf_ctrl_atmo_switch_effect(newMode);
|
|
#endif
|
|
}
|
|
return emDisabled;
|
|
}
|
|
|
|
/*
|
|
set the current live picture source, does only something on win32,
|
|
with the external libraries - if the buildin effects are used nothing
|
|
happens...
|
|
*/
|
|
static int32_t AtmoSetLiveSource(filter_t *p_filter, int32_t newSource)
|
|
{
|
|
filter_sys_t *p_sys = p_filter->p_sys;
|
|
if(p_sys->p_atmo_config)
|
|
{
|
|
/*
|
|
buildin driver
|
|
|
|
doesnt know different sources so this
|
|
function call would just do nothing special
|
|
in this case
|
|
*/
|
|
#if defined(WIN32)
|
|
} else if(p_sys->pf_ctrl_atmo_set_live_source)
|
|
{
|
|
/* on win32 with active ctrl dll */
|
|
return p_sys->pf_ctrl_atmo_set_live_source(newSource);
|
|
#endif
|
|
}
|
|
return lvsGDI;
|
|
}
|
|
|
|
/*
|
|
setup the pixel transferbuffers which is used to transfer pixeldata from
|
|
the filter to the effect thread, and possible accross the process
|
|
boundaries on win32, with the external DLL
|
|
*/
|
|
static void AtmoCreateTransferBuffers(filter_t *p_filter,
|
|
int32_t FourCC,
|
|
int32_t bytePerPixel,
|
|
int32_t width,
|
|
int32_t height)
|
|
{
|
|
filter_sys_t *p_sys = p_filter->p_sys;
|
|
if(p_sys->p_atmo_config)
|
|
{
|
|
/*
|
|
we need a buffer where the image is stored (only for transfer
|
|
to the processing thread)
|
|
*/
|
|
if(p_sys->p_atmo_transfer_buffer)
|
|
free(p_sys->p_atmo_transfer_buffer);
|
|
|
|
p_sys->p_atmo_transfer_buffer = (uint8_t *)malloc(bytePerPixel *
|
|
width * height);
|
|
|
|
memset(&p_sys->mini_image_format,0,sizeof(BITMAPINFOHEADER));
|
|
|
|
p_sys->mini_image_format.biSize = sizeof(BITMAPINFOHEADER);
|
|
p_sys->mini_image_format.biWidth = width;
|
|
p_sys->mini_image_format.biHeight = height;
|
|
p_sys->mini_image_format.biBitCount = bytePerPixel*8;
|
|
p_sys->mini_image_format.biCompression = FourCC;
|
|
|
|
#if defined(WIN32)
|
|
} else if(p_sys->pf_ctrl_atmo_create_transfer_buffers)
|
|
{
|
|
/* on win32 with active ctrl dll */
|
|
p_sys->pf_ctrl_atmo_create_transfer_buffers(FourCC,
|
|
bytePerPixel,
|
|
width,
|
|
height);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*
|
|
acquire the transfer buffer pointer the buildin version only
|
|
returns the pointer to the allocated buffer ... the
|
|
external version on win32 has to do some COM stuff to lock the
|
|
Variant Byte array which is behind the buffer
|
|
*/
|
|
static uint8_t* AtmoLockTransferBuffer(filter_t *p_filter)
|
|
{
|
|
filter_sys_t *p_sys = p_filter->p_sys;
|
|
if(p_sys->p_atmo_config)
|
|
{
|
|
return p_sys->p_atmo_transfer_buffer;
|
|
#if defined(WIN32)
|
|
} else if(p_sys->pf_ctrl_atmo_lock_transfer_buffer)
|
|
{
|
|
/* on win32 with active ctrl dll */
|
|
return p_sys->pf_ctrl_atmo_lock_transfer_buffer();
|
|
#endif
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
send the content of current pixel buffer got with AtmoLockTransferBuffer
|
|
to the processing threads
|
|
- build in version - will forward the data to AtmoExternalCaptureInput Thread
|
|
- win32 external - will do the same, but across the process boundaries via
|
|
COM to the AtmoWinA.exe Process
|
|
*/
|
|
static void AtmoSendPixelData(filter_t *p_filter)
|
|
{
|
|
filter_sys_t *p_sys = p_filter->p_sys;
|
|
if(p_sys->p_atmo_config && p_sys->p_atmo_transfer_buffer)
|
|
{
|
|
CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
|
|
if(p_atmo_dyndata)
|
|
{
|
|
/*
|
|
the cast will go Ok because we are inside videolan there is only
|
|
this kind of effect thread implemented!
|
|
*/
|
|
|
|
CAtmoLiveView *p_atmo_live_view_thread =
|
|
(CAtmoLiveView *)p_atmo_dyndata->getEffectThread();
|
|
if(p_atmo_live_view_thread)
|
|
{
|
|
/*
|
|
the same as above inside videolan only this single kind of
|
|
input exists so we can cast without further tests!
|
|
*/
|
|
CAtmoExternalCaptureInput *p_atmo_external_capture_input_thread =
|
|
(CAtmoExternalCaptureInput *)p_atmo_live_view_thread->getAtmoInput();
|
|
if(p_atmo_external_capture_input_thread)
|
|
{
|
|
/*
|
|
this call will do a 1:1 copy of this buffer, and wakeup
|
|
the thread from normal sleeping
|
|
*/
|
|
p_atmo_external_capture_input_thread->
|
|
DeliverNewSourceDataPaket(&p_sys->mini_image_format,
|
|
p_sys->p_atmo_transfer_buffer);
|
|
}
|
|
}
|
|
}
|
|
#if defined(WIN32)
|
|
} else if(p_sys->pf_ctrl_atmo_send_pixel_data)
|
|
{
|
|
/* on win32 with active ctrl dll */
|
|
p_sys->pf_ctrl_atmo_send_pixel_data();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*
|
|
Shutdown AtmoLight finally - is call from DestroyFilter
|
|
does the cleanup restores the effectmode on the external Software
|
|
(only win32) and possible setup the final light ...
|
|
*/
|
|
static void Atmo_Shutdown(filter_t *p_filter)
|
|
{
|
|
filter_sys_t *p_sys = p_filter->p_sys;
|
|
|
|
if(p_sys->b_enabled == true)
|
|
{
|
|
/*
|
|
if there is a still running show pause color thread kill him!
|
|
*/
|
|
CheckAndStopFadeThread(p_filter);
|
|
|
|
if(p_sys->p_atmo_config || (p_sys->i_AtmoOldEffect == emStaticColor))
|
|
{
|
|
/*
|
|
fade to end color (in case of external AtmoWin Software
|
|
assume that the static color will equal to this
|
|
one to get a soft change and no flash!
|
|
*/
|
|
p_sys->b_pause_live = true;
|
|
|
|
// perpare spawn fadeing thread
|
|
vlc_mutex_lock( &p_sys->filter_lock );
|
|
|
|
p_sys->p_fadethread = (fadethread_t *)vlc_object_create( p_filter,
|
|
sizeof(fadethread_t) );
|
|
|
|
p_sys->p_fadethread->p_filter = p_filter;
|
|
p_sys->p_fadethread->ui_red = p_sys->ui_endcolor_red;
|
|
p_sys->p_fadethread->ui_green = p_sys->ui_endcolor_green;
|
|
p_sys->p_fadethread->ui_blue = p_sys->ui_endcolor_blue;
|
|
p_sys->p_fadethread->i_steps = p_sys->i_endfadesteps;
|
|
|
|
if( vlc_thread_create( p_sys->p_fadethread,
|
|
"AtmoLight fadeing",
|
|
FadeToColorThread,
|
|
VLC_THREAD_PRIORITY_LOW,
|
|
false ) )
|
|
{
|
|
msg_Err( p_filter, "cannot create FadeToColorThread" );
|
|
vlc_object_release( p_sys->p_fadethread );
|
|
p_sys->p_fadethread = NULL;
|
|
vlc_mutex_unlock( &p_sys->filter_lock );
|
|
|
|
} else {
|
|
|
|
vlc_mutex_unlock( &p_sys->filter_lock );
|
|
|
|
/* wait for the thread... */
|
|
vlc_thread_join(p_sys->p_fadethread);
|
|
|
|
vlc_object_release(p_sys->p_fadethread);
|
|
|
|
p_sys->p_fadethread = NULL;
|
|
}
|
|
}
|
|
|
|
if(p_sys->i_AtmoOldEffect != emLivePicture)
|
|
AtmoSwitchEffect(p_filter, p_sys->i_AtmoOldEffect);
|
|
else
|
|
AtmoSetLiveSource(p_filter, lvsGDI);
|
|
|
|
AtmoFinalize(p_filter, 1);
|
|
|
|
/* disable filter method .. */
|
|
p_sys->b_enabled = false;
|
|
}
|
|
}
|
|
|
|
/*
|
|
initialize the filter_sys_t structure with the data from the settings
|
|
variables - if the external filter on win32 is enabled try loading the DLL,
|
|
if this fails fallback to the buildin software
|
|
*/
|
|
static void Atmo_SetupParameters(filter_t *p_filter)
|
|
{
|
|
bool b_use_buildin_driver = true;
|
|
char *psz_path;
|
|
filter_sys_t *p_sys = p_filter->p_sys;
|
|
|
|
|
|
/* default filter disabled until DLL loaded and Init Success!*/
|
|
p_sys->b_enabled = false;
|
|
|
|
/* setup default mini image size (may be later a user option) */
|
|
p_sys->i_atmo_width = 64;
|
|
p_sys->i_atmo_height = 48;
|
|
|
|
|
|
vlc_mutex_init( &p_sys->filter_lock );
|
|
|
|
|
|
#if defined(WIN32)
|
|
/*
|
|
only on WIN32 the user has the choice between
|
|
internal driver and external
|
|
*/
|
|
b_use_buildin_driver = var_CreateGetBoolCommand( p_filter,
|
|
CFG_PREFIX "usebuildin" );
|
|
|
|
if(b_use_buildin_driver == false) {
|
|
|
|
/* Load the Com Wrapper Library (source available) */
|
|
p_sys->h_AtmoCtrl = LoadLibraryA("AtmoCtrlLib.dll");
|
|
if(p_sys->h_AtmoCtrl != NULL)
|
|
{
|
|
msg_Dbg( p_filter, "LoadLibrary('AtmoCtrlLib.dll'); Success");
|
|
|
|
/* importing all required functions I hope*/
|
|
p_sys->pf_ctrl_atmo_initialize =
|
|
(int32_t (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoInitialize");
|
|
if(!p_sys->pf_ctrl_atmo_initialize)
|
|
msg_Err( p_filter, "export AtmoInitialize missing.");
|
|
|
|
p_sys->pf_ctrl_atmo_finalize =
|
|
(void (*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoFinalize");
|
|
if(!p_sys->pf_ctrl_atmo_finalize)
|
|
msg_Err( p_filter, "export AtmoFinalize missing.");
|
|
|
|
p_sys->pf_ctrl_atmo_switch_effect =
|
|
(int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoSwitchEffect");
|
|
if(!p_sys->pf_ctrl_atmo_switch_effect)
|
|
msg_Err( p_filter, "export AtmoSwitchEffect missing.");
|
|
|
|
p_sys->pf_ctrl_atmo_set_live_source =
|
|
(int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoSetLiveSource");
|
|
if(!p_sys->pf_ctrl_atmo_set_live_source)
|
|
msg_Err( p_filter, "export AtmoSetLiveSource missing.");
|
|
|
|
p_sys->pf_ctrl_atmo_create_transfer_buffers =
|
|
(void (*)(int32_t, int32_t, int32_t , int32_t))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoCreateTransferBuffers");
|
|
if(!p_sys->pf_ctrl_atmo_create_transfer_buffers)
|
|
msg_Err( p_filter, "export AtmoCreateTransferBuffers missing.");
|
|
|
|
p_sys->pf_ctrl_atmo_lock_transfer_buffer=
|
|
(uint8_t*(*) (void))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoLockTransferBuffer");
|
|
if(!p_sys->pf_ctrl_atmo_lock_transfer_buffer)
|
|
msg_Err( p_filter, "export AtmoLockTransferBuffer missing.");
|
|
|
|
p_sys->pf_ctrl_atmo_send_pixel_data =
|
|
(void (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoSendPixelData");
|
|
if(!p_sys->pf_ctrl_atmo_send_pixel_data)
|
|
msg_Err( p_filter, "export AtmoSendPixelData missing.");
|
|
} else {
|
|
/* the DLL is missing try internal filter ...*/
|
|
msg_Warn( p_filter, "AtmoCtrlLib.dll missing fallback to internal driver");
|
|
b_use_buildin_driver = true;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
if(b_use_buildin_driver == true) {
|
|
msg_Dbg( p_filter, "use buildin driver");
|
|
/*
|
|
now we have to read a lof of options from the config dialog
|
|
most important the serial device if not set ... we can skip
|
|
the rest and disable the filter...
|
|
*/
|
|
char *psz_serialdev = var_CreateGetStringCommand( p_filter,
|
|
CFG_PREFIX "serialdev" );
|
|
if(psz_serialdev && (strlen(psz_serialdev)>0)) {
|
|
msg_Dbg( p_filter, "use buildin driver on port %s",psz_serialdev);
|
|
|
|
p_sys->p_atmo_config = new CAtmoConfig();
|
|
|
|
p_sys->p_atmo_config->setSerialDevice(psz_serialdev);
|
|
|
|
p_sys->p_atmo_config->setLiveViewFilterMode(
|
|
(AtmoFilterMode)var_CreateGetIntegerCommand( p_filter,
|
|
CFG_PREFIX "filtermode")
|
|
);
|
|
|
|
p_sys->p_atmo_config->setLiveViewFilter_PercentNew(
|
|
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "PercentNew")
|
|
);
|
|
p_sys->p_atmo_config->setLiveViewFilter_MeanLength(
|
|
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "MeanLength")
|
|
);
|
|
p_sys->p_atmo_config->setLiveViewFilter_MeanThreshold(
|
|
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "MeanThreshold")
|
|
);
|
|
|
|
p_sys->p_atmo_config->setLiveView_EdgeWeighting(
|
|
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "EdgeWeightning")
|
|
);
|
|
p_sys->p_atmo_config->setLiveView_BrightCorrect(
|
|
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "Brightness")
|
|
);
|
|
p_sys->p_atmo_config->setLiveView_DarknessLimit(
|
|
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "DarknessLimit")
|
|
);
|
|
p_sys->p_atmo_config->setLiveView_HueWinSize(
|
|
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "HueWinSize")
|
|
);
|
|
p_sys->p_atmo_config->setLiveView_SatWinSize(
|
|
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "SatWinSize")
|
|
);
|
|
|
|
/* currently not required inside vlc */
|
|
p_sys->p_atmo_config->setLiveView_WidescreenMode( 0 );
|
|
|
|
p_sys->p_atmo_config->setLiveView_FrameDelay(
|
|
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "FrameDelay")
|
|
);
|
|
|
|
|
|
p_sys->p_atmo_config->setUseSoftwareWhiteAdj(
|
|
var_CreateGetBoolCommand( p_filter, CFG_PREFIX "whiteadj")
|
|
);
|
|
p_sys->p_atmo_config->setWhiteAdjustment_Red(
|
|
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-red")
|
|
);
|
|
p_sys->p_atmo_config->setWhiteAdjustment_Green(
|
|
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-green")
|
|
);
|
|
p_sys->p_atmo_config->setWhiteAdjustment_Blue(
|
|
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-blue")
|
|
);
|
|
|
|
tChannelAssignment *p_channel_assignment =
|
|
p_sys->p_atmo_config->getChannelAssignment(0);
|
|
|
|
p_channel_assignment->mappings[0] = var_CreateGetIntegerCommand(
|
|
p_filter, CFG_PREFIX "channel_0");
|
|
|
|
p_channel_assignment->mappings[1] = var_CreateGetIntegerCommand(
|
|
p_filter, CFG_PREFIX "channel_1");
|
|
|
|
p_channel_assignment->mappings[2] = var_CreateGetIntegerCommand(
|
|
p_filter, CFG_PREFIX "channel_2");
|
|
|
|
p_channel_assignment->mappings[3] = var_CreateGetIntegerCommand(
|
|
p_filter, CFG_PREFIX "channel_3");
|
|
|
|
p_channel_assignment->mappings[4] = var_CreateGetIntegerCommand(
|
|
p_filter, CFG_PREFIX "channel_4");
|
|
|
|
for(int i=0;i<ATMO_NUM_CHANNELS;i++)
|
|
msg_Dbg( p_filter, "map software channel %d to hardware channel %d",
|
|
p_channel_assignment->mappings[i],
|
|
i
|
|
);
|
|
|
|
// gradient_zone_0
|
|
char psz_gradient_var_name[30];
|
|
char *psz_gradient_file;
|
|
for(int i=0;i<ATMO_NUM_CHANNELS;i++)
|
|
{
|
|
sprintf(psz_gradient_var_name, CFG_PREFIX "gradient_zone_%d", i);
|
|
psz_gradient_file = var_CreateGetStringCommand(
|
|
p_filter,
|
|
psz_gradient_var_name
|
|
);
|
|
if(psz_gradient_file && strlen(psz_gradient_file)>0)
|
|
{
|
|
msg_Dbg( p_filter, "loading gradientfile %s for "\
|
|
"zone %d", psz_gradient_file, i);
|
|
|
|
int i_res = p_sys->p_atmo_config->getZoneDefinition(i)->
|
|
LoadGradientFromBitmap(psz_gradient_file);
|
|
|
|
if(i_res != ATMO_LOAD_GRADIENT_OK)
|
|
{
|
|
msg_Err( p_filter,"failed to load gradient '%s' with "\
|
|
"error %d",psz_gradient_file,i_res);
|
|
}
|
|
}
|
|
delete psz_gradient_file;
|
|
}
|
|
|
|
p_sys->p_atmo_dyndata = new CAtmoDynData((vlc_object_t *)p_filter,
|
|
p_sys->p_atmo_config
|
|
);
|
|
|
|
msg_Dbg( p_filter, "buildin driver initialized");
|
|
|
|
free(psz_serialdev);
|
|
} else {
|
|
msg_Err(p_filter,"no serial devicename set");
|
|
}
|
|
}
|
|
|
|
switch( p_filter->fmt_in.video.i_chroma )
|
|
{
|
|
case VLC_FOURCC('I','4','2','0'):
|
|
case VLC_FOURCC('I','Y','U','V'):
|
|
case VLC_FOURCC('Y','V','1','2'):
|
|
case VLC_FOURCC('Y','V','1','6'):
|
|
case VLC_FOURCC('Y','V','U','9'):
|
|
// simple enough? Dionoea?
|
|
p_sys->pf_extract_mini_image = ExtractMiniImage_YUV;
|
|
break;
|
|
default:
|
|
msg_Dbg( p_filter, "InitFilter-unsupported chroma: %4.4s",
|
|
(char *)&p_filter->fmt_in.video.i_chroma);
|
|
p_sys->pf_extract_mini_image = NULL;
|
|
}
|
|
|
|
p_sys->i_crop_x_offset = 0;
|
|
p_sys->i_crop_y_offset = 0;
|
|
p_sys->i_crop_width = p_filter->fmt_in.video.i_visible_width;
|
|
p_sys->i_crop_height = p_filter->fmt_in.video.i_visible_height;
|
|
|
|
msg_Dbg( p_filter, "set default crop %d,%d %dx%d",p_sys->i_crop_x_offset,
|
|
p_sys->i_crop_y_offset,
|
|
p_sys->i_crop_width,
|
|
p_sys->i_crop_height );
|
|
|
|
|
|
#if defined(__ATMO_DEBUG__)
|
|
/* save debug images to a folder as Bitmap files ? */
|
|
p_sys->b_saveframes = var_CreateGetBoolCommand( p_filter,
|
|
CFG_PREFIX "saveframes"
|
|
);
|
|
msg_Dbg(p_filter,"saveframes = %d", (int)p_sys->b_saveframes);
|
|
|
|
/*
|
|
read debug image folder from config
|
|
*/
|
|
psz_path = var_CreateGetStringCommand( p_filter, CFG_PREFIX "framepath" );
|
|
if(psz_path != NULL)
|
|
{
|
|
strcpy(p_sys->sz_framepath, psz_path);
|
|
#if defined( WIN32 )
|
|
size_t i_strlen = strlen(p_sys->sz_framepath);
|
|
if((i_strlen>0) && (p_sys->sz_framepath[i_strlen-1] != '\\'))
|
|
{
|
|
p_sys->sz_framepath[i_strlen] = '\\';
|
|
p_sys->sz_framepath[i_strlen+1] = 0;
|
|
}
|
|
#endif
|
|
free(psz_path);
|
|
}
|
|
msg_Dbg(p_filter,"saveframesfolder %s",p_sys->sz_framepath);
|
|
#endif
|
|
|
|
/*
|
|
size of extracted image by default 64x48 (other imagesizes are
|
|
currently ignored by AtmoWin)
|
|
*/
|
|
p_sys->i_atmo_width = var_CreateGetIntegerCommand( p_filter,
|
|
CFG_PREFIX "width");
|
|
p_sys->i_atmo_height = var_CreateGetIntegerCommand( p_filter,
|
|
CFG_PREFIX "height");
|
|
msg_Dbg(p_filter,"mini image size %d * %d pixels", p_sys->i_atmo_width,
|
|
p_sys->i_atmo_height);
|
|
|
|
/*
|
|
because atmowin could also be used for lighten up the room - I think if you
|
|
pause the video it would be useful to get a little bit more light into to
|
|
your living room? - instead switching on a lamp?
|
|
*/
|
|
p_sys->b_usepausecolor = var_CreateGetBoolCommand( p_filter,
|
|
CFG_PREFIX "usepausecolor" );
|
|
p_sys->ui_pausecolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
|
|
CFG_PREFIX "pcolor-red");
|
|
p_sys->ui_pausecolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
|
|
CFG_PREFIX "pcolor-green");
|
|
p_sys->ui_pausecolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
|
|
CFG_PREFIX "pcolor-blue");
|
|
p_sys->i_fadesteps = var_CreateGetIntegerCommand( p_filter,
|
|
CFG_PREFIX "fadesteps");
|
|
if(p_sys->i_fadesteps < 1)
|
|
p_sys->i_fadesteps = 1;
|
|
msg_Dbg(p_filter,"use pause color %d, RGB: %d, %d, %d, Fadesteps: %d",
|
|
(int)p_sys->b_usepausecolor,
|
|
p_sys->ui_pausecolor_red,
|
|
p_sys->ui_pausecolor_green,
|
|
p_sys->ui_pausecolor_blue,
|
|
p_sys->i_fadesteps);
|
|
|
|
/*
|
|
this color is use on shutdown of the filter - the define the
|
|
final light after playback... may be used to dim up the light -
|
|
how it happens in the cinema...
|
|
*/
|
|
p_sys->ui_endcolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
|
|
CFG_PREFIX "ecolor-red");
|
|
p_sys->ui_endcolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
|
|
CFG_PREFIX "ecolor-green");
|
|
p_sys->ui_endcolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
|
|
CFG_PREFIX "ecolor-blue");
|
|
p_sys->i_endfadesteps = var_CreateGetIntegerCommand( p_filter,
|
|
CFG_PREFIX "efadesteps");
|
|
if(p_sys->i_endfadesteps < 1)
|
|
p_sys->i_endfadesteps = 1;
|
|
msg_Dbg(p_filter,"use ende color RGB: %d, %d, %d, Fadesteps: %d",
|
|
p_sys->ui_endcolor_red,
|
|
p_sys->ui_endcolor_green,
|
|
p_sys->ui_endcolor_blue,
|
|
p_sys->i_endfadesteps);
|
|
|
|
/* if the external DLL was loaded successfully call AtmoInitialize -
|
|
(must be done for each thread where you wan't to use AtmoLight!
|
|
*/
|
|
int i = AtmoInitialize(p_filter, false);
|
|
#if defined( WIN32 )
|
|
if((i != 1) && !b_use_buildin_driver)
|
|
{
|
|
/* COM Server for AtmoLight not running ?
|
|
if the exe path is configured try to start the "userspace" driver
|
|
*/
|
|
psz_path = var_CreateGetStringCommand( p_filter,
|
|
CFG_PREFIX "atmowinexe" );
|
|
if(psz_path != NULL)
|
|
{
|
|
STARTUPINFO startupinfo;
|
|
PROCESS_INFORMATION pinfo;
|
|
memset(&startupinfo, 0, sizeof(STARTUPINFO));
|
|
startupinfo.cb = sizeof(STARTUPINFO);
|
|
if(CreateProcess(psz_path, NULL, NULL, NULL,
|
|
FALSE, 0, NULL, NULL, &startupinfo, &pinfo) == TRUE)
|
|
{
|
|
msg_Dbg(p_filter,"launched AtmoWin from %s",psz_path);
|
|
WaitForInputIdle(pinfo.hProcess, 5000);
|
|
/*
|
|
retry to initialize the library COM ... functionality
|
|
after the server was launched
|
|
*/
|
|
i = AtmoInitialize(p_filter, false);
|
|
} else {
|
|
msg_Err(p_filter,"failed to launch AtmoWin from %s", psz_path);
|
|
}
|
|
free(psz_path);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if(i == 1) /* Init Atmolight success... */
|
|
{
|
|
msg_Dbg( p_filter, "AtmoInitialize Ok!");
|
|
|
|
/* Setup Transferbuffers for 64 x 48 , RGB with 32bit Per Pixel */
|
|
AtmoCreateTransferBuffers(p_filter, BI_RGB, 4,
|
|
p_sys->i_atmo_width,
|
|
p_sys->i_atmo_height
|
|
);
|
|
|
|
/* say the userspace driver that a live mode should be activated
|
|
the functions returns the old mode for later restore!
|
|
*/
|
|
p_sys->i_AtmoOldEffect = AtmoSwitchEffect(p_filter, emLivePicture);
|
|
|
|
/*
|
|
live view can have two differnt source the AtmoWinA
|
|
internal GDI Screencapture and the external one - which we
|
|
need here...
|
|
*/
|
|
AtmoSetLiveSource(p_filter, lvsExternal);
|
|
|
|
/* enable other parts only if everything is fine */
|
|
p_sys->b_enabled = true;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* CreateFilter: allocates AtmoLight video thread output method
|
|
*****************************************************************************
|
|
* This function allocates and initializes a AtmoLight vout method.
|
|
*****************************************************************************/
|
|
static int CreateFilter( vlc_object_t *p_this )
|
|
{
|
|
filter_t *p_filter = (filter_t *)p_this;
|
|
filter_sys_t *p_sys;
|
|
|
|
/* Allocate structure */
|
|
p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) );
|
|
p_filter->p_sys = p_sys;
|
|
if( p_filter->p_sys == NULL )
|
|
{
|
|
msg_Err( p_filter, "out of memory for p_sys structure" );
|
|
return VLC_ENOMEM;
|
|
}
|
|
/* set all entries to zero */
|
|
memset(p_sys, 0, sizeof( filter_sys_t ));
|
|
|
|
/* further Setup Function pointers for videolan for calling my filter */
|
|
p_filter->pf_video_filter = Filter;
|
|
|
|
config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
|
|
p_filter->p_cfg );
|
|
|
|
AddStateVariableCallback(p_filter);
|
|
|
|
AddCropVariableCallback(p_filter);
|
|
|
|
AddAtmoSettingsVariablesCallbacks(p_filter);
|
|
|
|
Atmo_SetupParameters(p_filter);
|
|
|
|
|
|
return VLC_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
* DestroyFilter: destroy AtmoLight video thread output method
|
|
*****************************************************************************
|
|
* Terminate an output method created by CreateFilter
|
|
*****************************************************************************/
|
|
|
|
static void DestroyFilter( vlc_object_t *p_this )
|
|
{
|
|
filter_t *p_filter = (filter_t *)p_this;
|
|
filter_sys_t *p_sys = p_filter->p_sys;
|
|
|
|
DelStateVariableCallback(p_filter);
|
|
DelCropVariableCallback(p_filter);
|
|
DelAtmoSettingsVariablesCallbacks(p_filter);
|
|
|
|
Atmo_Shutdown(p_filter);
|
|
|
|
#if defined( WIN32 )
|
|
if(p_sys->h_AtmoCtrl != NULL)
|
|
{
|
|
FreeLibrary(p_sys->h_AtmoCtrl);
|
|
}
|
|
#endif
|
|
|
|
delete p_sys->p_atmo_dyndata;
|
|
delete p_sys->p_atmo_config;
|
|
|
|
vlc_mutex_destroy( &p_sys->filter_lock );
|
|
|
|
free( p_sys );
|
|
}
|
|
|
|
|
|
/*
|
|
function stolen from some other videolan source filter ;-)
|
|
for the moment RGB is OK... but better would be a direct transformation
|
|
from YUV --> HSV
|
|
*/
|
|
static inline void yuv_to_rgb( uint8_t *r, uint8_t *g, uint8_t *b,
|
|
uint8_t y1, uint8_t u1, uint8_t v1 )
|
|
{
|
|
/* macros used for YUV pixel conversions */
|
|
# define SCALEBITS 10
|
|
# define ONE_HALF (1 << (SCALEBITS - 1))
|
|
# define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
|
|
# define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
|
|
|
|
int y, cb, cr, r_add, g_add, b_add;
|
|
|
|
cb = u1 - 128;
|
|
cr = v1 - 128;
|
|
r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
|
|
g_add = - FIX(0.34414*255.0/224.0) * cb
|
|
- FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
|
|
b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
|
|
y = (y1 - 16) * FIX(255.0/219.0);
|
|
*r = CLAMP((y + r_add) >> SCALEBITS);
|
|
*g = CLAMP((y + g_add) >> SCALEBITS);
|
|
*b = CLAMP((y + b_add) >> SCALEBITS);
|
|
}
|
|
/******************************************************************************
|
|
* ExtractMiniImage_YUV: extract a small image from the picture as 24-bit RGB
|
|
*******************************************************************************
|
|
* p_sys is a pointer to
|
|
* p_inpic is the source frame
|
|
* p_transfer_dest is the target buffer for the picture must be big enough!
|
|
* (in win32 enviroment this buffer comes from the external DLL where it is
|
|
* create as "variant array" and returned through the AtmoLockTransferbuffer
|
|
*/
|
|
static void ExtractMiniImage_YUV(filter_sys_t *p_sys,
|
|
picture_t *p_inpic,
|
|
uint8_t *p_transfer_dest)
|
|
{
|
|
int i_col;
|
|
int i_row;
|
|
uint8_t *p_src_y;
|
|
uint8_t *p_src_u;
|
|
uint8_t *p_src_v;
|
|
uint8_t *p_rgb_dst_line_red;
|
|
uint8_t *p_rgb_dst_line_green;
|
|
uint8_t *p_rgb_dst_line_blue;
|
|
int i_xpos_y;
|
|
int i_xpos_u;
|
|
int i_xpos_v;
|
|
|
|
/* calcute Pointers for Storage of B G R (A) */
|
|
p_rgb_dst_line_blue = p_transfer_dest;
|
|
p_rgb_dst_line_green = p_transfer_dest + 1;
|
|
p_rgb_dst_line_red = p_transfer_dest + 2 ;
|
|
|
|
int i_row_count = p_sys->i_atmo_height + 1;
|
|
int i_col_count = p_sys->i_atmo_width + 1;
|
|
int i_y_row,i_u_row,i_v_row,i_pixel_row;
|
|
int i_pixel_col;
|
|
|
|
|
|
/* these two ugly loops extract the small image - goes it faster? how?
|
|
the loops are so designed that there is a small border around the extracted
|
|
image so we wont get column and row - zero from the frame, and not the most
|
|
right and bottom pixels --- which may be clipped on computers useing TV out
|
|
- through overscan!
|
|
|
|
TODO: try to find out if the output is clipped through VLC - and try here
|
|
to ingore the clipped away area for a better result!
|
|
|
|
TODO: performance improvement in InitFilter percalculated the offsets of
|
|
the lines inside the planes so I can save (i_row_count * 3) 2xMUL and
|
|
one time DIV the same could be done for the inner loop I think...
|
|
*/
|
|
for(i_row = 1; i_row < i_row_count; i_row++)
|
|
{
|
|
// calcute the current Lines in the source planes for this outputrow
|
|
/* Adresscalcuation pointer to plane Length of one pixelrow in bytes
|
|
calculate row now number
|
|
*/
|
|
/*
|
|
p_inpic->format? transform Pixel row into row of plane...
|
|
how? simple? fast? good?
|
|
*/
|
|
|
|
/* compute the source pixel row and respect the active cropping */
|
|
i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
|
|
+ p_sys->i_crop_y_offset;
|
|
|
|
/*
|
|
trans for these Pixel row into the row of each plane ..
|
|
because planesize can differ from image size
|
|
*/
|
|
i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
|
|
p_inpic->format.i_visible_height;
|
|
|
|
i_u_row = (i_pixel_row * p_inpic->p[U_PLANE].i_visible_lines) /
|
|
p_inpic->format.i_visible_height;
|
|
|
|
i_v_row = (i_pixel_row * p_inpic->p[V_PLANE].i_visible_lines) /
|
|
p_inpic->format.i_visible_height;
|
|
|
|
/* calculate the pointers to the pixeldata for this row
|
|
in each plane
|
|
*/
|
|
p_src_y = p_inpic->p[Y_PLANE].p_pixels +
|
|
p_inpic->p[Y_PLANE].i_pitch * i_y_row;
|
|
p_src_u = p_inpic->p[U_PLANE].p_pixels +
|
|
p_inpic->p[U_PLANE].i_pitch * i_u_row;
|
|
p_src_v = p_inpic->p[V_PLANE].p_pixels +
|
|
p_inpic->p[V_PLANE].i_pitch * i_v_row;
|
|
|
|
for(i_col = 1; i_col < i_col_count; i_col++)
|
|
{
|
|
i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
|
|
p_sys->i_crop_x_offset;
|
|
/*
|
|
trans for these Pixel row into the row of each plane ..
|
|
because planesize can differ from image size
|
|
*/
|
|
i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
|
|
p_inpic->format.i_visible_width;
|
|
i_xpos_u = (i_pixel_col * p_inpic->p[U_PLANE].i_visible_pitch) /
|
|
p_inpic->format.i_visible_width;
|
|
i_xpos_v = (i_pixel_col * p_inpic->p[V_PLANE].i_visible_pitch) /
|
|
p_inpic->format.i_visible_width;
|
|
|
|
yuv_to_rgb(p_rgb_dst_line_red,
|
|
p_rgb_dst_line_green,
|
|
p_rgb_dst_line_blue,
|
|
|
|
p_src_y[i_xpos_y],
|
|
p_src_u[i_xpos_u],
|
|
p_src_v[i_xpos_v]);
|
|
|
|
/* +4 because output image should be RGB32 with dword alignment! */
|
|
p_rgb_dst_line_red += 4;
|
|
p_rgb_dst_line_green += 4;
|
|
p_rgb_dst_line_blue += 4;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
* SaveBitmap: Saves the content of a transferbuffer as Bitmap to disk
|
|
*******************************************************************************
|
|
* just for debugging
|
|
* p_sys -> configuration if Atmo from there the function will get height and
|
|
* width
|
|
* p_pixels -> should be the dword aligned BGR(A) image data
|
|
* psz_filename -> filename where to store
|
|
*/
|
|
#if defined(__ATMO_DEBUG__)
|
|
void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename)
|
|
{
|
|
/* for debug out only used*/
|
|
BITMAPINFO bmp_info;
|
|
BITMAPFILEHEADER bmp_fileheader;
|
|
FILE *fp_bitmap;
|
|
|
|
memset(&bmp_info, 0, sizeof(BITMAPINFO));
|
|
bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
bmp_info.bmiHeader.biSizeImage = p_sys->i_atmo_height *
|
|
p_sys->i_atmo_width * 4;
|
|
bmp_info.bmiHeader.biCompression = BI_RGB;
|
|
bmp_info.bmiHeader.biWidth = p_sys->i_atmo_width;
|
|
bmp_info.bmiHeader.biHeight = -p_sys->i_atmo_height;
|
|
bmp_info.bmiHeader.biBitCount = 32;
|
|
bmp_info.bmiHeader.biPlanes = 1;
|
|
|
|
bmp_fileheader.bfReserved1 = 0;
|
|
bmp_fileheader.bfReserved2 = 0;
|
|
bmp_fileheader.bfSize = sizeof(BITMAPFILEHEADER) +
|
|
sizeof(BITMAPINFOHEADER) +
|
|
bmp_info.bmiHeader.biSizeImage;
|
|
bmp_fileheader.bfType = VLC_TWOCC('M','B');
|
|
bmp_fileheader.bfOffBits = sizeof(BITMAPFILEHEADER) +
|
|
sizeof(BITMAPINFOHEADER);
|
|
|
|
fp_bitmap = fopen(psz_filename,"wb");
|
|
if( fp_bitmap != NULL)
|
|
{
|
|
fwrite(&bmp_fileheader, sizeof(BITMAPFILEHEADER), 1, fp_bitmap);
|
|
fwrite(&bmp_info.bmiHeader, sizeof(BITMAPINFOHEADER), 1, fp_bitmap);
|
|
fwrite(p_pixels, bmp_info.bmiHeader.biSizeImage, 1, fp_bitmap);
|
|
fclose(fp_bitmap);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
/****************************************************************************
|
|
* CreateMiniImage: extracts a 64x48 pixel image from the frame
|
|
* (there is a small border arround thats why the loops starts with one
|
|
* instead zero) without any interpolation
|
|
*****************************************************************************/
|
|
static void CreateMiniImage( filter_t *p_filter, picture_t *p_inpic)
|
|
{
|
|
filter_sys_t *p_sys = p_filter->p_sys;
|
|
/*
|
|
pointer to RGB Buffer created in external libary as safe array which
|
|
is locked inside AtmoLockTransferBuffer
|
|
*/
|
|
uint8_t *p_transfer = NULL;
|
|
#if defined( __ATMO_DEBUG__ )
|
|
/* for debug out only used*/
|
|
char sz_filename[MAX_PATH];
|
|
#endif
|
|
|
|
/*
|
|
Lock the before created VarArray (AtmoCreateTransferBuffers)
|
|
inside my wrapper library and give me a pointer to the buffer!
|
|
below linux a global buffer may be used and protected with a mutex?
|
|
*/
|
|
p_transfer = AtmoLockTransferBuffer(p_filter);
|
|
if(p_transfer == NULL)
|
|
{
|
|
msg_Err( p_filter, "AtmoLight no transferbuffer available. "\
|
|
"AtmoLight will be disabled!");
|
|
p_sys->b_enabled = false;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
do the call via pointer to function instead of having a
|
|
case structure here
|
|
*/
|
|
p_sys->pf_extract_mini_image(p_sys, p_inpic, p_transfer);
|
|
|
|
|
|
#if defined( __ATMO_DEBUG__ )
|
|
/*
|
|
if debugging enabled save every 128th image to disk
|
|
*/
|
|
if((p_sys->b_saveframes == true) && (p_sys->sz_framepath[0] != 0 ))
|
|
{
|
|
|
|
if((p_sys->i_framecounter & 127) == 0)
|
|
{
|
|
sprintf(sz_filename,"%satmo_dbg_%06d.bmp",p_sys->sz_framepath,
|
|
p_sys->i_framecounter);
|
|
msg_Dbg(p_filter, "SaveFrame %s",sz_filename);
|
|
|
|
SaveBitmap(p_sys, p_transfer, sz_filename);
|
|
}
|
|
p_sys->i_framecounter++;
|
|
}
|
|
#endif
|
|
|
|
/* show the colors on the wall */
|
|
AtmoSendPixelData(p_filter);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
* Filter: calls the extract method and forwards the incomming picture 1:1
|
|
*****************************************************************************
|
|
*
|
|
*****************************************************************************/
|
|
|
|
static picture_t * Filter( filter_t *p_filter, picture_t *p_pic )
|
|
{
|
|
filter_sys_t *p_sys = p_filter->p_sys;
|
|
if( !p_pic ) return NULL;
|
|
|
|
if((p_sys->b_enabled == true) &&
|
|
(p_sys->pf_extract_mini_image != NULL) &&
|
|
(p_sys->b_pause_live == false))
|
|
{
|
|
CreateMiniImage(p_filter, p_pic);
|
|
}
|
|
|
|
return p_pic;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* FadeToColorThread: Threadmethod which changes slowly the color
|
|
* to a target color defined in p_fadethread struct
|
|
* use for: Fade to Pause Color, and Fade to End Color
|
|
*****************************************************************************/
|
|
static void FadeToColorThread(fadethread_t *p_fadethread)
|
|
{
|
|
filter_sys_t *p_sys = (filter_sys_t *)p_fadethread->p_filter->p_sys;
|
|
int i_steps_done = 0;
|
|
int i_index;
|
|
int i_pause_red;
|
|
int i_pause_green;
|
|
int i_pause_blue;
|
|
|
|
int i_src_red;
|
|
int i_src_green;
|
|
int i_src_blue;
|
|
|
|
vlc_thread_ready( p_fadethread );
|
|
|
|
uint8_t *p_source = NULL;
|
|
|
|
/* initialize AtmoWin for this thread! */
|
|
AtmoInitialize(p_fadethread->p_filter , true);
|
|
|
|
uint8_t *p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
|
|
if(p_transfer != NULL) {
|
|
/* safe colors as "32bit" Integers to avoid overflows*/
|
|
i_pause_red = p_fadethread->ui_red;
|
|
i_pause_blue = p_fadethread->ui_blue;
|
|
i_pause_green = p_fadethread->ui_green;
|
|
|
|
/*
|
|
allocate a temporary buffer for the last send
|
|
image size less then 15kb
|
|
*/
|
|
int i_size = 4 * p_sys->i_atmo_width * p_sys->i_atmo_height;
|
|
p_source = (uint8_t *)malloc( i_size );
|
|
if(p_source != NULL)
|
|
{
|
|
/*
|
|
get a copy of the last transfered image as orign for the
|
|
fading steps...
|
|
*/
|
|
memcpy(p_source, p_transfer, i_size);
|
|
/* send the same pixel data again... to unlock the buffer! */
|
|
AtmoSendPixelData( p_fadethread->p_filter );
|
|
|
|
while( (!p_fadethread->b_die) &&
|
|
(i_steps_done < p_fadethread->i_steps))
|
|
{
|
|
p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
|
|
if(!p_transfer) break; /* should not happen if it worked
|
|
one time in the code above! */
|
|
i_steps_done++;
|
|
/*
|
|
move all pixels in the mini image (64x48) one step closer to
|
|
the desired color these loop takes the most time of this
|
|
thread improvements wellcome!
|
|
*/
|
|
for(i_index = 0;
|
|
(i_index < i_size) && (!p_fadethread->b_die);
|
|
i_index+=4)
|
|
{
|
|
i_src_blue = p_source[i_index+0];
|
|
i_src_green = p_source[i_index+1];
|
|
i_src_red = p_source[i_index+2];
|
|
p_transfer[i_index+0] = (uint8_t) (((
|
|
(i_pause_blue - i_src_blue)
|
|
* i_steps_done)/p_fadethread->i_steps)
|
|
+ i_src_blue);
|
|
|
|
p_transfer[i_index+1] = (uint8_t) (((
|
|
(i_pause_green - i_src_green)
|
|
* i_steps_done)/p_fadethread->i_steps)
|
|
+ i_src_green);
|
|
|
|
p_transfer[i_index+2] = (uint8_t) (((
|
|
(i_pause_red - i_src_red)
|
|
* i_steps_done)/p_fadethread->i_steps)
|
|
+ i_src_red);
|
|
}
|
|
|
|
/* send image to lightcontroller */
|
|
AtmoSendPixelData( p_fadethread->p_filter );
|
|
/* is there something like and interruptable sleep inside
|
|
the VLC libaries? inside native win32 I would use an Event
|
|
(CreateEvent) and here an WaitForSingleObject?
|
|
*/
|
|
if(p_fadethread->b_die) break;
|
|
msleep(10000);
|
|
if(p_fadethread->b_die) break;
|
|
msleep(10000);
|
|
if(p_fadethread->b_die) break;
|
|
msleep(10000);
|
|
if(p_fadethread->b_die) break;
|
|
msleep(10000);
|
|
}
|
|
free(p_source);
|
|
} else {
|
|
/* in failure of malloc also unlock buffer */
|
|
AtmoSendPixelData(p_fadethread->p_filter);
|
|
}
|
|
}
|
|
/* call indirect to OleUnitialize() for this thread */
|
|
AtmoFinalize(p_fadethread->p_filter, 0);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* CheckAndStopFadeThread: if there is a fadethread structure left, or running.
|
|
******************************************************************************
|
|
* this function will stop the thread ... and waits for its termination
|
|
* before removeing the objects from vout_sys_t ...
|
|
******************************************************************************/
|
|
static void CheckAndStopFadeThread(filter_t *p_filter)
|
|
{
|
|
filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
|
|
vlc_mutex_lock( &p_sys->filter_lock );
|
|
if(p_sys->p_fadethread != NULL)
|
|
{
|
|
msg_Dbg(p_filter, "kill still running fadeing thread...");
|
|
|
|
p_sys->p_fadethread->b_die = true;
|
|
|
|
vlc_thread_join(p_sys->p_fadethread);
|
|
|
|
vlc_object_release(p_sys->p_fadethread);
|
|
p_sys->p_fadethread = NULL;
|
|
}
|
|
vlc_mutex_unlock( &p_sys->filter_lock );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* StateCallback: Callback for the inputs variable "State" to get notified
|
|
* about Pause and Continue Playback events.
|
|
*****************************************************************************/
|
|
static int StateCallback( vlc_object_t *p_this, char const *psz_cmd,
|
|
vlc_value_t oldval, vlc_value_t newval,
|
|
void *p_data )
|
|
{
|
|
filter_t *p_filter = (filter_t *)p_data;
|
|
filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
|
|
|
|
if((p_sys->b_usepausecolor == true) && (p_sys->b_enabled == true))
|
|
{
|
|
msg_Dbg(p_filter, "state change from: %d to %d", oldval.i_int,
|
|
newval.i_int);
|
|
|
|
if((newval.i_int == PAUSE_S) && (oldval.i_int == PLAYING_S))
|
|
{
|
|
/* tell the other thread to stop sending images to light
|
|
controller */
|
|
p_sys->b_pause_live = true;
|
|
|
|
// ggf. alten Thread abräumen should not happen....
|
|
CheckAndStopFadeThread(p_filter);
|
|
|
|
// perpare spawn fadeing thread
|
|
vlc_mutex_lock( &p_sys->filter_lock );
|
|
/*
|
|
launch only a new thread if there is none active!
|
|
or waiting for cleanup
|
|
*/
|
|
if(p_sys->p_fadethread == NULL)
|
|
{
|
|
p_sys->p_fadethread = (fadethread_t *)vlc_object_create(
|
|
p_filter,
|
|
sizeof(fadethread_t) );
|
|
|
|
p_sys->p_fadethread->p_filter = p_filter;
|
|
p_sys->p_fadethread->ui_red = p_sys->ui_pausecolor_red;
|
|
p_sys->p_fadethread->ui_green = p_sys->ui_pausecolor_green;
|
|
p_sys->p_fadethread->ui_blue = p_sys->ui_pausecolor_blue;
|
|
p_sys->p_fadethread->i_steps = p_sys->i_fadesteps;
|
|
|
|
if( vlc_thread_create( p_sys->p_fadethread,
|
|
"AtmoLight fadeing",
|
|
FadeToColorThread,
|
|
VLC_THREAD_PRIORITY_LOW,
|
|
false) )
|
|
{
|
|
msg_Err( p_filter, "cannot create FadeToColorThread" );
|
|
vlc_object_release( p_sys->p_fadethread );
|
|
p_sys->p_fadethread = NULL;
|
|
}
|
|
}
|
|
vlc_mutex_unlock( &p_sys->filter_lock );
|
|
}
|
|
|
|
if((newval.i_int == PLAYING_S) && (oldval.i_int == PAUSE_S))
|
|
{
|
|
/* playback continues check thread state */
|
|
CheckAndStopFadeThread(p_filter);
|
|
/* reactivate the Render function... to do its normal work */
|
|
p_sys->b_pause_live = false;
|
|
}
|
|
}
|
|
|
|
return VLC_SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* AddPlaylistInputThreadStateCallback: Setup call back on "State" Variable
|
|
*****************************************************************************
|
|
* Add Callback function to the "state" variable of the input thread..
|
|
* first find the PlayList and get the input thread from there to attach
|
|
* my callback? is vlc_object_find the right way for this??
|
|
*****************************************************************************/
|
|
static void AddStateVariableCallback(filter_t *p_filter)
|
|
{
|
|
playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_filter,
|
|
VLC_OBJECT_PLAYLIST,
|
|
FIND_ANYWHERE );
|
|
if( p_playlist )
|
|
{
|
|
input_thread_t *p_input = p_playlist->p_input;
|
|
if(p_input)
|
|
{
|
|
var_AddCallback( p_input, "state", StateCallback, p_filter );
|
|
}
|
|
vlc_object_release( p_playlist );
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DelPlaylistInputThreadStateCallback: Remove call back on "State" Variable
|
|
*****************************************************************************
|
|
* Delete the callback function to the "state" variable of the input thread...
|
|
* first find the PlayList and get the input thread from there to attach
|
|
* my callback? is vlc_object_find the right way for this??
|
|
*****************************************************************************/
|
|
static void DelStateVariableCallback( filter_t *p_filter )
|
|
{
|
|
playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_filter,
|
|
VLC_OBJECT_PLAYLIST,
|
|
FIND_ANYWHERE );
|
|
if( p_playlist )
|
|
{
|
|
input_thread_t *p_input = p_playlist->p_input;
|
|
if(p_input)
|
|
{
|
|
var_DelCallback( p_input, "state", StateCallback, p_filter );
|
|
}
|
|
vlc_object_release( p_playlist );
|
|
}
|
|
}
|
|
|
|
|
|
static int CropCallback(vlc_object_t *p_this, char const *psz_cmd,
|
|
vlc_value_t oldval, vlc_value_t newval,
|
|
void *p_data)
|
|
{
|
|
vout_thread_t *p_vout = (vout_thread_t *)p_this;
|
|
filter_t *p_filter = (filter_t *)p_data;
|
|
filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
|
|
|
|
/*
|
|
//if the handler is attache to crop variable directly!
|
|
int i_visible_width, i_visible_height, i_x_offset, i_y_offset;
|
|
atmo_parse_crop(newval.psz_string, p_vout->fmt_render,
|
|
p_vout->fmt_render,
|
|
i_visible_width, i_visible_height,
|
|
i_x_offset, i_y_offset);
|
|
p_sys->i_crop_x_offset = i_x_offset;
|
|
p_sys->i_crop_y_offset = i_y_offset;
|
|
p_sys->i_crop_width = i_visible_width;
|
|
p_sys->i_crop_height = i_visible_height;
|
|
*/
|
|
|
|
p_sys->i_crop_x_offset = p_vout->fmt_in.i_x_offset;
|
|
p_sys->i_crop_y_offset = p_vout->fmt_in.i_y_offset;
|
|
p_sys->i_crop_width = p_vout->fmt_in.i_visible_width;
|
|
p_sys->i_crop_height = p_vout->fmt_in.i_visible_height;
|
|
|
|
msg_Dbg(p_filter, "cropping picture %ix%i to %i,%i,%ix%i",
|
|
p_vout->fmt_in.i_width,
|
|
p_vout->fmt_in.i_height,
|
|
p_sys->i_crop_x_offset,
|
|
p_sys->i_crop_y_offset,
|
|
p_sys->i_crop_width,
|
|
p_sys->i_crop_height
|
|
);
|
|
|
|
return VLC_SUCCESS;
|
|
}
|
|
|
|
|
|
static void AddCropVariableCallback( filter_t *p_filter)
|
|
{
|
|
vout_thread_t *p_vout = (vout_thread_t *)vlc_object_find( p_filter,
|
|
VLC_OBJECT_VOUT,
|
|
FIND_ANYWHERE );
|
|
if( p_vout )
|
|
{
|
|
var_AddCallback( p_vout, "crop-update", CropCallback, p_filter );
|
|
vlc_object_release( p_vout );
|
|
}
|
|
}
|
|
|
|
static void DelCropVariableCallback( filter_t *p_filter)
|
|
{
|
|
vout_thread_t *p_vout = (vout_thread_t *)vlc_object_find( p_filter,
|
|
VLC_OBJECT_VOUT,
|
|
FIND_ANYWHERE );
|
|
if( p_vout )
|
|
{
|
|
var_DelCallback( p_vout, "crop-update", CropCallback, p_filter );
|
|
vlc_object_release( p_vout );
|
|
}
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* StateCallback: Callback for the inputs variable "State" to get notified
|
|
* about Pause and Continue Playback events.
|
|
*****************************************************************************/
|
|
static int AtmoSettingsCallback( vlc_object_t *p_this, char const *psz_var,
|
|
vlc_value_t oldval, vlc_value_t newval,
|
|
void *p_data )
|
|
{
|
|
filter_t *p_filter = (filter_t *)p_data;
|
|
filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
|
|
|
|
CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
|
|
if(p_atmo_config)
|
|
{
|
|
|
|
msg_Dbg(p_filter, "apply AtmoSettingsCallback %s (int: %d -> %d)",
|
|
psz_var,
|
|
oldval.i_int,
|
|
newval.i_int
|
|
);
|
|
|
|
if( !strcmp( psz_var, CFG_PREFIX "filtermode" ))
|
|
p_atmo_config->setLiveViewFilterMode( (AtmoFilterMode)newval.i_int);
|
|
|
|
else if( !strcmp( psz_var, CFG_PREFIX "PercentNew" ))
|
|
p_atmo_config->setLiveViewFilter_PercentNew( newval.i_int );
|
|
|
|
else if( !strcmp( psz_var, CFG_PREFIX "MeanLength" ))
|
|
p_atmo_config->setLiveViewFilter_MeanLength( newval.i_int );
|
|
|
|
else if( !strcmp( psz_var, CFG_PREFIX "MeanThreshold" ))
|
|
p_atmo_config->setLiveViewFilter_MeanThreshold( newval.i_int );
|
|
|
|
else if( !strcmp( psz_var, CFG_PREFIX "EdgeWeightning" ))
|
|
p_atmo_config->setLiveView_EdgeWeighting( newval.i_int );
|
|
|
|
else if( !strcmp( psz_var, CFG_PREFIX "Brightness" ))
|
|
p_atmo_config->setLiveView_BrightCorrect( newval.i_int );
|
|
|
|
else if( !strcmp( psz_var, CFG_PREFIX "DarknessLimit" ))
|
|
p_atmo_config->setLiveView_DarknessLimit( newval.i_int );
|
|
|
|
else if( !strcmp( psz_var, CFG_PREFIX "HueWinSize" ))
|
|
p_atmo_config->setLiveView_HueWinSize( newval.i_int );
|
|
|
|
else if( !strcmp( psz_var, CFG_PREFIX "SatWinSize" ))
|
|
p_atmo_config->setLiveView_SatWinSize( newval.i_int );
|
|
|
|
else if( !strcmp( psz_var, CFG_PREFIX "FrameDelay" ))
|
|
p_atmo_config->setLiveView_FrameDelay( newval.i_int );
|
|
|
|
else if( !strcmp( psz_var, CFG_PREFIX "whiteadj" ))
|
|
p_atmo_config->setUseSoftwareWhiteAdj( newval.b_bool );
|
|
|
|
else if( !strcmp( psz_var, CFG_PREFIX "white-red" ))
|
|
p_atmo_config->setWhiteAdjustment_Red( newval.i_int );
|
|
|
|
else if( !strcmp( psz_var, CFG_PREFIX "white-green" ))
|
|
p_atmo_config->setWhiteAdjustment_Green( newval.i_int );
|
|
|
|
else if( !strcmp( psz_var, CFG_PREFIX "white-blue" ))
|
|
p_atmo_config->setWhiteAdjustment_Blue( newval.i_int );
|
|
|
|
}
|
|
return VLC_SUCCESS;
|
|
}
|
|
|
|
static void AddAtmoSettingsVariablesCallbacks(filter_t *p_filter)
|
|
{
|
|
var_AddCallback( p_filter, CFG_PREFIX "filtermode",
|
|
AtmoSettingsCallback, p_filter );
|
|
var_AddCallback( p_filter, CFG_PREFIX "PercentNew",
|
|
AtmoSettingsCallback, p_filter );
|
|
|
|
|
|
var_AddCallback( p_filter, CFG_PREFIX "MeanLength",
|
|
AtmoSettingsCallback, p_filter );
|
|
var_AddCallback( p_filter, CFG_PREFIX "MeanThreshold",
|
|
AtmoSettingsCallback, p_filter );
|
|
|
|
var_AddCallback( p_filter, CFG_PREFIX "EdgeWeightning",
|
|
AtmoSettingsCallback, p_filter );
|
|
var_AddCallback( p_filter, CFG_PREFIX "Brightness",
|
|
AtmoSettingsCallback, p_filter );
|
|
var_AddCallback( p_filter, CFG_PREFIX "DarknessLimit",
|
|
AtmoSettingsCallback, p_filter );
|
|
|
|
var_AddCallback( p_filter, CFG_PREFIX "HueWinSize",
|
|
AtmoSettingsCallback, p_filter );
|
|
var_AddCallback( p_filter, CFG_PREFIX "SatWinSize",
|
|
AtmoSettingsCallback, p_filter );
|
|
var_AddCallback( p_filter, CFG_PREFIX "FrameDelay",
|
|
AtmoSettingsCallback, p_filter );
|
|
|
|
|
|
var_AddCallback( p_filter, CFG_PREFIX "whiteadj",
|
|
AtmoSettingsCallback, p_filter );
|
|
var_AddCallback( p_filter, CFG_PREFIX "white-red",
|
|
AtmoSettingsCallback, p_filter );
|
|
var_AddCallback( p_filter, CFG_PREFIX "white-green",
|
|
AtmoSettingsCallback, p_filter );
|
|
var_AddCallback( p_filter, CFG_PREFIX "white-blue",
|
|
AtmoSettingsCallback, p_filter );
|
|
}
|
|
|
|
static void DelAtmoSettingsVariablesCallbacks( filter_t *p_filter )
|
|
{
|
|
|
|
var_DelCallback( p_filter, CFG_PREFIX "filtermode",
|
|
AtmoSettingsCallback, p_filter );
|
|
|
|
var_DelCallback( p_filter, CFG_PREFIX "PercentNew",
|
|
AtmoSettingsCallback, p_filter );
|
|
var_DelCallback( p_filter, CFG_PREFIX "MeanLength",
|
|
AtmoSettingsCallback, p_filter );
|
|
var_DelCallback( p_filter, CFG_PREFIX "MeanThreshold",
|
|
AtmoSettingsCallback, p_filter );
|
|
|
|
var_DelCallback( p_filter, CFG_PREFIX "EdgeWeightning",
|
|
AtmoSettingsCallback, p_filter );
|
|
var_DelCallback( p_filter, CFG_PREFIX "Brightness",
|
|
AtmoSettingsCallback, p_filter );
|
|
var_DelCallback( p_filter, CFG_PREFIX "DarknessLimit",
|
|
AtmoSettingsCallback, p_filter );
|
|
|
|
var_DelCallback( p_filter, CFG_PREFIX "HueWinSize",
|
|
AtmoSettingsCallback, p_filter );
|
|
var_DelCallback( p_filter, CFG_PREFIX "SatWinSize",
|
|
AtmoSettingsCallback, p_filter );
|
|
var_DelCallback( p_filter, CFG_PREFIX "FrameDelay",
|
|
AtmoSettingsCallback, p_filter );
|
|
|
|
|
|
var_DelCallback( p_filter, CFG_PREFIX "whiteadj",
|
|
AtmoSettingsCallback, p_filter );
|
|
var_DelCallback( p_filter, CFG_PREFIX "white-red",
|
|
AtmoSettingsCallback, p_filter );
|
|
var_DelCallback( p_filter, CFG_PREFIX "white-green",
|
|
AtmoSettingsCallback, p_filter );
|
|
var_DelCallback( p_filter, CFG_PREFIX "white-blue",
|
|
AtmoSettingsCallback, p_filter );
|
|
|
|
}
|
|
|
|
|
|
#if defined(__ATMO_DEBUG__)
|
|
static void atmo_parse_crop(char *psz_cropconfig,
|
|
video_format_t fmt_in,
|
|
video_format_t fmt_render,
|
|
int &i_visible_width, int &i_visible_height,
|
|
int &i_x_offset, int &i_y_offset )
|
|
{
|
|
int64_t i_aspect_num, i_aspect_den;
|
|
unsigned int i_width, i_height;
|
|
|
|
i_visible_width = fmt_in.i_visible_width;
|
|
i_visible_height = fmt_in.i_visible_height;
|
|
i_x_offset = fmt_in.i_x_offset;
|
|
i_y_offset = fmt_in.i_y_offset;
|
|
|
|
char *psz_end = NULL, *psz_parser = strchr( psz_cropconfig, ':' );
|
|
if( psz_parser )
|
|
{
|
|
/* We're using the 3:4 syntax */
|
|
i_aspect_num = strtol( psz_cropconfig, &psz_end, 10 );
|
|
if( psz_end == psz_cropconfig || !i_aspect_num ) return;
|
|
|
|
i_aspect_den = strtol( ++psz_parser, &psz_end, 10 );
|
|
if( psz_end == psz_parser || !i_aspect_den ) return;
|
|
|
|
i_width = fmt_in.i_sar_den * fmt_render.i_visible_height *
|
|
i_aspect_num / i_aspect_den / fmt_in.i_sar_num;
|
|
|
|
i_height = fmt_render.i_visible_width*fmt_in.i_sar_num *
|
|
i_aspect_den / i_aspect_num / fmt_in.i_sar_den;
|
|
|
|
if( i_width < fmt_render.i_visible_width )
|
|
{
|
|
i_x_offset = fmt_render.i_x_offset +
|
|
(fmt_render.i_visible_width - i_width) / 2;
|
|
i_visible_width = i_width;
|
|
}
|
|
else
|
|
{
|
|
i_y_offset = fmt_render.i_y_offset +
|
|
(fmt_render.i_visible_height - i_height) / 2;
|
|
i_visible_height = i_height;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
psz_parser = strchr( psz_cropconfig, 'x' );
|
|
if( psz_parser )
|
|
{
|
|
/* Maybe we're using the <width>x<height>+<left>+<top> syntax */
|
|
unsigned int i_crop_width, i_crop_height, i_crop_top, i_crop_left;
|
|
|
|
i_crop_width = strtol( psz_cropconfig, &psz_end, 10 );
|
|
if( psz_end != psz_parser ) return;
|
|
|
|
psz_parser = strchr( ++psz_end, '+' );
|
|
i_crop_height = strtol( psz_end, &psz_end, 10 );
|
|
if( psz_end != psz_parser ) return;
|
|
|
|
psz_parser = strchr( ++psz_end, '+' );
|
|
i_crop_left = strtol( psz_end, &psz_end, 10 );
|
|
if( psz_end != psz_parser ) return;
|
|
|
|
psz_end++;
|
|
i_crop_top = strtol( psz_end, &psz_end, 10 );
|
|
if( *psz_end != '\0' ) return;
|
|
|
|
i_width = i_crop_width;
|
|
i_visible_width = i_width;
|
|
|
|
i_height = i_crop_height;
|
|
i_visible_height = i_height;
|
|
|
|
i_x_offset = i_crop_left;
|
|
i_y_offset = i_crop_top;
|
|
}
|
|
else
|
|
{
|
|
/* Maybe we're using the <left>+<top>+<right>+<bottom> syntax */
|
|
unsigned int i_crop_top, i_crop_left, i_crop_bottom, i_crop_right;
|
|
|
|
psz_parser = strchr( psz_cropconfig, '+' );
|
|
i_crop_left = strtol( psz_cropconfig, &psz_end, 10 );
|
|
if( psz_end != psz_parser ) return;
|
|
|
|
psz_parser = strchr( ++psz_end, '+' );
|
|
i_crop_top = strtol( psz_end, &psz_end, 10 );
|
|
if( psz_end != psz_parser ) return;
|
|
|
|
psz_parser = strchr( ++psz_end, '+' );
|
|
i_crop_right = strtol( psz_end, &psz_end, 10 );
|
|
if( psz_end != psz_parser ) return;
|
|
|
|
psz_end++;
|
|
i_crop_bottom = strtol( psz_end, &psz_end, 10 );
|
|
if( *psz_end != '\0' ) return;
|
|
|
|
i_width = fmt_render.i_visible_width - i_crop_left - i_crop_right;
|
|
i_visible_width = i_width;
|
|
|
|
i_height = fmt_render.i_visible_height - i_crop_top - i_crop_bottom;
|
|
i_visible_height = i_height;
|
|
|
|
i_x_offset = i_crop_left;
|
|
i_y_offset = i_crop_top;
|
|
}
|
|
}
|
|
}
|
|
#endif
|