diff options
Diffstat (limited to 'dvbsubtitle.c')
-rw-r--r-- | dvbsubtitle.c | 120 |
1 files changed, 75 insertions, 45 deletions
diff --git a/dvbsubtitle.c b/dvbsubtitle.c index 5494374..c1a0a0c 100644 --- a/dvbsubtitle.c +++ b/dvbsubtitle.c @@ -7,7 +7,7 @@ * Original author: Marco Schlüßler <marco@lordzodiac.de> * With some input from the "subtitle plugin" by Pekka Virtanen <pekka.virtanen@sci.fi> * - * $Id: dvbsubtitle.c 2.7 2010/08/29 14:08:23 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 @@ -570,12 +570,17 @@ void cDvbSubtitleAssembler::Reset(void) bool cDvbSubtitleAssembler::Realloc(int Size) { if (Size > size) { - size = max(Size, 2048); - data = (uchar *)realloc(data, size); - if (!data) { + Size = max(Size, 2048); + if (uchar *NewBuffer = (uchar *)realloc(data, Size)) { + size = Size; + data = NewBuffer; + } + else { esyslog("ERROR: can't allocate memory for subtitle assembler"); length = 0; size = 0; + free(data); + data = NULL; return false; } } @@ -611,9 +616,10 @@ private: int timeout; tArea *areas; int numAreas; + double osdFactor; cVector<cBitmap *> 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; } @@ -621,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() @@ -644,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(); } } @@ -661,10 +674,11 @@ cDvbSubtitleConverter::cDvbSubtitleConverter(void) osd = NULL; frozen = false; ddsVersionNumber = -1; - displayWidth = 720; - displayHeight = 576; - displayHorizontalOffset = 0; - displayVerticalOffset = 0; + displayWidth = windowWidth = 720; + displayHeight = windowHeight = 576; + windowHorizontalOffset = 0; + windowVerticalOffset = 0; + SetOsdData(); pages = new cList<cDvbSubtitlePage>; bitmaps = new cList<cDvbSubtitleBitmaps>; Start(); @@ -694,10 +708,11 @@ void cDvbSubtitleConverter::Reset(void) DELETENULL(osd); frozen = false; ddsVersionNumber = -1; - displayWidth = 720; - displayHeight = 576; - displayHorizontalOffset = 0; - displayVerticalOffset = 0; + displayWidth = windowWidth = 720; + displayHeight = windowHeight = 576; + windowHorizontalOffset = 0; + windowVerticalOffset = 0; + SetOsdData(); Unlock(); } @@ -781,7 +796,7 @@ int cDvbSubtitleConverter::Convert(const uchar *Data, int Length) return 0; } -#define LimitTo32Bit(n) (n & 0x00000000FFFFFFFFL) +#define LimitTo32Bit(n) ((n) & 0x00000000FFFFFFFFL) #define MAXDELTA 40000 // max. reasonable PTS/STC delta in ms void cDvbSubtitleConverter::Action(void) @@ -801,17 +816,11 @@ void cDvbSubtitleConverter::Action(void) Lock(); if (cDvbSubtitleBitmaps *sb = bitmaps->First()) { int64_t STC = cDevice::PrimaryDevice()->GetSTC(); - int64_t Delta = 0; - if (STC >= 0) { - Delta = LimitTo32Bit(sb->Pts()) - LimitTo32Bit(STC); // some devices only deliver 32 bits - if (Delta > (int64_t(1) << 31)) - Delta -= (int64_t(1) << 32); - else if (Delta < -((int64_t(1) << 31) - 1)) - Delta += (int64_t(1) << 32); - } - else { - //TODO sync on PTS? are there actually devices that don't deliver an STC? - } + int64_t Delta = LimitTo32Bit(sb->Pts()) - LimitTo32Bit(STC); // some devices only deliver 32 bits + if (Delta > (int64_t(1) << 31)) + Delta -= (int64_t(1) << 32); + else if (Delta < -((int64_t(1) << 31) - 1)) + Delta += (int64_t(1) << 32); Delta /= 90; // STC and PTS are in 1/90000s if (Delta <= MAXDELTA) { if (Delta <= 0) { @@ -851,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(displayHorizontalOffset, displayVerticalOffset + 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) @@ -1017,16 +1046,17 @@ int cDvbSubtitleConverter::ExtractSegment(const uchar *Data, int Length, int64_t int version = (Data[6] & 0xF0) >> 4; if (version != ddsVersionNumber) { int displayWindowFlag = (Data[6] & 0x08) >> 3; - displayHorizontalOffset = 0; - displayVerticalOffset = 0; - displayWidth = ((Data[7] << 8) | Data[8]) + 1; - displayHeight = ((Data[9] << 8) | Data[10]) + 1; + windowHorizontalOffset = 0; + windowVerticalOffset = 0; + displayWidth = windowWidth = ((Data[7] << 8) | Data[8]) + 1; + displayHeight = windowHeight = ((Data[9] << 8) | Data[10]) + 1; if (displayWindowFlag) { - displayHorizontalOffset = (Data[11] << 8) | Data[12]; // displayWindowHorizontalPositionMinimum - displayWidth = ((Data[13] << 8) | Data[14]) - displayHorizontalOffset + 1; // displayWindowHorizontalPositionMaximum - displayVerticalOffset = (Data[15] << 8) | Data[16]; // displayWindowVerticalPositionMinimum - displayHeight = ((Data[17] << 8) | Data[18]) - displayVerticalOffset + 1; // displayWindowVerticalPositionMaximum + windowHorizontalOffset = (Data[11] << 8) | Data[12]; // displayWindowHorizontalPositionMinimum + windowWidth = ((Data[13] << 8) | Data[14]) - windowHorizontalOffset + 1; // displayWindowHorizontalPositionMaximum + windowVerticalOffset = (Data[15] << 8) | Data[16]; // displayWindowVerticalPositionMinimum + windowHeight = ((Data[17] << 8) | Data[18]) - windowVerticalOffset + 1; // displayWindowVerticalPositionMaximum } + SetOsdData(); SetupChanged(); ddsVersionNumber = version; } @@ -1049,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; @@ -1086,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(); |