Fixed scaling subtitles with anti-aliasing

This commit is contained in:
Klaus Schmidinger 2021-03-17 15:24:34 +01:00
parent 3d55d3045e
commit f672fe90c1
3 changed files with 75 additions and 36 deletions

View File

@ -1228,6 +1228,7 @@ Peter Bieringer <pb@bieringer.de>
external commands external commands
for making the functions cRecordingInfo::SetData() and cRecordingInfo::SetAux() public for making the functions cRecordingInfo::SetData() and cRecordingInfo::SetAux() public
for adding some missing user command calls for copying, renaming and moving recordings for adding some missing user command calls for copying, renaming and moving recordings
for fixing scaling subtitles with anti-aliasing
Alexander Damhuis <ad@phonedation.de> Alexander Damhuis <ad@phonedation.de>
for reporting problems when deleting a timer that is currently recording for reporting problems when deleting a timer that is currently recording

View File

@ -9616,3 +9616,4 @@ Video Disk Recorder Revision History
"TITLE - EPISODE" and "TITLE: EPISODE" the same. "TITLE - EPISODE" and "TITLE: EPISODE" the same.
- Decreased the scrambling timeout for CAMs known to decrypt a certain channel, so - Decreased the scrambling timeout for CAMs known to decrypt a certain channel, so
that it won't collide with MAXBROKENTIMEOUT in recorder.c. that it won't collide with MAXBROKENTIMEOUT in recorder.c.
- Fixed scaling subtitles with anti-aliasing (thanks to Peter Bieringer).

View File

@ -7,7 +7,7 @@
* Original author: Marco Schluessler <marco@lordzodiac.de> * Original author: Marco Schluessler <marco@lordzodiac.de>
* With some input from the "subtitles plugin" by Pekka Virtanen <pekka.virtanen@sci.fi> * With some input from the "subtitles plugin" by Pekka Virtanen <pekka.virtanen@sci.fi>
* *
* $Id: dvbsubtitle.c 4.2 2020/05/15 12:32:51 kls Exp $ * $Id: dvbsubtitle.c 5.1 2021/03/17 15:24:34 kls Exp $
*/ */
#include "dvbsubtitle.h" #include "dvbsubtitle.h"
@ -993,7 +993,9 @@ public:
int64_t Pts(void) const { return pts; } int64_t Pts(void) const { return pts; }
bool Pending(void) { return pending; } bool Pending(void) { return pending; }
cSubtitleObjects *Objects(void) { return &objects; } cSubtitleObjects *Objects(void) { return &objects; }
tArea *GetAreas(int &NumAreas, double FactorX, double FactorY); tArea *GetAreas(int &NumAreas);
tArea CombineAreas(int NumAreas, const tArea *Areas);
tArea ScaleArea(const tArea &Area, double FactorX, double FactorY);
cSubtitleObject *GetObjectById(int ObjectId, bool New = false); cSubtitleObject *GetObjectById(int ObjectId, bool New = false);
cSubtitleClut *GetClutById(int ClutId, bool New = false); cSubtitleClut *GetClutById(int ClutId, bool New = false);
cSubtitleRegion *GetRegionById(int RegionId, bool New = false); cSubtitleRegion *GetRegionById(int RegionId, bool New = false);
@ -1077,7 +1079,7 @@ void cDvbSubtitlePage::ParsePgs(int64_t Pts, cBitStream &bs)
pending = true; pending = true;
} }
tArea *cDvbSubtitlePage::GetAreas(int &NumAreas, double FactorX, double FactorY) tArea *cDvbSubtitlePage::GetAreas(int &NumAreas)
{ {
if (regions.Count() > 0) { if (regions.Count() > 0) {
NumAreas = regionRefs.Count(); NumAreas = regionRefs.Count();
@ -1085,13 +1087,11 @@ tArea *cDvbSubtitlePage::GetAreas(int &NumAreas, double FactorX, double FactorY)
tArea *a = Areas; tArea *a = Areas;
for (cSubtitleRegionRef *srr = regionRefs.First(); srr; srr = regionRefs.Next(srr)) { for (cSubtitleRegionRef *srr = regionRefs.First(); srr; srr = regionRefs.Next(srr)) {
if (cSubtitleRegion *sr = GetRegionById(srr->RegionId())) { if (cSubtitleRegion *sr = GetRegionById(srr->RegionId())) {
a->x1 = int(round(FactorX * srr->RegionHorizontalAddress())); a->x1 = srr->RegionHorizontalAddress();
a->y1 = int(round(FactorY * srr->RegionVerticalAddress())); a->y1 = srr->RegionVerticalAddress();
a->x2 = int(round(FactorX * (srr->RegionHorizontalAddress() + sr->RegionWidth() - 1))); a->x2 = srr->RegionHorizontalAddress() + sr->RegionWidth() - 1;
a->y2 = int(round(FactorY * (srr->RegionVerticalAddress() + sr->RegionHeight() - 1))); a->y2 = srr->RegionVerticalAddress() + sr->RegionHeight() - 1;
a->bpp = sr->RegionDepth(); a->bpp = sr->RegionDepth();
while ((a->Width() & 3) != 0)
a->x2++; // aligns width to a multiple of 4, so 2, 4 and 8 bpp will work
} }
else else
a->x1 = a->y1 = a->x2 = a->y2 = a->bpp = 0; a->x1 = a->y1 = a->x2 = a->y2 = a->bpp = 0;
@ -1103,6 +1103,37 @@ tArea *cDvbSubtitlePage::GetAreas(int &NumAreas, double FactorX, double FactorY)
return NULL; return NULL;
} }
tArea cDvbSubtitlePage::CombineAreas(int NumAreas, const tArea *Areas)
{
tArea a;
a.x1 = INT_MAX;
a.x2 = INT_MIN;
a.y1 = INT_MAX;
a.y2 = INT_MIN;
a.bpp = 1;
for (int i = 0; i < NumAreas; i++) {
a.x1 = min(a.x1, Areas[i].x1);
a.x2 = max(a.x2, Areas[i].x2);
a.y1 = min(a.y1, Areas[i].y1);
a.y2 = max(a.y2, Areas[i].y2);
a.bpp = max(a.bpp, Areas[i].bpp);
}
return a;
}
tArea cDvbSubtitlePage::ScaleArea(const tArea &Area, double FactorX, double FactorY)
{
tArea a;
a.x1 = int(round(FactorX * Area.x1) );
a.x2 = int(round(FactorX * Area.x2) - 1);
a.y1 = int(round(FactorY * Area.y1) );
a.y2 = int(round(FactorY * Area.y2) - 1);
a.bpp = Area.bpp;
while ((a.Width() & 3) != 0)
a.x2++; // aligns width to a multiple of 4, so 2, 4 and 8 bpp will work
return a;
}
cSubtitleClut *cDvbSubtitlePage::GetClutById(int ClutId, bool New) cSubtitleClut *cDvbSubtitlePage::GetClutById(int ClutId, bool New)
{ {
for (cSubtitleClut *sc = cluts.First(); sc; sc = cluts.Next(sc)) { for (cSubtitleClut *sc = cluts.First(); sc; sc = cluts.Next(sc)) {
@ -1219,11 +1250,13 @@ private:
int timeout; int timeout;
tArea *areas; tArea *areas;
int numAreas; int numAreas;
tArea areaCombined;
tArea areaOsd;
double osdFactorX; double osdFactorX;
double osdFactorY; double osdFactorY;
cVector<cBitmap *> bitmaps; cVector<cBitmap *> bitmaps;
public: public:
cDvbSubtitleBitmaps(int State, int64_t Pts, int Timeout, tArea *Areas, int NumAreas, double OsdFactorX, double OsdFactorY); cDvbSubtitleBitmaps(int State, int64_t Pts, int Timeout, tArea *Areas, int NumAreas, double OsdFactorX, double OsdFactorY, tArea &AreaCombined, tArea &AreaOsd);
~cDvbSubtitleBitmaps(); ~cDvbSubtitleBitmaps();
int State(void) { return state; } int State(void) { return state; }
int64_t Pts(void) { return pts; } int64_t Pts(void) { return pts; }
@ -1234,13 +1267,15 @@ public:
void DbgDump(int WindowWidth, int WindowHeight); void DbgDump(int WindowWidth, int WindowHeight);
}; };
cDvbSubtitleBitmaps::cDvbSubtitleBitmaps(int State, int64_t Pts, int Timeout, tArea *Areas, int NumAreas, double OsdFactorX, double OsdFactorY) cDvbSubtitleBitmaps::cDvbSubtitleBitmaps(int State, int64_t Pts, int Timeout, tArea *Areas, int NumAreas, double OsdFactorX, double OsdFactorY, tArea &AreaCombined, tArea &AreaOsd)
{ {
state = State; state = State;
pts = Pts; pts = Pts;
timeout = Timeout; timeout = Timeout;
areas = Areas; areas = Areas;
numAreas = NumAreas; numAreas = NumAreas;
areaCombined = AreaCombined;
areaOsd = AreaOsd;
osdFactorX = OsdFactorX; osdFactorX = OsdFactorX;
osdFactorY = OsdFactorY; osdFactorY = OsdFactorY;
} }
@ -1260,25 +1295,25 @@ void cDvbSubtitleBitmaps::AddBitmap(cBitmap *Bitmap)
void cDvbSubtitleBitmaps::Draw(cOsd *Osd) void cDvbSubtitleBitmaps::Draw(cOsd *Osd)
{ {
bool Scale = !(DoubleEqual(osdFactorX, 1.0) && DoubleEqual(osdFactorY, 1.0)); bool Scale = !(DoubleEqual(osdFactorX, 1.0) && DoubleEqual(osdFactorY, 1.0));
bool AntiAlias = true; bool AntiAlias = Setup.AntiAlias;
if (Scale && osdFactorX > 1.0 || osdFactorY > 1.0) { if (Scale && osdFactorX > 1.0 || osdFactorY > 1.0) {
// Upscaling requires 8bpp: // Upscaling requires 8bpp:
int Bpp[MAXOSDAREAS]; int Bpp = areaOsd.bpp;
for (int i = 0; i < numAreas; i++) { areaOsd.bpp = 8;
Bpp[i] = areas[i].bpp; if (Osd->CanHandleAreas(&areaOsd, 1) != oeOk) {
areas[i].bpp = 8; areaOsd.bpp = Bpp;
}
if (Osd->CanHandleAreas(areas, numAreas) != oeOk) {
for (int i = 0; i < numAreas; i++)
areas[i].bpp = Bpp[i];
AntiAlias = false; AntiAlias = false;
} }
} }
if (State() == 0 || Osd->SetAreas(areas, numAreas) == oeOk) { if (State() == 0 || Osd->SetAreas(&areaOsd, 1) == oeOk) {
cBitmap combined(areaCombined.Width(), areaCombined.Height(), areaCombined.bpp);
combined.SetOffset(areaCombined.x1, areaCombined.y1);
for (int i = 0; i < bitmaps.Size(); i++) { for (int i = 0; i < bitmaps.Size(); i++) {
// merge bitmaps into combined
cBitmap *b = bitmaps[i]; cBitmap *b = bitmaps[i];
Osd->DrawScaledBitmap(int(round(b->X0() * osdFactorX)), int(round(b->Y0() * osdFactorY)), *b, osdFactorX, osdFactorY, AntiAlias); combined.DrawBitmap(b->X0(), b->Y0(), *b);
} }
Osd->DrawScaledBitmap(int(round(combined.X0() * osdFactorX)), int(round(combined.Y0() * osdFactorY)), combined, osdFactorX, osdFactorY, AntiAlias);
Osd->Flush(); Osd->Flush();
} }
} }
@ -1734,25 +1769,27 @@ void cDvbSubtitleConverter::FinishPage(cDvbSubtitlePage *Page)
if (!AssertOsd()) if (!AssertOsd())
return; return;
int NumAreas; int NumAreas;
tArea *Areas = Page->GetAreas(NumAreas, osdFactorX, osdFactorY); tArea *Areas = Page->GetAreas(NumAreas);
tArea AreaCombined = Page->CombineAreas(NumAreas, Areas);
tArea AreaOsd = Page->ScaleArea(AreaCombined, osdFactorX, osdFactorY);
int Bpp = 8; int Bpp = 8;
bool Reduced = false; bool Reduced = false;
while (osd && osd->CanHandleAreas(Areas, NumAreas) != oeOk) { if (osd && NumAreas > 0) {
dbgoutput("CanHandleAreas: %d<br>\n", osd->CanHandleAreas(Areas, NumAreas)); while (osd->CanHandleAreas(&AreaOsd, 1) != oeOk) {
dbgoutput("CanHandleAreas: %d<br>\n", osd->CanHandleAreas(&AreaOsd, 1));
int HalfBpp = Bpp / 2; int HalfBpp = Bpp / 2;
if (HalfBpp >= 2) { if (HalfBpp >= 2) {
for (int i = 0; i < NumAreas; i++) { if (AreaOsd.bpp >= Bpp) {
if (Areas[i].bpp >= Bpp) { AreaOsd.bpp = HalfBpp;
Areas[i].bpp = HalfBpp;
Reduced = true; Reduced = true;
} }
}
Bpp = HalfBpp; Bpp = HalfBpp;
} }
else else
return; // unable to draw bitmaps return; // unable to draw bitmaps
} }
cDvbSubtitleBitmaps *Bitmaps = new cDvbSubtitleBitmaps(Page->PageState(), Page->Pts(), Page->PageTimeout(), Areas, NumAreas, osdFactorX, osdFactorY); }
cDvbSubtitleBitmaps *Bitmaps = new cDvbSubtitleBitmaps(Page->PageState(), Page->Pts(), Page->PageTimeout(), Areas, NumAreas, osdFactorX, osdFactorY, AreaCombined, AreaOsd);
bitmaps->Add(Bitmaps); bitmaps->Add(Bitmaps);
for (int i = 0; i < NumAreas; i++) { for (int i = 0; i < NumAreas; i++) {
if (cSubtitleRegionRef *srr = Page->GetRegionRefByIndex(i)) { if (cSubtitleRegionRef *srr = Page->GetRegionRefByIndex(i)) {