Commit 1b637157 authored by Antoine Cellerier's avatar Antoine Cellerier

video filter module - for thehomebrewAmbiLight (AtmoLight) [2/3]: atmo-video_filter.diff

parent bcb07441
/*
* calculations.c: calculations needed by the input devices
*
* See the README file for copyright information and how to reach the author.
*
* $Id$
*/
#include <stdlib.h>
#include <string.h>
#include "AtmoDefs.h"
#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
// macros
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
#define POS_DIV(a, b) ( (a)/(b) + ( ((a)%(b) >= (b)/2 ) ? 1 : 0) )
tColorPacket CalcColorsAnalyzeHSV(CAtmoConfig *pAtmoConfig, tHSVColor *HSV_Img)
{
int i; // counter
// static tWeightPacket Weight[IMAGE_SIZE];
// 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)
static int Weight[ATMO_NUM_CHANNELS][IMAGE_SIZE];
/***************************************************************************/
/* Weight */
/***************************************************************************/
static int LastEdgeWeighting = -1;
static int LastWidescreenMode = -1;
int AtmoSetup_EdgeWeighting = pAtmoConfig->getLiveView_EdgeWeighting();
int AtmoSetup_WidescreenMode = pAtmoConfig->getLiveView_WidescreenMode();
int AtmoSetup_DarknessLimit = pAtmoConfig->getLiveView_DarknessLimit();
int AtmoSetup_BrightCorrect = pAtmoConfig->getLiveView_BrightCorrect();
int AtmoSetup_SatWinSize = pAtmoConfig->getLiveView_SatWinSize();
// calculate only if setup has changed
if ((AtmoSetup_EdgeWeighting != LastEdgeWeighting) ||
(AtmoSetup_WidescreenMode != LastWidescreenMode))
{
for(i =0 ;i < ATMO_NUM_CHANNELS; i++)
pAtmoConfig->getZoneDefinition(i)->UpdateWeighting(&Weight[i][0],
AtmoSetup_WidescreenMode,
AtmoSetup_EdgeWeighting);
/*
original code from VDR sources... my one is just more flexible?*g*
i = 0;
for (int row = 0; row < CAP_HEIGHT; row++)
{
float row_norm = (float)row / ((float)CAP_HEIGHT - 1.0f); // [0;Height] -> [0;1]
float weight_3 = pow(1.0f - row_norm, AtmoSetup_EdgeWeighting); // top
float weight_4 = pow(row_norm, AtmoSetup_EdgeWeighting); // bottom
for (int column = 0; column < CAP_WIDTH; column++)
{
// if widescreen mode, top and bottom of the picture are not
if ((AtmoSetup_WidescreenMode == 1) && ((row <= CAP_HEIGHT/8) || (row >= (7*CAP_HEIGHT)/8)))
{
Weight[i].channel[0] = Weight[i].channel[1] = Weight[i].channel[2] = Weight[i].channel[3] = Weight[i].channel[4] = 0;
}
else
{
float column_norm = (float)column / ((float)CAP_WIDTH - 1.0f); // [0;Width] -> [0;1]
Weight[i].channel[0] = 255;
Weight[i].channel[1] = (int)(255.0 * (float)pow((1.0 - column_norm), AtmoSetup_EdgeWeighting));
Weight[i].channel[2] = (int)(255.0 * (float)pow(column_norm, AtmoSetup_EdgeWeighting));
Weight[i].channel[3] = (int)(255.0 * (float)weight_3);
Weight[i].channel[4] = (int)(255.0 * (float)weight_4);
}
i++;
}
}
*/
LastEdgeWeighting = AtmoSetup_EdgeWeighting;
LastWidescreenMode = AtmoSetup_WidescreenMode;
}
/***************************************************************************/
/* Hue */
/***************************************************************************/
/*----------------------------*/
/* hue histogram builtup */
/*----------------------------*/
// HSV histogram
long int hue_hist[ATMO_NUM_CHANNELS][h_MAX+1];
// clean histogram
memset(&hue_hist, 0, sizeof(hue_hist));
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 (HSV_Img[i].v > 10*AtmoSetup_DarknessLimit)
{
// builtup histogram for the 5 channels
for (int channel = 0; channel < ATMO_NUM_CHANNELS; channel++)
{
// Add weight to channel
hue_hist[channel][HSV_Img[i].h] += Weight[channel][i] * HSV_Img[i].v;
}
}
i++;
}
}
/*----------------------------*/
/* hue histogram windowing */
/*----------------------------*/
// windowed HSV histogram
long int w_hue_hist[ATMO_NUM_CHANNELS][h_MAX+1];
// clean windowed histogram
memset(&w_hue_hist, 0, sizeof(w_hue_hist));
// steps in each direction; eg. 2 => -2 -1 0 1 2 windowing
int hue_windowsize = 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++)
{
// adressed 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 5 channels
for (int channel = 0; channel < ATMO_NUM_CHANNELS; channel++)
{
// apply lite triangular window design with gradient of 10% per discrete step
w_hue_hist[channel][i] += hue_hist[channel][myidx] * ((hue_windowsize+1)-abs(mywin)); // apply window
}
}
}
/*--------------------------------------*/
/* analyze histogram for most used hue */
/*--------------------------------------*/
// index of last maximum
static int most_used_hue_last[ATMO_NUM_CHANNELS] = {0, 0, 0, 0, 0};
// resulting hue for each channel
int most_used_hue[ATMO_NUM_CHANNELS];
memset(&most_used_hue, 0, sizeof(most_used_hue));
for (int channel = 0; channel < ATMO_NUM_CHANNELS; channel++)
{
int value = 0;
for (i = 0; i < h_MAX+1; i++) // walk through histogram
{
if (w_hue_hist[channel][i] > value) // if new value bigger then old one
{
most_used_hue[channel] = i; // remember index
value = w_hue_hist[channel][i]; // and value
}
}
float percent = (float)w_hue_hist[channel][most_used_hue_last[channel]] / (float)value;
if (percent > 0.93f) // less than 7% difference?
{
most_used_hue[channel] = most_used_hue_last[channel]; // use last index
}
most_used_hue_last[channel] = most_used_hue[channel]; // save current index of most used hue
}
/***************************************************************************/
/* saturation */
/***************************************************************************/
// sat histogram
long int sat_hist[ATMO_NUM_CHANNELS][s_MAX+1];
// hue of the pixel we are working at
int pixel_hue = 0;
// clean histogram
memset(&sat_hist, 0, sizeof(sat_hist));
/*--------------------------------------*/
/* saturation histogram builtup */
/*--------------------------------------*/
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 (HSV_Img[i].v > 10*AtmoSetup_DarknessLimit)
{
// find histogram position for pixel
pixel_hue = HSV_Img[i].h;
// TODO: brightness calculation(if we require it some time)
for (int channel = 0; channel < ATMO_NUM_CHANNELS; channel++)
{
// only use pixel for histogram if hue is near most_used_hue
if ((pixel_hue > most_used_hue[channel] - hue_windowsize) &&
(pixel_hue < most_used_hue[channel] + hue_windowsize))
{
// build histogram
// sat_hist[channel][HSV_Img[i].s] += Weight[i].channel[channel] * HSV_Img[i].v;
sat_hist[channel][HSV_Img[i].s] += Weight[channel][i] * HSV_Img[i].v;
}
}
}
i++;
}
}
/*--------------------------------------*/
/* saturation histogram windowing */
/*--------------------------------------*/
// windowed HSV histogram
long int w_sat_hist[ATMO_NUM_CHANNELS][s_MAX+1];
// clean windowed histogram
memset(&w_sat_hist, 0, sizeof(w_sat_hist));
// 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++)
{
// adressed 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 channel = 0; channel < ATMO_NUM_CHANNELS; channel++)
{
/*
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
}
}
}
/*--------------------------------------*/
/* analyze histogram for most used sat */
/*--------------------------------------*/
// resulting sat (most_used_hue) for each channel
int most_used_sat[ATMO_NUM_CHANNELS];
memset(&most_used_sat, 0, sizeof(most_used_sat));
for (int channel = 0; channel < ATMO_NUM_CHANNELS; channel++)
{
int value = 0;
// walk trough histogram
for (i = 0; i < s_MAX+1; i++)
{
// if new value bigger then old one
if (w_sat_hist[channel][i] > value)
{
// remember index
most_used_sat[channel] = i;
// and value
value = w_sat_hist[channel][i];
}
}
}
/*----------------------------------------------------------*/
/* calculate average brightness within HSV image */
/* uniform Brightness for all channels is calculated */
/*----------------------------------------------------------*/
int l_counter = 0;
// average brightness (value)
long int value_avg = 0;
// TODO: extract into a function? in sat-histo-built
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 > 10*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 = 10 * AtmoSetup_DarknessLimit; }
/*----------------------------*/
/* adjust and copy results */
/*----------------------------*/
tHSVColor hsv_pixel;
// storage container for resulting RGB values
tColorPacket ColorChannels;
for (int channel = 0; channel < ATMO_NUM_CHANNELS; channel++)
{
// copy values
hsv_pixel.h = most_used_hue[channel];
hsv_pixel.s = most_used_sat[channel];
// 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;
// convert back to rgb
ColorChannels.channel[channel] = HSV2RGB(hsv_pixel);
}
return ColorChannels;
}
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 = MIN(MIN(r, g), b);
max = MAX(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"
tColorPacket CalcColorsAnalyzeHSV(CAtmoConfig *pAtmoConfig, tHSVColor *HSV_Img);
tHSVColor RGB2HSV(tRGBColor color);
tRGBColor HSV2RGB(tHSVColor color);
#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$
*/
#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 = actSerialPort;
for(int i=0;i<10;i++)
m_ChannelAssignments[i] = NULL;
#if defined (_ATMO_VLC_PLUGIN_)
m_devicename = NULL;
#endif
// load all config values with there defaults
LoadDefaults();
// CAtmoZoneDefinition *m_ZoneDefinitions[ATMO_NUM_CHANNELS];
// generate default channel parameters which may be loaded later from .bmp files
for(int i=0;i<ATMO_NUM_CHANNELS;i++) {
m_ZoneDefinitions[i] = new CAtmoZoneDefinition();
m_ZoneDefinitions[i]->setZoneNumber(i);
switch(i) {
case 0: // summary channel
m_ZoneDefinitions[i]->Fill(255);
break;
case 1: // left channel
m_ZoneDefinitions[i]->FillGradientFromLeft();
break;
case 2: // right channel
m_ZoneDefinitions[i]->FillGradientFromRight();
break;
case 3: // top channel
m_ZoneDefinitions[i]->FillGradientFromTop();
break;
case 4: // bottom channel
m_ZoneDefinitions[i]->FillGradientFromBottom();
break;
}
}
}
CAtmoConfig::~CAtmoConfig() {
// and finally cleanup...
clearAllChannelMappings();
#if !defined (WIN32)
if(m_devicename)
free(m_devicename);
#endif
}
void CAtmoConfig::LoadDefaults() {
// m_eAtmoConnectionType = actSerialPort;
// m_Comport
m_eEffectMode = emDisabled;
m_WhiteAdjustment_Red = 255;
m_WhiteAdjustment_Green = 255;
m_WhiteAdjustment_Blue = 255;
m_UseSoftwareWhiteAdj = 1;
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_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 = 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;
clearAllChannelMappings();
m_CurrentChannelAssignment = 0;
tChannelAssignment *temp = temp = new tChannelAssignment;
temp->system = true;
for(int i=0;i<ATMO_NUM_CHANNELS;i++)
temp->mappings[i] = i;
strcpy(temp->name,"Standard");
this->m_ChannelAssignments[0] = temp;
}
void CAtmoConfig::Assign(CAtmoConfig *pAtmoConfigSrc) {
#if defined(_ATMO_VLC_PLUGIN_)
this->setSerialDevice(pAtmoConfigSrc->getSerialDevice());
#else
this->m_Comport = pAtmoConfigSrc->m_Comport;
#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_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_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;
clearChannelMappings();
for(int i=1;i<pAtmoConfigSrc->getNumChannelAssignments();i++) {
tChannelAssignment *ta = pAtmoConfigSrc->m_ChannelAssignments[i];
if(ta!=NULL) {
tChannelAssignment *dest = this->m_ChannelAssignments[i];
if(dest == NULL) {
dest = new tChannelAssignment;
this->m_ChannelAssignments[i] = dest;
}
memcpy(dest, ta, sizeof(tChannelAssignment));
}
}
}
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++) {
tChannelAssignment *ca = m_ChannelAssignments[i];
if(ca!=NULL)
delete ca;
m_ChannelAssignments[i] = NULL;
}
}
void CAtmoConfig::clearAllChannelMappings() {
for(int i=0;i<10;i++) {
tChannelAssignment *ca = m_ChannelAssignments[i];
if(ca!=NULL)
delete ca;
m_ChannelAssignments[i] = NULL;
}
}
void CAtmoConfig::AddChannelAssignment(tChannelAssignment *ta) {
for(int i=0;i<10;i++) {
if(m_ChannelAssignments[i] == NULL) {
m_ChannelAssignments[i] = ta;
break;
}
}
}
void CAtmoConfig::SetChannelAssignment(int index, tChannelAssignment *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 >= ATMO_NUM_CHANNELS)
return NULL;
return m_ZoneDefinitions[zoneIndex];
}
/*
* 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 "AtmoDefs.h"
#include "AtmoZoneDefinition.h"
#if defined(_ATMO_VLC_PLUGIN_)
# include <stdlib.h>
# include <string.h>
#endif
class CAtmoConfig {
protected:
int m_IsShowConfigDialog;
#if defined(_ATMO_VLC_PLUGIN_)
char *m_devicename;
#else
int m_Comport;
#endif
enum AtmoConnectionType m_eAtmoConnectionType;
enum EffectMode m_eEffectMode;
protected:
ATMO_BOOL m_UseSoftwareWhiteAdj;
int m_WhiteAdjustment_Red;
int m_WhiteAdjustment_Green;
int m_WhiteAdjustment_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?)
*/
tChannelAssignment *m_ChannelAssignments[10];
int m_CurrentChannelAssignment;
protected:
CAtmoZoneDefinition *m_ZoneDefinitions[ATMO_NUM_CHANNELS];
protected:
/* Live View Parameters (most interesting) */
AtmoFilterMode m_LiveViewFilterMode;
int m_LiveViewFilter_PercentNew;
int m_LiveViewFilter_MeanLength;
int m_LiveViewFilter_MeanThreshold;
// 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;
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;
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);
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(char *newdevice) { if(m_devicename) free(m_devicename); if(newdevice) m_devicename = strdup(newdevice); else m_devicename = NULL; }
#else
int getComport() { return m_Comport; }
void setComport(int value) { m_Comport = value; }
#endif
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; }
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; }
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_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 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; }
tChannelAssignment *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(tChannelAssignment *ta);
void SetChannelAssignment(int index, tChannelAssignment *ta);
CAtmoZoneDefinition *getZoneDefinition(int zoneIndex);
};
#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$
*/
#include "AtmoConnection.h"
CAtmoConnection::CAtmoConnection(CAtmoConfig *cfg)
{
this->m_pAtmoConfig = cfg;
if(cfg->getNumChannelAssignments()>0) {
tChannelAssignment *ca = cfg->getChannelAssignment(0);
for(int i=0;i<ATMO_NUM_CHANNELS;i++) {
m_ChannelAssignment[i] = ca->mappings[i];
}
} else {
for(int i=0;i<ATMO_NUM_CHANNELS;i++) {
m_ChannelAssignment[i] = i;
}
}
}
void CAtmoConnection::SetChannelAssignment(tChannelAssignment *ca) {
for(int i=0;i<ATMO_NUM_CHANNELS;i++) {
m_ChannelAssignment[i] = ca->mappings[i];
}
}
CAtmoConnection::~CAtmoConnection(void)
{
if(isOpen())
CloseConnection();
}
/*
* 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 "AtmoDefs.h"
#include "AtmoConfig.h"
class CAtmoConnection
{
protected:
CAtmoConfig *m_pAtmoConfig;
int m_ChannelAssignment[ATMO_NUM_CHANNELS];
public:
CAtmoConnection(CAtmoConfig *cfg);
virtual ~CAtmoConnection(void);
virtual ATMO_BOOL OpenConnection() { return false; }
virtual void CloseConnection() {};
virtual ATMO_BOOL isOpen(void) { return false; }
virtual ATMO_BOOL SendData(unsigned char numChannels,
int red[],
int green[],
int blue[]) { return false; }
virtual ATMO_BOOL SendData(tColorPacket data) { return false; }
virtual ATMO_BOOL setChannelColor(int channel, tRGBColor color) { return false; }
virtual ATMO_BOOL setChannelValues(int numValues,unsigned char *channel_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; }
virtual void SetChannelAssignment(tChannelAssignment *ca);
};
#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 "config.h"
# include <vlc/vlc.h>
/* some things need to be changed if this code is used inside VideoLan Filter Module */
# define _ATMO_VLC_PLUGIN_
# define ATMO_BOOL vlc_bool_t
# define ATMO_TRUE VLC_TRUE
# define ATMO_FALSE VLC_FALSE
#else
typedef int ATMO_BOOL;
# define ATMO_TRUE 1
# define ATMO_FALSE 0
#endif
#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
#define FCC(ch4) ((((DWORD)(ch4) & 0xFF) << 24) | \
(((DWORD)(ch4) & 0xFF00) << 8) | \
(((DWORD)(ch4) & 0xFF0000) >> 8) | \
(((DWORD)(ch4) & 0xFF000000) >> 24))
// maximal Anzahl Kanle...
#define ATMO_NUM_CHANNELS 5
// capture width/height
#define CAP_WIDTH 64
#define CAP_HEIGHT 48
// imagesize
#define IMAGE_SIZE (CAP_WIDTH * CAP_HEIGHT)
enum AtmoConnectionType
{
actSerialPort = 0,
actDummy = 1,
actDMX = 2
};
static const char *AtmoDeviceTypes[] = {
"Atmo",
"Dummy",
"DMX"
};
#define ATMO_DEVICE_COUNT 3
#if defined(_ATMO_VLC_PLUGIN_)
enum EffectMode {
emUndefined = -1,
emDisabled = 0,
emStaticColor = 1,
emLivePicture = 2
};
#else
enum EffectMode {
emUndefined = -1,
emDisabled = 0,
emStaticColor = 1,
emLivePicture = 2,
emColorChange = 3,
emLrColorChange = 4
};
#endif
enum AtmoFilterMode {
afmNoFilter,
afmCombined,
afmPercent
};
typedef struct {
ATMO_BOOL system;
char name[64];
int mappings[ATMO_NUM_CHANNELS];
} tChannelAssignment;
// --- tRGBColor --------------------------------------------------------------
typedef struct
{
unsigned char r, g, b;
} tRGBColor;
// --- tColorPacket -----------------------------------------------------------
typedef struct
{
tRGBColor channel[ATMO_NUM_CHANNELS];
} tColorPacket;
// --- tRGBColorLongInt -------------------------------------------------------
typedef struct
{
long int r, g, b;
} tRGBColorLongInt;
// --- tColorPacketLongInt ----------------------------------------------------
typedef struct
{
tRGBColorLongInt channel[ATMO_NUM_CHANNELS];
} tColorPacketLongInt;
// --- tWeightPacket ----------------------------------------------------------
typedef struct
{
int channel[ATMO_NUM_CHANNELS];
} tWeightPacket;
// --- tHSVColor --------------------------------------------------------------
typedef struct
{
unsigned char h, s, v;
} tHSVColor;
#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$
*/
#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;
vlc_mutex_init( p_atmo_filter, &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;
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
}
/*
* 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 "AtmoDefs.h"
#include "AtmoThread.h"
#include "AtmoConfig.h"
#include "AtmoConnection.h"
#if !defined(_ATMO_VLC_PLUGIN_)
# include "AtmoDisplays.h"
#else
# include <vlc/vlc.h>
# include <vlc_threads_funcs.h>
#endif
/*
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?
Problem: MultiThreading! todo semaphore, mutex!
Allways stop the current effect Thread before changing AtmoConnection or
AtmoConfig!
*/
class CAtmoDynData
{
private:
CThread *m_pCurrentEffectThread;
CAtmoConnection *m_pAtmoConnection;
CAtmoConfig *m_pAtmoConfig;
#if !defined(_ATMO_VLC_PLUGIN_)
CAtmoDisplays *m_pAtmoDisplays;
HINSTANCE m_hInst;
CRITICAL_SECTION m_RemoteCallCriticalSection;
#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; }
CAtmoConnection *getAtmoConnection() { return m_pAtmoConnection; }
void setAtmoConnection(CAtmoConnection *value) { m_pAtmoConnection = value; }
CAtmoConfig *getAtmoConfig() { return m_pAtmoConfig; }
#if !defined(_ATMO_VLC_PLUGIN_)
CAtmoDisplays *getAtmoDisplays() { return m_pAtmoDisplays; }
HINSTANCE getHinstance() { return m_hInst; }
#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$
*/
#include "AtmoExternalCaptureInput.h"
#include "AtmoTools.h"
#if defined(_ATMO_VLC_PLUGIN_)
CAtmoExternalCaptureInput::CAtmoExternalCaptureInput(CAtmoDynData *pAtmoDynData) :
CAtmoInput(pAtmoDynData),
CThread(pAtmoDynData->getAtmoFilter())
{
m_pCurrentFramePixels = NULL;
vlc_cond_init( this->m_pAtmoThread, &m_WakeupCond );
vlc_mutex_init( m_pAtmoThread, &m_WakeupLock );
msg_Dbg( m_pAtmoThread, "CAtmoExternalCaptureInput created.");
}
#else
CAtmoExternalCaptureInput::CAtmoExternalCaptureInput(CAtmoDynData *pAtmoDynData) :
CAtmoInput(pAtmoDynData)
{
m_hWakeupEvent = CreateEvent(NULL,ATMO_FALSE,ATMO_FALSE,NULL);
m_pCurrentFramePixels = NULL;
}
#endif
CAtmoExternalCaptureInput::~CAtmoExternalCaptureInput(void)
{
/* if there is still an unprocessed bufferpicture do kill it */
if(m_pCurrentFramePixels != NULL)
free(m_pCurrentFramePixels);
#if defined(_ATMO_VLC_PLUGIN_)
vlc_cond_destroy( &m_WakeupCond );
vlc_mutex_destroy(&m_WakeupLock);
msg_Dbg( m_pAtmoThread, "CAtmoExternalCaptureInput destroyed.");
#else
CloseHandle(m_hWakeupEvent);
#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;
}
tColorPacket CAtmoExternalCaptureInput::GetColorPacket(void)
{
return this->m_ColorPacket;
}
/*
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(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( !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_mutex_lock( &m_WakeupLock );
vlc_cond_signal( &m_WakeupCond );
vlc_mutex_unlock( &m_WakeupLock );
#else
SetEvent(m_hWakeupEvent);
#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)
{
msg_Dbg( m_pAtmoThread, "CAtmoExternalCaptureInput::Execute(void)");
int i = 0;
vlc_mutex_lock( &m_WakeupLock );
while ((this->m_bTerminated == ATMO_FALSE) && (this->m_pAtmoThread->b_die == VLC_FALSE)) {
int value = vlc_cond_timedwait(&m_WakeupCond, &m_WakeupLock, mdate() + I64C(75000));
if(!value) {
/* DeliverNewSourceDataPaket delivered new work for me... get it! */
CalcColors(); // read picture and calculate colors
this->m_FrameArrived = ATMO_TRUE;
}
i++;
if(i == 100) {
i = 0;
#if !defined(WIN32)
/* kludge for pthreads? using the same condition variable too often results in hanging the pthread
call inside vlc_cond_timedwait...
*/
#ifdef _ATMO_KLUDGE_
vlc_cond_destroy( &m_WakeupCond );
vlc_cond_init( m_pAtmoThread, &m_WakeupCond );
#endif
#endif
}
}
vlc_mutex_unlock( &m_WakeupLock );
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,ATMO_FALSE,INFINITE);
if(event == WAIT_OBJECT_0) {
// Terminate Thread Event was set... say good bye...!
break;
}
if(event == (WAIT_OBJECT_0+1)) {
CalcColors(); // read picture and calculate colors
this->m_FrameArrived = ATMO_TRUE;
}
}
return 0;
}
#endif
void CAtmoExternalCaptureInput::WaitForNextFrame(DWORD timeout)
{
this->m_FrameArrived = ATMO_FALSE;
for(DWORD i=0;(i<timeout) && !m_FrameArrived;i++)
#if defined (_ATMO_VLC_PLUGIN_)
msleep(1000);
#else
Sleep(1);
#endif
if(this->m_pAtmoDynData)
{
CAtmoConfig *cfg = this->m_pAtmoDynData->getAtmoConfig();
if(cfg)
{
int delay = cfg->getLiveView_FrameDelay();
if(delay > 0)
{
#if defined (_ATMO_VLC_PLUGIN_)
msleep(delay * 1000);
#else
Sleep(delay);
#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));
// Convert Data to HSV values.. bla bla....
if(m_pCurrentFramePixels!=NULL)
{
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
if(m_CurrentFrameHeader.biCompression == FCC('HSVI'))
{
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);
}
}
}
}
}
/*
if the image color format wasn't recognized - the output
will be black (memset)
*/
/*
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 formulars
are done by some one else...)
*/
m_ColorPacket = CalcColorsAnalyzeHSV(this->m_pAtmoDynData->getAtmoConfig(), HSV_Img);
/* remove the source buffe */
free(m_pCurrentFramePixels);
/*
the buffer zereo so that deliver new data paket will wakeup the
thread on the next frame again
*/
m_pCurrentFramePixels = NULL;
}
}
#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 <comdef.h>
# include "AtmoWin_h.h"
#endif
#include "AtmoInput.h"
#include "AtmoThread.h"
#include "AtmoConfig.h"
#include "AtmoDynData.h"
#include "AtmoCalculations.h"
class CAtmoExternalCaptureInput :
public CAtmoInput,
public CThread
{
protected:
#if defined(_ATMO_VLC_PLUGIN_)
vlc_cond_t m_WakeupCond;
vlc_mutex_t m_WakeupLock;
#else
HANDLE m_hWakeupEvent;
#endif
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(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);
/*
this method is called from the AtmoLiveView thread - to get the
new color packet (a packet is an RGB triple for each channel)
*/
virtual tColorPacket GetColorPacket(void);
/*
this method is also called from the AtmoLiveView thread - to
resync on a frame
*/
virtual void WaitForNextFrame(DWORD timeout);
};
#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$
*/
#include "AtmoInput.h"
CAtmoInput::CAtmoInput(CAtmoDynData *pAtmoDynData)
{
this->m_pAtmoDynData = pAtmoDynData;
}
CAtmoInput::~CAtmoInput(void)
{
}
void CAtmoInput::WaitForNextFrame(DWORD timeout)
{
return;
}
/*
* 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 "AtmoDynData.h"
/*
basic definition of an AtmoLight data/image source ...
*/
class CAtmoInput {
protected:
tColorPacket m_ColorPacket;
volatile ATMO_BOOL m_FrameArrived;
CAtmoDynData *m_pAtmoDynData;
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; }
// Returns the calculated tColorPacket for further processing (e.g. filtering).
virtual tColorPacket GetColorPacket(void) { return m_ColorPacket; }
// wait for the arrival of the next frame...(to come in sync again)
virtual void WaitForNextFrame(DWORD timeout);
};
#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$
*/
#include "AtmoDefs.h"
#include "AtmoLiveView.h"
#include "AtmoOutputFilter.h"
#include "AtmoTools.h"
#if defined(_ATMO_VLC_PLUGIN_)
# include <vlc/vlc.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;
m_pAtmoInput = NULL;
}
#else
CAtmoLiveView::CAtmoLiveView(CAtmoDynData *pAtmoDynData)
{
this->m_pAtmoDynData = pAtmoDynData;
m_LiveViewSource = lvsGDI;
m_CurrentLiveViewSource = lvsGDI;
m_InputChangedEvent = CreateEvent(NULL,ATMO_FALSE,ATMO_FALSE,NULL);
m_pAtmoInput = NULL;
InitializeCriticalSection(&m_InputChangeCriticalSection);
}
#endif
CAtmoLiveView::~CAtmoLiveView(void)
{
#if !defined(_ATMO_VLC_PLUGIN_)
DeleteCriticalSection(&m_InputChangeCriticalSection);
CloseHandle(m_InputChangedEvent);
#endif
}
#if !defined(_ATMO_VLC_PLUGIN_)
STDMETHODIMP CAtmoLiveView::setLiveViewSource(enum ComLiveViewSource dwModus)
{
if(dwModus != m_LiveViewSource) {
m_LiveViewSource = dwModus;
/*
you may ask why I don't use a critical section here and directly acces the
the variable of the Thread?
Just because you would need very much / often entering / leaving the critical
section ... and in this case It could be avoid ...
assigning the value to the "mirror" variable m_LiveViewSource which is compare
in every run of the thread with its current value ... if there is a change
the thread can proceed switching the live source ... until this is done
the thread calling this method is waiting...
*/
// I don't expect that it will take longer than 500ms to switch...
if(WaitForSingleObject(m_InputChangedEvent,500) == WAIT_TIMEOUT)
return S_FALSE; // if not so the switch seems be have failed (badly)
}
return S_OK;
}
STDMETHODIMP CAtmoLiveView::getCurrentLiveViewSource(enum ComLiveViewSource *modus) {
*modus = m_LiveViewSource;
return S_OK;
}
#endif
DWORD CAtmoLiveView::Execute(void)
{
#if defined(_ATMO_VLC_PLUGIN_)
mtime_t ticks;
#else
DWORD ticks;
#endif
int i_frame_counter = 0;
CAtmoInput *newInput,*oldInput;
tColorPacket ColorPacket;
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());
#if defined(_ATMO_VLC_PLUGIN_)
/* this thread is the data preprocess which gets the real 64x48 pixel
and converts them into the RGB channel values - this is done in
another thread to keep this thread at a constant timing - to that
color output is updated 25 times a second
*/
m_pAtmoInput = new CAtmoExternalCaptureInput(m_pAtmoDynData);
#else
if(m_LiveViewSource == lvsGDI)
m_pAtmoInput = new CAtmoGdiDisplayCaptureInput(m_pAtmoDynData);
else
m_pAtmoInput = new CAtmoExternalCaptureInput(m_pAtmoDynData);
#endif
if(m_pAtmoInput->Open() == ATMO_TRUE)
{
/*
wait for the first frame to go in sync with the other thread
*/
#if defined(_ATMO_VLC_PLUGIN_)
msg_Dbg( m_pAtmoThread, "CAtmoLiveView::Execute(void)");
#endif
m_pAtmoInput->WaitForNextFrame(500);
while(this->m_bTerminated == ATMO_FALSE)
{
/* atmoInput - capture Thread Running... */
#if defined(_ATMO_VLC_PLUGIN_)
ticks = mdate();
#else
ticks = GetTickCount();
#endif
/* grab current Packet from Input! */
ColorPacket = m_pAtmoInput->GetColorPacket();
/* pass it through the outputfilters! */
ColorPacket = filter->Filtering(ColorPacket);
/* apply gamma later ;-) not implemented yet */
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);
/*
experimental do sync every 100 Frames to the image producer
thread because GetTickCount precision is really poor ;-)
*/
i_frame_counter++;
if(i_frame_counter == 100) {
m_pAtmoInput->WaitForNextFrame(50);
i_frame_counter = 0;
#if !defined(WIN32)
/* kludge for pthreads? when running GDB debugger using the same condition variable
to often results in haging wait timedout...
*/
#ifdef _ATMO_KLUDGE_
vlc_mutex_lock( &m_TerminateLock );
vlc_cond_destroy( &m_TerminateCond );
vlc_cond_init( m_pAtmoThread, &m_TerminateCond );
vlc_mutex_unlock( &m_TerminateLock );
#endif
#endif
continue;
}
#if !defined(_ATMO_VLC_PLUGIN_)
/*
Check if Input Source has changed - through an async
call from the com interface?
*/
if(m_CurrentLiveViewSource != m_LiveViewSource) {
oldInput = m_pAtmoInput;
m_pAtmoInput = NULL;
if(m_LiveViewSource == lvsGDI) {
// create new GDI Input Source...
newInput = new CAtmoGdiDisplayCaptureInput(m_pAtmoDynData);
newInput->Open(); // should not fail now... hope is the best!
} else if(m_LiveViewSource == lvsExternal) {
newInput = new CAtmoExternalCaptureInput(m_pAtmoDynData);
newInput->Open();
}
m_CurrentLiveViewSource = m_LiveViewSource;
m_pAtmoInput = newInput;
oldInput->Close();
delete oldInput;
/*
signal the call to the method "setLiveViewSource" the source
was switched...
*/
SetEvent(m_InputChangedEvent);
// do sync with input thread
m_pAtmoInput->WaitForNextFrame(100);
continue;
}
#endif
/*
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)
{
// ThreadSleep -> AtmoThread.cpp
if(this->ThreadSleep(40 - ticks)==ATMO_FALSE)
break;
}
}
/* shutdown the input processor thread */
m_pAtmoInput->Close();
}
delete m_pAtmoInput;
m_pAtmoInput = NULL;
#if !defined(_ATMO_VLC_PLUGIN_)
/*
if there is a pending call to setLiveViewSource let him surely return before
destroying the thread and this class instance...
*/
SetEvent(m_InputChangedEvent);
#endif
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 <comdef.h>
# include "AtmoWin_h.h"
# 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);
#if !defined(_ATMO_VLC_PLUGIN_)
public:
STDMETHODIMP setLiveViewSource(enum ComLiveViewSource dwModus);
STDMETHODIMP getCurrentLiveViewSource(enum ComLiveViewSource *modus);
#endif
protected:
CAtmoDynData *m_pAtmoDynData;
CAtmoInput *m_pAtmoInput;
#if !defined(_ATMO_VLC_PLUGIN_)
ComLiveViewSource m_LiveViewSource;
ComLiveViewSource m_CurrentLiveViewSource;
CRITICAL_SECTION m_InputChangeCriticalSection;
HANDLE m_InputChangedEvent;
#endif
public:
CAtmoLiveView(CAtmoDynData *pAtmoDynData);
virtual ~CAtmoLiveView(void);
CAtmoInput *getAtmoInput() { return m_pAtmoInput; }
#if !defined(_ATMO_VLC_PLUGIN_)
ComLiveViewSource getLiveViewSource() { return m_CurrentLiveViewSource; }
#endif
};
#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$
*/
#include <string.h>
#include "AtmoOutputFilter.h"
CAtmoOutputFilter::CAtmoOutputFilter(CAtmoConfig *atmoConfig)
{
this->m_pAtmoConfig = atmoConfig;
ResetFilter();
}
CAtmoOutputFilter::~CAtmoOutputFilter(void)
{
}
void CAtmoOutputFilter::ResetFilter(void)
{
// reset filter values
MeanFilter(true);
PercentFilter(true);
}
tColorPacket CAtmoOutputFilter::Filtering(tColorPacket ColorPacket)
{
filter_input = ColorPacket;
switch (m_pAtmoConfig->getLiveViewFilterMode())
{
case afmNoFilter:
filter_output = filter_input;
break;
case afmCombined:
MeanFilter(false);
break;
case afmPercent:
PercentFilter(false);
break;
default:
filter_output = filter_input;
break;
}
return filter_output;
}
void CAtmoOutputFilter::PercentFilter(ATMO_BOOL init)
{
// last values needed for the percentage filter
static tColorPacket filter_output_old;
if (init) // Initialization
{
memset(&filter_output_old, 0, sizeof(filter_output_old));
return;
}
int percentNew = this->m_pAtmoConfig->getLiveViewFilter_PercentNew();
for (int ch = 0; ch < ATMO_NUM_CHANNELS; ch++)
{
filter_output.channel[ch].r = (filter_input.channel[ch].r *
(100-percentNew) + filter_output_old.channel[ch].r * percentNew) / 100;
filter_output.channel[ch].g = (filter_input.channel[ch].g *
(100-percentNew) + filter_output_old.channel[ch].g * percentNew) / 100;
filter_output.channel[ch].b = (filter_input.channel[ch].b *
(100-percentNew) + filter_output_old.channel[ch].b * percentNew) / 100;
}
filter_output_old = filter_output;
}
void CAtmoOutputFilter::MeanFilter(ATMO_BOOL init)
{
// needed vor the running mean value filter
static tColorPacketLongInt mean_sums;
static tColorPacket mean_values;
// needed for the percentage filter
static tColorPacket filter_output_old;
static int filter_length_old;
char reinitialize = 0;
if (init) // Initialization
{
memset(&filter_output_old, 0, sizeof(filter_output_old));
memset(&mean_sums, 0, sizeof(mean_sums));
memset(&mean_values, 0, sizeof(mean_values));
return;
}
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 ch = 0; ch < ATMO_NUM_CHANNELS; ch++)
{
// calculate the mean-value filters
mean_sums.channel[ch].r +=
(long int)(filter_input.channel[ch].r - mean_values.channel[ch].r); // red
mean_values.channel[ch].r = mean_sums.channel[ch].r / ((long int)filter_length_old / 20);
mean_sums.channel[ch].g +=
(long int)(filter_input.channel[ch].g - mean_values.channel[ch].g); // green
mean_values.channel[ch].g = mean_sums.channel[ch].g / ((long int)filter_length_old / 20);
mean_sums.channel[ch].b +=
(long int)(filter_input.channel[ch].b - mean_values.channel[ch].b); // blue
mean_values.channel[ch].b = mean_sums.channel[ch].b / ((long int)filter_length_old / 20);
// 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 = (mean_values.channel[ch].r - filter_input.channel[ch].r) *
(mean_values.channel[ch].r - filter_input.channel[ch].r) +
(mean_values.channel[ch].g - filter_input.channel[ch].g) *
(mean_values.channel[ch].g - filter_input.channel[ch].g) +
(mean_values.channel[ch].b - filter_input.channel[ch].b) *
(mean_values.channel[ch].b - filter_input.channel[ch].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.channel[ch] = mean_values.channel[ch] = filter_input.channel[ch];
mean_sums.channel[ch].r = filter_input.channel[ch].r *
(filter_length_old / 20);
mean_sums.channel[ch].g = filter_input.channel[ch].g *
(filter_length_old / 20);
mean_sums.channel[ch].b = filter_input.channel[ch].b *
(filter_length_old / 20);
}
else
{
// apply an additional percent filter and return calculated values
filter_output.channel[ch].r = (mean_values.channel[ch].r *
(100-AtmoSetup_Filter_PercentNew) +
filter_output_old.channel[ch].r * AtmoSetup_Filter_PercentNew) / 100;
filter_output.channel[ch].g = (mean_values.channel[ch].g *
(100-AtmoSetup_Filter_PercentNew) +
filter_output_old.channel[ch].g * AtmoSetup_Filter_PercentNew) / 100;
filter_output.channel[ch].b = (mean_values.channel[ch].b *
(100-AtmoSetup_Filter_PercentNew) +
filter_output_old.channel[ch].b * AtmoSetup_Filter_PercentNew) / 100;
}
}
filter_output_old = 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
tColorPacket filter_output; // output of the filter
void PercentFilter(ATMO_BOOL init);
void MeanFilter(ATMO_BOOL init);
CAtmoConfig *m_pAtmoConfig;
public:
public:
CAtmoOutputFilter(CAtmoConfig *atmoConfig);
virtual ~CAtmoOutputFilter(void);
void ResetFilter(void);
tColorPacket Filtering(tColorPacket ColorPacket);
};
#endif
/*
* AtmoSerialConnection.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$
*/
#include "AtmoDefs.h"
#include "AtmoSerialConnection.h"
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#if !defined(WIN32)
#include <termios.h>
#include <unistd.h>
#endif
/*
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <vdr/tools.h>
*/
CAtmoSerialConnection::CAtmoSerialConnection(CAtmoConfig *cfg) : CAtmoConnection(cfg) {
m_hComport = INVALID_HANDLE_VALUE;
}
CAtmoSerialConnection::~CAtmoSerialConnection() {
CloseConnection();
}
ATMO_BOOL CAtmoSerialConnection::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 comport[16]; // com4294967295
sprintf(comport,"com%d",portNummer);
#endif
#if defined(WIN32)
# if defined(_ATMO_VLC_PLUGIN_)
m_hComport = CreateFile(serdevice, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
# else
m_hComport = CreateFile(comport, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
# endif
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; // fr 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;
# if defined(_ATMO_VLC_PLUGIN_)
m_hComport = open(serdevice,O_RDWR |O_NOCTTY);
# else
m_hComport = open(comport,O_RDWR | O_NOCTTY);
# endif
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 CAtmoSerialConnection::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 CAtmoSerialConnection::isOpen(void) {
return (m_hComport != INVALID_HANDLE_VALUE);
}
ATMO_BOOL CAtmoSerialConnection::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 CAtmoSerialConnection::SendData(tColorPacket 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;
for(int i=0;i<5;i++) {
if(m_ChannelAssignment[i]>=0) {
buffer[iBuffer++] = data.channel[m_ChannelAssignment[i]].r;
buffer[iBuffer++] = data.channel[m_ChannelAssignment[i]].g;
buffer[iBuffer++] = data.channel[m_ChannelAssignment[i]].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
return (iBytesWritten == 19) ? ATMO_TRUE : ATMO_FALSE;
}
ATMO_BOOL CAtmoSerialConnection::SendData(unsigned char numChannels,
int red[],
int green[],
int blue[])
{
if(m_hComport == INVALID_HANDLE_VALUE)
return ATMO_FALSE;
DWORD bufSize = 4 + numChannels*3;
unsigned char *buffer = new unsigned char[bufSize];
DWORD iBytesWritten;
buffer[0] = 0xFF; // Start Byte
buffer[1] = 0x00; // Start Kanal 0
buffer[2] = 0x00; // Start Kanal 0
buffer[3] = numChannels * 3; //
int iBuffer = 4;
for(int i=0;i<numChannels;i++) {
if(m_ChannelAssignment[i]>=0) {
buffer[iBuffer++] = red[m_ChannelAssignment[i]] & 255;
buffer[iBuffer++] = green[m_ChannelAssignment[i]] & 255;
buffer[iBuffer++] = blue[m_ChannelAssignment[i]] & 255;
} else {
buffer[iBuffer++] = 0;
buffer[iBuffer++] = 0;
buffer[iBuffer++] = 0;
}
}
#if defined(WIN32)
WriteFile(m_hComport, buffer, bufSize, &iBytesWritten, NULL);
#else
iBytesWritten = write(m_hComport, buffer, bufSize);
tcdrain(m_hComport);
#endif
delete buffer;
return (iBytesWritten == bufSize) ? ATMO_TRUE : ATMO_FALSE;
}
/*
* AtmoCom.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 _AtmoSerialConnection_h_
#define _AtmoSerialConnection_h_
#include "AtmoDefs.h"
#include "AtmoConnection.h"
#include "AtmoConfig.h"
#if defined(WIN32)
# include <windows.h>
#endif
class CAtmoSerialConnection : public CAtmoConnection {
private:
HANDLE m_hComport;
#if defined(WIN32)
DWORD m_dwLastWin32Error;
public:
DWORD getLastError() { return m_dwLastWin32Error; }
#endif
public:
CAtmoSerialConnection(CAtmoConfig *cfg);
virtual ~CAtmoSerialConnection(void);
virtual ATMO_BOOL OpenConnection();
virtual void CloseConnection();
virtual ATMO_BOOL isOpen(void);
virtual ATMO_BOOL SendData(unsigned char numChannels,
int red[],
int green[],
int blue[]);
virtual ATMO_BOOL SendData(tColorPacket 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);
};
#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$
*/
#include "AtmoThread.h"
#if defined(_ATMO_VLC_PLUGIN_)
CThread::CThread(vlc_object_t *pOwner)
{
int err;
m_pAtmoThread = (atmo_thread_t *)vlc_object_create( pOwner,
sizeof(atmo_thread_t) );
if(m_pAtmoThread)
{
m_pAtmoThread->p_thread = this;
this->m_pOwner = pOwner;
vlc_object_attach( m_pAtmoThread, m_pOwner);
vlc_mutex_init( m_pAtmoThread, &m_TerminateLock );
err = vlc_cond_init( m_pAtmoThread, &m_TerminateCond );
if(err) {
msg_Err( m_pAtmoThread, "vlc_cond_init failed %d",err);
}
}
}
#else
CThread::CThread(void)
{
m_hThread = CreateThread(NULL, 0, CThread::ThreadProc ,
this, CREATE_SUSPENDED, &m_dwThreadID);
m_hTerminateEvent = CreateEvent(NULL,ATMO_FALSE,ATMO_FALSE,NULL);
}
#endif
#if defined(_ATMO_VLC_PLUGIN_)
CThread::~CThread(void)
{
if(m_pAtmoThread)
{
vlc_mutex_destroy( &m_TerminateLock );
vlc_cond_destroy( &m_TerminateCond );
vlc_object_detach(m_pAtmoThread);
vlc_object_destroy(m_pAtmoThread);
}
}
#else
CThread::~CThread(void)
{
CloseHandle(m_hThread);
CloseHandle(m_hTerminateEvent);
}
#endif
#if defined(_ATMO_VLC_PLUGIN_)
void CThread::ThreadProc(atmo_thread_t *pAtmoThread)
{
CThread *pThread = (CThread *)pAtmoThread->p_thread;
if(pThread) {
// give feedback I'am running?
vlc_thread_ready( pThread->m_pAtmoThread );
pThread->Execute();
}
}
#else
DWORD WINAPI CThread::ThreadProc(LPVOID lpParameter)
{
CThread *aThread = (CThread *)lpParameter;
if(aThread)
return aThread->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
m_bTerminated = ATMO_TRUE;
#if defined(_ATMO_VLC_PLUGIN_)
if(m_pAtmoThread)
{
vlc_mutex_lock( &m_TerminateLock );
vlc_cond_signal( &m_TerminateCond );
vlc_mutex_unlock( &m_TerminateLock );
vlc_object_kill( m_pAtmoThread );
vlc_thread_join( m_pAtmoThread );
}
#else
SetEvent(m_hTerminateEvent);
WaitForSingleObject(m_hThread,INFINITE);
#endif
}
void CThread::Run()
{
m_bTerminated = ATMO_FALSE;
#if defined(_ATMO_VLC_PLUGIN_)
m_pAtmoThread->b_die = VLC_FALSE;
if(vlc_thread_create( m_pAtmoThread,
"Atmo-CThread-Class",
CThread::ThreadProc,
VLC_THREAD_PRIORITY_LOW,
VLC_FALSE ))
{
msg_Err( m_pOwner, "cannot launch one of the AtmoLight threads");
}
#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_)
vlc_mutex_lock( &m_TerminateLock );
int value = vlc_cond_timedwait(&m_TerminateCond,
&m_TerminateLock,
mdate() + (mtime_t)(millisekunden * 1000));
vlc_mutex_unlock( &m_TerminateLock );
return (value != 0);
#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/vlc.h>
# include <vlc_threads_funcs.h>
# include <vlc_threads.h>
typedef struct
{
VLC_COMMON_MEMBERS
void *p_thread; /* cast to CThread * */
} atmo_thread_t;
#else
# include <windows.h>
#endif
class CThread
{
protected:
#if defined(_ATMO_VLC_PLUGIN_)
atmo_thread_t *m_pAtmoThread;
vlc_mutex_t m_TerminateLock;
vlc_cond_t m_TerminateCond;
vlc_object_t *m_pOwner;
#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(atmo_thread_t *pAtmoThread);
#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$
*/
#include "AtmoTools.h"
#include "AtmoLiveView.h"
#include "AtmoSerialConnection.h"
#if !defined(_ATMO_VLC_PLUGIN_)
# include "AtmoColorChanger.h"
# include "AtmoLeftRightColorChanger.h"
# include "AtmoDummyConnection.h"
# include "AtmoDmxSerialConnection.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)) {
int r[ATMO_NUM_CHANNELS],g[ATMO_NUM_CHANNELS],b[ATMO_NUM_CHANNELS],i;
// 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...
if(atmoConnection->isOpen() == ATMO_TRUE) {
if(atmoConfig->isSetShutdownColor() == 1) {
for(i=0;i<ATMO_NUM_CHANNELS;i++) {
r[i] = atmoConfig->getShutdownColor_Red();
g[i] = atmoConfig->getShutdownColor_Green();
b[i] = atmoConfig->getShutdownColor_Blue();
}
atmoConnection->SendData(ATMO_NUM_CHANNELS,r,g,b);
}
}
}
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();
// stop and delete/cleanup current Effect Thread...
pDynData->setEffectThread(NULL);
if(currentEffect!=NULL) {
currentEffect->Terminate();
delete currentEffect;
currentEffect = NULL;
}
if((atmoConnection!=NULL) && (atmoConnection->isOpen()==ATMO_TRUE)) {
// neuen EffectThread nur mit aktiver Connection starten...
switch(newEffectMode) {
case emDisabled:
break;
case emStaticColor:
// get values from config - and put them to all channels?
int r[ATMO_NUM_CHANNELS],g[ATMO_NUM_CHANNELS],b[ATMO_NUM_CHANNELS];
for(int i=0;i<ATMO_NUM_CHANNELS;i++) {
r[i] = (atmoConfig->getStaticColor_Red() * atmoConfig->getWhiteAdjustment_Red())/255;
g[i] = (atmoConfig->getStaticColor_Green() * atmoConfig->getWhiteAdjustment_Green())/255;
b[i] = (atmoConfig->getStaticColor_Blue() * atmoConfig->getWhiteAdjustment_Blue())/255;
}
atmoConnection->SendData(ATMO_NUM_CHANNELS,r,g,b);
break;
case emLivePicture:
currentEffect = new CAtmoLiveView(pDynData);
break;
#if !defined(_ATMO_VLC_PLUGIN_)
case emColorChange:
currentEffect = new CAtmoColorChanger(atmoConnection, atmoConfig);
break;
#endif
#if !defined(_ATMO_VLC_PLUGIN_)
case emLrColorChange:
currentEffect = new CAtmoLeftRightColorChanger(atmoConnection, atmoConfig);
break;
#endif
}
}
atmoConfig->setEffectMode(newEffectMode);
pDynData->setEffectThread(currentEffect);
if(currentEffect!=NULL)
currentEffect->Run();
pDynData->UnLockCriticalSection();
return oldEffectMode;
}
ATMO_BOOL CAtmoTools::RecreateConnection(CAtmoDynData *pDynData)
{
pDynData->LockCriticalSection();
CAtmoConnection *current = pDynData->getAtmoConnection();
AtmoConnectionType act = pDynData->getAtmoConfig()->getConnectionType();
pDynData->setAtmoConnection(NULL);
if(current != NULL) {
current->CloseConnection();
delete current;
}
switch(act) {
case actSerialPort: {
CAtmoSerialConnection *tempConnection = new CAtmoSerialConnection(pDynData->getAtmoConfig());
if(tempConnection->OpenConnection() == ATMO_FALSE) {
#if !defined(_ATMO_VLC_PLUGIN_)
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
delete tempConnection;
pDynData->UnLockCriticalSection();
return ATMO_FALSE;
}
pDynData->setAtmoConnection(tempConnection);
CAtmoTools::SetChannelAssignment(pDynData,
pDynData->getAtmoConfig()->getCurrentChannelAssignment());
pDynData->UnLockCriticalSection();
return ATMO_TRUE;
}
#if !defined(_ATMO_VLC_PLUGIN_)
case actDummy: {
CAtmoDummyConnection *tempConnection = new CAtmoDummyConnection(pDynData->getHinstance(),
pDynData->getAtmoConfig());
if(tempConnection->OpenConnection() == ATMO_FALSE) {
delete tempConnection;
pDynData->UnLockCriticalSection();
return ATMO_FALSE;
}
pDynData->setAtmoConnection(tempConnection);
CAtmoTools::SetChannelAssignment(pDynData, pDynData->getAtmoConfig()->getCurrentChannelAssignment());
pDynData->UnLockCriticalSection();
return ATMO_TRUE;
}
case actDMX: {
// create here your DMX connections... instead of the dummy....
CAtmoDmxSerialConnection *tempConnection = new CAtmoDmxSerialConnection(pDynData->getAtmoConfig());
if(tempConnection->OpenConnection() == ATMO_FALSE) {
delete tempConnection;
pDynData->UnLockCriticalSection();
return ATMO_FALSE;
}
pDynData->setAtmoConnection(tempConnection);
CAtmoTools::SetChannelAssignment(pDynData, pDynData->getAtmoConfig()->getCurrentChannelAssignment());
pDynData->UnLockCriticalSection();
return ATMO_TRUE;
}
#endif
default: {
pDynData->UnLockCriticalSection();
return ATMO_FALSE;
}
}
}
tColorPacket CAtmoTools::WhiteCalibration(CAtmoConfig *pAtmoConfig, tColorPacket 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 < ATMO_NUM_CHANNELS; i++) {
ColorPacket.channel[i].r = (unsigned char)(((int)w_adj_red * (int)ColorPacket.channel[i].r) / 255);
ColorPacket.channel[i].g = (unsigned char)(((int)w_adj_green * (int)ColorPacket.channel[i].g) / 255);
ColorPacket.channel[i].b = (unsigned char)(((int)w_adj_blue * (int)ColorPacket.channel[i].b) / 255);
}
return ColorPacket;
}
tColorPacket CAtmoTools::ApplyGamma(CAtmoConfig *pAtmoConfig, tColorPacket ColorPacket)
{
return ColorPacket;
}
int CAtmoTools::SetChannelAssignment(CAtmoDynData *pDynData, int index)
{
CAtmoConfig *pAtmoConfig = pDynData->getAtmoConfig();
CAtmoConnection *pAtmoConnection = pDynData->getAtmoConnection();
int oldIndex = pAtmoConfig->getCurrentChannelAssignment();
tChannelAssignment *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='MB';
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);
}
#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 void ShowShutdownColor(CAtmoDynData *pDynData);
static ATMO_BOOL RecreateConnection(CAtmoDynData *pDynData);
static tColorPacket WhiteCalibration(CAtmoConfig *pAtmoConfig, tColorPacket ColorPacket);
static tColorPacket ApplyGamma(CAtmoConfig *pAtmoConfig, tColorPacket ColorPacket);
static int SetChannelAssignment(CAtmoDynData *pDynData, int index);
#if !defined(_ATMO_VLC_PLUGIN_)
static void SaveBitmap(HDC hdc,HBITMAP hBmp,char *fileName);
#endif
};
#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 index = 0;
unsigned char col_norm;
for(int row=0; row < CAP_HEIGHT; 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 index = 0;
unsigned char col_norm;
for(int row=0; row < CAP_HEIGHT; 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 index = 0;
unsigned char row_norm;
for(int row=0; row < CAP_HEIGHT; row++) {
row_norm = (255 * (CAP_HEIGHT-row-1)) / (CAP_HEIGHT-1); // should be a value between 0 .. 255?
for(int col=0; col < CAP_WIDTH; col++) {
m_BasicWeight[index++] = row_norm;
}
}
}
// max weight from bottom
void CAtmoZoneDefinition::FillGradientFromBottom()
{
int index = 0;
unsigned char row_norm;
for(int row=0; row < CAP_HEIGHT; row++) {
row_norm = (255 * row) / (CAP_HEIGHT-1); // should be a value between 0 .. 255?
for(int col=0; col < CAP_WIDTH; col++) {
m_BasicWeight[index++] = row_norm;
}
}
}
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!
BITMAPINFO bmpInfo;
BITMAPFILEHEADER bmpFileHeader;
/*
#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 != 'MB')
{
fclose(bmp);
return ATMO_LOAD_GRADIENT_FAILED_HEADER;
}
if(fread(&bmpInfo, sizeof(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)
{
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_HEIGHT; 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();
void FillGradientFromRight();
void FillGradientFromTop();
void FillGradientFromBottom();
int LoadGradientFromBitmap(char *pszBitmap);
void UpdateWeighting(int *destWeight,
int WidescreenMode,
int newEdgeWeightning);
void setZoneNumber(int num);
int getZoneNumber();
};
#endif
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 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.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, 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 or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
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 give any other recipients of the Program a copy of this License
along with the Program.
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 Program or any portion
of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
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 Program, 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 Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) 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; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, 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 executable. However, as a
special exception, the source code 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.
If distribution of executable or 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 counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program 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.
5. 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 Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program 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 to
this License.
7. 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 Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program 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 Program.
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.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program 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.
9. The Free Software Foundation may publish revised and/or new versions
of the 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 Program
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 Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, 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
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), 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 Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. 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 program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
SOURCES_atmo = atmo.cpp AtmoDefs.h AtmoCalculations.cpp AtmoCalculations.h AtmoConfig.cpp AtmoConfig.h AtmoConnection.cpp AtmoConnection.h AtmoDynData.cpp AtmoDynData.h AtmoExternalCaptureInput.cpp AtmoExternalCaptureInput.h AtmoInput.cpp AtmoInput.h AtmoLiveView.cpp AtmoLiveView.h AtmoOutputFilter.cpp AtmoOutputFilter.h AtmoSerialConnection.cpp AtmoSerialConnection.h AtmoThread.cpp AtmoThread.h AtmoTools.cpp AtmoTools.h AtmoZoneDefinition.cpp AtmoZoneDefinition.h
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
See the file COPYING.txt for license information.
Original Readme - of the Linux Version - from where some code was used
to do the color calculations ...
######################################################################
This is the Atmolight-plugin for the Video Disk Recorder (VDR).
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.
Requirements: a full-featured DVB-card or
softdevice-plugin (2006-12-03: CVS-version necessary)
Description: Plugin for the Atmolight.
----------------------------------------------------------------------
for detailed informations 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
----------------------------------------------------------------------
NOTE:
-------
If you want to change the Atmolight color from outside,
you can do this with a script using SVDRP-commands
(see scripts/disco.sh).
/*****************************************************************************
* atmo.cpp : "Atmo Light" video filter
*****************************************************************************
* Copyright (C) 2000-2006 the VideoLAN team
* $Id$
*
* Authors: André Weber (WeberAndre@gmx.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
#include <string.h>
#include <math.h> /* sin(), cos() */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
// #define __ATMO_DEBUG__
// [:Zs]+$
#include <vlc/vlc.h>
#include <vlc_vout.h>
#include <vlc_playlist.h>
#include "vlc_filter.h"
#include "AtmoDefs.h"
#include "AtmoDynData.h"
#include "AtmoLiveView.h"
#include "AtmoTools.h"
#include "AtmoExternalCaptureInput.h"
#include "AtmoConfig.h"
#include "AtmoConnection.h"
#include "AtmoSerialConnection.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
/* directly to vlc related functions required that the module is accepted */
static int CreateFilter ( vlc_object_t * );
static void DestroyFilter ( vlc_object_t * );
static picture_t * Filter( filter_t *, picture_t *);
/* callback for global variable state pause / continue / stop events */
static void AddStateVariableCallback( filter_t *);
static void DelStateVariableCallback( filter_t *);
static int StateCallback(vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void *);
/* callback for variable crop-update */
static void AddCropVariableCallback( filter_t *);
static void DelCropVariableCallback( filter_t *);
static int CropCallback(vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void *);
/* callback for atmo settings variables whose change
should be immediately realized and applied to output
*/
static void DelAtmoSettingsVariablesCallbacks(filter_t *);
static void AddAtmoSettingsVariablesCallbacks(filter_t *);
static int AtmoSettingsCallback(vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void *);
#if defined(__ATMO_DEBUG__)
static void atmo_parse_crop(char *psz_cropconfig,
video_format_t fmt_in,
video_format_t fmt_render,
int &i_visible_width,
int &i_visible_height,
int &i_x_offset,
int &i_y_offset );
#endif
/* function to shutdown the fade thread which is started on pause*/
static void CheckAndStopFadeThread(filter_t *);
/* extracts a small RGB (BGR) Image from an YUV image */
static void ExtractMiniImage_YUV(filter_sys_t *, picture_t *, uint8_t *);
#if defined(__ATMO_DEBUG__)
void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename);
#endif
/*****************************************************************************
* External Prototypes for the AtmoCtrlLib.DLL
*****************************************************************************/
/*
* if effectmode = emLivePicture then the source could be GDI (Screencapture)
* or External - this means another application delivers Pixeldata to AtmoWin
* Clientsoftware through AtmoCtrlLib.DLL and the COM Api
*/
#define lvsGDI 0
#define lvsExternal 1
/*
strings for settings menus and hints
*/
#define MODULE_DESCRIPTION N_ ( \
"This module allows to control an so called AtmoLight device which "\
"is connected to your computer.\n"\
"AtmoLight is the homebrew version of that what Philips calls AmbiLight.\n"\
"If you need further informations feel free to visit us at\n\n"\
"http://www.vdr-wiki.de/wiki/index.php/Atmo-plugin\n"\
"http://www.vdr-wiki.de/wiki/index.php/AtmoWin\n\n"\
"there you will find detailed descriptions how to build it for your self and "\
"where you can get the required parts and so on.\n There you can also see "\
"pictures and some movies showing such a device in live action...")
#if defined( __ATMO_DEBUG__ )
# define SAVEFRAMES_TEXT N_("Save Debug Frames")
# define SAVEFRAMES_LONGTEXT N_("Writes every 128th miniframe to a folder.")
# define FRAMEPATH_TEXT N_("Debug Frame Folder")
# define FRAMEPATH_LONGTEXT N_("defines the path where the debugframes " \
"should be saved")
#endif
#define WIDTH_TEXT N_("Extracted Image Width")
#define WIDTH_LONGTEXT N_("defines the width of the mini image for " \
"further processing (64 is default)")
#define HEIGHT_TEXT N_("Extracted Image Height")
#define HEIGHT_LONGTEXT N_("defines the height of the mini image for " \
"further processing (48 is default)")
#define PCOLOR_TEXT N_("use Pause Color")
#define PCOLOR_LONGTEXT N_("use the color defined below if the user " \
"paused the video.(have light to get another beer?)")
#define PCOLOR_RED_TEXT N_("Pause-Red")
#define PCOLOR_RED_LONGTEXT N_("the red component of pause color")
#define PCOLOR_GREEN_TEXT N_("Pause-Green")
#define PCOLOR_GREEN_LONGTEXT N_("the green component of pause color")
#define PCOLOR_BLUE_TEXT N_("Pause-Blue")
#define PCOLOR_BLUE_LONGTEXT N_("the blue component of pause color")
#define FADESTEPS_TEXT N_("Pause-Fadesteps")
#define FADESTEPS_LONGTEXT N_("Number of steps to change current color " \
"to pause color (each step takes 40ms)")
#define ECOLOR_RED_TEXT N_("End-Red")
#define ECOLOR_RED_LONGTEXT N_("the red component of the shutdown color")
#define ECOLOR_GREEN_TEXT N_("End-Green")
#define ECOLOR_GREEN_LONGTEXT N_("the green component of the shutdown color")
#define ECOLOR_BLUE_TEXT N_("End-Blue")
#define ECOLOR_BLUE_LONGTEXT N_("the blue component of the shutdown color")
#define EFADESTEPS_TEXT N_("End-Fadesteps")
#define EFADESTEPS_LONGTEXT N_("Number of steps to change current color to " \
"end color for dimming up the light in cinema " \
"style... (each step takes 40ms)")
#define USEWHITEADJ_TEXT N_("Use Software White adjust")
#define USEWHITEADJ_LONGTEXT N_("Should the buildin driver do a white " \
"adjust or you LED stripes? recommend.")
#define WHITE_RED_TEXT N_("White Red")
#define WHITE_RED_LONGTEXT N_("Red value of a pure white on your "\
"LED stripes.")
#define WHITE_GREEN_TEXT N_("White Green")
#define WHITE_GREEN_LONGTEXT N_("Green value of a pure white on your "\
"LED stripes.")
#define WHITE_BLUE_TEXT N_("White Blue")
#define WHITE_BLUE_LONGTEXT N_("Blue value of a pure white on your "\
"LED stripes.")
#define SERIALDEV_TEXT N_("Serial Port/Device")
#define SERIALDEV_LONGTEXT N_("Name of the serial port where the AtmoLight "\
"controller is attached to\n on Windows usually "\
"something like COM1 or COM2 on Linux /dev/ttyS01 f.e.")
#define EDGE_TEXT N_("Edge Weightning")
#define EDGE_LONGTEXT N_("increasing this value will result in color "\
"more depending on the border of the frame")
#define BRIGHTNESS_TEXT N_("Brightness")
#define BRIGHTNESS_LONGTEXT N_("overall Brightness of you LED stripes")
#define DARKNESS_TEXT N_("Darkness Limit")
#define DARKNESS_LONGTEXT N_("pixels with a saturation lower than this will "\
"be ignored should be greater than one for "\
"letterboxed videos")
#define HUEWINSIZE_TEXT N_("Hue windowing")
#define HUEWINSIZE_LONGTEXT N_("used for statistics")
#define SATWINSIZE_TEXT N_("Sat windowing")
#define SATWINSIZE_LONGTEXT N_("used for statistics")
#define MEANLENGTH_TEXT N_("Filter length [ms]")
#define MEANLENGTH_LONGTEXT N_("Time it takes until a color is complete "\
"changed, removes flickering")
#define MEANTHRESHOLD_TEXT N_("Filter threshold")
#define MEANTHRESHOLD_LONGTEXT N_("How much a color must changed, for an "\
"imediate color change")
#define MEANPERCENTNEW_TEXT N_("Filter Smoothness %")
#define MEANPERCENTNEW_LONGTEXT N_("Filter Smoothness")
#define FILTERMODE_TEXT N_("Filtermode")
#define FILTERMODE_LONGTEXT N_("kind of filtering which should be use to "\
"calcuate the color output")
static int pi_filtermode_values[] = {
(int)afmNoFilter,
(int)afmCombined,
(int)afmPercent
};
static const char *ppsz_filtermode_descriptions[] = {
N_("No Filtering"),
N_("Combined"),
N_("Percent")
};
#define FRAMEDELAY_TEXT N_("Framedelay")
#define FRAMEDELAY_LONGTEXT N_("helps to get video out and light effects "\
"insync values around 20ms should do the trick")
#define CHANNEL_0_ASSIGN_TEXT N_("Channel summary")
#define CHANNEL_1_ASSIGN_TEXT N_("Channel left")
#define CHANNEL_2_ASSIGN_TEXT N_("Channel right")
#define CHANNEL_3_ASSIGN_TEXT N_("Channel top")
#define CHANNEL_4_ASSIGN_TEXT N_("Channel bottom")
#define CHANNELASSIGN_LONGTEXT N_("maps the hardware channel X to logical "\
"channel Y to fix wrong wiring:-)")
static int pi_channel_assignment_values[] = {
-1,
0,
1,
2,
3,
4
};
static const char *ppsz_channel_assignment_descriptions[] = {
N_("disabled"),
N_("summary"),
N_("left"),
N_("right"),
N_("top"),
N_("bottom")
};
#define ZONE_0_GRADIENT_TEXT N_("summary gradient")
#define ZONE_1_GRADIENT_TEXT N_("left gradient")
#define ZONE_2_GRADIENT_TEXT N_("right gradient")
#define ZONE_3_GRADIENT_TEXT N_("top gradient")
#define ZONE_4_GRADIENT_TEXT N_("bottom gradient")
#define ZONE_X_GRADIENT_LONG_TEXT N_("defines a small bitmap with 64x48 "\
"pixels, containing a grayscale gradient")
#if defined( WIN32 )
# define ATMOWINEXE_TEXT N_("Filename of AtmoWinA.exe")
# define ATMOWINEXE_LONGTEXT N_("if you wan't that the AtmoLight control "\
"software is launched by\nVLC enter the "\
"complete Filename of AtmoWinA.exe here")
# define USEBUILDIN_TEXT N_("Use buildin AtmoLight")
# define USEBUILDIN_LONGTEXT N_("VideoLan will directly use your AtmoLight "\
"hardware without running the external "\
"AtmoWinA.exe Userspace driver.")
#endif
#define CFG_PREFIX "atmo-"
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
set_description( _("AtmoLight Filter") );
set_help( MODULE_DESCRIPTION );
set_shortname( _( "AtmoLight" ));
set_capability( "video filter2", 0 );
set_category( CAT_VIDEO );
set_subcategory( SUBCAT_VIDEO_VFILTER );
#if defined(WIN32)
set_section( N_("Choose between the buildin AtmoLight "\
"driver or the external" ), 0 );
/*
only on win32 exists the option to use the buildin driver or
the more flexible external driver application
*/
add_bool(CFG_PREFIX "usebuildin", VLC_TRUE, NULL,
USEBUILDIN_TEXT, USEBUILDIN_LONGTEXT, VLC_FALSE);
add_string(CFG_PREFIX "serialdev", "COM1", NULL,
SERIALDEV_TEXT, SERIALDEV_LONGTEXT, VLC_FALSE );
/*
on win32 the executeable external driver application
for automatic start if needed
*/
add_file(CFG_PREFIX "atmowinexe", NULL, NULL,
ATMOWINEXE_TEXT, ATMOWINEXE_LONGTEXT, VLC_FALSE );
#else
set_section( N_("Enter connection of your AtmoLight hardware" ), 0 );
add_string(CFG_PREFIX "serialdev", "/dev/ttyS01", NULL,
SERIALDEV_TEXT, SERIALDEV_LONGTEXT, VLC_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", VLC_FALSE, NULL,
PCOLOR_TEXT, PCOLOR_LONGTEXT, VLC_FALSE);
add_integer_with_range(CFG_PREFIX "pcolor-red", 0, 0, 255, NULL,
PCOLOR_RED_TEXT, PCOLOR_RED_LONGTEXT, VLC_FALSE);
add_integer_with_range(CFG_PREFIX "pcolor-green", 0, 0, 255, NULL,
PCOLOR_GREEN_TEXT, PCOLOR_GREEN_LONGTEXT, VLC_FALSE);
add_integer_with_range(CFG_PREFIX "pcolor-blue", 192, 0, 255, NULL,
PCOLOR_BLUE_TEXT, PCOLOR_BLUE_LONGTEXT, VLC_FALSE);
add_integer_with_range(CFG_PREFIX "fadesteps", 50, 1, 250, NULL,
FADESTEPS_TEXT, FADESTEPS_LONGTEXT, VLC_FALSE);
/*
color which is showed if you finished watching your movie ...
used for both buildin / external
*/
set_section( N_("Illuminate the room with this color on shutdown" ), 0 );
add_integer_with_range(CFG_PREFIX "ecolor-red", 192, 0, 255, NULL,
ECOLOR_RED_TEXT, ECOLOR_RED_LONGTEXT, VLC_FALSE);
add_integer_with_range(CFG_PREFIX "ecolor-green", 192, 0, 255, NULL,
ECOLOR_GREEN_TEXT, ECOLOR_GREEN_LONGTEXT, VLC_FALSE);
add_integer_with_range(CFG_PREFIX "ecolor-blue", 192, 0, 255, NULL,
ECOLOR_BLUE_TEXT, ECOLOR_BLUE_LONGTEXT, VLC_FALSE);
add_integer_with_range(CFG_PREFIX "efadesteps", 50, 1, 250, NULL,
EFADESTEPS_TEXT, EFADESTEPS_LONGTEXT, VLC_FALSE);
/*
settings only for the buildin driver (if external driver app is used
these parameters are ignored.)
definition of parameters for the buildin filter ...
*/
set_section( N_("Settings only for buildin Live Video Processor" ), 0 );
add_integer_with_range(CFG_PREFIX "EdgeWeightning", 8, 1, 30, NULL,
EDGE_TEXT, EDGE_LONGTEXT, VLC_FALSE);
add_integer_with_range(CFG_PREFIX "Brightness", 100, 50, 300, NULL,
BRIGHTNESS_TEXT, BRIGHTNESS_LONGTEXT, VLC_FALSE);
add_integer_with_range(CFG_PREFIX "DarknessLimit", 5, 0, 10, NULL,
DARKNESS_TEXT, DARKNESS_LONGTEXT, VLC_FALSE);
add_integer_with_range(CFG_PREFIX "HueWinSize", 3, 0, 5, NULL,
HUEWINSIZE_TEXT, HUEWINSIZE_LONGTEXT, VLC_FALSE);
add_integer_with_range(CFG_PREFIX "SatWinSize", 3, 0, 5, NULL,
SATWINSIZE_TEXT, SATWINSIZE_LONGTEXT, VLC_FALSE);
add_integer(CFG_PREFIX "filtermode", (int)afmCombined, NULL,
FILTERMODE_TEXT, FILTERMODE_LONGTEXT, VLC_FALSE );
change_integer_list(pi_filtermode_values, ppsz_filtermode_descriptions, 0 );
add_integer_with_range(CFG_PREFIX "MeanLength", 300, 300, 5000, NULL,
MEANLENGTH_TEXT, MEANLENGTH_LONGTEXT, VLC_FALSE);
add_integer_with_range(CFG_PREFIX "MeanThreshold", 40, 1, 100, NULL,
MEANTHRESHOLD_TEXT, MEANTHRESHOLD_LONGTEXT, VLC_FALSE);
add_integer_with_range(CFG_PREFIX "PercentNew", 50, 1, 100, NULL,
MEANPERCENTNEW_TEXT, MEANPERCENTNEW_LONGTEXT, VLC_FALSE);
add_integer_with_range(CFG_PREFIX "FrameDelay", 18, 0, 35, NULL,
FRAMEDELAY_TEXT, FRAMEDELAY_LONGTEXT, VLC_FALSE);
/*
output channel reordering
*/
set_section( N_("Change channel assignment (fixes wrong wiring)" ), 0 );
add_integer( CFG_PREFIX "channel_0", 0, NULL,
CHANNEL_0_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, VLC_FALSE );
change_integer_list( pi_channel_assignment_values,
ppsz_channel_assignment_descriptions, 0 );
add_integer( CFG_PREFIX "channel_1", 1, NULL,
CHANNEL_1_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, VLC_FALSE );
change_integer_list( pi_channel_assignment_values,
ppsz_channel_assignment_descriptions, 0 );
add_integer( CFG_PREFIX "channel_2", 2, NULL,
CHANNEL_2_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, VLC_FALSE );
change_integer_list( pi_channel_assignment_values,
ppsz_channel_assignment_descriptions, 0 );
add_integer( CFG_PREFIX "channel_3", 3, NULL,
CHANNEL_3_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, VLC_FALSE );
change_integer_list( pi_channel_assignment_values,
ppsz_channel_assignment_descriptions, 0 );
add_integer( CFG_PREFIX "channel_4", 4, NULL,
CHANNEL_4_ASSIGN_TEXT, CHANNELASSIGN_LONGTEXT, VLC_FALSE );
change_integer_list( pi_channel_assignment_values,
ppsz_channel_assignment_descriptions, 0 );
/*
LED color white calibration
*/
set_section( N_("Adjust the white light to your LED stripes" ), 0 );
add_bool(CFG_PREFIX "whiteadj", VLC_TRUE, NULL,
USEWHITEADJ_TEXT, USEWHITEADJ_LONGTEXT, VLC_FALSE);
add_integer_with_range(CFG_PREFIX "white-red", 255, 0, 255, NULL,
WHITE_RED_TEXT, WHITE_RED_LONGTEXT, VLC_FALSE);
add_integer_with_range(CFG_PREFIX "white-green", 255, 0, 255, NULL,
WHITE_GREEN_TEXT, WHITE_GREEN_LONGTEXT, VLC_FALSE);
add_integer_with_range(CFG_PREFIX "white-blue", 255, 0, 255, NULL,
WHITE_BLUE_TEXT, WHITE_BLUE_LONGTEXT, VLC_FALSE);
/* end of definition of parameter for the buildin filter ... part 1 */
/*
only for buildin (external has own definition) per default the calucation
used linear gradients for assigning a priority to the pixel - depending
how near they are to the border ...for changing this you can create 64x48
Pixel BMP files - which contain your own grayscale... (you can produce funny
effects with this...) the images MUST not compressed, should have 24-bit per
pixel, or a simple 256 color grayscale palette
*/
set_section( N_("Change gradients" ), 0 );
add_file(CFG_PREFIX "gradient_zone_0", NULL, NULL,
ZONE_0_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, VLC_TRUE );
add_file(CFG_PREFIX "gradient_zone_1", NULL, NULL,
ZONE_1_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, VLC_TRUE );
add_file(CFG_PREFIX "gradient_zone_2", NULL, NULL,
ZONE_2_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, VLC_TRUE );
add_file(CFG_PREFIX "gradient_zone_3", NULL, NULL,
ZONE_3_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, VLC_TRUE );
add_file(CFG_PREFIX "gradient_zone_4", NULL, NULL,
ZONE_4_GRADIENT_TEXT, ZONE_X_GRADIENT_LONG_TEXT, VLC_TRUE );
#if defined(__ATMO_DEBUG__)
add_bool(CFG_PREFIX "saveframes", VLC_FALSE, NULL,
SAVEFRAMES_TEXT, SAVEFRAMES_LONGTEXT, VLC_FALSE);
add_string(CFG_PREFIX "framepath", "", NULL,
FRAMEPATH_TEXT, FRAMEPATH_LONGTEXT, VLC_FALSE );
#endif
/*
may be later if computers gets more power ;-) than now we increase
the samplesize from which we do the stats for output color calculation
*/
add_integer_with_range(CFG_PREFIX "width", 64, 64, 512, NULL,
WIDTH_TEXT, WIDTH_LONGTEXT, VLC_TRUE);
add_integer_with_range(CFG_PREFIX "height", 48, 48, 384, NULL,
HEIGHT_TEXT, HEIGHT_LONGTEXT, VLC_TRUE);
add_shortcut( "atmo" );
set_callbacks( CreateFilter, DestroyFilter );
vlc_module_end();
static const char *ppsz_filter_options[] = {
#if defined(WIN32)
"usebuildin",
#endif
"serialdev",
"EdgeWeightning",
"Brightness",
"DarknessLimit",
"HueWinSize",
"SatWinSize",
"filtermode",
"MeanLength",
"MeanThreshold",
"PercentNew",
"FrameDelay",
"channel_0",
"channel_1",
"channel_2",
"channel_3",
"channel_4",
"whiteadj",
"white-red",
"white-green",
"white-blue",
"usepausecolor",
"pcolor-red",
"pcolor-green",
"pcolor-blue",
"fadesteps",
"ecolor-red",
"ecolor-green",
"ecolor-blue",
"efadesteps",
#if defined(WIN32 )
"usebuildin",
"atmowinexe",
#endif
#if defined(__ATMO_DEBUG__)
"saveframes" ,
"framepath",
#endif
"width",
"height",
"gradient_zone_0",
"gradient_zone_1",
"gradient_zone_2",
"gradient_zone_3",
"gradient_zone_4",
NULL
};
/*****************************************************************************
* fadethread_t: Color Fading Thread
*****************************************************************************
* changes slowly the color of the output if videostream gets paused...
*****************************************************************************
*/
typedef struct
{
VLC_COMMON_MEMBERS
filter_t *p_filter;
/* tell the thread which color should be the target of fading */
uint8_t ui_red;
uint8_t ui_green;
uint8_t ui_blue;
/* how many steps should happen until this */
int i_steps;
} fadethread_t;
static void FadeToColorThread(fadethread_t *p_fadethread);
/*****************************************************************************
* filter_sys_t: AtmoLight filter method descriptor
*****************************************************************************
* It describes the AtmoLight specific properties of an video filter.
*****************************************************************************/
struct filter_sys_t
{
/*
special for the access of the p_fadethread member all other members
need no special protection so far!
*/
vlc_mutex_t filter_lock;
vlc_bool_t b_enabled;
int32_t i_AtmoOldEffect;
vlc_bool_t b_pause_live;
int32_t i_atmo_width;
int32_t i_atmo_height;
#if defined(__ATMO_DEBUG__)
vlc_bool_t b_saveframes;
int i_framecounter;
char sz_framepath[MAX_PATH];
#endif
/* light color durring movie pause ... */
vlc_bool_t b_usepausecolor;
uint8_t ui_pausecolor_red;
uint8_t ui_pausecolor_green;
uint8_t ui_pausecolor_blue;
int i_fadesteps;
/* light color on movie finish ... */
uint8_t ui_endcolor_red;
uint8_t ui_endcolor_green;
uint8_t ui_endcolor_blue;
int i_endfadesteps;
fadethread_t *p_fadethread;
/* Variables for buildin driver only... */
/* is only present and initialized if the internal driver is used*/
CAtmoConfig *p_atmo_config;
/* storage for temporal settings "volatile" */
CAtmoDynData *p_atmo_dyndata;
/* initialized for buildin driver with AtmoCreateTransferBuffers */
BITMAPINFOHEADER mini_image_format;
/* is only use buildin driver! */
uint8_t *p_atmo_transfer_buffer;
/* end buildin driver */
/*
contains the real output size of the video calculated on
change event of the variable "crop" from vout
*/
int32_t i_crop_x_offset;
int32_t i_crop_y_offset;
int32_t i_crop_width;
int32_t i_crop_height;
void (*pf_extract_mini_image) (filter_sys_t *p_sys,
picture_t *p_inpic,
uint8_t *p_transfer_dest);
#if defined( WIN32 )
/* External Library as wrapper arround COM Stuff */
HINSTANCE h_AtmoCtrl;
int32_t (*pf_ctrl_atmo_initialize) (void);
void (*pf_ctrl_atmo_finalize) (int32_t what);
int32_t (*pf_ctrl_atmo_switch_effect) (int32_t);
int32_t (*pf_ctrl_atmo_set_live_source) (int32_t);
void (*pf_ctrl_atmo_create_transfer_buffers) (int32_t, int32_t,
int32_t , int32_t);
uint8_t* (*pf_ctrl_atmo_lock_transfer_buffer) (void);
void (*pf_ctrl_atmo_send_pixel_data) (void);
#endif
};
/*
initialize previously configured Atmo Light environment
- if internal is enabled try to access the device on the serial port
- if not internal is enabled and we are on win32 try to initialize
the previously loaded DLL ...
Return Values may be: -1 (failed for some reason - filter will be disabled)
1 Ok. lets rock
*/
static int32_t AtmoInitialize(filter_t *p_filter, vlc_bool_t b_for_thread)
{
filter_sys_t *p_sys = p_filter->p_sys;
if(p_sys->p_atmo_config)
{
if(b_for_thread == VLC_FALSE)
{
/* open com port */
/* setup Output Threads ... */
msg_Dbg( p_filter, "open serial connection %s",
p_sys->p_atmo_config->getSerialDevice());
if(CAtmoTools::RecreateConnection(p_sys->p_atmo_dyndata) == ATMO_TRUE)
{
msg_Dbg( p_filter, "start live view thread ...");
CAtmoTools::SwitchEffect(p_sys->p_atmo_dyndata, emLivePicture);
msg_Dbg( p_filter, "live view thread launched...");
return 1;
} else {
msg_Err( p_filter,"failed to open serial device? some other software/driver may use it?");
}
}
#if defined(WIN32)
} else if(p_sys->pf_ctrl_atmo_initialize)
{
/* on win32 with active ctrl dll */
return p_sys->pf_ctrl_atmo_initialize();
#endif
}
return -1;
}
/*
prepare the shutdown of the effect threads,
for build in filter - close the serialport after finishing the threads...
cleanup possible loaded DLL...
*/
static void AtmoFinalize(filter_t *p_filter, int32_t what)
{
filter_sys_t *p_sys = p_filter->p_sys;
if(p_sys->p_atmo_config)
{
if(what == 1)
{
CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
if(p_atmo_dyndata)
{
p_atmo_dyndata->LockCriticalSection();
CThread *p_effect_thread = p_atmo_dyndata->getEffectThread();
p_atmo_dyndata->setEffectThread(NULL);
if(p_effect_thread != NULL)
{
/*
forced the thread to die...
and wait for termination of the thread
*/
p_effect_thread->Terminate();
delete p_effect_thread;
msg_Dbg( p_filter, "effect thread died peacefully");
}
/*
close serial port if it is open (all OS specific is inside
CAtmoSerialConnection implemented / defined)
*/
CAtmoConnection *p_atmo_connection =
p_atmo_dyndata->getAtmoConnection();
p_atmo_dyndata->setAtmoConnection(NULL);
if(p_atmo_connection) {
p_atmo_connection->CloseConnection();
delete p_atmo_connection;
}
p_atmo_dyndata->UnLockCriticalSection();
}
}
#if defined(WIN32)
} else if(p_sys->pf_ctrl_atmo_finalize)
{
/* on win32 with active ctrl dll */
p_sys->pf_ctrl_atmo_finalize(what);
#endif
}
}
/*
switch the current light effect - does only something on win32, with the
external libraries - if the buildin effects are used nothing happens
*/
static int32_t AtmoSwitchEffect(filter_t *p_filter, int32_t newMode)
{
filter_sys_t *p_sys = p_filter->p_sys;
if(p_sys->p_atmo_config)
{
/*
buildin driver
doesnt know different modes for effects so this
function call would just do nothing special
in this case
*/
#if defined(WIN32)
} else if(p_sys->pf_ctrl_atmo_switch_effect)
{
/* on win32 with active ctrl dll */
return p_sys->pf_ctrl_atmo_switch_effect(newMode);
#endif
}
return emDisabled;
}
/*
set the current live picture source, does only something on win32,
with the external libraries - if the buildin effects are used nothing
happens...
*/
static int32_t AtmoSetLiveSource(filter_t *p_filter, int32_t newSource)
{
filter_sys_t *p_sys = p_filter->p_sys;
if(p_sys->p_atmo_config)
{
/*
buildin driver
doesnt know different sources so this
function call would just do nothing special
in this case
*/
#if defined(WIN32)
} else if(p_sys->pf_ctrl_atmo_set_live_source)
{
/* on win32 with active ctrl dll */
return p_sys->pf_ctrl_atmo_set_live_source(newSource);
#endif
}
return lvsGDI;
}
/*
setup the pixel transferbuffers which is used to transfer pixeldata from
the filter to the effect thread, and possible accross the process
boundaries on win32, with the external DLL
*/
static void AtmoCreateTransferBuffers(filter_t *p_filter,
int32_t FourCC,
int32_t bytePerPixel,
int32_t width,
int32_t height)
{
filter_sys_t *p_sys = p_filter->p_sys;
if(p_sys->p_atmo_config)
{
/*
we need a buffer where the image is stored (only for transfer
to the processing thread)
*/
if(p_sys->p_atmo_transfer_buffer)
free(p_sys->p_atmo_transfer_buffer);
p_sys->p_atmo_transfer_buffer = (uint8_t *)malloc(bytePerPixel *
width * height);
memset(&p_sys->mini_image_format,0,sizeof(BITMAPINFOHEADER));
p_sys->mini_image_format.biSize = sizeof(BITMAPINFOHEADER);
p_sys->mini_image_format.biWidth = width;
p_sys->mini_image_format.biHeight = height;
p_sys->mini_image_format.biBitCount = bytePerPixel*8;
p_sys->mini_image_format.biCompression = FourCC;
#if defined(WIN32)
} else if(p_sys->pf_ctrl_atmo_create_transfer_buffers)
{
/* on win32 with active ctrl dll */
p_sys->pf_ctrl_atmo_create_transfer_buffers(FourCC,
bytePerPixel,
width,
height);
#endif
}
}
/*
acquire the transfer buffer pointer the buildin version only
returns the pointer to the allocated buffer ... the
external version on win32 has to do some COM stuff to lock the
Variant Byte array which is behind the buffer
*/
static uint8_t* AtmoLockTransferBuffer(filter_t *p_filter)
{
filter_sys_t *p_sys = p_filter->p_sys;
if(p_sys->p_atmo_config)
{
return p_sys->p_atmo_transfer_buffer;
#if defined(WIN32)
} else if(p_sys->pf_ctrl_atmo_lock_transfer_buffer)
{
/* on win32 with active ctrl dll */
return p_sys->pf_ctrl_atmo_lock_transfer_buffer();
#endif
}
return NULL;
}
/*
send the content of current pixel buffer got with AtmoLockTransferBuffer
to the processing threads
- build in version - will forward the data to AtmoExternalCaptureInput Thread
- win32 external - will do the same, but across the process boundaries via
COM to the AtmoWinA.exe Process
*/
static void AtmoSendPixelData(filter_t *p_filter)
{
filter_sys_t *p_sys = p_filter->p_sys;
if(p_sys->p_atmo_config && p_sys->p_atmo_transfer_buffer)
{
CAtmoDynData *p_atmo_dyndata = p_sys->p_atmo_dyndata;
if(p_atmo_dyndata)
{
/*
the cast will go Ok because we are inside videolan there is only
this kind of effect thread implemented!
*/
CAtmoLiveView *p_atmo_live_view_thread =
(CAtmoLiveView *)p_atmo_dyndata->getEffectThread();
if(p_atmo_live_view_thread)
{
/*
the same as above inside videolan only this single kind of
input exists so we can cast without further tests!
*/
CAtmoExternalCaptureInput *p_atmo_external_capture_input_thread =
(CAtmoExternalCaptureInput *)p_atmo_live_view_thread->getAtmoInput();
if(p_atmo_external_capture_input_thread)
{
/*
this call will do a 1:1 copy of this buffer, and wakeup
the thread from normal sleeping
*/
p_atmo_external_capture_input_thread->
DeliverNewSourceDataPaket(&p_sys->mini_image_format,
p_sys->p_atmo_transfer_buffer);
}
}
}
#if defined(WIN32)
} else if(p_sys->pf_ctrl_atmo_send_pixel_data)
{
/* on win32 with active ctrl dll */
p_sys->pf_ctrl_atmo_send_pixel_data();
#endif
}
}
/*
Shutdown AtmoLight finally - is call from DestroyFilter
does the cleanup restores the effectmode on the external Software
(only win32) and possible setup the final light ...
*/
static void Atmo_Shutdown(filter_t *p_filter)
{
filter_sys_t *p_sys = p_filter->p_sys;
if(p_sys->b_enabled == VLC_TRUE)
{
/*
if there is a still running show pause color thread kill him!
*/
CheckAndStopFadeThread(p_filter);
if(p_sys->p_atmo_config || (p_sys->i_AtmoOldEffect == emStaticColor))
{
/*
fade to end color (in case of external AtmoWin Software
assume that the static color will equal to this
one to get a soft change and no flash!
*/
p_sys->b_pause_live = VLC_TRUE;
// perpare spawn fadeing thread
vlc_mutex_lock( &p_sys->filter_lock );
p_sys->p_fadethread = (fadethread_t *)vlc_object_create( p_filter,
sizeof(fadethread_t) );
p_sys->p_fadethread->p_filter = p_filter;
p_sys->p_fadethread->ui_red = p_sys->ui_endcolor_red;
p_sys->p_fadethread->ui_green = p_sys->ui_endcolor_green;
p_sys->p_fadethread->ui_blue = p_sys->ui_endcolor_blue;
p_sys->p_fadethread->i_steps = p_sys->i_endfadesteps;
if( vlc_thread_create( p_sys->p_fadethread,
"AtmoLight fadeing",
FadeToColorThread,
VLC_THREAD_PRIORITY_LOW,
VLC_FALSE ) )
{
msg_Err( p_filter, "cannot create FadeToColorThread" );
vlc_object_destroy( p_sys->p_fadethread );
p_sys->p_fadethread = NULL;
vlc_mutex_unlock( &p_sys->filter_lock );
} else {
vlc_mutex_unlock( &p_sys->filter_lock );
/* wait for the thread... */
vlc_thread_join(p_sys->p_fadethread);
vlc_object_destroy(p_sys->p_fadethread);
p_sys->p_fadethread = NULL;
}
}
if(p_sys->i_AtmoOldEffect != emLivePicture)
AtmoSwitchEffect(p_filter, p_sys->i_AtmoOldEffect);
else
AtmoSetLiveSource(p_filter, lvsGDI);
AtmoFinalize(p_filter, 1);
/* disable filter method .. */
p_sys->b_enabled = VLC_FALSE;
}
}
/*
initialize the filter_sys_t structure with the data from the settings
variables - if the external filter on win32 is enabled try loading the DLL,
if this fails fallback to the buildin software
*/
static void Atmo_SetupParameters(filter_t *p_filter)
{
vlc_bool_t b_use_buildin_driver = VLC_TRUE;
char *psz_path;
filter_sys_t *p_sys = p_filter->p_sys;
/* default filter disabled until DLL loaded and Init Success!*/
p_sys->b_enabled = VLC_FALSE;
/* setup default mini image size (may be later a user option) */
p_sys->i_atmo_width = 64;
p_sys->i_atmo_height = 48;
vlc_mutex_init( p_filter, &p_sys->filter_lock );
#if defined(WIN32)
/*
only on WIN32 the user has the choice between
internal driver and external
*/
b_use_buildin_driver = var_CreateGetBoolCommand( p_filter,
CFG_PREFIX "usebuildin" );
if(b_use_buildin_driver == VLC_FALSE) {
/* Load the Com Wrapper Library (source available) */
p_sys->h_AtmoCtrl = LoadLibraryA("AtmoCtrlLib.dll");
if(p_sys->h_AtmoCtrl != NULL)
{
msg_Dbg( p_filter, "LoadLibrary('AtmoCtrlLib.dll'); Success");
/* importing all required functions I hope*/
p_sys->pf_ctrl_atmo_initialize =
(int32_t (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoInitialize");
if(!p_sys->pf_ctrl_atmo_initialize)
msg_Err( p_filter, "export AtmoInitialize missing.");
p_sys->pf_ctrl_atmo_finalize =
(void (*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoFinalize");
if(!p_sys->pf_ctrl_atmo_finalize)
msg_Err( p_filter, "export AtmoFinalize missing.");
p_sys->pf_ctrl_atmo_switch_effect =
(int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoSwitchEffect");
if(!p_sys->pf_ctrl_atmo_switch_effect)
msg_Err( p_filter, "export AtmoSwitchEffect missing.");
p_sys->pf_ctrl_atmo_set_live_source =
(int32_t(*)(int32_t))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoSetLiveSource");
if(!p_sys->pf_ctrl_atmo_set_live_source)
msg_Err( p_filter, "export AtmoSetLiveSource missing.");
p_sys->pf_ctrl_atmo_create_transfer_buffers =
(void (*)(int32_t, int32_t, int32_t , int32_t))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoCreateTransferBuffers");
if(!p_sys->pf_ctrl_atmo_create_transfer_buffers)
msg_Err( p_filter, "export AtmoCreateTransferBuffers missing.");
p_sys->pf_ctrl_atmo_lock_transfer_buffer=
(uint8_t*(*) (void))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoLockTransferBuffer");
if(!p_sys->pf_ctrl_atmo_lock_transfer_buffer)
msg_Err( p_filter, "export AtmoLockTransferBuffer missing.");
p_sys->pf_ctrl_atmo_send_pixel_data =
(void (*)(void))GetProcAddress(p_sys->h_AtmoCtrl,"AtmoSendPixelData");
if(!p_sys->pf_ctrl_atmo_send_pixel_data)
msg_Err( p_filter, "export AtmoSendPixelData missing.");
} else {
/* the DLL is missing try internal filter ...*/
msg_Warn( p_filter, "AtmoCtrlLib.dll missing fallback to internal driver");
b_use_buildin_driver = VLC_TRUE;
}
}
#endif
if(b_use_buildin_driver == VLC_TRUE) {
msg_Dbg( p_filter, "use buildin driver");
/*
now we have to read a lof of options from the config dialog
most important the serial device if not set ... we can skip
the rest and disable the filter...
*/
char *psz_serialdev = var_CreateGetStringCommand( p_filter,
CFG_PREFIX "serialdev" );
if(psz_serialdev && (strlen(psz_serialdev)>0)) {
msg_Dbg( p_filter, "use buildin driver on port %s",psz_serialdev);
p_sys->p_atmo_config = new CAtmoConfig();
p_sys->p_atmo_config->setSerialDevice(psz_serialdev);
p_sys->p_atmo_config->setLiveViewFilterMode(
(AtmoFilterMode)var_CreateGetIntegerCommand( p_filter,
CFG_PREFIX "filtermode")
);
p_sys->p_atmo_config->setLiveViewFilter_PercentNew(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "PercentNew")
);
p_sys->p_atmo_config->setLiveViewFilter_MeanLength(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "MeanLength")
);
p_sys->p_atmo_config->setLiveViewFilter_MeanThreshold(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "MeanThreshold")
);
p_sys->p_atmo_config->setLiveView_EdgeWeighting(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "EdgeWeightning")
);
p_sys->p_atmo_config->setLiveView_BrightCorrect(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "Brightness")
);
p_sys->p_atmo_config->setLiveView_DarknessLimit(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "DarknessLimit")
);
p_sys->p_atmo_config->setLiveView_HueWinSize(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "HueWinSize")
);
p_sys->p_atmo_config->setLiveView_SatWinSize(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "SatWinSize")
);
/* currently not required inside vlc */
p_sys->p_atmo_config->setLiveView_WidescreenMode( 0 );
p_sys->p_atmo_config->setLiveView_FrameDelay(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "FrameDelay")
);
p_sys->p_atmo_config->setUseSoftwareWhiteAdj(
var_CreateGetBoolCommand( p_filter, CFG_PREFIX "whiteadj")
);
p_sys->p_atmo_config->setWhiteAdjustment_Red(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-red")
);
p_sys->p_atmo_config->setWhiteAdjustment_Green(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-green")
);
p_sys->p_atmo_config->setWhiteAdjustment_Blue(
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "white-blue")
);
tChannelAssignment *p_channel_assignment =
p_sys->p_atmo_config->getChannelAssignment(0);
p_channel_assignment->mappings[0] = var_CreateGetIntegerCommand(
p_filter, CFG_PREFIX "channel_0");
p_channel_assignment->mappings[1] = var_CreateGetIntegerCommand(
p_filter, CFG_PREFIX "channel_1");
p_channel_assignment->mappings[2] = var_CreateGetIntegerCommand(
p_filter, CFG_PREFIX "channel_2");
p_channel_assignment->mappings[3] = var_CreateGetIntegerCommand(
p_filter, CFG_PREFIX "channel_3");
p_channel_assignment->mappings[4] = var_CreateGetIntegerCommand(
p_filter, CFG_PREFIX "channel_4");
for(int i=0;i<ATMO_NUM_CHANNELS;i++)
msg_Dbg( p_filter, "map software channel %d to hardware channel %d",
p_channel_assignment->mappings[i],
i
);
// gradient_zone_0
char psz_gradient_var_name[30];
char *psz_gradient_file;
for(int i=0;i<ATMO_NUM_CHANNELS;i++)
{
sprintf(psz_gradient_var_name, CFG_PREFIX "gradient_zone_%d", i);
psz_gradient_file = var_CreateGetStringCommand(
p_filter,
psz_gradient_var_name
);
if(psz_gradient_file && strlen(psz_gradient_file)>0)
{
msg_Dbg( p_filter, "loading gradientfile %s for "\
"zone %d", psz_gradient_file, i);
int i_res = p_sys->p_atmo_config->getZoneDefinition(i)->
LoadGradientFromBitmap(psz_gradient_file);
if(i_res != ATMO_LOAD_GRADIENT_OK)
{
msg_Err( p_filter,"failed to load gradient '%s' with "\
"error %d",psz_gradient_file,i_res);
}
}
delete psz_gradient_file;
}
p_sys->p_atmo_dyndata = new CAtmoDynData((vlc_object_t *)p_filter,
p_sys->p_atmo_config
);
msg_Dbg( p_filter, "buildin driver initialized");
free(psz_serialdev);
} else {
msg_Err(p_filter,"no serial devicename set");
}
}
switch( p_filter->fmt_in.video.i_chroma )
{
case VLC_FOURCC('I','4','2','0'):
case VLC_FOURCC('I','Y','U','V'):
case VLC_FOURCC('Y','V','1','2'):
case VLC_FOURCC('Y','V','1','6'):
case VLC_FOURCC('Y','V','U','9'):
// simple enough? Dionoea?
p_sys->pf_extract_mini_image = ExtractMiniImage_YUV;
break;
default:
msg_Dbg( p_filter, "InitFilter-unsupported chroma: %4.4s",
(char *)&p_filter->fmt_in.video.i_chroma);
p_sys->pf_extract_mini_image = NULL;
}
p_sys->i_crop_x_offset = 0;
p_sys->i_crop_y_offset = 0;
p_sys->i_crop_width = p_filter->fmt_in.video.i_visible_width;
p_sys->i_crop_height = p_filter->fmt_in.video.i_visible_height;
msg_Dbg( p_filter, "set default crop %d,%d %dx%d",p_sys->i_crop_x_offset,
p_sys->i_crop_y_offset,
p_sys->i_crop_width,
p_sys->i_crop_height );
#if defined(__ATMO_DEBUG__)
/* save debug images to a folder as Bitmap files ? */
p_sys->b_saveframes = var_CreateGetBoolCommand( p_filter,
CFG_PREFIX "saveframes"
);
msg_Dbg(p_filter,"saveframes = %d", (int)p_sys->b_saveframes);
/*
read debug image folder from config
*/
psz_path = var_CreateGetStringCommand( p_filter, CFG_PREFIX "framepath" );
if(psz_path != NULL)
{
strcpy(p_sys->sz_framepath, psz_path);
#if defined( WIN32 )
size_t i_strlen = strlen(p_sys->sz_framepath);
if((i_strlen>0) && (p_sys->sz_framepath[i_strlen-1] != '\\'))
{
p_sys->sz_framepath[i_strlen] = '\\';
p_sys->sz_framepath[i_strlen+1] = 0;
}
#endif
free(psz_path);
}
msg_Dbg(p_filter,"saveframesfolder %s",p_sys->sz_framepath);
#endif
/*
size of extracted image by default 64x48 (other imagesizes are
currently ignored by AtmoWin)
*/
p_sys->i_atmo_width = var_CreateGetIntegerCommand( p_filter,
CFG_PREFIX "width");
p_sys->i_atmo_height = var_CreateGetIntegerCommand( p_filter,
CFG_PREFIX "height");
msg_Dbg(p_filter,"mini image size %d * %d pixels", p_sys->i_atmo_width,
p_sys->i_atmo_height);
/*
because atmowin could also be used for lighten up the room - I think if you
pause the video it would be useful to get a little bit more light into to
your living room? - instead switching on a lamp?
*/
p_sys->b_usepausecolor = var_CreateGetBoolCommand( p_filter,
CFG_PREFIX "usepausecolor" );
p_sys->ui_pausecolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
CFG_PREFIX "pcolor-red");
p_sys->ui_pausecolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
CFG_PREFIX "pcolor-green");
p_sys->ui_pausecolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
CFG_PREFIX "pcolor-blue");
p_sys->i_fadesteps = var_CreateGetIntegerCommand( p_filter,
CFG_PREFIX "fadesteps");
if(p_sys->i_fadesteps < 1)
p_sys->i_fadesteps = 1;
msg_Dbg(p_filter,"use pause color %d, RGB: %d, %d, %d, Fadesteps: %d",
(int)p_sys->b_usepausecolor,
p_sys->ui_pausecolor_red,
p_sys->ui_pausecolor_green,
p_sys->ui_pausecolor_blue,
p_sys->i_fadesteps);
/*
this color is use on shutdown of the filter - the define the
final light after playback... may be used to dim up the light -
how it happens in the cinema...
*/
p_sys->ui_endcolor_red = (uint8_t)var_CreateGetIntegerCommand( p_filter,
CFG_PREFIX "ecolor-red");
p_sys->ui_endcolor_green = (uint8_t)var_CreateGetIntegerCommand( p_filter,
CFG_PREFIX "ecolor-green");
p_sys->ui_endcolor_blue = (uint8_t)var_CreateGetIntegerCommand( p_filter,
CFG_PREFIX "ecolor-blue");
p_sys->i_endfadesteps = var_CreateGetIntegerCommand( p_filter,
CFG_PREFIX "efadesteps");
if(p_sys->i_endfadesteps < 1)
p_sys->i_endfadesteps = 1;
msg_Dbg(p_filter,"use ende color RGB: %d, %d, %d, Fadesteps: %d",
p_sys->ui_endcolor_red,
p_sys->ui_endcolor_green,
p_sys->ui_endcolor_blue,
p_sys->i_endfadesteps);
/* if the external DLL was loaded successfully call AtmoInitialize -
(must be done for each thread where you wan't to use AtmoLight!
*/
int i = AtmoInitialize(p_filter, VLC_FALSE);
#if defined( WIN32 )
if((i != 1) && !b_use_buildin_driver)
{
/* COM Server for AtmoLight not running ?
if the exe path is configured try to start the "userspace" driver
*/
psz_path = var_CreateGetStringCommand( p_filter,
CFG_PREFIX "atmowinexe" );
if(psz_path != NULL)
{
STARTUPINFO startupinfo;
PROCESS_INFORMATION pinfo;
memset(&startupinfo, 0, sizeof(STARTUPINFO));
startupinfo.cb = sizeof(STARTUPINFO);
if(CreateProcess(psz_path, NULL, NULL, NULL,
FALSE, 0, NULL, NULL, &startupinfo, &pinfo) == TRUE)
{
msg_Dbg(p_filter,"launched AtmoWin from %s",psz_path);
WaitForInputIdle(pinfo.hProcess, 5000);
/*
retry to initialize the library COM ... functionality
after the server was launched
*/
i = AtmoInitialize(p_filter, VLC_FALSE);
} else {
msg_Err(p_filter,"failed to launch AtmoWin from %s", psz_path);
}
free(psz_path);
}
}
#endif
if(i == 1) /* Init Atmolight success... */
{
msg_Dbg( p_filter, "AtmoInitialize Ok!");
/* Setup Transferbuffers for 64 x 48 , RGB with 32bit Per Pixel */
AtmoCreateTransferBuffers(p_filter, BI_RGB, 4,
p_sys->i_atmo_width,
p_sys->i_atmo_height
);
/* say the userspace driver that a live mode should be activated
the functions returns the old mode for later restore!
*/
p_sys->i_AtmoOldEffect = AtmoSwitchEffect(p_filter, emLivePicture);
/*
live view can have two differnt source the AtmoWinA
internal GDI Screencapture and the external one - which we
need here...
*/
AtmoSetLiveSource(p_filter, lvsExternal);
/* enable other parts only if everything is fine */
p_sys->b_enabled = VLC_TRUE;
}
}
/*****************************************************************************
* CreateFilter: allocates AtmoLight video thread output method
*****************************************************************************
* This function allocates and initializes a AtmoLight vout method.
*****************************************************************************/
static int CreateFilter( vlc_object_t *p_this )
{
filter_t *p_filter = (filter_t *)p_this;
filter_sys_t *p_sys;
/* Allocate structure */
p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) );
p_filter->p_sys = p_sys;
if( p_filter->p_sys == NULL )
{
msg_Err( p_filter, "out of memory for p_sys structure" );
return VLC_ENOMEM;
}
/* set all entries to zero */
memset(p_sys, 0, sizeof( filter_sys_t ));
/* further Setup Function pointers for videolan for calling my filter */
p_filter->pf_video_filter = Filter;
config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
p_filter->p_cfg );
AddStateVariableCallback(p_filter);
AddCropVariableCallback(p_filter);
AddAtmoSettingsVariablesCallbacks(p_filter);
Atmo_SetupParameters(p_filter);
return VLC_SUCCESS;
}
/*****************************************************************************
* DestroyFilter: destroy AtmoLight video thread output method
*****************************************************************************
* Terminate an output method created by CreateFilter
*****************************************************************************/
static void DestroyFilter( vlc_object_t *p_this )
{
filter_t *p_filter = (filter_t *)p_this;
filter_sys_t *p_sys = p_filter->p_sys;
DelStateVariableCallback(p_filter);
DelCropVariableCallback(p_filter);
DelAtmoSettingsVariablesCallbacks(p_filter);
Atmo_Shutdown(p_filter);
#if defined( WIN32 )
if(p_sys->h_AtmoCtrl != NULL)
{
FreeLibrary(p_sys->h_AtmoCtrl);
}
#endif
delete p_sys->p_atmo_dyndata;
delete p_sys->p_atmo_config;
vlc_mutex_destroy( &p_sys->filter_lock );
free( p_sys );
}
/*
function stolen from some other videolan source filter ;-)
for the moment RGB is OK... but better would be a direct transformation
from YUV --> HSV
*/
static inline void yuv_to_rgb( uint8_t *r, uint8_t *g, uint8_t *b,
uint8_t y1, uint8_t u1, uint8_t v1 )
{
/* macros used for YUV pixel conversions */
# define SCALEBITS 10
# define ONE_HALF (1 << (SCALEBITS - 1))
# define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
# define CLAMP( x ) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (x));
int y, cb, cr, r_add, g_add, b_add;
cb = u1 - 128;
cr = v1 - 128;
r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;
g_add = - FIX(0.34414*255.0/224.0) * cb
- FIX(0.71414*255.0/224.0) * cr + ONE_HALF;
b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;
y = (y1 - 16) * FIX(255.0/219.0);
*r = CLAMP((y + r_add) >> SCALEBITS);
*g = CLAMP((y + g_add) >> SCALEBITS);
*b = CLAMP((y + b_add) >> SCALEBITS);
}
/******************************************************************************
* ExtractMiniImage_YUV: extract a small image from the picture as 24-bit RGB
*******************************************************************************
* p_sys is a pointer to
* p_inpic is the source frame
* p_transfer_dest is the target buffer for the picture must be big enough!
* (in win32 enviroment this buffer comes from the external DLL where it is
* create as "variant array" and returned through the AtmoLockTransferbuffer
*/
static void ExtractMiniImage_YUV(filter_sys_t *p_sys,
picture_t *p_inpic,
uint8_t *p_transfer_dest)
{
int i_col;
int i_row;
uint8_t *p_src_y;
uint8_t *p_src_u;
uint8_t *p_src_v;
uint8_t *p_rgb_dst_line_red;
uint8_t *p_rgb_dst_line_green;
uint8_t *p_rgb_dst_line_blue;
int i_xpos_y;
int i_xpos_u;
int i_xpos_v;
/* calcute Pointers for Storage of B G R (A) */
p_rgb_dst_line_blue = p_transfer_dest;
p_rgb_dst_line_green = p_transfer_dest + 1;
p_rgb_dst_line_red = p_transfer_dest + 2 ;
int i_row_count = p_sys->i_atmo_height + 1;
int i_col_count = p_sys->i_atmo_width + 1;
int i_y_row,i_u_row,i_v_row,i_pixel_row;
int i_pixel_col;
/* these two ugly loops extract the small image - goes it faster? how?
the loops are so designed that there is a small border around the extracted
image so we wont get column and row - zero from the frame, and not the most
right and bottom pixels --- which may be clipped on computers useing TV out
- through overscan!
TODO: try to find out if the output is clipped through VLC - and try here
to ingore the clipped away area for a better result!
TODO: performance improvement in InitFilter percalculated the offsets of
the lines inside the planes so I can save (i_row_count * 3) 2xMUL and
one time DIV the same could be done for the inner loop I think...
*/
for(i_row = 1; i_row < i_row_count; i_row++)
{
// calcute the current Lines in the source planes for this outputrow
/* Adresscalcuation pointer to plane Length of one pixelrow in bytes
calculate row now number
*/
/*
p_inpic->format? transform Pixel row into row of plane...
how? simple? fast? good?
*/
/* compute the source pixel row and respect the active cropping */
i_pixel_row = (i_row * p_sys->i_crop_height) / i_row_count
+ p_sys->i_crop_y_offset;
/*
trans for these Pixel row into the row of each plane ..
because planesize can differ from image size
*/
i_y_row = (i_pixel_row * p_inpic->p[Y_PLANE].i_visible_lines) /
p_inpic->format.i_visible_height;
i_u_row = (i_pixel_row * p_inpic->p[U_PLANE].i_visible_lines) /
p_inpic->format.i_visible_height;
i_v_row = (i_pixel_row * p_inpic->p[V_PLANE].i_visible_lines) /
p_inpic->format.i_visible_height;
/* calculate the pointers to the pixeldata for this row
in each plane
*/
p_src_y = p_inpic->p[Y_PLANE].p_pixels +
p_inpic->p[Y_PLANE].i_pitch * i_y_row;
p_src_u = p_inpic->p[U_PLANE].p_pixels +
p_inpic->p[U_PLANE].i_pitch * i_u_row;
p_src_v = p_inpic->p[V_PLANE].p_pixels +
p_inpic->p[V_PLANE].i_pitch * i_v_row;
for(i_col = 1; i_col < i_col_count; i_col++)
{
i_pixel_col = (i_col * p_sys->i_crop_width) / i_col_count +
p_sys->i_crop_x_offset;
/*
trans for these Pixel row into the row of each plane ..
because planesize can differ from image size
*/
i_xpos_y = (i_pixel_col * p_inpic->p[Y_PLANE].i_visible_pitch) /
p_inpic->format.i_visible_width;
i_xpos_u = (i_pixel_col * p_inpic->p[U_PLANE].i_visible_pitch) /
p_inpic->format.i_visible_width;
i_xpos_v = (i_pixel_col * p_inpic->p[V_PLANE].i_visible_pitch) /
p_inpic->format.i_visible_width;
yuv_to_rgb(p_rgb_dst_line_red,
p_rgb_dst_line_green,
p_rgb_dst_line_blue,
p_src_y[i_xpos_y],
p_src_u[i_xpos_u],
p_src_v[i_xpos_v]);
/* +4 because output image should be RGB32 with dword alignment! */
p_rgb_dst_line_red += 4;
p_rgb_dst_line_green += 4;
p_rgb_dst_line_blue += 4;
}
}
}
/******************************************************************************
* SaveBitmap: Saves the content of a transferbuffer as Bitmap to disk
*******************************************************************************
* just for debugging
* p_sys -> configuration if Atmo from there the function will get height and
* width
* p_pixels -> should be the dword aligned BGR(A) image data
* psz_filename -> filename where to store
*/
#if defined(__ATMO_DEBUG__)
void SaveBitmap(filter_sys_t *p_sys, uint8_t *p_pixels, char *psz_filename)
{
/* for debug out only used*/
BITMAPINFO bmp_info;
BITMAPFILEHEADER bmp_fileheader;
FILE *fp_bitmap;
memset(&bmp_info, 0, sizeof(BITMAPINFO));
bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmp_info.bmiHeader.biSizeImage = p_sys->i_atmo_height *
p_sys->i_atmo_width * 4;
bmp_info.bmiHeader.biCompression = BI_RGB;
bmp_info.bmiHeader.biWidth = p_sys->i_atmo_width;
bmp_info.bmiHeader.biHeight = -p_sys->i_atmo_height;
bmp_info.bmiHeader.biBitCount = 32;
bmp_info.bmiHeader.biPlanes = 1;
bmp_fileheader.bfReserved1 = 0;
bmp_fileheader.bfReserved2 = 0;
bmp_fileheader.bfSize = sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER) +
bmp_info.bmiHeader.biSizeImage;
bmp_fileheader.bfType = 'MB';
bmp_fileheader.bfOffBits = sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER);
fp_bitmap = fopen(psz_filename,"wb");
if( fp_bitmap != NULL)
{
fwrite(&bmp_fileheader, sizeof(BITMAPFILEHEADER), 1, fp_bitmap);
fwrite(&bmp_info.bmiHeader, sizeof(BITMAPINFOHEADER), 1, fp_bitmap);
fwrite(p_pixels, bmp_info.bmiHeader.biSizeImage, 1, fp_bitmap);
fclose(fp_bitmap);
}
}
#endif
/****************************************************************************
* CreateMiniImage: extracts a 64x48 pixel image from the frame
* (there is a small border arround thats why the loops starts with one
* instead zero) without any interpolation
*****************************************************************************/
static void CreateMiniImage( filter_t *p_filter, picture_t *p_inpic)
{
filter_sys_t *p_sys = p_filter->p_sys;
/*
pointer to RGB Buffer created in external libary as safe array which
is locked inside AtmoLockTransferBuffer
*/
uint8_t *p_transfer = NULL;
#if defined( __ATMO_DEBUG__ )
/* for debug out only used*/
char sz_filename[MAX_PATH];
#endif
/*
Lock the before created VarArray (AtmoCreateTransferBuffers)
inside my wrapper library and give me a pointer to the buffer!
below linux a global buffer may be used and protected with a mutex?
*/
p_transfer = AtmoLockTransferBuffer(p_filter);
if(p_transfer == NULL)
{
msg_Err( p_filter, "AtmoLight no transferbuffer available. "\
"AtmoLight will be disabled!");
p_sys->b_enabled = VLC_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 == VLC_TRUE) && (p_sys->sz_framepath[0] != 0 ))
{
if((p_sys->i_framecounter & 127) == 0)
{
sprintf(sz_filename,"%satmo_dbg_%06d.bmp",p_sys->sz_framepath,
p_sys->i_framecounter);
msg_Dbg(p_filter, "SaveFrame %s",sz_filename);
SaveBitmap(p_sys, p_transfer, sz_filename);
}
p_sys->i_framecounter++;
}
#endif
/* show the colors on the wall */
AtmoSendPixelData(p_filter);
}
/*****************************************************************************
* Filter: calls the extract method and forwards the incomming picture 1:1
*****************************************************************************
*
*****************************************************************************/
static picture_t * Filter( filter_t *p_filter, picture_t *p_pic )
{
filter_sys_t *p_sys = p_filter->p_sys;
if( !p_pic ) return NULL;
if((p_sys->b_enabled == VLC_TRUE) &&
(p_sys->pf_extract_mini_image != NULL) &&
(p_sys->b_pause_live == VLC_FALSE))
{
CreateMiniImage(p_filter, p_pic);
}
return p_pic;
}
/*****************************************************************************
* FadeToColorThread: Threadmethod which changes slowly the color
* to a target color defined in p_fadethread struct
* use for: Fade to Pause Color, and Fade to End Color
*****************************************************************************/
static void FadeToColorThread(fadethread_t *p_fadethread)
{
filter_sys_t *p_sys = (filter_sys_t *)p_fadethread->p_filter->p_sys;
int i_steps_done = 0;
int i_index;
int i_pause_red;
int i_pause_green;
int i_pause_blue;
int i_src_red;
int i_src_green;
int i_src_blue;
vlc_thread_ready( p_fadethread );
uint8_t *p_source = NULL;
/* initialize AtmoWin for this thread! */
AtmoInitialize(p_fadethread->p_filter , VLC_TRUE);
uint8_t *p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
if(p_transfer != NULL) {
/* safe colors as "32bit" Integers to avoid overflows*/
i_pause_red = p_fadethread->ui_red;
i_pause_blue = p_fadethread->ui_blue;
i_pause_green = p_fadethread->ui_green;
/*
allocate a temporary buffer for the last send
image size less then 15kb
*/
int i_size = 4 * p_sys->i_atmo_width * p_sys->i_atmo_height;
p_source = (uint8_t *)malloc( i_size );
if(p_source != NULL)
{
/*
get a copy of the last transfered image as orign for the
fading steps...
*/
memcpy(p_source, p_transfer, i_size);
/* send the same pixel data again... to unlock the buffer! */
AtmoSendPixelData( p_fadethread->p_filter );
while( (!p_fadethread->b_die) &&
(i_steps_done < p_fadethread->i_steps))
{
p_transfer = AtmoLockTransferBuffer( p_fadethread->p_filter );
if(!p_transfer) break; /* should not happen if it worked
one time in the code above! */
i_steps_done++;
/*
move all pixels in the mini image (64x48) one step closer to
the desired color these loop takes the most time of this
thread improvements wellcome!
*/
for(i_index = 0;
(i_index < i_size) && (!p_fadethread->b_die);
i_index+=4)
{
i_src_blue = p_source[i_index+0];
i_src_green = p_source[i_index+1];
i_src_red = p_source[i_index+2];
p_transfer[i_index+0] = (uint8_t) (((
(i_pause_blue - i_src_blue)
* i_steps_done)/p_fadethread->i_steps)
+ i_src_blue);
p_transfer[i_index+1] = (uint8_t) (((
(i_pause_green - i_src_green)
* i_steps_done)/p_fadethread->i_steps)
+ i_src_green);
p_transfer[i_index+2] = (uint8_t) (((
(i_pause_red - i_src_red)
* i_steps_done)/p_fadethread->i_steps)
+ i_src_red);
}
/* send image to lightcontroller */
AtmoSendPixelData( p_fadethread->p_filter );
/* is there something like and interruptable sleep inside
the VLC libaries? inside native win32 I would use an Event
(CreateEvent) and here an WaitForSingleObject?
*/
if(p_fadethread->b_die) break;
msleep(10000);
if(p_fadethread->b_die) break;
msleep(10000);
if(p_fadethread->b_die) break;
msleep(10000);
if(p_fadethread->b_die) break;
msleep(10000);
}
free(p_source);
} else {
/* in failure of malloc also unlock buffer */
AtmoSendPixelData(p_fadethread->p_filter);
}
}
/* call indirect to OleUnitialize() for this thread */
AtmoFinalize(p_fadethread->p_filter, 0);
}
/*****************************************************************************
* CheckAndStopFadeThread: if there is a fadethread structure left, or running.
******************************************************************************
* this function will stop the thread ... and waits for its termination
* before removeing the objects from vout_sys_t ...
******************************************************************************/
static void CheckAndStopFadeThread(filter_t *p_filter)
{
filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
vlc_mutex_lock( &p_sys->filter_lock );
if(p_sys->p_fadethread != NULL)
{
msg_Dbg(p_filter, "kill still running fadeing thread...");
p_sys->p_fadethread->b_die = VLC_TRUE;
vlc_thread_join(p_sys->p_fadethread);
vlc_object_destroy(p_sys->p_fadethread);
p_sys->p_fadethread = NULL;
}
vlc_mutex_unlock( &p_sys->filter_lock );
}
/*****************************************************************************
* StateCallback: Callback for the inputs variable "State" to get notified
* about Pause and Continue Playback events.
*****************************************************************************/
static int StateCallback( vlc_object_t *p_this, char const *psz_cmd,
vlc_value_t oldval, vlc_value_t newval,
void *p_data )
{
filter_t *p_filter = (filter_t *)p_data;
filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
if((p_sys->b_usepausecolor == VLC_TRUE) && (p_sys->b_enabled == VLC_TRUE))
{
msg_Dbg(p_filter, "state change from: %d to %d", oldval.i_int,
newval.i_int);
if((newval.i_int == PAUSE_S) && (oldval.i_int == PLAYING_S))
{
/* tell the other thread to stop sending images to light
controller */
p_sys->b_pause_live = VLC_TRUE;
// ggf. alten Thread abräumen should not happen....
CheckAndStopFadeThread(p_filter);
// perpare spawn fadeing thread
vlc_mutex_lock( &p_sys->filter_lock );
/*
launch only a new thread if there is none active!
or waiting for cleanup
*/
if(p_sys->p_fadethread == NULL)
{
p_sys->p_fadethread = (fadethread_t *)vlc_object_create(
p_filter,
sizeof(fadethread_t) );
p_sys->p_fadethread->p_filter = p_filter;
p_sys->p_fadethread->ui_red = p_sys->ui_pausecolor_red;
p_sys->p_fadethread->ui_green = p_sys->ui_pausecolor_green;
p_sys->p_fadethread->ui_blue = p_sys->ui_pausecolor_blue;
p_sys->p_fadethread->i_steps = p_sys->i_fadesteps;
if( vlc_thread_create( p_sys->p_fadethread,
"AtmoLight fadeing",
FadeToColorThread,
VLC_THREAD_PRIORITY_LOW,
VLC_FALSE) )
{
msg_Err( p_filter, "cannot create FadeToColorThread" );
vlc_object_destroy( p_sys->p_fadethread );
p_sys->p_fadethread = NULL;
}
}
vlc_mutex_unlock( &p_sys->filter_lock );
}
if((newval.i_int == PLAYING_S) && (oldval.i_int == PAUSE_S))
{
/* playback continues check thread state */
CheckAndStopFadeThread(p_filter);
/* reactivate the Render function... to do its normal work */
p_sys->b_pause_live = VLC_FALSE;
}
}
return VLC_SUCCESS;
}
/*****************************************************************************
* AddPlaylistInputThreadStateCallback: Setup call back on "State" Variable
*****************************************************************************
* Add Callback function to the "state" variable of the input thread..
* first find the PlayList and get the input thread from there to attach
* my callback? is vlc_object_find the right way for this??
*****************************************************************************/
static void AddStateVariableCallback(filter_t *p_filter)
{
playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_filter,
VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( p_playlist )
{
input_thread_t *p_input = p_playlist->p_input;
if(p_input)
{
var_AddCallback( p_input, "state", StateCallback, p_filter );
}
vlc_object_release( p_playlist );
}
}
/*****************************************************************************
* DelPlaylistInputThreadStateCallback: Remove call back on "State" Variable
*****************************************************************************
* Delete the callback function to the "state" variable of the input thread...
* first find the PlayList and get the input thread from there to attach
* my callback? is vlc_object_find the right way for this??
*****************************************************************************/
static void DelStateVariableCallback( filter_t *p_filter )
{
playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_filter,
VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( p_playlist )
{
input_thread_t *p_input = p_playlist->p_input;
if(p_input)
{
var_DelCallback( p_input, "state", StateCallback, p_filter );
}
vlc_object_release( p_playlist );
}
}
static int CropCallback(vlc_object_t *p_this, char const *psz_cmd,
vlc_value_t oldval, vlc_value_t newval,
void *p_data)
{
vout_thread_t *p_vout = (vout_thread_t *)p_this;
filter_t *p_filter = (filter_t *)p_data;
filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
/*
//if the handler is attache to crop variable directly!
int i_visible_width, i_visible_height, i_x_offset, i_y_offset;
atmo_parse_crop(newval.psz_string, p_vout->fmt_render,
p_vout->fmt_render,
i_visible_width, i_visible_height,
i_x_offset, i_y_offset);
p_sys->i_crop_x_offset = i_x_offset;
p_sys->i_crop_y_offset = i_y_offset;
p_sys->i_crop_width = i_visible_width;
p_sys->i_crop_height = i_visible_height;
*/
p_sys->i_crop_x_offset = p_vout->fmt_in.i_x_offset;
p_sys->i_crop_y_offset = p_vout->fmt_in.i_y_offset;
p_sys->i_crop_width = p_vout->fmt_in.i_visible_width;
p_sys->i_crop_height = p_vout->fmt_in.i_visible_height;
msg_Dbg(p_filter, "cropping picture %ix%i to %i,%i,%ix%i",
p_vout->fmt_in.i_width,
p_vout->fmt_in.i_height,
p_sys->i_crop_x_offset,
p_sys->i_crop_y_offset,
p_sys->i_crop_width,
p_sys->i_crop_height
);
return VLC_SUCCESS;
}
static void AddCropVariableCallback( filter_t *p_filter)
{
vout_thread_t *p_vout = (vout_thread_t *)vlc_object_find( p_filter,
VLC_OBJECT_VOUT,
FIND_ANYWHERE );
if( p_vout )
{
var_AddCallback( p_vout, "crop-update", CropCallback, p_filter );
vlc_object_release( p_vout );
}
}
static void DelCropVariableCallback( filter_t *p_filter)
{
vout_thread_t *p_vout = (vout_thread_t *)vlc_object_find( p_filter,
VLC_OBJECT_VOUT,
FIND_ANYWHERE );
if( p_vout )
{
var_DelCallback( p_vout, "crop-update", CropCallback, p_filter );
vlc_object_release( p_vout );
}
}
/****************************************************************************
* StateCallback: Callback for the inputs variable "State" to get notified
* about Pause and Continue Playback events.
*****************************************************************************/
static int AtmoSettingsCallback( vlc_object_t *p_this, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval,
void *p_data )
{
filter_t *p_filter = (filter_t *)p_data;
filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
CAtmoConfig *p_atmo_config = p_sys->p_atmo_config;
if(p_atmo_config)
{
msg_Dbg(p_filter, "apply AtmoSettingsCallback %s (int: %d -> %d)",
psz_var,
oldval.i_int,
newval.i_int
);
if( !strcmp( psz_var, CFG_PREFIX "filtermode" ))
p_atmo_config->setLiveViewFilterMode( (AtmoFilterMode)newval.i_int);
else if( !strcmp( psz_var, CFG_PREFIX "PercentNew" ))
p_atmo_config->setLiveViewFilter_PercentNew( newval.i_int );
else if( !strcmp( psz_var, CFG_PREFIX "MeanLength" ))
p_atmo_config->setLiveViewFilter_MeanLength( newval.i_int );
else if( !strcmp( psz_var, CFG_PREFIX "MeanThreshold" ))
p_atmo_config->setLiveViewFilter_MeanThreshold( newval.i_int );
else if( !strcmp( psz_var, CFG_PREFIX "EdgeWeightning" ))
p_atmo_config->setLiveView_EdgeWeighting( newval.i_int );
else if( !strcmp( psz_var, CFG_PREFIX "Brightness" ))
p_atmo_config->setLiveView_BrightCorrect( newval.i_int );
else if( !strcmp( psz_var, CFG_PREFIX "DarknessLimit" ))
p_atmo_config->setLiveView_DarknessLimit( newval.i_int );
else if( !strcmp( psz_var, CFG_PREFIX "HueWinSize" ))
p_atmo_config->setLiveView_HueWinSize( newval.i_int );
else if( !strcmp( psz_var, CFG_PREFIX "SatWinSize" ))
p_atmo_config->setLiveView_SatWinSize( newval.i_int );
else if( !strcmp( psz_var, CFG_PREFIX "FrameDelay" ))
p_atmo_config->setLiveView_FrameDelay( newval.i_int );
else if( !strcmp( psz_var, CFG_PREFIX "whiteadj" ))
p_atmo_config->setUseSoftwareWhiteAdj( newval.b_bool );
else if( !strcmp( psz_var, CFG_PREFIX "white-red" ))
p_atmo_config->setWhiteAdjustment_Red( newval.i_int );
else if( !strcmp( psz_var, CFG_PREFIX "white-green" ))
p_atmo_config->setWhiteAdjustment_Green( newval.i_int );
else if( !strcmp( psz_var, CFG_PREFIX "white-blue" ))
p_atmo_config->setWhiteAdjustment_Blue( newval.i_int );
}
return VLC_SUCCESS;
}
static void AddAtmoSettingsVariablesCallbacks(filter_t *p_filter)
{
var_AddCallback( p_filter, CFG_PREFIX "filtermode",
AtmoSettingsCallback, p_filter );
var_AddCallback( p_filter, CFG_PREFIX "PercentNew",
AtmoSettingsCallback, p_filter );
var_AddCallback( p_filter, CFG_PREFIX "MeanLength",
AtmoSettingsCallback, p_filter );
var_AddCallback( p_filter, CFG_PREFIX "MeanThreshold",
AtmoSettingsCallback, p_filter );
var_AddCallback( p_filter, CFG_PREFIX "EdgeWeightning",
AtmoSettingsCallback, p_filter );
var_AddCallback( p_filter, CFG_PREFIX "Brightness",
AtmoSettingsCallback, p_filter );
var_AddCallback( p_filter, CFG_PREFIX "DarknessLimit",
AtmoSettingsCallback, p_filter );
var_AddCallback( p_filter, CFG_PREFIX "HueWinSize",
AtmoSettingsCallback, p_filter );
var_AddCallback( p_filter, CFG_PREFIX "SatWinSize",
AtmoSettingsCallback, p_filter );
var_AddCallback( p_filter, CFG_PREFIX "FrameDelay",
AtmoSettingsCallback, p_filter );
var_AddCallback( p_filter, CFG_PREFIX "whiteadj",
AtmoSettingsCallback, p_filter );
var_AddCallback( p_filter, CFG_PREFIX "white-red",
AtmoSettingsCallback, p_filter );
var_AddCallback( p_filter, CFG_PREFIX "white-green",
AtmoSettingsCallback, p_filter );
var_AddCallback( p_filter, CFG_PREFIX "white-blue",
AtmoSettingsCallback, p_filter );
}
static void DelAtmoSettingsVariablesCallbacks( filter_t *p_filter )
{
var_DelCallback( p_filter, CFG_PREFIX "filtermode",
AtmoSettingsCallback, p_filter );
var_DelCallback( p_filter, CFG_PREFIX "PercentNew",
AtmoSettingsCallback, p_filter );
var_DelCallback( p_filter, CFG_PREFIX "MeanLength",
AtmoSettingsCallback, p_filter );
var_DelCallback( p_filter, CFG_PREFIX "MeanThreshold",
AtmoSettingsCallback, p_filter );
var_DelCallback( p_filter, CFG_PREFIX "EdgeWeightning",
AtmoSettingsCallback, p_filter );
var_DelCallback( p_filter, CFG_PREFIX "Brightness",
AtmoSettingsCallback, p_filter );
var_DelCallback( p_filter, CFG_PREFIX "DarknessLimit",
AtmoSettingsCallback, p_filter );
var_DelCallback( p_filter, CFG_PREFIX "HueWinSize",
AtmoSettingsCallback, p_filter );
var_DelCallback( p_filter, CFG_PREFIX "SatWinSize",
AtmoSettingsCallback, p_filter );
var_DelCallback( p_filter, CFG_PREFIX "FrameDelay",
AtmoSettingsCallback, p_filter );
var_DelCallback( p_filter, CFG_PREFIX "whiteadj",
AtmoSettingsCallback, p_filter );
var_DelCallback( p_filter, CFG_PREFIX "white-red",
AtmoSettingsCallback, p_filter );
var_DelCallback( p_filter, CFG_PREFIX "white-green",
AtmoSettingsCallback, p_filter );
var_DelCallback( p_filter, CFG_PREFIX "white-blue",
AtmoSettingsCallback, p_filter );
}
#if defined(__ATMO_DEBUG__)
static void atmo_parse_crop(char *psz_cropconfig,
video_format_t fmt_in,
video_format_t fmt_render,
int &i_visible_width, int &i_visible_height,
int &i_x_offset, int &i_y_offset )
{
int64_t i_aspect_num, i_aspect_den;
unsigned int i_width, i_height;
i_visible_width = fmt_in.i_visible_width;
i_visible_height = fmt_in.i_visible_height;
i_x_offset = fmt_in.i_x_offset;
i_y_offset = fmt_in.i_y_offset;
char *psz_end = NULL, *psz_parser = strchr( psz_cropconfig, ':' );
if( psz_parser )
{
/* We're using the 3:4 syntax */
i_aspect_num = strtol( psz_cropconfig, &psz_end, 10 );
if( psz_end == psz_cropconfig || !i_aspect_num ) return;
i_aspect_den = strtol( ++psz_parser, &psz_end, 10 );
if( psz_end == psz_parser || !i_aspect_den ) return;
i_width = fmt_in.i_sar_den * fmt_render.i_visible_height *
i_aspect_num / i_aspect_den / fmt_in.i_sar_num;
i_height = fmt_render.i_visible_width*fmt_in.i_sar_num *
i_aspect_den / i_aspect_num / fmt_in.i_sar_den;
if( i_width < fmt_render.i_visible_width )
{
i_x_offset = fmt_render.i_x_offset +
(fmt_render.i_visible_width - i_width) / 2;
i_visible_width = i_width;
}
else
{
i_y_offset = fmt_render.i_y_offset +
(fmt_render.i_visible_height - i_height) / 2;
i_visible_height = i_height;
}
}
else
{
psz_parser = strchr( psz_cropconfig, 'x' );
if( psz_parser )
{
/* Maybe we're using the <width>x<height>+<left>+<top> syntax */
unsigned int i_crop_width, i_crop_height, i_crop_top, i_crop_left;
i_crop_width = strtol( psz_cropconfig, &psz_end, 10 );
if( psz_end != psz_parser ) return;
psz_parser = strchr( ++psz_end, '+' );
i_crop_height = strtol( psz_end, &psz_end, 10 );
if( psz_end != psz_parser ) return;
psz_parser = strchr( ++psz_end, '+' );
i_crop_left = strtol( psz_end, &psz_end, 10 );
if( psz_end != psz_parser ) return;
psz_end++;
i_crop_top = strtol( psz_end, &psz_end, 10 );
if( *psz_end != '\0' ) return;
i_width = i_crop_width;
i_visible_width = i_width;
i_height = i_crop_height;
i_visible_height = i_height;
i_x_offset = i_crop_left;
i_y_offset = i_crop_top;
}
else
{
/* Maybe we're using the <left>+<top>+<right>+<bottom> syntax */
unsigned int i_crop_top, i_crop_left, i_crop_bottom, i_crop_right;
psz_parser = strchr( psz_cropconfig, '+' );
i_crop_left = strtol( psz_cropconfig, &psz_end, 10 );
if( psz_end != psz_parser ) return;
psz_parser = strchr( ++psz_end, '+' );
i_crop_top = strtol( psz_end, &psz_end, 10 );
if( psz_end != psz_parser ) return;
psz_parser = strchr( ++psz_end, '+' );
i_crop_right = strtol( psz_end, &psz_end, 10 );
if( psz_end != psz_parser ) return;
psz_end++;
i_crop_bottom = strtol( psz_end, &psz_end, 10 );
if( *psz_end != '\0' ) return;
i_width = fmt_render.i_visible_width - i_crop_left - i_crop_right;
i_visible_width = i_width;
i_height = fmt_render.i_visible_height - i_crop_top - i_crop_bottom;
i_visible_height = i_height;
i_x_offset = i_crop_left;
i_y_offset = i_crop_top;
}
}
}
#endif
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