/* * thread.c: The thread for the Atmolight-plugin * * See the README file for copyright information and how to reach the author. * * $Id$ */ #include #include #include #include #include "math.h" #include "defs.h" // filter class #include "filter.h" // input classes #include "input.h" #include "inputffdvb.h" #include "inputsoftdevice.h" // output classes #include "output.h" #include "outputserial.h" #include "outputnetwork.h" #include "setup.h" #include "thread.h" // seconds the next timer must be in the future to assume manual start #define MANUALSTART 600 //************************************************************************************************************ //*** cAtmoThread *** //************************************************************************************************************ cAtmoThread::cAtmoThread() { // input device switch (AtmoSetup.AtmoInput) { case ffdvb: Input = new cInputFFDVB(); break; case softdevice: Input = new cInputSoftdevice(); break; default: case no_input: Input = NULL; Skins.QueueMessage(mtInfo, tr("Atmolight: No input device given!")); break; } // filter Filter = new cAtmoFilter(); // output device switch (AtmoSetup.AtmoOutput) { case serial: Output = new cOutputSerial(); break; case network: Output = new cOutputNetwork(); break; default: case no_output: Output = NULL; Skins.QueueMessage(mtInfo, tr("Atmolight: No output device given!")); break; } } cAtmoThread::~cAtmoThread() { AtmoSetup.atmo_on = false; cCondWait::SleepMs(200); OutputColors(ColorPacket); // send all off if (Input) { Input->Close(); delete Input; Input = NULL; } delete Filter; Filter = NULL; if (Output) { Output->Close(); delete Output; Output = NULL; } } void cAtmoThread::SwitchOn(void) { if (false == AtmoSetup.atmo_on) { if (false == Input->Open(NULL)) { AtmoSetup.AtmoInput = no_input; Skins.QueueMessage(mtInfo, tr("Atmolight: Could not open input device!")); return; } if (false == Output->Open(AtmoSetup.output_arg)) { AtmoSetup.AtmoOutput = no_output; Skins.QueueMessage(mtInfo, tr("Atmolight: Could not open output device!")); return; } Filter->ResetFilter(); AtmoSetup.atmo_on = true; } } void cAtmoThread::SwitchOff(void) { if (true == AtmoSetup.atmo_on) { AtmoSetup.atmo_on = false; cCondWait::SleepMs(200); OutputColors(ColorPacket); // send all off Input->Close(); Output->Close(); } } void cAtmoThread::Action(void) { cTimeMs t; if ((NULL == Input) || (NULL == Output)) { return; } // input and output existing? cCondWait::SleepMs(1000); // wait 1000ms for loaded timers GetStartMode(); // manual or automatic start of vdr? while (Running()) { t.Set(0); if (AtmoSetup.atmo_on) { // get calculated color from input ColorPacket = Input->GetColorPacket(); // send to filter ColorPacket = Filter->Filtering(ColorPacket); // apply gamma ColorPacket = ApplyGamma(ColorPacket); // apply white calibration ColorPacket = WhiteCalibration(ColorPacket); // send to output device OutputColors(ColorPacket); } if (t.Elapsed() < 20) // ensure that the filter is called every 20ms { cCondWait::SleepMs(20 - t.Elapsed()); } } } // assumption of manual/automatic start of vdr void cAtmoThread::GetStartMode(void) { if (AtmoSetup.StartMode == 0) { SwitchOn(); } // on else if (AtmoSetup.StartMode == 1) { SwitchOff(); } // off else if (AtmoSetup.StartMode == 2) // timer dependent { time_t Now = time(NULL); cTimer *timer = Timers.GetNextActiveTimer(); time_t Next = timer ? timer->StartTime() : 0; time_t Delta = timer ? Next - Now : 0; if (!timer || Delta > MANUALSTART) { // Apparently the user started VDR manually SwitchOn(); } else { SwitchOff(); } } } // apply gamma-correction tColorPacket cAtmoThread::ApplyGamma(tColorPacket ColorPacket) { switch (AtmoSetup.Gamma_Mode) { case by_color: // gamma correction for each color { double GammaRed = (double)AtmoSetup.Gamma.r; double GammaGreen = (double)AtmoSetup.Gamma.g; double GammaBlue = (double)AtmoSetup.Gamma.b; for (int i = 0; i < 5; i++) { ColorPacket.channel[i].r = (unsigned char)(pow((double)ColorPacket.channel[i].r / 255.0f, GammaRed / 10.0f) * 255.0f); ColorPacket.channel[i].g = (unsigned char)(pow((double)ColorPacket.channel[i].g / 255.0f, GammaGreen / 10.0f) * 255.0f); ColorPacket.channel[i].b = (unsigned char)(pow((double)ColorPacket.channel[i].b / 255.0f, GammaBlue / 10.0f) * 255.0f); } } break; default: break; } return ColorPacket; } // apply white-calibration tColorPacket cAtmoThread::WhiteCalibration(tColorPacket ColorPacket) { for (int i = 0; i < 5; i++) { ColorPacket.channel[i].r = (unsigned char)((int)AtmoSetup.WhiteCalibration.r * (int)ColorPacket.channel[i].r / 255); ColorPacket.channel[i].g = (unsigned char)((int)AtmoSetup.WhiteCalibration.g * (int)ColorPacket.channel[i].g / 255); ColorPacket.channel[i].b = (unsigned char)((int)AtmoSetup.WhiteCalibration.b * (int)ColorPacket.channel[i].b / 255); } return ColorPacket; } // send filter-output to output-device void cAtmoThread::OutputColors(const tColorPacket ColorPacket) { tColorPacket col; static tColorPacket last_col; if (AtmoSetup.atmo_on) { switch (AtmoSetup.Mode) { case live_picture_hsv: // live mode col = ColorPacket; break; case default_color: // default color switch (AtmoSetup.DefaultColor) { case black: default: for (int i=0; i<5; i++) { col.channel[i].r = 0; // red (0-255) col.channel[i].g = 0; // green (0-255) col.channel[i].b = 0; // blue (0-255) } break; case white: for (int i=0; i<5; i++) { col.channel[i].r = 255; // red (0-255) col.channel[i].g = 255; // green (0-255) col.channel[i].b = 255; // blue (0-255) } break; case red: for (int i=0; i<5; i++) { col.channel[i].r = 255; // red (0-255) col.channel[i].g = 0; // green (0-255) col.channel[i].b = 0; // blue (0-255) } break; case green: for (int i=0; i<5; i++) { col.channel[i].r = 0; // red (0-255) col.channel[i].g = 255; // green (0-255) col.channel[i].b = 0; // blue (0-255) } break; case blue: for (int i=0; i<5; i++) { col.channel[i].r = 0; // red (0-255) col.channel[i].g = 0; // green (0-255) col.channel[i].b = 255; // blue (0-255) } break; case yellow: for (int i=0; i<5; i++) { col.channel[i].r = 255; // red (0-255) col.channel[i].g = 255; // green (0-255) col.channel[i].b = 0; // blue (0-255) } break; case cyan: for (int i=0; i<5; i++) { col.channel[i].r = 0; // red (0-255) col.channel[i].g = 255; // green (0-255) col.channel[i].b = 255; // blue (0-255) } break; case magenta: for (int i=0; i<5; i++) { col.channel[i].r = 255; // red (0-255) col.channel[i].g = 0; // green (0-255) col.channel[i].b = 255; // blue (0-255) } break; } break; case static_color: // static color col = AtmoSetup.StaticColor; break; } } else // (false == AtmoSetup.atmo_on) { col.channel[0].r = col.channel[0].g = col.channel[0].b = 0; col.channel[4] = col.channel[3] = col.channel[2] = col.channel[1] = col.channel[0]; } if (Output) { if (0 != memcmp(&last_col, &col, sizeof(last_col))) { Output->OutputColors(col); } memcpy(&last_col, &col, sizeof(last_col)); } }