diff options
Diffstat (limited to 'dvbosd.c')
-rw-r--r-- | dvbosd.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/dvbosd.c b/dvbosd.c new file mode 100644 index 00000000..2ab01bc3 --- /dev/null +++ b/dvbosd.c @@ -0,0 +1,175 @@ +/* + * dvbosd.c: Interface to the DVB On Screen Display + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: dvbosd.c 1.1 2000/10/03 10:10:28 kls Exp $ + */ + +#include "dvbosd.h" +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/unistd.h> +#include "tools.h" + +// --- cBitmap --------------------------------------------------------------- + +cBitmap::cBitmap(int Width, int Height) +{ + width = Width; + height = Height; + bitmap = NULL; + font = NULL; + if (width > 0 && height > 0) { + bitmap = new char[width * height]; + if (bitmap) { + Clean(); + memset(bitmap, clrTransparent, width * height); + SetFont(fontOsd); + } + else + esyslog(LOG_ERR, "ERROR: can't allocate bitmap!"); + } + else + esyslog(LOG_ERR, "ERROR: illegal bitmap parameters (%d, %d)!", width, height); +} + +cBitmap::~cBitmap() +{ + delete font; + delete bitmap; +} + +void cBitmap::SetFont(eDvbFont Font) +{ + delete font; + font = new cFont(Font); +} + +bool cBitmap::Dirty(void) +{ + return dirtyX2 >= 0; +} + +void cBitmap::Clean(void) +{ + dirtyX1 = width; + dirtyY1 = height; + dirtyX2 = -1; + dirtyY2 = -1; +} + +void cBitmap::SetPixel(int x, int y, eDvbColor Color) +{ + if (bitmap) { + if (0 <= x && x < width && 0 <= y && y < height) { + if (bitmap[width * y + x] != Color) { + bitmap[width * y + x] = Color; + if (dirtyX1 > x) dirtyX1 = x; + if (dirtyY1 > y) dirtyY1 = y; + if (dirtyX2 < x) dirtyX2 = x; + if (dirtyY2 < y) dirtyY2 = y; + } + } + } +} + +void cBitmap::Text(int x, int y, const char *s, eDvbColor ColorFg, eDvbColor ColorBg) +{ + if (bitmap) { + int h = font->Height(s); + while (s && *s) { + const cFont::tCharData *CharData = font->CharData(*s++); + for (int row = 0; row < h; row++) { + cFont::tPixelData PixelData = CharData->lines[row]; + for (int col = CharData->width; col-- > 0; ) { + SetPixel(x + col, y + row, (PixelData & 1) ? ColorFg : ColorBg); + PixelData >>= 1; + } + } + x += CharData->width; + } + } +} + +void cBitmap::Fill(int x1, int y1, int x2, int y2, eDvbColor Color) +{ + if (bitmap) { + for (int y = y1; y <= y2; y++) + for (int x = x1; x <= x2; x++) + SetPixel(x, y, Color); + } +} + +void cBitmap::Clear(void) +{ + Fill(0, 0, width - 1, height - 1, clrBackground); +} + +// --- cDvbOsd --------------------------------------------------------------- + +cDvbOsd::cDvbOsd(int VideoDev, int x1, int y1, int x2, int y2, int Bpp) +:cBitmap(x2 - x1 + 1, y2 - y1 + 1) +{ + videoDev = VideoDev; + if (videoDev >= 0) + Cmd(OSD_Open, Bpp, x1, y1, x2, y2); + else + esyslog(LOG_ERR, "ERROR: illegal video device handle (%d)!", videoDev); +} + +cDvbOsd::~cDvbOsd() +{ + if (videoDev >= 0) + Cmd(OSD_Close); +} + +void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, const void *data) +{ + if (videoDev >= 0) { + struct drawcmd dc; + dc.cmd = cmd; + dc.color = color; + dc.x0 = x0; + dc.y0 = y0; + dc.x1 = x1; + dc.y1 = y1; + dc.data = (void *)data; + ioctl(videoDev, VIDIOCSOSDCOMMAND, &dc); + usleep(10); // XXX Workaround for a driver bug (cInterface::DisplayChannel() displayed texts at wrong places + // XXX and sometimes the OSD was no longer displayed). + // XXX Increase the value if the problem still persists on your particular system. + // TODO Check if this is still necessary with driver versions after 0.7. + } +} + +void cDvbOsd::Flush(void) +{ + if (Dirty()) { + //XXX Workaround: apparently the bitmap sent to the driver always has to be a multiple + //XXX of 8 bits wide, and (dx * dy) also has to be a multiple of 8. + //TODO Fix driver (should be able to handle any size bitmaps!) + while ((dirtyX1 > 0 || dirtyX2 < width - 1) && ((dirtyX2 - dirtyX1) & 7) != 7) { + if (dirtyX2 < width - 1) + dirtyX2++; + else if (dirtyX1 > 0) + dirtyX1--; + } + while ((dirtyY1 > 0 || dirtyY2 < height - 1) && (((dirtyX2 - dirtyX1 + 1) * (dirtyY2 - dirtyY1 + 1) / 2) & 7) != 0) { + if (dirtyY2 < height - 1) + dirtyY2++; + else if (dirtyY1 > 0) + dirtyY1--; + } + while ((dirtyX1 > 0 || dirtyX2 < width - 1) && (((dirtyX2 - dirtyX1 + 1) * (dirtyY2 - dirtyY1 + 1) / 2) & 7) != 0) { + if (dirtyX2 < width - 1) + dirtyX2++; + else if (dirtyX1 > 0) + dirtyX1--; + } + Cmd(OSD_SetBlock, width, dirtyX1, dirtyY1, dirtyX2, dirtyY2, &bitmap[dirtyY1 * width + dirtyX1]); + Clean(); + } +} + |