From 1b973fd8ebb0a5dca7c82fac0651c33ecb7edd50 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sat, 5 Dec 2009 14:45:07 +0100 Subject: [PATCH] Improved SPU handling on devices with limited OSD capabilities --- CONTRIBUTORS | 3 ++ HISTORY | 2 + dvbspu.c | 122 +++++++++++++++++++++++++++++++++++++++++---------- dvbspu.h | 5 ++- 4 files changed, 108 insertions(+), 24 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 09936aa2..07687752 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -2514,3 +2514,6 @@ Milan Hrala Andreas Schaefers for adding the audio id to the call of PlayAudio() in cDevice::PlayTsAudio() + +Matthieu Castet + for improving SPU handling on devices with limited OSD capabilities diff --git a/HISTORY b/HISTORY index da683a93..1a07bdfe 100644 --- a/HISTORY +++ b/HISTORY @@ -6207,3 +6207,5 @@ Video Disk Recorder Revision History cPatPmtGenerator::GeneratePmt(), because VDR doesn't record the PCR pid. - Updated the Estonian OSD texts (thanks to Arthur Konovalov). - The 'sky' plugin is no longer part of the VDR source. +- Improved SPU handling on devices with limited OSD capabilities (thanks to + Matthieu Castet). diff --git a/dvbspu.c b/dvbspu.c index 76ed4056..11bd6bb0 100644 --- a/dvbspu.c +++ b/dvbspu.c @@ -8,7 +8,7 @@ * * parts of this file are derived from the OMS program. * - * $Id: dvbspu.c 2.2 2009/11/22 14:17:59 kls Exp $ + * $Id: dvbspu.c 2.3 2009/12/05 14:41:40 kls Exp $ */ #include "dvbspu.h" @@ -340,6 +340,35 @@ sDvbSpuRect cDvbSpuDecoder::CalcAreaSize(sDvbSpuRect fgsize, cBitmap *fgbmp, sDv return size; } +int cDvbSpuBitmap::getMinBpp(const aDvbSpuPalDescr paldescr) +{ + int col = 1; + for (int i = 0; i < 4; i++) { + if (paldescr[i].trans != 0) { + col++; + } + } + return col > 2 ? 2 : 1; +} + +int cDvbSpuDecoder::CalcAreaBpp(cBitmap *fgbmp, cBitmap *bgbmp) +{ + int fgbpp = 0; + int bgbpp = 0; + int ret; + if (fgbmp) { + fgbpp = spubmp->getMinBpp(hlpDescr); + } + if (bgbmp) { + bgbpp = spubmp->getMinBpp(palDescr); + } + ret = fgbpp + bgbpp; + if (ret > 2) + ret = 4; + return ret; +} + + void cDvbSpuDecoder::Draw(void) { cMutexLock MutexLock(&mutex); @@ -347,43 +376,89 @@ void cDvbSpuDecoder::Draw(void) Hide(); return; } - + sDvbSpuRect bgsize; cBitmap *fg = NULL; cBitmap *bg = NULL; - sDvbSpuRect bgsize; - sDvbSpuRect hlsize; - - hlsize.x1 = hlpsize.x1; - hlsize.y1 = hlpsize.y1; - hlsize.x2 = hlpsize.x2; - hlsize.y2 = hlpsize.y2; if (highlight) - fg = spubmp->getBitmap(hlpDescr, palette, hlsize); + fg = spubmp->getBitmap(hlpDescr, palette, hlpsize); if (spubmp->getMinSize(palDescr, bgsize)) bg = spubmp->getBitmap(palDescr, palette, bgsize); - sDvbSpuRect areaSize = CalcAreaSize(hlsize, fg, bgsize, bg); + if (osd == NULL) { + restricted_osd = false; + osd = cOsdProvider::NewOsd(0, 0); - if (!fg || !bg || !osd) { - Hide(); - } + tArea Area = { size.x1, size.y1, size.x2, size.y2, 4}; + if (osd->CanHandleAreas(&Area, 1) != oeOk) + restricted_osd = true; + else + osd->SetAreas(&Area, 1); + } + if (restricted_osd) { + sDvbSpuRect hlsize; + bool setarea = false; + /* reduce fg area (only valid if there is no bg below) */ + if (fg) { + spubmp->getMinSize(hlpDescr,hlsize); + /* clip to the highligh area */ + setMax(hlsize.x1, hlpsize.x1); + setMax(hlsize.y1, hlpsize.y1); + setMin(hlsize.x2, hlpsize.x2); + setMin(hlsize.y2, hlpsize.y2); + if (hlsize.x1 > hlsize.x2 || hlsize.y1 > hlsize.y2) { + hlsize.x1 = hlsize.x2 = hlsize.y1 = hlsize.y2 = 0; + } + } + sDvbSpuRect areaSize = CalcAreaSize((fg && bg) ? hlpsize : hlsize, fg, bgsize, bg); - if (bg || fg) { - if (osd == NULL) { - osd = cOsdProvider::NewOsd(0, 0); - if ((areaSize.width() & 3) != 0) - areaSize.x2 += 4 - (areaSize.width() & 3); - tArea Area = { areaSize.x1, areaSize.y1, areaSize.x2, areaSize.y2, (fg && bg) ? 4 : 2 }; - if (osd->SetAreas(&Area, 1) != oeOk) +#define DIV(a, b) (a/b)?:1 + for (int d = 1; !setarea && d <= 2; d++) { + + /* first try old behaviour */ + tArea Area = { areaSize.x1, areaSize.y1, areaSize.x2, areaSize.y2, DIV(CalcAreaBpp(fg, bg), d) }; + + if ((Area.Width() & 7) != 0) + Area.x2 += 8 - (Area.Width() & 7); + + if (osd->CanHandleAreas(&Area, 1) == oeOk && + osd->SetAreas(&Area, 1) == oeOk) + setarea = true; + + /* second try to split area if there is both area */ + if (!setarea && fg && bg) { + tArea Area_Both [2] = { + {bgsize.x1, bgsize.y1, bgsize.x2, bgsize.y2, DIV(CalcAreaBpp(0, bg), d)}, + {hlpsize.x1, hlpsize.y1, hlpsize.x2, hlpsize.y2, DIV(CalcAreaBpp(fg, 0), d)} + }; + if (!Area_Both[0].Intersects(Area_Both[1])) { + /* there is no intersection. We can reduce hl */ + Area_Both[1].x1 = hlsize.x1; + Area_Both[1].y1 = hlsize.y1; + Area_Both[1].x2 = hlsize.x2; + Area_Both[1].y2 = hlsize.y2; + + if ((Area_Both[0].Width() & 7) != 0) + Area_Both[0].x2 += 8 - (Area_Both[0].Width() & 7); + if ((Area_Both[1].Width() & 7) != 0) + Area_Both[1].x2 += 8 - (Area_Both[1].Width() & 7); + if (osd->CanHandleAreas(Area_Both, 2) == oeOk && + osd->SetAreas(Area_Both, 2) == oeOk) + setarea = true; + } + } + } + if (!setarea) dsyslog("dvbspu: AreaSize (%d, %d) (%d, %d) Bpp %d", areaSize.x1, areaSize.y1, areaSize.x2, areaSize.y2, (fg && bg) ? 4 : 2 ); - } + } + /* we could draw use DrawPixel on osd */ + if (bg || fg) { if (bg) osd->DrawBitmap(bgsize.x1, bgsize.y1, *bg); if (fg) - osd->DrawBitmap(hlsize.x1, hlsize.y1, *fg); + osd->DrawBitmap(hlpsize.x1, hlpsize.y1, *fg); delete fg; delete bg; @@ -514,6 +589,7 @@ int cDvbSpuDecoder::setTime(uint32_t pts) } } if (fodd != 0 && feven != 0) { + Hide(); delete spubmp; spubmp = new cDvbSpuBitmap(size, spu + fodd, spu + feven, spu + feven, spu + cmdOffs()); diff --git a/dvbspu.h b/dvbspu.h index 685681be..42aa7f08 100644 --- a/dvbspu.h +++ b/dvbspu.h @@ -8,7 +8,7 @@ * * parts of this file are derived from the OMS program. * - * $Id: dvbspu.h 2.1 2009/05/09 16:26:45 kls Exp $ + * $Id: dvbspu.h 2.2 2009/12/05 14:40:08 kls Exp $ */ #ifndef __DVBSPU_H @@ -80,6 +80,7 @@ class cDvbSpuBitmap { bool getMinSize(const aDvbSpuPalDescr paldescr, sDvbSpuRect & size) const; + int getMinBpp(const aDvbSpuPalDescr paldescr); cBitmap *getBitmap(const aDvbSpuPalDescr paldescr, const cDvbSpuPalette & pal, sDvbSpuRect & size) const; @@ -97,6 +98,7 @@ class cDvbSpuDecoder:public cSpuDecoder { uint32_t spupts; bool clean; bool ready; + bool restricted_osd; enum spFlag { spNONE, spHIDE, spSHOW, spMENU }; spFlag state; @@ -129,6 +131,7 @@ class cDvbSpuDecoder:public cSpuDecoder { }; sDvbSpuRect CalcAreaSize(sDvbSpuRect fgsize, cBitmap *fgbmp, sDvbSpuRect bgsize, cBitmap *bgbmp); + int CalcAreaBpp(cBitmap *fgbmp, cBitmap *bgbmp); public: cDvbSpuDecoder();