diff --git a/HISTORY b/HISTORY index 7e9a3da8..f73f5cf2 100644 --- a/HISTORY +++ b/HISTORY @@ -6554,3 +6554,5 @@ Video Disk Recorder Revision History - Updated the Romanian OSD texts (thanks to Lucian Muresan). - Now storing the original display size when handling DVB subtitles (thanks to Reinhard Nissl). +- The original display size of subtitles is now used to scale them properly when + displaying them on an HD OSD. diff --git a/dvbsubtitle.c b/dvbsubtitle.c index 3e7ffa6b..c1a0a0c2 100644 --- a/dvbsubtitle.c +++ b/dvbsubtitle.c @@ -7,7 +7,7 @@ * Original author: Marco Schlüßler * With some input from the "subtitle plugin" by Pekka Virtanen * - * $Id: dvbsubtitle.c 2.10 2011/03/12 13:07:59 kls Exp $ + * $Id: dvbsubtitle.c 2.11 2011/03/12 15:13:03 kls Exp $ */ #include "dvbsubtitle.h" @@ -420,7 +420,7 @@ public: int PageId(void) { return pageId; } int Version(void) { return version; } int State(void) { return state; } - tArea *GetAreas(void); + tArea *GetAreas(double Factor); cSubtitleClut *GetClutById(int ClutId, bool New = false); cSubtitleObject *GetObjectById(int ObjectId); cSubtitleRegion *GetRegionById(int RegionId, bool New = false); @@ -446,16 +446,16 @@ cDvbSubtitlePage::~cDvbSubtitlePage() { } -tArea *cDvbSubtitlePage::GetAreas(void) +tArea *cDvbSubtitlePage::GetAreas(double Factor) { if (regions.Count() > 0) { tArea *Areas = new tArea[regions.Count()]; tArea *a = Areas; for (cSubtitleRegion *sr = regions.First(); sr; sr = regions.Next(sr)) { - a->x1 = sr->HorizontalAddress(); - a->y1 = sr->VerticalAddress(); - a->x2 = sr->HorizontalAddress() + sr->Width() - 1; - a->y2 = sr->VerticalAddress() + sr->Height() - 1; + a->x1 = int(round(Factor * sr->HorizontalAddress())); + a->y1 = int(round(Factor * sr->VerticalAddress())); + a->x2 = int(round(Factor * (sr->HorizontalAddress() + sr->Width() - 1))); + a->y2 = int(round(Factor * (sr->VerticalAddress() + sr->Height() - 1))); a->bpp = sr->Bpp(); while ((a->Width() & 3) != 0) a->x2++; // aligns width to a multiple of 4, so 2, 4 and 8 bpp will work @@ -616,9 +616,10 @@ private: int timeout; tArea *areas; int numAreas; + double osdFactor; cVector bitmaps; public: - cDvbSubtitleBitmaps(int64_t Pts, int Timeout, tArea *Areas, int NumAreas); + cDvbSubtitleBitmaps(int64_t Pts, int Timeout, tArea *Areas, int NumAreas, double OsdFactor); ~cDvbSubtitleBitmaps(); int64_t Pts(void) { return pts; } int Timeout(void) { return timeout; } @@ -626,12 +627,13 @@ public: void Draw(cOsd *Osd); }; -cDvbSubtitleBitmaps::cDvbSubtitleBitmaps(int64_t Pts, int Timeout, tArea *Areas, int NumAreas) +cDvbSubtitleBitmaps::cDvbSubtitleBitmaps(int64_t Pts, int Timeout, tArea *Areas, int NumAreas, double OsdFactor) { pts = Pts; timeout = Timeout; areas = Areas; numAreas = NumAreas; + osdFactor = OsdFactor; } cDvbSubtitleBitmaps::~cDvbSubtitleBitmaps() @@ -649,8 +651,14 @@ void cDvbSubtitleBitmaps::AddBitmap(cBitmap *Bitmap) void cDvbSubtitleBitmaps::Draw(cOsd *Osd) { if (Osd->SetAreas(areas, numAreas) == oeOk) { - for (int i = 0; i < bitmaps.Size(); i++) - Osd->DrawBitmap(bitmaps[i]->X0(), bitmaps[i]->Y0(), *bitmaps[i]); + for (int i = 0; i < bitmaps.Size(); i++) { + cBitmap *b = bitmaps[i]; + if (osdFactor != 1.0) + b = b->Scale(osdFactor, osdFactor); + Osd->DrawBitmap(int(round(b->X0() * osdFactor)), int(round(b->Y0() * osdFactor)), *b); + if (b != bitmaps[i]) + delete b; + } Osd->Flush(); } } @@ -670,6 +678,7 @@ cDvbSubtitleConverter::cDvbSubtitleConverter(void) displayHeight = windowHeight = 576; windowHorizontalOffset = 0; windowVerticalOffset = 0; + SetOsdData(); pages = new cList; bitmaps = new cList; Start(); @@ -703,6 +712,7 @@ void cDvbSubtitleConverter::Reset(void) displayHeight = windowHeight = 576; windowHorizontalOffset = 0; windowVerticalOffset = 0; + SetOsdData(); Unlock(); } @@ -850,9 +860,29 @@ tColor cDvbSubtitleConverter::yuv2rgb(int Y, int Cb, int Cr) return (Er << 16) | (Eg << 8) | Eb; } +void cDvbSubtitleConverter::SetOsdData(void) +{ + int OsdWidth; + int OsdHeight; + double OsdAspect; + cDevice::PrimaryDevice()->GetOsdSize(OsdWidth, OsdHeight, OsdAspect); + osdDeltaX = osdDeltaY = 0; + osdFactor = 1.0; + double fw = double(OsdWidth) / displayWidth; + double fh = double(OsdHeight) / displayHeight; + if (fw >= fh) { + osdFactor = fh; + osdDeltaX = (OsdWidth - displayWidth * osdFactor) / 2; + } + else { + osdFactor = fw; + osdDeltaY = (OsdHeight - displayHeight * osdFactor) / 2; + } +} + bool cDvbSubtitleConverter::AssertOsd(void) { - return osd || (osd = cOsdProvider::NewOsd(windowHorizontalOffset, windowVerticalOffset + Setup.SubtitleOffset, OSD_LEVEL_SUBTITLES)); + return osd || (osd = cOsdProvider::NewOsd(int(round(osdFactor * windowHorizontalOffset + osdDeltaX)), int(round(osdFactor * windowVerticalOffset + osdDeltaY)) + Setup.SubtitleOffset, OSD_LEVEL_SUBTITLES)); } int cDvbSubtitleConverter::ExtractSegment(const uchar *Data, int Length, int64_t Pts) @@ -1026,6 +1056,7 @@ int cDvbSubtitleConverter::ExtractSegment(const uchar *Data, int Length, int64_t windowVerticalOffset = (Data[15] << 8) | Data[16]; // displayWindowVerticalPositionMinimum windowHeight = ((Data[17] << 8) | Data[18]) - windowVerticalOffset + 1; // displayWindowVerticalPositionMaximum } + SetOsdData(); SetupChanged(); ddsVersionNumber = version; } @@ -1048,7 +1079,7 @@ void cDvbSubtitleConverter::FinishPage(cDvbSubtitlePage *Page) { if (!AssertOsd()) return; - tArea *Areas = Page->GetAreas(); + tArea *Areas = Page->GetAreas(osdFactor); int NumAreas = Page->regions.Count(); int Bpp = 8; bool Reduced = false; @@ -1085,7 +1116,7 @@ void cDvbSubtitleConverter::FinishPage(cDvbSubtitlePage *Page) } } } - cDvbSubtitleBitmaps *Bitmaps = new cDvbSubtitleBitmaps(Page->Pts(), Page->Timeout(), Areas, NumAreas); + cDvbSubtitleBitmaps *Bitmaps = new cDvbSubtitleBitmaps(Page->Pts(), Page->Timeout(), Areas, NumAreas, osdFactor); bitmaps->Add(Bitmaps); for (cSubtitleRegion *sr = Page->regions.First(); sr; sr = Page->regions.Next(sr)) { int posX = sr->HorizontalAddress(); diff --git a/dvbsubtitle.h b/dvbsubtitle.h index 69572b49..6e717659 100644 --- a/dvbsubtitle.h +++ b/dvbsubtitle.h @@ -6,7 +6,7 @@ * * Original author: Marco Schlüßler * - * $Id: dvbsubtitle.h 2.4 2011/03/12 13:07:59 kls Exp $ + * $Id: dvbsubtitle.h 2.5 2011/03/12 14:03:42 kls Exp $ */ #ifndef __DVBSUBTITLE_H @@ -33,9 +33,13 @@ private: int windowVerticalOffset; int windowWidth; int windowHeight; + int osdDeltaX; + int osdDeltaY; + double osdFactor; cList *pages; cList *bitmaps; tColor yuv2rgb(int Y, int Cb, int Cr); + void SetOsdData(void); bool AssertOsd(void); int ExtractSegment(const uchar *Data, int Length, int64_t Pts); void FinishPage(cDvbSubtitlePage *Page); diff --git a/osd.c b/osd.c index 4b4105ab..3a535561 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 2.16 2011/02/27 11:57:37 kls Exp $ + * $Id: osd.c 2.17 2011/03/12 15:32:33 kls Exp $ */ #include "osd.h" @@ -807,6 +807,30 @@ void cBitmap::ShrinkBpp(int NewBpp) } } +cBitmap *cBitmap::Scale(double FactorX, double FactorY) +{ + // Fixed point scaling code based on www.inversereality.org/files/bitmapscaling.pdf + // by deltener@mindtremors.com + cBitmap *b = new cBitmap(int(round(Width() * FactorX)), int(round(Height() * FactorY)), Bpp(), X0(), Y0()); + b->Replace(*this); // copy palette + int RatioX = (Width() << 16) / b->Width(); + int RatioY = (Height() << 16) / b->Height(); + tIndex *DestRow = b->bitmap; + int SourceY = 0; + for (int y = 0; y < b->Height(); y++) { + int SourceX = 0; + tIndex *SourceRow = bitmap + (SourceY >> 16) * Width(); + tIndex *Dest = DestRow; + for (int x = 0; x < b->Width(); x++) { + *Dest++ = SourceRow[SourceX >> 16]; + SourceX += RatioX; + } + SourceY += RatioY; + DestRow += b->Width(); + } + return b; +} + // --- cRect ----------------------------------------------------------------- const cRect cRect::Null; diff --git a/osd.h b/osd.h index fce9d998..ebd27979 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 2.10 2011/03/08 15:52:12 kls Exp $ + * $Id: osd.h 2.11 2011/03/12 16:06:48 kls Exp $ */ #ifndef __OSD_H @@ -273,6 +273,9 @@ public: ///< the 2^NewBpp most frequently used colors as defined in the current palette. ///< If NewBpp is not smaller than the bitmap's current color depth, ///< or if it is not one of 4bpp or 2bpp, nothing happens. + cBitmap *Scale(double FactorX, double FactorY); + ///< Creates a copy of this bitmap, scaled by the given factors. + ///< The caller must delete the returned bitmap once it is no longer used. }; struct tArea {