summaryrefslogtreecommitdiff
path: root/ambithread.c
diff options
context:
space:
mode:
Diffstat (limited to 'ambithread.c')
-rw-r--r--ambithread.c311
1 files changed, 311 insertions, 0 deletions
diff --git a/ambithread.c b/ambithread.c
new file mode 100644
index 0000000..3ee66e7
--- /dev/null
+++ b/ambithread.c
@@ -0,0 +1,311 @@
+/*
+ * ambithread.c
+ *
+ * Copyright (C) 2013 - Christian Völlinger
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <vdr/plugin.h>
+
+#include "softhdservice.h"
+#include "ambithread.h"
+#include "config.h"
+
+//***************************************************************************
+// Class cAmbiThread
+//***************************************************************************
+//***************************************************************************
+// Object
+//***************************************************************************
+
+cAmbiThread::cAmbiThread()
+{
+ loopActive = false;
+ image = 0;
+ imageSize = 0;
+ imageWidth = 0;
+ imageHeight = 0;
+ cineBarsHor = 0;
+ cineBarsVer = 0;
+}
+
+cAmbiThread::~cAmbiThread()
+{
+ bob.close();
+}
+
+//***************************************************************************
+// Stop Thread
+//***************************************************************************
+
+void cAmbiThread::Stop()
+{
+ loopActive = false;
+ waitCondition.Broadcast(); // wakeup the thread
+
+ Cancel(3); // wait up to 3 seconds for thread was stopping
+}
+
+//***************************************************************************
+// Action
+//***************************************************************************
+
+void cAmbiThread::Action()
+{
+ MsTime wait = 0;
+ cMutexLock lock(&mutex);
+
+ tell(0, "boblight Thread started (pid=%d)", getpid());
+
+ loopActive = true;
+ bob.open();
+
+ while (loopActive && Running())
+ {
+ MsTime start = msNow();
+
+ // work ...
+ if(bob.ping() == success) {
+
+ if(cfg.dirty > 0) {
+ cfg.dirty = 0;
+ bob.sendOptions();
+ }
+
+ if (cfg.viewMode == vmAtmo)
+ {
+ if (grabImage() == success)
+ {
+ detectCineBars();
+ putData();
+
+ MsTime elapsed = msNow() - start;
+ wait = 1000 / cfg.frequence - elapsed;
+ tell(3, "sleeping %ldms (%d Hz)", wait, cfg.frequence);
+ }
+ else
+ {
+ wait = 10000; // retry softhd grab every 10 seconds
+ }
+ }
+ else
+ {
+ putData();
+ wait = 500; // less load on fixed color or black
+ }
+ }
+ else { // Connection lost, reconnect
+ bob.close();
+ bob.open();
+ wait = 10000;
+ }
+
+ waitCondition.TimedWait(mutex, wait); // wait time in ms
+ }
+
+ bob.close();
+ loopActive = false;
+
+ tell(0, "boblight thread ended (pid=%d)", getpid());
+}
+
+//***************************************************************************
+// Grab Image
+//***************************************************************************
+
+int cAmbiThread::grabImage()
+{
+ SoftHDDevice_AtmoGrabService_v1_1_t req;
+
+ free(image);
+ image = 0;
+
+ cPlugin* softHdPlugin = cPluginManager::GetPlugin("softhddevice");
+ int softHdGrabService = (softHdPlugin && softHdPlugin->Service(ATMO1_GRAB_SERVICE, 0));
+
+ if (!softHdGrabService)
+ return error("Can't find softhddevice %s, aborting grab, retrying in 10 seconds!",
+ softHdPlugin ? "service" : "plugin");
+
+ // grab image at sofhddevice
+ req.width = -64; //warum? steht hier => http://projects.vdr-developer.org/projects/plg-softhddevice/repository/revisions/master/entry/video.c#L7372
+ req.height = 64;
+ req.img = 0;
+
+ if (!softHdPlugin->Service(ATMO1_GRAB_SERVICE, &req) || !req.img)
+ return fail;
+
+ tell(3, "Got image with %dx%d pixel; %d bytes", req.width, req.height, req.size);
+
+ image = (Pixel*)req.img;
+ imageSize = req.size;
+ imageWidth = req.width;
+ imageHeight = req.height;
+
+ return success;
+}
+
+//***************************************************************************
+// Detect Cine Bars
+//***************************************************************************
+
+int cAmbiThread::detectCineBars()
+{
+ const int threshold = 3; // threshold for black level of cine bars
+ Pixel* p;
+ int off;
+
+ // check horizontal bars
+
+ if (cfg.detectCineBars == cbHorizontal || cfg.detectCineBars == cbBoth)
+ {
+ for (off = 0; off < imageHeight/5; off++) // cinebar height max 1/5 of the screen height
+ {
+ int above = 0;
+
+ for (int x = 0; x < imageWidth; x++)
+ {
+ p = &image[off*imageWidth + x];
+
+ if (p->r > threshold || p->g > threshold || p->b > threshold)
+ above++;
+
+ p = &image[((imageHeight-1)-off)*imageWidth + x];
+
+ if (p->r > threshold || p->g > threshold || p->b > threshold)
+ above++;
+ }
+
+ if (above > imageWidth/8) // max 1/8 failed pixel
+ break;
+ }
+
+ if (cineBarsHor != off)
+ {
+ static int last = 0;
+ static int count = 0;
+
+ if (off != last)
+ {
+ last = off;
+ count = 0;
+ }
+
+ if (count++ >= cfg.frequence)
+ {
+ count = 0;
+ cineBarsHor = off;
+ tell(0, "Switch horizontal cine bars to %d", cineBarsHor);
+ }
+ }
+ }
+
+ // check vertical bars
+
+ if (cfg.detectCineBars == cbVertical || cfg.detectCineBars == cbBoth)
+ {
+ for (off = 0; off < imageWidth/5; off++) // cinebar height max 1/5 of the screen width
+ {
+ int above = 0;
+
+ for (int y = 0; y < imageHeight; y++)
+ {
+ p = &image[y*imageWidth + off];
+
+ if (p->r > threshold || p->g > threshold || p->b > threshold)
+ above++;
+
+ p = &image[y*imageWidth + ((imageWidth-1)-off)];
+
+ if (p->r > threshold || p->g > threshold || p->b > threshold)
+ above++;
+ }
+
+ if (above > imageHeight/6) // max 1/6 failed pixel
+ break;
+ }
+
+ if (cineBarsVer != off)
+ {
+ static int last = 0;
+ static int count = 0;
+
+ if (off != last)
+ {
+ last = off;
+ count = 0;
+ }
+
+ if (count++ >= cfg.frequence)
+ {
+ count = 0;
+
+ cineBarsVer = off;
+ tell(0, "Switch vertical cine bars to %d", cineBarsVer);
+ }
+ }
+ }
+
+ return done;
+}
+
+//***************************************************************************
+// Put Data
+//***************************************************************************
+
+int cAmbiThread::putData()
+{
+
+ if (cfg.viewMode == vmFixedCol)
+ {
+ int pFixedCol[3] = {cfg.fixedR, cfg.fixedG, cfg.fixedB};
+ bob.writePix(pFixedCol);
+ }
+ else if (cfg.viewMode == vmBlack) {
+ int pFixedCol[3] = {0,0,0};
+ bob.writePix(pFixedCol);
+ }
+ else if(cfg.viewMode == vmAtmo) {
+
+ int row = 0;
+ Pixel pixel = {0,0,0,0};
+ Pixel* p = &pixel;
+
+ for (int y = 0; y < imageHeight; y++) {
+ // skip horizontal cinebars
+ if(y < cineBarsHor) continue;
+ if(y > imageHeight - cineBarsHor) continue;
+
+ int rgb[3];
+ row = imageWidth * y;
+ for (int x = 0; x < imageWidth; x++) {
+ // skip vertical cinebars
+ if(x < cineBarsVer) continue;
+ if(x > imageWidth - cineBarsVer) continue;
+
+ p = &image[row + x];
+ rgb[0] = p->r;
+ rgb[1] = p->g;
+ rgb[2] = p->b;
+ bob.writeColor(rgb, x - cineBarsVer, y - cineBarsHor);
+ }
+ }
+ bob.setScanRange(imageWidth - (2*cineBarsVer), imageHeight - (2*cineBarsHor));
+ }
+
+ bob.send();
+
+ return success;
+}