vdr/dvbosd.c
Klaus Schmidinger a69b3211dc Version 0.67
- The EIT information is now gathered in a separate thread.
- The sytem time can now be synchronized to the time broadcast in the DVB data
  stream. This can be enabled in the "Setup" menu by setting "SetSystemTime" to
  1.  Note that this works only if VDR is running under a user id that has
  permisson to set the system time.
- The new item "Schedule" in the "Main" menu opens VDR's EPG (thanks to Robert
  Schneider). See the MANUAL file for a detailed description.
- The new setup parameters MarginStart and MarginStop define how long (in
  minutes) before the official start time of a broadcast VDR shall begin
  recording, and how long after the official end time it shall stop recording.
  These are used when a recording is programmed from the "Schedules" menu.
- The delay value in the dvb.c.071.diff patch to the driver has been increased
  to '3', because on some systems the OSD was not displayed correctly. If you
  are running an already patched version 0.71 driver and encounter problems
  with the OSD, please make sure the parameter in the ddelay call is '3', not
  '2'.
- Fixed initializing the RCU remote control code (didn't work after switching
  on the system).
- Problematic characters in recording names (which can come from timers that
  are programmed via the "Schedules" menu) are now replaced by suitable
  substitutes.
2000-11-01 18:00:00 +01:00

189 lines
5.1 KiB
C

/*
* 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.4 2000/11/01 09:13:32 kls Exp $
*/
#include "dvbosd.h"
#include <signal.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;
}
}
}
}
int cBitmap::Width(unsigned char c)
{
return font ? font->Width(c) : -1;
}
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++);
if (int(x + CharData->width) > width)
break;
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;
// must block all signals, otherwise the command might not be fully executed
sigset_t set, oldset;
sigfillset(&set);
sigprocmask(SIG_BLOCK, &set, &oldset);
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.
sigprocmask(SIG_SETMASK, &oldset, NULL);
}
}
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();
}
}