mirror of
https://github.com/tuxbox-neutrino/neutrino.git
synced 2025-08-26 23:13:13 +02:00
Code cleanup, still testing
git-svn-id: file:///home/bas/coolstream_public_svn/THIRDPARTY/applications/neutrino-experimental@173 e54a6e83-5905-42d5-8d5c-058d10e6a962
This commit is contained in:
@@ -13,7 +13,6 @@
|
||||
#include "Debug.hpp"
|
||||
#include "PacketQueue.hpp"
|
||||
#include "semaphore.h"
|
||||
#include "reader_thread.hpp"
|
||||
#include "dvbsub_thread.hpp"
|
||||
#include "helpers.hpp"
|
||||
#include "dvbsubtitle.h"
|
||||
@@ -43,6 +42,8 @@ static int dvbsub_pid;
|
||||
static int dvbsub_stopped;
|
||||
|
||||
cDvbSubtitleConverter *dvbSubtitleConverter;
|
||||
void* reader_thread(void *arg);
|
||||
void* dvbsub_thread(void* arg);
|
||||
|
||||
int dvbsub_init() {
|
||||
int trc;
|
||||
@@ -215,61 +216,26 @@ void* reader_thread(void * /*arg*/)
|
||||
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;
|
||||
}
|
||||
len = dmx->Read(tmp, 6, 1000);
|
||||
if(len <= 0)
|
||||
continue;
|
||||
|
||||
if(memcmp(tmp, "\x00\x00\x01\xbd", 4)) {
|
||||
sub_debug.print(Debug::VERBOSE, "[subtitles] bad start code: %02x%02x%02x%02x\n", tmp[0], tmp[1], tmp[2], tmp[3]);
|
||||
continue;
|
||||
}
|
||||
count = 6;
|
||||
|
||||
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];
|
||||
buf = (uint8_t*) malloc(packlen);
|
||||
|
||||
memcpy(buf, tmp, 6);
|
||||
/* 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;
|
||||
@@ -277,6 +243,18 @@ void* reader_thread(void * /*arg*/)
|
||||
count += len;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
for(int i = 6; i < packlen - 4; i++) {
|
||||
if(!memcmp(&buf[i], "\x00\x00\x01\xbd", 4)) {
|
||||
int plen = getbits(&buf[i], 4*8, 16) + 6;
|
||||
sub_debug.print(Debug::VERBOSE, "[subtitles] ******************* PES header at %d ?! *******************\n", i);
|
||||
sub_debug.print(Debug::VERBOSE, "[subtitles] start code: %02x%02x%02x%02x len %d\n", buf[i+0], buf[i+1], buf[i+2], buf[i+3], plen);
|
||||
free(buf);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!dvbsub_paused) {
|
||||
sub_debug.print(Debug::VERBOSE, "[subtitles] ******************* new packet, len %d buf 0x%x pts-stc diff %lld *******************\n", count, buf, get_pts_stc_delta(get_pts(buf)));
|
||||
/* Packet now in memory */
|
||||
@@ -287,7 +265,7 @@ void* reader_thread(void * /*arg*/)
|
||||
pthread_cond_broadcast(&packetCond);
|
||||
pthread_mutex_unlock(&packetMutex);
|
||||
} else {
|
||||
delete[] buf;
|
||||
free(buf);
|
||||
buf=NULL;
|
||||
}
|
||||
}
|
||||
@@ -320,7 +298,6 @@ void* dvbsub_thread(void* /*arg*/)
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
int ret = 0;
|
||||
#if 1
|
||||
now.tv_usec += (timeout == 0) ? 1000000 : timeout; // add the timeout
|
||||
while (now.tv_usec >= 1000000) { // take care of an overflow
|
||||
now.tv_sec++;
|
||||
@@ -338,30 +315,11 @@ void* dvbsub_thread(void* /*arg*/)
|
||||
if(packet_queue.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
|
||||
TIMEVAL_TO_TIMESPEC(&now, &restartWait);
|
||||
restartWait.tv_sec += 1;
|
||||
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));
|
||||
}
|
||||
#endif
|
||||
sub_debug.print(Debug::VERBOSE, "PES: Wakeup, queue size %d\n\n", packet_queue.size());
|
||||
if(dvbsub_paused) {
|
||||
while(packet_queue.size()) {
|
||||
packet = packet_queue.pop();
|
||||
delete[] packet;
|
||||
free(packet);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -372,25 +330,16 @@ void* dvbsub_thread(void* /*arg*/)
|
||||
}
|
||||
packlen = (packet[4] << 8 | packet[5]) + 6;
|
||||
|
||||
#if 0
|
||||
/* 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;
|
||||
}
|
||||
#endif
|
||||
pts = get_pts(packet);
|
||||
|
||||
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);
|
||||
#if 0
|
||||
for(int i = 0; i < packlen; i++)
|
||||
printf("%02X ", packet[i]);
|
||||
printf("\n");
|
||||
#endif
|
||||
goto next_round;
|
||||
}
|
||||
|
||||
@@ -412,7 +361,7 @@ void* dvbsub_thread(void* /*arg*/)
|
||||
timeout = dvbSubtitleConverter->Action();
|
||||
|
||||
next_round:
|
||||
delete[] packet;
|
||||
free(packet);
|
||||
}
|
||||
|
||||
delete dvbSubtitleConverter;
|
||||
|
@@ -1,8 +0,0 @@
|
||||
#ifndef DVBSUB_THREAD_HPP_
|
||||
#define DVBSUB_THREAD_HPP_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
void* dvbsub_thread(void* arg);
|
||||
|
||||
#endif
|
@@ -30,6 +30,9 @@ static bool DebugConverter = true;
|
||||
|
||||
#define dbgconverter(a...) if (DebugConverter) sub_debug.print(Debug::VERBOSE, a)
|
||||
|
||||
extern unsigned char *simple_resize (unsigned char *orgin, int ox, int oy, int dx, int dy);
|
||||
extern unsigned char *color_average_resize (unsigned char *orgin, int ox, int oy, int dx, int dy);
|
||||
|
||||
// --- cDvbSubtitleBitmaps ---------------------------------------------------
|
||||
|
||||
class cDvbSubtitleBitmaps : public cListObject
|
||||
@@ -38,24 +41,20 @@ class cDvbSubtitleBitmaps : public cListObject
|
||||
int64_t pts;
|
||||
int timeout;
|
||||
AVSubtitle sub;
|
||||
// int min_x, min_y, max_x, max_y;
|
||||
public:
|
||||
cDvbSubtitleBitmaps(int64_t Pts);
|
||||
~cDvbSubtitleBitmaps();
|
||||
int64_t Pts(void) { return pts; }
|
||||
int Timeout(void) { return sub.end_display_time; }
|
||||
void Draw();
|
||||
void Clear(void);
|
||||
void Draw(int &min_x, int &min_y, int &max_x, int &max_y);
|
||||
int Count(void) { return sub.num_rects; };
|
||||
AVSubtitle * GetSub(void) { return ⊂ };
|
||||
};
|
||||
|
||||
cDvbSubtitleBitmaps::cDvbSubtitleBitmaps(int64_t pPts)
|
||||
{
|
||||
pts = pPts;
|
||||
// max_x = max_y = 0;
|
||||
// min_x = min_y = 0xFFFF;
|
||||
//dbgconverter("cDvbSubtitleBitmaps::new: PTS: %lld\n", pts);
|
||||
pts = pPts;
|
||||
}
|
||||
|
||||
cDvbSubtitleBitmaps::~cDvbSubtitleBitmaps()
|
||||
@@ -63,35 +62,20 @@ cDvbSubtitleBitmaps::~cDvbSubtitleBitmaps()
|
||||
dbgconverter("cDvbSubtitleBitmaps::delete: PTS: %lld rects %d\n", pts, Count());
|
||||
int i;
|
||||
|
||||
//return; //FIXME !
|
||||
if(sub.rects) {
|
||||
for (i = 0; i < Count(); i++)
|
||||
{
|
||||
av_freep(&sub.rects[i]->pict.data[0]);
|
||||
av_freep(&sub.rects[i]->pict.data[1]);
|
||||
av_freep(&sub.rects[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < Count(); i++)
|
||||
{
|
||||
av_freep(&sub.rects[i]->pict.data[0]);
|
||||
av_freep(&sub.rects[i]->pict.data[1]);
|
||||
av_freep(&sub.rects[i]);
|
||||
av_free(sub.rects);
|
||||
}
|
||||
|
||||
av_free(sub.rects);
|
||||
|
||||
memset(&sub, 0, sizeof(AVSubtitle));
|
||||
}
|
||||
|
||||
static int min_x = 0xFFFF, min_y = 0xFFFF;
|
||||
static int max_x = 0, max_y = 0;
|
||||
|
||||
void cDvbSubtitleBitmaps::Clear()
|
||||
{
|
||||
dbgconverter("cDvbSubtitleBitmaps::Clear: x=% d y= %d, w= %d, h= %d\n", min_x, min_y, max_x-min_x, max_y-min_y);
|
||||
if(max_x && max_y) {
|
||||
CFrameBuffer::getInstance()->paintBackgroundBoxRel (min_x, min_y-10, max_x-min_x, max_y-min_y+10);
|
||||
//CFrameBuffer::getInstance()->paintBackground();
|
||||
//max_x = max_y = 0;
|
||||
//min_x = min_y = 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
void cDvbSubtitleBitmaps::Draw()
|
||||
void cDvbSubtitleBitmaps::Draw(int &min_x, int &min_y, int &max_x, int &max_y)
|
||||
{
|
||||
int i;
|
||||
int stride = CFrameBuffer::getInstance()->getScreenWidth(true);
|
||||
@@ -100,14 +84,13 @@ void cDvbSubtitleBitmaps::Draw()
|
||||
int yend = CFrameBuffer::getInstance()->getScreenY() + CFrameBuffer::getInstance()->getScreenHeight();
|
||||
uint32_t *sublfb = CFrameBuffer::getInstance()->getFrameBufferPointer();
|
||||
|
||||
dbgconverter("cDvbSubtitleBitmaps::Draw: %d bitmaps, x= %d, width= %d end=%d stride %d\n", sub.num_rects, xs, wd, yend, stride);
|
||||
|
||||
//if(Count())
|
||||
Clear(); //FIXME should we clear for new bitmaps set ?
|
||||
dbgconverter("cDvbSubtitleBitmaps::Draw: %d bitmaps, x= %d, width= %d yend=%d stride %d\n", Count(), xs, wd, yend, stride);
|
||||
|
||||
for (i = 0; i < Count(); i++) {
|
||||
/* center on screen */
|
||||
int xoff = xs + (wd - sub.rects[i]->w) / 2;
|
||||
/* int xoff = xs + (wd - sub.rects[i]->w) / 2;*/
|
||||
int xdiff = (wd > 720) ? ((wd - 720) / 2) : 0;
|
||||
int xoff = sub.rects[i]->x + xs + xdiff; // 720 - (720 - x) = orig offset;
|
||||
/* move to screen bottom */
|
||||
int yoff = (yend - (576 - sub.rects[i]->y)) * stride;
|
||||
int ys = yend - (576 - sub.rects[i]->y);
|
||||
@@ -171,6 +154,12 @@ cDvbSubtitleConverter::cDvbSubtitleConverter(void)
|
||||
av_log_set_level(99);
|
||||
if(DebugConverter)
|
||||
av_log_set_level(AV_LOG_INFO);
|
||||
|
||||
min_x = CFrameBuffer::getInstance()->getScreenWidth();
|
||||
min_y = CFrameBuffer::getInstance()->getScreenHeight();
|
||||
max_x = CFrameBuffer::getInstance()->getScreenX();
|
||||
max_y = CFrameBuffer::getInstance()->getScreenY();
|
||||
Timeout.Set(0xFFFF*1000);
|
||||
}
|
||||
|
||||
cDvbSubtitleConverter::~cDvbSubtitleConverter()
|
||||
@@ -195,32 +184,32 @@ void cDvbSubtitleConverter::Pause(bool pause)
|
||||
if(!running)
|
||||
return;
|
||||
Lock();
|
||||
running = false;
|
||||
Clear();
|
||||
running = false;
|
||||
Unlock();
|
||||
Reset();
|
||||
} else {
|
||||
Reset();
|
||||
running = true;
|
||||
}
|
||||
}
|
||||
|
||||
void cDvbSubtitleConverter::Clear(void)
|
||||
{
|
||||
if(max_x && max_y) {
|
||||
dbgconverter("cDvbSubtitleConverter::Clear: x=% d y= %d, w= %d, h= %d\n", min_x, min_y, max_x-min_x, max_y-min_y);
|
||||
CFrameBuffer::getInstance()->paintBackgroundBoxRel (min_x, min_y-10, max_x-min_x, max_y-min_y+10);
|
||||
dbgconverter("cDvbSubtitleConverter::Clear: x=% d y= %d, w= %d, h= %d\n", min_x, min_y, max_x-min_x, max_y-min_y);
|
||||
if(running && (max_x-min_x > 0) && (max_y-min_y > 0)) {
|
||||
CFrameBuffer::getInstance()->paintBackgroundBoxRel (min_x, min_y, max_x-min_x, max_y-min_y);
|
||||
//CFrameBuffer::getInstance()->paintBackground();
|
||||
//max_x = max_y = 0;
|
||||
//min_x = min_y = 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
void cDvbSubtitleConverter::Reset(void)
|
||||
{
|
||||
dbgconverter("Converter reset -----------------------\n");
|
||||
Lock();
|
||||
bitmaps->Clear();
|
||||
Unlock();
|
||||
dbgconverter("Converter reset -----------------------\n");
|
||||
Lock();
|
||||
bitmaps->Clear();
|
||||
Unlock();
|
||||
Timeout.Set(0xFFFF*1000);
|
||||
}
|
||||
|
||||
int cDvbSubtitleConverter::Convert(const uchar *Data, int Length, int64_t pts)
|
||||
@@ -243,11 +232,11 @@ int cDvbSubtitleConverter::Convert(const uchar *Data, int Length, int64_t pts)
|
||||
avpkt.data = (uint8_t*) Data;
|
||||
avpkt.size = Length;
|
||||
|
||||
dbgconverter("cDvbSubtitleConverter::Convert: sub %x pkt %x\n", sub, &avpkt);
|
||||
dbgconverter("cDvbSubtitleConverter::Convert: sub %x pkt %x pts %lld\n", sub, &avpkt, pts);
|
||||
//avctx->sub_id = (anc_page << 16) | comp_page; //FIXME not patched ffmpeg needs this !
|
||||
|
||||
avcodec_decode_subtitle2(avctx, sub, &got_subtitle, &avpkt);
|
||||
dbgconverter("cDvbSubtitleConverter::Convert: subs ? %s, %d bitmaps\n", got_subtitle? "yes" : "no", sub->num_rects);
|
||||
dbgconverter("cDvbSubtitleConverter::Convert: pts %lld subs ? %s, %d bitmaps\n", pts, got_subtitle? "yes" : "no", sub->num_rects);
|
||||
|
||||
if(got_subtitle) {
|
||||
if(DebugConverter) {
|
||||
@@ -274,7 +263,6 @@ void dvbsub_get_stc(int64_t * STC);
|
||||
|
||||
int cDvbSubtitleConverter::Action(void)
|
||||
{
|
||||
static cTimeMs Timeout(0xFFFF*1000);
|
||||
int WaitMs = WAITMS;
|
||||
|
||||
if (!running)
|
||||
@@ -299,7 +287,8 @@ int cDvbSubtitleConverter::Action(void)
|
||||
if (Delta <= SHOW_DELTA) {
|
||||
dbgconverter("cDvbSubtitleConverter::Action: Got %d bitmaps, showing #%d\n", bitmaps->Count(), sb->Index() + 1);
|
||||
if (running) {
|
||||
sb->Draw();
|
||||
Clear();
|
||||
sb->Draw(min_x, min_y, max_x, max_y);
|
||||
Timeout.Set(sb->Timeout());
|
||||
}
|
||||
if(sb->Count())
|
||||
|
@@ -33,6 +33,8 @@ private:
|
||||
cList<cDvbSubtitleBitmaps> *bitmaps;
|
||||
AVCodecContext * avctx;
|
||||
AVCodec * avcodec;
|
||||
int min_x, min_y, max_x, max_y;
|
||||
cTimeMs Timeout;
|
||||
public:
|
||||
cDvbSubtitleConverter(void);
|
||||
virtual ~cDvbSubtitleConverter();
|
||||
|
@@ -1,287 +0,0 @@
|
||||
/*
|
||||
* 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 pBpp)
|
||||
{
|
||||
SetBpp(pBpp);
|
||||
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 pColor)
|
||||
{
|
||||
// Check if color is already defined:
|
||||
for (int i = 0; i < numColors; i++) {
|
||||
if (color[i] == pColor)
|
||||
return i;
|
||||
}
|
||||
// No exact color, try a close one:
|
||||
int i = ClosestColor(pColor, 4);
|
||||
if (i >= 0)
|
||||
return i;
|
||||
// No close one, try to define a new one:
|
||||
if (numColors < maxColors) {
|
||||
color[numColors++] = pColor;
|
||||
modified = true;
|
||||
return numColors - 1;
|
||||
}
|
||||
// Out of colors, so any close color must do:
|
||||
return ClosestColor(pColor);
|
||||
}
|
||||
|
||||
void cPalette::SetBpp(int pBpp)
|
||||
{
|
||||
bpp = pBpp;
|
||||
maxColors = 1 << bpp;
|
||||
Reset();
|
||||
}
|
||||
|
||||
void cPalette::SetColor(int pIndex, tColor pColor)
|
||||
{
|
||||
if (pIndex < maxColors) {
|
||||
if (numColors <= pIndex) {
|
||||
numColors = pIndex + 1;
|
||||
modified = true;
|
||||
}
|
||||
else
|
||||
modified |= color[pIndex] != pColor;
|
||||
color[pIndex] = pColor;
|
||||
}
|
||||
}
|
||||
|
||||
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 pColor = Palette.color[i];
|
||||
if (ColorFg || ColorBg) {
|
||||
switch (i) {
|
||||
case 0: pColor = ColorBg; break;
|
||||
case 1: pColor = ColorFg; break;
|
||||
}
|
||||
}
|
||||
int n = Index(pColor);
|
||||
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 pColor, int MaxDiff) const
|
||||
{
|
||||
int n = 0;
|
||||
int d = INT_MAX;
|
||||
int A1 = (pColor & 0xFF000000) >> 24;
|
||||
int R1 = (pColor & 0x00FF0000) >> 16;
|
||||
int G1 = (pColor & 0x0000FF00) >> 8;
|
||||
int B1 = (pColor & 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 pWidth, int pHeight, int pBpp, int pX0, int pY0)
|
||||
:cPalette(pBpp)
|
||||
{
|
||||
bitmap = NULL;
|
||||
x0 = pX0;
|
||||
y0 = pY0;
|
||||
SetSize(pWidth, pHeight);
|
||||
}
|
||||
|
||||
cBitmap::~cBitmap()
|
||||
{
|
||||
free(bitmap);
|
||||
}
|
||||
|
||||
void cBitmap::SetIndex(int x, int y, tIndex pIndex)
|
||||
{
|
||||
if (bitmap) {
|
||||
if (0 <= x && x < width && 0 <= y && y < height) {
|
||||
if (bitmap[width * y + x] != pIndex) {
|
||||
bitmap[width * y + x] = pIndex;
|
||||
if (dirtyX1 > x) dirtyX1 = x;
|
||||
if (dirtyY1 > y) dirtyY1 = y;
|
||||
if (dirtyX2 < x) dirtyX2 = x;
|
||||
if (dirtyY2 < y) dirtyY2 = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cBitmap::SetSize(int pWidth, int pHeight)
|
||||
{
|
||||
if (bitmap && pWidth == width && pHeight == height)
|
||||
return;
|
||||
width = pWidth;
|
||||
height = pHeight;
|
||||
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];
|
||||
}
|
||||
|
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* 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 pIndex) const { return pIndex < maxColors ? color[pIndex] : 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
|
@@ -1,6 +0,0 @@
|
||||
#ifndef READER_THREAD_HPP_
|
||||
#define READER_THREAD_HPP_
|
||||
|
||||
void* reader_thread(void *arg);
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user