our current experimental Neutrino branch

git-svn-id: file:///home/bas/coolstream_public_svn/THIRDPARTY/applications/neutrino-experimental@27 e54a6e83-5905-42d5-8d5c-058d10e6a962
This commit is contained in:
mrcolor
2009-12-08 11:05:11 +00:00
commit bc5bd4154e
876 changed files with 193775 additions and 0 deletions

41
lib/libdvbsub/Debug.cpp Normal file
View File

@@ -0,0 +1,41 @@
#include <cstdio>
#include <cstdarg>
#include "Debug.hpp"
Debug::Debug() :
file_(""), level_(0), fp_(stdout)
{
}
Debug::~Debug()
{
if (fp_ && fp_ != stdout) {
fclose(fp_);
}
}
void Debug::set_level(int level)
{
level_ = level;
}
FILE* Debug::set_file(char* file)
{
FILE* fp = fopen(file, "a");
if (!fp) {
return NULL;
}
fp_ = fp;
return fp_;
}
void Debug::print(int level, const char *fmt, ...)
{
va_list argp;
va_start(argp, fmt);
// if (level < level_) {
vfprintf(fp_, fmt, argp);
// }
va_end(argp);
}

28
lib/libdvbsub/Debug.hpp Normal file
View File

@@ -0,0 +1,28 @@
#ifndef DEBUG_HPP_
#define DEBUG_HPP_
#include <cstdio>
class Debug {
public:
Debug();
~Debug();
void set_level(int level);
FILE* set_file(char* file);
void print(int level, const char *fmt, ...);
static const int ERROR = 0;
static const int INFO = 1;
static const int VERBOSE = 2;
private:
char* file_;
int level_;
FILE* fp_;
};
extern Debug sub_debug;
#endif

11
lib/libdvbsub/Makefile.am Normal file
View File

@@ -0,0 +1,11 @@
INCLUDES = \
-I$(top_srcdir)/src/zapit/include \
-I$(top_srcdir)/src \
-I$(top_srcdir)/lib/libcoolstream
AM_CPPFLAGS = -fno-rtti -fno-exceptions
noinst_LIBRARIES = libdvbsub.a
libdvbsub_a_SOURCES = dvbsub.cpp dvbsubtitle.cpp \
tools.cpp osd.cpp PacketQueue.cpp helpers.cpp Debug.cpp

View File

@@ -0,0 +1,47 @@
#include <cstdlib>
#include <pthread.h>
#include <list>
#include "Debug.hpp"
#include "PacketQueue.hpp"
PacketQueue::PacketQueue()
{
pthread_mutex_init(&mutex, NULL);
}
PacketQueue::~PacketQueue()
{
while (queue.begin() != queue.end()) {
delete[] queue.front();
queue.pop_front();
}
}
void PacketQueue::push(uint8_t* data)
{
pthread_mutex_lock(&mutex);
queue.push_back(data);
pthread_mutex_unlock(&mutex);
}
uint8_t* PacketQueue::pop()
{
uint8_t* retval;
pthread_mutex_lock(&mutex);
retval = queue.front();
queue.pop_front();
pthread_mutex_unlock(&mutex);
return retval;
}
size_t PacketQueue::size()
{
return queue.size();
}

View File

@@ -0,0 +1,20 @@
#ifndef PACKET_QUEUE_H_
#define PACKET_QUEUE_H_
#include <inttypes.h>
#include <pthread.h>
#include <list>
class PacketQueue {
public:
PacketQueue();
~PacketQueue();
void push(uint8_t* data);
uint8_t* pop();
size_t size();
private:
std::list<uint8_t*> queue;
pthread_mutex_t mutex;
};
#endif

369
lib/libdvbsub/dvbsub.cpp Normal file
View File

@@ -0,0 +1,369 @@
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <inttypes.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/time.h>
#include <cerrno>
#include <dmx_cs.h>
#include "Debug.hpp"
#include "PacketQueue.hpp"
#include "semaphore.h"
#include "reader_thread.hpp"
#include "dvbsub_thread.hpp"
#include "helpers.hpp"
#include "dvbsubtitle.h"
#define Log2File printf
#define RECVBUFFER_STEPSIZE 1024
enum {NOERROR, NETWORK, DENIED, NOSERVICE, BOXTYPE, THREAD, ABOUT};
enum {GET_VOLUME, SET_VOLUME, SET_MUTE, SET_CHANNEL};
Debug sub_debug;
static PacketQueue packet_queue;
//sem_t event_semaphore;
static pthread_t threadReader;
static pthread_t threadDvbsub;
static pthread_cond_t readerCond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t readerMutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t packetCond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t packetMutex = PTHREAD_MUTEX_INITIALIZER;
static int reader_running;
static int dvbsub_running;
static int dvbsub_paused = true;
static int dvbsub_pid;
static int dvbsub_stopped;
cDvbSubtitleConverter *dvbSubtitleConverter;
int dvbsub_init() {
int trc;
sub_debug.set_level(42);
reader_running = true;
// reader-Thread starten
trc = pthread_create(&threadReader, 0, reader_thread, (void *) NULL);
if (trc) {
fprintf(stderr, "[dvb-sub] failed to create reader-thread (rc=%d)\n", trc);
reader_running = false;
return -1;
}
dvbsub_running = true;
// subtitle decoder-Thread starten
trc = pthread_create(&threadDvbsub, 0, dvbsub_thread, NULL);
if (trc) {
fprintf(stderr, "[dvb-sub] failed to create dvbsub-thread (rc=%d)\n", trc);
dvbsub_running = false;
return -1;
}
return(0);
}
int dvbsub_pause()
{
if(reader_running) {
if(dvbSubtitleConverter) {
dvbSubtitleConverter->Pause(true);
}
dvbsub_paused = true;
printf("[dvb-sub] paused\n");
}
return 0;
}
int dvbsub_start(int pid)
{
if(!dvbsub_paused && (pid == 0)) {
return 0;
}
if(pid) {
if(pid != dvbsub_pid)
dvbsub_pause();
dvbsub_pid = pid;
}
while(!dvbsub_stopped)
usleep(10);
if(dvbsub_pid > 0) {
dvbsub_paused = false;
dvbSubtitleConverter->Pause(false);
pthread_mutex_lock(&readerMutex);
pthread_cond_broadcast(&readerCond);
pthread_mutex_unlock(&readerMutex);
printf("[dvb-sub] started with pid 0x%x\n", pid);
}
return 0;
}
int dvbsub_stop()
{
dvbsub_pid = 0;
if(reader_running) {
dvbsub_pause();
}
return 0;
}
int dvbsub_getpid()
{
return dvbsub_pid;
}
int dvbsub_close()
{
if(threadReader) {
dvbsub_pause();
reader_running = false;
pthread_mutex_lock(&readerMutex);
pthread_cond_broadcast(&readerCond);
pthread_mutex_unlock(&readerMutex);
pthread_join(threadReader, NULL);
threadReader = NULL;
}
if(threadDvbsub) {
dvbsub_running = false;
pthread_join(threadDvbsub, NULL);
threadDvbsub = NULL;
}
printf("[dvb-sub] stopped\n");
return 0;
}
static cDemux * dmx;
void* reader_thread(void *arg)
{
uint8_t tmp[16]; /* actually 6 should be enough */
int count;
int len;
uint16_t packlen;
uint8_t* buf;
dmx = new cDemux(0);
dmx->Open(DMX_PES_CHANNEL, NULL, 64*1024);
while (reader_running) {
if(dvbsub_paused) {
sub_debug.print(Debug::VERBOSE, "%s stopped\n", __FUNCTION__);
dmx->Stop();
dvbsub_stopped = 1;
pthread_mutex_lock(&readerMutex );
int ret = pthread_cond_wait(&readerCond, &readerMutex);
pthread_mutex_unlock(&readerMutex);
if (ret) {
sub_debug.print(Debug::VERBOSE, "pthread_cond_timedwait fails with %d\n", ret);
}
if(reader_running) {
dmx->pesFilter(dvbsub_pid);
dmx->Start();
sub_debug.print(Debug::VERBOSE, "%s started: pid 0x%x\n", __FUNCTION__, dvbsub_pid);
dvbsub_stopped = 0;
} else
break;
}
/* Wait for pes sync */
len = 0;
count = 0;
int tosync = 0;
while (!dvbsub_paused) {
//len = read(fd, &tmp[count], 3-count);
len = dmx->Read(&tmp[count], 3-count, 1000);
//printf("reader: fd = %d, len = %d\n", fd, len);
if(len <= 0)
continue;
else if (len == (3-count)) {
if ( (tmp[0] == 0x00) &&
(tmp[1] == 0x00) &&
(tmp[2] == 0x01)) {
count = 3;
break;
}
tosync += len;
} else {
count += len;
tosync += len;
continue;
}
tmp[0] = tmp[1];
tmp[1] = tmp[2];
count = 2;
} // while (!dvbsub_paused)
if(tosync)
printf("[subtitles] sync after %d bytes\n", tosync);
/* read stream id & length */
while ((count < 6) && !dvbsub_paused) {
//printf("try to read 6-count = %d\n", 6-count);
//len = read(fd, &tmp[count], 6-count);
len = dmx->Read(&tmp[count], 6-count, 1000);
if (len < 0) {
continue;
} else {
count += len;
}
}
packlen = getbits(tmp, 4*8, 16) + 6;
buf = new uint8_t[packlen];
/* TODO: Throws an exception on out of memory */
/* copy tmp[0..5] => buf[0..5] */
*(uint32_t*)buf = *(uint32_t*)tmp;
((uint16_t*)buf)[2] = ((uint16_t*)tmp)[2];
/* read rest of the packet */
while((count < packlen) && !dvbsub_paused) {
//len = read(fd, buf+count, packlen-count);
len = dmx->Read(buf+count, packlen-count, 1000);
if (len < 0) {
continue;
} else {
count += len;
}
}
if(!dvbsub_paused) {
printf("[subtitles] adding packet, len %d\n", count);
/* Packet now in memory */
packet_queue.push(buf);
/* TODO: allocation exception */
// wake up dvb thread
pthread_mutex_lock(&packetMutex);
pthread_cond_broadcast(&packetCond);
pthread_mutex_unlock(&packetMutex);
} else {
delete[] buf;
buf=NULL;
}
}
dmx->Stop();
delete dmx;
dmx = NULL;
sub_debug.print(Debug::VERBOSE, "%s shutdown\n", __FUNCTION__);
pthread_exit(NULL);
}
void* dvbsub_thread(void* arg)
{
struct timespec restartWait;
struct timeval now;
sub_debug.print(Debug::VERBOSE, "%s started\n", __FUNCTION__);
if (!dvbSubtitleConverter)
dvbSubtitleConverter = new cDvbSubtitleConverter;
while(dvbsub_running) {
uint8_t* packet;
int64_t pts;
int pts_dts_flag;
int dataoffset;
int packlen;
gettimeofday(&now, NULL);
TIMEVAL_TO_TIMESPEC(&now, &restartWait);
restartWait.tv_sec += 1;
int ret = 0;
if(packet_queue.size() == 0) {
pthread_mutex_lock( &packetMutex );
ret = pthread_cond_timedwait( &packetCond, &packetMutex, &restartWait );
pthread_mutex_unlock( &packetMutex );
}
if (ret == ETIMEDOUT)
{
dvbSubtitleConverter->Action();
continue;
}
else if (ret == EINTR)
{
sub_debug.print(Debug::VERBOSE, "pthread_cond_timedwait fails with %s\n", strerror(errno));
}
sub_debug.print(Debug::VERBOSE, "\nPES: Wakeup, queue size %d\n", packet_queue.size());
if(dvbsub_paused) {
do {
packet = packet_queue.pop();
if(packet)
delete[] packet;
} while(packet);
continue;
}
packet = packet_queue.pop();
if (!packet) {
sub_debug.print(Debug::VERBOSE, "Error no packet found\n");
continue;
}
packlen = (packet[4] << 8 | packet[5]) + 6;
/* Get PTS */
pts_dts_flag = getbits(packet, 7*8, 2);
if ((pts_dts_flag == 2) || (pts_dts_flag == 3)) {
pts = (uint64_t)getbits(packet, 9*8+4, 3) << 30; /* PTS[32..30] */
pts |= getbits(packet, 10*8, 15) << 15; /* PTS[29..15] */
pts |= getbits(packet, 12*8, 15); /* PTS[14..0] */
} else {
pts = 0;
}
dataoffset = packet[8] + 8 + 1;
if (packet[dataoffset] != 0x20) {
sub_debug.print(Debug::VERBOSE, "Not a dvb subtitle packet, discard it (len %d)\n", packlen);
for(int i = 0; i < packlen; i++)
printf("%02X ", packet[i]);
printf("\n");
goto next_round;
}
sub_debug.print(Debug::VERBOSE, "PES packet: len %d PTS=%Ld (%02d:%02d:%02d.%d)\n",
packlen, pts, (int)(pts/324000000), (int)((pts/5400000)%60),
(int)((pts/90000)%60), (int)(pts%90000));
if (packlen <= dataoffset + 3) {
sub_debug.print(Debug::INFO, "Packet too short, discard\n");
goto next_round;
}
if (packet[dataoffset + 2] == 0x0f) {
dvbSubtitleConverter->Convert(&packet[dataoffset + 2],
packlen - (dataoffset + 2), pts);
} else {
sub_debug.print(Debug::INFO, "End_of_PES is missing\n");
}
dvbSubtitleConverter->Action();
next_round:
delete[] packet;
}
delete dvbSubtitleConverter;
sub_debug.print(Debug::VERBOSE, "%s shutdown\n", __FUNCTION__);
pthread_exit(NULL);
}
void dvbsub_get_stc(int64_t * STC)
{
if(dmx)
dmx->getSTC(STC);
}

View File

@@ -0,0 +1,8 @@
#ifndef DVBSUB_THREAD_HPP_
#define DVBSUB_THREAD_HPP_
#include <inttypes.h>
void* dvbsub_thread(void* arg);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,51 @@
/*
* dvbsubtitle.h: DVB subtitles
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* Original author: Marco Schl<68><6C>ler <marco@lordzodiac.de>
*
* $Id: dvbsubtitle.h,v 1.1 2009/02/23 19:46:44 rhabarber1848 Exp $
*/
#ifndef __DVBSUBTITLE_H
#define __DVBSUBTITLE_H
#include "osd.h"
#include "tools.h"
class cDvbSubtitlePage;
class cDvbSubtitleAssembler; // for legacy PES recordings
class cDvbSubtitleBitmaps;
class cDvbSubtitleConverter /*: public cThread */{
private:
static int setupLevel;
cDvbSubtitleAssembler *dvbSubtitleAssembler;
// cOsd *osd;
cList<cDvbSubtitlePage> *pages;
cList<cDvbSubtitleBitmaps> *bitmaps;
tColor yuv2rgb(int Y, int Cb, int Cr);
bool AssertOsd(void);
int ExtractSegment(const uchar *Data, int Length, int64_t Pts);
void FinishPage(cDvbSubtitlePage *Page);
bool running;
pthread_mutex_t mutex;
public:
cDvbSubtitleConverter(void);
virtual ~cDvbSubtitleConverter();
void Action(void);
void Reset(void);
void Clear(void);
void Pause(bool pause);
void Lock();
void Unlock();
int ConvertFragments(const uchar *Data, int Length, int64_t pts); // for legacy PES recordings
int Convert(const uchar *Data, int Length, int64_t pts);
static void SetupChanged(void);
bool Running() { return running; };
};
#endif //__DVBSUBTITLE_H

50
lib/libdvbsub/helpers.cpp Normal file
View File

@@ -0,0 +1,50 @@
#include <inttypes.h>
#include "helpers.hpp"
/* Max 24 bit */
uint32_t getbits(const uint8_t* buf, uint32_t offset, uint8_t len)
{
const uint8_t* a = buf + (offset / 8);
uint32_t retval = 0;
uint32_t mask = 1;
retval = ((*(a)<<8) | *(a+1));
mask <<= len;
if (len > 8) {
retval <<= 8;
retval |= *(a+2);
len -= 8;
}
if (len > 8) {
retval <<= 8;
retval |= *(a+3);
len -= 8;
}
if (len > 8) {
unsigned long long tmp = retval << 8;
tmp |= *(a+4);
tmp >>= ((8-(offset%8)) + (8-(len)));
return tmp & (mask -1);
}
retval >>= ((8-(offset%8)) + (8-len));
return retval & (mask -1);
}
#if 0
void hexdump(uint8_t* buf)
{
int i;
for (i = 0 ; i < 16 ; i++) {
debug.print(Debug::DEBUG, "%02x ", buf[i]);
}
debug.print(Debug::DEBUG, "\n");
for (i = 16 ; i < 32 ; i++) {
debug.print(Debug::DEBUG, "%02x ", buf[i]);
}
debug.print(Debug::DEBUG, "\n");
}
#endif

14
lib/libdvbsub/helpers.hpp Normal file
View File

@@ -0,0 +1,14 @@
#ifndef HELPERS_H_
#define HELPERS_H_
#include <inttypes.h>
uint32_t getbits(const uint8_t* buf, uint32_t offset, uint8_t len);
void hexdump(uint8_t* buf);
#define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif

287
lib/libdvbsub/osd.cpp Normal file
View File

@@ -0,0 +1,287 @@
/*
* osd.c: Abstract On Screen Display layer
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: osd.cpp,v 1.1 2009/02/23 19:46:44 rhabarber1848 Exp $
*/
#include "dvbsubtitle.h"
//#include "device.h"
#define PAGE_COMPOSITION_SEGMENT 0x10
#define REGION_COMPOSITION_SEGMENT 0x11
#define CLUT_DEFINITION_SEGMENT 0x12
#define OBJECT_DATA_SEGMENT 0x13
#define END_OF_DISPLAY_SET_SEGMENT 0x80
// --- cPalette --------------------------------------------------------------
cPalette::cPalette(int Bpp)
{
SetBpp(Bpp);
SetAntiAliasGranularity(10, 10);
}
void cPalette::SetAntiAliasGranularity(uint FixedColors, uint BlendColors)
{
if (FixedColors >= MAXNUMCOLORS || BlendColors == 0)
antiAliasGranularity = MAXNUMCOLORS - 1;
else {
int ColorsForBlending = MAXNUMCOLORS - FixedColors;
int ColorsPerBlend = ColorsForBlending / BlendColors + 2; // +2 = the full foreground and background colors, which are amoung the fixed colors
antiAliasGranularity = double(MAXNUMCOLORS - 1) / (ColorsPerBlend - 1);
}
}
void cPalette::Reset(void)
{
numColors = 0;
modified = false;
}
int cPalette::Index(tColor Color)
{
// Check if color is already defined:
for (int i = 0; i < numColors; i++) {
if (color[i] == Color)
return i;
}
// No exact color, try a close one:
int i = ClosestColor(Color, 4);
if (i >= 0)
return i;
// No close one, try to define a new one:
if (numColors < maxColors) {
color[numColors++] = Color;
modified = true;
return numColors - 1;
}
// Out of colors, so any close color must do:
return ClosestColor(Color);
}
void cPalette::SetBpp(int Bpp)
{
bpp = Bpp;
maxColors = 1 << bpp;
Reset();
}
void cPalette::SetColor(int Index, tColor Color)
{
if (Index < maxColors) {
if (numColors <= Index) {
numColors = Index + 1;
modified = true;
}
else
modified |= color[Index] != Color;
color[Index] = Color;
}
}
const tColor *cPalette::Colors(int &NumColors) const
{
NumColors = numColors;
return numColors ? color : NULL;
}
void cPalette::Take(const cPalette &Palette, tIndexes *Indexes, tColor ColorFg, tColor ColorBg)
{
for (int i = 0; i < Palette.numColors; i++) {
tColor Color = Palette.color[i];
if (ColorFg || ColorBg) {
switch (i) {
case 0: Color = ColorBg; break;
case 1: Color = ColorFg; break;
}
}
int n = Index(Color);
if (Indexes)
(*Indexes)[i] = n;
}
}
void cPalette::Replace(const cPalette &Palette)
{
for (int i = 0; i < Palette.numColors; i++)
SetColor(i, Palette.color[i]);
numColors = Palette.numColors;
antiAliasGranularity = Palette.antiAliasGranularity;
}
tColor cPalette::Blend(tColor ColorFg, tColor ColorBg, uint8_t Level) const
{
if (antiAliasGranularity > 0)
Level = uint8_t(int(Level / antiAliasGranularity + 0.5) * antiAliasGranularity);
int Af = (ColorFg & 0xFF000000) >> 24;
int Rf = (ColorFg & 0x00FF0000) >> 16;
int Gf = (ColorFg & 0x0000FF00) >> 8;
int Bf = (ColorFg & 0x000000FF);
int Ab = (ColorBg & 0xFF000000) >> 24;
int Rb = (ColorBg & 0x00FF0000) >> 16;
int Gb = (ColorBg & 0x0000FF00) >> 8;
int Bb = (ColorBg & 0x000000FF);
int A = (Ab + (Af - Ab) * Level / 0xFF) & 0xFF;
int R = (Rb + (Rf - Rb) * Level / 0xFF) & 0xFF;
int G = (Gb + (Gf - Gb) * Level / 0xFF) & 0xFF;
int B = (Bb + (Bf - Bb) * Level / 0xFF) & 0xFF;
return (A << 24) | (R << 16) | (G << 8) | B;
}
int cPalette::ClosestColor(tColor Color, int MaxDiff) const
{
int n = 0;
int d = INT_MAX;
int A1 = (Color & 0xFF000000) >> 24;
int R1 = (Color & 0x00FF0000) >> 16;
int G1 = (Color & 0x0000FF00) >> 8;
int B1 = (Color & 0x000000FF);
for (int i = 0; i < numColors; i++) {
int A2 = (color[i] & 0xFF000000) >> 24;
int R2 = (color[i] & 0x00FF0000) >> 16;
int G2 = (color[i] & 0x0000FF00) >> 8;
int B2 = (color[i] & 0x000000FF);
int diff = (abs(A1 - A2) << 1) + (abs(R1 - R2) << 1) + (abs(G1 - G2) << 1) + (abs(B1 - B2) << 1);
if (diff < d) {
d = diff;
n = i;
}
}
return d <= MaxDiff ? n : -1;
}
cBitmap::cBitmap(int Width, int Height, int Bpp, int X0, int Y0)
:cPalette(Bpp)
{
bitmap = NULL;
x0 = X0;
y0 = Y0;
SetSize(Width, Height);
}
cBitmap::~cBitmap()
{
free(bitmap);
}
void cBitmap::SetIndex(int x, int y, tIndex Index)
{
if (bitmap) {
if (0 <= x && x < width && 0 <= y && y < height) {
if (bitmap[width * y + x] != Index) {
bitmap[width * y + x] = Index;
if (dirtyX1 > x) dirtyX1 = x;
if (dirtyY1 > y) dirtyY1 = y;
if (dirtyX2 < x) dirtyX2 = x;
if (dirtyY2 < y) dirtyY2 = y;
}
}
}
}
void cBitmap::SetSize(int Width, int Height)
{
if (bitmap && Width == width && Height == height)
return;
width = Width;
height = Height;
free(bitmap);
bitmap = NULL;
dirtyX1 = 0;
dirtyY1 = 0;
dirtyX2 = width - 1;
dirtyY2 = height - 1;
if (width > 0 && height > 0) {
bitmap = MALLOC(tIndex, width * height);
if (bitmap)
memset(bitmap, 0x00, width * height);
else
esyslog("ERROR: can't allocate bitmap!");
}
else
esyslog("ERROR: invalid bitmap parameters (%d, %d)!", width, height);
}
void cBitmap::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay)
{
if (bitmap && Bitmap.bitmap && Intersects(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1)) {
if (Covers(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1))
Reset();
x -= x0;
y -= y0;
if (ReplacePalette && Covers(x + x0, y + y0, x + x0 + Bitmap.Width() - 1, y + y0 + Bitmap.Height() - 1)) {
Replace(Bitmap);
for (int ix = 0; ix < Bitmap.width; ix++) {
for (int iy = 0; iy < Bitmap.height; iy++) {
if (!Overlay || Bitmap.bitmap[Bitmap.width * iy + ix] != 0)
SetIndex(x + ix, y + iy, Bitmap.bitmap[Bitmap.width * iy + ix]);
}
}
}
else {
tIndexes Indexes;
Take(Bitmap, &Indexes, ColorFg, ColorBg);
for (int ix = 0; ix < Bitmap.width; ix++) {
for (int iy = 0; iy < Bitmap.height; iy++) {
if (!Overlay || Bitmap.bitmap[Bitmap.width * iy + ix] != 0)
SetIndex(x + ix, y + iy, Indexes[int(Bitmap.bitmap[Bitmap.width * iy + ix])]);
}
}
}
}
}
bool cBitmap::Contains(int x, int y) const
{
x -= x0;
y -= y0;
return 0 <= x && x < width && 0 <= y && y < height;
}
bool cBitmap::Covers(int x1, int y1, int x2, int y2) const
{
x1 -= x0;
y1 -= y0;
x2 -= x0;
y2 -= y0;
return x1 <= 0 && y1 <= 0 && x2 >= width - 1 && y2 >= height - 1;
}
bool cBitmap::Intersects(int x1, int y1, int x2, int y2) const
{
x1 -= x0;
y1 -= y0;
x2 -= x0;
y2 -= y0;
return !(x2 < 0 || x1 >= width || y2 < 0 || y1 >= height);
}
bool cBitmap::Dirty(int &x1, int &y1, int &x2, int &y2)
{
if (dirtyX2 >= 0) {
x1 = dirtyX1;
y1 = dirtyY1;
x2 = dirtyX2;
y2 = dirtyY2;
return true;
}
return false;
}
void cBitmap::Clean(void)
{
dirtyX1 = width;
dirtyY1 = height;
dirtyX2 = -1;
dirtyY2 = -1;
}
const tIndex *cBitmap::Data(int x, int y)
{
return &bitmap[y * width + x];
}

147
lib/libdvbsub/osd.h Normal file
View File

@@ -0,0 +1,147 @@
/*
* osd.h: Abstract On Screen Display layer
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* Original author: Marco Schl<68><6C>ler <marco@lordzodiac.de>
*
* $Id: osd.h,v 1.1 2009/02/23 19:46:44 rhabarber1848 Exp $
*/
#ifndef __OSD_H
#define __OSD_H
#include "tools.h"
#include <limits.h>
#define MAXNUMCOLORS 256
typedef uint32_t tColor;
typedef unsigned char tIndex;
class cPalette {
private:
tColor color[MAXNUMCOLORS];
int bpp;
int maxColors, numColors;
bool modified;
double antiAliasGranularity;
protected:
typedef tIndex tIndexes[MAXNUMCOLORS];
public:
cPalette(int Bpp = 8);
///< Initializes the palette with the given color depth.
void SetAntiAliasGranularity(uint FixedColors, uint BlendColors);
///< Allows the system to optimize utilization of the limited color
///< palette entries when generating blended colors for anti-aliasing.
///< FixedColors is the maximum number of colors used, and BlendColors
///< is the maximum number of foreground/background color combinations
///< used with anti-aliasing. If this function is not called with
///< useful values, the palette may be filled up with many shades of
///< a single color combination, and may not be able to serve all
///< requested colors. By default the palette assumes there will be
///< 10 fixed colors and 10 color combinations.
int Bpp(void) const { return bpp; }
void Reset(void);
///< Resets the palette, making it contain no colors.
int Index(tColor Color);
///< Returns the index of the given Color (the first color has index 0).
///< If Color is not yet contained in this palette, it will be added if
///< there is a free slot. If the color can't be added to this palette,
///< the closest existing color will be returned.
tColor Color(int Index) const { return Index < maxColors ? color[Index] : 0; }
///< Returns the color at the given Index. If Index is outside the valid
///< range, 0 will be returned.
void SetBpp(int Bpp);
///< Sets the color depth of this palette to the given value.
///< The palette contents will be reset, so that it contains no colors.
void SetColor(int Index, tColor Color);
///< Sets the palette entry at Index to Color. If Index is larger than
///< the number of currently used entries in this palette, the entries
///< in between will have undefined values.
const tColor *Colors(int &NumColors) const;
///< Returns a pointer to the complete color table and stores the
///< number of valid entries in NumColors. If no colors have been
///< stored yet, NumColors will be set to 0 and the function will
///< return NULL.
void Take(const cPalette &Palette, tIndexes *Indexes = NULL, tColor ColorFg = 0, tColor ColorBg = 0);
///< Takes the colors from the given Palette and adds them to this palette,
///< using existing entries if possible. If Indexes is given, it will be
///< filled with the index values that each color of Palette has in this
///< palette. If either of ColorFg or ColorBg is not zero, the first color
///< in Palette will be taken as ColorBg, and the second color will become
///< ColorFg.
void Replace(const cPalette &Palette);
///< Replaces the colors of this palette with the colors from the given
///< palette.
tColor Blend(tColor ColorFg, tColor ColorBg, uint8_t Level) const;
///< Determines a color that consists of a linear blend between ColorFg
///< and ColorBg. If Level is 0, the result is ColorBg, if it is 255,
///< the result is ColorFg. If SetAntiAliasGranularity() has been called previously,
///< Level will be mapped to a limited range of levels that allow to make best
///< use of the palette entries.
int ClosestColor(tColor Color, int MaxDiff = INT_MAX) const;
///< Returns the index of a color in this palette that is closest to the given
///< Color. MaxDiff can be used to control the maximum allowed color difference.
///< If no color with a maximum difference of MaxDiff can be found, -1 will
///< be returned. With the default value of INT_MAX, there will always be
///< a valid color index returned, but the color may be completely different.
};
class cBitmap : public cPalette {
private:
tIndex *bitmap;
int x0, y0;
int width, height;
int dirtyX1, dirtyY1, dirtyX2, dirtyY2;
public:
cBitmap(int Width, int Height, int Bpp, int X0 = 0, int Y0 = 0);
///< Creates a bitmap with the given Width, Height and color depth (Bpp).
///< X0 and Y0 define the offset at which this bitmap will be located on the OSD.
///< All coordinates given in the other functions will be relative to
///< this offset (unless specified otherwise).
cBitmap(const char *FileName);
///< Creates a bitmap and loads an XPM image from the given file.
virtual ~cBitmap();
int X0(void) const { return x0; }
int Y0(void) const { return y0; }
int Width(void) const { return width; }
int Height(void) const { return height; }
void SetSize(int Width, int Height);
///< Sets the size of this bitmap to the given values. Any previous
///< contents of the bitmap will be lost. If Width and Height are the same
///< as the current values, nothing will happen and the bitmap remains
///< unchanged.
void SetIndex(int x, int y, tIndex Index);
///< Sets the index at the given coordinates to Index.
///< Coordinates are relative to the bitmap's origin.
void DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg = 0, tColor ColorBg = 0, bool ReplacePalette = false, bool Overlay = false);
///< Sets the pixels in this bitmap with the data from the given
///< Bitmap, putting the upper left corner of the Bitmap at (x, y).
///< If ColorFg or ColorBg is given, the first palette entry of the Bitmap
///< will be mapped to ColorBg and the second palette entry will be mapped to
///< ColorFg (palette indexes are defined so that 0 is the background and
///< 1 is the foreground color). ReplacePalette controls whether the target
///< area shall have its palette replaced with the one from Bitmap.
///< If Overlay is true, any pixel in Bitmap that has color index 0 will
///< not overwrite the corresponding pixel in the target area.
const tIndex *Data(int x, int y);
///< Returns the address of the index byte at the given coordinates.
bool Contains(int x, int y) const;
bool Covers(int x1, int y1, int x2, int y2) const;
bool Intersects(int x1, int y1, int x2, int y2) const;
bool Dirty(int &x1, int &y1, int &x2, int &y2);
void Clean(void);
};
struct tArea {
int x1, y1, x2, y2;
int bpp;
int Width(void) const { return x2 - x1 + 1; }
int Height(void) const { return y2 - y1 + 1; }
bool Intersects(const tArea &Area) const { return !(x2 < Area.x1 || x1 > Area.x2 || y2 < Area.y1 || y1 > Area.y2); }
};
#endif //__OSD_H

View File

@@ -0,0 +1,6 @@
#ifndef READER_THREAD_HPP_
#define READER_THREAD_HPP_
void* reader_thread(void *arg);
#endif

267
lib/libdvbsub/tools.cpp Normal file
View File

@@ -0,0 +1,267 @@
/*
* tools.c: Various tools
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* vdr: Id: tools.c 2.0 2008/03/05 17:23:47 kls Exp
*/
#include "tools.h"
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/vfs.h>
#include <time.h>
#include <unistd.h>
#include <utime.h>
int SysLogLevel = 3;
#define MAXSYSLOGBUF 256
// --- cTimeMs ---------------------------------------------------------------
cTimeMs::cTimeMs(int Ms)
{
Set(Ms);
}
uint64_t cTimeMs::Now(void)
{
#if 0 && _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK)
#define MIN_RESOLUTION 5 // ms
static bool initialized = false;
static bool monotonic = false;
struct timespec tp;
if (!initialized) {
// check if monotonic timer is available and provides enough accurate resolution:
if (clock_getres(CLOCK_MONOTONIC, &tp) == 0) {
long Resolution = tp.tv_nsec;
// require a minimum resolution:
if (tp.tv_sec == 0 && tp.tv_nsec <= MIN_RESOLUTION * 1000000) {
if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
dsyslog("cTimeMs: using monotonic clock (resolution is %ld ns)", Resolution);
monotonic = true;
}
else
esyslog("cTimeMs: clock_gettime(CLOCK_MONOTONIC) failed");
}
else
dsyslog("cTimeMs: not using monotonic clock - resolution is too bad (%ld s %ld ns)", tp.tv_sec, tp.tv_nsec);
}
else
esyslog("cTimeMs: clock_getres(CLOCK_MONOTONIC) failed");
initialized = true;
}
if (monotonic) {
if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
return (uint64_t(tp.tv_sec)) * 1000 + tp.tv_nsec / 1000000;
esyslog("cTimeMs: clock_gettime(CLOCK_MONOTONIC) failed");
monotonic = false;
// fall back to gettimeofday()
}
#else
# warning Posix monotonic clock not available
#endif
struct timeval t;
if (gettimeofday(&t, NULL) == 0)
return (uint64_t(t.tv_sec)) * 1000 + t.tv_usec / 1000;
return 0;
}
void cTimeMs::Set(int Ms)
{
begin = Now() + Ms;
}
bool cTimeMs::TimedOut(void)
{
return Now() >= begin;
}
uint64_t cTimeMs::Elapsed(void)
{
return Now() - begin;
}
// --- cListObject -----------------------------------------------------------
cListObject::cListObject(void)
{
prev = next = NULL;
}
cListObject::~cListObject()
{
}
void cListObject::Append(cListObject *Object)
{
next = Object;
Object->prev = this;
}
void cListObject::Insert(cListObject *Object)
{
prev = Object;
Object->next = this;
}
void cListObject::Unlink(void)
{
if (next)
next->prev = prev;
if (prev)
prev->next = next;
next = prev = NULL;
}
int cListObject::Index(void) const
{
cListObject *p = prev;
int i = 0;
while (p) {
i++;
p = p->prev;
}
return i;
}
// --- cListBase -------------------------------------------------------------
cListBase::cListBase(void)
{
objects = lastObject = NULL;
count = 0;
}
cListBase::~cListBase()
{
Clear();
}
void cListBase::Add(cListObject *Object, cListObject *After)
{
if (After && After != lastObject) {
After->Next()->Insert(Object);
After->Append(Object);
}
else {
if (lastObject)
lastObject->Append(Object);
else
objects = Object;
lastObject = Object;
}
count++;
}
void cListBase::Ins(cListObject *Object, cListObject *Before)
{
if (Before && Before != objects) {
Before->Prev()->Append(Object);
Before->Insert(Object);
}
else {
if (objects)
objects->Insert(Object);
else
lastObject = Object;
objects = Object;
}
count++;
}
void cListBase::Del(cListObject *Object, bool DeleteObject)
{
if (Object == objects)
objects = Object->Next();
if (Object == lastObject)
lastObject = Object->Prev();
Object->Unlink();
if (DeleteObject) {
delete Object;
count--;
}
}
void cListBase::Move(int From, int To)
{
Move(Get(From), Get(To));
}
void cListBase::Move(cListObject *From, cListObject *To)
{
if (From && To) {
if (From->Index() < To->Index())
To = To->Next();
if (From == objects)
objects = From->Next();
if (From == lastObject)
lastObject = From->Prev();
From->Unlink();
if (To) {
if (To->Prev())
To->Prev()->Append(From);
From->Append(To);
}
else {
lastObject->Append(From);
lastObject = From;
}
if (!From->Prev())
objects = From;
}
}
void cListBase::Clear(void)
{
while (objects) {
cListObject *object = objects->Next();
delete objects;
objects = object;
}
objects = lastObject = NULL;
count = 0;
}
cListObject *cListBase::Get(int Index) const
{
if (Index < 0)
return NULL;
cListObject *object = objects;
while (object && Index-- > 0)
object = object->Next();
return object;
}
static int CompareListObjects(const void *a, const void *b)
{
const cListObject *la = *(const cListObject **)a;
const cListObject *lb = *(const cListObject **)b;
return la->Compare(*lb);
}
void cListBase::Sort(void)
{
int n = Count();
cListObject *a[n];
cListObject *object = objects;
int i = 0;
while (object && i < n) {
a[i++] = object;
object = object->Next();
}
qsort(a, n, sizeof(cListObject *), CompareListObjects);
objects = lastObject = NULL;
for (i = 0; i < n; i++) {
a[i]->Unlink();
count--;
Add(a[i]);
}
}

193
lib/libdvbsub/tools.h Normal file
View File

@@ -0,0 +1,193 @@
/*
* tools.h: Various tools
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: tools.h,v 1.1 2009/02/23 19:46:44 rhabarber1848 Exp $
*/
#ifndef __TOOLS_H
#define __TOOLS_H
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <iconv.h>
#include <poll.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <sys/stat.h>
#include <sys/types.h>
typedef unsigned char uchar;
extern int SysLogLevel;
#if 0
#define esyslog(a...) void( (SysLogLevel > 0) ? syslog_with_tid(LOG_ERR, a) : void() )
#define isyslog(a...) void( (SysLogLevel > 1) ? syslog_with_tid(LOG_ERR, a) : void() )
#define dsyslog(a...) void( (SysLogLevel > 2) ? syslog_with_tid(LOG_ERR, a) : void() )
#else
#define esyslog printf
#define isyslog printf
#define dsyslog printf
#endif
#define LOG_ERROR esyslog("ERROR (%s,%d): %m", __FILE__, __LINE__)
#define LOG_ERROR_STR(s) esyslog("ERROR: %s: %m", s)
#define SECSINDAY 86400
#define KILOBYTE(n) ((n) * 1024)
#define MEGABYTE(n) ((n) * 1024 * 1024)
#define MALLOC(type, size) (type *)malloc(sizeof(type) * (size))
#define DELETENULL(p) (delete (p), p = NULL)
#define CHECK(s) { if ((s) < 0) LOG_ERROR; } // used for 'ioctl()' calls
#define FATALERRNO (errno && errno != EAGAIN && errno != EINTR)
#ifndef __STL_CONFIG_H // in case some plugin needs to use the STL
template<class T> inline T min(T a, T b) { return a <= b ? a : b; }
template<class T> inline T max(T a, T b) { return a >= b ? a : b; }
template<class T> inline int sgn(T a) { return a < 0 ? -1 : a > 0 ? 1 : 0; }
template<class T> inline void swap(T &a, T &b) { T t = a; a = b; b = t; }
#endif
class cTimeMs {
private:
uint64_t begin;
public:
cTimeMs(int Ms = 0);
///< Creates a timer with ms resolution and an initial timeout of Ms.
static uint64_t Now(void);
void Set(int Ms = 0);
bool TimedOut(void);
uint64_t Elapsed(void);
};
class cListObject {
private:
cListObject *prev, *next;
public:
cListObject(void);
virtual ~cListObject();
virtual int Compare(const cListObject &ListObject) const { return 0; }
///< Must return 0 if this object is equal to ListObject, a positive value
///< if it is "greater", and a negative value if it is "smaller".
void Append(cListObject *Object);
void Insert(cListObject *Object);
void Unlink(void);
int Index(void) const;
cListObject *Prev(void) const { return prev; }
cListObject *Next(void) const { return next; }
};
class cListBase {
protected:
cListObject *objects, *lastObject;
cListBase(void);
int count;
public:
virtual ~cListBase();
void Add(cListObject *Object, cListObject *After = NULL);
void Ins(cListObject *Object, cListObject *Before = NULL);
void Del(cListObject *Object, bool DeleteObject = true);
virtual void Move(int From, int To);
void Move(cListObject *From, cListObject *To);
virtual void Clear(void);
cListObject *Get(int Index) const;
int Count(void) const { return count; }
void Sort(void);
};
template<class T> class cList : public cListBase {
public:
T *Get(int Index) const { return (T *)cListBase::Get(Index); }
T *First(void) const { return (T *)objects; }
T *Last(void) const { return (T *)lastObject; }
T *Prev(const T *object) const { return (T *)object->cListObject::Prev(); } // need to call cListObject's members to
T *Next(const T *object) const { return (T *)object->cListObject::Next(); } // avoid ambiguities in case of a "list of lists"
};
template<class T> class cVector {
private:
mutable int allocated;
mutable int size;
mutable T *data;
cVector(const cVector &Vector) {} // don't copy...
cVector &operator=(const cVector &Vector) { return *this; } // ...or assign this!
void Realloc(int Index) const
{
if (++Index > allocated) {
data = (T *)realloc(data, Index * sizeof(T));
for (int i = allocated; i < Index; i++)
data[i] = T(0);
allocated = Index;
}
}
public:
cVector(int Allocated = 10)
{
allocated = 0;
size = 0;
data = NULL;
Realloc(Allocated);
}
virtual ~cVector() { free(data); }
T& At(int Index) const
{
Realloc(Index);
if (Index >= size)
size = Index + 1;
return data[Index];
}
const T& operator[](int Index) const
{
return At(Index);
}
T& operator[](int Index)
{
return At(Index);
}
int Size(void) const { return size; }
virtual void Insert(T Data, int Before = 0)
{
if (Before < size) {
Realloc(size);
memmove(&data[Before + 1], &data[Before], (size - Before) * sizeof(T));
size++;
data[Before] = Data;
}
else
Append(Data);
}
virtual void Append(T Data)
{
if (size >= allocated)
Realloc(allocated * 4 / 2); // increase size by 50%
data[size++] = Data;
}
virtual void Remove(int Index)
{
if (Index < size - 1)
memmove(&data[Index], &data[Index + 1], (size - Index) * sizeof(T));
size--;
}
virtual void Clear(void)
{
size = 0;
}
void Sort(__compar_fn_t Compare)
{
qsort(data, size, sizeof(T), Compare);
}
};
#endif //__TOOLS_H