From a80915ff22ec0103fb95212b0048aa73007f87eb Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 26 Aug 2007 09:58:10 +0200 Subject: [PATCH] There can now be more than one OSD at the same time --- HISTORY | 11 ++++++++++- dvbosd.c | 60 ++++++++++++++++++++++++++++++++++++++------------------ dvbosd.h | 4 ++-- osd.c | 43 +++++++++++++++++++++++++++++----------- osd.h | 24 +++++++++++++++++------ tools.h | 8 +++++++- 6 files changed, 110 insertions(+), 40 deletions(-) diff --git a/HISTORY b/HISTORY index a09b711b..e55f4cca 100644 --- a/HISTORY +++ b/HISTORY @@ -5380,7 +5380,7 @@ Video Disk Recorder Revision History name of the plugin. The "newplugin" script has been changed accordingly, and plugin authors should change their Makefiles, too. -2007-08-25: Version 1.5.9 +2007-08-26: Version 1.5.9 - Fixed handling locale directories with a large number of entries (thanks to Anssi Hannula). @@ -5405,3 +5405,12 @@ Video Disk Recorder Revision History option ':groups' is given (thanks to Andreas Mair). - Added a missing error report to cCuttingThread::Action() (thanks to Udo Richter). +- There can now be more than one OSD at the same time. At any given time, + however, only one of them can be active (and thus visible). This is to + allow displaying things like subtitles in an easy way. A cOsd therefore + now has a "Level", and only the OSD with the smallest level will be + displayed. The level 0 OSD is special, and there can only be one with + this level. If there is more than one OSD with a particular level, only + the one that was created first will be displayed. + Plugins that provide an OSD need to adjust their cOsdProvider::CreateOsd() + function to hand through the Level. diff --git a/dvbosd.c b/dvbosd.c index 469ef1fb..87c8dec2 100644 --- a/dvbosd.c +++ b/dvbosd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.c 1.30 2006/01/28 14:24:04 kls Exp $ + * $Id: dvbosd.c 1.31 2007/08/26 09:39:20 kls Exp $ */ #include "dvbosd.h" @@ -26,15 +26,17 @@ private: int osdMem; bool shown; void Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = NULL); +protected: + virtual void SetActive(bool On); public: - cDvbOsd(int Left, int Top, int OsdDev); + cDvbOsd(int Left, int Top, int OsdDev, uint Level); virtual ~cDvbOsd(); virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas); virtual void Flush(void); }; -cDvbOsd::cDvbOsd(int Left, int Top, int OsdDev) -:cOsd(Left, Top) +cDvbOsd::cDvbOsd(int Left, int Top, int OsdDev, uint Level) +:cOsd(Left, Top, Level) { osdDev = OsdDev; shown = false; @@ -49,23 +51,36 @@ cDvbOsd::cDvbOsd(int Left, int Top, int OsdDev) if (ioctl(osdDev, OSD_GET_CAPABILITY, &cap) == 0) osdMem = cap.val; #endif - // must clear all windows here to avoid flashing effects - doesn't work if done - // in Flush() only for the windows that are actually used... - for (int i = 0; i < MAXNUMWINDOWS; i++) { - Cmd(OSD_SetWindow, 0, i + 1); - Cmd(OSD_Clear); - } } } cDvbOsd::~cDvbOsd() { - if (shown) { - cBitmap *Bitmap; - for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { - Cmd(OSD_SetWindow, 0, i + 1); - Cmd(OSD_Close); - } + SetActive(false); +} + +void cDvbOsd::SetActive(bool On) +{ + if (On != Active()) { + cOsd::SetActive(On); + if (On) { + // must clear all windows here to avoid flashing effects - doesn't work if done + // in Flush() only for the windows that are actually used... + for (int i = 0; i < MAXNUMWINDOWS; i++) { + Cmd(OSD_SetWindow, 0, i + 1); + Cmd(OSD_Clear); + } + if (GetBitmap(0)) // only flush here if there are already bitmaps + Flush(); + } + else if (shown) { + cBitmap *Bitmap; + for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { + Cmd(OSD_SetWindow, 0, i + 1); + Cmd(OSD_Close); + } + shown = false; + } } } @@ -108,13 +123,20 @@ void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, co void cDvbOsd::Flush(void) { + if (!Active()) + return; cBitmap *Bitmap; for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { Cmd(OSD_SetWindow, 0, i + 1); if (!shown) 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! int x1 = 0, y1 = 0, x2 = 0, y2 = 0; - if (Bitmap->Dirty(x1, y1, x2, y2)) { + if (!shown || Bitmap->Dirty(x1, y1, x2, y2)) { + if (!shown) { + x1 = y1 = 0; + x2 = Bitmap->Width() - 1; + y2 = Bitmap->Height() - 1; + } //TODO Workaround: apparently the bitmap sent to the driver always has to be a multiple //TODO 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!) @@ -173,7 +195,7 @@ cDvbOsdProvider::cDvbOsdProvider(int OsdDev) osdDev = OsdDev; } -cOsd *cDvbOsdProvider::CreateOsd(int Left, int Top) +cOsd *cDvbOsdProvider::CreateOsd(int Left, int Top, uint Level) { - return new cDvbOsd(Left, Top, osdDev); + return new cDvbOsd(Left, Top, osdDev, Level); } diff --git a/dvbosd.h b/dvbosd.h index 752b9fa1..ae8afb6d 100644 --- a/dvbosd.h +++ b/dvbosd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.h 1.18 2004/06/12 13:09:52 kls Exp $ + * $Id: dvbosd.h 1.19 2007/08/25 13:49:34 kls Exp $ */ #ifndef __DVBOSD_H @@ -17,7 +17,7 @@ private: int osdDev; public: cDvbOsdProvider(int OsdDev); - virtual cOsd *CreateOsd(int Left, int Top); + virtual cOsd *CreateOsd(int Left, int Top, uint Level); }; #endif //__DVBOSD_H diff --git a/osd.c b/osd.c index 96dfc2e4..1c91184d 100644 --- a/osd.c +++ b/osd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.c 1.73 2007/08/17 15:23:50 kls Exp $ + * $Id: osd.c 1.74 2007/08/26 09:44:50 kls Exp $ */ #include "osd.h" @@ -646,18 +646,24 @@ int cOsd::osdLeft = 0; int cOsd::osdTop = 0; int cOsd::osdWidth = 0; int cOsd::osdHeight = 0; -int cOsd::isOpen = 0; +cVector cOsd::Osds; -cOsd::cOsd(int Left, int Top) +cOsd::cOsd(int Left, int Top, uint Level) { - if (isOpen) - esyslog("ERROR: OSD opened without closing previous OSD!"); savedRegion = NULL; numBitmaps = 0; left = Left; top = Top; width = height = 0; - isOpen++; + level = Level; + active = false; + for (int i = 0; i < Osds.Size(); i++) { + if (Osds[i]->level > level) { + Osds.Insert(this, i); + return; + } + } + Osds.Append(this); } cOsd::~cOsd() @@ -665,7 +671,14 @@ cOsd::~cOsd() for (int i = 0; i < numBitmaps; i++) delete bitmaps[i]; delete savedRegion; - isOpen--; + for (int i = 0; i < Osds.Size(); i++) { + if (Osds[i] == this) { + Osds.Remove(i); + if (Osds.Size()) + Osds[0]->SetActive(true); + break; + } + } } void cOsd::SetOsdPosition(int Left, int Top, int Width, int Height) @@ -803,15 +816,23 @@ cOsdProvider::~cOsdProvider() osdProvider = NULL; } -cOsd *cOsdProvider::NewOsd(int Left, int Top) +cOsd *cOsdProvider::NewOsd(int Left, int Top, uint Level) { if (Level == 0 && cOsd::IsOpen()) esyslog("ERROR: attempt to open OSD while it is already open - using dummy OSD!"); - else if (osdProvider) - return osdProvider->CreateOsd(Left, Top); + else if (osdProvider) { + cOsd *ActiveOsd = cOsd::Osds.Size() ? cOsd::Osds[0] : NULL; + cOsd *Osd = osdProvider->CreateOsd(Left, Top, Level); + if (Osd == cOsd::Osds[0]) { + if (ActiveOsd) + ActiveOsd->SetActive(false); + Osd->SetActive(true); + } + return Osd; + } else esyslog("ERROR: no OSD provider available - using dummy OSD!"); - return new cOsd(Left, Top); // create a dummy cOsd, so that access won't result in a segfault + return new cOsd(Left, Top, 999); // create a dummy cOsd, so that access won't result in a segfault } void cOsdProvider::Shutdown(void) diff --git a/osd.h b/osd.h index 08bc4184..604b2d22 100644 --- a/osd.h +++ b/osd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 1.56 2007/07/20 14:50:17 kls Exp $ + * $Id: osd.h 1.57 2007/08/26 09:45:38 kls Exp $ */ #ifndef __OSD_H @@ -15,6 +15,7 @@ #include #include "config.h" #include "font.h" +#include "tools.h" #define MAXNUMCOLORS 256 @@ -247,13 +248,15 @@ class cOsd { friend class cOsdProvider; private: static int osdLeft, osdTop, osdWidth, osdHeight; - static int isOpen; + static cVector Osds; cBitmap *savedRegion; cBitmap *bitmaps[MAXOSDAREAS]; int numBitmaps; int left, top, width, height; + uint level; + bool active; protected: - cOsd(int Left, int Top); + cOsd(int Left, int Top, uint Level); ///< Initializes the OSD with the given coordinates. ///< By default it is assumed that the full area will be able to display ///< full 32 bit graphics (ARGB with eight bit for each color and the alpha @@ -269,6 +272,14 @@ protected: ///< and should require only the minimum necessary color depth. This is ///< because a derived cOsd class may or may not be able to handle more ///< than one area. + ///< There can be any number of cOsd objects at the same time, but only + ///< one of them will be active at any given time. The active OSD is the + ///< one with the lowest value of Level. If there are several cOsd objects + ///< with the same Level, the one that was created first will be active. + bool Active(void) { return active; } + virtual void SetActive(bool On) { active = On; } + ///< Sets this OSD to be the active one. + ///< A derived class must call cOsd::SetActive(On). public: virtual ~cOsd(); ///< Shuts down the OSD. @@ -281,7 +292,8 @@ public: ///< This may be useful for plugins that determine the scaling of the ///< video image and need to scale the OSD accordingly to fit on the ///< screen. - static int IsOpen(void) { return isOpen; } + static int IsOpen(void) { return Osds.Size() && Osds[0]->level == 0; } + ///< Returns true if there is currently a level 0 OSD open. int Left(void) { return left; } int Top(void) { return top; } int Width(void) { return width; } @@ -379,14 +391,14 @@ class cOsdProvider { private: static cOsdProvider *osdProvider; protected: - virtual cOsd *CreateOsd(int Left, int Top) = 0; + virtual cOsd *CreateOsd(int Left, int Top, uint Level) = 0; ///< Returns a pointer to a newly created cOsd object, which will be located ///< at the given coordinates. public: cOsdProvider(void); //XXX maybe parameter to make this one "sticky"??? (frame-buffer etc.) virtual ~cOsdProvider(); - static cOsd *NewOsd(int Left, int Top); + static cOsd *NewOsd(int Left, int Top, uint Level = 0); ///< Returns a pointer to a newly created cOsd object, which will be located ///< at the given coordinates. When the cOsd object is no longer needed, the ///< caller must delete it. If the OSD is already in use, or there is no OSD diff --git a/tools.h b/tools.h index bd77f857..28dbd5ea 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.107 2007/08/05 12:11:52 kls Exp $ + * $Id: tools.h 1.108 2007/08/25 14:16:39 kls Exp $ */ #ifndef __TOOLS_H @@ -464,6 +464,12 @@ public: Realloc(allocated * 4 / 2); // increase size by 50% data[size++] = Data; } + virtual void Remove(int Index) + { + if (Index < size - 1) + memmove(&data[Index], &data[Index + 1], (size - Index) * sizeof(T)); + size--; + } virtual void Clear(void) {} void Sort(__compar_fn_t Compare) {