There can now be more than one OSD at the same time

This commit is contained in:
Klaus Schmidinger 2007-08-26 09:58:10 +02:00
parent 6a737033ad
commit a80915ff22
6 changed files with 110 additions and 40 deletions

11
HISTORY
View File

@ -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.

View File

@ -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);
}

View File

@ -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

43
osd.c
View File

@ -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 *> 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)

24
osd.h
View File

@ -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 <stdint.h>
#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<cOsd *> 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

View File

@ -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)
{