summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2002-09-08 14:17:51 +0200
committerKlaus Schmidinger <vdr@tvdr.de>2002-09-08 14:17:51 +0200
commit9133fdcf630192fb57b7db4e3b35839588c3451d (patch)
tree38b51eb9d1bd241f1a7a28192d42f7bd91f59523
parent1b396902e488e093234ac181bbc0e514dd098942 (diff)
downloadvdr-9133fdcf630192fb57b7db4e3b35839588c3451d.tar.gz
vdr-9133fdcf630192fb57b7db4e3b35839588c3451d.tar.bz2
Implemented an SPU decoder
-rw-r--r--CONTRIBUTORS1
-rw-r--r--HISTORY1
-rw-r--r--Makefile6
-rw-r--r--device.c7
-rw-r--r--device.h6
-rw-r--r--dvbdevice.c11
-rw-r--r--dvbdevice.h6
-rw-r--r--dvbspu.c505
-rw-r--r--dvbspu.h204
-rw-r--r--osdbase.h6
-rw-r--r--spu.c23
-rw-r--r--spu.h38
12 files changed, 804 insertions, 10 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index ca9a31ae..28da4004 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -166,6 +166,7 @@ Andreas Schultz <aschultz@warp10.net>
for making the use of malloc/free and new/delete consistent
for adding cDevice::NewOsd() to allow a derived cDevice class to implement its own
OSD capabilities
+ for implementing an SPU decoder
Aaron Holtzman
for writing 'ac3dec'
diff --git a/HISTORY b/HISTORY
index f2c944f1..fc78e6e6 100644
--- a/HISTORY
+++ b/HISTORY
@@ -1455,3 +1455,4 @@ Video Disk Recorder Revision History
- Switching through channels with the 'Up' and 'Down' keys now skips channels
that are currently not available (for instance because all devices are
recording and these channels are on different transponders).
+- Implemented an SPU decoder (thanks to Andreas Schultz).
diff --git a/Makefile b/Makefile
index 0f3f9672..4f468c42 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
-# $Id: Makefile 1.45 2002/08/09 16:02:02 kls Exp $
+# $Id: Makefile 1.46 2002/09/08 14:00:48 kls Exp $
.DELETE_ON_ERROR:
@@ -32,9 +32,9 @@ endif
DTVLIB = $(DTVDIR)/libdtv.a
-OBJS = audio.o config.o cutter.o device.o dvbdevice.o dvbosd.o dvbplayer.o eit.o eitscan.o font.o i18n.o\
+OBJS = audio.o config.o cutter.o device.o dvbdevice.o dvbosd.o dvbplayer.o dvbspu.o eit.o eitscan.o font.o i18n.o\
interface.o menu.o menuitems.o osdbase.o osd.o player.o plugin.o receiver.o\
- recorder.o recording.o remote.o remux.o ringbuffer.o status.o svdrp.o thread.o\
+ recorder.o recording.o remote.o remux.o ringbuffer.o spu.o status.o svdrp.o thread.o\
tools.o transfer.o vdr.o videodir.o
OSDFONT = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1
diff --git a/device.c b/device.c
index ab1067d0..72f1fc63 100644
--- a/device.c
+++ b/device.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: device.c 1.18 2002/09/08 11:46:53 kls Exp $
+ * $Id: device.c 1.19 2002/09/08 14:03:43 kls Exp $
*/
#include "device.h"
@@ -113,6 +113,11 @@ cOsdBase *cDevice::NewOsd(int x, int y)
return NULL;
}
+cSpuDecoder *cDevice::GetSpuDecoder(void)
+{
+ return NULL;
+}
+
cDevice *cDevice::GetDevice(int Index)
{
return (0 <= Index && Index < numDevices) ? device[Index] : NULL;
diff --git a/device.h b/device.h
index 0bf9d3db..905b3d3d 100644
--- a/device.h
+++ b/device.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: device.h 1.14 2002/09/08 11:17:41 kls Exp $
+ * $Id: device.h 1.15 2002/09/08 14:02:50 kls Exp $
*/
#ifndef __DEVICE_H
@@ -47,6 +47,7 @@ class cOsdBase;
class cChannel;
class cPlayer;
class cReceiver;
+class cSpuDecoder;
class cDevice : cThread {
private:
@@ -128,6 +129,9 @@ public:
// of the OSD at the given coordinates. If a derived cDevice doesn't
// implement this function, NULL will be returned by default (which
// means the device has no OSD capabilities).
+ virtual cSpuDecoder *GetSpuDecoder(void);
+ // Returns a pointer to the device's SPU decoder (or NULL, if this
+ // device doesn't have an SPU decoder).
// Channel facilities
diff --git a/dvbdevice.c b/dvbdevice.c
index 3d971b59..2b9c0aae 100644
--- a/dvbdevice.c
+++ b/dvbdevice.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbdevice.c 1.11 2002/09/07 13:39:49 kls Exp $
+ * $Id: dvbdevice.c 1.12 2002/09/08 14:07:08 kls Exp $
*/
#include "dvbdevice.h"
@@ -80,6 +80,7 @@ cDvbDevice::cDvbDevice(int n)
{
frontendType = FrontendType(-1); // don't know how else to initialize this - there is no FE_UNKNOWN
siProcessor = NULL;
+ spuDecoder = NULL;
playMode = pmNone;
// Devices that are present on all card types:
@@ -128,6 +129,7 @@ cDvbDevice::cDvbDevice(int n)
cDvbDevice::~cDvbDevice()
{
+ delete spuDecoder;
delete siProcessor;
// We're not explicitly closing any device files here, since this sometimes
// caused segfaults. Besides, the program is about to terminate anyway...
@@ -189,6 +191,13 @@ cOsdBase *cDvbDevice::NewOsd(int x, int y)
return new cDvbOsd(x, y);
}
+cSpuDecoder *cDvbDevice::GetSpuDecoder(void)
+{
+ if (!spuDecoder && IsPrimaryDevice())
+ spuDecoder = new cDvbSpuDecoder();
+ return spuDecoder;
+}
+
bool cDvbDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY)
{
int videoDev = DvbOpen(DEV_VIDEO, CardIndex(), O_RDWR, true);
diff --git a/dvbdevice.h b/dvbdevice.h
index 7de89665..b135ff66 100644
--- a/dvbdevice.h
+++ b/dvbdevice.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbdevice.h 1.9 2002/09/07 09:06:40 kls Exp $
+ * $Id: dvbdevice.h 1.10 2002/09/08 14:05:29 kls Exp $
*/
#ifndef __DVBDEVICE_H
@@ -21,6 +21,7 @@
#include <ost/frontend.h>
#endif
#include "device.h"
+#include "dvbspu.h"
#include "eit.h"
#define MAXDVBDEVICES 4
@@ -51,8 +52,11 @@ public:
// OSD facilities
+private:
+ cDvbSpuDecoder *spuDecoder;
public:
cOsdBase *NewOsd(int x, int y);
+ virtual cSpuDecoder *GetSpuDecoder(void);
// Channel facilities
diff --git a/dvbspu.c b/dvbspu.c
new file mode 100644
index 00000000..1e298590
--- /dev/null
+++ b/dvbspu.c
@@ -0,0 +1,505 @@
+/*
+ * SPU decoder for DVB devices
+ *
+ * Copyright (C) 2001.2002 Andreas Schultz <aschultz@warp10.net>
+ *
+ * This code is distributed under the terms and conditions of the
+ * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+ *
+ * parts of this file are derived from the OMS program.
+ *
+ * $Id: dvbspu.c 1.1 2002/09/08 14:17:35 kls Exp $
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <inttypes.h>
+#include <math.h>
+
+#include "osd.h"
+#include "osdbase.h"
+#include "device.h"
+#include "dvbspu.h"
+
+/*
+ * cDvbSpubitmap:
+ *
+ * this is a bitmap of the full screen and two palettes
+ * the normal palette for the background and the highlight palette
+ *
+ * Inputs:
+ * - a SPU rle encoded image on creation, which will be decoded into
+ * the full screen indexed bitmap
+ *
+ * Output:
+ * - a minimal sized cDvbSpuBitmap a given palette, the indexed bitmap
+ * will be scanned to get the smallest possible resulting bitmap considering
+ * transparencies
+ */
+
+// #define SPUDEBUG
+
+#ifdef SPUDEBUG
+#define DEBUG(format, args...) printf (format, ## args)
+#else
+#define DEBUG(format, args...)
+#endif
+
+// --- cDvbSpuPalette----------------------------------
+
+void cDvbSpuPalette::setPalette(const uint32_t * pal)
+{
+ for (int i = 0; i < 16; i++)
+ palette[i] = yuv2rgb(pal[i]);
+}
+
+// --- cDvbSpuBitmap --------------------------------------------
+
+#define setMin(a, b) if (a > b) a = b
+#define setMax(a, b) if (a < b) a = b
+
+#define spuXres 720
+#define spuYres 576
+
+#define revRect(r1, r2) { r1.x1 = r2.x2; r1.y1 = r2.y2; r1.x2 = r2.x1; r1.y2 = r2.y1; }
+
+cDvbSpuBitmap::cDvbSpuBitmap(sDvbSpuRect size,
+ uint8_t * fodd, uint8_t * eodd,
+ uint8_t * feven, uint8_t * eeven)
+{
+ if (size.x1 < 0 || size.y1 < 0 || size.x2 >= spuXres
+ || size.y2 >= spuYres)
+ throw;
+
+ bmpsize = size;
+ revRect(minsize[0], size);
+ revRect(minsize[1], size);
+ revRect(minsize[2], size);
+ revRect(minsize[3], size);
+
+ if (!(bmp = new uint8_t[spuXres * spuYres * sizeof(uint8_t)]))
+ throw;
+
+ memset(bmp, 0, spuXres * spuYres * sizeof(uint8_t));
+ putFieldData(0, fodd, eodd);
+ putFieldData(1, feven, eeven);
+}
+
+cDvbSpuBitmap::~cDvbSpuBitmap()
+{
+ delete[]bmp;
+}
+
+cBitmap *cDvbSpuBitmap::getBitmap(const aDvbSpuPalDescr paldescr,
+ const cDvbSpuPalette & pal,
+ sDvbSpuRect & size) const
+{
+ int h = size.height();
+ int w = size.width();
+
+ if (size.y1 + h >= spuYres)
+ h = spuYres - size.y1 - 1;
+ if (size.x1 + w >= spuXres)
+ w = spuXres - size.x1 - 1;
+
+ if (w & 0x03)
+ w += 4 - (w & 0x03);
+
+ cBitmap *ret = new cBitmap(w, h, 2, true);
+
+ // set the palette
+ for (int i = 0; i < 4; i++) {
+ uint32_t color =
+ pal.getColor(paldescr[i].index, paldescr[i].trans);
+ ret->SetColor(i, (eDvbColor) color);
+ }
+
+ // set the content
+ for (int yp = 0; yp < h; yp++) {
+ for (int xp = 0; xp < w; xp++) {
+ uint8_t idx = bmp[(size.y1 + yp) * spuXres + size.x1 + xp];
+ ret->SetIndex(xp, yp, idx);
+ }
+ }
+ return ret;
+}
+
+// find the minimum non-transparent area
+bool cDvbSpuBitmap::getMinSize(const aDvbSpuPalDescr paldescr,
+ sDvbSpuRect & size) const
+{
+ bool ret = false;
+ for (int i = 0; i < 4; i++) {
+ if (paldescr[i].trans != 0) {
+ if (!ret)
+ size = minsize[i];
+ else {
+ setMin(size.x1, minsize[i].x1);
+ setMin(size.y1, minsize[i].y1);
+ setMax(size.x2, minsize[i].x2);
+ setMax(size.y2, minsize[i].y2);
+ ret = true;
+ }
+ }
+ }
+ if (ret)
+ DEBUG("MinSize: (%d, %d) x (%d, %d)\n",
+ size.x1, size.y1, size.x2, size.y2);
+
+ return ret;
+}
+
+void cDvbSpuBitmap::putPixel(int xp, int yp, int len, uint8_t colorid)
+{
+ memset(bmp + spuXres * yp + xp, colorid, len);
+ setMin(minsize[colorid].x1, xp);
+ setMin(minsize[colorid].y1, yp);
+ setMax(minsize[colorid].x2, xp + len - 1);
+ setMax(minsize[colorid].y2, yp + len - 1);
+}
+
+static uint8_t getBits(uint8_t * &data, uint8_t & bitf)
+{
+ uint8_t ret = *data;
+ if (bitf)
+ ret >>= 4;
+ else
+ data++;
+ bitf ^= 1;
+
+ return (ret & 0xf);
+}
+
+void cDvbSpuBitmap::putFieldData(int field, uint8_t * data, uint8_t * endp)
+{
+ int xp = bmpsize.x1;
+ int yp = bmpsize.y1 + field;
+ uint8_t bitf = 1;
+
+ while (data < endp) {
+ uint16_t vlc = getBits(data, bitf);
+ if (vlc < 0x0004) {
+ vlc = (vlc << 4) | getBits(data, bitf);
+ if (vlc < 0x0010) {
+ vlc = (vlc << 4) | getBits(data, bitf);
+ if (vlc < 0x0040) {
+ vlc = (vlc << 4) | getBits(data, bitf);
+ }
+ }
+ }
+
+ uint8_t color = vlc & 0x03;
+ int len = vlc >> 2;
+
+ // if len == 0 -> end sequence - fill to end of line
+ len = len ? : bmpsize.x2 - xp + 1;
+ putPixel(xp, yp, len, color);
+ xp += len;
+
+ if (xp > bmpsize.x2) {
+ // nextLine
+ if (!bitf)
+ data++;
+ bitf = 1;
+ xp = bmpsize.x1;
+ yp += 2;
+ if (yp > bmpsize.y2)
+ return;
+ }
+ }
+}
+
+// --- cDvbSpuDecoder-----------------------------
+
+#define CMD_SPU_MENU 0x00
+#define CMD_SPU_SHOW 0x01
+#define CMD_SPU_HIDE 0x02
+#define CMD_SPU_SET_PALETTE 0x03
+#define CMD_SPU_SET_ALPHA 0x04
+#define CMD_SPU_SET_SIZE 0x05
+#define CMD_SPU_SET_PXD_OFFSET 0x06
+#define CMD_SPU_EOF 0xff
+
+#define spuU32(i) ((spu[i] << 8) + spu[i+1])
+
+cDvbSpuDecoder::cDvbSpuDecoder()
+{
+ clean = true;
+ scaleMode = eSpuNormal;
+ spu = NULL;
+ osd = NULL;
+ spubmp = NULL;
+}
+
+cDvbSpuDecoder::~cDvbSpuDecoder()
+{
+ delete spubmp;
+ delete spu;
+ delete osd;
+}
+
+void cDvbSpuDecoder::processSPU(uint32_t pts, uint8_t * buf)
+{
+ setTime(pts);
+
+ DEBUG("SPU pushData: pts: %d\n", pts);
+
+ delete spubmp;
+ spubmp = NULL;
+ delete[]spu;
+ spu = buf;
+
+ DCSQ_offset = cmdOffs();
+ prev_DCSQ_offset = 0;
+
+ clean = true;
+}
+
+void cDvbSpuDecoder::setScaleMode(cSpuDecoder::eScaleMode ScaleMode)
+{
+ scaleMode = ScaleMode;
+}
+
+void cDvbSpuDecoder::setPalette(uint32_t * pal)
+{
+ palette.setPalette(pal);
+}
+
+void cDvbSpuDecoder::setHighlight(uint16_t sx, uint16_t sy,
+ uint16_t ex, uint16_t ey,
+ uint32_t palette)
+{
+ aDvbSpuPalDescr pld;
+ for (int i = 0; i < 4; i++) {
+ pld[i].index = 0xf & (palette >> (16 + 4 * i));
+ pld[i].trans = 0xf & (palette >> (4 * i));
+ }
+
+ bool ne = hlpsize.x1 != sx || hlpsize.y1 != sy ||
+ hlpsize.x2 != ex || hlpsize.y2 != ey ||
+ pld[0] != hlpDescr[0] || pld[1] != hlpDescr[1] ||
+ pld[2] != hlpDescr[2] || pld[3] != hlpDescr[3];
+
+ if (ne) {
+ DEBUG("setHighlight: %d,%d x %d,%d\n", sx, sy, ex, ey);
+ hlpsize.x1 = sx;
+ hlpsize.y1 = sy;
+ hlpsize.x2 = ex;
+ hlpsize.y2 = ey;
+ memcpy(hlpDescr, pld, sizeof(aDvbSpuPalDescr));
+ highlight = true;
+ clean = false;
+ }
+}
+
+void cDvbSpuDecoder::clearHighlight(void)
+{
+ clean &= !highlight;
+ highlight = false;
+}
+
+int cDvbSpuDecoder::ScaleYcoord(int value)
+{
+ if (scaleMode == eSpuLetterBox)
+ return lround((value * 3.0) / 4.0 + 72.0);
+ else
+ return value;
+}
+
+int cDvbSpuDecoder::ScaleYres(int value)
+{
+ if (scaleMode == eSpuLetterBox)
+ return lround((value * 3.0) / 4.0);
+ else
+ return value;
+}
+
+void cDvbSpuDecoder::DrawBmp(sDvbSpuRect & size, cBitmap * bmp)
+{
+ osd->Create(size.x1, size.y1, size.width(), size.height(), 2, false);
+ osd->SetBitmap(size.x1, size.y1, *bmp);
+ delete bmp;
+}
+
+void cDvbSpuDecoder::Draw(void)
+{
+ Hide();
+
+ if (!spubmp)
+ return;
+
+ cBitmap *fg = NULL;
+ cBitmap *bg = NULL;
+ sDvbSpuRect bgsize;
+ sDvbSpuRect hlsize;
+
+ hlsize.x1 = hlpsize.x1;
+ hlsize.y1 = ScaleYcoord(hlpsize.y1);
+ hlsize.x2 = hlpsize.x2;
+ hlsize.y2 = ScaleYcoord(hlpsize.y2);
+
+ if (highlight)
+ fg = spubmp->getBitmap(hlpDescr, palette, hlsize);
+
+ if (spubmp->getMinSize(palDescr, bgsize)) {
+ bg = spubmp->getBitmap(palDescr, palette, bgsize);
+ if (scaleMode == eSpuLetterBox) {
+ // the coordinates have to be modified for letterbox
+ int y1 = ScaleYres(bgsize.y1) + bgsize.height();
+ bgsize.y2 = y1 + bgsize.height();
+ bgsize.y1 = y1;
+ }
+ }
+
+ if (bg || fg) {
+ if (osd == NULL)
+ if ((osd = cOsd::OpenRaw(0, 0)) == NULL) {
+ dsyslog("OpenRaw failed\n");
+ return;
+ }
+
+ if (fg)
+ DrawBmp(hlsize, fg);
+
+ if (bg)
+ DrawBmp(bgsize, bg);
+
+ osd->Flush();
+ }
+
+ clean = true;
+}
+
+void cDvbSpuDecoder::Hide(void)
+{
+ delete osd;
+ osd = NULL;
+}
+
+void cDvbSpuDecoder::Empty(void)
+{
+ Hide();
+
+ delete spubmp;
+ spubmp = NULL;
+
+ delete[]spu;
+ spu = NULL;
+
+ clearHighlight();
+ clean = true;
+}
+
+int cDvbSpuDecoder::setTime(uint32_t pts)
+{
+ if (!spu)
+ return 0;
+
+ if (spu && !clean)
+ Draw();
+
+ while (DCSQ_offset != prev_DCSQ_offset) { /* Display Control Sequences */
+ int i = DCSQ_offset;
+ state = spNONE;
+
+ uint32_t exec_time = pts + spuU32(i) * 1024;
+ if ((pts != 0) && (exec_time > pts))
+ return 0;
+ DEBUG("offs = %d, rel = %d, time = %d, pts = %d, diff = %d\n",
+ i, spuU32(i) * 1024, exec_time, pts, exec_time - pts);
+
+ if (pts != 0) {
+ uint16_t feven = 0;
+ uint16_t fodd = 0;
+
+ i += 2;
+
+ prev_DCSQ_offset = DCSQ_offset;
+ DCSQ_offset = spuU32(i);
+ DEBUG("offs = %d, DCSQ = %d\n", i, DCSQ_offset);
+ i += 2;
+
+ while (spu[i] != CMD_SPU_EOF) { // Command Sequence
+ switch (spu[i]) {
+ case CMD_SPU_SHOW: // show subpicture
+ DEBUG("\tshow subpicture\n");
+ state = spSHOW;
+ i++;
+ break;
+
+ case CMD_SPU_HIDE: // hide subpicture
+ DEBUG("\thide subpicture\n");
+ state = spHIDE;
+ i++;
+ break;
+
+ case CMD_SPU_SET_PALETTE: // CLUT
+ palDescr[0].index = spu[i + 2] & 0xf;
+ palDescr[1].index = spu[i + 2] >> 4;
+ palDescr[2].index = spu[i + 1] & 0xf;
+ palDescr[3].index = spu[i + 1] >> 4;
+ i += 3;
+ break;
+
+ case CMD_SPU_SET_ALPHA: // transparency palette
+ palDescr[0].trans = spu[i + 2] & 0xf;
+ palDescr[1].trans = spu[i + 2] >> 4;
+ palDescr[2].trans = spu[i + 1] & 0xf;
+ palDescr[3].trans = spu[i + 1] >> 4;
+ i += 3;
+ break;
+
+ case CMD_SPU_SET_SIZE: // image coordinates
+ size.x1 = (spu[i + 1] << 4) | (spu[i + 2] >> 4);
+ size.x2 = ((spu[i + 2] & 0x0f) << 8) | spu[i + 3];
+
+ size.y1 = (spu[i + 4] << 4) | (spu[i + 5] >> 4);
+ size.y2 = ((spu[i + 5] & 0x0f) << 8) | spu[i + 6];
+
+ DEBUG("\t(%d, %d) x (%d, %d)\n",
+ size.x1, size.y1, size.x2, size.y2);
+ i += 7;
+ break;
+
+ case CMD_SPU_SET_PXD_OFFSET: // image 1 / image 2 offsets
+ fodd = spuU32(i + 1);
+ feven = spuU32(i + 3);
+ DEBUG("\todd = %d even = %d\n", fodd, feven);
+ i += 5;
+ break;
+
+ case CMD_SPU_MENU:
+ DEBUG("\tspu menu\n");
+ state = spMENU;
+
+ i++;
+ break;
+
+ default:
+ esyslog("invalid sequence in control header (%.2x)\n",
+ spu[i]);
+ assert(0);
+ i++;
+ break;
+ }
+ }
+ if (fodd != 0 && feven != 0) {
+ delete spubmp;
+ spubmp = new cDvbSpuBitmap(size, spu + fodd, spu + feven,
+ spu + feven, spu + cmdOffs());
+ }
+ } else if (!clean)
+ state = spSHOW;
+
+ if (state == spSHOW || state == spMENU)
+ Draw();
+
+ if (state == spHIDE)
+ Hide();
+
+ if (pts == 0)
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/dvbspu.h b/dvbspu.h
new file mode 100644
index 00000000..5ac2d0ac
--- /dev/null
+++ b/dvbspu.h
@@ -0,0 +1,204 @@
+/*
+ * SPU decoder for DVB devices
+ *
+ * Copyright (C) 2001.2002 Andreas Schultz <aschultz@warp10.net>
+ *
+ * This code is distributed under the terms and conditions of the
+ * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+ *
+ * parts of this file are derived from the OMS program.
+ *
+ * $Id: dvbspu.h 1.1 2002/09/08 14:17:38 kls Exp $
+ */
+
+#ifndef __DVBSPU_H
+#define __DVBSPU_H
+
+#include <inttypes.h>
+
+#include "osdbase.h"
+#include "spu.h"
+
+typedef struct sDvbSpuPalDescr {
+ uint8_t index;
+ uint8_t trans;
+
+ bool operator != (const sDvbSpuPalDescr pd) const {
+ return index != pd.index && trans != pd.trans;
+ };
+} aDvbSpuPalDescr[4];
+
+typedef struct sDvbSpuRect {
+ int x1, y1;
+ int x2, y2;
+
+ int width() {
+ return x2 - x1 + 1;
+ };
+ int height() {
+ return y2 - y1 + 1;
+ };
+
+ bool operator != (const sDvbSpuRect r) const {
+ return r.x1 != x1 || r.y1 != y1 || r.x2 != x2 || r.y2 != y2;
+ };
+}
+
+sDvbSpuRect;
+
+// --- cDvbSpuPalette----------------------------------
+
+class cDvbSpuPalette {
+ private:
+ uint32_t palette[16];
+
+ private:
+ uint32_t yuv2rgb(uint32_t yuv_color);
+
+ public:
+ void setPalette(const uint32_t * pal);
+ uint32_t getColor(uint8_t idx, uint8_t trans) const;
+};
+
+// --- cDvbSpuBitmap----------------------------------
+
+class cDvbSpuBitmap {
+
+ public:
+ private:
+ sDvbSpuRect bmpsize;
+ sDvbSpuRect minsize[4];
+ uint8_t *bmp;
+
+ private:
+ void putPixel(int xp, int yp, int len, uint8_t colorid);
+ void putFieldData(int field, uint8_t * data, uint8_t * endp);
+
+ public:
+ cDvbSpuBitmap(sDvbSpuRect size,
+ uint8_t * fodd, uint8_t * eodd,
+ uint8_t * feven, uint8_t * eeven);
+ ~cDvbSpuBitmap();
+
+ bool getMinSize(const aDvbSpuPalDescr paldescr,
+ sDvbSpuRect & size) const;
+ cBitmap *getBitmap(const aDvbSpuPalDescr paldescr,
+ const cDvbSpuPalette & pal,
+ sDvbSpuRect & size) const;
+};
+
+// --- cDvbSpuDecoder------------------------------------
+
+class cDvbSpuDecoder:public cSpuDecoder {
+ private:
+ cOsdBase * osd;
+
+ // processing state
+ uint8_t *spu;
+ bool clean;
+ bool ready;
+
+ enum spFlag { spNONE, spHIDE, spSHOW, spMENU };
+ spFlag state;
+
+ cSpuDecoder::eScaleMode scaleMode;
+
+ //highligh area
+ bool highlight;
+ sDvbSpuRect hlpsize;
+ aDvbSpuPalDescr hlpDescr;
+
+ //palette
+ cDvbSpuPalette palette;
+
+ // spu info's
+ sDvbSpuRect size;
+ aDvbSpuPalDescr palDescr;
+
+ uint16_t DCSQ_offset;
+ uint16_t prev_DCSQ_offset;
+
+ cDvbSpuBitmap *spubmp;
+ private:
+ int cmdOffs(void) {
+ return ((spu[2] << 8) | spu[3]);
+ };
+ int spuSize(void) {
+ return ((spu[0] << 8) | spu[1]);
+ };
+
+ int ScaleYcoord(int value);
+ int ScaleYres(int value);
+ void DrawBmp(sDvbSpuRect & size, cBitmap * bmp);
+
+ void Draw();
+ void Hide();
+
+ public:
+ cDvbSpuDecoder();
+ ~cDvbSpuDecoder();
+
+ int setTime(uint32_t pts);
+
+ void setScaleMode(cSpuDecoder::eScaleMode ScaleMode);
+ void setPalette(uint32_t * pal);
+ void setHighlight(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey,
+ uint32_t palette);
+ void clearHighlight(void);
+ void Empty(void);
+ void processSPU(uint32_t pts, uint8_t * buf);
+};
+
+// --- cDvbSpuPalette -------------------------------------------
+
+inline uint32_t cDvbSpuPalette::yuv2rgb(uint32_t yuv_color)
+{
+ int Y, Cb, Cr;
+ int Ey, Epb, Epr;
+ int Eg, Eb, Er;
+ uint32_t result;
+
+ Y = (yuv_color >> 16) & 0xff;
+ Cb = (yuv_color) & 0xff;
+ Cr = (yuv_color >> 8) & 0xff;
+
+ Ey = (Y - 16);
+ Epb = (Cb - 128);
+ Epr = (Cr - 128);
+ /* ITU-R 709
+ Eg = (298*Ey - 55*Epb - 137*Epr)/256;
+ Eb = (298*Ey + 543*Epb)/256;
+ Er = (298*Ey + 460*Epr)/256;
+ */
+ /* FCC ~= mediaLib */
+ Eg = (298 * Ey - 100 * Epb - 208 * Epr) / 256;
+ Eb = (298 * Ey + 516 * Epb) / 256;
+ Er = (298 * Ey + 408 * Epr) / 256;
+
+ if (Eg > 255)
+ Eg = 255;
+ if (Eg < 0)
+ Eg = 0;
+
+ if (Eb > 255)
+ Eb = 255;
+ if (Eb < 0)
+ Eb = 0;
+
+ if (Er > 255)
+ Er = 255;
+ if (Er < 0)
+ Er = 0;
+
+ result = (Eb << 16) | (Eg << 8) | Er;
+
+ return result;
+}
+
+inline uint32_t cDvbSpuPalette::getColor(uint8_t idx, uint8_t trans) const
+{
+ uint8_t t = trans == 0x0f ? 0xff : trans << 4;
+ return palette[idx] | (t << 24);
+}
+
+#endif // __DVBSPU_H
diff --git a/osdbase.h b/osdbase.h
index 39221261..605bd8e9 100644
--- a/osdbase.h
+++ b/osdbase.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: osdbase.h 1.5 2002/08/25 10:01:00 kls Exp $
+ * $Id: osdbase.h 1.6 2002/09/08 14:12:41 kls Exp $
*/
#ifndef __OSDBASE_H
@@ -50,12 +50,12 @@ private:
bool full;
protected:
typedef unsigned char tIndexes[MAXNUMCOLORS];
- void SetColor(int Index, eDvbColor Color);
- eDvbColor GetColor(int Index) { return color[Index]; }
public:
cPalette(int Bpp);
int Index(eDvbColor Color);
void Reset(void);
+ void SetColor(int Index, eDvbColor Color);
+ eDvbColor GetColor(int Index) { return Index < maxColors ? color[Index] : clrBlack; }
const eDvbColor *NewColors(int &FirstColor, int &LastColor);
// With every call this function returns a consecutive range of
// color entries that have been added since the last call. The
diff --git a/spu.c b/spu.c
new file mode 100644
index 00000000..ccdcc390
--- /dev/null
+++ b/spu.c
@@ -0,0 +1,23 @@
+/*
+ * SPU Decoder Prototype
+ *
+ * Copyright (C) 2001.2002 Andreas Schultz <aschultz@warp10.net>
+ *
+ * This code is distributed under the terms and conditions of the
+ * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+ *
+ * $Id: spu.c 1.1 2002/09/08 14:17:41 kls Exp $
+ */
+
+#include <inttypes.h>
+#include "spu.h"
+
+// -- cSpuDecoder ----------------
+/*
+cSpuDecoder::cSpuDecoder()
+{};
+*/
+
+cSpuDecoder::~cSpuDecoder()
+{
+};
diff --git a/spu.h b/spu.h
new file mode 100644
index 00000000..1ccc74b9
--- /dev/null
+++ b/spu.h
@@ -0,0 +1,38 @@
+/*
+ * SPU Decoder Prototype
+ *
+ * Copyright (C) 2001.2002 Andreas Schultz <aschultz@warp10.net>
+ *
+ * This code is distributed under the terms and conditions of the
+ * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+ *
+ * $Id: spu.h 1.1 2002/09/08 14:17:51 kls Exp $
+ */
+
+#ifndef __SPU_VDR_H
+#define __SPU_VDR_H
+
+#include <inttypes.h>
+
+// --- cSpuDecoder -------------------------------------------
+
+class cSpuDecoder {
+ public:
+ typedef enum { eSpuNormal, eSpuLetterBox, eSpuPanAndScan } eScaleMode;
+ public:
+ // cSpuDecoder();
+ virtual ~ cSpuDecoder();
+
+ virtual int setTime(uint32_t pts) = 0;
+
+ virtual void setScaleMode(cSpuDecoder::eScaleMode ScaleMode) = 0;
+ virtual void setPalette(uint32_t * pal) = 0;
+ virtual void setHighlight(uint16_t sx, uint16_t sy,
+ uint16_t ex, uint16_t ey,
+ uint32_t palette) = 0;
+ virtual void clearHighlight(void) = 0;
+ virtual void Empty(void) = 0;
+ virtual void processSPU(uint32_t pts, uint8_t * buf) = 0;
+};
+
+#endif // __SPU_VDR_H