diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 2c3c5f98..82f5cd0d 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -2712,6 +2712,7 @@ Johann Friedrichs for some fixes to dvbspu.[hc] for fixing a busy loop when moving editing marks for making cPalette::ClosestColor() treat fully transparent colors as "equal" + for implementing scaling of SPU bitmaps Timo Helkio for reporting a hangup when replaying a TS recording with subtitles activated diff --git a/HISTORY b/HISTORY index 4868df2f..4c337d90 100644 --- a/HISTORY +++ b/HISTORY @@ -7494,7 +7494,7 @@ Video Disk Recorder Revision History use it. - Added maximum SNR value for PCTV Systems PCTV 73ESE (thanks to Cedric Dewijs). -2013-01-17: Version 1.7.36 +2013-01-20: Version 1.7.36 - Added maximum SNR value for PCTV Systems nanoStick T2 290e (thanks to Antti Hartikainen). @@ -7529,3 +7529,4 @@ Video Disk Recorder Revision History "Resume" key in the main menu to work even after a restart of VDR. - The SVDRP command NEWT no longer checks whether a timer with the given data already exists (suggested by Malte Forkel). +- Implemented scaling of SPU bitmaps (thanks to Johann Friedrichs). diff --git a/dvbspu.c b/dvbspu.c index 25af228b..2a311e30 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.9 2011/12/10 14:39:19 kls Exp $ + * $Id: dvbspu.c 2.10 2013/01/20 10:36:58 kls Exp $ */ #include "dvbspu.h" @@ -54,6 +54,7 @@ void cDvbSpuPalette::setPalette(const uint32_t * pal) #define setMin(a, b) if (a > b) a = b #define setMax(a, b) if (a < b) a = b +// DVD SPU bitmaps cover max. 720 x 576 - this sizes the SPU bitmap #define spuXres 720 #define spuYres 576 @@ -243,6 +244,36 @@ cDvbSpuDecoder::~cDvbSpuDecoder() delete osd; } +// SPUs must be scaled if screensize is not 720x576 + +void cDvbSpuDecoder::SetSpuScaling(void) +{ + int Width = spuXres; + int Height = spuYres; + int OsdWidth = 0; + int OsdHeight = 0; + double VideoAspect; + cDevice::PrimaryDevice()->GetOsdSize(OsdWidth, OsdHeight, VideoAspect); + DEBUG("dvbspu SetSpuScaling OsdSize %d x %d\n", OsdWidth, OsdHeight); + if (!OsdWidth) { // guess correct size + if (Setup.OSDWidth <= 720 || Setup.OSDHeight <= 576) + xscaling = yscaling = 1.0; + else if (Setup.OSDWidth <= 1280 || Setup.OSDHeight <= 720) { + xscaling = 1280.0 / Width; + yscaling = 720.0 / Height; + } + else { + xscaling = 1920.0 / Width; + yscaling = 1080.0/ Height; + } + } + else { + xscaling = (double)OsdWidth / Width; + yscaling = (double)OsdHeight / Height; + } + DEBUG("dvbspu xscaling = %f yscaling = %f\n", xscaling, yscaling); +} + void cDvbSpuDecoder::processSPU(uint32_t pts, uint8_t * buf, bool AllowedShow) { setTime(pts); @@ -296,6 +327,7 @@ void cDvbSpuDecoder::setHighlight(uint16_t sx, uint16_t sy, memcpy(hlpDescr, pld, sizeof(aDvbSpuPalDescr)); highlight = true; clean = false; + Draw(); // we have to trigger Draw() here } } @@ -376,32 +408,52 @@ void cDvbSpuDecoder::Draw(void) return; } sDvbSpuRect bgsize; + sDvbSpuRect drawsize; + sDvbSpuRect bgdrawsize; cBitmap *fg = NULL; cBitmap *bg = NULL; + cBitmap *tmp = NULL; - if (highlight) - fg = spubmp->getBitmap(hlpDescr, palette, hlpsize); + SetSpuScaling(); // always set current scaling, size could have changed - if (spubmp->getMinSize(palDescr, bgsize)) - bg = spubmp->getBitmap(palDescr, palette, bgsize); + if (highlight) { + tmp = spubmp->getBitmap(hlpDescr, palette, hlpsize); + fg = tmp->Scaled(xscaling, yscaling, true); + drawsize.x1 = hlpsize.x1 * xscaling; + drawsize.y1 = hlpsize.y1 * yscaling; + drawsize.x2 = drawsize.x1 + fg->Width(); + drawsize.y2 = drawsize.y1 + fg->Height(); + } - if (!fg || !bg || !osd) + if (spubmp->getMinSize(palDescr, bgsize)) { + tmp = spubmp->getBitmap(palDescr, palette, bgsize); + bg = tmp->Scaled(xscaling, yscaling, true); + bgdrawsize.x1 = bgsize.x1 * xscaling; + bgdrawsize.y1 = bgsize.y1 * yscaling; + bgdrawsize.x2 = bgdrawsize.x1 + bg->Width(); + bgdrawsize.y2 = bgdrawsize.y1 + bg->Height(); + } + + if (osd) // always rewrite OSD Hide(); if (osd == NULL) { restricted_osd = false; osd = cOsdProvider::NewOsd(0, 0); - tArea Area = { size.x1, size.y1, size.x2, size.y2, 4}; - if (osd->CanHandleAreas(&Area, 1) != oeOk) - restricted_osd = true; + sDvbSpuRect areaSize = CalcAreaSize(drawsize, fg, bgdrawsize, bg); // combine + tArea Area = { areaSize.x1, areaSize.y1, areaSize.x2, areaSize.y2, 4 }; + if (osd->CanHandleAreas(&Area, 1) != oeOk) { + DEBUG("dvbspu CanHandleAreas (%d,%d)x(%d,%d), 4 failed\n", areaSize.x1, areaSize.y1, areaSize.x2, areaSize.y2); + 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) */ + /* reduce fg area */ if (fg) { spubmp->getMinSize(hlpDescr,hlsize); /* clip to the highligh area */ @@ -409,11 +461,15 @@ void cDvbSpuDecoder::Draw(void) setMax(hlsize.y1, hlpsize.y1); setMin(hlsize.x2, hlpsize.x2); setMin(hlsize.y2, hlpsize.y2); - if (hlsize.x1 > hlsize.x2 || hlsize.y1 > hlsize.y2) { + if (hlsize.x1 > hlsize.x2 || hlsize.y1 > hlsize.y2) hlsize.x1 = hlsize.x2 = hlsize.y1 = hlsize.y2 = 0; - } + /* resize scaled fg */ + drawsize.x1=hlsize.x1 * xscaling; + drawsize.y1=hlsize.y1 * yscaling; + drawsize.x2=hlsize.x2 * xscaling; + drawsize.y2=hlsize.y2 * yscaling; } - sDvbSpuRect areaSize = CalcAreaSize((fg && bg) ? hlpsize : hlsize, fg, bgsize, bg); + sDvbSpuRect areaSize = CalcAreaSize(drawsize, fg, bgdrawsize, bg); #define DIV(a, b) (a/b)?:1 for (int d = 1; !setarea && d <= 2; d++) { @@ -431,16 +487,11 @@ void cDvbSpuDecoder::Draw(void) /* 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)} + { bgdrawsize.x1, bgdrawsize.y1, bgdrawsize.x2, bgdrawsize.y2, DIV(CalcAreaBpp(0, bg), d) }, + { drawsize.x1, drawsize.y1, drawsize.x2, drawsize.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; - + /* there is no intersection. We can try with split areas */ if ((Area_Both[0].Width() & 7) != 0) Area_Both[0].x2 += 8 - (Area_Both[0].Width() & 7); if ((Area_Both[1].Width() & 7) != 0) @@ -451,18 +502,21 @@ void cDvbSpuDecoder::Draw(void) } } } - if (!setarea) - dsyslog("dvbspu: AreaSize (%d, %d) (%d, %d) Bpp %d", areaSize.x1, areaSize.y1, areaSize.x2, areaSize.y2, (fg && bg) ? 4 : 2 ); + if (setarea) + DEBUG("dvbspu: reduced AreaSize (%d, %d) (%d, %d) Bpp %d\n", areaSize.x1, areaSize.y1, areaSize.x2, areaSize.y2, (fg && bg) ? 4 : 2); + else + dsyslog("dvbspu: reduced AreaSize (%d, %d) (%d, %d) Bpp %d failed", 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); + osd->DrawBitmap(bgdrawsize.x1, bgdrawsize.y1, *bg); if (fg) - osd->DrawBitmap(hlpsize.x1, hlpsize.y1, *fg); + osd->DrawBitmap(drawsize.x1, drawsize.y1, *fg); delete fg; delete bg; + delete tmp; osd->Flush(); } diff --git a/dvbspu.h b/dvbspu.h index 863e4464..5c7cc0a4 100644 --- a/dvbspu.h +++ b/dvbspu.h @@ -8,13 +8,14 @@ * * parts of this file are derived from the OMS program. * - * $Id: dvbspu.h 2.5 2011/03/27 14:50:48 kls Exp $ + * $Id: dvbspu.h 2.6 2013/01/20 10:15:47 kls Exp $ */ #ifndef __DVBSPU_H #define __DVBSPU_H #include +#include "device.h" #include "osd.h" #include "spu.h" #include "thread.h" @@ -106,7 +107,8 @@ class cDvbSpuDecoder:public cSpuDecoder { enum spFlag { spNONE, spHIDE, spSHOW, spMENU }; spFlag state; - cSpuDecoder::eScaleMode scaleMode; + cSpuDecoder::eScaleMode scaleMode; + double xscaling, yscaling; //highligh area bool highlight; @@ -133,6 +135,7 @@ class cDvbSpuDecoder:public cSpuDecoder { return ((spu[0] << 8) | spu[1]); }; + void SetSpuScaling(void); sDvbSpuRect CalcAreaSize(sDvbSpuRect fgsize, cBitmap *fgbmp, sDvbSpuRect bgsize, cBitmap *bgbmp); int CalcAreaBpp(cBitmap *fgbmp, cBitmap *bgbmp);