--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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];
+
+}
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 Kanäle...
+#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
--- /dev/null
+/*
+ * 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
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+ }
+}
+
--- /dev/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
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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; // fĂ¼r comport-parameter
+ dcb.DCBlength = sizeof(DCB);
+ GetCommState (m_hComport, &dcb); // ger current serialport settings
+ dcb.BaudRate = 38400; // set speed
+ dcb.ByteSize = 8; // set databits
+ dcb.Parity = NOPARITY; // set parity
+ dcb.StopBits = ONESTOPBIT; // set one stop bit
+ SetCommState (m_hComport, &dcb); // apply settings
+
+#else
+
+ int bconst = B38400;
+# 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;
+}
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
+}
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+
+#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;
+}
+
+
--- /dev/null
+#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
--- /dev/null
+ 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.
--- /dev/null
+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
+
--- /dev/null
+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).
--- /dev/null
+/*****************************************************************************
+* 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