vdr-1.4.7/dvbosd.c

Go to the documentation of this file.
00001 /*
00002  * dvbosd.c: Implementation of the DVB On Screen Display
00003  *
00004  * See the main source file 'vdr.c' for copyright information and
00005  * how to reach the author.
00006  *
00007  * $Id: dvbosd.c 1.30 2006/01/28 14:24:04 kls Exp $
00008  */
00009 
00010 #include "dvbosd.h"
00011 #include <linux/dvb/osd.h>
00012 #include <signal.h>
00013 #include <sys/ioctl.h>
00014 #include <sys/unistd.h>
00015 #include "dvbdevice.h"
00016 #include "tools.h"
00017 
00018 // --- cDvbOsd ---------------------------------------------------------------
00019 
00020 #define MAXNUMWINDOWS 7 // OSD windows are counted 1...7
00021 #define MAXOSDMEMORY  92000 // number of bytes available to the OSD (for unmodified DVB cards)
00022 
00023 class cDvbOsd : public cOsd {
00024 private:
00025   int osdDev;
00026   int osdMem;
00027   bool shown;
00028   void Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = NULL);
00029 public:
00030   cDvbOsd(int Left, int Top, int OsdDev);
00031   virtual ~cDvbOsd();
00032   virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas);
00033   virtual void Flush(void);
00034   };
00035 
00036 cDvbOsd::cDvbOsd(int Left, int Top, int OsdDev)
00037 :cOsd(Left, Top)
00038 {
00039   osdDev = OsdDev;
00040   shown = false;
00041   if (osdDev < 0)
00042      esyslog("ERROR: invalid OSD device handle (%d)!", osdDev);
00043   else {
00044      osdMem = MAXOSDMEMORY;
00045 #ifdef OSD_CAP_MEMSIZE
00046      // modified DVB cards may have more OSD memory:
00047      osd_cap_t cap;
00048      cap.cmd = OSD_CAP_MEMSIZE;
00049      if (ioctl(osdDev, OSD_GET_CAPABILITY, &cap) == 0)
00050         osdMem = cap.val;
00051 #endif
00052      // must clear all windows here to avoid flashing effects - doesn't work if done
00053      // in Flush() only for the windows that are actually used...
00054      for (int i = 0; i < MAXNUMWINDOWS; i++) {
00055          Cmd(OSD_SetWindow, 0, i + 1);
00056          Cmd(OSD_Clear);
00057          }
00058      }
00059 }
00060 
00061 cDvbOsd::~cDvbOsd()
00062 {
00063   if (shown) {
00064      cBitmap *Bitmap;
00065      for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) {
00066          Cmd(OSD_SetWindow, 0, i + 1);
00067          Cmd(OSD_Close);
00068          }
00069      }
00070 }
00071 
00072 eOsdError cDvbOsd::CanHandleAreas(const tArea *Areas, int NumAreas)
00073 {
00074   eOsdError Result = cOsd::CanHandleAreas(Areas, NumAreas);
00075   if (Result == oeOk) {
00076      if (NumAreas > MAXNUMWINDOWS)
00077         return oeTooManyAreas;
00078      int TotalMemory = 0;
00079      for (int i = 0; i < NumAreas; i++) {
00080          if (Areas[i].bpp != 1 && Areas[i].bpp != 2 && Areas[i].bpp != 4 && Areas[i].bpp != 8)
00081             return oeBppNotSupported;
00082          if ((Areas[i].Width() & (8 / Areas[i].bpp - 1)) != 0)
00083             return oeWrongAlignment;
00084          if (Areas[i].Width() < 1 || Areas[i].Height() < 1 || Areas[i].Width() > 720 || Areas[i].Height() > 576)
00085             return oeWrongAreaSize;
00086          TotalMemory += Areas[i].Width() * Areas[i].Height() / (8 / Areas[i].bpp);
00087          }
00088      if (TotalMemory > osdMem)
00089         return oeOutOfMemory;
00090      }
00091   return Result;
00092 }
00093 
00094 void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, const void *data)
00095 {
00096   if (osdDev >= 0) {
00097      osd_cmd_t dc;
00098      dc.cmd   = cmd;
00099      dc.color = color;
00100      dc.x0    = x0;
00101      dc.y0    = y0;
00102      dc.x1    = x1;
00103      dc.y1    = y1;
00104      dc.data  = (void *)data;
00105      ioctl(osdDev, OSD_SEND_CMD, &dc);
00106      }
00107 }
00108 
00109 void cDvbOsd::Flush(void)
00110 {
00111   cBitmap *Bitmap;
00112   for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) {
00113       Cmd(OSD_SetWindow, 0, i + 1);
00114       if (!shown)
00115          Cmd(OSD_Open, Bitmap->Bpp(), Left() + Bitmap->X0(), Top() + Bitmap->Y0(), Left() + Bitmap->X0() + Bitmap->Width() - 1, Top() + Bitmap->Y0() + Bitmap->Height() - 1, (void *)1); // initially hidden!
00116       int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
00117       if (Bitmap->Dirty(x1, y1, x2, y2)) {
00118          //TODO Workaround: apparently the bitmap sent to the driver always has to be a multiple
00119          //TODO of 8 bits wide, and (dx * dy) also has to be a multiple of 8.
00120          //TODO Fix driver (should be able to handle any size bitmaps!)
00121          while ((x1 > 0 || x2 < Bitmap->Width() - 1) && ((x2 - x1) & 7) != 7) {
00122                if (x2 < Bitmap->Width() - 1)
00123                   x2++;
00124                else if (x1 > 0)
00125                   x1--;
00126                }
00127          //TODO "... / 2" <==> Bpp???
00128          while ((y1 > 0 || y2 < Bitmap->Height() - 1) && (((x2 - x1 + 1) * (y2 - y1 + 1) / 2) & 7) != 0) {
00129                if (y2 < Bitmap->Height() - 1)
00130                   y2++;
00131                else if (y1 > 0)
00132                   y1--;
00133                }
00134          while ((x1 > 0 || x2 < Bitmap->Width() - 1) && (((x2 - x1 + 1) * (y2 - y1 + 1) / 2) & 7) != 0) {
00135                if (x2 < Bitmap->Width() - 1)
00136                   x2++;
00137                else if (x1 > 0)
00138                   x1--;
00139                }
00140          // commit colors:
00141          int NumColors;
00142          const tColor *Colors = Bitmap->Colors(NumColors);
00143          if (Colors) {
00144             //TODO this should be fixed in the driver!
00145             tColor colors[NumColors];
00146             for (int i = 0; i < NumColors; i++) {
00147                 // convert AARRGGBB to AABBGGRR (the driver expects the colors the wrong way):
00148                 colors[i] = (Colors[i] & 0xFF000000) | ((Colors[i] & 0x0000FF) << 16) | (Colors[i] & 0x00FF00) | ((Colors[i] & 0xFF0000) >> 16);
00149                 }
00150             Colors = colors;
00151             //TODO end of stuff that should be fixed in the driver
00152             Cmd(OSD_SetPalette, 0, NumColors - 1, 0, 0, 0, Colors);
00153             }
00154          // commit modified data:
00155          Cmd(OSD_SetBlock, Bitmap->Width(), x1, y1, x2, y2, Bitmap->Data(x1, y1));
00156          }
00157       Bitmap->Clean();
00158       }
00159   if (!shown) {
00160      // Showing the windows in a separate loop to avoid seeing them come up one after another
00161      for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) {
00162          Cmd(OSD_SetWindow, 0, i + 1);
00163          Cmd(OSD_MoveWindow, 0, Left() + Bitmap->X0(), Top() + Bitmap->Y0());
00164          }
00165      shown = true;
00166      }
00167 }
00168 
00169 // --- cDvbOsdProvider -------------------------------------------------------
00170 
00171 cDvbOsdProvider::cDvbOsdProvider(int OsdDev)
00172 {
00173   osdDev = OsdDev;
00174 }
00175 
00176 cOsd *cDvbOsdProvider::CreateOsd(int Left, int Top)
00177 {
00178   return new cDvbOsd(Left, Top, osdDev);
00179 }

Generated on Tue Nov 6 19:57:52 2007 for VDR by  doxygen 1.5.3-20071008