Commit 6713041e authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

atmo: remove video filter

parent 651687f3
......@@ -157,6 +157,9 @@ Misc
* remove ZPL playlist format
* Update libVLC doxygen modules
Removed modules
* Atmo video filter
Changes between 2.2.0 and 2.2.1:
--------------------------------
......
......@@ -3902,18 +3902,6 @@ AS_IF([test "${enable_vsxu}" != "no"],
])
])
dnl
dnl AtmoLight (homemade Philips Ambilight clone)
dnl
AC_ARG_ENABLE(atmo,
AS_HELP_STRING([--disable-atmo],[AtmoLight (homemade Philips Ambilight clone)
(default enabled)]),, [enable_atmo="yes"])
AS_IF([test "${enable_atmo}" != no], [
AS_IF([test "${SYS}" = "mingw32" -o "${SYS}" = "linux"], [
VLC_ADD_PLUGIN([atmo])
])
])
EXTEND_HELP_STRING([Service Discovery plugins:])
dnl
dnl Bonjour services discovery
......
......@@ -42,7 +42,6 @@ $Id$
* aribcam: ARIB STD-B25 decoder/virtual CAM
* aribsub: ARIB subtitles decoder
* asf: ASF demuxer
* atmo: Ambilight-like video-output
* attachment: Attachment access module
* au: AU file demuxer
* audio_format: helper module for audio transcoding
......
......@@ -106,31 +106,6 @@ video_filter_LTLIBRARIES = \
libpuzzle_plugin.la \
librotate_plugin.la
libatmo_plugin_la_SOURCES = video_filter/atmo/atmo.cpp \
video_filter/atmo/AtmoDefs.h \
video_filter/atmo/AtmoCalculations.cpp video_filter/atmo/AtmoCalculations.h \
video_filter/atmo/AtmoConfig.cpp video_filter/atmo/AtmoConfig.h \
video_filter/atmo/AtmoConnection.cpp video_filter/atmo/AtmoConnection.h \
video_filter/atmo/AtmoDynData.cpp video_filter/atmo/AtmoDynData.h \
video_filter/atmo/AtmoExternalCaptureInput.cpp video_filter/atmo/AtmoExternalCaptureInput.h \
video_filter/atmo/AtmoInput.cpp video_filter/atmo/AtmoInput.h \
video_filter/atmo/AtmoLiveView.cpp video_filter/atmo/AtmoLiveView.h \
video_filter/atmo/AtmoOutputFilter.cpp video_filter/atmo/AtmoOutputFilter.h \
video_filter/atmo/AtmoThread.cpp video_filter/atmo/AtmoThread.h \
video_filter/atmo/AtmoTools.cpp video_filter/atmo/AtmoTools.h \
video_filter/atmo/AtmoZoneDefinition.cpp video_filter/atmo/AtmoZoneDefinition.h \
video_filter/atmo/AtmoChannelAssignment.cpp video_filter/atmo/AtmoChannelAssignment.h \
video_filter/atmo/AtmoClassicConnection.cpp video_filter/atmo/AtmoClassicConnection.h \
video_filter/atmo/AtmoDmxSerialConnection.cpp video_filter/atmo/AtmoDmxSerialConnection.h \
video_filter/atmo/DmxTools.cpp video_filter/atmo/DmxTools.h \
video_filter/atmo/AtmoMultiConnection.cpp video_filter/atmo/AtmoMultiConnection.h \
video_filter/atmo/MoMoConnection.cpp video_filter/atmo/MoMoConnection.h \
video_filter/atmo/FnordlichtConnection.cpp video_filter/atmo/FnordlichtConnection.h \
video_filter/atmo/AtmoPacketQueue.cpp video_filter/atmo/AtmoPacketQueue.h
libatmo_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(video_filterdir)'
video_filter_LTLIBRARIES += $(LTLIBatmo)
EXTRA_LTLIBRARIES += libatmo_plugin.la
libdeinterlace_plugin_la_SOURCES = \
video_filter/deinterlace/deinterlace.c video_filter/deinterlace/deinterlace.h \
video_filter/deinterlace/mmx.h video_filter/deinterlace/common.h \
......
/*
* AtmoCalculations.cpp: calculations needed by the input devices
*
* See the README file for copyright information and how to reach the author.
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "AtmoDefs.h"
#if defined(_WIN32)
# include <windows.h>
#endif
#include "AtmoCalculations.h"
#include "AtmoConfig.h"
#include "AtmoZoneDefinition.h"
// set accuracy of color calculation
#define h_MAX 255
#define s_MAX 255
#define v_MAX 255
// macro
#define POS_DIV(a, b) ( (a)/(b) + ( ((a)%(b) >= (b)/2 ) ? 1 : 0) )
CAtmoColorCalculator::CAtmoColorCalculator(CAtmoConfig *pAtmoConfig)
{
m_pAtmoConfig = pAtmoConfig;
m_Weight = NULL;
m_hue_hist = NULL;
m_windowed_hue_hist = NULL;
m_most_used_hue_last = NULL;
m_most_used_hue = NULL;
m_sat_hist = NULL;
m_windowed_sat_hist = NULL;
m_most_used_sat = NULL;
m_Zone_Weights = NULL;
m_average_v = NULL;
m_average_counter = NULL;
m_LastEdgeWeighting = -1;
m_LastWidescreenMode = -1;
m_LastLayout_TopCount = -1;
m_LastLayout_BottomCount = -1;
m_LastLayout_LRCount = -1;
m_LastNumZones = -1;
}
CAtmoColorCalculator::~CAtmoColorCalculator(void)
{
delete[] m_Weight;
delete[] m_hue_hist;
delete[] m_windowed_hue_hist;
delete[] m_most_used_hue_last;
delete[] m_most_used_hue;
delete[] m_sat_hist;
delete[] m_windowed_sat_hist;
delete[] m_most_used_sat;
delete[] m_Zone_Weights;
delete[] m_average_v;
delete[] m_average_counter;
}
void CAtmoColorCalculator::UpdateParameters()
{
// Zonen Definition neu laden
// diverse Vorberechnungen neu ausführen
// Speicherbuffer neu allokieren!
}
void CAtmoColorCalculator::FindMostUsed(int AtmoSetup_NumZones,int *most_used,long int *windowed_hist)
{
memset(most_used, 0, sizeof(int) * AtmoSetup_NumZones);
for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
{
int value = 0;
// walk trough histogram
for (int i = 0; i < s_MAX+1; i++) // assume s_MAX = h_MAX = v_Max
{
// if new value bigger then old one
int tmp = *windowed_hist; // windowed_hist[zone * (s_MAX+1) + i];
// if (w_sat_hist[channel][i] > value)
if (tmp > value)
{
// remember index
most_used[zone] = i;
// and value
value = tmp;
}
windowed_hist++;
}
}
}
pColorPacket CAtmoColorCalculator::AnalyzeHSV(tHSVColor *HSV_Img)
{
int i; // counter
int AtmoSetup_EdgeWeighting = m_pAtmoConfig->getLiveView_EdgeWeighting();
int AtmoSetup_WidescreenMode = m_pAtmoConfig->getLiveView_WidescreenMode();
int AtmoSetup_DarknessLimit = m_pAtmoConfig->getLiveView_DarknessLimit();
int AtmoSetup_BrightCorrect = m_pAtmoConfig->getLiveView_BrightCorrect();
int AtmoSetup_SatWinSize = m_pAtmoConfig->getLiveView_SatWinSize();
int AtmoSetup_NumZones = m_pAtmoConfig->getZoneCount();
tHSVColor *temp_Img;
if(AtmoSetup_NumZones != m_LastNumZones)
{
delete[] m_Weight;
delete[] m_hue_hist;
delete[] m_windowed_hue_hist;
delete[] m_most_used_hue_last;
delete[] m_most_used_hue;
delete[] m_sat_hist;
delete[] m_windowed_sat_hist;
delete[] m_most_used_sat;
delete[] m_Zone_Weights;
delete[] m_average_v;
delete[] m_average_counter;
m_Weight = new int[AtmoSetup_NumZones * IMAGE_SIZE];
m_Zone_Weights = new int*[AtmoSetup_NumZones];
for(int i = 0; i < AtmoSetup_NumZones; i++)
m_Zone_Weights[i] = &m_Weight[i * IMAGE_SIZE];
m_hue_hist = new long int[(h_MAX+1) * AtmoSetup_NumZones];
m_windowed_hue_hist = new long int[(h_MAX+1) * AtmoSetup_NumZones];
m_most_used_hue_last = new int[AtmoSetup_NumZones];
m_most_used_hue = new int[AtmoSetup_NumZones];
memset( m_most_used_hue_last, 0, sizeof(int) * AtmoSetup_NumZones);
m_sat_hist = new long int[(s_MAX+1) * AtmoSetup_NumZones];
m_windowed_sat_hist = new long int[(s_MAX+1) * AtmoSetup_NumZones];
m_most_used_sat = new int[AtmoSetup_NumZones];
m_average_v = new long int[AtmoSetup_NumZones];
m_average_counter = new int[AtmoSetup_NumZones];
m_LastNumZones = AtmoSetup_NumZones;
}
// calculate only if setup has changed
if ((AtmoSetup_EdgeWeighting != m_LastEdgeWeighting) ||
(AtmoSetup_WidescreenMode != m_LastWidescreenMode) ||
(m_pAtmoConfig->getZonesTopCount() != m_LastLayout_TopCount) ||
(m_pAtmoConfig->getZonesBottomCount() != m_LastLayout_BottomCount) ||
(m_pAtmoConfig->getZonesLRCount() != m_LastLayout_LRCount) ||
(m_pAtmoConfig->m_UpdateEdgeWeightningFlag != 0)
)
{
for(i = 0 ;i < AtmoSetup_NumZones; i++) {
CAtmoZoneDefinition *pZoneDef = m_pAtmoConfig->getZoneDefinition(i);
if(pZoneDef)
{
pZoneDef->UpdateWeighting(m_Zone_Weights[i],
AtmoSetup_WidescreenMode,
AtmoSetup_EdgeWeighting);
#ifdef _debug_zone_weight_
char filename[128];
sprintf(filename, "zone_%d_gradient_debug.bmp",i);
pZoneDef->SaveZoneBitmap( filename );
sprintf(filename, "zone_%d_weight_%d_debug.bmp",i,AtmoSetup_EdgeWeighting);
pZoneDef->SaveWeightBitmap(filename, m_Zone_Weights[i] );
#endif
}
}
m_pAtmoConfig->m_UpdateEdgeWeightningFlag = 0;
m_LastEdgeWeighting = AtmoSetup_EdgeWeighting;
m_LastWidescreenMode = AtmoSetup_WidescreenMode;
m_LastLayout_TopCount = m_pAtmoConfig->getZonesTopCount();
m_LastLayout_BottomCount = m_pAtmoConfig->getZonesBottomCount();
m_LastLayout_LRCount = m_pAtmoConfig->getZonesLRCount();
}
AtmoSetup_DarknessLimit = AtmoSetup_DarknessLimit * 10;
/***************************************************************************/
/* Hue */
/***************************************************************************/
/*----------------------------*/
/* hue histogram builtup */
/*----------------------------*/
// HSV histogram
// long int hue_hist[CAP_MAX_NUM_ZONES][h_MAX+1];
// average brightness (value)
// m_average_v m_average_counter
// clean histogram --> calloc
memset(m_hue_hist, 0, sizeof(long int) * (h_MAX+1) * AtmoSetup_NumZones);
memset(m_average_v, 0, sizeof(long int) * AtmoSetup_NumZones);
memset(m_average_counter, 0, sizeof(int) * AtmoSetup_NumZones);
temp_Img = HSV_Img;
i = 0;
for (int row = 0; row < CAP_HEIGHT; row++)
{
for (int column = 0; column < CAP_WIDTH; column++)
{
// forget black bars: perform calculations only if pixel has some luminosity
if ((*temp_Img).v > AtmoSetup_DarknessLimit)
{
// builtup histogram for the x Zones of the Display
for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
{
// Add weight to channel
// Weight(zone, pixel_nummer) m_Weight[((zone) * (IMAGE_SIZE)) + (pixel_nummer)]
// m_hue_hist[zone*(h_MAX+1) + HSV_Img[i].h] += m_Zone_Weights[zone][i] * HSV_Img[i].v;
m_hue_hist[zone*(h_MAX+1) + (*temp_Img).h] += m_Zone_Weights[zone][i] * temp_Img->v;
if(m_Zone_Weights[zone][i] > 0) {
m_average_v[zone] += temp_Img->v;
m_average_counter[zone]++;
}
}
// calculate brightness average
}
temp_Img++;
i++;
}
}
/*----------------------------*/
/* hue histogram windowing */
/*----------------------------*/
// windowed HSV histogram
// long int w_hue_hist[CAP_MAX_NUM_ZONES][h_MAX+1]; -> m_windowed_hue_hist
// clean windowed histogram
memset(m_windowed_hue_hist, 0, sizeof(long int) * (h_MAX+1) * AtmoSetup_NumZones);
// steps in each direction; eg. 2 => -2 -1 0 1 2 windowing
int hue_windowsize = m_pAtmoConfig->getLiveView_HueWinSize();
for (i = 0; i < h_MAX+1; i++) // walk through histogram [0;h_MAX]
{
// windowing from -hue_windowsize -> +hue_windowsize
for (int mywin = -hue_windowsize; mywin < hue_windowsize+1; mywin++)
{
// addressed histogram candlestick
int myidx = i + mywin;
// handle beginning of windowing -> roll back
if (myidx < 0) { myidx = myidx + h_MAX + 1; }
// handle end of windowing -> roll forward
if (myidx > h_MAX) { myidx = myidx - h_MAX - 1; }
// Apply windowing to all x zones
for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
{
// apply lite triangular window design with gradient of 10% per discrete step
m_windowed_hue_hist[(zone * (h_MAX+1)) + i] += m_hue_hist[(zone * (h_MAX+1)) + myidx] * ((hue_windowsize+1)-abs(mywin)); // apply window
}
}
}
/*--------------------------------------*/
/* analyze histogram for most used hue */
/*--------------------------------------*/
// index of last maximum
// static int most_used_hue_last[CAP_MAX_NUM_ZONES] = {0, 0, 0, 0, 0}; --> m_most_used_hue_last
// resulting hue for each channel
//int most_used_hue[CAP_MAX_NUM_ZONES]; --> m_most_used_hue
FindMostUsed(AtmoSetup_NumZones, m_most_used_hue, m_windowed_hue_hist);
for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
{
float percent = (float)m_windowed_hue_hist[zone * (h_MAX+1) + m_most_used_hue_last[zone]] / (float)m_windowed_hue_hist[zone * (h_MAX+1) + m_most_used_hue[zone]];
if (percent > 0.93f) // less than 7% difference?
m_most_used_hue[zone] = m_most_used_hue_last[zone]; // use last index
else
m_most_used_hue_last[zone] = m_most_used_hue[zone];
}
/*
memset(m_most_used_hue, 0, sizeof(int) * AtmoSetup_NumZones);
for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
{
long int value = 0;
for (i = 0; i < h_MAX+1; i++) // walk through histogram
{
long int tmp = m_windowed_hue_hist[ (zone * (h_MAX+1)) + i ];
if (tmp > value) // if new value bigger then old one
{
m_most_used_hue[zone] = i; // remember index
value = tmp; // w_hue_hist[zone][i]; // and value
}
}
float percent = (float)m_windowed_hue_hist[zone * (h_MAX+1) + m_most_used_hue_last[zone]] / (float)value;
if (percent > 0.93f) // less than 7% difference?
{
m_most_used_hue[zone] = m_most_used_hue_last[zone]; // use last index
}
m_most_used_hue_last[zone] = m_most_used_hue[zone]; // save current index of most used hue
}
*/
/***************************************************************************/
/* saturation */
/***************************************************************************/
// sat histogram
// long int sat_hist[CAP_MAX_NUM_ZONES][s_MAX+1]; -> m_sat_hist
// hue of the pixel we are working at
int pixel_hue = 0;
// clean histogram
memset(m_sat_hist, 0, sizeof(long int) * (s_MAX+1) * AtmoSetup_NumZones);
/*--------------------------------------*/
/* saturation histogram builtup */
/*--------------------------------------*/
i = 0;
temp_Img = HSV_Img;
for (int row = 0; row < CAP_HEIGHT; row++)
{
for (int column = 0; column < CAP_WIDTH; column++)
{
// forget black bars: perform calculations only if pixel has some luminosity
if ((*temp_Img).v > AtmoSetup_DarknessLimit)
{
// find histogram position for pixel
pixel_hue = (*temp_Img).h;
// TODO: brightness calculation(if we require it some time)
for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
{
// only use pixel for histogram if hue is near most_used_hue
if ((pixel_hue > m_most_used_hue[zone] - hue_windowsize) &&
(pixel_hue < m_most_used_hue[zone] + hue_windowsize))
{
// build histogram
// sat_hist[channel][HSV_Img[i].s] += Weight[i].channel[channel] * HSV_Img[i].v;
m_sat_hist[zone * (s_MAX+1) + (*temp_Img).s ] += m_Zone_Weights[zone][i] * (*temp_Img).v;
}
}
}
i++;
temp_Img++;
}
}
/*--------------------------------------*/
/* saturation histogram windowing */
/*--------------------------------------*/
// windowed HSV histogram
// long int w_sat_hist[CAP_MAX_NUM_ZONES][s_MAX+1]; --> m_windowed_sat_hist
// clean windowed histogram
memset(m_windowed_sat_hist, 0, sizeof(long int) * (s_MAX+1) * AtmoSetup_NumZones);
// steps in each direction; eg. 2 => -2 -1 0 1 2 windowing
int sat_windowsize = AtmoSetup_SatWinSize;
// walk through histogram [0;h_MAX]
for (i = 0; i < s_MAX + 1; i++)
{
// windowing from -hue_windowsize -> +hue_windowsize
for (int mywin = -sat_windowsize; mywin < sat_windowsize+1; mywin++)
{
// addressed histogram candlestick
int myidx = i + mywin;
// handle beginning of windowing -> roll back
if (myidx < 0) { myidx = myidx + s_MAX + 1; }
// handle end of windowing -> roll forward
if (myidx > h_MAX) { myidx = myidx - s_MAX - 1; }
for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
{
/*
apply lite triangular window design with
gradient of 10% per discrete step
*/
/*
w_sat_hist[channel][i] += sat_hist[channel][myidx] *
((sat_windowsize+1)-abs(mywin)); // apply window
*/
m_windowed_sat_hist[zone * (s_MAX+1) + i] += m_sat_hist[zone* (h_MAX+1) + myidx] *
((sat_windowsize+1)-abs(mywin)); // apply window
}
}
}
/*--------------------------------------*/
/* analyze histogram for most used sat */
/*--------------------------------------*/
// resulting sat (most_used_hue) for each channel
// int most_used_sat[CAP_MAX_NUM_ZONES];->m_most_used_sat
FindMostUsed(AtmoSetup_NumZones, m_most_used_sat, m_windowed_sat_hist);
/*
memset(m_most_used_sat, 0, sizeof(int) * AtmoSetup_NumZones);
for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
{
int value = 0;
// walk trough histogram
for (i = 0; i < s_MAX+1; i++)
{
// if new value bigger then old one
int tmp = m_windowed_sat_hist[zone * (s_MAX+1) + i];
// if (w_sat_hist[channel][i] > value)
if (tmp > value)
{
// remember index
m_most_used_sat[zone] = i;
// and value
value = tmp;
}
}
}
*/
/*----------------------------------------------------------*/
/* calculate average brightness within HSV image */
/* uniform Brightness for all channels is calculated */
/*----------------------------------------------------------*/
/* code integrated into "hue histogram builtup" to save some looping time!
int l_counter = 0;
// average brightness (value)
long int value_avg = 0;
i = 0;
for (int row = 0; row < CAP_HEIGHT; row++)
{
for (int column = 0; column < CAP_WIDTH; column++)
{
// find average value: only use bright pixels for luminance average
if (HSV_Img[i].v > AtmoSetup_DarknessLimit)
{
// build brightness average
value_avg += HSV_Img[i].v;
l_counter++;
}
i++;
}
}
// calculate brightness average
if (l_counter > 0) { value_avg = value_avg / l_counter; }
else { value_avg = AtmoSetup_DarknessLimit; }
*/
/*----------------------------*/
/* adjust and copy results */
/*----------------------------*/
tHSVColor hsv_pixel;
// storage container for resulting RGB values
pColorPacket output_colors;
AllocColorPacket(output_colors, AtmoSetup_NumZones);
// adjust brightness
// int new_value = (int) ((float)value_avg * ((float)AtmoSetup_BrightCorrect / 100.0));
// if (new_value > 255) new_value = 255; // ensure brightness isn't set too high
// hsv_pixel.v = (unsigned char)new_value;
/*
// calculate brightness average
for(int zone = 0; zone < AtmoSetup_NumZones; zone++) {
if(m_average_counter[zone] > 0)
m_average_v[zone] = m_average_v[zone] / m_average_counter[zone]
else
m_average_v[zone] = AtmoSetup_DarknessLimit;
}
*/
for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
{
if(m_average_counter[zone] > 0)
m_average_v[zone] = m_average_v[zone] / m_average_counter[zone];
else
m_average_v[zone] = AtmoSetup_DarknessLimit;
m_average_v[zone] = (int)((float)m_average_v[zone] * ((float)AtmoSetup_BrightCorrect / 100.0));
hsv_pixel.v = (unsigned char)ATMO_MAX(ATMO_MIN(m_average_v[zone],255),0);
hsv_pixel.h = m_most_used_hue[zone];
hsv_pixel.s = m_most_used_sat[zone];
// convert back to rgb
output_colors->zone[zone] = HSV2RGB(hsv_pixel);
}
return output_colors;
}
tHSVColor RGB2HSV(tRGBColor color)
{
int min, max, delta;
int r, g, b;
int h = 0;
tHSVColor hsv;
r = color.r;
g = color.g;
b = color.b;
min = ATMO_MIN(ATMO_MIN(r, g), b);
max = ATMO_MAX(ATMO_MAX(r, g), b);
delta = max - min;
hsv.v = (unsigned char) POS_DIV( max*v_MAX, 255 );
if (delta == 0) // This is a gray, no chroma...
{
h = 0; // HSV results = 0 / 1
hsv.s = 0;
}
else // Chromatic data...
{
hsv.s = (unsigned char) POS_DIV( (delta*s_MAX) , max );
int dr = (max - r) + 3*delta;
int dg = (max - g) + 3*delta;
int db = (max - b) + 3*delta;
int divisor = 6*delta;
if (r == max)
{
h = POS_DIV(( (db - dg) * h_MAX ) , divisor);
}
else if (g == max)
{
h = POS_DIV( ((dr - db) * h_MAX) , divisor) + (h_MAX/3);
}
else if (b == max)
{
h = POS_DIV(( (dg - dr) * h_MAX) , divisor) + (h_MAX/3)*2;
}
if ( h < 0 ) { h += h_MAX; }
if ( h > h_MAX ) { h -= h_MAX; }
}
hsv.h = (unsigned char)h;
return hsv;
}
tRGBColor HSV2RGB(tHSVColor color)
{
tRGBColor rgb = {0, 0, 0};
float h = (float)color.h/(float)h_MAX;
float s = (float)color.s/(float)s_MAX;
float v = (float)color.v/(float)v_MAX;
if (s == 0)
{
rgb.r = (int)((v*255.0)+0.5);
rgb.g = rgb.r;
rgb.b = rgb.r;
}
else
{
h = h * 6.0f;
if (h == 6.0) { h = 0.0; }
int i = (int)h;
float f = h - i;
float p = v*(1.0f-s);
float q = v*(1.0f-(s*f));
float t = v*(1.0f-(s*(1.0f-f)));
if (i == 0)
{
rgb.r = (int)((v*255.0)+0.5);
rgb.g = (int)((t*255.0)+0.5);
rgb.b = (int)((p*255.0)+0.5);
}
else if (i == 1)
{
rgb.r = (int)((q*255.0)+0.5);
rgb.g = (int)((v*255.0)+0.5);
rgb.b = (int)((p*255.0)+0.5);
}
else if (i == 2)
{
rgb.r = (int)((p*255.0)+0.5);
rgb.g = (int)((v*255.0)+0.5);
rgb.b = (int)((t*255.0)+0.5);
}
else if (i == 3)
{
rgb.r = (int)((p*255.0)+0.5);
rgb.g = (int)((q*255.0)+0.5);
rgb.b = (int)((v*255.0)+0.5);
}
else if (i == 4)
{
rgb.r = (int)((t*255.0)+0.5);
rgb.g = (int)((p*255.0)+0.5);
rgb.b = (int)((v*255.0)+0.5);
}
else
{
rgb.r = (int)((v*255.0)+0.5);
rgb.g = (int)((p*255.0)+0.5);
rgb.b = (int)((q*255.0)+0.5);
}
}
return rgb;
}
/*
* AtmoCalculations.h: see calculations.h of the linux version... one to one copy
* calculations.h: calculations needed by the input devices
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifndef _AtmoCalculations_h_
#define _AtmoCalculations_h_
#include "AtmoDefs.h"
#include "AtmoConfig.h"
#define Weight(zone, pixel_nummer) m_Weight[((zone) * (IMAGE_SIZE)) + (pixel_nummer)]
class CAtmoColorCalculator
{
protected:
CAtmoConfig *m_pAtmoConfig;
// Flip instead having a array with (64x48) entries of values for each channel
// I have x arrays of 64x48 so each channel has its own array...
// (or gradient which is use to judge about the pixels)
int *m_Weight;
int **m_Zone_Weights;
long int *m_hue_hist;
long int *m_windowed_hue_hist;
int *m_most_used_hue_last;
int *m_most_used_hue;
long int *m_sat_hist;
long int *m_windowed_sat_hist;
int *m_most_used_sat;
long int *m_average_v;
int *m_average_counter;
protected:
int m_LastEdgeWeighting;
int m_LastWidescreenMode;
int m_LastLayout_TopCount;
int m_LastLayout_BottomCount;
int m_LastLayout_LRCount;
int m_LastNumZones;
protected:
void FindMostUsed(int AtmoSetup_NumZones,int *most_used,long int *windowed_hist);
public:
CAtmoColorCalculator(CAtmoConfig *pAtmoConfig);
~CAtmoColorCalculator(void);
pColorPacket AnalyzeHSV(tHSVColor *HSV_Img);
void UpdateParameters();
};
tHSVColor RGB2HSV(tRGBColor color);
tRGBColor HSV2RGB(tHSVColor color);
#endif
/*
* AtmoChannelAssignment.cpp: Class for storing a hardware channel to zone mapping
* List
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include "AtmoChannelAssignment.h"
CAtmoChannelAssignment::CAtmoChannelAssignment(void)
{
m_psz_name = strdup("");
m_mappings = NULL;
m_num_channels = 0;
system = ATMO_FALSE;
}
CAtmoChannelAssignment::CAtmoChannelAssignment(CAtmoChannelAssignment &source)
{
m_num_channels = 0; m_psz_name = NULL;
m_mappings = source.getMapArrayClone(m_num_channels);
setName( source.getName() );
system = source.system;
}
CAtmoChannelAssignment::~CAtmoChannelAssignment(void)
{
delete[] m_mappings;
free(m_psz_name);
}
void CAtmoChannelAssignment::setName(const char *pszNewName)
{
free(m_psz_name);
m_psz_name = pszNewName ? strdup(pszNewName) : strdup("");
}
void CAtmoChannelAssignment::setSize(int numChannels)
{
if(numChannels != m_num_channels)
{
delete[] m_mappings;
m_num_channels = numChannels;
if(m_num_channels > 0)
{
m_mappings = new int[m_num_channels];
memset(m_mappings, 0, sizeof(int) * m_num_channels);
}
else
m_mappings = NULL;
}
}
int *CAtmoChannelAssignment::getMapArrayClone(int &count)
{
count = m_num_channels;
if(count == 0) return NULL;
int *temp = new int[m_num_channels];
memcpy(temp, m_mappings, sizeof(int) * m_num_channels);
return(temp);
}
int CAtmoChannelAssignment::getZoneIndex(int channel)
{
if(m_mappings && (channel>=0) && (channel<m_num_channels))
return m_mappings[channel] ;
else
return -1;
}
void CAtmoChannelAssignment::setZoneIndex(int channel, int zone)
{
if(m_mappings && (channel>=0) && (channel<m_num_channels))
m_mappings[channel] = zone;
}
#ifndef _AtmoChannelAssignment_
#define _AtmoChannelAssignment_
#include "AtmoDefs.h"
class CAtmoChannelAssignment
{
protected:
// name of the mapping (for menus and lists)
char *m_psz_name;
// count of channels starting with 0 ... X for which a mapping exists!
int m_num_channels;
// array were each destination channel - has an index to the source zone to use
// or -1 to show black output on this channel
int *m_mappings;
public:
CAtmoChannelAssignment(void);
CAtmoChannelAssignment(CAtmoChannelAssignment &source);
~CAtmoChannelAssignment(void);
public:
// internal used to mark a not modifyable definition
// with a default assignment!
ATMO_BOOL system;
char *getName() { return(m_psz_name); }
void setName(const char *pszNewName);
void setSize(int numChannels);
int getSize() { return m_num_channels; }
int *getMapArrayClone(int &count);
int getZoneIndex(int channel);
void setZoneIndex(int channel, int zone);
};
#endif
/*
* AtmoClassicConnection.cpp: Class for communication with the serial hardware of
* Atmo Light, opens and configures the serial port
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "AtmoDefs.h"
#include "AtmoClassicConnection.h"
#if !defined(_ATMO_VLC_PLUGIN_)
# include "AtmoClassicConfigDialog.h"
#endif
#include <stdio.h>
#include <fcntl.h>
#if !defined(_WIN32)
#include <termios.h>
#include <unistd.h>
#include <vlc_fs.h>
#endif
CAtmoClassicConnection::CAtmoClassicConnection(CAtmoConfig *cfg) : CAtmoConnection(cfg) {
m_hComport = INVALID_HANDLE_VALUE;
}
CAtmoClassicConnection::~CAtmoClassicConnection() {
}
ATMO_BOOL CAtmoClassicConnection::OpenConnection() {
#if defined(_ATMO_VLC_PLUGIN_)
char *serdevice = m_pAtmoConfig->getSerialDevice();
if(!serdevice)
return ATMO_FALSE;
#else
int portNummer = m_pAtmoConfig->getComport();
m_dwLastWin32Error = 0;
if(portNummer < 1) return ATMO_FALSE; // make no real sense;-)
#endif
CloseConnection();
#if !defined(_ATMO_VLC_PLUGIN_)
char serdevice[16]; // com4294967295
sprintf(serdevice,"com%d",portNummer);
#endif
#if defined(_WIN32)
m_hComport = CreateFileA(serdevice, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if(m_hComport == INVALID_HANDLE_VALUE) {
// we have a problem here can't open com port... somebody else may use it?
// m_dwLastWin32Error = GetLastError();
return ATMO_FALSE;
}
/* change serial settings (Speed, stopbits etc.) */
DCB dcb; // für comport-parameter
dcb.DCBlength = sizeof(DCB);
GetCommState (m_hComport, &dcb); // ger current serialport settings
dcb.BaudRate = 38400; // set speed
dcb.ByteSize = 8; // set databits
dcb.Parity = NOPARITY; // set parity
dcb.StopBits = ONESTOPBIT; // set one stop bit
SetCommState (m_hComport, &dcb); // apply settings
#else
int bconst = B38400;
m_hComport = vlc_open(serdevice,O_RDWR | O_NOCTTY);
if(m_hComport < 0) {
return ATMO_FALSE;
}
struct termios tio;
memset(&tio,0,sizeof(tio));
tio.c_cflag = (CS8 | CREAD | HUPCL | CLOCAL);
tio.c_iflag = (INPCK | BRKINT);
cfsetispeed(&tio, bconst);
cfsetospeed(&tio, bconst);
if(!tcsetattr(m_hComport, TCSANOW, &tio)) {
tcflush(m_hComport, TCIOFLUSH);
} else {
// can't change parms
close(m_hComport);
m_hComport = -1;
return false;
}
#endif
return true;
}
void CAtmoClassicConnection::CloseConnection() {
if(m_hComport!=INVALID_HANDLE_VALUE) {
#if defined(_WIN32)
CloseHandle(m_hComport);
#else
close(m_hComport);
#endif
m_hComport = INVALID_HANDLE_VALUE;
}
}
ATMO_BOOL CAtmoClassicConnection::isOpen(void) {
return (m_hComport != INVALID_HANDLE_VALUE);
}
ATMO_BOOL CAtmoClassicConnection::HardwareWhiteAdjust(int global_gamma,
int global_contrast,
int contrast_red,
int contrast_green,
int contrast_blue,
int gamma_red,
int gamma_green,
int gamma_blue,
ATMO_BOOL storeToEeprom) {
if(m_hComport == INVALID_HANDLE_VALUE)
return ATMO_FALSE;
DWORD iBytesWritten;
/*
[0] = 255
[1] = 00
[2] = 00
[3] = 101
[4] brightness 0..255 ?
[5] Contrast Red 11 .. 100
[6] Contrast Green 11 .. 100
[7] Contrast Blue 11 .. 100
[8] Gamma Red 11 .. 35
[9] Gamma Red 11 .. 35
[10] Gamma Red 11 .. 35
[11] Globale Contrast 11 .. 100
[12] Store Data: 199 (else 0)
*/
unsigned char sendBuffer[16];
sendBuffer[0] = 0xFF;
sendBuffer[1] = 0x00;
sendBuffer[2] = 0x00;
sendBuffer[3] = 101;
sendBuffer[4] = (global_gamma & 255);
sendBuffer[5] = (contrast_red & 255);
sendBuffer[6] = (contrast_green & 255);
sendBuffer[7] = (contrast_blue & 255);
sendBuffer[8] = (gamma_red & 255);
sendBuffer[9] = (gamma_green & 255);
sendBuffer[10] = (gamma_blue & 255);
sendBuffer[11] = (global_contrast & 255);
if(storeToEeprom == ATMO_TRUE)
sendBuffer[12] = 199; // store to eeprom!
else
sendBuffer[12] = 0;
#if defined(_WIN32)
WriteFile(m_hComport, sendBuffer, 13, &iBytesWritten, NULL); // send to COM-Port
#else
iBytesWritten = write(m_hComport, sendBuffer, 13);
tcdrain(m_hComport);
#endif
return (iBytesWritten == 13) ? ATMO_TRUE : ATMO_FALSE;
}
ATMO_BOOL CAtmoClassicConnection::SendData(pColorPacket data) {
if(m_hComport == INVALID_HANDLE_VALUE)
return ATMO_FALSE;
unsigned char buffer[19];
DWORD iBytesWritten;
buffer[0] = 0xFF; // Start Byte
buffer[1] = 0x00; // Start channel 0
buffer[2] = 0x00; // Start channel 0
buffer[3] = 15; //
int iBuffer = 4;
int idx;
Lock();
for(int i=0; i < 5 ; i++) {
if(m_ChannelAssignment && (i < m_NumAssignedChannels))
idx = m_ChannelAssignment[i];
else
idx = -1;
if((idx>=0) && (idx<data->numColors)) {
buffer[iBuffer++] = data->zone[idx].r;
buffer[iBuffer++] = data->zone[idx].g;
buffer[iBuffer++] = data->zone[idx].b;
} else {
buffer[iBuffer++] = 0;
buffer[iBuffer++] = 0;
buffer[iBuffer++] = 0;
}
}
#if defined(_WIN32)
WriteFile(m_hComport, buffer, 19, &iBytesWritten, NULL); // send to COM-Port
#else
iBytesWritten = write(m_hComport, buffer, 19);
tcdrain(m_hComport);
#endif
Unlock();
return (iBytesWritten == 19) ? ATMO_TRUE : ATMO_FALSE;
}
ATMO_BOOL CAtmoClassicConnection::CreateDefaultMapping(CAtmoChannelAssignment *ca)
{
if(!ca) return ATMO_FALSE;
ca->setSize(5);
ca->setZoneIndex(0, 4); // Zone 5
ca->setZoneIndex(1, 3);
ca->setZoneIndex(2, 1);
ca->setZoneIndex(3, 0);
ca->setZoneIndex(4, 2);
return ATMO_TRUE;
}
#if !defined(_ATMO_VLC_PLUGIN_)
char *CAtmoClassicConnection::getChannelName(int ch)
{
if(ch < 0) return NULL;
char buf[30];
switch(ch) {
case 0:
sprintf(buf,"Summen Kanal [%d]",ch);
break;
case 1:
sprintf(buf,"Linker Kanal [%d]",ch);
break;
case 2:
sprintf(buf,"Rechter Kanal [%d]",ch);
break;
case 3:
sprintf(buf,"Oberer Kanal [%d]",ch);
break;
case 4:
sprintf(buf,"Unterer Kanal [%d]",ch);
break;
default:
sprintf(buf,"Kanal [%d]",ch);
break;
}
return strdup(buf);
}
ATMO_BOOL CAtmoClassicConnection::ShowConfigDialog(HINSTANCE hInst, HWND parent, CAtmoConfig *cfg)
{
CAtmoClassicConfigDialog *dlg = new CAtmoClassicConfigDialog(hInst, parent, cfg);
INT_PTR result = dlg->ShowModal();
delete dlg;
if(result == IDOK)
return ATMO_TRUE;
else
return ATMO_FALSE;
}
#endif
/*
* AtmoClassicConnection.h: Class for communication with the serial hardware of Atmo Light,
* opens and configures the serial port
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifndef _AtmoClassicConnection_h_
#define _AtmoClassicConnection_h_
#include "AtmoDefs.h"
#include "AtmoConnection.h"
#include "AtmoConfig.h"
#if defined(_WIN32)
# include <windows.h>
#endif
class CAtmoClassicConnection : public CAtmoConnection {
private:
HANDLE m_hComport;
#if defined(_WIN32)
DWORD m_dwLastWin32Error;
public:
DWORD getLastError() { return m_dwLastWin32Error; }
#endif
public:
CAtmoClassicConnection(CAtmoConfig *cfg);
virtual ~CAtmoClassicConnection(void);
virtual ATMO_BOOL OpenConnection();
virtual void CloseConnection();
virtual ATMO_BOOL isOpen(void);
virtual ATMO_BOOL SendData(pColorPacket data);
virtual ATMO_BOOL HardwareWhiteAdjust(int global_gamma,
int global_contrast,
int contrast_red,
int contrast_green,
int contrast_blue,
int gamma_red,
int gamma_green,
int gamma_blue,
ATMO_BOOL storeToEeprom);
virtual int getNumChannels() { return 5; }
virtual const char *getDevicePath() { return "atmo"; }
#if !defined(_ATMO_VLC_PLUGIN_)
virtual char *getChannelName(int ch);
virtual ATMO_BOOL ShowConfigDialog(HINSTANCE hInst, HWND parent, CAtmoConfig *cfg);
#endif
virtual ATMO_BOOL CreateDefaultMapping(CAtmoChannelAssignment *ca);
};
#endif
/*
* AtmoConfig.cpp: Class for holding all configuration values of AtmoWin - stores
* the values and retrieves its values from registry
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <string.h>
#include "AtmoConfig.h"
/* Import Hint
if somebody Adds new config option this has to be done in the following
files and includes!
AtmoConfig.h -- extend class definition!, and add get... and set... Methods!
so that the real variables are still hidden inside the class!
AtmoConfigRegistry.cpp --> SaveToRegistry();
AtmoConfigRegistry.cpp --> LoadFromRegistry();
AtmoConfig.cpp --> Assign( ... );
*/
CAtmoConfig::CAtmoConfig()
{
// setup basic configruation structures...
m_IsShowConfigDialog = 0;
m_eAtmoConnectionType = actClassicAtmo;
for(int i=0;i<10;i++)
m_ChannelAssignments[i] = NULL;
#if defined (_ATMO_VLC_PLUGIN_)
m_devicename = NULL;
m_devicenames[0] = NULL;
m_devicenames[1] = NULL;
m_devicenames[2] = NULL;
#endif
// load all config values with there defaults
m_ZoneDefinitions = NULL;
m_AtmoZoneDefCount = -1;
m_DMX_BaseChannels = NULL;
m_chWhiteAdj_Red = NULL;
m_chWhiteAdj_Green = NULL;
m_chWhiteAdj_Blue = NULL;
LoadDefaults();
}
CAtmoConfig::~CAtmoConfig() {
// and finally cleanup...
clearAllChannelMappings();
if(m_ZoneDefinitions)
{
for(int zone=0; zone<m_AtmoZoneDefCount; zone++)
delete m_ZoneDefinitions[zone];
delete[] m_ZoneDefinitions;
m_ZoneDefinitions = NULL;
}
delete []m_chWhiteAdj_Red;
delete []m_chWhiteAdj_Green;
delete []m_chWhiteAdj_Blue;
free( m_DMX_BaseChannels );
#if defined (_ATMO_VLC_PLUGIN_)
free( m_devicename );
free( m_devicenames[0] );
free( m_devicenames[1] );
free( m_devicenames[2] );
#endif
}
void CAtmoConfig::LoadDefaults() {
// m_eAtmoConnectionType = actSerialPort;
// m_Comport
#if defined (_ATMO_VLC_PLUGIN_)
free( m_devicename );
free( m_devicenames[0] );
free( m_devicenames[1] );
free( m_devicenames[2] );
m_devicename = NULL;
m_devicenames[0] = NULL;
m_devicenames[1] = NULL;
m_devicenames[2] = NULL;
#else
m_Comport = -1;
m_Comports[0] = -1;
m_Comports[1] = -1;
m_Comports[2] = -1;
#endif
m_eEffectMode = emDisabled;
m_IgnoreConnectionErrorOnStartup = ATMO_FALSE;
m_UpdateEdgeWeightningFlag = 0;
m_Software_gamma_mode = agcNone;
m_Software_gamma_red = 10;
m_Software_gamma_green = 10;
m_Software_gamma_blue = 10;
m_Software_gamma_global = 10;
m_WhiteAdjustment_Red = 255;
m_WhiteAdjustment_Green = 255;
m_WhiteAdjustment_Blue = 255;
m_UseSoftwareWhiteAdj = 1;
m_WhiteAdjPerChannel = ATMO_FALSE;
m_chWhiteAdj_Count = 0;
delete []m_chWhiteAdj_Red;
delete []m_chWhiteAdj_Green;
delete []m_chWhiteAdj_Blue;
m_chWhiteAdj_Red = NULL;
m_chWhiteAdj_Green = NULL;
m_chWhiteAdj_Blue = NULL;
m_ColorChanger_iSteps = 50;
m_ColorChanger_iDelay = 25;
m_LrColorChanger_iSteps = 50;
m_LrColorChanger_iDelay = 25;
m_IsSetShutdownColor = 1;
m_ShutdownColor_Red = 0;
m_ShutdownColor_Green = 0;
m_ShutdownColor_Blue = 0;
m_StaticColor_Red = 127; // ??
m_StaticColor_Green = 192;
m_StaticColor_Blue = 255;
m_LiveViewFilterMode = afmCombined;
m_LiveViewFilter_PercentNew = 50;
m_LiveViewFilter_MeanLength = 300;
m_LiveViewFilter_MeanThreshold = 40;
m_show_statistics = ATMO_FALSE;
m_LiveView_EdgeWeighting = 8;
m_LiveView_BrightCorrect = 100;
m_LiveView_DarknessLimit = 5;
m_LiveView_HueWinSize = 3;
m_LiveView_SatWinSize = 3;
m_LiveView_WidescreenMode = 0;
m_LiveView_HOverscanBorder = 0;
m_LiveView_VOverscanBorder = 0;
m_LiveView_DisplayNr = 0;
m_LiveView_FrameDelay = 30;
m_LiveView_GDI_FrameRate = 25;
m_LiveView_RowsPerFrame = 0;
m_Hardware_global_gamma = 128;
m_Hardware_global_contrast = 100;
m_Hardware_contrast_red = 100;
m_Hardware_contrast_green = 100;
m_Hardware_contrast_blue = 100;
m_Hardware_gamma_red = 22;
m_Hardware_gamma_green = 22;
m_Hardware_gamma_blue = 22;
m_DMX_BaseChannels = strdup("0");
m_DMX_RGB_Channels = 5; // so wie atmolight
m_MoMo_Channels = 3; // default momo, there exists also a 4 ch version!
m_Fnordlicht_Amount = 2; // default fnordlicht, there are 2 fnordlicht's!
m_ZonesTopCount = 1;
m_ZonesBottomCount = 1;
m_ZonesLRCount = 1;
m_ZoneSummary = ATMO_FALSE;
UpdateZoneCount();
clearAllChannelMappings();
m_CurrentChannelAssignment = 0;
CAtmoChannelAssignment *temp = new CAtmoChannelAssignment();
temp->system = true;
temp->setName( "Standard" );
this->m_ChannelAssignments[0] = temp;
UpdateZoneDefinitionCount();
}
void CAtmoConfig::Assign(CAtmoConfig *pAtmoConfigSrc) {
#if defined(_ATMO_VLC_PLUGIN_)
this->setSerialDevice(0, pAtmoConfigSrc->getSerialDevice(0));
this->setSerialDevice(1, pAtmoConfigSrc->getSerialDevice(1));
this->setSerialDevice(2, pAtmoConfigSrc->getSerialDevice(2));
this->setSerialDevice(3, pAtmoConfigSrc->getSerialDevice(3));
#else
this->m_Comport = pAtmoConfigSrc->m_Comport;
this->m_Comports[0] = pAtmoConfigSrc->m_Comports[0];
this->m_Comports[1] = pAtmoConfigSrc->m_Comports[1];
this->m_Comports[2] = pAtmoConfigSrc->m_Comports[2];
#endif
this->m_eAtmoConnectionType = pAtmoConfigSrc->m_eAtmoConnectionType;
this->m_eEffectMode = pAtmoConfigSrc->m_eEffectMode;
this->m_WhiteAdjustment_Red = pAtmoConfigSrc->m_WhiteAdjustment_Red;
this->m_WhiteAdjustment_Green = pAtmoConfigSrc->m_WhiteAdjustment_Green;
this->m_WhiteAdjustment_Blue = pAtmoConfigSrc->m_WhiteAdjustment_Blue;
this->m_UseSoftwareWhiteAdj = pAtmoConfigSrc->m_UseSoftwareWhiteAdj;
this->m_WhiteAdjPerChannel = pAtmoConfigSrc->m_WhiteAdjPerChannel;
this->m_chWhiteAdj_Count = pAtmoConfigSrc->m_chWhiteAdj_Count;
delete []m_chWhiteAdj_Red;
delete []m_chWhiteAdj_Green;
delete []m_chWhiteAdj_Blue;
if(m_chWhiteAdj_Count > 0)
{
m_chWhiteAdj_Red = new int[ m_chWhiteAdj_Count ];
m_chWhiteAdj_Green = new int[ m_chWhiteAdj_Count ];
m_chWhiteAdj_Blue = new int[ m_chWhiteAdj_Count ];
memcpy(m_chWhiteAdj_Red, pAtmoConfigSrc->m_chWhiteAdj_Red, sizeof(int) * m_chWhiteAdj_Count);
memcpy(m_chWhiteAdj_Green, pAtmoConfigSrc->m_chWhiteAdj_Green, sizeof(int) * m_chWhiteAdj_Count);
memcpy(m_chWhiteAdj_Blue, pAtmoConfigSrc->m_chWhiteAdj_Blue, sizeof(int) * m_chWhiteAdj_Count);
} else {
m_chWhiteAdj_Red = NULL;
m_chWhiteAdj_Green = NULL;
m_chWhiteAdj_Blue = NULL;
}
this->m_IsSetShutdownColor = pAtmoConfigSrc->m_IsSetShutdownColor;
this->m_ShutdownColor_Red = pAtmoConfigSrc->m_ShutdownColor_Red;
this->m_ShutdownColor_Green = pAtmoConfigSrc->m_ShutdownColor_Green;
this->m_ShutdownColor_Blue = pAtmoConfigSrc->m_ShutdownColor_Blue;
this->m_ColorChanger_iSteps = pAtmoConfigSrc->m_ColorChanger_iSteps;
this->m_ColorChanger_iDelay = pAtmoConfigSrc->m_ColorChanger_iDelay;
this->m_LrColorChanger_iSteps = pAtmoConfigSrc->m_LrColorChanger_iSteps;
this->m_LrColorChanger_iDelay = pAtmoConfigSrc->m_LrColorChanger_iDelay;
this->m_StaticColor_Red = pAtmoConfigSrc->m_StaticColor_Red;
this->m_StaticColor_Green = pAtmoConfigSrc->m_StaticColor_Green;
this->m_StaticColor_Blue = pAtmoConfigSrc->m_StaticColor_Blue;
this->m_LiveViewFilterMode = pAtmoConfigSrc->m_LiveViewFilterMode;
this->m_LiveViewFilter_PercentNew = pAtmoConfigSrc->m_LiveViewFilter_PercentNew;
this->m_LiveViewFilter_MeanLength = pAtmoConfigSrc->m_LiveViewFilter_MeanLength;
this->m_LiveViewFilter_MeanThreshold = pAtmoConfigSrc->m_LiveViewFilter_MeanThreshold;
this->m_show_statistics = pAtmoConfigSrc->m_show_statistics;
this->m_LiveView_EdgeWeighting = pAtmoConfigSrc->m_LiveView_EdgeWeighting;
this->m_LiveView_BrightCorrect = pAtmoConfigSrc->m_LiveView_BrightCorrect;
this->m_LiveView_DarknessLimit = pAtmoConfigSrc->m_LiveView_DarknessLimit;
this->m_LiveView_HueWinSize = pAtmoConfigSrc->m_LiveView_HueWinSize;
this->m_LiveView_SatWinSize = pAtmoConfigSrc->m_LiveView_SatWinSize;
this->m_LiveView_WidescreenMode = pAtmoConfigSrc->m_LiveView_WidescreenMode;
this->m_LiveView_HOverscanBorder = pAtmoConfigSrc->m_LiveView_HOverscanBorder;
this->m_LiveView_VOverscanBorder = pAtmoConfigSrc->m_LiveView_VOverscanBorder;
this->m_LiveView_DisplayNr = pAtmoConfigSrc->m_LiveView_DisplayNr;
this->m_LiveView_FrameDelay = pAtmoConfigSrc->m_LiveView_FrameDelay;
this->m_LiveView_GDI_FrameRate = pAtmoConfigSrc->m_LiveView_GDI_FrameRate;
this->m_LiveView_RowsPerFrame = pAtmoConfigSrc->m_LiveView_RowsPerFrame;
this->m_ZonesTopCount = pAtmoConfigSrc->m_ZonesTopCount;
this->m_ZonesBottomCount = pAtmoConfigSrc->m_ZonesBottomCount;
this->m_ZonesLRCount = pAtmoConfigSrc->m_ZonesLRCount;
this->m_ZoneSummary = pAtmoConfigSrc->m_ZoneSummary;
UpdateZoneCount();
this->m_Software_gamma_mode = pAtmoConfigSrc->m_Software_gamma_mode;
this->m_Software_gamma_red = pAtmoConfigSrc->m_Software_gamma_red;
this->m_Software_gamma_green = pAtmoConfigSrc->m_Software_gamma_green;
this->m_Software_gamma_blue = pAtmoConfigSrc->m_Software_gamma_blue;
this->m_Software_gamma_global = pAtmoConfigSrc->m_Software_gamma_global;
this->setDMX_BaseChannels( pAtmoConfigSrc->getDMX_BaseChannels() );
this->m_DMX_RGB_Channels = pAtmoConfigSrc->m_DMX_RGB_Channels;
this->m_MoMo_Channels = pAtmoConfigSrc->m_MoMo_Channels;
this->m_Fnordlicht_Amount = pAtmoConfigSrc->m_Fnordlicht_Amount;
this->m_CurrentChannelAssignment = pAtmoConfigSrc->m_CurrentChannelAssignment;
clearChannelMappings();
for(int i=1;i<pAtmoConfigSrc->getNumChannelAssignments();i++) {
CAtmoChannelAssignment *ta = pAtmoConfigSrc->m_ChannelAssignments[i];
if(ta!=NULL) {
CAtmoChannelAssignment *dest = this->m_ChannelAssignments[i];
if(dest == NULL) {
dest = new CAtmoChannelAssignment();
this->m_ChannelAssignments[i] = dest;
}
// memcpy(dest, ta, sizeof(tChannelAssignment));
dest->setSize(ta->getSize());
dest->setName(ta->getName());
dest->system = ta->system;
for(int c=0;c<dest->getSize();c++)
dest->setZoneIndex(c, ta->getZoneIndex(c));
}
}
UpdateZoneDefinitionCount();
}
int CAtmoConfig::getNumChannelAssignments() {
int z=0;
for(int i=0;i<10;i++)
if(this->m_ChannelAssignments[i]!=NULL) z++;
return z;
}
void CAtmoConfig::clearChannelMappings() {
for(int i=1;i<10;i++) {
CAtmoChannelAssignment *ca = m_ChannelAssignments[i];
if(ca!=NULL)
delete ca;
m_ChannelAssignments[i] = NULL;
}
}
void CAtmoConfig::clearAllChannelMappings() {
for(int i=0;i<10;i++) {
CAtmoChannelAssignment *ca = m_ChannelAssignments[i];
if(ca!=NULL)
delete ca;
m_ChannelAssignments[i] = NULL;
}
}
void CAtmoConfig::AddChannelAssignment(CAtmoChannelAssignment *ta) {
for(int i=0;i<10;i++) {
if(m_ChannelAssignments[i] == NULL) {
m_ChannelAssignments[i] = ta;
break;
}
}
}
void CAtmoConfig::SetChannelAssignment(int index, CAtmoChannelAssignment *ta) {
if(m_ChannelAssignments[index]!=NULL)
delete m_ChannelAssignments[index];
m_ChannelAssignments[index] = ta;
}
CAtmoZoneDefinition *CAtmoConfig::getZoneDefinition(int zoneIndex) {
if(zoneIndex < 0)
return NULL;
if(zoneIndex >= m_AtmoZoneDefCount)
return NULL;
return m_ZoneDefinitions[zoneIndex];
}
void CAtmoConfig::UpdateZoneCount()
{
m_computed_zones_count = m_ZonesTopCount + m_ZonesBottomCount + 2 * m_ZonesLRCount;
if(m_ZoneSummary)
m_computed_zones_count++;
}
int CAtmoConfig::getZoneCount()
{
return(m_computed_zones_count);
}
void CAtmoConfig::UpdateZoneDefinitionCount()
{
if( getZoneCount() != m_AtmoZoneDefCount)
{
// okay zonen anzahl hat sich geändert - wir müssen neu rechnen
// und allokieren!
if(m_ZoneDefinitions)
{
for(int zone=0; zone<m_AtmoZoneDefCount; zone++)
delete m_ZoneDefinitions[zone];
delete[] m_ZoneDefinitions;
m_ZoneDefinitions = NULL;
}
m_AtmoZoneDefCount = getZoneCount();
if(m_AtmoZoneDefCount > 0)
{
m_ZoneDefinitions = new CAtmoZoneDefinition*[m_AtmoZoneDefCount];
for(int zone=0; zone< m_AtmoZoneDefCount; zone++) {
m_ZoneDefinitions[zone] = new CAtmoZoneDefinition();
m_ZoneDefinitions[zone]->Fill(255);
}
}
}
}
#if defined(_ATMO_VLC_PLUGIN_)
char *CAtmoConfig::getSerialDevice(int i)
{
if(i == 0)
return m_devicename;
else {
i--;
return m_devicenames[i];
}
}
void CAtmoConfig::setSerialDevice(int i,const char *pszNewDevice)
{
if(i == 0)
setSerialDevice(pszNewDevice);
else {
i--;
free( m_devicenames[i] );
if(pszNewDevice)
m_devicenames[i] = strdup(pszNewDevice);
else
m_devicenames[i] = NULL;
}
}
#else
int CAtmoConfig::getComport(int i)
{
if(i == 0)
return this->m_Comport;
else {
i--;
return this->m_Comports[i];
}
}
void CAtmoConfig::setComport(int i, int nr)
{
if(i == 0)
this->m_Comport = nr;
else {
this->m_Comports[i-1] = nr;
}
}
#endif
void CAtmoConfig::setDMX_BaseChannels(char *channels)
{
free(m_DMX_BaseChannels);
m_DMX_BaseChannels = strdup(channels);
}
void CAtmoConfig::getChannelWhiteAdj(int channel,int &red,int &green,int &blue)
{
if(channel >= m_chWhiteAdj_Count)
{
red = 256;
green = 256;
blue = 256;
} else {
red = m_chWhiteAdj_Red[ channel ];
green = m_chWhiteAdj_Green[ channel ];
blue = m_chWhiteAdj_Blue[ channel ];
}
}
void CAtmoConfig::setChannelWhiteAdj(int channel,int red,int green,int blue)
{
if(channel >= m_chWhiteAdj_Count)
{
int *tmp = new int[channel+1];
if(m_chWhiteAdj_Red)
memcpy( tmp, m_chWhiteAdj_Red, m_chWhiteAdj_Count * sizeof(int) );
delete []m_chWhiteAdj_Red;
m_chWhiteAdj_Red = tmp;
tmp = new int[channel + 1];
if(m_chWhiteAdj_Green)
memcpy( tmp, m_chWhiteAdj_Green, m_chWhiteAdj_Count * sizeof(int) );
delete []m_chWhiteAdj_Green;
m_chWhiteAdj_Green = tmp;
tmp = new int[channel + 1];
if(m_chWhiteAdj_Blue)
memcpy( tmp, m_chWhiteAdj_Blue, m_chWhiteAdj_Count * sizeof(int) );
delete []m_chWhiteAdj_Blue;
m_chWhiteAdj_Blue = tmp;
m_chWhiteAdj_Count = channel + 1;
}
m_chWhiteAdj_Red[channel] = red;
m_chWhiteAdj_Green[channel] = green;
m_chWhiteAdj_Blue[channel] = blue;
}
/*
* AtmoConfig.h: Class for holding all configuration values of AtmoWin
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifndef _AtmoConfig_h_
#define _AtmoConfig_h_
#include <stdlib.h>
#include "AtmoDefs.h"
#include "AtmoZoneDefinition.h"
#include "AtmoChannelAssignment.h"
#if defined(_ATMO_VLC_PLUGIN_)
# include <string.h>
#endif
class CAtmoConfig {
protected:
int m_IsShowConfigDialog;
#if defined(_ATMO_VLC_PLUGIN_)
char *m_devicename;
char *m_devicenames[3]; // additional Devices ?
#else
int m_Comport;
int m_Comports[3]; // additional Comports
#endif
enum AtmoConnectionType m_eAtmoConnectionType;
enum EffectMode m_eEffectMode;
ATMO_BOOL m_IgnoreConnectionErrorOnStartup;
protected:
ATMO_BOOL m_UseSoftwareWhiteAdj;
int m_WhiteAdjustment_Red;
int m_WhiteAdjustment_Green;
int m_WhiteAdjustment_Blue;
ATMO_BOOL m_WhiteAdjPerChannel;
int m_chWhiteAdj_Count;
int *m_chWhiteAdj_Red;
int *m_chWhiteAdj_Green;
int *m_chWhiteAdj_Blue;
protected:
int m_IsSetShutdownColor;
int m_ShutdownColor_Red;
int m_ShutdownColor_Green;
int m_ShutdownColor_Blue;
protected:
/* Config Values for Color Changer */
int m_ColorChanger_iSteps;
int m_ColorChanger_iDelay;
protected:
/* Config values for the primitive Left Right Color Changer */
int m_LrColorChanger_iSteps;
int m_LrColorChanger_iDelay;
protected:
/* the static background color */
int m_StaticColor_Red;
int m_StaticColor_Green;
int m_StaticColor_Blue;
protected:
/*
one for System + 9 for userdefined channel
assignments (will it be enough?)
*/
CAtmoChannelAssignment *m_ChannelAssignments[10];
int m_CurrentChannelAssignment;
protected:
CAtmoZoneDefinition **m_ZoneDefinitions;
int m_AtmoZoneDefCount;
/*
zone layout description for generating the default Zone weightning
*/
// count of zone on the top of the screen
int m_ZonesTopCount;
// count of zone on the bottom of the screen
int m_ZonesBottomCount;
// count of zones on left and right (the same count)
int m_ZonesLRCount;
// does a summary Zone exists (Fullscreen)
int m_computed_zones_count;
ATMO_BOOL m_ZoneSummary;
public:
int getZoneCount();
protected:
/* Live View Parameters (most interesting) */
AtmoFilterMode m_LiveViewFilterMode;
int m_LiveViewFilter_PercentNew;
int m_LiveViewFilter_MeanLength;
int m_LiveViewFilter_MeanThreshold;
ATMO_BOOL m_show_statistics;
// number of rows to process each frame
int m_LiveView_RowsPerFrame;
// weighting of distance to edge
int m_LiveView_EdgeWeighting; // = 8;
// brightness correction
int m_LiveView_BrightCorrect; // = 100;
// darkness limit (pixels below this value will be ignored)
int m_LiveView_DarknessLimit; // = 5;
// Windowing size for hue histogram building
int m_LiveView_HueWinSize; // = 3;
// Windowing size for sat histogram building
int m_LiveView_SatWinSize; // = 3;
/*
special (hack) for ignorning black borders durring
playback of letterboxed material on a 16:9 output device
*/
int m_LiveView_WidescreenMode; // = 0
// border from source image which should be ignored
// the values are only used by the Win32 GDI Screen capture
int m_LiveView_HOverscanBorder;
int m_LiveView_VOverscanBorder;
int m_LiveView_DisplayNr;
/*
a special delay to get the light in sync with the video
was required because the frames will pass my VLC filter some [ms]
before they become visible on screen with this delay - screenoutput
and light timing could be "synchronized"
*/
int m_LiveView_FrameDelay;
int m_LiveView_GDI_FrameRate;
protected:
/* values of the last hardware white adjustment (only for hardware with new firmware) */
int m_Hardware_global_gamma;
int m_Hardware_global_contrast;
int m_Hardware_contrast_red;
int m_Hardware_contrast_green;
int m_Hardware_contrast_blue;
int m_Hardware_gamma_red;
int m_Hardware_gamma_green;
int m_Hardware_gamma_blue;
protected:
char *m_DMX_BaseChannels;
int m_DMX_RGB_Channels;
protected:
int m_MoMo_Channels;
protected:
int m_Fnordlicht_Amount;
protected:
AtmoGammaCorrect m_Software_gamma_mode;
int m_Software_gamma_red;
int m_Software_gamma_green;
int m_Software_gamma_blue;
int m_Software_gamma_global;
public:
volatile int m_UpdateEdgeWeightningFlag;
public:
CAtmoConfig();
virtual ~CAtmoConfig();
virtual void SaveSettings() {}
virtual void LoadSettings() {};
void LoadDefaults();
/*
function to copy the values of one configuration object to another
will be used in windows settings dialog as backup if the user
presses cancel
*/
void Assign(CAtmoConfig *pAtmoConfigSrc);
void UpdateZoneDefinitionCount();
public:
int isShowConfigDialog() { return m_IsShowConfigDialog; }
void setShowConfigDialog(int value) { m_IsShowConfigDialog = value; }
#if defined(_ATMO_VLC_PLUGIN_)
char *getSerialDevice() { return m_devicename; }
void setSerialDevice(const char *newdevice) { free(m_devicename); if(newdevice) m_devicename = strdup(newdevice); else m_devicename = NULL; }
char *getSerialDevice(int i);
void setSerialDevice(int i,const char *pszNewDevice);
#else
int getComport() { return m_Comport; }
void setComport(int value) { m_Comport = value; }
int getComport(int i);
void setComport(int i, int nr);
#endif
ATMO_BOOL getIgnoreConnectionErrorOnStartup() { return m_IgnoreConnectionErrorOnStartup; }
void setIgnoreConnectionErrorOnStartup(ATMO_BOOL ignore) { m_IgnoreConnectionErrorOnStartup = ignore; }
int getWhiteAdjustment_Red() { return m_WhiteAdjustment_Red; }
void setWhiteAdjustment_Red(int value) { m_WhiteAdjustment_Red = value; }
int getWhiteAdjustment_Green() { return m_WhiteAdjustment_Green; }
void setWhiteAdjustment_Green(int value) { m_WhiteAdjustment_Green = value; }
int getWhiteAdjustment_Blue() { return m_WhiteAdjustment_Blue; }
void setWhiteAdjustment_Blue(int value) { m_WhiteAdjustment_Blue = value; }
ATMO_BOOL isUseSoftwareWhiteAdj() { return m_UseSoftwareWhiteAdj; }
void setUseSoftwareWhiteAdj(ATMO_BOOL value) { m_UseSoftwareWhiteAdj = value; }
/* White ADJ per Channel settings */
ATMO_BOOL isWhiteAdjPerChannel() { return m_WhiteAdjPerChannel; }
void setWhiteAdjPerChannel( ATMO_BOOL value) { m_WhiteAdjPerChannel = value; }
void setChannelWhiteAdj(int channel,int red,int green,int blue);
void getChannelWhiteAdj(int channel,int &red,int &green,int &blue);
int isSetShutdownColor() { return m_IsSetShutdownColor; }
void SetSetShutdownColor(int value) { m_IsSetShutdownColor = value; }
int getShutdownColor_Red() { return m_ShutdownColor_Red; }
void setShutdownColor_Red(int value) { m_ShutdownColor_Red = value; }
int getShutdownColor_Green() { return m_ShutdownColor_Green; }
void setShutdownColor_Green(int value) { m_ShutdownColor_Green = value; }
int getShutdownColor_Blue() { return m_ShutdownColor_Blue; }
void setShutdownColor_Blue(int value) { m_ShutdownColor_Blue=value; }
int getColorChanger_iSteps() { return m_ColorChanger_iSteps; }
void setColorChanger_iSteps(int value) { m_ColorChanger_iSteps = value; }
int getColorChanger_iDelay() { return m_ColorChanger_iDelay; }
void setColorChanger_iDelay(int value) { m_ColorChanger_iDelay = value; }
int getLrColorChanger_iSteps() { return m_LrColorChanger_iSteps; }
void setLrColorChanger_iSteps(int value) { m_LrColorChanger_iSteps = value; }
int getLrColorChanger_iDelay() { return m_LrColorChanger_iDelay; }
void setLrColorChanger_iDelay(int value) { m_LrColorChanger_iDelay = value; }
int getStaticColor_Red() { return m_StaticColor_Red; }
void setStaticColor_Red(int value) { m_StaticColor_Red=value; }
int getStaticColor_Green() { return m_StaticColor_Green; }
void setStaticColor_Green(int value) { m_StaticColor_Green=value; }
int getStaticColor_Blue() { return m_StaticColor_Blue; }
void setStaticColor_Blue(int value) { m_StaticColor_Blue=value; }
AtmoConnectionType getConnectionType() { return m_eAtmoConnectionType; }
void setConnectionType(AtmoConnectionType value) { m_eAtmoConnectionType = value; }
EffectMode getEffectMode() { return m_eEffectMode; }
void setEffectMode(EffectMode value) { m_eEffectMode = value; }
ATMO_BOOL getShow_statistics() { return m_show_statistics; }
AtmoFilterMode getLiveViewFilterMode() { return m_LiveViewFilterMode; }
void setLiveViewFilterMode(AtmoFilterMode value) { m_LiveViewFilterMode = value; }
int getLiveViewFilter_PercentNew() { return m_LiveViewFilter_PercentNew; }
void setLiveViewFilter_PercentNew(int value) { m_LiveViewFilter_PercentNew=value; }
int getLiveViewFilter_MeanLength() { return m_LiveViewFilter_MeanLength; }
void setLiveViewFilter_MeanLength(int value) { m_LiveViewFilter_MeanLength = value; }
int getLiveViewFilter_MeanThreshold() { return m_LiveViewFilter_MeanThreshold; }
void setLiveViewFilter_MeanThreshold(int value) { m_LiveViewFilter_MeanThreshold = value; }
int getLiveView_EdgeWeighting() { return m_LiveView_EdgeWeighting; }
void setLiveView_EdgeWeighting(int value) { m_LiveView_EdgeWeighting=value; }
int getLiveView_RowsPerFrame() { return m_LiveView_RowsPerFrame; }
void setLiveView_RowsPerFrame(int value) { m_LiveView_RowsPerFrame=value; }
int getLiveView_BrightCorrect() { return m_LiveView_BrightCorrect; }
void setLiveView_BrightCorrect(int value) { m_LiveView_BrightCorrect=value; }
int getLiveView_DarknessLimit() { return m_LiveView_DarknessLimit; }
void setLiveView_DarknessLimit(int value) { m_LiveView_DarknessLimit=value; }
int getLiveView_HueWinSize() { return m_LiveView_HueWinSize; }
void setLiveView_HueWinSize(int value) { m_LiveView_HueWinSize=value; }
int getLiveView_SatWinSize() { return m_LiveView_SatWinSize; }
void setLiveView_SatWinSize(int value) { m_LiveView_SatWinSize=value; }
int getLiveView_WidescreenMode() { return m_LiveView_WidescreenMode; }
void setLiveView_WidescreenMode(int value) { m_LiveView_WidescreenMode=value; }
int getLiveView_HOverscanBorder() { return m_LiveView_HOverscanBorder; }
void setLiveView_HOverscanBorder(int value) { m_LiveView_HOverscanBorder = value; }
int getLiveView_VOverscanBorder() { return m_LiveView_VOverscanBorder; }
void setLiveView_VOverscanBorder(int value) { m_LiveView_VOverscanBorder = value; }
int getLiveView_DisplayNr() { return m_LiveView_DisplayNr; }
void setLiveView_DisplayNr(int value) { m_LiveView_DisplayNr = value; }
int getLiveView_FrameDelay() { return m_LiveView_FrameDelay; }
void setLiveView_FrameDelay(int delay) { m_LiveView_FrameDelay = delay; }
int getLiveView_GDI_FrameRate() { return m_LiveView_GDI_FrameRate; }
void setLiveView_GDI_FrameRate(int value) { m_LiveView_GDI_FrameRate=value; }
int getHardware_global_gamma() { return m_Hardware_global_gamma ; }
void setHardware_global_gamma(int value) { m_Hardware_global_gamma=value; }
int getHardware_global_contrast() { return m_Hardware_global_contrast; }
void setHardware_global_contrast(int value) { m_Hardware_global_contrast=value; }
int getHardware_contrast_red() { return m_Hardware_contrast_red; }
void setHardware_contrast_red(int value) { m_Hardware_contrast_red=value; }
int getHardware_contrast_green() { return m_Hardware_contrast_green; }
void setHardware_contrast_green(int value) { m_Hardware_contrast_green=value; }
int getHardware_contrast_blue() { return m_Hardware_contrast_blue; }
void setHardware_contrast_blue(int value) { m_Hardware_contrast_blue=value; }
int getHardware_gamma_red() { return m_Hardware_gamma_red; }
void setHardware_gamma_red(int value) { m_Hardware_gamma_red=value; }
int getHardware_gamma_green() { return m_Hardware_gamma_green; }
void setHardware_gamma_green(int value) { m_Hardware_gamma_green=value; }
int getHardware_gamma_blue() { return m_Hardware_gamma_blue; }
void setHardware_gamma_blue(int value) { m_Hardware_gamma_blue=value; }
AtmoGammaCorrect getSoftware_gamma_mode() { return m_Software_gamma_mode; }
int getSoftware_gamma_red() { return m_Software_gamma_red; }
int getSoftware_gamma_green() { return m_Software_gamma_green; }
int getSoftware_gamma_blue() { return m_Software_gamma_blue; }
int getSoftware_gamma_global() { return m_Software_gamma_global; }
void setSoftware_gamma_mode(AtmoGammaCorrect value) { m_Software_gamma_mode = value; }
void setSoftware_gamma_red(int value) { m_Software_gamma_red = value; }
void setSoftware_gamma_green(int value) { m_Software_gamma_green = value; }
void setSoftware_gamma_blue(int value) { m_Software_gamma_blue = value; }
void setSoftware_gamma_global(int value) { m_Software_gamma_global = value; }
CAtmoChannelAssignment *getChannelAssignment(int nummer) {
return this->m_ChannelAssignments[nummer];
}
int getCurrentChannelAssignment() { return m_CurrentChannelAssignment; }
void setCurrentChannelAssignment(int index) { m_CurrentChannelAssignment = index; }
int getNumChannelAssignments();
void clearChannelMappings();
void clearAllChannelMappings();
void AddChannelAssignment(CAtmoChannelAssignment *ta);
void SetChannelAssignment(int index, CAtmoChannelAssignment *ta);
CAtmoZoneDefinition *getZoneDefinition(int zoneIndex);
void UpdateZoneCount();
void setZonesTopCount(int zones) { m_ZonesTopCount = zones; UpdateZoneCount(); };
int getZonesTopCount() { return m_ZonesTopCount; }
void setZonesBottomCount(int zones) { m_ZonesBottomCount = zones; UpdateZoneCount(); };
int getZonesBottomCount() { return m_ZonesBottomCount; }
void setZonesLRCount(int zones) { m_ZonesLRCount = zones; UpdateZoneCount(); };
int getZonesLRCount() { return m_ZonesLRCount; }
ATMO_BOOL getZoneSummary() { return m_ZoneSummary; }
void setZoneSummary(ATMO_BOOL summary) { m_ZoneSummary = summary; UpdateZoneCount(); }
char *getDMX_BaseChannels() { return m_DMX_BaseChannels; }
void setDMX_BaseChannels(char *channels);
int getDMX_RGB_Channels() { return m_DMX_RGB_Channels; }
void setDMX_RGB_Channels(int ch) { m_DMX_RGB_Channels = ch; }
int getMoMo_Channels() { return m_MoMo_Channels; }
void setMoMo_Channels(int chCount) { m_MoMo_Channels = chCount; }
int getFnordlicht_Amount() { return m_Fnordlicht_Amount; }
void setFnordlicht_Amount(int fnordlichtAmount) { m_Fnordlicht_Amount = fnordlichtAmount; }
};
#endif
/*
* AtmoConnection.cpp: generic/abstract class defining all methods for the
* communication with the hardware
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <string.h>
#include "AtmoConnection.h"
CAtmoConnection::CAtmoConnection(CAtmoConfig *cfg)
{
this->m_pAtmoConfig = cfg;
m_ChannelAssignment = NULL;
m_NumAssignedChannels = 0;
#if defined(_ATMO_VLC_PLUGIN_)
vlc_mutex_init( &m_AccessConnection );
#else
InitializeCriticalSection( &m_AccessConnection );
#endif
}
CAtmoConnection::~CAtmoConnection(void)
{
if(isOpen())
CloseConnection();
#if defined(_ATMO_VLC_PLUGIN_)
vlc_mutex_destroy( &m_AccessConnection );
#else
DeleteCriticalSection( &m_AccessConnection );
#endif
}
void CAtmoConnection::SetChannelAssignment(CAtmoChannelAssignment *ca)
{
if(ca)
{
Lock();
delete m_ChannelAssignment;
m_ChannelAssignment = ca->getMapArrayClone(m_NumAssignedChannels);
Unlock();
}
}
#if !defined(_ATMO_VLC_PLUGIN_)
ATMO_BOOL CAtmoConnection::ShowConfigDialog(HINSTANCE hInst, HWND parent, CAtmoConfig *cfg)
{
MessageBox(parent, "This device doesn't have a special config dialog", "Info", 0);
return ATMO_FALSE;
}
#endif
void CAtmoConnection::Lock()
{
#if defined(_ATMO_VLC_PLUGIN_)
vlc_mutex_lock( &m_AccessConnection );
#else
EnterCriticalSection( &m_AccessConnection );
#endif
}
void CAtmoConnection::Unlock()
{
#if defined(_ATMO_VLC_PLUGIN_)
vlc_mutex_unlock( &m_AccessConnection );
#else
LeaveCriticalSection( &m_AccessConnection );
#endif
}
/*
* AtmoConnection.h: generic/abstract class defining all methods for the
* communication with the hardware
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifndef _AtmoConnection_h_
#define _AtmoConnection_h_
#include <stdlib.h>
#include "AtmoDefs.h"
#include "AtmoConfig.h"
#include "AtmoChannelAssignment.h"
#if defined(_ATMO_VLC_PLUGIN_)
# include <vlc_common.h>
# include <vlc_threads.h>
#else
# include <windows.h>
#endif
class CAtmoConnection
{
protected:
CAtmoConfig *m_pAtmoConfig;
#if defined(_ATMO_VLC_PLUGIN_)
vlc_mutex_t m_AccessConnection;
#else
CRITICAL_SECTION m_AccessConnection;
#endif
int *m_ChannelAssignment;
int m_NumAssignedChannels;
protected:
void Lock();
void Unlock();
public:
CAtmoConnection(CAtmoConfig *cfg);
virtual ~CAtmoConnection(void);
virtual ATMO_BOOL OpenConnection() = 0;
virtual void CloseConnection() {};
virtual ATMO_BOOL isOpen(void) { return false; }
virtual ATMO_BOOL SendData(pColorPacket data) = 0;
virtual ATMO_BOOL setChannelColor(int /*channel*/, tRGBColor /*color*/)
{ return false; }
virtual ATMO_BOOL setChannelValues(int /*num*/,unsigned char * /*values*/)
{ return false; }
virtual ATMO_BOOL HardwareWhiteAdjust(int /*global_gamma*/,
int /*global_contrast*/,
int /*contrast_red*/,
int /*contrast_green*/,
int /*contrast_blue*/,
int /*gamma_red*/,
int /*gamma_green*/,
int /*gamma_blue*/,
ATMO_BOOL /*storeToEeprom*/)
{ return false; }
#if !defined(_ATMO_VLC_PLUGIN_)
virtual ATMO_BOOL ShowConfigDialog(HINSTANCE hInst, HWND parent, CAtmoConfig *cfg);
#endif
virtual void SetChannelAssignment(CAtmoChannelAssignment *ca);
virtual int getNumChannels() { return 0; }
virtual char *getChannelName(int /*ch*/) { return NULL; }
virtual const char *getDevicePath() { return "none"; }
virtual ATMO_BOOL CreateDefaultMapping(CAtmoChannelAssignment * /*ca*/)
{ return false; }
};
#endif
/*
* AtmoDefs.h: a lot of globals defines for the color computation - most of this file
* is an one to one copy of "defs.h" from Atmo VDR Plugin
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifndef _AtmoDefs_h_
#define _AtmoDefs_h_
#if defined(__LIBVLC__)
# include <vlc_common.h>
# include <vlc_codecs.h>
/* some things need to be changed if this code is used inside VideoLan Filter Module */
# define _ATMO_VLC_PLUGIN_
# define get_time mdate()
# define do_sleep(a) msleep(a)
#else
# define MakeDword(ch1,ch2,ch3,ch4) ((((DWORD)(ch1)&255) << 24) | \
(((DWORD)(ch2)&255) << 16) | \
(((DWORD)(ch3)&255) << 8) | \
(((DWORD)(ch4)&255)))
# define get_time GetTickCount()
# define do_sleep(a) Sleep(a)
#endif
#define ATMO_BOOL bool
#define ATMO_TRUE true
#define ATMO_FALSE false
/*
can't use the VLC_TWOCC macro because the byte order there is CPU dependent
but for the use in Atmo I need for this single purpose Intel Byte Order
every time!
*/
#define MakeIntelWord(ch1,ch2) ((((int)(ch1)&255)<<8) | \
((int)(ch2)&255))
// my own min max macros
#define ATMO_MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#define ATMO_MAX(X, Y) ((X) > (Y) ? (X) : (Y))
#if !defined(_WIN32)
#define INVALID_HANDLE_VALUE -1
typedef int HANDLE;
typedef unsigned long DWORD;
#define BI_RGB 0L
#if !defined(_BITMAPFILEHEADER_)
#define _BITMAPFILEHEADER_
typedef struct
#ifdef HAVE_ATTRIBUTE_PACKED
__attribute__((__packed__))
#endif
{
uint16_t bfType;
uint32_t bfSize;
uint16_t bfReserved1;
uint16_t bfReserved2;
uint32_t bfOffBits;
} BITMAPFILEHEADER, *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
#endif
#endif
// maximal Anzahl Kanäle... original 5!
#define CAP_MAX_NUM_ZONES 64
// only for classic to avoid changing too much code!
// #define ATMO_MAX_NUM_CHANNELS 5
// capture width/height
// #define CAP_WIDTH 88
#ifdef CAP_16x9
# define CAP_WIDTH 88
# define CAP_HEIGHT 48
#else
# define CAP_WIDTH 64
# define CAP_HEIGHT 48
#endif
// imagesize
#define IMAGE_SIZE (CAP_WIDTH * CAP_HEIGHT)
/*
number of pixel the atmo zones should overlap - based on CAP_WIDTH and CAP_HEIGHT
*/
#define CAP_ZONE_OVERLAP 2
enum AtmoConnectionType
{
actClassicAtmo = 0,
actDummy = 1,
actDMX = 2,
actNUL = 3,
actMultiAtmo = 4,
actMondolight = 5,
actMoMoLight = 6,
actFnordlicht = 7
};
static const char AtmoDeviceTypes[8][16] = {
"Atmo-Classic",
"Dummy",
"DMX",
"Nul-Device",
"Multi-Atmo",
"Mondolight",
"MoMoLight",
"Fnordlicht"
};
#define ATMO_DEVICE_COUNT 8
#if defined(_ATMO_VLC_PLUGIN_)
enum EffectMode {
emUndefined = -1,
emDisabled = 0,
emStaticColor = 1,
emLivePicture = 2
};
enum LivePictureSource {
lpsDisabled = 0,
lpsExtern = 2
};
#else
enum EffectMode {
emUndefined = -1,
emDisabled = 0,
emStaticColor = 1,
emLivePicture = 2,
emColorChange = 3,
emLrColorChange = 4
};
enum LivePictureSource {
lpsDisabled = 0,
lpsScreenCapture = 1,
lpsExtern = 2
};
#endif
enum AtmoGammaCorrect {
agcNone = 0,
agcPerColor = 1,
agcGlobal = 2
};
enum AtmoFilterMode {
afmNoFilter,
afmCombined,
afmPercent
};
// --- tRGBColor --------------------------------------------------------------
typedef struct
{
unsigned char r, g, b;
} tRGBColor;
// --- tColorPacket -----------------------------------------------------------
typedef struct
{
int numColors;
tRGBColor zone[1];
} xColorPacket;
typedef xColorPacket* pColorPacket;
#define AllocColorPacket(packet, numColors_) packet = (pColorPacket)new char[sizeof(xColorPacket) + (numColors_)*sizeof(tRGBColor)]; \
packet->numColors = numColors_;
#define DupColorPacket(dest, source) dest = NULL; \
if(source) { \
dest = (pColorPacket)new char[sizeof(xColorPacket) + (source->numColors)*sizeof(tRGBColor)]; \
memcpy(dest, source, sizeof(xColorPacket) + (source->numColors)*sizeof(tRGBColor)); \
}
#define CopyColorPacket( source, dest) memcpy(dest, source, sizeof(xColorPacket) + (source->numColors)*sizeof(tRGBColor) );
#define ZeroColorPacket( packet ) memset( &((packet)->zone[0]), 0, (packet->numColors)*sizeof(tRGBColor));
// --- tRGBColorLongInt -------------------------------------------------------
typedef struct
{
long int r, g, b;
} tRGBColorLongInt;
// --- tColorPacketLongInt ----------------------------------------------------
typedef struct
{
int numColors;
tRGBColorLongInt longZone[1];
} xColorPacketLongInt;
typedef xColorPacketLongInt* pColorPacketLongInt;
#define AllocLongColorPacket(packet, numColors_) packet = (pColorPacketLongInt)new char[sizeof(xColorPacketLongInt) + (numColors_)*sizeof(tRGBColorLongInt)]; \
packet->numColors = numColors_;
#define DupLongColorPacket(dest, source) dest = NULL; \
if(source) { \
dest = (pColorPacketLongInt)new char[sizeof(xColorPacketLongInt) + (source->numColors)*sizeof(tRGBColorLongInt)]; \
memcpy(dest, source, sizeof(xColorPacketLongInt) + (source->numColors)*sizeof(tRGBColorLongInt)); \
}
#define ZeroLongColorPacket( packet ) memset( &((packet)->longZone[0]), 0, (packet->numColors)*sizeof(tRGBColorLongInt));
// --- tWeightPacket ----------------------------------------------------------
/*
typedef struct
{
int channel[CAP_MAX_NUM_ZONES];
} tWeightPacket;
*/
// --- tHSVColor --------------------------------------------------------------
typedef struct
{
unsigned char h, s, v;
} tHSVColor;
#endif
/*
* AtmoDmxSerialConnection.cpp: Class for communication with a Simple DMX Dongle/Controller
* for hardware see also:
* http://www.dzionsko.de/elektronic/index.htm
* http://www.ulrichradig.de/ (search for dmx on his page)
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "AtmoDefs.h"
#include "AtmoDmxSerialConnection.h"
#include "DmxTools.h"
#if !defined(_ATMO_VLC_PLUGIN_)
#include "DmxConfigDialog.h"
#endif
#include <stdio.h>
#include <fcntl.h>
#if !defined(_WIN32)
#include <termios.h>
#include <unistd.h>
#endif
CAtmoDmxSerialConnection::CAtmoDmxSerialConnection(CAtmoConfig *cfg) : CAtmoConnection(cfg) {
m_hComport = INVALID_HANDLE_VALUE;
memset(&DMXout, 0, sizeof(DMXout));
DMXout[0] = 0x5A; // DMX Command Start Byte
DMXout[1] = 0xA1; // DMX Controlcommand for 256 channels
DMXout[258] = 0xA5; // end of block
m_dmx_channels_base = ConvertDmxStartChannelsToInt( cfg->getDMX_RGB_Channels(), cfg->getDMX_BaseChannels());
}
CAtmoDmxSerialConnection::~CAtmoDmxSerialConnection() {
delete m_dmx_channels_base;
}
ATMO_BOOL CAtmoDmxSerialConnection::OpenConnection() {
#if defined(_ATMO_VLC_PLUGIN_)
char *serdevice = m_pAtmoConfig->getSerialDevice();
if(!serdevice)
return ATMO_FALSE;
#else
int portNummer = m_pAtmoConfig->getComport();
m_dwLastWin32Error = 0;
if(portNummer < 1) return ATMO_FALSE; // make no real sense;-)
#endif
if(!m_dmx_channels_base)
return ATMO_FALSE;
CloseConnection();
#if !defined(_ATMO_VLC_PLUGIN_)
char serdevice[16]; // com4294967295
sprintf(serdevice,"com%d",portNummer);
#endif
#if defined(_WIN32)
m_hComport = CreateFileA(serdevice, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if(m_hComport == INVALID_HANDLE_VALUE) {
// we have a problem here can't open com port... somebody else may use it?
// m_dwLastWin32Error = GetLastError();
return ATMO_FALSE;
}
/* change serial settings (Speed, stopbits etc.) */
DCB dcb; // für comport-parameter
dcb.DCBlength = sizeof(DCB);
GetCommState (m_hComport, &dcb); // ger current serialport settings
dcb.BaudRate = 115200; // set speed
dcb.ByteSize = 8; // set databits
dcb.Parity = NOPARITY; // set parity
dcb.StopBits = ONESTOPBIT; // set one stop bit
SetCommState (m_hComport, &dcb); // apply settings
#else
int bconst = B115200;
m_hComport = open(serdevice, O_RDWR |O_NOCTTY);
if(m_hComport < 0) {
return ATMO_FALSE;
}
struct termios tio;
memset(&tio,0,sizeof(tio));
tio.c_cflag = (CS8 | CREAD | HUPCL | CLOCAL);
tio.c_iflag = (INPCK | BRKINT);
cfsetispeed(&tio, bconst);
cfsetospeed(&tio, bconst);
if(!tcsetattr(m_hComport, TCSANOW, &tio)) {
tcflush(m_hComport, TCIOFLUSH);
} else {
// can't change parms
close(m_hComport);
m_hComport = -1;
return false;
}
#endif
return true;
}
void CAtmoDmxSerialConnection::CloseConnection() {
if(m_hComport!=INVALID_HANDLE_VALUE) {
#if defined(_WIN32)
CloseHandle(m_hComport);
#else
close(m_hComport);
#endif
m_hComport = INVALID_HANDLE_VALUE;
}
}
ATMO_BOOL CAtmoDmxSerialConnection::isOpen(void) {
return (m_hComport != INVALID_HANDLE_VALUE);
}
ATMO_BOOL CAtmoDmxSerialConnection::SendData(pColorPacket data) {
if(m_hComport == INVALID_HANDLE_VALUE)
return ATMO_FALSE;
int iBuffer = 2;
DWORD iBytesWritten;
Lock();
int idx, z = 0;
for(int i=0;i<getNumChannels();i++) {
if(m_ChannelAssignment && (i < m_NumAssignedChannels))
idx = m_ChannelAssignment[i];
else
idx = -1;
if((idx>=0) && (idx<data->numColors)) {
if( m_dmx_channels_base[z] >= 0 )
iBuffer = m_dmx_channels_base[z] + 2;
else
iBuffer += 3;
DMXout[iBuffer] = data->zone[ idx ].r;
DMXout[iBuffer+1] = data->zone[ idx ].g;
DMXout[iBuffer+2] = data->zone[ idx ].b;
}
if( m_dmx_channels_base[z] >= 0 )
z++;
}
#if defined(_WIN32)
WriteFile(m_hComport, DMXout, 259, &iBytesWritten, NULL); // send to COM-Port
#else
iBytesWritten = write(m_hComport, DMXout, 259);
tcdrain(m_hComport);
#endif
Unlock();
return (iBytesWritten == 259) ? ATMO_TRUE : ATMO_FALSE;
}
ATMO_BOOL CAtmoDmxSerialConnection::setChannelValues(int numValues,unsigned char *channel_values)
{
DWORD iBytesWritten;
if((numValues & 1) || !channel_values)
return ATMO_FALSE; // numValues must be even!
/*
the array shall contain
*/
Lock();
int dmxIndex = 0;
for (int i = 0; i < numValues; i+=2) {
dmxIndex = ((int)channel_values[i]) + 2;
DMXout[dmxIndex] = channel_values[i+1];
}
#if defined(_WIN32)
WriteFile(m_hComport, DMXout, 259, &iBytesWritten, NULL);
#else
iBytesWritten = write(m_hComport, DMXout, 259);
tcdrain(m_hComport);
#endif
Unlock();
return (iBytesWritten == 259) ? ATMO_TRUE : ATMO_FALSE;
}
ATMO_BOOL CAtmoDmxSerialConnection::setChannelColor(int channel, tRGBColor color)
{
DWORD iBytesWritten;
Lock();
DMXout[channel+0+2]=color.r;
DMXout[channel+1+2]=color.g;
DMXout[channel+2+2]=color.b;
#if defined(_WIN32)
WriteFile(m_hComport, DMXout, 259, &iBytesWritten, NULL);
#else
iBytesWritten = write(m_hComport, DMXout, 259);
tcdrain(m_hComport);
#endif
Unlock();
return (iBytesWritten == 259) ? ATMO_TRUE : ATMO_FALSE;
}
ATMO_BOOL CAtmoDmxSerialConnection::CreateDefaultMapping(CAtmoChannelAssignment *ca)
{
if(!ca) return ATMO_FALSE;
ca->setSize( getNumChannels() );
for(int i = 0; i < getNumChannels(); i++)
ca->setZoneIndex(i , i);
return ATMO_TRUE;
}
#if !defined(_ATMO_VLC_PLUGIN_)
char *CAtmoDmxSerialConnection::getChannelName(int ch)
{
if(ch < 0) return NULL;
char buf[30];
switch(ch) {
case 0:
sprintf(buf,"Summenkanal [%d]",ch);
break;
case 1:
sprintf(buf,"Linker Kanal [%d]",ch);
break;
case 2:
sprintf(buf,"Rechter Kanal [%d]",ch);
break;
case 3:
sprintf(buf,"Oberer Kanal [%d]",ch);
break;
case 4:
sprintf(buf,"Unterer Kanal [%d]",ch);
break;
default:
sprintf(buf,"Kanal [%d]",ch);
break;
}
return strdup(buf);
}
ATMO_BOOL CAtmoDmxSerialConnection::ShowConfigDialog(HINSTANCE hInst, HWND parent, CAtmoConfig *cfg)
{
CDmxConfigDialog *dlg = new CDmxConfigDialog(hInst, parent, cfg);
INT_PTR result = dlg->ShowModal();
delete dlg;
if(result == IDOK)
return ATMO_TRUE;
else
return ATMO_FALSE;
}
#endif
int CAtmoDmxSerialConnection::getNumChannels()
{
return m_pAtmoConfig->getDMX_RGB_Channels();
}
/*
* AtmoDmxSerialConnection.h: Class for communication with the serial DMX Interface of dzionsko,
* opens and configures the serial port
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifndef _AtmoDmxSerialConnection_h_
#define _AtmoDmxSerialConnection_h_
#include "AtmoDefs.h"
#include "AtmoConnection.h"
#include "AtmoConfig.h"
#if defined(_WIN32)
# include <windows.h>
#endif
class CAtmoDmxSerialConnection : public CAtmoConnection {
private:
HANDLE m_hComport;
// DMX Channel Buffer including some Control Bytes for up to 256 DMX Channels
unsigned char DMXout[259];
// contains the DMX Start Adress of each Atmo-Dmx-Channel
int *m_dmx_channels_base;
#if defined(_WIN32)
DWORD m_dwLastWin32Error;
public:
DWORD getLastError() { return m_dwLastWin32Error; }
#endif
public:
CAtmoDmxSerialConnection(CAtmoConfig *cfg);
virtual ~CAtmoDmxSerialConnection(void);
virtual ATMO_BOOL OpenConnection();
virtual void CloseConnection();
virtual ATMO_BOOL isOpen(void);
virtual ATMO_BOOL SendData(pColorPacket data);
virtual ATMO_BOOL setChannelColor(int channel, tRGBColor color);
virtual ATMO_BOOL setChannelValues(int numValues,unsigned char *channel_values);
virtual int getNumChannels();
#if !defined(_ATMO_VLC_PLUGIN_)
virtual char *getChannelName(int ch);
virtual ATMO_BOOL ShowConfigDialog(HINSTANCE hInst, HWND parent, CAtmoConfig *cfg);
#endif
virtual const char *getDevicePath() { return "dmx"; }
virtual ATMO_BOOL CreateDefaultMapping(CAtmoChannelAssignment *ca);
};
#endif
/*
* AtmoDynData.cpp: class for holding all variable data - which may be
* passed between function calls, into threads instead of the use
* of global variables
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "AtmoDynData.h"
#if defined(_ATMO_VLC_PLUGIN_)
CAtmoDynData::CAtmoDynData(vlc_object_t *p_atmo_filter, CAtmoConfig *pAtmoConfig) {
this->p_atmo_filter = p_atmo_filter;
this->m_pAtmoConfig = pAtmoConfig;
this->m_pAtmoConnection = NULL;
this->m_pCurrentEffectThread = NULL;
this->m_pLivePacketQueue = NULL;
this->m_pLiveInput = NULL;
this->m_LivePictureSource = lpsExtern;
vlc_mutex_init( &m_lock );
}
#else
CAtmoDynData::CAtmoDynData(HINSTANCE hInst, CAtmoConfig *pAtmoConfig, CAtmoDisplays *pAtmoDisplays) {
this->m_pAtmoConfig = pAtmoConfig;
this->m_pAtmoDisplays = pAtmoDisplays;
this->m_pAtmoConnection = NULL;
this->m_pCurrentEffectThread = NULL;
this->m_hInst = hInst;
this->m_pLivePacketQueue = NULL;
this->m_pLiveInput = NULL;
this->m_LivePictureSource = lpsScreenCapture;
InitializeCriticalSection( &m_RemoteCallCriticalSection );
}
#endif
CAtmoDynData::~CAtmoDynData(void)
{
#if defined(_ATMO_VLC_PLUGIN_)
vlc_mutex_destroy( &m_lock );
#else
DeleteCriticalSection(&m_RemoteCallCriticalSection);
#endif
}
void CAtmoDynData::LockCriticalSection() {
#if defined(_ATMO_VLC_PLUGIN_)
vlc_mutex_lock( &m_lock );
#else
EnterCriticalSection(&m_RemoteCallCriticalSection);
#endif
}
void CAtmoDynData::UnLockCriticalSection() {
#if defined(_ATMO_VLC_PLUGIN_)
vlc_mutex_unlock( &m_lock );
#else
LeaveCriticalSection(&m_RemoteCallCriticalSection);
#endif
}
void CAtmoDynData::CalculateDefaultZones()
{
int i;
int num_cols_top;
int num_cols_bottom;
int num_rows;
CAtmoZoneDefinition *zoneDef;
if(!m_pAtmoConfig)
return;
m_pAtmoConfig->UpdateZoneDefinitionCount();
num_cols_top = m_pAtmoConfig->getZonesTopCount();
num_cols_bottom = m_pAtmoConfig->getZonesBottomCount();
num_rows = m_pAtmoConfig->getZonesLRCount();
for(int zone=0; zone < m_pAtmoConfig->getZoneCount(); zone++)
{
zoneDef = m_pAtmoConfig->getZoneDefinition(zone);
if(zoneDef)
zoneDef->Fill(0);
}
// the zones will be counted starting from top left - in clockwise order around the display
// the summary channel will be the last one (in the center)
i = 0;
// top zones from left to right
for(int c=0;c<num_cols_top;c++)
{
zoneDef = m_pAtmoConfig->getZoneDefinition(i); i++;
if(zoneDef) {
int l = (c * CAP_WIDTH)/num_cols_top;
int r = ((c+1) * CAP_WIDTH)/num_cols_top;
zoneDef->FillGradientFromTop( ATMO_MAX( l - CAP_ZONE_OVERLAP, 0) , ATMO_MIN( r + CAP_ZONE_OVERLAP, CAP_WIDTH ) );
}
}
// right zones from top to bottom
for(int r=0;r<num_rows;r++)
{
zoneDef = m_pAtmoConfig->getZoneDefinition(i); i++;
if(zoneDef) {
int t = (r * CAP_HEIGHT)/num_rows;
int b = ((r+1) * CAP_HEIGHT)/num_rows;
zoneDef->FillGradientFromRight( ATMO_MAX( t - CAP_ZONE_OVERLAP, 0) , ATMO_MIN( b + CAP_ZONE_OVERLAP, CAP_HEIGHT) );
}
}
// bottom zones from RIGHT to LEFT!
for(int c=(num_cols_bottom-1);c>=0;c--)
{
zoneDef = m_pAtmoConfig->getZoneDefinition(i); i++;
if(zoneDef) {
int l = (c * CAP_WIDTH)/num_cols_bottom;
int r = ((c+1) * CAP_WIDTH)/num_cols_bottom;
zoneDef->FillGradientFromBottom( ATMO_MAX( l - CAP_ZONE_OVERLAP, 0 ), ATMO_MIN( r + CAP_ZONE_OVERLAP, CAP_WIDTH ) );
}
}
// left zones from bottom to top!
for(int r=(num_rows-1);r>=0;r--)
{
zoneDef = m_pAtmoConfig->getZoneDefinition(i); i++;
if(zoneDef)
{
int t = (r * CAP_HEIGHT)/num_rows;
int b = ((r+1) * CAP_HEIGHT)/num_rows;
zoneDef->FillGradientFromLeft( ATMO_MAX( t - CAP_ZONE_OVERLAP, 0 ), ATMO_MIN( b + CAP_ZONE_OVERLAP, CAP_HEIGHT ) );
}
}
if(m_pAtmoConfig->getZoneSummary())
{
// and last the summary zone if requested!
zoneDef = m_pAtmoConfig->getZoneDefinition(i++);
if(zoneDef)
zoneDef->Fill(255);
}
}
#if defined(_ATMO_VLC_PLUGIN_)
void CAtmoDynData::ReloadZoneDefinitionBitmaps()
{
// only as dummy for VLC Module - to avoid to if def out all calls to this function
}
#endif
#if !defined(_ATMO_VLC_PLUGIN_)
void CAtmoDynData::setWorkDir(const char *dir)
{
strcpy( m_WorkDir, dir );
}
char *CAtmoDynData::getWorkDir()
{
return m_WorkDir;
}
void CAtmoDynData::ReloadZoneDefinitionBitmaps()
{
int i;
// suchlogik für die Bitmaps ...
// <WorkDir>\hardware\numchannels\zone..0..n.bmp
// <WorkDir>\hardware\zone..0..n.bmp
// <WorkDir>\zone..0..n.bmp
// Automatik Berechnung...
LockCriticalSection();
if(!m_pAtmoConnection || !m_pAtmoConfig) {
UnLockCriticalSection();
return;
}
m_pAtmoConfig->UpdateZoneDefinitionCount();
CalculateDefaultZones();
char psz_filename[MAX_PATH];
CAtmoZoneDefinition *zoneDef;
sprintf(psz_filename,"%s%s",
m_WorkDir,
m_pAtmoConnection->getDevicePath()
);
CreateDirectory( psz_filename, NULL );
sprintf(psz_filename,"%s%s\\%dx%dx%d",
m_WorkDir,
m_pAtmoConnection->getDevicePath(),
m_pAtmoConfig->getZonesTopCount(),
m_pAtmoConfig->getZonesLRCount(),
m_pAtmoConfig->getZonesBottomCount()
);
CreateDirectory(psz_filename, NULL );
// try to load device depended zone definition bitmaps
for(int zone=0; zone < m_pAtmoConfig->getZoneCount(); zone++) {
zoneDef = m_pAtmoConfig->getZoneDefinition(zone);
if(!zoneDef) continue;
sprintf(psz_filename,"%s%s\\%dx%dx%d\\zone_%d.bmp",
m_WorkDir,
m_pAtmoConnection->getDevicePath(),
m_pAtmoConfig->getZonesTopCount(),
m_pAtmoConfig->getZonesLRCount(),
m_pAtmoConfig->getZonesBottomCount(),
zone
);
i = zoneDef->LoadGradientFromBitmap( psz_filename );
if(i == ATMO_LOAD_GRADIENT_OK) continue;
if((i == ATMO_LOAD_GRADIENT_FAILED_SIZE) || (i == ATMO_LOAD_GRADIENT_FAILED_HEADER))
MessageBox(0,psz_filename,"Failed to load, Check Format, Check Size.",MB_ICONERROR);
sprintf(psz_filename,"%s%s\\zone_%d.bmp",
m_WorkDir,
m_pAtmoConnection->getDevicePath(),
zone
);
i = zoneDef->LoadGradientFromBitmap( psz_filename );
if(i == ATMO_LOAD_GRADIENT_OK) continue;
if((i == ATMO_LOAD_GRADIENT_FAILED_SIZE) || (i == ATMO_LOAD_GRADIENT_FAILED_HEADER))
MessageBox(0,psz_filename,"Failed to load, Check Format, Check Size.",MB_ICONERROR);
sprintf(psz_filename,"%szone_%d.bmp",
m_WorkDir,
zone
);
i = zoneDef->LoadGradientFromBitmap( psz_filename );
if(i == ATMO_LOAD_GRADIENT_OK) continue;
if((i == ATMO_LOAD_GRADIENT_FAILED_SIZE) || (i == ATMO_LOAD_GRADIENT_FAILED_HEADER))
MessageBox(0,psz_filename,"Failed to load, Check Format, Check Size.",MB_ICONERROR);
}
UnLockCriticalSection();
}
#endif
/*
* AtmoDynData.h: class for holding all variable data - which may be passed
* between function calls, into threads instead of the use of global variables
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifndef _AtmoDynData_h_
#define _AtmoDynData_h_
#include <stdio.h>
#include "AtmoDefs.h"
#include "AtmoThread.h"
#include "AtmoConfig.h"
#include "AtmoConnection.h"
#include "AtmoPacketQueue.h"
#include "AtmoInput.h"
#if !defined(_ATMO_VLC_PLUGIN_)
# include "AtmoDisplays.h"
#else
# include <vlc_common.h>
# include <vlc_threads.h>
#endif
class CAtmoInput;
/*
the idea behind this class is to avoid a mix of persistent value and
volatile values in CAtmoConfig class because some parameters and variables
exists only for the current process and won't be stored to the registry
(Simple thought its a container... )
you ask? why I didn't used a struct for it? ..mmh I like classes?
Always stop the current effect Thread before changing AtmoConnection or
AtmoConfig!
*/
class CAtmoDynData
{
private:
/*
thread creating the current output (depends on active effect)
*/
CThread *m_pCurrentEffectThread;
/*
in Modus Live View the packetQueue is the connection
between the output processing and the pixelsource
*/
CAtmoPacketQueue *m_pLivePacketQueue;
/*
thread for getting and preparing the pixeldata in color
packets for each zone
*/
CAtmoInput *m_pLiveInput;
LivePictureSource m_LivePictureSource;
/*
connection to the current configure hardware device
*/
CAtmoConnection *m_pAtmoConnection;
/*
all global persistent parameters
*/
CAtmoConfig *m_pAtmoConfig;
#if !defined(_ATMO_VLC_PLUGIN_)
CAtmoDisplays *m_pAtmoDisplays;
HINSTANCE m_hInst;
CRITICAL_SECTION m_RemoteCallCriticalSection;
char m_WorkDir[MAX_PATH];
#else
vlc_object_t *p_atmo_filter;
vlc_mutex_t m_lock;
#endif
public:
#if !defined(_ATMO_VLC_PLUGIN_)
CAtmoDynData(HINSTANCE hInst,
CAtmoConfig *pAtmoConfig,
CAtmoDisplays *pAtmoDisplays);
#else
CAtmoDynData(vlc_object_t *p_atmo_filter,
CAtmoConfig *pAtmoConfig);
#endif
~CAtmoDynData(void);
CThread *getEffectThread() { return m_pCurrentEffectThread; }
void setEffectThread(CThread *value) { m_pCurrentEffectThread = value; }
CAtmoPacketQueue *getLivePacketQueue() { return m_pLivePacketQueue; }
void setLivePacketQueue(CAtmoPacketQueue *pQueue) { m_pLivePacketQueue = pQueue; }
CAtmoInput *getLiveInput() { return m_pLiveInput; }
void setLiveInput(CAtmoInput *value) { m_pLiveInput = value; }
LivePictureSource getLivePictureSource() { return m_LivePictureSource; }
void setLivePictureSource(LivePictureSource lps) { m_LivePictureSource = lps; }
CAtmoConnection *getAtmoConnection() { return m_pAtmoConnection; }
void setAtmoConnection(CAtmoConnection *value) { m_pAtmoConnection = value; }
CAtmoConfig *getAtmoConfig() { return m_pAtmoConfig; }
void ReloadZoneDefinitionBitmaps();
void CalculateDefaultZones();
#if !defined(_ATMO_VLC_PLUGIN_)
CAtmoDisplays *getAtmoDisplays() { return m_pAtmoDisplays; }
HINSTANCE getHinstance() { return m_hInst; }
void setWorkDir(const char *dir);
char *getWorkDir();
#else
vlc_object_t *getAtmoFilter() { return p_atmo_filter; }
#endif
void LockCriticalSection();
void UnLockCriticalSection();
};
#endif
/*
* AtmoExternalCaptureInput.cpp: Datasource which gets its data via a COM object call
* or some other external method.
*
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "AtmoExternalCaptureInput.h"
#include "AtmoTools.h"
#if defined(_ATMO_VLC_PLUGIN_)
#ifndef INT64_C
#define INT64_C(c) c ## LL
#endif
CAtmoExternalCaptureInput::CAtmoExternalCaptureInput(CAtmoDynData *pAtmoDynData) :
CAtmoInput(pAtmoDynData)
{
vlc_cond_init( &m_WakeupCond );
vlc_mutex_init( &m_WakeupLock );
m_pCurrentFramePixels = NULL;
m_pLog = pAtmoDynData->getAtmoFilter();
}
#else
CAtmoExternalCaptureInput::CAtmoExternalCaptureInput(CAtmoDynData *pAtmoDynData) :
CAtmoInput(pAtmoDynData)
{
m_hWakeupEvent = CreateEvent(NULL,0,0,NULL);
InitializeCriticalSection( &m_BufferLock );
m_pCurrentFramePixels = NULL;
}
#endif
CAtmoExternalCaptureInput::~CAtmoExternalCaptureInput(void)
{
/* if there is still an unprocessed bufferpicture do kill it */
#if defined(_ATMO_VLC_PLUGIN_)
vlc_mutex_lock( &m_WakeupLock );
free( m_pCurrentFramePixels );
vlc_mutex_unlock( &m_WakeupLock );
vlc_cond_destroy( &m_WakeupCond );
vlc_mutex_destroy( &m_WakeupLock );
#else
EnterCriticalSection( &m_BufferLock );
free( m_pCurrentFramePixels );
LeaveCriticalSection( &m_BufferLock );
CloseHandle(m_hWakeupEvent);
DeleteCriticalSection( &m_BufferLock );
#endif
}
ATMO_BOOL CAtmoExternalCaptureInput::Open()
{
this->Run();
return ATMO_TRUE;
}
// Closes the input-device.
// Returns true if the input-device was closed successfully.
ATMO_BOOL CAtmoExternalCaptureInput::Close(void)
{
this->Terminate();
return ATMO_TRUE;
}
/*
this method will be called from another thread or possible the COM Server to feed
new pixeldata into the calculation process it doest just the following:
1: check if last buffer was allready processed (!m_pCurrentFramePixels)
2. copy the bitmap info structure into the threads own one
3. alloc memory for frame
4. copy sourcepixeldata into own buffer...
5. let the thread wake up and return imediately to the caller
so that the real videoout wouldn't be stop for a too long time
*/
void CAtmoExternalCaptureInput::DeliverNewSourceDataPaket(VLC_BITMAPINFOHEADER *bmpInfoHeader,void *pixelData)
{
/*
normaly we should protect this area of code by critical_section or a mutex,
but I think we can omit this here because the timing this method is called
is really slow (in terms of the speed of a modern computer?)
so it's nearly impossible that two frames are delivert in the same time
the test needs and malloc needs...
*/
#if defined(_ATMO_VLC_PLUGIN_)
// msg_Dbg( m_pLog, "DeliverNewSourceDataPaket start...");
vlc_mutex_lock( &m_WakeupLock );
#else
EnterCriticalSection( &m_BufferLock );
#endif
if( !m_pCurrentFramePixels )
{
// Last Frame was processed... take this one...
memcpy(&m_CurrentFrameHeader,bmpInfoHeader,bmpInfoHeader->biSize);
int PixelDataSize = m_CurrentFrameHeader.biHeight * m_CurrentFrameHeader.biWidth;
switch(m_CurrentFrameHeader.biBitCount) {
case 8: /* PixelDataSize = PixelDataSize; */ break;
case 16: PixelDataSize = PixelDataSize * 2; break;
case 24: PixelDataSize = PixelDataSize * 3; break;
case 32: PixelDataSize = PixelDataSize * 4; break;
}
m_pCurrentFramePixels = malloc(PixelDataSize);
memcpy(m_pCurrentFramePixels,pixelData,PixelDataSize);
}
#if defined(_ATMO_VLC_PLUGIN_)
vlc_cond_signal( &m_WakeupCond );
vlc_mutex_unlock( &m_WakeupLock );
// msg_Dbg( m_pLog, "DeliverNewSourceDataPaket done.");
#else
SetEvent(m_hWakeupEvent);
LeaveCriticalSection( &m_BufferLock );
#endif
}
/*
the real thread Method which is processing the pixeldata into the hardware channel
values - which are used by the thread AtmoLiveView...
*/
#if defined (_ATMO_VLC_PLUGIN_)
DWORD CAtmoExternalCaptureInput::Execute(void)
{
while (this->m_bTerminated == ATMO_FALSE) {
vlc_mutex_lock( &m_WakeupLock );
vlc_cond_timedwait(&m_WakeupCond, &m_WakeupLock, mdate() + 75000 );
/* DeliverNewSourceDataPaket delivered new work for me... get it! */
if(m_pCurrentFramePixels)
CalcColors(); // read picture and calculate colors
vlc_mutex_unlock( &m_WakeupLock );
}
msg_Dbg( m_pLog, "DWORD CAtmoExternalCaptureInput::Execute(void) bailed out?");
return 0;
}
#else
DWORD CAtmoExternalCaptureInput::Execute(void) {
HANDLE handles[2];
handles[0] = this->m_hTerminateEvent;
handles[1] = m_hWakeupEvent;
while (this->m_bTerminated == ATMO_FALSE) {
DWORD event = WaitForMultipleObjects(2, &handles[0], FALSE, INFINITE);
if(event == WAIT_OBJECT_0) {
// Terminate Thread Event was set... say good bye...!
break;
}
if(event == (WAIT_OBJECT_0+1)) {
EnterCriticalSection( &m_BufferLock );
if(m_pCurrentFramePixels)
CalcColors(); // read picture and calculate colors
LeaveCriticalSection( &m_BufferLock );
}
}
return 0;
}
#endif
void CAtmoExternalCaptureInput::CalcColors()
{
// take data from m_CurrentFrameHeader and m_pCurrentFramePixels .. process for atmo ...
tHSVColor HSV_Img[IMAGE_SIZE];
tRGBColor pixelColor;
int srcIndex,index = 0;
memset(&HSV_Img,0,sizeof(HSV_Img));
// msg_Dbg( m_pLog, "CalcColors start...");
if((m_CurrentFrameHeader.biWidth == CAP_WIDTH) && (m_CurrentFrameHeader.biHeight == CAP_HEIGHT))
{
// HSVI = HSV Image allready in right format just copy the easiest task
// und weiterverarbeiten lassen
#ifdef _ATMO_VLC_PLUGIN_
if(m_CurrentFrameHeader.biCompression == VLC_FOURCC('H','S','V','I'))
#else
if(m_CurrentFrameHeader.biCompression == MakeDword('H','S','V','I'))
#endif
{
memcpy( &HSV_Img, m_pCurrentFramePixels, CAP_WIDTH * CAP_HEIGHT * sizeof(tHSVColor));
}
else if(m_CurrentFrameHeader.biCompression == BI_RGB)
{
if(m_CurrentFrameHeader.biBitCount == 16)
{
unsigned short *buffer = (unsigned short *)m_pCurrentFramePixels;
for(int y=0;y<CAP_HEIGHT;y++)
{
srcIndex = y * CAP_WIDTH;
for(int x=0;x<CAP_WIDTH;x++)
{
pixelColor.b = (buffer[srcIndex] & 31) << 3;
pixelColor.g = ((buffer[srcIndex] >> 5) & 31) << 3;
pixelColor.r = ((buffer[srcIndex] >> 10) & 63) << 2;
srcIndex++;
HSV_Img[index++] = RGB2HSV(pixelColor);
}
}
}
else if(m_CurrentFrameHeader.biBitCount == 24)
{
for(int y=0;y<CAP_HEIGHT;y++)
{
srcIndex = y * (CAP_WIDTH*3);
for(int x=0;x<CAP_WIDTH;x++)
{
pixelColor.b = ((unsigned char *)m_pCurrentFramePixels)[srcIndex++];
pixelColor.g = ((unsigned char *)m_pCurrentFramePixels)[srcIndex++];
pixelColor.r = ((unsigned char *)m_pCurrentFramePixels)[srcIndex++];
HSV_Img[index++] = RGB2HSV(pixelColor);
}
}
}
else if(m_CurrentFrameHeader.biBitCount == 32)
{
for(int y=0;y<CAP_HEIGHT;y++)
{
srcIndex = y * (CAP_WIDTH*4);
for(int x=0;x<CAP_WIDTH;x++)
{
pixelColor.b = ((unsigned char *)m_pCurrentFramePixels)[srcIndex++];
pixelColor.g = ((unsigned char *)m_pCurrentFramePixels)[srcIndex++];
pixelColor.r = ((unsigned char *)m_pCurrentFramePixels)[srcIndex++];
srcIndex++;
HSV_Img[index++] = RGB2HSV(pixelColor);
}
}
}
}
}
/*
else {
if the image color format wasn't recognized - the output
will be black (memset)
}
*/
/* remove the source buffer */
free( m_pCurrentFramePixels );
m_pCurrentFramePixels = NULL;
/*
now convert the pixeldata into one RGB trippel for each channel,
this is done by some very sophisticated methods and statistics ...
the only thing I know - the pixel priority is controled by some
gradients for each edge of the picture
(sorry I don't know how it exactly works because the formulas
are done by some one else...)
*/
//msg_Dbg( m_pLog, "CalcColors ende AddPacket...");
m_pAtmoDynData->getLivePacketQueue()->AddPacket( m_pAtmoColorCalculator->AnalyzeHSV( HSV_Img ) );
//msg_Dbg( m_pLog, "CalcColors ende AddPacket...done.");
}
#ifndef _AtmoExternalCaptureInput_h_
#define _AtmoExternalCaptureInput_h_
#include "AtmoDefs.h"
#if defined(_WIN32)
# include <windows.h>
# else
# if defined(_ATMO_VLC_PLUGIN_)
// need bitmap info header
# include <vlc_codecs.h>
# endif
#endif
#if defined(_ATMO_VLC_PLUGIN_)
# include <vlc_common.h>
# include <vlc_threads.h>
#endif
#include "AtmoInput.h"
#include "AtmoThread.h"
#include "AtmoConfig.h"
#include "AtmoDynData.h"
#include "AtmoCalculations.h"
class CAtmoExternalCaptureInput : public CAtmoInput
{
protected:
#if defined(_ATMO_VLC_PLUGIN_)
vlc_cond_t m_WakeupCond;
vlc_mutex_t m_WakeupLock;
vlc_object_t *m_pLog;
#else
HANDLE m_hWakeupEvent;
CRITICAL_SECTION m_BufferLock;
#endif
VLC_BITMAPINFOHEADER m_CurrentFrameHeader;
void *m_pCurrentFramePixels;
virtual DWORD Execute(void);
void CalcColors();
public:
/*
this method is called from the com server AtmoLiveViewControlImpl!
or inside videolan from the filter method to start a new processing
*/
void DeliverNewSourceDataPaket(VLC_BITMAPINFOHEADER *bmpInfoHeader,void *pixelData);
public:
CAtmoExternalCaptureInput(CAtmoDynData *pAtmoDynData);
virtual ~CAtmoExternalCaptureInput(void);
/*
Opens the input-device. Parameters (e.g. the device-name)
Returns true if the input-device was opened successfully.
input-device can be the GDI surface of screen (windows only)
or the videolan filter
*/
virtual ATMO_BOOL Open(void);
/*
Closes the input-device.
Returns true if the input-device was closed successfully.
*/
virtual ATMO_BOOL Close(void);
};
#endif
/*
* AtmoInput.cpp: abstract class for retrieving precalculated image data
* from different sources in the live view mode
*
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "AtmoDefs.h"
#include "AtmoInput.h"
#if defined(_ATMO_VLC_PLUGIN_)
CAtmoInput::CAtmoInput(CAtmoDynData *pAtmoDynData) : CThread(pAtmoDynData->getAtmoFilter())
{
m_pAtmoDynData = pAtmoDynData;
m_pAtmoColorCalculator = new CAtmoColorCalculator(pAtmoDynData->getAtmoConfig());
}
#else
CAtmoInput::CAtmoInput(CAtmoDynData *pAtmoDynData)
{
m_pAtmoDynData = pAtmoDynData;
m_pAtmoColorCalculator = new CAtmoColorCalculator(pAtmoDynData->getAtmoConfig());
}
#endif
CAtmoInput::~CAtmoInput(void)
{
delete m_pAtmoColorCalculator;
}
/*
* AtmoInput.h: abstract class for retrieving precalculated image data from
* different sources in the live view mode
*
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifndef _AtmoInput_h_
#define _AtmoInput_h_
#include "AtmoDefs.h"
#include "AtmoCalculations.h"
#include "AtmoPacketQueue.h"
#include "AtmoThread.h"
#include "AtmoDynData.h"
class CAtmoDynData;
/*
basic definition of an AtmoLight data/image source ...
*/
class CAtmoInput : public CThread {
protected:
CAtmoDynData *m_pAtmoDynData;
CAtmoColorCalculator *m_pAtmoColorCalculator;
public:
CAtmoInput(CAtmoDynData *pAtmoDynData);
virtual ~CAtmoInput(void);
// Opens the input-device.
// Returns true if the input-device was opened successfully.
virtual ATMO_BOOL Open(void) { return ATMO_FALSE; }
// Closes the input-device.
// Returns true if the input-device was closed successfully.
virtual ATMO_BOOL Close(void) { return ATMO_FALSE; }
};
#endif
/*
* AtmoLiveView.cpp: this effect outputs colors as result of a picture
* content (most complex effect) see thread.c of the linux VDR version -
* to fully understand what happens here..
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "AtmoDefs.h"
#include "AtmoLiveView.h"
#include "AtmoOutputFilter.h"
#include "AtmoTools.h"
#if defined(_ATMO_VLC_PLUGIN_)
# include <vlc_common.h>
#else
# include "AtmoGdiDisplayCaptureInput.h"
#endif
#include "AtmoExternalCaptureInput.h"
#if defined(_ATMO_VLC_PLUGIN_)
CAtmoLiveView::CAtmoLiveView(CAtmoDynData *pAtmoDynData) :
CThread(pAtmoDynData->getAtmoFilter())
{
this->m_pAtmoDynData = pAtmoDynData;
}
#else
CAtmoLiveView::CAtmoLiveView(CAtmoDynData *pAtmoDynData)
{
this->m_pAtmoDynData = pAtmoDynData;
}
#endif
CAtmoLiveView::~CAtmoLiveView(void)
{
}
DWORD CAtmoLiveView::Execute(void)
{
#if defined(_ATMO_VLC_PLUGIN_)
vlc_object_t *m_pLog = m_pAtmoDynData->getAtmoFilter();
mtime_t ticks;
mtime_t t;
mtime_t packet_time;
#else
DWORD ticks;
DWORD t;
DWORD packet_time;
#endif
int i_frame_counter = -1;
pColorPacket ColorPacket;
pColorPacket PreviousPacket = NULL;
CAtmoConnection *pAtmoConnection = this->m_pAtmoDynData->getAtmoConnection();
if((pAtmoConnection == NULL) || (pAtmoConnection->isOpen() == ATMO_FALSE)) return 0;
CAtmoConfig *pAtmoConfig = this->m_pAtmoDynData->getAtmoConfig();
/*
this object does post processing of the pixel data
like jump /scenechange detection fading over the colors
*/
CAtmoOutputFilter *filter = new CAtmoOutputFilter( this->m_pAtmoDynData->getAtmoConfig() );
CAtmoPacketQueue *pPacketQueue = this->m_pAtmoDynData->getLivePacketQueue();
int frameDelay = pAtmoConfig->getLiveView_FrameDelay();
#if defined(_ATMO_VLC_PLUGIN_)
/*
because time function of vlc are working with us values instead of ms
*/
frameDelay = frameDelay * 1000;
#endif
/*
wait for the first frame to go in sync with the other thread
*/
t = get_time;
if( pPacketQueue->WaitForNextPacket(3000) )
{
if( frameDelay > 0 )
do_sleep( frameDelay );
#if defined(_ATMO_VLC_PLUGIN_)
msg_Dbg( m_pLog, "First Packet got %" PRId64 " ms", (get_time - t) / 1000 );
#endif
}
while(this->m_bTerminated == ATMO_FALSE)
{
i_frame_counter++;
if(i_frame_counter == 50) i_frame_counter = 0;
/* grab current Packet from InputQueue (working as FIFO)! */
#if defined(_ATMO_VLC_PLUGIN_)
ColorPacket = pPacketQueue->GetNextPacket(get_time - frameDelay, (i_frame_counter == 0), m_pLog, packet_time);
#else
ColorPacket = pPacketQueue->GetNextPacket(get_time - frameDelay, (i_frame_counter == 0), packet_time);
#endif
if(ColorPacket)
{
/*
create a packet copy - for later reuse if the input is slower than 25fps
*/
if(PreviousPacket && (PreviousPacket->numColors == ColorPacket->numColors))
CopyColorPacket(ColorPacket, PreviousPacket)
else {
delete [] PreviousPacket;
DupColorPacket(PreviousPacket, ColorPacket )
}
} else {
/*
packet queue was empty for the given point of time
*/
if(i_frame_counter == 0)
{
#if defined(_ATMO_VLC_PLUGIN_)
msg_Dbg( m_pLog, "wait for delayed packet..." );
#endif
t = get_time;
if( pPacketQueue->WaitForNextPacket(200) )
{
if( frameDelay > 0 )
do_sleep( frameDelay );
#if defined(_ATMO_VLC_PLUGIN_)
msg_Dbg( m_pLog, "got delayed packet %" PRId64 " ms", (mdate() - t) / 1000 );
#endif
continue;
}
}
/*
reuse previous color packet
*/
DupColorPacket(ColorPacket, PreviousPacket)
}
ticks = get_time;
if(ColorPacket)
{
/* pass it through the outputfilters! */
// Info Filtering will possible free the colorpacket and alloc a new one!
ColorPacket = filter->Filtering(ColorPacket);
/* apply gamma correction - only if the hardware isnt capable doing this */
ColorPacket = CAtmoTools::ApplyGamma(pAtmoConfig, ColorPacket);
/*
apply white calibration - only if it is not
done by the hardware
*/
if(pAtmoConfig->isUseSoftwareWhiteAdj())
ColorPacket = CAtmoTools::WhiteCalibration(pAtmoConfig, ColorPacket);
/* send color data to the the hardware... */
pAtmoConnection->SendData(ColorPacket);
delete (char *)ColorPacket;
}
/*
calculate RunTime of thread abbove (doesn't work well - so
this threads comes out of sync with Image producer and the
framerate (25fps) drifts away
*/
#if defined(_ATMO_VLC_PLUGIN_)
ticks = ((mdate() - ticks) + 999)/1000;
#else
ticks = GetTickCount() - ticks;
#endif
if(ticks < 40)
{
if( ThreadSleep( 40 - ticks ) == ATMO_FALSE )
break;
}
}
#if defined(_ATMO_VLC_PLUGIN_)
msg_Dbg( m_pLog, "DWORD CAtmoLiveView::Execute(void) terminates");
pPacketQueue->ShowQueueStatus( m_pLog );
#endif
delete [] PreviousPacket;
delete filter;
return 0;
}
/*
* AtmoLiveView.h: this effect outputs colors as result of a picture content
* (most complex effect) see thread.c of the linux version - to fully understand
* what happes here..
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifndef _AtmoLiveView_h_
#define _AtmoLiveView_h_
#include "AtmoDefs.h"
#if !defined(_ATMO_VLC_PLUGIN_)
# include <windows.h>
#endif
#include "AtmoThread.h"
#include "AtmoConfig.h"
#include "AtmoConnection.h"
#include "AtmoInput.h"
class CAtmoLiveView : public CThread
{
protected:
virtual DWORD Execute(void);
protected:
CAtmoDynData *m_pAtmoDynData;
public:
CAtmoLiveView(CAtmoDynData *pAtmoDynData);
virtual ~CAtmoLiveView(void);
};
#endif
/*
* AtmoMultiConnection.cpp: Class for communication with up to 4 - 4 channel classic atmolight controllers
* so you can built a cheap solution for having up to 16 channels
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "AtmoDefs.h"
#include "AtmoMultiConnection.h"
#if !defined(_ATMO_VLC_PLUGIN_)
#include "AtmoMultiConfigDialog.h"
#endif
#include <stdio.h>
#include <fcntl.h>
#if !defined(_WIN32)
#include <termios.h>
#include <unistd.h>
#endif
CAtmoMultiConnection::CAtmoMultiConnection(CAtmoConfig *cfg) : CAtmoConnection(cfg)
{
m_hComports[0] = INVALID_HANDLE_VALUE;
m_hComports[1] = INVALID_HANDLE_VALUE;
m_hComports[2] = INVALID_HANDLE_VALUE;
m_hComports[3] = INVALID_HANDLE_VALUE;
memset(&m_output, 0, sizeof(m_output));
}
CAtmoMultiConnection::~CAtmoMultiConnection(void)
{
}
HANDLE CAtmoMultiConnection::OpenDevice(char *devName)
{
HANDLE hComport;
#if !defined(_ATMO_VLC_PLUGIN_)
m_dwLastWin32Error = 0;
#endif
#if defined(_WIN32)
hComport = CreateFileA(devName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if(hComport == INVALID_HANDLE_VALUE) {
#if !defined(_ATMO_VLC_PLUGIN_)
m_dwLastWin32Error = GetLastError();
#endif
return INVALID_HANDLE_VALUE;
}
/* change serial settings (Speed, stopbits etc.) */
DCB dcb; // für comport-parameter
dcb.DCBlength = sizeof(DCB);
GetCommState (hComport, &dcb); // ger current serialport settings
dcb.BaudRate = 38400; // set speed
dcb.ByteSize = 8; // set databits
dcb.Parity = NOPARITY; // set parity
dcb.StopBits = ONESTOPBIT; // set one stop bit
SetCommState (hComport, &dcb); // apply settings
#else
int bconst = B38400;
hComport = open(devName,O_RDWR |O_NOCTTY);
if(hComport < 0) {
return INVALID_HANDLE_VALUE;;
}
struct termios tio;
memset(&tio,0,sizeof(tio));
tio.c_cflag = (CS8 | CREAD | HUPCL | CLOCAL);
tio.c_iflag = (INPCK | BRKINT);
cfsetispeed(&tio, bconst);
cfsetospeed(&tio, bconst);
if(!tcsetattr(hComport, TCSANOW, &tio)) {
tcflush(hComport, TCIOFLUSH);
} else {
// can't change parms
close(hComport);
return INVALID_HANDLE_VALUE;
}
#endif
return hComport;
}
ATMO_BOOL CAtmoMultiConnection::OpenConnection()
{
int z = 0;
#if defined(_ATMO_VLC_PLUGIN_)
for(int c = 0; c < 4; c++ ) {
char *devName = m_pAtmoConfig->getSerialDevice( c );
if( !EMPTY_STR( devName ) )
{
m_hComports[z] = OpenDevice( devName );
if(m_hComports[z] == INVALID_HANDLE_VALUE) {
while(z) {
z--;
#if defined(_WIN32)
CloseHandle( m_hComports[z] );
#else
close( m_hComports[z] );
#endif
m_hComports[z] = INVALID_HANDLE_VALUE;
}
return ATMO_FALSE;
}
z++;
}
}
#else
char devName[16];
for(int c = 0; c < 4; c++ ) {
int comportnr = m_pAtmoConfig->getComport(c);
if(comportnr > 0)
{
sprintf(devName,"com%d",comportnr);
m_hComports[z] = OpenDevice(devName);
if(m_hComports[z] == INVALID_HANDLE_VALUE) {
while(z) {
z--;
CloseHandle( m_hComports[z] );
m_hComports[z] = INVALID_HANDLE_VALUE;
}
return ATMO_FALSE;
}
z++;
}
}
#endif
return ATMO_TRUE;
}
void CAtmoMultiConnection::CloseConnection() {
for(int i = 0; i < 4; i++ ) {
if(m_hComports[i] != INVALID_HANDLE_VALUE) {
#if defined(_WIN32)
CloseHandle( m_hComports[i] );
#else
close( m_hComports[i] );
#endif
m_hComports[i] = INVALID_HANDLE_VALUE;
}
}
}
ATMO_BOOL CAtmoMultiConnection::isOpen(void) {
int z = 0;
for(int i = 0; i < 4; i++ )
if(m_hComports[i] != INVALID_HANDLE_VALUE) z++;
return (z > 0);
}
int CAtmoMultiConnection::getNumChannels()
{
int z = 0;
#if defined(_ATMO_VLC_PLUGIN_)
char *psz_dev;
for(int i=0;i<4;i++) {
psz_dev = m_pAtmoConfig->getSerialDevice( i );
if( !EMPTY_STR( psz_dev ) )
z+=4;
}
#else
for(int i=0;i<4;i++)
if(m_pAtmoConfig->getComport(i)>0)
z+=4;
#endif
return z;
}
ATMO_BOOL CAtmoMultiConnection::CreateDefaultMapping(CAtmoChannelAssignment *ca)
{
if(!ca) return ATMO_FALSE;
int z = getNumChannels();
ca->setSize( z );
// 1 : 1 mapping vorschlagen...
for(int i = 0; i < z ; i++ ) {
ca->setZoneIndex( i, i );
}
return ATMO_TRUE;
}
ATMO_BOOL CAtmoMultiConnection::internal_HardwareWhiteAdjust(HANDLE hComport,
int global_gamma,
int global_contrast,
int contrast_red,
int contrast_green,
int contrast_blue,
int gamma_red,
int gamma_green,
int gamma_blue,
ATMO_BOOL storeToEeprom) {
if(hComport == INVALID_HANDLE_VALUE)
return ATMO_FALSE;
DWORD iBytesWritten;
/*
[0] = 255
[1] = 00
[2] = 00
[3] = 101
[4] brightness 0..255 ?
[5] Contrast Red 11 .. 100
[6] Contrast Green 11 .. 100
[7] Contrast Blue 11 .. 100
[8] Gamma Red 11 .. 35
[9] Gamma Red 11 .. 35
[10] Gamma Red 11 .. 35
[11] Globale Contrast 11 .. 100
[12] Store Data: 199 (else 0)
*/
unsigned char sendBuffer[16];
sendBuffer[0] = 0xFF;
sendBuffer[1] = 0x00;
sendBuffer[2] = 0x00;
sendBuffer[3] = 101;
sendBuffer[4] = (global_gamma & 255);
sendBuffer[5] = (contrast_red & 255);
sendBuffer[6] = (contrast_green & 255);
sendBuffer[7] = (contrast_blue & 255);
sendBuffer[8] = (gamma_red & 255);
sendBuffer[9] = (gamma_green & 255);
sendBuffer[10] = (gamma_blue & 255);
sendBuffer[11] = (global_contrast & 255);
if(storeToEeprom == ATMO_TRUE)
sendBuffer[12] = 199; // store to eeprom!
else
sendBuffer[12] = 0;
#if defined(_WIN32)
WriteFile(hComport, sendBuffer, 13, &iBytesWritten, NULL); // send to COM-Port
#else
iBytesWritten = write(hComport, sendBuffer, 13);
tcdrain(hComport);
#endif
return (iBytesWritten == 13) ? ATMO_TRUE : ATMO_FALSE;
}
ATMO_BOOL CAtmoMultiConnection::HardwareWhiteAdjust( int global_gamma,
int global_contrast,
int contrast_red,
int contrast_green,
int contrast_blue,
int gamma_red,
int gamma_green,
int gamma_blue,
ATMO_BOOL storeToEeprom)
{
for(int z = 0 ; z < 4; z++ ) {
if(m_hComports[z]!= INVALID_HANDLE_VALUE)
if(internal_HardwareWhiteAdjust(m_hComports[z], global_gamma, global_contrast,
contrast_red, contrast_green, contrast_blue,
gamma_red, gamma_green, gamma_blue,
storeToEeprom) == ATMO_FALSE)
return ATMO_FALSE;
}
return ATMO_TRUE;
}
ATMO_BOOL CAtmoMultiConnection::internal_SendData(HANDLE hComport, unsigned char *colorData)
{
if(m_hComports[0] == INVALID_HANDLE_VALUE)
return ATMO_FALSE;
unsigned char buffer[19];
DWORD iBytesWritten;
buffer[0] = 0xFF; // Start Byte
buffer[1] = 0x00; // Start channel 0
buffer[2] = 0x00; // Start channel 0
buffer[3] = 15; //
buffer[4] = 0; // Summe Red
buffer[5] = 0; // Summe Green
buffer[6] = 0; // Summe Blue
memcpy(&buffer[7], colorData, 4 * 3);
#if defined(_WIN32)
WriteFile(hComport, buffer, 19, &iBytesWritten, NULL); // send to COM-Port
#else
iBytesWritten = write(hComport, buffer, 19);
tcdrain(hComport);
#endif
return (iBytesWritten == 19) ? ATMO_TRUE : ATMO_FALSE;
}
ATMO_BOOL CAtmoMultiConnection::SendData(pColorPacket data)
{
if(m_hComports[0] == INVALID_HANDLE_VALUE)
return ATMO_FALSE;
int numChannels = this->getNumChannels();
int idx;
int iBuffer = 0;
ATMO_BOOL result = ATMO_TRUE;
Lock();
for(int i = 0; i < numChannels ; i++) {
if(m_ChannelAssignment && (i < m_NumAssignedChannels))
idx = m_ChannelAssignment[i];
else
idx = -1;
if((idx>=0) && (idx<data->numColors)) {
m_output[iBuffer] = data->zone[idx].r;
m_output[iBuffer+1] = data->zone[idx].g;
m_output[iBuffer+2] = data->zone[idx].b;
}
iBuffer+=3;
}
for(int i = 0;i < 4; i++)
if(m_hComports[i] != INVALID_HANDLE_VALUE)
result = result & internal_SendData(m_hComports[i], &m_output[i*4*3]);
Unlock();
return result;
}
ATMO_BOOL CAtmoMultiConnection::setChannelColor(int channel, tRGBColor color)
{
if(m_hComports[0] == INVALID_HANDLE_VALUE)
return ATMO_FALSE;
if((channel < 0) || (channel >= getNumChannels()))
return ATMO_FALSE;
ATMO_BOOL result = ATMO_TRUE;
Lock();
channel*=3;
m_output[channel++] = color.r;
m_output[channel++] = color.g;
m_output[channel] = color.b;
for(int i = 0; i < 4; i++)
if(m_hComports[i] != INVALID_HANDLE_VALUE)
result = result & internal_SendData(m_hComports[i], &m_output[i*4*3]);
Unlock();
return result;
}
ATMO_BOOL CAtmoMultiConnection::setChannelValues(int numValues,unsigned char *channel_values)
{
if(m_hComports[0] == INVALID_HANDLE_VALUE)
return ATMO_FALSE;
if((numValues & 1) || !channel_values)
return ATMO_FALSE; // numValues must be even!
ATMO_BOOL result = ATMO_TRUE;
Lock();
size_t Index = 0;
for (int i = 0; i < numValues; i+=2) {
Index = (size_t)channel_values[i];
if(Index < sizeof(m_output))
m_output[Index] = channel_values[i + 1];
}
for(int i = 0; i < 4; i++)
if(m_hComports[i] != INVALID_HANDLE_VALUE)
result = result & internal_SendData(m_hComports[i], &m_output[i*4*3]);
Unlock();
return result;
}
#if !defined(_ATMO_VLC_PLUGIN_)
char *CAtmoMultiConnection::getChannelName(int ch)
{
int devnum = ch / 4;
int kanal = ch % 4;
char buf[60];
switch(kanal) {
case 0: {
sprintf(buf,"Atmo[%d.%d] Links (%d)", devnum, kanal, ch);
break;
}
case 1: {
sprintf(buf,"Atmo[%d.%d] Rechts (%d)", devnum, kanal, ch);
break;
}
case 2: {
sprintf(buf,"Atmo[%d.%d] Oben (%d)", devnum, kanal, ch);
break;
}
case 3: {
sprintf(buf,"Atmo[%d.%d] Unten (%d)", devnum, kanal, ch);
break;
}
}
return strdup(buf);
}
ATMO_BOOL CAtmoMultiConnection::ShowConfigDialog(HINSTANCE hInst, HWND parent, CAtmoConfig *cfg)
{
CAtmoMultiConfigDialog *dlg = new CAtmoMultiConfigDialog(hInst, parent, cfg);
INT_PTR result = dlg->ShowModal();
delete dlg;
if(result == IDOK)
return ATMO_TRUE;
else
return ATMO_FALSE;
}
#endif
/*
* AtmoMultiConnection.h: Class for communication with up to 4 - 4 channel classic atmolight controllers
* so you can built a cheap solution for having up to 16 channels, but you need four comports or
* USB Adapters
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifndef _AtmoMultiConnection_h_
#define _AtmoMultiConnection_h_
#include "AtmoDefs.h"
#include "AtmoConnection.h"
#include "AtmoConfig.h"
#if defined(_WIN32)
# include <windows.h>
#endif
class CAtmoMultiConnection : public CAtmoConnection
{
private:
HANDLE m_hComports[4];
unsigned char m_output[4 * 4 * 3];
#if defined(_WIN32)
DWORD m_dwLastWin32Error;
public:
DWORD getLastError() { return m_dwLastWin32Error; }
#endif
/*
on windows devName is COM1 COM2 etc.
on linux devname my be /dev/ttyS0 or /dev/ttyUSB0
*/
HANDLE OpenDevice(char *devName);
ATMO_BOOL internal_HardwareWhiteAdjust(HANDLE hComport,int global_gamma,
int global_contrast,
int contrast_red,
int contrast_green,
int contrast_blue,
int gamma_red,
int gamma_green,
int gamma_blue,
ATMO_BOOL storeToEeprom);
ATMO_BOOL internal_SendData(HANDLE hComport, unsigned char *colorData);
public:
CAtmoMultiConnection(CAtmoConfig *cfg);
virtual ~CAtmoMultiConnection(void);
virtual ATMO_BOOL OpenConnection();
virtual void CloseConnection();
virtual ATMO_BOOL isOpen(void);
virtual ATMO_BOOL SendData(pColorPacket data);
virtual ATMO_BOOL setChannelColor(int channel, tRGBColor color);
virtual ATMO_BOOL setChannelValues(int numValues,unsigned char *channel_values);
virtual ATMO_BOOL HardwareWhiteAdjust(int global_gamma,
int global_contrast,
int contrast_red,
int contrast_green,
int contrast_blue,
int gamma_red,
int gamma_green,
int gamma_blue,
ATMO_BOOL storeToEeprom);
virtual int getNumChannels();
virtual const char *getDevicePath() { return "multiatmo"; }
#if !defined(_ATMO_VLC_PLUGIN_)
virtual char *getChannelName(int ch);
virtual ATMO_BOOL ShowConfigDialog(HINSTANCE hInst, HWND parent, CAtmoConfig *cfg);
#endif
virtual ATMO_BOOL CreateDefaultMapping(CAtmoChannelAssignment *ca);
};
#endif
/*
* AtmoOutputFilter.cpp: Post Processor for the color data retrieved from
* a CAtmoInput
*
* mostly 1:1 from vdr-linux-src "filter.c" copied
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <string.h>
#include "AtmoOutputFilter.h"
CAtmoOutputFilter::CAtmoOutputFilter(CAtmoConfig *atmoConfig )
{
this->m_pAtmoConfig = atmoConfig;
this->m_percent_filter_output_old = NULL;
this->m_mean_filter_output_old = NULL;
this->m_mean_values = NULL;
this->m_mean_sums = NULL;
ResetFilter();
}
CAtmoOutputFilter::~CAtmoOutputFilter(void)
{
if(m_percent_filter_output_old)
delete[] m_percent_filter_output_old;
if(m_mean_filter_output_old)
delete[] m_mean_filter_output_old;
if(m_mean_values)
delete[] m_mean_values;
if(m_mean_sums)
delete[] m_mean_sums;
}
void CAtmoOutputFilter::ResetFilter(void)
{
// reset filter values
MeanFilter(NULL, true);
PercentFilter(NULL, true);
}
pColorPacket CAtmoOutputFilter::Filtering(pColorPacket ColorPacket)
{
switch (m_pAtmoConfig->getLiveViewFilterMode())
{
case afmNoFilter:
return ColorPacket;
break;
case afmCombined:
return MeanFilter(ColorPacket, false);
break;
case afmPercent:
return PercentFilter(ColorPacket, false);
break;
}
return ColorPacket;
}
pColorPacket CAtmoOutputFilter::PercentFilter(pColorPacket filter_input, ATMO_BOOL init)
{
// last values needed for the percentage filter
if (init) // Initialization
{
if(m_percent_filter_output_old)
delete[] m_percent_filter_output_old;
m_percent_filter_output_old = NULL;
return(NULL);
}
if(!m_percent_filter_output_old || (m_percent_filter_output_old->numColors!=filter_input->numColors)) {
delete[] m_percent_filter_output_old;
AllocColorPacket(m_percent_filter_output_old, filter_input->numColors);
ZeroColorPacket(m_percent_filter_output_old);
}
int percentNew = this->m_pAtmoConfig->getLiveViewFilter_PercentNew();
pColorPacket filter_output;
AllocColorPacket(filter_output, filter_input->numColors);
for (int zone = 0; zone < filter_input->numColors; zone++)
{
filter_output->zone[zone].r = (filter_input->zone[zone].r *
(100-percentNew) + m_percent_filter_output_old->zone[zone].r * percentNew) / 100;
filter_output->zone[zone].g = (filter_input->zone[zone].g *
(100-percentNew) + m_percent_filter_output_old->zone[zone].g * percentNew) / 100;
filter_output->zone[zone].b = (filter_input->zone[zone].b *
(100-percentNew) + m_percent_filter_output_old->zone[zone].b * percentNew) / 100;
}
CopyColorPacket( filter_output, m_percent_filter_output_old );
delete[] filter_input;
return filter_output;
}
pColorPacket CAtmoOutputFilter::MeanFilter(pColorPacket filter_input, ATMO_BOOL init)
{
// needed vor the running mean value filter
// needed for the percentage filter
static int filter_length_old;
char reinitialize = 0;
long int tmp;
pColorPacket filter_output;
if (init) // Initialization
{
if(m_mean_filter_output_old)
delete[] m_mean_filter_output_old;
m_mean_filter_output_old = NULL;
if(m_mean_values)
delete[] m_mean_values;
m_mean_values = NULL;
if(m_mean_sums)
delete[] m_mean_sums;
m_mean_sums = NULL;
return (NULL);
}
if(!m_mean_filter_output_old || (m_mean_filter_output_old->numColors!=filter_input->numColors)) {
delete[] m_mean_filter_output_old;
AllocColorPacket(m_mean_filter_output_old, filter_input->numColors);
ZeroColorPacket(m_mean_filter_output_old);
}
if(!m_mean_values || (m_mean_values->numColors!=filter_input->numColors)) {
delete[] m_mean_values;
AllocColorPacket(m_mean_values, filter_input->numColors);
ZeroColorPacket(m_mean_values);
}
if(!m_mean_sums || (m_mean_sums->numColors!=filter_input->numColors)) {
delete[] m_mean_sums;
AllocLongColorPacket(m_mean_sums, filter_input->numColors);
ZeroLongColorPacket(m_mean_sums);
}
AllocColorPacket(filter_output, filter_input->numColors);
int AtmoSetup_Filter_MeanLength = m_pAtmoConfig->getLiveViewFilter_MeanLength();
int AtmoSetup_Filter_PercentNew = m_pAtmoConfig->getLiveViewFilter_PercentNew();
int AtmoSetup_Filter_MeanThreshold = m_pAtmoConfig->getLiveViewFilter_MeanThreshold();
// if filter_length has changed
if (filter_length_old != AtmoSetup_Filter_MeanLength)
{
// force reinitialization of the filter
reinitialize = 1;
}
filter_length_old = AtmoSetup_Filter_MeanLength;
if (filter_length_old < 20) filter_length_old = 20; // avoid division by 0
for (int zone = 0; zone < filter_input->numColors; zone++)
{
// calculate the mean-value filters
m_mean_sums->longZone[zone].r +=
(long int)(filter_input->zone[zone].r - m_mean_values->zone[zone].r); // red
tmp = m_mean_sums->longZone[zone].r / ((long int)filter_length_old / 20);
if(tmp<0) tmp = 0; else { if(tmp>255) tmp = 255; }
m_mean_values->zone[zone].r = (unsigned char)tmp;
m_mean_sums->longZone[zone].g +=
(long int)(filter_input->zone[zone].g - m_mean_values->zone[zone].g); // green
tmp = m_mean_sums->longZone[zone].g / ((long int)filter_length_old / 20);
if(tmp<0) tmp = 0; else { if(tmp>255) tmp = 255; }
m_mean_values->zone[zone].g = (unsigned char)tmp;
m_mean_sums->longZone[zone].b +=
(long int)(filter_input->zone[zone].b - m_mean_values->zone[zone].b); // blue
tmp = m_mean_sums->longZone[zone].b / ((long int)filter_length_old / 20);
if(tmp<0) tmp = 0; else { if(tmp>255) tmp = 255; }
m_mean_values->zone[zone].b = (unsigned char)tmp;
// check, if there is a jump -> check if differences between actual values and filter values are too big
long int dist; // distance between the two colors in the 3D RGB space
dist = (m_mean_values->zone[zone].r - filter_input->zone[zone].r) *
(m_mean_values->zone[zone].r - filter_input->zone[zone].r) +
(m_mean_values->zone[zone].g - filter_input->zone[zone].g) *
(m_mean_values->zone[zone].g - filter_input->zone[zone].g) +
(m_mean_values->zone[zone].b - filter_input->zone[zone].b) *
(m_mean_values->zone[zone].b - filter_input->zone[zone].b);
/*
if (dist > 0) { dist = (long int)sqrt((double)dist); }
avoid sqrt(0) (TODO: necessary?)
I think its cheaper to calculate the square of something ..? insteas geting the square root?
*/
double distMean = ((double)AtmoSetup_Filter_MeanThreshold * 3.6f);
distMean = distMean * distMean;
/*
compare calculated distance with the filter threshold
if ((dist > (long int)((double)AtmoSetup.Filter_MeanThreshold * 3.6f)) || ( reinitialize == 1))
*/
if ((dist > distMean) || ( reinitialize == 1))
{
// filter jump detected -> set the long filters to the result of the short filters
filter_output->zone[zone] = m_mean_values->zone[zone] = filter_input->zone[zone];
m_mean_sums->longZone[zone].r = filter_input->zone[zone].r *
(filter_length_old / 20);
m_mean_sums->longZone[zone].g = filter_input->zone[zone].g *
(filter_length_old / 20);
m_mean_sums->longZone[zone].b = filter_input->zone[zone].b *
(filter_length_old / 20);
}
else
{
// apply an additional percent filter and return calculated values
filter_output->zone[zone].r = (m_mean_values->zone[zone].r *
(100-AtmoSetup_Filter_PercentNew) +
m_mean_filter_output_old->zone[zone].r * AtmoSetup_Filter_PercentNew) / 100;
filter_output->zone[zone].g = (m_mean_values->zone[zone].g *
(100-AtmoSetup_Filter_PercentNew) +
m_mean_filter_output_old->zone[zone].g * AtmoSetup_Filter_PercentNew) / 100;
filter_output->zone[zone].b = (m_mean_values->zone[zone].b *
(100-AtmoSetup_Filter_PercentNew) +
m_mean_filter_output_old->zone[zone].b * AtmoSetup_Filter_PercentNew) / 100;
}
}
CopyColorPacket(filter_output, m_mean_filter_output_old);
delete[] filter_input;
return(filter_output);
}
/*
* AtmoOutputFilter.h: Post Processor for the color data retrieved from a CAtmoInput
*
* mostly 1:1 from Linux-src "filter.c" copied
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifndef _AtmoOutputFilter_h_
#define _AtmoOutputFilter_h_
#include "AtmoConfig.h"
#include "AtmoDefs.h"
class CAtmoOutputFilter
{
private:
//tColorPacket filter_input; // input of the filter wozu?
//tColorPacket filter_output; // output of the filter
pColorPacket m_percent_filter_output_old;
pColorPacket m_mean_filter_output_old;
pColorPacket m_mean_values;
pColorPacketLongInt m_mean_sums;
pColorPacket PercentFilter(pColorPacket filter_input, ATMO_BOOL init);
pColorPacket MeanFilter(pColorPacket filter_input, ATMO_BOOL init);
CAtmoConfig *m_pAtmoConfig;
public:
public:
CAtmoOutputFilter(CAtmoConfig *atmoConfig);
virtual ~CAtmoOutputFilter(void);
void ResetFilter(void);
pColorPacket Filtering(pColorPacket ColorPacket);
};
#endif
/*
* AtmoPacketQueue.cpp: works as connection between the framegrabber (color-preprocessor)
* and the live output thread. It works as a FIFO for the colorpackets - helps also
* to synchronize between grabber and liveview threads.
* especially if the grabber has another framerate as the liveview (25fps)
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "AtmoDefs.h"
#include "AtmoPacketQueue.h"
#if defined(_ATMO_VLC_PLUGIN_)
# include <vlc_common.h>
#define MAX_PACKET_TOO_LATE -30000
#define MAX_PACKET_TOO_EARLY 30000
#define MIN_SLEEP_TIME 15000
#else
#define MAX_PACKET_TOO_LATE -30
#define MAX_PACKET_TOO_EARLY 30
#define MIN_SLEEP_TIME 15
#endif
#if defined(_ATMO_VLC_PLUGIN_)
CAtmoPacketQueue::CAtmoPacketQueue()
{
m_first = NULL;
m_last = NULL;
m_waitcounter = 0;
m_skipcounter = 0;
m_framecounter = 0;
m_nullpackets = 0;
m_avgWait = 0;
m_avgDelay = 0;
vlc_cond_init( &m_PacketArrivedCond );
vlc_mutex_init( &m_PacketArrivedLock );
vlc_mutex_init( &m_Lock );
m_PacketArrived = ATMO_FALSE;
}
#else
CAtmoPacketQueue::CAtmoPacketQueue(CAtmoPacketQueueStatus *statusMonitor)
{
m_first = NULL;
m_last = NULL;
m_waitcounter = 0;
m_skipcounter = 0;
m_framecounter = 0;
m_nullpackets = 0;
m_avgWait = 0;
m_avgDelay = 0;
m_StatusMonitor = statusMonitor;
InitializeCriticalSection(&m_lock);
m_hPacketArrivedEvent = CreateEvent(NULL,ATMO_FALSE,ATMO_FALSE,NULL);
}
#endif
CAtmoPacketQueue::~CAtmoPacketQueue(void)
{
ClearQueue();
#if defined(_ATMO_VLC_PLUGIN_)
vlc_cond_destroy( &m_PacketArrivedCond );
vlc_mutex_destroy( &m_Lock );
#else
DeleteCriticalSection( &m_lock );
CloseHandle(m_hPacketArrivedEvent);
if(m_StatusMonitor)
m_StatusMonitor->destroyWindow();
#endif
}
void CAtmoPacketQueue::Lock()
{
#if defined(_ATMO_VLC_PLUGIN_)
vlc_mutex_lock( &m_Lock );
#else
EnterCriticalSection( &m_lock );
#endif
}
void CAtmoPacketQueue::Unlock()
{
#if defined(_ATMO_VLC_PLUGIN_)
vlc_mutex_unlock( &m_Lock );
#else
LeaveCriticalSection( &m_lock );
#endif
}
void CAtmoPacketQueue::SignalEvent()
{
#if defined(_ATMO_VLC_PLUGIN_)
vlc_mutex_lock( &m_PacketArrivedLock );
m_PacketArrived = ATMO_TRUE;
vlc_cond_signal( &m_PacketArrivedCond );
vlc_mutex_unlock( &m_PacketArrivedLock );
#else
SetEvent( m_hPacketArrivedEvent );
#endif
}
void CAtmoPacketQueue::UnSignalEvent()
{
#if defined(_ATMO_VLC_PLUGIN_)
#else
ResetEvent( m_hPacketArrivedEvent );
#endif
}
void CAtmoPacketQueue::AddPacket(pColorPacket newPacket)
{
pColorPacketItem temp = new ColorPacketItem;
temp->packet = newPacket;
temp->next = NULL;
#if defined(_ATMO_VLC_PLUGIN_)
temp->tickcount = mdate();
#else
temp->tickcount = GetTickCount();
#endif
Lock();
if(m_last) {
m_last->next = temp;
m_last = temp;
} else {
m_last = temp;
m_first = temp;
}
Unlock();
SignalEvent();
}
pColorPacketItem CAtmoPacketQueue::GetNextPacketContainer()
{
pColorPacketItem temp = NULL;
Lock();
if(m_first) {
temp = m_first;
m_first = m_first->next;
if(!m_first)
m_last = NULL;
temp->next = NULL;
}
Unlock();
return temp;
}
pColorPacket CAtmoPacketQueue::GetNextPacket()
{
pColorPacketItem item = GetNextPacketContainer();
if(item) {
pColorPacket temp = item->packet;
delete item;
return(temp);
} else
return(NULL);
}
#if defined(_ATMO_VLC_PLUGIN_)
void CAtmoPacketQueue::ShowQueueStatus(vlc_object_t *p_this)
{
/*
show some statistics for the whole time...
*/
msg_Dbg( p_this, "Skipped Packets: %d", m_skipcounter );
if( m_skipcounter > 0 )
msg_Dbg( p_this, "Average Delay: %d ms", (int)(m_avgDelay/m_skipcounter)/1000 );
msg_Dbg( p_this, "Waited Packets: %d", m_waitcounter );
if( m_waitcounter > 0 )
msg_Dbg( p_this, "Average Wait: %d ms", (int)(m_avgWait/m_waitcounter)/1000 );
msg_Dbg( p_this, "Used Packets: %d", m_framecounter );
msg_Dbg( p_this, "Null Packets: %d", m_nullpackets );
}
#endif
#if defined(_ATMO_VLC_PLUGIN_)
pColorPacket CAtmoPacketQueue::GetNextPacket(mtime_t timecode, ATMO_BOOL withWait, vlc_object_t *p_this, mtime_t &packet_time)
#else
pColorPacket CAtmoPacketQueue::GetNextPacket(DWORD timecode, ATMO_BOOL withWait, DWORD &packet_time)
#endif
{
#if !defined(_ATMO_VLC_PLUGIN_)
if(timecode & 0x80000000) // GetTickCount - delay < 0 ;-)
return NULL;
#endif
int timeDiff;
while(1)
{
Lock();
if(!m_first) {
Unlock();
break;
}
timeDiff = m_first->tickcount - timecode;
packet_time = m_first->tickcount;
Unlock();
if(timeDiff >= MAX_PACKET_TOO_EARLY) // packet should be process in 35ms or later (usually we are to early for it)
{
if( !withWait )
break;
}
else
{
if(timeDiff <= MAX_PACKET_TOO_LATE) {
// we are more than -35ms too late for this packet, skip it and throw it away!
#if defined(_ATMO_VLC_PLUGIN_)
msg_Dbg( p_this, "getNextPacket skip late %d ms", timeDiff / 1000 );
#endif
pColorPacket skip = GetNextPacket();
delete (char *)skip;
m_skipcounter++;
m_avgDelay += abs(timeDiff);
continue;
}
}
if(withWait && timeDiff > MIN_SLEEP_TIME)
{
// if this is a sync call, to get in sync with frame source again we wait untils its time!
#if defined(_ATMO_VLC_PLUGIN_)
msg_Dbg( p_this, "getNextPacket Sleep %d ms", timeDiff / 1000 );
#endif
do_sleep( timeDiff );
m_avgWait += timeDiff;
m_waitcounter++;
}
m_framecounter++;
#if !defined(_ATMO_VLC_PLUGIN_)
if(m_StatusMonitor)
{
if(withWait)
m_StatusMonitor->UpdateValues(m_waitcounter, m_skipcounter, m_framecounter, m_nullpackets, m_avgWait, m_avgDelay);
}
#endif
return GetNextPacket();
}
m_nullpackets++;
#if !defined(_ATMO_VLC_PLUGIN_)
if(m_StatusMonitor)
{
if(withWait)
m_StatusMonitor->UpdateValues(m_waitcounter, m_skipcounter, m_framecounter, m_nullpackets, m_avgWait, m_avgDelay);
}
#endif
return NULL;
}
ATMO_BOOL CAtmoPacketQueue::WaitForNextPacket(DWORD timeout)
{
UnSignalEvent();
#if !defined(_ATMO_VLC_PLUGIN_)
return ( WaitForSingleObject( m_hPacketArrivedEvent, timeout ) == WAIT_OBJECT_0 );
#else
mtime_t maxWait = mdate() + timeout * 1000;
vlc_mutex_lock( &m_PacketArrivedLock );
m_PacketArrived = ATMO_FALSE;
while(vlc_cond_timedwait( &m_PacketArrivedCond, &m_PacketArrivedLock, maxWait) == 0)
{
/*
condition was set -> but may be an old signal from previous AddPacket
which is still left - so if m_PacketArrived is still false, wait again
*/
if(mdate() >= maxWait)
break;
if( m_PacketArrived )
break;
}
vlc_mutex_unlock( &m_PacketArrivedLock );
return m_PacketArrived;
#endif
}
void CAtmoPacketQueue::ClearQueue()
{
pColorPacketItem next;
Lock();
while(m_first)
{
next = m_first->next;
delete (char *)(m_first->packet);
delete m_first;
m_first = next;
}
m_last = NULL;
m_waitcounter = 0;
m_skipcounter = 0;
m_framecounter = 0;
m_avgWait = 0;
m_avgDelay = 0;
m_nullpackets = 0;
Unlock();
}
/*
* AtmoPacketQueue.h: works as connection between the framegrabber (color-preprocessor)
* and the live output thread. It works as a FIFO for the colorpackets - helps also
* to synchronize between grabber and liveview threads.
* especially if the grabber has another framerate as the liveview (25fps)
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifndef _AtmoPacketQueue_
#define _AtmoPacketQueue_
#include "AtmoDefs.h"
#include "AtmoThread.h"
#if defined(_ATMO_VLC_PLUGIN_)
# include <vlc_common.h>
# include <vlc_threads.h>
#else
# include "AtmoPacketQueueStatus.h"
#endif
struct ColorPacketItem {
pColorPacket packet;
#if defined(_ATMO_VLC_PLUGIN_)
mtime_t tickcount;
#else
DWORD tickcount;
#endif
ColorPacketItem *next;
};
typedef ColorPacketItem* pColorPacketItem;
class CAtmoPacketQueue
{
public:
#if defined(_ATMO_VLC_PLUGIN_)
CAtmoPacketQueue();
#else
CAtmoPacketQueue(CAtmoPacketQueueStatus *statusMonitor);
#endif
~CAtmoPacketQueue(void);
protected:
int m_waitcounter;
int m_skipcounter;
int m_framecounter;
int m_nullpackets;
DWORD m_avgWait;
DWORD m_avgDelay;
#if !defined(_ATMO_VLC_PLUGIN_)
CAtmoPacketQueueStatus *m_StatusMonitor;
#endif
private:
volatile pColorPacketItem m_first;
volatile pColorPacketItem m_last;
#if defined(_ATMO_VLC_PLUGIN_)
vlc_cond_t m_PacketArrivedCond;
vlc_mutex_t m_PacketArrivedLock;
volatile ATMO_BOOL m_PacketArrived;
vlc_mutex_t m_Lock;
#else
CRITICAL_SECTION m_lock;
HANDLE m_hPacketArrivedEvent;
#endif
private:
void Lock();
void Unlock();
void SignalEvent();
void UnSignalEvent();
private:
pColorPacket GetNextPacket();
pColorPacketItem GetNextPacketContainer();
public:
void AddPacket(pColorPacket newPacket);
// timecode = GetTickCount() - framedelay;
#if defined(_ATMO_VLC_PLUGIN_)
void ShowQueueStatus(vlc_object_t *p_this);
pColorPacket GetNextPacket(mtime_t timecode, ATMO_BOOL withWait, vlc_object_t *p_this, mtime_t &packet_time );
#else
pColorPacket GetNextPacket(DWORD timecode, ATMO_BOOL withWait, DWORD &packet_time );
#endif
void ClearQueue();
ATMO_BOOL WaitForNextPacket(DWORD timeout);
};
#endif
/*
* AtmoThread.cpp: Base thread class for all threads inside AtmoWin
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <assert.h>
#include "AtmoThread.h"
#if defined(_ATMO_VLC_PLUGIN_)
CThread::CThread(vlc_object_t *pOwner)
{
m_bTerminated = ATMO_FALSE;
vlc_mutex_init( &m_TerminateLock );
vlc_cond_init( &m_TerminateCond );
m_pOwner = pOwner;
m_HasThread = ATMO_FALSE;
}
#else
CThread::CThread(void)
{
m_bTerminated = ATMO_FALSE;
m_hThread = CreateThread(NULL, 0, CThread::ThreadProc ,
this, CREATE_SUSPENDED, &m_dwThreadID);
m_hTerminateEvent = CreateEvent(NULL,0,0,NULL);
}
#endif
#if defined(_ATMO_VLC_PLUGIN_)
CThread::~CThread(void)
{
assert(m_HasThread == ATMO_FALSE);
vlc_mutex_destroy( &m_TerminateLock );
vlc_cond_destroy( &m_TerminateCond );
}
#else
CThread::~CThread(void)
{
CloseHandle(m_hThread);
CloseHandle(m_hTerminateEvent);
}
#endif
#if defined(_ATMO_VLC_PLUGIN_)
void *CThread::ThreadProc(void *obj)
{
CThread *pThread = static_cast<CThread*>(obj);
int canc = vlc_savecancel ();
pThread->Execute();
vlc_restorecancel (canc);
return NULL;
}
#else
DWORD WINAPI CThread::ThreadProc(LPVOID lpParameter)
{
CThread *pThread = (CThread *)lpParameter;
if(pThread)
return pThread->Execute();
else
return (DWORD)-1;
}
#endif
DWORD CThread::Execute(void)
{
/*
to do implement! override!
while(!bTerminated) {
...
}
*/
return 0;
}
void CThread::Terminate(void)
{
// Set Termination Flag and EventObject!
// and wait for Termination
#if defined(_ATMO_VLC_PLUGIN_)
if(m_HasThread != ATMO_FALSE)
{
vlc_mutex_lock( &m_TerminateLock );
m_bTerminated = ATMO_TRUE;
vlc_cond_signal( &m_TerminateCond );
vlc_mutex_unlock( &m_TerminateLock );
vlc_cancel( m_Thread );
vlc_join( m_Thread, NULL );
}
#else
m_bTerminated = ATMO_TRUE;
SetEvent(m_hTerminateEvent);
WaitForSingleObject(m_hThread,INFINITE);
#endif
}
void CThread::Run()
{
m_bTerminated = ATMO_FALSE;
#if defined(_ATMO_VLC_PLUGIN_)
if (vlc_clone( &m_Thread, CThread::ThreadProc, this, VLC_THREAD_PRIORITY_LOW))
{
m_HasThread = ATMO_FALSE;
msg_Err( m_pOwner, "cannot launch one of the AtmoLight threads");
}
else
{
m_HasThread = ATMO_TRUE;;
}
#else
ResetEvent(m_hTerminateEvent);
ResumeThread(m_hThread);
#endif
}
/*
does a sleep if the sleep was interrupted through
the thread kill event return false...
*/
ATMO_BOOL CThread::ThreadSleep(DWORD millisekunden)
{
#if defined(_ATMO_VLC_PLUGIN_)
ATMO_BOOL temp;
vlc_mutex_lock( &m_TerminateLock );
vlc_cond_timedwait(&m_TerminateCond,
&m_TerminateLock,
mdate() + (mtime_t)(millisekunden * 1000));
temp = m_bTerminated;
vlc_mutex_unlock( &m_TerminateLock );
return !temp;
#else
DWORD res = WaitForSingleObject(m_hTerminateEvent,millisekunden);
return (res == WAIT_TIMEOUT);
#endif
}
/*
* AtmoThread.h: Base thread class for all threads inside AtmoWin
*
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifndef _AtmoThread_h_
#define _AtmoThread_h_
#include "AtmoDefs.h"
#if defined(_ATMO_VLC_PLUGIN_)
// use threading stuff from videolan!
# include <vlc_common.h>
# include <vlc_threads.h>
#else
# include <windows.h>
#endif
class CThread
{
protected:
#if defined(_ATMO_VLC_PLUGIN_)
vlc_mutex_t m_TerminateLock;
vlc_cond_t m_TerminateCond;
vlc_object_t *m_pOwner;
ATMO_BOOL m_HasThread;
vlc_thread_t m_Thread;
#else
HANDLE m_hThread;
DWORD m_dwThreadID;
HANDLE m_hTerminateEvent;
#endif
volatile ATMO_BOOL m_bTerminated;
private:
#if defined(_ATMO_VLC_PLUGIN_)
static void *ThreadProc(void *);
#else
static DWORD WINAPI ThreadProc(LPVOID lpParameter);
#endif
protected:
virtual DWORD Execute(void);
ATMO_BOOL ThreadSleep(DWORD millisekunden);
public:
#if defined(_ATMO_VLC_PLUGIN_)
CThread(vlc_object_t *pOwner);
#else
CThread(void);
#endif
virtual ~CThread(void);
void Terminate(void);
void Run();
};
#endif
/*
* AtmoTools.cpp: Collection of tool and helperfunction
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "AtmoTools.h"
#include "AtmoDynData.h"
#include "AtmoLiveView.h"
#include "AtmoClassicConnection.h"
#include "AtmoDmxSerialConnection.h"
#include "AtmoMultiConnection.h"
#include "MoMoConnection.h"
#include "FnordlichtConnection.h"
#include "AtmoExternalCaptureInput.h"
#include <math.h>
#if !defined(_ATMO_VLC_PLUGIN_)
# include "AtmoColorChanger.h"
# include "AtmoLeftRightColorChanger.h"
# include "AtmoDummyConnection.h"
# include "AtmoNulConnection.h"
# include "MondolightConnection.h"
# include "AtmoGdiDisplayCaptureInput.h"
#endif
CAtmoTools::CAtmoTools(void)
{
}
CAtmoTools::~CAtmoTools(void)
{
}
void CAtmoTools::ShowShutdownColor(CAtmoDynData *pDynData)
{
pDynData->LockCriticalSection();
CAtmoConnection *atmoConnection = pDynData->getAtmoConnection();
CAtmoConfig *atmoConfig = pDynData->getAtmoConfig();
if((atmoConnection != NULL) && (atmoConfig!=NULL) && atmoConfig->isSetShutdownColor()) {
int i;
pColorPacket packet;
AllocColorPacket(packet, atmoConfig->getZoneCount());
// set a special color? on shutdown of the software? mostly may use black or so ...
// if this function ist disabled ... atmo will continuing to show the last color...
for(i = 0; i < packet->numColors; i++) {
packet->zone[i].r = atmoConfig->getShutdownColor_Red();
packet->zone[i].g = atmoConfig->getShutdownColor_Green();
packet->zone[i].b = atmoConfig->getShutdownColor_Blue();
}
packet = CAtmoTools::ApplyGamma(atmoConfig, packet);
if(atmoConfig->isUseSoftwareWhiteAdj())
packet = CAtmoTools::WhiteCalibration(atmoConfig, packet);
atmoConnection->SendData(packet);
delete [] packet;
}
pDynData->UnLockCriticalSection();
}
EffectMode CAtmoTools::SwitchEffect(CAtmoDynData *pDynData, EffectMode newEffectMode)
{
// may need a critical section??
if(pDynData == NULL) {
return emUndefined;
}
pDynData->LockCriticalSection();
CAtmoConfig *atmoConfig = pDynData->getAtmoConfig();
if(atmoConfig == NULL) {
pDynData->UnLockCriticalSection();
return emUndefined;
}
CAtmoConnection *atmoConnection = pDynData->getAtmoConnection();
EffectMode oldEffectMode = atmoConfig->getEffectMode();
CThread *currentEffect = pDynData->getEffectThread();
CAtmoInput *currentInput = pDynData->getLiveInput();
CAtmoPacketQueue *currentPacketQueue = pDynData->getLivePacketQueue();
if(oldEffectMode == emLivePicture) {
/* in case of disabling the live mode
first we have to stop the input
then the effect thread!
*/
if(currentInput != NULL) {
pDynData->setLiveInput( NULL );
currentInput->Close();
delete currentInput;
currentInput = NULL;
}
}
// stop and delete/cleanup current Effect Thread...
pDynData->setEffectThread( NULL );
if(currentEffect != NULL) {
currentEffect->Terminate();
delete currentEffect;
currentEffect = NULL;
}
if(oldEffectMode == emLivePicture) {
/*
and last we kill the PacketQueue used for communication between the threads
*/
pDynData->setLivePacketQueue( NULL );
delete currentPacketQueue;
currentPacketQueue = NULL;
}
if((atmoConnection!=NULL) && (atmoConnection->isOpen()==ATMO_TRUE)) {
// neuen EffectThread nur mit aktiver Connection starten...
switch(newEffectMode) {
case emUndefined: // do nothing also in that case (avoid compiler warning)
break;
case emDisabled:
break;
case emStaticColor: {
// get values from config - and put them to all channels?
pColorPacket packet;
AllocColorPacket(packet, atmoConfig->getZoneCount());
for(int i=0; i < packet->numColors; i++){
packet->zone[i].r = atmoConfig->getStaticColor_Red();
packet->zone[i].g = atmoConfig->getStaticColor_Green();
packet->zone[i].b = atmoConfig->getStaticColor_Blue();
}
packet = CAtmoTools::ApplyGamma( atmoConfig, packet );
if(atmoConfig->isUseSoftwareWhiteAdj())
packet = CAtmoTools::WhiteCalibration(atmoConfig, packet);
atmoConnection->SendData( packet );
delete [] packet;
break;
}
case emLivePicture: {
currentEffect = new CAtmoLiveView(pDynData);
#if !defined(_ATMO_VLC_PLUGIN_)
CAtmoPacketQueueStatus *packetMon = NULL;
if(atmoConfig->getShow_statistics()) {
packetMon = new CAtmoPacketQueueStatus(pDynData->getHinstance(), (HWND)NULL);
packetMon->createWindow();
packetMon->showWindow(SW_SHOW);
}
currentPacketQueue = new CAtmoPacketQueue(packetMon);
pDynData->setLivePictureSource(lpsScreenCapture);
currentInput = new CAtmoGdiDisplayCaptureInput( pDynData );
#else
currentPacketQueue = new CAtmoPacketQueue();
pDynData->setLivePictureSource(lpsExtern);
currentInput = new CAtmoExternalCaptureInput( pDynData );
#endif
break;
}
#if !defined(_ATMO_VLC_PLUGIN_)
case emColorChange:
currentEffect = new CAtmoColorChanger(atmoConnection, atmoConfig);
break;
case emLrColorChange:
currentEffect = new CAtmoLeftRightColorChanger(atmoConnection, atmoConfig);
break;
#endif
}
}
atmoConfig->setEffectMode( newEffectMode );
pDynData->setLivePacketQueue( currentPacketQueue );
pDynData->setEffectThread( currentEffect );
pDynData->setLiveInput( currentInput );
if(currentEffect != NULL)
currentEffect->Run();
if(currentInput != NULL)
currentInput->Open();
pDynData->UnLockCriticalSection();
return oldEffectMode;
}
LivePictureSource CAtmoTools::SwitchLiveSource(CAtmoDynData *pDynData, LivePictureSource newLiveSource)
{
LivePictureSource oldSource;
pDynData->LockCriticalSection();
oldSource = pDynData->getLivePictureSource();
pDynData->setLivePictureSource( newLiveSource );
if ((pDynData->getAtmoConfig()->getEffectMode() == emLivePicture) &&
(pDynData->getEffectThread() != NULL) &&
(pDynData->getLivePacketQueue() != NULL))
{
CAtmoInput *input = pDynData->getLiveInput();
pDynData->setLiveInput( NULL );
if(input != NULL) {
input->Close();
delete input;
input = NULL;
}
switch(pDynData->getLivePictureSource()) {
case lpsDisabled: // do nothing in that case - avoid compiler warning
break;
#if !defined(_ATMO_VLC_PLUGIN_)
case lpsScreenCapture:
input = new CAtmoGdiDisplayCaptureInput( pDynData );
break;
#endif
case lpsExtern:
input = new CAtmoExternalCaptureInput( pDynData );
break;
}
pDynData->setLiveInput( input );
if(input != NULL)
input->Open();
}
pDynData->UnLockCriticalSection();
return oldSource;
}
ATMO_BOOL CAtmoTools::RecreateConnection(CAtmoDynData *pDynData)
{
pDynData->LockCriticalSection();
CAtmoConnection *current = pDynData->getAtmoConnection();
CAtmoConfig *atmoConfig = pDynData->getAtmoConfig();
AtmoConnectionType act = atmoConfig->getConnectionType();
pDynData->setAtmoConnection(NULL);
if(current != NULL) {
current->CloseConnection();
delete current;
}
switch(act) {
case actClassicAtmo: {
CAtmoClassicConnection *tempConnection = new CAtmoClassicConnection( atmoConfig );
if(tempConnection->OpenConnection() == ATMO_FALSE) {
#if !defined(_ATMO_VLC_PLUGIN_)
if(atmoConfig->getIgnoreConnectionErrorOnStartup() == ATMO_FALSE)
{
char errorMsgBuf[200];
sprintf(errorMsgBuf,"Failed to open serial port com%d with errorcode: %d (0x%x)",
pDynData->getAtmoConfig()->getComport(),
tempConnection->getLastError(),
tempConnection->getLastError()
);
MessageBox(0,errorMsgBuf,"Error",MB_ICONERROR | MB_OK);
}
#endif
pDynData->setAtmoConnection(tempConnection);
pDynData->UnLockCriticalSection();
return ATMO_FALSE;
}
pDynData->setAtmoConnection(tempConnection);
pDynData->ReloadZoneDefinitionBitmaps();
tempConnection->CreateDefaultMapping(atmoConfig->getChannelAssignment(0));
CAtmoTools::SetChannelAssignment(pDynData,
atmoConfig->getCurrentChannelAssignment());
pDynData->UnLockCriticalSection();
return ATMO_TRUE;
}
#if !defined(_ATMO_VLC_PLUGIN_)
case actDummy:
{
// actDummy8,actDummy12,actDummy16
CAtmoDummyConnection *tempConnection = new CAtmoDummyConnection(pDynData->getHinstance(),
atmoConfig);
if(tempConnection->OpenConnection() == ATMO_FALSE) {
pDynData->setAtmoConnection(tempConnection);
pDynData->UnLockCriticalSection();
return ATMO_FALSE;
}
pDynData->setAtmoConnection(tempConnection);
pDynData->ReloadZoneDefinitionBitmaps();
tempConnection->CreateDefaultMapping(atmoConfig->getChannelAssignment(0));
CAtmoTools::SetChannelAssignment(pDynData, pDynData->getAtmoConfig()->getCurrentChannelAssignment());
pDynData->UnLockCriticalSection();
return ATMO_TRUE;
}
#endif
case actDMX: {
// create here your DMX connections... instead of the dummy....
CAtmoDmxSerialConnection *tempConnection = new CAtmoDmxSerialConnection( atmoConfig );
if(tempConnection->OpenConnection() == ATMO_FALSE) {
pDynData->setAtmoConnection(tempConnection);
pDynData->UnLockCriticalSection();
return ATMO_FALSE;
}
pDynData->setAtmoConnection(tempConnection);
pDynData->ReloadZoneDefinitionBitmaps();
tempConnection->CreateDefaultMapping(atmoConfig->getChannelAssignment(0));
CAtmoTools::SetChannelAssignment(pDynData, atmoConfig->getCurrentChannelAssignment());
pDynData->UnLockCriticalSection();
return ATMO_TRUE;
}
#if !defined(_ATMO_VLC_PLUGIN_)
case actNUL: {
CAtmoNulConnection *tempConnection = new CAtmoNulConnection( atmoConfig );
if(tempConnection->OpenConnection() == ATMO_FALSE) {
pDynData->setAtmoConnection(tempConnection);
pDynData->UnLockCriticalSection();
return ATMO_FALSE;
}
pDynData->setAtmoConnection(tempConnection);
pDynData->ReloadZoneDefinitionBitmaps();
tempConnection->CreateDefaultMapping(atmoConfig->getChannelAssignment(0));
CAtmoTools::SetChannelAssignment(pDynData, atmoConfig->getCurrentChannelAssignment());
pDynData->UnLockCriticalSection();
return ATMO_TRUE;
}
#endif
case actMultiAtmo: {
CAtmoMultiConnection *tempConnection = new CAtmoMultiConnection( atmoConfig );
if(tempConnection->OpenConnection() == ATMO_FALSE) {
pDynData->setAtmoConnection(tempConnection);
pDynData->UnLockCriticalSection();
return ATMO_FALSE;
}
pDynData->setAtmoConnection(tempConnection);
pDynData->ReloadZoneDefinitionBitmaps();
tempConnection->CreateDefaultMapping(atmoConfig->getChannelAssignment(0));
CAtmoTools::SetChannelAssignment(pDynData, atmoConfig->getCurrentChannelAssignment());
pDynData->UnLockCriticalSection();
return ATMO_TRUE;
}
#if !defined(_ATMO_VLC_PLUGIN_)
case actMondolight: {
CMondolightConnection *tempConnection = new CMondolightConnection( atmoConfig );
if(tempConnection->OpenConnection() == ATMO_FALSE) {
pDynData->setAtmoConnection(tempConnection);
pDynData->UnLockCriticalSection();
return ATMO_FALSE;
}
pDynData->setAtmoConnection(tempConnection);
pDynData->ReloadZoneDefinitionBitmaps();
tempConnection->CreateDefaultMapping(atmoConfig->getChannelAssignment(0));
CAtmoTools::SetChannelAssignment(pDynData, atmoConfig->getCurrentChannelAssignment());
pDynData->UnLockCriticalSection();
return ATMO_TRUE;
}
#endif
case actMoMoLight: {
CMoMoConnection *tempConnection = new CMoMoConnection( atmoConfig );
if(tempConnection->OpenConnection() == ATMO_FALSE) {
pDynData->setAtmoConnection(tempConnection);
pDynData->UnLockCriticalSection();
return ATMO_FALSE;
}
pDynData->setAtmoConnection(tempConnection);
pDynData->ReloadZoneDefinitionBitmaps();
tempConnection->CreateDefaultMapping( atmoConfig->getChannelAssignment(0) );
CAtmoTools::SetChannelAssignment(pDynData, atmoConfig->getCurrentChannelAssignment() );
pDynData->UnLockCriticalSection();
return ATMO_TRUE;
}
case actFnordlicht: {
CFnordlichtConnection *tempConnection = new CFnordlichtConnection( atmoConfig );
if(tempConnection->OpenConnection() == ATMO_FALSE) {
pDynData->setAtmoConnection(tempConnection);
pDynData->UnLockCriticalSection();
return ATMO_FALSE;
}
pDynData->setAtmoConnection(tempConnection);
pDynData->ReloadZoneDefinitionBitmaps();
tempConnection->CreateDefaultMapping( atmoConfig->getChannelAssignment(0) );
CAtmoTools::SetChannelAssignment(pDynData, atmoConfig->getCurrentChannelAssignment() );
pDynData->UnLockCriticalSection();
return ATMO_TRUE;
}
default: {
pDynData->UnLockCriticalSection();
return ATMO_FALSE;
}
}
}
pColorPacket CAtmoTools::WhiteCalibration(CAtmoConfig *pAtmoConfig, pColorPacket ColorPacket)
{
int w_adj_red = pAtmoConfig->getWhiteAdjustment_Red();
int w_adj_green = pAtmoConfig->getWhiteAdjustment_Green();
int w_adj_blue = pAtmoConfig->getWhiteAdjustment_Blue();
for (int i = 0; i < ColorPacket->numColors; i++) {
ColorPacket->zone[i].r = (unsigned char)(((int)w_adj_red * (int)ColorPacket->zone[i].r) / 255);
ColorPacket->zone[i].g = (unsigned char)(((int)w_adj_green * (int)ColorPacket->zone[i].g) / 255);
ColorPacket->zone[i].b = (unsigned char)(((int)w_adj_blue * (int)ColorPacket->zone[i].b) / 255);
}
return ColorPacket;
}
pColorPacket CAtmoTools::ApplyGamma(CAtmoConfig *pAtmoConfig, pColorPacket ColorPacket)
{
double v;
switch(pAtmoConfig->getSoftware_gamma_mode()) {
case agcNone: break;
case agcPerColor: {
double GammaRed = 10.0 / ((double)pAtmoConfig->getSoftware_gamma_red());
double GammaGreen = 10.0 / ((double)pAtmoConfig->getSoftware_gamma_green());
double GammaBlue = 10.0 / ((double)pAtmoConfig->getSoftware_gamma_blue());
for (int i = 0; i < ColorPacket->numColors; i++)
{
v = ColorPacket->zone[i].r;
v = (pow( v / 255.0f, GammaRed ) * 255.0f);
ColorPacket->zone[i].r = ATMO_MIN((int)v, 255);
v = ColorPacket->zone[i].g;
v = (pow( v / 255.0f, GammaGreen ) * 255.0f);
ColorPacket->zone[i].g = ATMO_MIN((int)v, 255);
v = ColorPacket->zone[i].b;
v = (pow( v / 255.0f, GammaBlue ) * 255.0f);
ColorPacket->zone[i].b = ATMO_MIN((int)v, 255);
}
break;
}
case agcGlobal: {
double Gamma = 10.0 / ((double)pAtmoConfig->getSoftware_gamma_global());
for (int i = 0; i < ColorPacket->numColors; i++)
{
v = ColorPacket->zone[i].r;
v = (pow( v / 255.0f, Gamma ) * 255.0f);
ColorPacket->zone[i].r = ATMO_MIN((int)v, 255);
v = ColorPacket->zone[i].g;
v = (pow( v / 255.0f, Gamma ) * 255.0f);
ColorPacket->zone[i].g = ATMO_MIN((int)v, 255);
v = ColorPacket->zone[i].b;
v = (pow( v / 255.0f, Gamma ) * 255.0f);
ColorPacket->zone[i].b = ATMO_MIN((int)v, 255);
}
break;
}
}
return ColorPacket;
}
int CAtmoTools::SetChannelAssignment(CAtmoDynData *pDynData, int index)
{
CAtmoConfig *pAtmoConfig = pDynData->getAtmoConfig();
CAtmoConnection *pAtmoConnection = pDynData->getAtmoConnection();
int oldIndex = pAtmoConfig->getCurrentChannelAssignment();
CAtmoChannelAssignment *ca = pAtmoConfig->getChannelAssignment(index);
if((ca!=NULL) && (pAtmoConnection!=NULL)) {
pAtmoConnection->SetChannelAssignment(ca);
pAtmoConfig->setCurrentChannelAssignment(index);
}
return oldIndex;
}
#if !defined(_ATMO_VLC_PLUGIN_)
void CAtmoTools::SaveBitmap(HDC hdc,HBITMAP hBmp,char *fileName) {
BITMAPINFO bmpInfo;
BITMAPFILEHEADER bmpFileHeader;
ZeroMemory(&bmpInfo, sizeof(BITMAPINFO));
bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
GetDIBits(hdc,hBmp,0,0,NULL,&bmpInfo,DIB_RGB_COLORS);
if(bmpInfo.bmiHeader.biSizeImage<=0)
bmpInfo.bmiHeader.biSizeImage=bmpInfo.bmiHeader.biWidth * abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8;
void *pBuf = malloc(bmpInfo.bmiHeader.biSizeImage);
bmpInfo.bmiHeader.biCompression=BI_RGB;
GetDIBits(hdc,hBmp,0,bmpInfo.bmiHeader.biHeight,pBuf, &bmpInfo, DIB_RGB_COLORS);
bmpFileHeader.bfReserved1=0;
bmpFileHeader.bfReserved2=0;
bmpFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+bmpInfo.bmiHeader.biSizeImage;
bmpFileHeader.bfType = MakeIntelWord('M','B');
bmpFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
FILE *fp = NULL;
fp = fopen(fileName,"wb");
fwrite(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp);
fwrite(&bmpInfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);
fwrite(pBuf,bmpInfo.bmiHeader.biSizeImage,1,fp);
fclose(fp);
free(pBuf);
}
#endif
/*
* AtmoTools.h: Collection of tool and helperfunction
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifndef _AtmoTools_h_
#define _AtmoTools_h_
#include "AtmoDefs.h"
#include "AtmoConfig.h"
#include "AtmoConnection.h"
#include "AtmoDynData.h"
/*
implements some tool functions - for use in different classes - and cases!
to avoid copy and paste code ...
*/
class CAtmoTools
{
private:
CAtmoTools(void);
~CAtmoTools(void);
public:
static EffectMode SwitchEffect(CAtmoDynData *pDynData, EffectMode newEffectMode);
static LivePictureSource SwitchLiveSource(CAtmoDynData *pDynData, LivePictureSource newLiveSource);
static void ShowShutdownColor(CAtmoDynData *pDynData);
static ATMO_BOOL RecreateConnection(CAtmoDynData *pDynData);
static pColorPacket WhiteCalibration(CAtmoConfig *pAtmoConfig, pColorPacket ColorPacket);
static pColorPacket ApplyGamma(CAtmoConfig *pAtmoConfig, pColorPacket ColorPacket);
static int SetChannelAssignment(CAtmoDynData *pDynData, int index);
#if !defined(_ATMO_VLC_PLUGIN_)
static void SaveBitmap(HDC hdc,HBITMAP hBmp,char *fileName);
#endif
};
#endif
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "AtmoDefs.h"
#if defined (_WIN32)
# include <windows.h>
#else
# include <vlc_codecs.h>
#endif
#include <math.h>
#include <stdio.h>
#include "AtmoZoneDefinition.h"
CAtmoZoneDefinition::CAtmoZoneDefinition(void)
{
}
CAtmoZoneDefinition::~CAtmoZoneDefinition(void)
{
}
void CAtmoZoneDefinition::Fill(unsigned char value)
{
for(int i=0; i < IMAGE_SIZE; i++)
m_BasicWeight[i] = value;
}
// max weight to left
void CAtmoZoneDefinition::FillGradientFromLeft(int start_row,int end_row)
{
int index;
unsigned char col_norm;
index = start_row * CAP_WIDTH;
for(int row=start_row; row < end_row; row++) {
for(int col=0; col < CAP_WIDTH; col++) {
// should be a value between 0 .. 255?
col_norm = (255 * (CAP_WIDTH-col-1)) / (CAP_WIDTH-1);
m_BasicWeight[index++] = col_norm;
}
}
}
// max weight to right
void CAtmoZoneDefinition::FillGradientFromRight(int start_row,int end_row)
{
int index;
unsigned char col_norm;
index = start_row * CAP_WIDTH;
for(int row=start_row; row < end_row; row++) {
for(int col=0; col < CAP_WIDTH; col++) {
col_norm = (255 * col) / (CAP_WIDTH-1); // should be a value between 0 .. 255?
m_BasicWeight[index++] = col_norm;
}
}
}
// max weight from top
void CAtmoZoneDefinition::FillGradientFromTop(int start_col,int end_col)
{
int index;
unsigned char row_norm;
for(int row=0; row < CAP_HEIGHT; row++) {
index = row * CAP_WIDTH + start_col;
row_norm = (255 * (CAP_HEIGHT-row-1)) / (CAP_HEIGHT-1); // should be a value between 0 .. 255?
for(int col=start_col; col < end_col; col++) {
m_BasicWeight[index++] = row_norm;
}
}
}
// max weight from bottom
void CAtmoZoneDefinition::FillGradientFromBottom(int start_col,int end_col)
{
int index;
unsigned char row_norm;
for(int row=0; row < CAP_HEIGHT; row++) {
index = row * CAP_WIDTH + start_col;
row_norm = (255 * row) / (CAP_HEIGHT-1); // should be a value between 0 .. 255?
for(int col=start_col; col < end_col; col++) {
m_BasicWeight[index++] = row_norm;
}
}
}
#if !defined(_ATMO_VLC_PLUGIN_)
void CAtmoZoneDefinition::SaveZoneBitmap(char *fileName)
{
if(!fileName) return;
BITMAPINFO bmpInfo;
// BITMAPINFOHEADER
BITMAPFILEHEADER bmpFileHeader;
ZeroMemory(&bmpInfo, sizeof(BITMAPINFO));
bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biHeight = -CAP_HEIGHT;
bmpInfo.bmiHeader.biWidth = CAP_WIDTH;
bmpInfo.bmiHeader.biSizeImage = abs(bmpInfo.bmiHeader.biHeight) * bmpInfo.bmiHeader.biWidth * 3;
unsigned char *pBuf = (unsigned char *)malloc(bmpInfo.bmiHeader.biSizeImage);
for(int y=0; y < CAP_HEIGHT; y++ )
{
for(int x=0; x < CAP_WIDTH; x++)
{
pBuf[y * CAP_WIDTH * 3 + x * 3 ] = 0;
pBuf[y * CAP_WIDTH * 3 + x * 3 + 1 ] = m_BasicWeight[y * CAP_WIDTH + x];
pBuf[y * CAP_WIDTH * 3 + x * 3 + 2] = 0;
}
}
bmpInfo.bmiHeader.biCompression = BI_RGB;
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biBitCount = 24;
bmpFileHeader.bfReserved1=0;
bmpFileHeader.bfReserved2=0;
bmpFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+bmpInfo.bmiHeader.biSizeImage;
bmpFileHeader.bfType = MakeIntelWord('M','B');
bmpFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
FILE *fp = NULL;
fp = fopen(fileName,"wb");
fwrite(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp);
fwrite(&bmpInfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);
fwrite(pBuf,bmpInfo.bmiHeader.biSizeImage,1,fp);
fclose(fp);
free(pBuf);
}
void CAtmoZoneDefinition::SaveWeightBitmap(char *fileName,int *weight)
{
if(!fileName || !weight) return;
BITMAPINFO bmpInfo;
// BITMAPINFOHEADER
BITMAPFILEHEADER bmpFileHeader;
ZeroMemory(&bmpInfo, sizeof(BITMAPINFO));
bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biHeight = -CAP_HEIGHT;
bmpInfo.bmiHeader.biWidth = CAP_WIDTH;
bmpInfo.bmiHeader.biSizeImage = abs(bmpInfo.bmiHeader.biHeight) * bmpInfo.bmiHeader.biWidth * 3;
unsigned char *pBuf = (unsigned char *)malloc(bmpInfo.bmiHeader.biSizeImage);
for(int y=0; y < CAP_HEIGHT; y++ )
{
for(int x=0; x < CAP_WIDTH; x++)
{
pBuf[y * CAP_WIDTH * 3 + x * 3 ] = 0;
pBuf[y * CAP_WIDTH * 3 + x * 3 + 1 ] = (unsigned char)weight[y * CAP_WIDTH + x];
pBuf[y * CAP_WIDTH * 3 + x * 3 + 2] = 0;
}
}
bmpInfo.bmiHeader.biCompression = BI_RGB;
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biBitCount = 24;
bmpFileHeader.bfReserved1=0;
bmpFileHeader.bfReserved2=0;
bmpFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+bmpInfo.bmiHeader.biSizeImage;
bmpFileHeader.bfType = MakeIntelWord('M','B');
bmpFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
FILE *fp = NULL;
fp = fopen(fileName,"wb");
fwrite(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp);
fwrite(&bmpInfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);
fwrite(pBuf,bmpInfo.bmiHeader.biSizeImage,1,fp);
fclose(fp);
free(pBuf);
}
#endif
int CAtmoZoneDefinition::LoadGradientFromBitmap(char *pszBitmap)
{
// transform 256 color image (gray scale!)
// into m_basicWeight or use the GREEN value of a 24bit image!
// channel of a true color bitmap!
VLC_BITMAPINFO bmpInfo;
BITMAPFILEHEADER bmpFileHeader;
/*
ATMO_LOAD_GRADIENT_FILENOTFOND
#define ATMO_LOAD_GRADIENT_OK 0
#define ATMO_LOAD_GRADIENT_FAILED_SIZE 1
#define ATMO_LOAD_GRADIENT_FAILED_HEADER 2
*/
FILE *bmp = fopen(pszBitmap, "rb");
if(!bmp)
return ATMO_LOAD_GRADIENT_FILENOTFOND;
if(fread(&bmpFileHeader, sizeof(BITMAPFILEHEADER), 1, bmp) != 1)
{
fclose(bmp);
return ATMO_LOAD_GRADIENT_FAILED_SIZE;
}
if(bmpFileHeader.bfType != MakeIntelWord('M','B'))
{
fclose(bmp);
return ATMO_LOAD_GRADIENT_FAILED_HEADER;
}
if(fread(&bmpInfo, sizeof(VLC_BITMAPINFO), 1, bmp) != 1)
{
fclose(bmp);
return ATMO_LOAD_GRADIENT_FAILED_SIZE;
}
if(bmpInfo.bmiHeader.biCompression != BI_RGB)
{
fclose(bmp);
return ATMO_LOAD_GRADIENT_FAILED_FORMAT;
}
if((bmpInfo.bmiHeader.biBitCount != 8) && (bmpInfo.bmiHeader.biBitCount != 24))
{
fclose(bmp);
return ATMO_LOAD_GRADIENT_FAILED_FORMAT;
}
int width = bmpInfo.bmiHeader.biWidth;
int height = bmpInfo.bmiHeader.biHeight;
ATMO_BOOL invertDirection = (height > 0);
height = abs(height);
if((width != CAP_WIDTH) || (height != CAP_HEIGHT))
{
fclose(bmp);
return ATMO_LOAD_GRADIENT_FAILED_SIZE;
}
fseek(bmp, bmpFileHeader.bfOffBits, SEEK_SET);
int imageSize = width * height * bmpInfo.bmiHeader.biBitCount/8;
unsigned char *pixelBuffer = (unsigned char *)malloc(imageSize);
if(fread(pixelBuffer,imageSize,1,bmp) != 1)
{
free(pixelBuffer);
fclose(bmp);
return ATMO_LOAD_GRADIENT_FAILED_SIZE;
}
if(bmpInfo.bmiHeader.biBitCount == 8)
{
int ydest;
for(int y=0;y < CAP_HEIGHT; y++) {
if(invertDirection) {
ydest = (CAP_HEIGHT - y - 1);
} else {
ydest = y;
}
for(int x=0;x < CAP_WIDTH; x++) {
// palette should be grey scale - so that index 0 is black and
// index 255 means white!
// everything else would produce funny results!
m_BasicWeight[ydest * CAP_WIDTH + x] =
pixelBuffer[y * CAP_WIDTH + x];
}
}
}
if(bmpInfo.bmiHeader.biBitCount == 24)
{
int ydest;
for(int y=0;y < CAP_HEIGHT; y++) {
if(invertDirection) {
ydest = (CAP_HEIGHT - y - 1);
} else {
ydest = y;
}
for(int x=0;x < CAP_WIDTH; x++) {
// use the green value as reference...
m_BasicWeight[ydest * CAP_WIDTH + x] =
pixelBuffer[y * CAP_WIDTH * 3 + (x*3) + 1 ];
}
}
}
free(pixelBuffer);
fclose(bmp);
return ATMO_LOAD_GRADIENT_OK;
}
void CAtmoZoneDefinition::UpdateWeighting(int *destWeight,
int WidescreenMode,
int newEdgeWeightning)
{
/*
use the values in m_BasicWeight and newWeightning to
update the direct control array for the output thread!
*/
int index = 0;
for(int row=0; row < CAP_HEIGHT; row++) {
for(int col=0; col < CAP_WIDTH; col++) {
if ((WidescreenMode == 1) && ((row <= CAP_HEIGHT/8) || (row >= (7*CAP_HEIGHT)/8)))
{
destWeight[index] = 0;
} else {
destWeight[index] = (int)(255.0 * (float)pow( ((float)m_BasicWeight[index])/255.0 , newEdgeWeightning));
}
index++;
}
}
}
void CAtmoZoneDefinition::setZoneNumber(int num)
{
m_zonenumber = num;
}
int CAtmoZoneDefinition::getZoneNumber()
{
return m_zonenumber;
}
#ifndef _AtmoZoneDefinition_h_
#define _AtmoZoneDefinition_h_
#include "AtmoDefs.h"
#define ATMO_LOAD_GRADIENT_OK 0
#define ATMO_LOAD_GRADIENT_FILENOTFOND 1
#define ATMO_LOAD_GRADIENT_FAILED_SIZE 2
#define ATMO_LOAD_GRADIENT_FAILED_HEADER 3
#define ATMO_LOAD_GRADIENT_FAILED_FORMAT 4
class CAtmoZoneDefinition
{
private:
int m_zonenumber; // just for identification and channel assignment!
unsigned char m_BasicWeight[IMAGE_SIZE];
public:
CAtmoZoneDefinition(void);
~CAtmoZoneDefinition(void);
void Fill(unsigned char value);
void FillGradientFromLeft(int start_row,int end_row);
void FillGradientFromRight(int start_row,int end_row);
void FillGradientFromTop(int start_col,int end_col);
void FillGradientFromBottom(int start_col,int end_col);
int LoadGradientFromBitmap(char *pszBitmap);
#if !defined(_ATMO_VLC_PLUGIN_)
void SaveZoneBitmap(char *);
void SaveWeightBitmap(char *fileName,int *weight);
#endif
void UpdateWeighting(int *destWeight,
int WidescreenMode,
int newEdgeWeightning);
void setZoneNumber(int num);
int getZoneNumber();
};
#endif
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
/*
* DmxTools.cpp: functions to convert , or ; separated numbers into an integer array
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "DmxTools.h"
int IsValidDmxStartString(char *startChannels)
{
if(!startChannels) return -1;
char channel[16];
int tmp;
int ch = 0;
int i = 0;
while(*startChannels) {
if(*startChannels == ',' || *startChannels == ';') {
if(i > 0) {
channel[i] = 0;
// atoi ?
tmp = atoi(channel);
if((tmp >= 0) && (tmp<=253))
ch++;
else
return -2; // invalid channel number!
i = 0;
}
}
else
{
if((*startChannels >= '0') && (*startChannels <= '9')) {
if(i < 3)
channel[i++] = *startChannels;
else
return -3; // invalid index length!
} else {
if(*startChannels != ' ') {
return -4; // invalid character found!
}
}
}
startChannels++;
}
// process the rest (or last channel)
if(!*startChannels && (i>0)) {
channel[i] = 0;
tmp = atoi(channel);
if((tmp >= 0) && (tmp<=253)) {
ch++;
} else
return -2;
}
return ch;
}
int *ConvertDmxStartChannelsToInt(int numChannels, char *startChannels)
{
if(!numChannels || !startChannels) return NULL;
int *channels = new int[numChannels + 1];
// tmp buffer to store channel number!
char channel[16];
int next_dmx_ch = 0;
int tmp;
int ch = 0;
int i = 0;
while(*startChannels) {
if(*startChannels == ',' || *startChannels == ';') {
if(i > 0) {
channel[i] = 0;
// atoi ?
tmp = atoi(channel);
if((tmp >= 0) && (tmp<=253)) {
next_dmx_ch = tmp + 3;
channels[ch++] = tmp;
if(ch == numChannels)
break;
} else
break;
i = 0;
}
}
if((*startChannels >= '0') && (*startChannels <= '9')) {
if(i < 3)
channel[i++] = *startChannels;
else
break;
}
startChannels++;
}
if(!*startChannels && (i>0)) {
channel[i] = 0;
tmp = atoi(channel);
if((tmp >= 0) && (tmp<=253)) {
next_dmx_ch = tmp + 3;
channels[ch++] = tmp;
}
}
//
// fillup the array with the logical next dmx channels - for simple devices that should work!
//
while(ch < numChannels) {
if(next_dmx_ch>253) next_dmx_ch=0; // wrap arround :) better than indexing memory out of range
channels[ch++] = next_dmx_ch;
next_dmx_ch += 3;
}
channels[ch++] = -1; // last Entry :)
return channels;
}
char *ConvertDmxStartChannelsToString(int numChannels, int *startChannels)
{
// maxBufSize worst case having numChannels 256 each 3 digits Adress and one colon 256*4 bytes + zero byte
char tmp[1025];
// fuck up! (should not happen)
if(numChannels > 256) return NULL;
char *psz_tmp = tmp;
for(int i = 0; i < numChannels; i++) {
if(startChannels[i] == -1) break;
if(i > 0) {
*psz_tmp = ',';
psz_tmp++;
*psz_tmp = 0;
}
int n = sprintf(psz_tmp, "%d", startChannels[i] );
if(n > 0)
psz_tmp += n;
}
return strdup(tmp);
}
/*
* DmxTools.h: functions to convert , or ; separated numbers into an integer array
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifndef _dmxtools_h_
#define _dmxtools_h_
int *ConvertDmxStartChannelsToInt(int numChannels, char *startChannels);
char *ConvertDmxStartChannelsToString(int numChannels, int *startChannels);
int IsValidDmxStartString(char *startChannels);
#endif
/*
* FnordlichtConnection.cpp: class to access a FnordlichtLight Hardware
* - the description could be found
* here: http://github.com/fd0/fnordlicht/raw/master/doc/PROTOCOL
*
* (C) Kai Lauterbach (klaute at gmail.com)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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.
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "AtmoDefs.h"
#include "FnordlichtConnection.h"
#if !defined(_ATMO_VLC_PLUGIN_)
# include "FnordlichtConfigDialog.h"
#endif
#include <stdio.h>
#include <fcntl.h>
#if !defined(_WIN32)
#include <termios.h>
#include <unistd.h>
#endif
CFnordlichtConnection::CFnordlichtConnection(CAtmoConfig *cfg)
: CAtmoConnection(cfg)
{
m_hComport = INVALID_HANDLE_VALUE;
}
CFnordlichtConnection::~CFnordlichtConnection()
{
}
ATMO_BOOL CFnordlichtConnection::OpenConnection()
{
#if defined(_ATMO_VLC_PLUGIN_)
char *serdevice = m_pAtmoConfig->getSerialDevice();
if ( !serdevice )
return ATMO_FALSE;
#else
int portNummer = m_pAtmoConfig->getComport();
m_dwLastWin32Error = 0;
if ( portNummer < 1 )
return ATMO_FALSE; // make no real sense;-)
#endif
CloseConnection();
#if !defined(_ATMO_VLC_PLUGIN_)
char serdevice[16]; // com4294967295
sprintf(serdevice,"com%d",portNummer);
#endif
#if defined(_WIN32)
m_hComport = CreateFileA(serdevice,
GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, 0, NULL);
if ( m_hComport == INVALID_HANDLE_VALUE )
{
// we have a problem here can't open com port...
// somebody else may use it?
// m_dwLastWin32Error = GetLastError();
return ATMO_FALSE;
}
/* change serial settings (Speed, stopbits etc.) */
DCB dcb; // für comport-parameter
dcb.DCBlength = sizeof(DCB);
GetCommState(m_hComport, &dcb); // ger current serialport settings
dcb.BaudRate = 19200; // set speed
dcb.ByteSize = 8; // set databits
dcb.Parity = NOPARITY; // set parity
dcb.StopBits = ONESTOPBIT; // set one stop bit
SetCommState(m_hComport, &dcb); // apply settings
#else
int bconst = B19200;
m_hComport = open(serdevice,O_RDWR |O_NOCTTY);
if ( m_hComport < 0 )
return ATMO_FALSE;
struct termios tio;
memset(&tio,0,sizeof(tio));
tio.c_cflag = (CS8 | CREAD | HUPCL | CLOCAL);
tio.c_iflag = (INPCK | BRKINT);
cfsetispeed(&tio, bconst);
cfsetospeed(&tio, bconst);
if( ! tcsetattr(m_hComport, TCSANOW, &tio) )
tcflush(m_hComport, TCIOFLUSH);
else {
// can't change parms
close(m_hComport);
m_hComport = -1;
return false;
}
#endif
// sync fnordlicht
if ( sync() )
// stop fading on all devices
if ( stop(255) )
return true; // fnordlicht initialized...
return false; // something is going wrong...
}
void CFnordlichtConnection::CloseConnection()
{
if ( m_hComport != INVALID_HANDLE_VALUE )
{
reset(255);
#if defined(_WIN32)
CloseHandle(m_hComport);
#else
close(m_hComport);
#endif
m_hComport = INVALID_HANDLE_VALUE;
}
}
ATMO_BOOL CFnordlichtConnection::isOpen(void)
{
return (m_hComport != INVALID_HANDLE_VALUE);
}
/*
def fade_rgb(addr, r, g, b, step, delay)
$dev.write addr.chr
$dev.write "\x01"
$dev.write step.chr
$dev.write delay.chr
$dev.write r.chr
$dev.write g.chr
$dev.write b.chr
$dev.write "\x00\x00\x00\x00\x00"
$dev.write "\x00\x00\x00"
$dev.flush
end
*/
ATMO_BOOL CFnordlichtConnection::SendData(pColorPacket data)
{
if ( m_hComport == INVALID_HANDLE_VALUE )
return ATMO_FALSE;
int amount = getAmountFnordlichter();
unsigned char buffer[15];
memset(&buffer, 0, sizeof(buffer) ); // zero buffer
int iBytesWritten;
Lock();
buffer[1] = 0x01; // fade to rgb color
buffer[2] = 0x80; // in two steps
buffer[3] = 0x01; // 1ms pause between steps
// send all packages to all fnordlicht's
for( unsigned char i=0; i < amount; i++ )
{
int idx;
if ( m_ChannelAssignment && i < m_NumAssignedChannels )
idx = m_ChannelAssignment[i];
else
idx = -1; // no channel assigned to fnordlicht[i]
if( idx >= 0 && idx <= data->numColors )
{
// fnordlicht address equals to a MoMo Channel
buffer[0] = i; // fnordlicht address (0..254, 255 = broadcast)
buffer[4] = data->zone[idx].r;
buffer[5] = data->zone[idx].g;
buffer[6] = data->zone[idx].b;
}
#if defined(_WIN32)
// send to COM-Port
WriteFile( m_hComport, buffer, sizeof(buffer),
(DWORD*)&iBytesWritten, NULL );
#else
iBytesWritten = write(m_hComport, buffer, sizeof(buffer));
tcflush(m_hComport, TCIOFLUSH);
tcdrain(m_hComport); // flush buffer
#endif
if (iBytesWritten != sizeof(buffer))
{
Unlock();
return ATMO_FALSE; // shouldn't be...
}
}
Unlock();
return ATMO_TRUE;
}
ATMO_BOOL CFnordlichtConnection::CreateDefaultMapping(CAtmoChannelAssignment *ca)
{
if ( !ca )
return ATMO_FALSE;
ca->setSize( getAmountFnordlichter() ); // oder 4 ? depending on config!
ca->setZoneIndex(0, 0); // Zone 5
ca->setZoneIndex(1, 1);
ca->setZoneIndex(2, 2);
ca->setZoneIndex(3, 3);
return ATMO_TRUE;
}
int CFnordlichtConnection::getAmountFnordlichter()
{
return m_pAtmoConfig->getFnordlicht_Amount();
}
/*
def sync(addr = 0)
1.up to(15) do
$dev.write "\e"
end
$dev.write addr.chr
$dev.flush
end
*/
ATMO_BOOL CFnordlichtConnection::sync(void)
{
if ( m_hComport == INVALID_HANDLE_VALUE )
return ATMO_FALSE;
unsigned char buffer[16];
int iBytesWritten;
Lock();
// fill buffer with 15 escape character
memset(&buffer, 0x1b, sizeof(buffer)-1);
buffer[sizeof(buffer)-1] = 0x00; // append one zero byte
#if defined(_WIN32)
// send to COM-Port
WriteFile( m_hComport, buffer, sizeof(buffer),
(DWORD*)&iBytesWritten, NULL );
#else
iBytesWritten = write(m_hComport, buffer, sizeof(buffer));
tcflush(m_hComport, TCIOFLUSH);
tcdrain(m_hComport); // flush buffer
#endif
Unlock();
return (iBytesWritten == sizeof(buffer)) ? ATMO_TRUE : ATMO_FALSE;
}
/*
def stop(addr, fading = 1)
$dev.write addr.chr
$dev.write "\x08"
$dev.write fading.chr
$dev.write "\x00\x00\x00\x00"
$dev.write "\x00\x00\x00\x00\x00"
$dev.write "\x00\x00\x00"
$dev.flush
end
*/
ATMO_BOOL CFnordlichtConnection::stop(unsigned char addr)
{
if(m_hComport == INVALID_HANDLE_VALUE)
return ATMO_FALSE;
unsigned char buffer[15];
memset(&buffer, 0, sizeof(buffer)); // zero buffer
int iBytesWritten;
Lock();
buffer[0] = addr; // fnordlicht address (255 = broadcast)
buffer[1] = 0x08; // stop command
buffer[2] = 1; // fading
#if defined(_WIN32)
// send to COM-Port
WriteFile( m_hComport, buffer, sizeof(buffer),
(DWORD*)&iBytesWritten, NULL );
#else
iBytesWritten = write(m_hComport, buffer, sizeof(buffer));
tcflush(m_hComport, TCIOFLUSH);
tcdrain(m_hComport); // flush buffer
#endif
Unlock();
return (iBytesWritten == sizeof(buffer)) ? ATMO_TRUE : ATMO_FALSE;
}
/*
*/
ATMO_BOOL CFnordlichtConnection::reset(unsigned char addr)
{
if(m_hComport == INVALID_HANDLE_VALUE)
return ATMO_FALSE;
stop(255);
if ( sync() && start_bootloader(addr) )
{
#if defined(_ATMO_VLC_PLUGIN_)
do_sleep(200000); // wait 200ms
#else
do_sleep(200); // wait 200ms
#endif
if ( sync() && boot_enter_application(addr) )
return ATMO_TRUE;
}
return ATMO_FALSE;
}
/*
def start_bootloader(addr)
$dev.write(addr.chr)
$dev.write("\x80")
$dev.write("\x6b\x56\x27\xfc")
$dev.write("\x00\x00\x00\x00\x00\x00\x00\x00\x00")
$dev.flush
end
*/
ATMO_BOOL CFnordlichtConnection::start_bootloader(unsigned char addr)
{
if(m_hComport == INVALID_HANDLE_VALUE)
return ATMO_FALSE;
unsigned char buffer[15];
memset(&buffer, 0, sizeof(buffer)); // zero buffer
int iBytesWritten;
Lock();
buffer[0] = addr; // fnordlicht address (255 = broadcast)
buffer[1] = 0x80; // start_bootloader
buffer[2] = 0x6b;
buffer[3] = 0x56;
buffer[4] = 0x27;
buffer[5] = 0xfc;
#if defined(_WIN32)
// send to COM-Port
WriteFile( m_hComport, buffer, sizeof(buffer),
(DWORD*)&iBytesWritten, NULL );
#else
iBytesWritten = write(m_hComport, buffer, sizeof(buffer));
tcflush(m_hComport, TCIOFLUSH);
tcdrain(m_hComport); // flush buffer
#endif
Unlock();
return (iBytesWritten == sizeof(buffer)) ? ATMO_TRUE : ATMO_FALSE;
}
/*
def boot_enter_application(addr)
$dev.write(addr.chr)
$dev.write("\x87")
$dev.write("\x00"*13)
$dev.flush
end
*/
ATMO_BOOL CFnordlichtConnection::boot_enter_application(unsigned char addr)
{
if(m_hComport == INVALID_HANDLE_VALUE)
return ATMO_FALSE;
unsigned char buffer[15];
memset(&buffer, 0, sizeof(buffer)); // zero buffer
int iBytesWritten;
Lock();
buffer[0] = addr; // fnordlicht address (255 = broadcast)
buffer[1] = 0x87; // boot_ender_application command
#if defined(_WIN32)
// send to COM-Port
WriteFile( m_hComport, buffer, sizeof(buffer),
(DWORD*)&iBytesWritten, NULL );
#else
iBytesWritten = write(m_hComport, buffer, sizeof(buffer));
tcflush(m_hComport, TCIOFLUSH);
tcdrain(m_hComport); // flush buffer
#endif
Unlock();
return (iBytesWritten == sizeof(buffer)) ? ATMO_TRUE : ATMO_FALSE;
}
#if !defined(_ATMO_VLC_PLUGIN_)
char *CFnordlichtConnection::getChannelName(int ch)
{
char buf[60];
if( ch < 0 ) return NULL;
if( ch >= getAmountFnordlichter() ) return NULL;
sprintf(buf,"Number [%d]",ch);
return strdup(buf);
// sorry asprintf is not defined on Visual Studio :)
// return (asprintf(&ret, "Number [%d]", ch) != -1) ? ret : NULL;
}
ATMO_BOOL CFnordlichtConnection::ShowConfigDialog(HINSTANCE hInst, HWND parent,
CAtmoConfig *cfg)
{
CFnordlichtConfigDialog *dlg = new CFnordlichtConfigDialog(hInst,
parent,
cfg);
INT_PTR result = dlg->ShowModal();
delete dlg;
if(result == IDOK)
return ATMO_TRUE;
else
return ATMO_FALSE;
}
#endif
/*
* FnordlichtConnection.h: class to access a FnordlichtLight Hardware
* - the description could be found
* here: http://github.com/fd0/fnordlicht/raw/master/doc/PROTOCOL
*
* (C) Kai Lauterbach (klaute at gmail.com)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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.
*
* $Id$
*/
#ifndef _FnordlichtConnection_h_
#define _FnordlichtConnection_h_
#include "AtmoDefs.h"
#include "AtmoConnection.h"
#include "AtmoConfig.h"
#if defined(_WIN32)
# include <windows.h>
#endif
class CFnordlichtConnection : public CAtmoConnection
{
private:
HANDLE m_hComport;
ATMO_BOOL sync(void);
ATMO_BOOL stop(unsigned char addr);
ATMO_BOOL reset(unsigned char addr);
ATMO_BOOL start_bootloader(unsigned char addr);
ATMO_BOOL boot_enter_application(unsigned char addr);
#if defined(_WIN32)
DWORD m_dwLastWin32Error;
public:
DWORD getLastError() { return m_dwLastWin32Error; }
#endif
public:
CFnordlichtConnection (CAtmoConfig *cfg);
virtual ~CFnordlichtConnection (void);
virtual ATMO_BOOL OpenConnection();
virtual void CloseConnection();
virtual ATMO_BOOL isOpen(void);
virtual ATMO_BOOL SendData(pColorPacket data);
virtual int getAmountFnordlichter();
virtual const char *getDevicePath() { return "fnordlicht"; }
#if !defined(_ATMO_VLC_PLUGIN_)
virtual char *getChannelName(int ch);
virtual ATMO_BOOL ShowConfigDialog(HINSTANCE hInst, HWND parent,
CAtmoConfig *cfg);
#endif
virtual ATMO_BOOL CreateDefaultMapping(CAtmoChannelAssignment *ca);
};
#endif
/*
* MoMoConnection.cpp: Class for communication with the serial hardware of
* Atmo Light, opens and configures the serial port
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "AtmoDefs.h"
#include "MoMoConnection.h"
#if !defined(_ATMO_VLC_PLUGIN_)
# include "MoMoConfigDialog.h"
#endif
#include <stdio.h>
#include <fcntl.h>
#if !defined(_WIN32)
#include <termios.h>
#include <unistd.h>
#endif
CMoMoConnection::CMoMoConnection(CAtmoConfig *cfg) : CAtmoConnection(cfg) {
m_hComport = INVALID_HANDLE_VALUE;
}
CMoMoConnection::~CMoMoConnection() {
}
ATMO_BOOL CMoMoConnection::OpenConnection() {
#if defined(_ATMO_VLC_PLUGIN_)
char *serdevice = m_pAtmoConfig->getSerialDevice();
if(!serdevice)
return ATMO_FALSE;
#else
int portNummer = m_pAtmoConfig->getComport();
m_dwLastWin32Error = 0;
if(portNummer < 1) return ATMO_FALSE; // make no real sense;-)
#endif
CloseConnection();
#if !defined(_ATMO_VLC_PLUGIN_)
char serdevice[16]; // com4294967295
sprintf(serdevice,"com%d",portNummer);
#endif
#if defined(_WIN32)
m_hComport = CreateFileA(serdevice, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if(m_hComport == INVALID_HANDLE_VALUE) {
// we have a problem here can't open com port... somebody else may use it?
// m_dwLastWin32Error = GetLastError();
return ATMO_FALSE;
}
/* change serial settings (Speed, stopbits etc.) */
DCB dcb; // für comport-parameter
dcb.DCBlength = sizeof(DCB);
GetCommState (m_hComport, &dcb); // ger current serialport settings
dcb.BaudRate = 9600; // set speed
dcb.ByteSize = 8; // set databits
dcb.Parity = NOPARITY; // set parity
dcb.StopBits = ONESTOPBIT; // set one stop bit
SetCommState (m_hComport, &dcb); // apply settings
#else
int bconst = B9600;
m_hComport = open(serdevice,O_RDWR |O_NOCTTY);
if(m_hComport < 0) {
return ATMO_FALSE;
}
struct termios tio;
memset(&tio,0,sizeof(tio));
tio.c_cflag = (CS8 | CREAD | HUPCL | CLOCAL);
tio.c_iflag = (INPCK | BRKINT);
cfsetispeed(&tio, bconst);
cfsetospeed(&tio, bconst);
if(!tcsetattr(m_hComport, TCSANOW, &tio)) {
tcflush(m_hComport, TCIOFLUSH);
} else {
// can't change parms
close(m_hComport);
m_hComport = -1;
return false;
}
#endif
return true;
}
void CMoMoConnection::CloseConnection() {
if(m_hComport!=INVALID_HANDLE_VALUE) {
#if defined(_WIN32)
CloseHandle(m_hComport);
#else
close(m_hComport);
#endif
m_hComport = INVALID_HANDLE_VALUE;
}
}
ATMO_BOOL CMoMoConnection::isOpen(void) {
return (m_hComport != INVALID_HANDLE_VALUE);
}
ATMO_BOOL CMoMoConnection::SendData(pColorPacket data) {
if(m_hComport == INVALID_HANDLE_VALUE)
return ATMO_FALSE;
int channels = getNumChannels();
DWORD bufSize = channels * 3;
unsigned char *buffer = new unsigned char[ bufSize ];
DWORD iBytesWritten;
Lock();
int i_red = 0;
int i_green = channels;
int i_blue = channels * 2;
int idx;
/*
3 ch
i_red = 0, i_green = 3, i_blue = 6
4 ch
i_red = 0, i_green = 4, i_blue = 8
*/
for(int i=0; i < channels ; i++) {
if(m_ChannelAssignment && (i < m_NumAssignedChannels))
idx = m_ChannelAssignment[i];
else
idx = -1;
if((idx>=0) && (idx<data->numColors)) {
buffer[i_red++] = data->zone[idx].r;
buffer[i_green++] = data->zone[idx].g;
buffer[i_blue++] = data->zone[idx].b;
} else {
buffer[i_red++] = 0;
buffer[i_green++] = 0;
buffer[i_blue++] = 0;
}
}
#if defined(_WIN32)
WriteFile(m_hComport, buffer, bufSize, &iBytesWritten, NULL); // send to COM-Port
#else
iBytesWritten = write(m_hComport, buffer, bufSize);
tcdrain(m_hComport);
#endif
delete []buffer;
Unlock();
return (iBytesWritten == bufSize) ? ATMO_TRUE : ATMO_FALSE;
}
ATMO_BOOL CMoMoConnection::CreateDefaultMapping(CAtmoChannelAssignment *ca)
{
if(!ca) return ATMO_FALSE;
ca->setSize( getNumChannels() ); // oder 4 ? depending on config!
ca->setZoneIndex(0, 0); // Zone 5
ca->setZoneIndex(1, 1);
ca->setZoneIndex(2, 2);
ca->setZoneIndex(3, 3);
return ATMO_TRUE;
}
int CMoMoConnection::getNumChannels()
{
return m_pAtmoConfig->getMoMo_Channels();
}
#if !defined(_ATMO_VLC_PLUGIN_)
char *CMoMoConnection::getChannelName(int ch)
{
if(ch < 0) return NULL;
char buf[30];
switch(ch) {
case 0:
sprintf(buf,"Channel [%d]",ch);
break;
case 1:
sprintf(buf,"Channel [%d]",ch);
break;
case 2:
sprintf(buf,"Channel [%d]",ch);
break;
case 3:
sprintf(buf,"Channel [%d]",ch);
break;
default:
sprintf(buf,"Channel [%d]",ch);
break;
}
return strdup(buf);
}
ATMO_BOOL CMoMoConnection::ShowConfigDialog(HINSTANCE hInst, HWND parent, CAtmoConfig *cfg)
{
CMoMoConfigDialog *dlg = new CMoMoConfigDialog(hInst, parent, cfg);
INT_PTR result = dlg->ShowModal();
delete dlg;
if(result == IDOK)
return ATMO_TRUE;
else
return ATMO_FALSE;
}
#endif
/*
* MoMoConnection.h: class to access a MoMoLight Hardware - the description could be found
* here: http://lx.divxstation.com/article.asp?aId=151
*
* See the README.txt file for copyright information and how to reach the author(s).
*
* $Id$
*/
#ifndef _MoMoConnection_h_
#define _MoMoConnection_h_
#include "AtmoDefs.h"
#include "AtmoConnection.h"
#include "AtmoConfig.h"
#if defined(_WIN32)
# include <windows.h>
#endif
class CMoMoConnection : public CAtmoConnection {
private:
HANDLE m_hComport;
#if defined(_WIN32)
DWORD m_dwLastWin32Error;
public:
DWORD getLastError() { return m_dwLastWin32Error; }
#endif
public:
CMoMoConnection (CAtmoConfig *cfg);
virtual ~CMoMoConnection (void);
virtual ATMO_BOOL OpenConnection();
virtual void CloseConnection();
virtual ATMO_BOOL isOpen(void);
virtual ATMO_BOOL SendData(pColorPacket data);
virtual int getNumChannels();
virtual const char *getDevicePath() { return "momo"; }
#if !defined(_ATMO_VLC_PLUGIN_)
virtual char *getChannelName(int ch);
virtual ATMO_BOOL ShowConfigDialog(HINSTANCE hInst, HWND parent, CAtmoConfig *cfg);
#endif
virtual ATMO_BOOL CreateDefaultMapping(CAtmoChannelAssignment *ca);
};
#endif
This piece of software is based on the software and descriptions mentioned below -
(re)Written by: Igor / Atmo (aka André Weber) - WeberAndre@gmx.de
Matthiaz
MacGyver2k
if you need to contact one of us - come to www.vdr-portal.de
http://www.vdr-portal.de/board/thread.php?threadid=59294 -- Description and Development of the Windows Software
http://www.vdr-portal.de/board/thread.php?threadid=48574 -- Description and Development of the Hardware part
=====================================================
Info for Users on Vista or Windows 7 with active UAC!
=====================================================
for the first launch do it as Administrator with the following command line
AtmoWinA.exe /register
to create the required registry entries for the COM Objects, without
these registry entries - the DirectShow Filter and also the VLC Plugin
will not work.
If anything went fine you should see the message "COM Server registered Ok!".
See the file COPYING.txt for license information.
VideoLAN / VLC
---------------
In order to use this Programm with the VLC-Media-Player properly copy the "AtmoCtrlLib.dll" into the same Location where the vlc.exe is. E.G.: "D:\Programme\VLC".
NEWER Versions of VideoLAN 1.1.x and higher, don't need a own copy of the "AtmoCtrlLib.dll" in the vlc.exe folder,
if the complete filename of the AtmoWin*.exe is given. (Atmo Filter will try to load the DLL from there)
Then open VLC and navigate to "Extras" / "Settings" or Press "Ctrl" + "p".
Check that the radiobutton in the lower part of the dialogbox called "Show settings" -> "all" is checked.
Now open the Register "Video" and click on "Filter". There you have to select the checkbox "AtmoLight-Filter".
Afterwards you expand the Tree "Filter" in the Listbox on the left side. By selecting the entry "AtmoLight" you gain more settings.
The most important are right these one at the beginning:
VideoLAN 1.0.x
==============
"Use build in AtmoLight driver":
Using this Property means VLC will control the Hardware with its built in driver.
(no need for the extra AtmoWin software driver)
VideoLAN 1.1.x
==============
You have the following choices for "Devicetype" instead of the old settings
"AtmoWin Software" - is only available on Windows and works like the old way useing the external AtmoWin*.exe Software package, with the AtmoCtrlLib.dll.
"Classic AtmoLight" - is the same as the former "use build in AtmoLight driver"
"Quattro AtmoLight" - allows to use up to four serial connected class AtmoLight devices, as one logical device
"DMX" - allows to control a simple serial DMX devices for AtmoLight effects
"MoMoLight" - is a another kind of hardware supporting 2 oder 3 channels.
(see bottom of this file - for more infos about the devices.)
VideonLAN 1.0.x
===============
"Serial Device / Port":
The COM-Port you are using for the hardware. E.G.: COM6 (This setting must be done if you are using the Property
"use build in AtmoLight driver" )
VideonLAN 1.1.x
===============
"Serial Device / Port":
The COM-Port you are using for the hardware. E.G.: COM6 (This setting must be done if you are using a device
other than "AtmoWin Software")
in the case of the device "Quattro AtmoLight" you may specify up to four ports/devices separated by
, or ; for example if you are useing two physical devices write
COM6;COM7 or on linux /dev/ttyUSB1;/dev/ttyUSB2
VideoLAN 1.0.x
==============
"Filename of AtmoWinA.exe":
The Path and the Name of the executable. E.G.:
'D:\atmoWin_0.45\AtmoWinA.exe' (Using this setting expects that you have copied "AtmoCtrlLib.dll" to the Path where VLC.exe is like described before)
VideoLAN 1.1.x
==============
"Filename of AtmoWinA.exe":
The Path and the Name of the executable. E.G.:
'D:\atmoWin_0.45\AtmoWinA.exe'
in the same path where the .exe resides the "AtmoCtrlLib.dll" should be there. or you may need to place
a copy of this ".dll" into the vlc.exe folder - like in VideoLAN 1.0.x
Afterwards you should apply those settings by pressing the button "Save".
VideoLAN 1.1.x - new options and settings
=========================================
Zone Layout for the build-in Atmo
=================================
This is the most important change I think - because the number of analyzed zones isn't
longer fixed to 4 or 5 - it allows to define the physical layout of your lights arround
the screen.
"Number of zones on top" -- how many light sources are place on top of the screen
(number of columns in which the screen should be tiled)
"Number of zones on bottom" -- how many light sources are place on bottom of the screen
(number of columns in which the screen should be tiled)
"Zones on left / right side" -- how many light sources are place on right/left of the screen
(number of rows in which the screen should be tiled)
its assumed that the number on right and left is equal.
"[] Calculate a average zone" -- define a color pair depending on the complete screen content
This settings tiles the screen into a number of zones - which get analyzed by atmoLight to
determine a most used color for these areas - each zone has a number starting from zero.
The zones are usualy numbered in clock-wise order starting at the top/left of the screen.
Example 1: classic Atmo with 4 channels
---------------------------------------
"Number of zones on top" = 1
"Number of zones on bottom" = 1
"Zones on left / right side" = 1
"[] Calculate a average zone" = false/0 not checked.
will produce this zone layout
-----------
| Zone 0 |
---------------------
| | | |
| Z | | Z |
| o | | o |
| n | | n |
| e | | e |
| | | |
| 3 | | 1 |
---------------- ----
| Zone 2 |
-----------
Example 2: classic Atmo with 4 channels
---------------------------------------
"Number of zones on top" = 2
"Number of zones on bottom" = 0
"Zones on left / right side" = 1
"[] Calculate a average zone" = false/0 not checked.
----------- -----------
| Zone 0 | | Zone 1 |
---------------------------------
| | | |
| Z | | Z |
| o | | o |
| n | | n |
| e | | e |
| | | |
| 3 | | 2 |
----- -----
Example 3: classic Atmo with 4 channels
---------------------------------------
"Number of zones on top" = 1
"Number of zones on bottom" = 0
"Zones on left / right side" = 1
"[X] Calculate a average zone" = true/1 checked.
-----------
| Zone 0 |
---------------------
| | -------- | |
| Z | | Z | | Z |
| o | | o | | o |
| n | | n | | n |
| e | | e | | e |
| | | 3 | | |
| 2 | -------- | 1 |
----- -----
Zone 3 - usualy calcuates the most used color of the full screen / picture / frame
not only at the border of the picture.
"The average zone" is allways the last in the sequence of numbers.
the weightning gradients for these zones are auto calculated
from 100% .. 0% starting from the edge.
thats also the cause why the parameters Channel assignment changed,
the classic comboboxes are still there for devices with 4 channels ot less,
but for newer devices the "Channel / Zone assignment" should be used which
is defined by a , or ; separated list of "AtmoLight channel numbers" if you
want to hide a calcuated zone from output - you can assign channel -1 to
do this.
for classic AtmoLight with "Example 1" you may write this:
-1;3;2;1;0
AtmoLight Channel 0: gets no zone assigned (-1)
AtmoLight Channel 1: gets zone 3 (left)
AtmoLight Channel 2: gets zone 2 (bottom)
AtmoLight Channel 3: gets zone 1 (right)
AtmoLight Channel 4: gets zone 0 (top)
Also the settings for Gradient images change for the new devices, its no longer
sufficient to speficy only 5 image name - because the number of zones is no longer
fixed to five.
So its preferred to set a path ("Gradient Bitmap searchpath"), where files
like "zone_0.bmp" "zone_1.bmp" etc. exists. (with the same rules as defined for
the old zone bitmaps.)
--> I think in most cases its no longer required to use this option,
to change the zone layout - for most cases its sufficient to change
"Zone Layout for the build-in Atmo" to get the same effect?
Live Set of parameters for Buildin AtmoLight
============================================
durring playback with the buildin driver you can now change some settings
of the filter without stopping / starting your movie - just open the
"extras" --> "Effects and Filters" --> [Video effects] --> [AtmoLight]
- move the sliders or change the calcuation mode, or enable/disable
the debug grid - just in time.
new Debugging Option
====================
[] Mark analyzed pixels - puts a grid of the used pixels on each frame
to see from which locations/positions the colors are extracted.
DMX Options
-----------
like the group says only for the DMX device
"Count of AtmoLight Channels" - defines how many RGB Channels should be simulated
with this DMX device (each RGB channel needs three DMX channels!)
"DMX address for each channel" - defines the DMX Startadress for each AtmoLight
channel as "," or ";" separated list. (starting with 0 up to 252) it is assumed
that the f.e. of the DMX-AtmoLight channel starts at DMX-Channel 5 - that
DMX-Channel 5: is red
DMX-Channel 6: is green
DMX-Channel 7: is blue!
MoMoLight options
-----------------
"Count of channels" - defines the devicetype and serial protocol
3: - means 3 channels hardware
4: - means 4 channels hardware
(its required to set the correct number of channels to get this device working,
because the serial protocol isn't the same!)
Fnordlicht options
------------------
"Count of fnordlicht's" - defines the number of devices connected to the bus
VideoLan Options and Devices - the buildin version of AtmoLight supports a subset of the
devices that AtmoWin supports.
- AtmoWin Software - means do not use the VLC buildin video processing - just forward
the basic preprocessed data to the launched AtmoWinA.exe controlling your hardware.
- Classic AtmoLight - means the classic hardware from www.vdr-portal.de - with up to 5 channels.
- Quattro AtmoLight - is nothing else as that you have connected up to 4 "classic AtmoLight" devices
to your computer creating a up 16 channel Atmo Light - each devices needs its own serial port.
you have to write the ports separated by , or ; to [Serial Port/device] f.e. COM3,COM4,COM5 or on
Linux /dev/ttyUSB01,/dev/ttyUSB02,/dev/ttyUSB03
- DMX - stands for a simple DMX controller which can control up to 255 DMX devices (lights)
- f.e. you may have a look here:
* http://www.dzionsko.de/elektronic/index.htm
* http://www.ulrichradig.de/ (search for dmx on his page)
- MoMoLight - is a serial device, with 3 or 4 channels - doing nearly the same like
Classic AtmoLight - just another protocol to control the hardware.
http://lx.divxstation.com/article.asp?aId=151
http://www.the-boss.dk/pages/momolight.htm
- Fnordlicht - is a serial device bus, where up 254 lights could be connected
for more information about the device look here:
http://wiki.lochraster.org/wiki/Fnordlicht
http://github.com/fd0/fnordlicht/raw/master/doc/PROTOCOL
Original Readme - of the Linux Version - from where some code was used
to do the color calculations ...
######################################################################
Original Readme and Authors of the Linux VDR Plugin!
######################################################################
Written by: Eike Edener <vdr@edener.de>
Project's homepage: www.edener.de
Latest version available at: www.edener.de
See the file COPYING for license information.
----------------------------------------------------------------------
for detailed information visit the VDR-Wiki:
http://www.vdr-wiki.de/wiki/index.php/Atmo-plugin
Development:
http://www.vdr-portal.de/board/thread.php?threadid=48574
Known bugs:
n/a
----------------------------------------------------------------------
/*****************************************************************************
* atmo.cpp : "Atmo Light" video filter
*****************************************************************************
* Copyright (C) 2000-2006 VLC authors and VideoLAN
* $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 Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
#include <string.h>
#include <math.h> /* sin(), cos() */
#include <assert.h>
// #define __ATMO_DEBUG__
// [:Zs]+$
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_vout.h>
#include <vlc_filter.h>
#include <vlc_atomic.h>
#include <vlc_charset.h>
#include "../filter_picture.h"
#include "AtmoDefs.h"
#include "AtmoDynData.h"
#include "AtmoLiveView.h"
#include "AtmoTools.h"
#include "AtmoExternalCaptureInput.h"
#include "AtmoConfig.h"
#include "AtmoConnection.h"
#include "AtmoClassicConnection.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 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
#define CLASSIC_ATMO_NUM_ZONES 5
/*
strings for settings menus and hints
*/
#define MODULE_DESCRIPTION N_ ( \
"This module allows controlling an so called AtmoLight device "\
"connected to your computer.\n"\
"AtmoLight is the homegrown version of what Philips calls AmbiLight.\n"\
"If you need further information 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"\
"You can find there detailed descriptions on how to build it for yourself "\
"and where to get the required parts.\n" \
"You can also have a look at pictures and some movies showing such a device " \
"in live action.")
#define DRIVER_TEXT N_("Device type")
#define DRIVER_LONGTEXT N_("Choose your preferred hardware from " \
"the list, or choose AtmoWin Software " \
"to delegate processing to the external " \
"process - with more options")
static const int pi_device_type_values[] = {
#if defined( _WIN32 )
0, /* use AtmoWinA.exe userspace driver */
#endif
1, /* AtmoLight classic */
2, /* Quattro AtmoLight */
3, /* DMX Device */
4, /* MoMoLight device */
5 /* fnordlicht */
};
static const char *const ppsz_device_type_descriptions[] = {
#if defined( _WIN32 )
N_("AtmoWin Software"),
#endif
N_("Classic AtmoLight"),
N_("Quattro AtmoLight"),
N_("DMX"),
N_("MoMoLight"),
N_("fnordlicht")
};
#define DMX_CHANNELS_TEXT N_("Count of AtmoLight channels")
#define DMX_CHANNELS_LONGTEXT N_("How many AtmoLight channels, should be " \
"emulated with that DMX device")
#define DMX_CHBASE_TEXT N_("DMX address for each channel")
#define DMX_CHBASE_LONGTEXT N_("Define here the DMX base address for each " \
"channel use , or ; to separate the values")
#define MOMO_CHANNELS_TEXT N_("Count of channels")
#define MOMO_CHANNELS_LONGTEXT N_("Depending on your MoMoLight hardware " \
"choose 3 or 4 channels")
#define FNORDLICHT_AMOUNT_TEXT N_("Count of fnordlicht's")
#define FNORDLICHT_AMOUNT_LONGTEXT N_("Depending on the amount your " \
"fnordlicht hardware " \
"choose 1 to 254 channels")
#if defined( _WIN32 )
# define DEFAULT_DEVICE 0
#else
# define DEFAULT_DEVICE 1
#endif
#if defined( __ATMO_DEBUG__ )
# define SAVEFRAMES_TEXT N_("Save Debug Frames")
# define SAVEFRAMES_LONGTEXT N_("Write every 128th miniframe to a folder.")
# define FRAMEPATH_TEXT N_("Debug Frame Folder")
# define FRAMEPATH_LONGTEXT N_("The path where the debugframes " \
"should be saved")
#endif
#define WIDTH_TEXT N_("Extracted Image Width")
#define WIDTH_LONGTEXT N_("The width of the mini image for " \
"further processing (64 is default)")
#define HEIGHT_TEXT N_("Extracted Image Height")
#define HEIGHT_LONGTEXT N_("The height of the mini image for " \
"further processing (48 is default)")
#define SHOW_DOTS_TEXT N_("Mark analyzed pixels")
#define SHOW_DOTS_LONGTEXT N_("makes the sample grid visible on screen as "\
"white pixels")
#define PCOLOR_TEXT N_("Color when paused")
#define PCOLOR_LONGTEXT N_("Set the color to show if the user " \
"pauses the video. (Have light to get " \
"another beer?)")
#define PCOLOR_RED_TEXT N_("Pause-Red")
#define PCOLOR_RED_LONGTEXT N_("Red component of the pause color")
#define PCOLOR_GREEN_TEXT N_("Pause-Green")
#define PCOLOR_GREEN_LONGTEXT N_("Green component of the pause color")
#define PCOLOR_BLUE_TEXT N_("Pause-Blue")
#define PCOLOR_BLUE_LONGTEXT N_("Blue component of the 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_("Red component of the shutdown color")
#define ECOLOR_GREEN_TEXT N_("End-Green")
#define ECOLOR_GREEN_LONGTEXT N_("Green component of the shutdown color")
#define ECOLOR_BLUE_TEXT N_("End-Blue")
#define ECOLOR_BLUE_LONGTEXT N_("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 ZONE_TOP_TEXT N_("Number of zones on top")
#define ZONE_TOP_LONGTEXT N_("Number of zones on the top of the screen")
#define ZONE_BOTTOM_TEXT N_("Number of zones on bottom")
#define ZONE_BOTTOM_LONGTEXT N_("Number of zones on the bottom of the screen")
#define ZONE_LR_TEXT N_("Zones on left / right side")
#define ZONE_LR_LONGTEXT N_("left and right side having always the " \
"same number of zones")
#define ZONE_SUMMARY_TEXT N_("Calculate a average zone")
#define ZONE_SUMMARY_LONGTEXT N_("it contains the average of all pixels " \
"in the sample image (only useful for " \
"single channel AtmoLight)")
#define USEWHITEADJ_TEXT N_("Use Software White adjust")
#define USEWHITEADJ_LONGTEXT N_("Should the buildin driver do a white " \
"adjust or your 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 your 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 completely "\
"changed. This prevents flickering.")
#define MEANTHRESHOLD_TEXT N_("Filter threshold")
#define MEANTHRESHOLD_LONGTEXT N_("How much a color has to be changed for an "\
"immediate color change.")
#define MEANPERCENTNEW_TEXT N_("Filter smoothness (%)")
#define MEANPERCENTNEW_LONGTEXT N_("Filter Smoothness")
#define FILTERMODE_TEXT N_("Output Color filter mode")
#define FILTERMODE_LONGTEXT N_("defines the how the output color should " \
"be calculated based on previous color")
static const int pi_filtermode_values[] = {
(int)afmNoFilter,
(int)afmCombined,
(int)afmPercent
};
static const char *const ppsz_filtermode_descriptions[] = {
N_("No Filtering"),
N_("Combined"),
N_("Percent")
};
#define FRAMEDELAY_TEXT N_("Frame delay (ms)")
#define FRAMEDELAY_LONGTEXT N_("Helps to get the video output and the light "\
"effects in sync. Values around 20ms should " \
"do the trick.")
#define CHANNEL_0_ASSIGN_TEXT N_("Channel 0: summary")
#define CHANNEL_1_ASSIGN_TEXT N_("Channel 1: left")
#define CHANNEL_2_ASSIGN_TEXT N_("Channel 2: right")
#define CHANNEL_3_ASSIGN_TEXT N_("Channel 3: top")
#define CHANNEL_4_ASSIGN_TEXT N_("Channel 4: bottom")
#define CHANNELASSIGN_LONGTEXT N_("Maps the hardware channel X to logical "\
"zone Y to fix wrong wiring :-)")
static const int pi_zone_assignment_values[] = {
-1,
4,
3,
1,
0,
2
};
static const char *const ppsz_zone_assignment_descriptions[] = {
N_("disabled"),
N_("Zone 4:summary"),
N_("Zone 3:left"),
N_("Zone 1:right"),
N_("Zone 0:top"),
N_("Zone 2:bottom")
};
#define CHANNELS_ASSIGN_TEXT N_("Channel / Zone Assignment")
#define CHANNELS_ASSIGN_LONGTEXT N_("for devices with more than five " \
"channels / zones write down here for each channel " \
"the zone number to show and separate the values with " \
", or ; and use -1 to not use some channels. For the " \
"classic AtmoLight the sequence 4,3,1,0,2 would set the " \
"default channel/zone mapping. " \
"Having only two zones on top, and one zone on left and " \
"right and no summary zone the mapping for classic " \
"AtmoLight would be -1,3,2,1,0")
#define ZONE_0_GRADIENT_TEXT N_("Zone 0: Top gradient")
#define ZONE_1_GRADIENT_TEXT N_("Zone 1: Right gradient")
#define ZONE_2_GRADIENT_TEXT N_("Zone 2: Bottom gradient")
#define ZONE_3_GRADIENT_TEXT N_("Zone 3: Left gradient")
#define ZONE_4_GRADIENT_TEXT N_("Zone 4: Summary gradient")
#define ZONE_X_GRADIENT_LONG_TEXT N_("Defines a small bitmap with 64x48 "\
"pixels, containing a grayscale gradient")
#define GRADIENT_PATH_TEXT N_("Gradient bitmap searchpath")
#define GRADIENT_PATH_LONGTEXT N_("Now preferred option to assign gradient "\
"bitmaps, put them as zone_0.bmp, zone_1.bmp etc. into one folder and "\
"set the foldername here")
#if defined( _WIN32 )
# define ATMOWINEXE_TEXT N_("Filename of AtmoWin*.exe")
# define ATMOWINEXE_LONGTEXT N_("if you want the AtmoLight control "\
"software to be launched by VLC, enter the "\
"complete path of AtmoWinA.exe here.")
#endif
#define CFG_PREFIX "atmo-"
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin ()
set_description( N_("AtmoLight Filter") )
set_help( MODULE_DESCRIPTION )
set_shortname( N_( "AtmoLight" ))
set_category( CAT_VIDEO )
set_subcategory( SUBCAT_VIDEO_VFILTER )
set_capability( "video filter2", 0 )
set_section( N_("Choose Devicetype and Connection" ), 0 )
add_integer( CFG_PREFIX "device", DEFAULT_DEVICE,
DRIVER_TEXT, DRIVER_LONGTEXT, false )
change_integer_list( pi_device_type_values,
ppsz_device_type_descriptions )
#if defined(_WIN32)
add_string(CFG_PREFIX "serialdev", "COM1",
SERIALDEV_TEXT, SERIALDEV_LONGTEXT, false )
/*
on win32 the executeable external driver application
for automatic start if needed
*/
add_loadfile(CFG_PREFIX "atmowinexe", NULL,
ATMOWINEXE_TEXT, ATMOWINEXE_LONGTEXT, false )
#else
add_string(CFG_PREFIX "serialdev", "/dev/ttyUSB0",
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,
PCOLOR_TEXT, PCOLOR_LONGTEXT, false)
add_integer_with_range(CFG_PREFIX "pcolor-red", 0, 0, 255,
PCOLOR_RED_TEXT, PCOLOR_RED_LONGTEXT, false)
add_integer_with_range(CFG_PREFIX "pcolor-green", 0, 0, 255,
PCOLOR_GREEN_TEXT, PCOLOR_GREEN_LONGTEXT, false)
add_integer_with_range(CFG_PREFIX "pcolor-blue", 192, 0, 255,
PCOLOR_BLUE_TEXT, PCOLOR_BLUE_LONGTEXT, false)
add_integer_with_range(CFG_PREFIX "fadesteps", 50, 1, 250,
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,
ECOLOR_RED_TEXT, ECOLOR_RED_LONGTEXT, false)
add_integer_with_range(CFG_PREFIX "ecolor-green", 192, 0, 255,
ECOLOR_GREEN_TEXT, ECOLOR_GREEN_LONGTEXT, false)
add_integer_with_range(CFG_PREFIX "ecolor-blue", 192, 0, 255,
ECOLOR_BLUE_TEXT, ECOLOR_BLUE_LONGTEXT, false)
add_integer_with_range(CFG_PREFIX "efadesteps", 50, 1, 250,
EFADESTEPS_TEXT, EFADESTEPS_LONGTEXT, false)
set_section( N_("DMX options" ), 0 )
add_integer_with_range(CFG_PREFIX "dmx-channels", 5, 1, 64,
DMX_CHANNELS_TEXT, DMX_CHANNELS_LONGTEXT, false)
add_string(CFG_PREFIX "dmx-chbase", "0,3,6,9,12",
DMX_CHBASE_TEXT, DMX_CHBASE_LONGTEXT, false )
set_section( N_("MoMoLight options" ), 0 )
add_integer_with_range(CFG_PREFIX "momo-channels", 3, 3, 4,
MOMO_CHANNELS_TEXT, MOMO_CHANNELS_LONGTEXT, false)
/* 2,2,4 means 2 is the default value, 1 minimum amount,
4 maximum amount
*/
set_section( N_("fnordlicht options" ), 0 )
add_integer_with_range(CFG_PREFIX "fnordlicht-amount", 2, 1, 254,
FNORDLICHT_AMOUNT_TEXT,
FNORDLICHT_AMOUNT_LONGTEXT, false)
/*
instead of redefining the original AtmoLight zones with gradient
bitmaps, we can now define the layout of the zones useing these
parameters - the function with the gradient bitmaps would still
work (but for most cases its no longer required)
short description whats this means - f.e. the classic atmo would
have this layout
zones-top = 1 - zone 0
zones-lr = 1 - zone 1 und zone 3
zones-bottom = 1 - zone 2
zone-summary = true - zone 4
Z0
,------------,
| |
Z3| Z4 | Z1
|____________|
Z2
the zone numbers will be counted clockwise starting at top / left
if you want to split the light at the top, without having a bottom zone
(which is my private config)
zones-top = 2 - zone 0, zone 1
zones-lr = 1 - zone 2 und zone 3
zones-bottom = 0
zone-summary = false
Z0 Z1
,------------,
| |
Z3| | Z2
|____________|
*/
set_section( N_("Zone Layout for the build-in Atmo" ), 0 )
add_integer_with_range(CFG_PREFIX "zones-top", 1, 0, 16,
ZONE_TOP_TEXT, ZONE_TOP_LONGTEXT, false)
add_integer_with_range(CFG_PREFIX "zones-bottom", 1, 0, 16,
ZONE_BOTTOM_TEXT, ZONE_BOTTOM_LONGTEXT, false)
add_integer_with_range(CFG_PREFIX "zones-lr", 1, 0, 16,
ZONE_LR_TEXT, ZONE_LR_LONGTEXT, false)
add_bool(CFG_PREFIX "zone-summary", false,
ZONE_SUMMARY_TEXT, ZONE_SUMMARY_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 for the built-in Live Video Processor only" ), 0 )
add_integer_with_range(CFG_PREFIX "edgeweightning", 3, 1, 30,
EDGE_TEXT, EDGE_LONGTEXT, false)
add_integer_with_range(CFG_PREFIX "brightness", 100, 50, 300,
BRIGHTNESS_TEXT, BRIGHTNESS_LONGTEXT, false)
add_integer_with_range(CFG_PREFIX "darknesslimit", 3, 0, 10,
DARKNESS_TEXT, DARKNESS_LONGTEXT, false)
add_integer_with_range(CFG_PREFIX "huewinsize", 3, 0, 5,
HUEWINSIZE_TEXT, HUEWINSIZE_LONGTEXT, false)
add_integer_with_range(CFG_PREFIX "satwinsize", 3, 0, 5,
SATWINSIZE_TEXT, SATWINSIZE_LONGTEXT, false)
add_integer(CFG_PREFIX "filtermode", (int)afmCombined,
FILTERMODE_TEXT, FILTERMODE_LONGTEXT, false )
change_integer_list(pi_filtermode_values, ppsz_filtermode_descriptions )
add_integer_with_range(CFG_PREFIX "meanlength", 300, 300, 5000,
MEANLENGTH_TEXT, MEANLENGTH_LONGTEXT, false)
add_integer_with_range(CFG_PREFIX "meanthreshold", 40, 1, 100,
MEANTHRESHOLD_TEXT, MEANTHRESHOLD_LONGTEXT, false)
add_integer_with_range(CFG_PREFIX "percentnew", 50, 1, 100,
MEANPERCENTNEW_TEXT, MEANPERCENTNEW_LONGTEXT, false)
add_integer_with_range(CFG_PREFIX "framedelay", 18, 0, 200,
FRAMEDELAY_TEXT, FRAMEDELAY_LONGTEXT, false)
/*
output channel reordering
*/
set_section( N_("Change channel assignment (fixes wrong wiring)" ), 0 )
add_integer( CFG_PREFIX "channel_0", 4,
CHANNEL_0_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
change_integer_list( pi_zone_assignment_values,
ppsz_zone_assignment_descriptions )
add_integer( CFG_PREFIX "channel_1", 3,
CHANNEL_1_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
change_integer_list( pi_zone_assignment_values,
ppsz_zone_assignment_descriptions )
add_integer( CFG_PREFIX "channel_2", 1,
CHANNEL_2_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
change_integer_list( pi_zone_assignment_values,
ppsz_zone_assignment_descriptions )
add_integer( CFG_PREFIX "channel_3", 0,
CHANNEL_3_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
change_integer_list( pi_zone_assignment_values,
ppsz_zone_assignment_descriptions )
add_integer( CFG_PREFIX "channel_4", 2,
CHANNEL_4_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, false )
change_integer_list( pi_zone_assignment_values,
ppsz_zone_assignment_descriptions )
add_string(CFG_PREFIX "channels", "",
CHANNELS_ASSIGN_TEXT, CHANNELS_ASSIGN_LONGTEXT, false )
/*
LED color white calibration
*/
set_section( N_("Adjust the white light to your LED stripes" ), 0 )
add_bool(CFG_PREFIX "whiteadj", true,
USEWHITEADJ_TEXT, USEWHITEADJ_LONGTEXT, false)
add_integer_with_range(CFG_PREFIX "white-red", 255, 0, 255,
WHITE_RED_TEXT, WHITE_RED_LONGTEXT, false)
add_integer_with_range(CFG_PREFIX "white-green", 255, 0, 255,
WHITE_GREEN_TEXT, WHITE_GREEN_LONGTEXT, false)
add_integer_with_range(CFG_PREFIX "white-blue", 255, 0, 255,
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_loadfile(CFG_PREFIX "gradient_zone_0", NULL,
ZONE_0_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
add_loadfile(CFG_PREFIX "gradient_zone_1", NULL,
ZONE_1_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
add_loadfile(CFG_PREFIX "gradient_zone_2", NULL,
ZONE_2_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
add_loadfile(CFG_PREFIX "gradient_zone_3", NULL,
ZONE_3_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
add_loadfile(CFG_PREFIX "gradient_zone_4", NULL,
ZONE_4_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, true )
add_directory(CFG_PREFIX "gradient_path", NULL,
GRADIENT_PATH_TEXT, GRADIENT_PATH_LONGTEXT, false )
#if defined(__ATMO_DEBUG__)
add_bool(CFG_PREFIX "saveframes", false,
SAVEFRAMES_TEXT, SAVEFRAMES_LONGTEXT, false)
add_string(CFG_PREFIX "framepath", "",
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,
WIDTH_TEXT, WIDTH_LONGTEXT, true)
add_integer_with_range(CFG_PREFIX "height", 48, 48, 384,
HEIGHT_TEXT, HEIGHT_LONGTEXT, true)
add_bool(CFG_PREFIX "showdots", false,
SHOW_DOTS_TEXT, SHOW_DOTS_LONGTEXT, false)
add_shortcut( "atmo" )
set_callbacks( CreateFilter, DestroyFilter )
vlc_module_end ()
static const char *const ppsz_filter_options[] = {
"device",
"serialdev",
"edgeweightning",
"brightness",
"darknesslimit",
"huewinsize",
"satwinsize",
"filtermode",
"meanlength",
"meanthreshold",
"percentnew",
"framedelay",
"zones-top",
"zones-bottom",
"zones-lr",
"zone-summary",
"channel_0",
"channel_1",
"channel_2",
"channel_3",
"channel_4",
"channels",
"whiteadj",
"white-red",
"white-green",
"white-blue",
"usepausecolor",
"pcolor-red",
"pcolor-green",
"pcolor-blue",
"fadesteps",
"ecolor-red",
"ecolor-green",
"ecolor-blue",
"efadesteps",
"dmx-channels",
"dmx-chbase",
"momo-channels",
"fnordlicht-amount",
#if defined(_WIN32 )
"atmowinexe",
#endif
#if defined(__ATMO_DEBUG__)
"saveframes" ,
"framepath",
#endif
"width",
"height",
"showdots",
"gradient_zone_0",
"gradient_zone_1",
"gradient_zone_2",
"gradient_zone_3",
"gradient_zone_4",
"gradient_path",
NULL
};
/*****************************************************************************
* fadethread_t: Color Fading Thread
*****************************************************************************
* changes slowly the color of the output if videostream gets paused...
*****************************************************************************
*/
typedef struct
{
filter_t *p_filter;
vlc_thread_t thread;
std::atomic_bool abort;
/* 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(void *);
/*****************************************************************************
* 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;
bool b_show_dots;
int32_t i_device_type;
bool b_swap_uv;
int32_t i_atmo_width;
int32_t i_atmo_height;
/* used to disable fadeout if less than 50 frames are processed
used to avoid long time waiting when switch quickly between
deinterlaceing modes, where the output filter chains is rebuild
on each switch
*/
int32_t i_frames_processed;
#if defined(__ATMO_DEBUG__)
bool b_saveframes;
uint32_t ui_frame_counter;
char sz_framepath[MAX_PATH];
#endif
/* 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 */
VLC_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);
void (*pf_ctrl_atmo_get_image_size)(int32_t *,int32_t *);
#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)
{
/* open com port */
/* setup Output Threads ... */
msg_Dbg( p_filter, "open atmo device...");
if(CAtmoTools::RecreateConnection(p_sys->p_atmo_dyndata)
== ATMO_TRUE)
{
return 1;
} else {
msg_Err( p_filter,"failed to open atmo 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();
CAtmoInput *p_input = p_atmo_dyndata->getLiveInput();
p_atmo_dyndata->setLiveInput( NULL );
if(p_input != NULL)
{
p_input->Terminate();
delete p_input;
msg_Dbg( p_filter, "input thread died peacefully");
}
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");
}
CAtmoPacketQueue *p_queue =
p_atmo_dyndata->getLivePacketQueue();
p_atmo_dyndata->setLivePacketQueue( NULL );
if(p_queue != NULL)
{
delete p_queue;
msg_Dbg( p_filter, "packetqueue removed");
}
/*
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 to LiveView
*/
static int32_t AtmoSwitchEffect(filter_t *p_filter, int32_t newMode)
{
filter_sys_t *p_sys = p_filter->p_sys;
msg_Dbg( p_filter, "AtmoSwitchEffect %d", newMode );
if(p_sys->p_atmo_config)
{
return CAtmoTools::SwitchEffect(p_sys->p_atmo_dyndata, emLivePicture);
#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;
msg_Dbg( p_filter, "AtmoSetLiveSource %d", newSource );
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)
*/
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(VLC_BITMAPINFOHEADER));
p_sys->mini_image_format.biSize = sizeof(VLC_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 &&
(p_atmo_dyndata->getLivePictureSource() == lpsExtern))
{
/*
the cast will go Ok because we are inside videolan there is only
this kind of effect thread implemented!
*/
CAtmoExternalCaptureInput *p_atmo_external_capture_input_thread =
(CAtmoExternalCaptureInput *)p_atmo_dyndata->getLiveInput();
if(p_atmo_external_capture_input_thread)
{
/*
the same as above inside videolan only this single kind of
input exists so we can cast without further tests!
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
} else
{
msg_Warn( p_filter, "AtmoSendPixelData no method");
}
}
/*
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)
{
msg_Dbg( p_filter, "shut down atmo!");
/*
if there is a still running show pause color thread kill him!
*/
CheckAndStopFadeThread(p_filter);
// perpare spawn fadeing thread
vlc_mutex_lock( &p_sys->filter_lock );
/*
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;
p_sys->p_fadethread = (fadethread_t *)calloc( 1, 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;
if(p_sys->i_frames_processed < 50)
p_sys->p_fadethread->i_steps = 1;
else
p_sys->p_fadethread->i_steps = p_sys->i_endfadesteps;
p_sys->p_fadethread->abort.store(false);
if( vlc_clone( &p_sys->p_fadethread->thread,
FadeToColorThread,
p_sys->p_fadethread,
VLC_THREAD_PRIORITY_LOW ) )
{
msg_Err( p_filter, "cannot create FadeToColorThread" );
free( 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_join(p_sys->p_fadethread->thread, NULL);
free(p_sys->p_fadethread);
p_sys->p_fadethread = NULL;
}
/*
the following happens only useing the
external AtmoWin Device Software
*/
if( !p_sys->p_atmo_config )
{
if(p_sys->i_AtmoOldEffect != emLivePicture)
AtmoSwitchEffect( p_filter, p_sys->i_AtmoOldEffect);
else
AtmoSetLiveSource( p_filter, lvsGDI );
}
/* close device connection etc. */
AtmoFinalize(p_filter, 1);
/* disable filter method .. */
p_sys->b_enabled = false;
}
}
/*
depending on mode setup imagesize to 64x48(classic), or defined
resolution of external atmowin.exe on windows
*/
static void Atmo_SetupImageSize(filter_t *p_filter)
{
filter_sys_t *p_sys = p_filter->p_sys;
/*
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");
if(p_sys->p_atmo_config)
{
#if defined(_WIN32)
} else if(p_sys->pf_ctrl_atmo_get_image_size)
{
/* on win32 with active ctrl dll */
p_sys->pf_ctrl_atmo_get_image_size( &p_sys->i_atmo_width,
&p_sys->i_atmo_height );
#endif
}
msg_Dbg(p_filter,"sample image size %d * %d pixels", p_sys->i_atmo_width,
p_sys->i_atmo_height);
}
/*
initialize the zone and channel mapping for the buildin atmolight adapter
*/
static void Atmo_SetupBuildZones(filter_t *p_filter)
{
filter_sys_t *p_sys = p_filter->p_sys;
p_sys->p_atmo_dyndata->LockCriticalSection();
CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
CAtmoChannelAssignment *p_channel_assignment =
p_atmo_config->getChannelAssignment(0);
// channel 0 - zone 4
p_channel_assignment->setZoneIndex( 0, var_CreateGetIntegerCommand(
p_filter, CFG_PREFIX "channel_0")
);
// channel 1 - zone 3
p_channel_assignment->setZoneIndex( 1, var_CreateGetIntegerCommand(
p_filter, CFG_PREFIX "channel_1")
);
// channel 2 - zone 1
p_channel_assignment->setZoneIndex( 2, var_CreateGetIntegerCommand(
p_filter, CFG_PREFIX "channel_2")
);
// channel 3 - zone 0
p_channel_assignment->setZoneIndex( 3, var_CreateGetIntegerCommand(
p_filter, CFG_PREFIX "channel_3")
);
// channel 4 - zone 2
p_channel_assignment->setZoneIndex( 4, var_CreateGetIntegerCommand(
p_filter, CFG_PREFIX "channel_4")
);
char *psz_channels = var_CreateGetStringCommand(
p_filter,
CFG_PREFIX "channels"
);
if( !EMPTY_STR(psz_channels) )
{
msg_Dbg( p_filter, "deal with new zone mapping %s", psz_channels );
int channel = 0;
char *psz_temp = psz_channels;
char *psz_start = psz_temp;
while( *psz_temp )
{
if(*psz_temp == ',' || *psz_temp == ';')
{
*psz_temp = 0;
if(*psz_start)
{
int zone = atoi( psz_start );
if( zone < -1 ||
zone >= p_channel_assignment->getSize()) {
msg_Warn( p_filter, "Zone %d out of range -1..%d",
zone, p_channel_assignment->getSize()-1 );
} else {
p_channel_assignment->setZoneIndex( channel, zone );
channel++;
}
}
psz_start = psz_temp;
psz_start++;
}
psz_temp++;
}
/*
process the rest of the string
*/
if( *psz_start && !*psz_temp )
{
int zone = atoi( psz_start );
if( zone < -1 ||
zone >= p_channel_assignment->getSize()) {
msg_Warn( p_filter, "Zone %d out of range -1..%d",
zone, p_channel_assignment->getSize()-1 );
} else {
p_channel_assignment->setZoneIndex( channel, zone );
}
}
}
free( psz_channels );
for(int i=0;i< p_channel_assignment->getSize() ;i++)
msg_Info( p_filter, "map zone %d to hardware channel %d",
p_channel_assignment->getZoneIndex( i ),
i
);
p_sys->p_atmo_dyndata->getAtmoConnection()
->SetChannelAssignment( p_channel_assignment );
/*
calculate the default gradients for each zone!
depending on the zone layout set before, this now
supports also multiple gradients on each side
(older versions could do this only with external
gradient bitmaps)
*/
p_sys->p_atmo_dyndata->CalculateDefaultZones();
/*
first try to load the old style defined gradient bitmaps
this could only be done for the first five zones
- should be deprecated -
*/
CAtmoZoneDefinition *p_zone;
char psz_gradient_var_name[30];
char *psz_gradient_file;
for(int i=0;i<CLASSIC_ATMO_NUM_ZONES;i++)
{
sprintf(psz_gradient_var_name, CFG_PREFIX "gradient_zone_%d", i);
psz_gradient_file = var_CreateGetStringCommand(
p_filter,
psz_gradient_var_name
);
if( !EMPTY_STR(psz_gradient_file) )
{
msg_Dbg( p_filter, "loading gradientfile %s for "\
"zone %d", psz_gradient_file, i);
p_zone = p_atmo_config->getZoneDefinition(i);
if( p_zone )
{
int i_res = p_zone->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);
}
}
}
free( psz_gradient_file );
}
/*
the new approach try to load a gradient bitmap for each zone
from a previously defined folder containing
zone_0.bmp
zone_1.bmp
zone_2.bmp etc.
*/
char *psz_gradient_path = var_CreateGetStringCommand(
p_filter,
CFG_PREFIX "gradient_path"
);
if( EMPTY_STR(psz_gradient_path) )
{
char *psz_file_name = (char *)malloc( strlen(psz_gradient_path) + 16 );
assert( psz_file_name );
for(int i=0; i < p_atmo_config->getZoneCount(); i++ )
{
p_zone = p_atmo_config->getZoneDefinition(i);
if( p_zone )
{
sprintf(psz_file_name, "%s%szone_%d.bmp",
psz_gradient_path, DIR_SEP, i );
int i_res = p_zone->LoadGradientFromBitmap( psz_file_name );
if( i_res == ATMO_LOAD_GRADIENT_OK )
{
msg_Dbg( p_filter, "loaded gradientfile %s for "\
"zone %d", psz_file_name, i);
}
if( (i_res != ATMO_LOAD_GRADIENT_OK) &&
(i_res != ATMO_LOAD_GRADIENT_FILENOTFOND) )
{
msg_Err( p_filter,"failed to load gradient '%s' with "\
"error %d",psz_file_name,i_res);
}
}
}
free( psz_file_name );
}
free( psz_gradient_path );
p_sys->p_atmo_dyndata->UnLockCriticalSection();
}
static void Atmo_SetupConfig(filter_t *p_filter, CAtmoConfig *p_atmo_config)
{
/*
figuring out the device ports (com-ports, ttys)
*/
char *psz_serialdev = var_CreateGetStringCommand( p_filter,
CFG_PREFIX "serialdev" );
char *psz_temp = psz_serialdev;
if( !EMPTY_STR(psz_serialdev) )
{
char *psz_token;
int i_port = 0;
int i;
int j;
msg_Dbg( p_filter, "use port(s) %s",psz_serialdev);
/*
psz_serialdev - may contain up to 4 COM ports for the quattro device
the quattro device is just hack of useing 4 classic devices as one
logical device - thanks that usb-com-ports exists :)
as Seperator I defined , or ; with the hope that these
characters are never part of a device name
*/
while( (psz_token = strsep(&psz_temp, ",;")) != NULL && i_port < 4 )
{
/*
psz_token may contain spaces we have to trim away
*/
i = 0;
j = 0;
/*
find first none space in string
*/
while( psz_token[i] == 32 ) i++;
/*
contains string only spaces or is empty? skip it
*/
if( !psz_token[i] )
continue;
/*
trim
*/
while( psz_token[i] && psz_token[i] != 32 )
psz_token[ j++ ] = psz_token[ i++ ];
psz_token[j++] = 0;
msg_Dbg( p_filter, "Serial Device [%d]: %s", i_port, psz_token );
p_atmo_config->setSerialDevice( i_port, psz_token );
i_port++;
}
}
else
{
msg_Err(p_filter,"no serial devicename(s) set");
}
free( psz_serialdev );
/*
configuration of light source layout arround the display
*/
p_atmo_config->setZonesTopCount(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-top")
);
p_atmo_config->setZonesBottomCount(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-bottom")
);
p_atmo_config->setZonesLRCount(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "zones-lr")
);
p_atmo_config->setZoneSummary(
var_CreateGetBoolCommand( p_filter, CFG_PREFIX "zone-summary")
);
p_atmo_config->setLiveViewFilterMode(
(AtmoFilterMode)var_CreateGetIntegerCommand( p_filter,
CFG_PREFIX "filtermode")
);
p_atmo_config->setLiveViewFilter_PercentNew(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "percentnew")
);
p_atmo_config->setLiveViewFilter_MeanLength(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "meanlength")
);
p_atmo_config->setLiveViewFilter_MeanThreshold(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "meanthreshold")
);
p_atmo_config->setLiveView_EdgeWeighting(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "edgeweightning")
);
p_atmo_config->setLiveView_BrightCorrect(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "brightness")
);
p_atmo_config->setLiveView_DarknessLimit(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "darknesslimit")
);
p_atmo_config->setLiveView_HueWinSize(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "huewinsize")
);
p_atmo_config->setLiveView_SatWinSize(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "satwinsize")
);
/* currently not required inside vlc */
p_atmo_config->setLiveView_WidescreenMode( 0 );
p_atmo_config->setLiveView_FrameDelay(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "framedelay")
);
p_atmo_config->setUseSoftwareWhiteAdj(
var_CreateGetBoolCommand( p_filter, CFG_PREFIX "whiteadj")
);
p_atmo_config->setWhiteAdjustment_Red(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-red")
);
p_atmo_config->setWhiteAdjustment_Green(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-green")
);
p_atmo_config->setWhiteAdjustment_Blue(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-blue")
);
/*
settings for DMX device only
*/
p_atmo_config->setDMX_RGB_Channels(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "dmx-channels")
);
char *psz_chbase = var_CreateGetStringCommand( p_filter,
CFG_PREFIX "dmx-chbase" );
if( !EMPTY_STR(psz_chbase) )
p_atmo_config->setDMX_BaseChannels( psz_chbase );
free( psz_chbase );
/*
momolight options
*/
p_atmo_config->setMoMo_Channels(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "momo-channels")
);
/*
fnordlicht options
*/
p_atmo_config->setFnordlicht_Amount(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "fnordlicht-amount")
);
}
/*
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)
{
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;
p_sys->i_device_type = var_CreateGetIntegerCommand( p_filter,
CFG_PREFIX "device");
/*
i_device_type
0 => use AtmoWin Software (only win32)
1 => use AtmoClassicConnection (direct)
2 => use AtmoMultiConnection (direct up to four serial ports required)
3 => use AtmoDmxConnection (simple serial DMX Device up to 255 channels)
*/
#if defined(_WIN32)
/*
only on _WIN32 the user has the choice between
internal driver and external
*/
if(p_sys->i_device_type == 0) {
/* Load the Com Wrapper Library (source available) */
p_sys->h_AtmoCtrl = LoadLibraryA("AtmoCtrlLib.dll");
if(p_sys->h_AtmoCtrl == NULL)
{
/*
be clever if the location of atmowin.exe is set
try to load the dll from the same folder :-)
*/
char *psz_path = var_CreateGetStringCommand( p_filter,
CFG_PREFIX "atmowinexe" );
if( !EMPTY_STR(psz_path) )
{
char *psz_bs = strrchr( psz_path , '\\');
if( psz_bs )
{
*psz_bs = 0;
/*
now format a new dll filename with complete path
*/
char *psz_dllname = NULL;
asprintf( &psz_dllname, "%s\\AtmoCtrlLib.dll", psz_path );
if( psz_dllname )
{
msg_Dbg( p_filter, "Try Loading '%s'", psz_dllname );
TCHAR* ptsz_dllname = ToT(psz_dllname);
p_sys->h_AtmoCtrl = LoadLibrary( ptsz_dllname );
free(ptsz_dllname);
}
free( psz_dllname );
}
}
free( psz_path );
}
if(p_sys->h_AtmoCtrl != NULL)
{
msg_Dbg( p_filter, "Load Library ok!");
/* 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.");
p_sys->pf_ctrl_atmo_get_image_size =
(void (*)(int32_t*,int32_t*))GetProcAddress(p_sys->h_AtmoCtrl,
"AtmoWinGetImageSize");
if(!p_sys->pf_ctrl_atmo_get_image_size)
msg_Err( p_filter, "export AtmoWinGetImageSize missing.");
} else {
/* the DLL is missing try internal filter ...*/
msg_Warn( p_filter,
"AtmoCtrlLib.dll missing fallback to internal atmo classic driver");
p_sys->i_device_type = 1;
}
}
#endif
if(p_sys->i_device_type >= 1) {
msg_Dbg( p_filter, "try use buildin driver %d ", p_sys->i_device_type);
/*
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...
*/
p_sys->p_atmo_config = new CAtmoConfig();
p_sys->p_atmo_dyndata = new CAtmoDynData(
(vlc_object_t *)p_filter,
p_sys->p_atmo_config
);
Atmo_SetupConfig( p_filter, p_sys->p_atmo_config );
switch(p_sys->i_device_type)
{
case 1:
p_sys->p_atmo_config->setConnectionType( actClassicAtmo );
break;
case 2:
p_sys->p_atmo_config->setConnectionType( actMultiAtmo );
break;
case 3:
p_sys->p_atmo_config->setConnectionType( actDMX );
break;
case 4:
p_sys->p_atmo_config->setConnectionType( actMoMoLight );
break;
case 5:
p_sys->p_atmo_config->setConnectionType( actFnordlicht );
break;
default:
msg_Warn( p_filter, "invalid device type %d found",
p_sys->i_device_type );
}
msg_Dbg( p_filter, "buildin driver config set");
}
switch( p_filter->fmt_in.video.i_chroma )
{
case VLC_CODEC_I420:
p_sys->pf_extract_mini_image = ExtractMiniImage_YUV;
p_sys->b_swap_uv = false;
break;
case VLC_CODEC_YV12:
p_sys->pf_extract_mini_image = ExtractMiniImage_YUV;
p_sys->b_swap_uv = true;
break;
default:
msg_Warn( p_filter, "InitFilter-unsupported chroma: %4.4s",
(char *)&p_filter->fmt_in.video.i_chroma);
p_sys->pf_extract_mini_image = NULL;
}
/*
for debugging purpose show the samplinggrid on each frame as
white dots
*/
p_sys->b_show_dots = var_CreateGetBoolCommand( p_filter,
CFG_PREFIX "showdots"
);
#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 ) || defined( __OS2__ )
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
/*
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 want to use AtmoLight!)
*/
int i = AtmoInitialize(p_filter, false);
#if defined( _WIN32 )
if((i != 1) && (p_sys->i_device_type == 0))
{
/*
COM Server for AtmoLight not running ?
if the exe path is configured try to start the "userspace" driver
*/
char *psz_path = var_CreateGetStringCommand( p_filter,
CFG_PREFIX "atmowinexe" );
LPTSTR ptsz_path = ToT(psz_path);
if(psz_path != NULL)
{
STARTUPINFO startupinfo;
PROCESS_INFORMATION pinfo;
memset(&startupinfo, 0, sizeof(STARTUPINFO));
startupinfo.cb = sizeof(STARTUPINFO);
if(CreateProcess(ptsz_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);
free(ptsz_path);
}
}
#endif
if(i == 1) /* Init Atmolight success... */
{
msg_Dbg( p_filter, "AtmoInitialize Ok!");
/*
configure
p_sys->i_atmo_width and p_sys->i_atmo_height
if the external AtmoWinA.exe is used, it may require
a other sample image size than 64 x 48
(this overrides the settings of the filter)
*/
Atmo_SetupImageSize( p_filter );
if( p_sys->i_device_type >= 1 )
{
/*
AtmoConnection class initialized now we can initialize
the default zone and channel mappings
*/
Atmo_SetupBuildZones( p_filter );
}
/* 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!
- the buildin driver launches the live view thread in that case
*/
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;
msg_Dbg( p_filter, "Atmo Filter Enabled Ok!");
}
}
/*****************************************************************************
* 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 )
return VLC_ENOMEM;
/* set all entries to zero */
memset(p_sys, 0, sizeof( filter_sys_t ));
vlc_mutex_init( &p_sys->filter_lock );
msg_Dbg( p_filter, "Create Atmo Filter");
/* 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 );
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;
msg_Dbg( p_filter, "Destroy Atmo 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 environment 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 won't 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;
if(p_sys->b_swap_uv)
{
/*
swap u and v plane for YV12 images
*/
uint8_t *p_temp_plane = p_src_u;
p_src_u = p_src_v;
p_src_v = p_temp_plane;
}
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;
}
}
if(p_sys->b_show_dots)
{
for(i_row = 1; i_row < i_row_count; i_row++)
{
i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
+ p_sys->i_crop_y_offset;
i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
p_inpic->format.i_visible_height;
p_src_y = p_inpic->p[Y_PLANE].p_pixels +
p_inpic->p[Y_PLANE].i_pitch * i_y_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;
i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
p_inpic->format.i_visible_width;
p_src_y[i_xpos_y] = 255;
}
}
}
}
/******************************************************************************
* 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*/
VLC_BITMAPINFO bmp_info;
BITMAPFILEHEADER bmp_fileheader;
FILE *fp_bitmap;
memset(&bmp_info, 0, sizeof(VLC_BITMAPINFO));
bmp_info.bmiHeader.biSize = sizeof(VLC_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(VLC_BITMAPINFOHEADER) +
bmp_info.bmiHeader.biSizeImage;
bmp_fileheader.bfType = VLC_TWOCC('B','M');
bmp_fileheader.bfOffBits = sizeof(BITMAPFILEHEADER) +
sizeof(VLC_BITMAPINFOHEADER);
fp_bitmap = fopen(psz_filename,"wb");
if( fp_bitmap != NULL)
{
fwrite(&bmp_fileheader, sizeof(BITMAPFILEHEADER), 1, fp_bitmap);
fwrite(&bmp_info.bmiHeader, sizeof(VLC_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;
#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 && p_sys->sz_framepath[0] != 0 )
{
if((p_sys->ui_frame_counter & 127) == 0)
{
sprintf(sz_filename,"%satmo_dbg_%06u.bmp",p_sys->sz_framepath,
p_sys->ui_frame_counter);
msg_Dbg(p_filter, "SaveFrame %s",sz_filename);
SaveBitmap(p_sys, p_transfer, sz_filename);
}
}
msg_Dbg( p_filter, "AtmoFrame %u Time: %d ms", p_sys->ui_frame_counter,
mdate() / 1000);
p_sys->ui_frame_counter++;
#endif
p_sys->i_frames_processed++;
/* 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;
picture_t *p_outpic = filter_NewPicture( p_filter );
if( !p_outpic )
{
picture_Release( p_pic );
return NULL;
}
picture_CopyPixels( p_outpic, p_pic );
vlc_mutex_lock( &p_sys->filter_lock );
if(p_sys->b_enabled && p_sys->pf_extract_mini_image &&
!p_sys->b_pause_live)
{
p_sys->i_crop_x_offset = p_filter->fmt_in.video.i_x_offset;
p_sys->i_crop_y_offset = p_filter->fmt_in.video.i_y_offset;
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;
CreateMiniImage(p_filter, p_outpic);
}
vlc_mutex_unlock( &p_sys->filter_lock );
return CopyInfoAndRelease( p_outpic, 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(void *obj)
{
fadethread_t *p_fadethread = (fadethread_t *)obj;
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;
uint8_t *p_source = NULL;
int canc = vlc_savecancel ();
/* 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->abort.load() &&
(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->abort.load();
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?
*/
msleep(40000);
}
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);
vlc_restorecancel (canc);
return NULL;
}
/*****************************************************************************
* 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->abort.store(true);
vlc_join(p_sys->p_fadethread->thread, NULL);
free(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 AtmoSettingsCallback( vlc_object_t *, 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;
vlc_mutex_lock( &p_sys->filter_lock );
if( !strcmp( psz_var, CFG_PREFIX "showdots" ))
{
p_sys->b_show_dots = newval.b_bool;
}
CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
if(p_atmo_config)
{
msg_Dbg(p_filter, "apply AtmoSettingsCallback %s (int: %" PRId64 " -> %" PRId64 ")",
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 );
}
vlc_mutex_unlock( &p_sys->filter_lock );
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 );
var_AddCallback( p_filter, CFG_PREFIX "showdots",
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 );
var_DelCallback( p_filter, CFG_PREFIX "showdots",
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
......@@ -1084,30 +1084,6 @@ modules/video_filter/adjust.c
modules/video_filter/alphamask.c
modules/video_filter/anaglyph.c
modules/video_filter/antiflicker.c
modules/video_filter/atmo/AtmoCalculations.cpp
modules/video_filter/atmo/AtmoCalculations.h
modules/video_filter/atmo/AtmoConfig.cpp
modules/video_filter/atmo/AtmoConfig.h
modules/video_filter/atmo/AtmoConnection.cpp
modules/video_filter/atmo/AtmoConnection.h
modules/video_filter/atmo/atmo.cpp
modules/video_filter/atmo/AtmoDefs.h
modules/video_filter/atmo/AtmoDynData.cpp
modules/video_filter/atmo/AtmoDynData.h
modules/video_filter/atmo/AtmoExternalCaptureInput.cpp
modules/video_filter/atmo/AtmoExternalCaptureInput.h
modules/video_filter/atmo/AtmoInput.cpp
modules/video_filter/atmo/AtmoInput.h
modules/video_filter/atmo/AtmoLiveView.cpp
modules/video_filter/atmo/AtmoLiveView.h
modules/video_filter/atmo/AtmoOutputFilter.cpp
modules/video_filter/atmo/AtmoOutputFilter.h
modules/video_filter/atmo/AtmoThread.cpp
modules/video_filter/atmo/AtmoThread.h
modules/video_filter/atmo/AtmoTools.cpp
modules/video_filter/atmo/AtmoTools.h
modules/video_filter/atmo/AtmoZoneDefinition.cpp
modules/video_filter/atmo/AtmoZoneDefinition.h
modules/video_filter/audiobargraph_v.c
modules/video_filter/ball.c
modules/video_filter/blendbench.c
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment