14 #define __STDC_FORMAT_MACROS // Required for format specifiers
21 #define PAGE_COMPOSITION_SEGMENT 0x10
22 #define REGION_COMPOSITION_SEGMENT 0x11
23 #define CLUT_DEFINITION_SEGMENT 0x12
24 #define OBJECT_DATA_SEGMENT 0x13
25 #define DISPLAY_DEFINITION_SEGMENT 0x14
26 #define DISPARITY_SIGNALING_SEGMENT 0x15 // DVB BlueBook A156
27 #define END_OF_DISPLAY_SET_SEGMENT 0x80
28 #define STUFFING_SEGMENT 0xFF
38 #define dbgconverter(a...) if (DebugConverter) fprintf(stderr, a)
39 #define dbgsegments(a...) if (DebugSegments) fprintf(stderr, a)
40 #define dbgpages(a...) if (DebugPages) fprintf(stderr, a)
41 #define dbgregions(a...) if (DebugRegions) fprintf(stderr, a)
42 #define dbgobjects(a...) if (DebugObjects) fprintf(stderr, a)
43 #define dbgcluts(a...) if (DebugCluts) fprintf(stderr, a)
68 int a = 0, r = 0, g = 0, b = 0;
78 for (
int i = 1; i < 16; ++i) {
80 r = (i & 1) ? 255 : 0;
81 g = (i & 2) ? 255 : 0;
82 b = (i & 4) ? 255 : 0;
85 r = (i & 1) ? 127 : 0;
86 g = (i & 2) ? 127 : 0;
87 b = (i & 4) ? 127 : 0;
93 for (
int i = 1; i < 256; ++i) {
95 r = (i & 1) ? 255 : 0;
96 g = (i & 2) ? 255 : 0;
97 b = (i & 4) ? 255 : 0;
103 r = ((i & 1) ? 85 : 0) + ((i & 0x10) ? 170 : 0);
104 g = ((i & 2) ? 85 : 0) + ((i & 0x20) ? 170 : 0);
105 b = ((i & 4) ? 85 : 0) + ((i & 0x40) ? 170 : 0);
109 r = ((i & 1) ? 85 : 0) + ((i & 0x10) ? 170 : 0);
110 g = ((i & 2) ? 85 : 0) + ((i & 0x20) ? 170 : 0);
111 b = ((i & 4) ? 85 : 0) + ((i & 0x40) ? 170 : 0);
115 r = 127 + ((i & 1) ? 43 : 0) + ((i & 0x10) ? 85 : 0);
116 g = 127 + ((i & 2) ? 43 : 0) + ((i & 0x20) ? 85 : 0);
117 b = 127 + ((i & 4) ? 43 : 0) + ((i & 0x40) ? 85 : 0);
121 r = ((i & 1) ? 43 : 0) + ((i & 0x10) ? 85 : 0);
122 g = ((i & 2) ? 43 : 0) + ((i & 0x20) ? 85 : 0);
123 b = ((i & 4) ? 43 : 0) + ((i & 0x40) ? 85 : 0);
138 default:
esyslog(
"ERROR: wrong Bpp in cSubtitleClut::SetColor(%d, %d, %08X)", Bpp, Index, Color);
148 default:
esyslog(
"ERROR: wrong Bpp in cSubtitleClut::GetPalette(%d)", Bpp);
180 int X(
void) {
return px; }
181 int Y(
void) {
return py; }
210 if (NumberOfCodes > 0) {
212 const uchar *from = &Data[1];
213 int len = NumberOfCodes * 2 - 1;
216 char txt[NumberOfCodes + 1];
218 for (
int i = 2; i < NumberOfCodes; ++i) {
219 uchar c = Data[i * 2 + 1] & 0xFF;
222 if (
' ' <= c && c <=
'~' || c ==
'\n' || 0xA0 <= c)
228 const char *s = conv.
Convert(txt);
240 int y = Even ? 0 : 1;
241 uint8_t map2to4[ 4] = { 0x00, 0x07, 0x08, 0x0F };
242 uint8_t map2to8[ 4] = { 0x00, 0x77, 0x88, 0xFF };
243 uint8_t map4to8[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
244 const uint8_t *mapTable = NULL;
246 while (!bs.
IsEOF()) {
251 case 8: mapTable = map2to8;
break;
252 case 4: mapTable = map2to4;
break;
253 default: mapTable = NULL;
break;
262 case 8: mapTable = map4to8;
break;
263 default: mapTable = NULL;
break;
283 for (
int i = 0; i < 4; ++i)
288 for (
int i = 0; i < 16; ++i)
296 default:
dbgobjects(
"unknown sub block %s %d\n", __FUNCTION__, __LINE__);
307 for (
int pos = x; pos < x + Length; pos++)
345 color = MapTable[color];
360 else if (bs->
GetBit() == 0) {
367 else if (bs->
GetBit() == 0) {
390 color = MapTable[color];
468 for (
int y = 0; y <
Height(); y++) {
469 for (
int x = 0; x <
Width(); x++)
478 if (so->ObjectId() == ObjectId)
481 if (!result && New) {
496 tmp.DrawText(0, 0, so->TextData(), palette->Color(so->ForegroundPixelCode()), palette->Color(so->BackgroundPixelCode()), font);
507 if (Level > 0 && Level < 4)
513 if (Depth > 0 && Depth < 4)
565 a->
x1 = int(round(FactorX * sr->HorizontalAddress()));
566 a->
y1 = int(round(FactorY * sr->VerticalAddress()));
567 a->
x2 = int(round(FactorX * (sr->HorizontalAddress() + sr->Width() - 1)));
568 a->
y2 = int(round(FactorY * (sr->VerticalAddress() + sr->Height() - 1)));
570 while ((a->
Width() & 3) != 0)
583 if (sc->ClutId() == ClutId)
586 if (!result && New) {
597 if (sr->RegionId() == RegionId)
600 if (!result && New) {
611 result = sr->GetObjectById(ObjectId);
633 default:
dbgpages(
"unknown page state (%s %d)\n", __FUNCTION__, __LINE__);
650 unsigned char *
Get(
int &Length);
651 void Put(
const uchar *Data,
int Length);
675 Size =
max(Size, 2048);
681 esyslog(
"ERROR: can't allocate memory for subtitle assembler");
697 unsigned char *result =
data +
pos;
758 bool AntiAlias =
true;
762 for (
int i = 0; i <
numAreas; i++) {
768 Bpp[i] =
areas[i].bpp = Bpp[i];
821 dbgconverter(
"Converter reset -----------------------\n");
838 if (Data && Length > 8) {
840 int SubstreamHeaderLength = 4;
841 bool ResetSubtitleAssembler = Data[PayloadOffset + 3] == 0x00;
844 if ((Data[7] & 0x01) && (Data[PayloadOffset - 3] & 0x81) == 0x01 && Data[PayloadOffset - 2] == 0x81) {
846 SubstreamHeaderLength = 1;
847 ResetSubtitleAssembler = Data[8] >= 5;
850 if (Length > PayloadOffset + SubstreamHeaderLength) {
854 const uchar *data = Data + PayloadOffset + SubstreamHeaderLength;
855 int length = Length - PayloadOffset - SubstreamHeaderLength;
856 if (ResetSubtitleAssembler)
860 if (data[0] == 0x20 && data[1] == 0x00 && data[2] == 0x0F)
868 if (b && b[0] == 0x0F) {
884 if (Data && Length > 8) {
886 if (Length > PayloadOffset) {
890 const uchar *data = Data + PayloadOffset;
891 int length = Length - PayloadOffset;
893 if (data[0] == 0x20 && data[1] == 0x00 && data[2] == 0x0F) {
897 const uchar *b = data;
916 #define LimitTo32Bit(n) ((n) & 0x00000000FFFFFFFFL)
917 #define MAXDELTA 40000 // max. reasonable PTS/STC delta in ms
929 if (Timeout.
TimedOut() || LastSetupLevel != NewSetupLevel) {
932 LastSetupLevel = NewSetupLevel;
937 if (Delta > (int64_t(1) << 31))
938 Delta -= (int64_t(1) << 32);
939 else if (Delta < -((int64_t(1) << 31) - 1))
940 Delta += (int64_t(1) << 32);
947 Timeout.
Set(sb->Timeout() * 1000);
952 else if (Delta < WaitMs)
972 Er =
constrain((298 * Ey + 460 * Epr) / 256, 0, 255);
973 Eg =
constrain((298 * Ey - 55 * Epb - 137 * Epr) / 256, 0, 255);
974 Eb =
constrain((298 * Ey + 543 * Epb ) / 256, 0, 255);
976 return (Er << 16) | (Eg << 8) | Eb;
981 int OsdWidth, OsdHeight;
983 int VideoWidth, VideoHeight;
1012 if (Length > 5 && bs.
GetBits(8) == 0x0F) {
1013 int segmentType = bs.
GetBits(8);
1017 int segmentLength = bs.
GetBits(16);
1023 if (sp->PageId() == pageId) {
1035 switch (segmentType) {
1038 int pageTimeout = bs.
GetBits(8);
1039 int pageVersion = bs.
GetBits(4);
1040 if (pageVersion == page->
Version())
1046 dbgpages(
"Update page id %d version %d pts %"PRId64
" timeout %d state %d\n", pageId, page->
Version(), page->
Pts(), page->
Timeout(), page->
State());
1047 while (!bs.
IsEOF()) {
1060 int regionVersion = bs.
GetBits(4);
1061 if (regionVersion == region->
Version())
1064 bool regionFillFlag = bs.
GetBit();
1066 int regionWidth = bs.
GetBits(16);
1067 if (regionWidth < 1)
1069 int regionHeight = bs.
GetBits(16);
1070 if (regionHeight < 1)
1072 region->
SetSize(regionWidth, regionHeight);
1077 dbgregions(
"Region pageId %d id %d version %d fill %d width %d height %d level %d depth %d clutId %d\n", pageId, region->
RegionId(), region->
Version(), regionFillFlag, regionWidth, regionHeight, region->
Level(), region->
Depth(), region->
ClutId());
1078 int region8bitPixelCode = bs.
GetBits(8);
1079 int region4bitPixelCode = bs.
GetBits(4);
1080 int region2bitPixelCode = bs.
GetBits(2);
1082 if (regionFillFlag) {
1083 switch (region->
Bpp()) {
1084 case 2: region->
FillRegion(region8bitPixelCode);
break;
1085 case 4: region->
FillRegion(region4bitPixelCode);
break;
1086 case 8: region->
FillRegion(region2bitPixelCode);
break;
1087 default:
dbgregions(
"unknown bpp %d (%s %d)\n", region->
Bpp(), __FUNCTION__, __LINE__);
1090 while (!bs.
IsEOF()) {
1092 int objectType = bs.
GetBits(2);
1093 object->SetCodingMethod(objectType);
1094 object->SetProviderFlag(bs.
GetBits(2));
1095 int objectHorizontalPosition = bs.
GetBits(12);
1097 int objectVerticalPosition = bs.
GetBits(12);
1098 object->SetPosition(objectHorizontalPosition, objectVerticalPosition);
1099 if (objectType == 0x01 || objectType == 0x02) {
1100 object->SetForegroundPixelCode(bs.
GetBits(8));
1101 object->SetBackgroundPixelCode(bs.
GetBits(8));
1109 int clutVersion = bs.
GetBits(4);
1110 if (clutVersion == clut->
Version())
1115 while (!bs.
IsEOF()) {
1117 bool entryClut2Flag = bs.
GetBit();
1118 bool entryClut4Flag = bs.
GetBit();
1119 bool entryClut8Flag = bs.
GetBit();
1139 value =
yuv2rgb(yval, cbval, crval);
1142 dbgcluts(
"%2d %d %d %d %08X\n", clutEntryId, entryClut2Flag ? 2 : 0, entryClut4Flag ? 4 : 0, entryClut8Flag ? 8 : 0, value);
1144 clut->
SetColor(2, clutEntryId, value);
1146 clut->
SetColor(4, clutEntryId, value);
1148 clut->
SetColor(8, clutEntryId, value);
1158 int objectVersion = bs.
GetBits(4);
1159 if (objectVersion == object->
Version())
1161 object->SetVersion(objectVersion);
1162 int codingMethod = bs.
GetBits(2);
1163 object->SetNonModifyingColorFlag(bs.
GetBit());
1165 dbgobjects(
"Object pageId %d id %d version %d method %d modify %d\n", pageId, object->
ObjectId(),
object->Version(),
object->CodingMethod(),
object->NonModifyingColorFlag());
1166 if (codingMethod == 0) {
1167 int topFieldLength = bs.
GetBits(16);
1168 int bottomFieldLength = bs.
GetBits(16);
1169 object->DecodeSubBlock(bs.
GetData(), topFieldLength,
true);
1170 if (bottomFieldLength)
1171 object->DecodeSubBlock(bs.
GetData() + topFieldLength, bottomFieldLength,
false);
1173 object->DecodeSubBlock(bs.
GetData(), topFieldLength,
false);
1176 else if (codingMethod == 1) {
1177 int numberOfCodes = bs.
GetBits(8);
1178 object->DecodeCharacterString(bs.
GetData(), numberOfCodes);
1180 #ifdef FINISHPAGE_HACK
1189 bool displayWindowFlag = bs.
GetBit();
1195 if (displayWindowFlag) {
1210 bool disparity_shift_update_sequence_page_flag = bs.
GetBit();
1213 if (disparity_shift_update_sequence_page_flag) {
1216 int division_period_count = bs.
GetBits(8);
1217 for (
int i = 0; i < division_period_count; ++i) {
1222 while (!bs.
IsEOF()) {
1224 bool disparity_shift_update_sequence_region_flag = bs.
GetBit();
1226 int number_of_subregions_minus_1 = bs.
GetBits(2);
1227 for (
int i = 0; i <= number_of_subregions_minus_1; ++i) {
1228 if (number_of_subregions_minus_1 > 0) {
1235 if (disparity_shift_update_sequence_region_flag) {
1238 int division_period_count = bs.
GetBits(8);
1239 for (
int i = 0; i < division_period_count; ++i) {
1254 dbgsegments(
"*** unknown segment type: %02X\n", segmentType);
1268 bool Reduced =
false;
1270 int HalfBpp = Bpp / 2;
1272 for (
int i = 0; i < NumAreas; i++) {
1273 if (Areas[i].bpp >= Bpp) {
1274 Areas[i].
bpp = HalfBpp;
1285 for (
int i = 0; i < NumAreas; i++) {
1293 if (sr->
Bpp() != Areas[i].
bpp) {
cVector< cBitmap * > bitmaps
void ReduceBpp(const cPalette &Palette)
Reduces the color depth of the bitmap to that of the given Palette.
void SetVersion(int Version)
void SetProviderFlag(int ProviderFlag)
cList< cDvbSubtitlePage > * pages
bool NonModifyingColorFlag(void)
void DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg=0, tColor ColorBg=0, bool ReplacePalette=false, bool Overlay=false)
Sets the pixels in this bitmap with the data from the given Bitmap, putting the upper left corner of ...
static bool DebugConverter
void DecodeSubBlock(const uchar *Data, int Length, bool Even)
void SetNonModifyingColorFlag(bool NonModifyingColorFlag)
int PesPayloadOffset(const uchar *p)
#define dbgconverter(a...)
bool Decode2BppCodeString(cBitStream *bs, int &x, int y, const uint8_t *MapTable)
void SetForegroundPixelCode(uchar ForegroundPixelCode)
void Add(cListObject *Object, cListObject *After=NULL)
int Convert(const uchar *Data, int Length)
bool Decode8BppCodeString(cBitStream *bs, int &x, int y)
virtual eOsdError SetAreas(const tArea *Areas, int NumAreas)
Sets the sub-areas to the given areas.
void SetVersion(int Version)
#define CLUT_DEFINITION_SEGMENT
cList< cSubtitleObject > objects
#define DISPARITY_SIGNALING_SEGMENT
virtual void GetVideoSize(int &Width, int &Height, double &VideoAspect)
Returns the Width, Height and VideoAspect ratio of the currently displayed video material.
const uint8_t * GetData(void) const
cSubtitleObject * GetObjectById(int ObjectId, bool New=false)
const char * getCharacterTable(const unsigned char *&buffer, int &length, bool *isSingleByte)
uchar BackgroundPixelCode(void)
int HorizontalAddress(void)
virtual void DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg=0, tColor ColorBg=0, bool ReplacePalette=false, bool Overlay=false)
Sets the pixels in the OSD with the data from the given Bitmap, putting the upper left corner of the ...
int64_t PesGetPts(const uchar *p)
virtual void Append(T Data)
uchar backgroundPixelCode
cDvbSubtitleConverter(void)
void Action(void)
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
#define REGION_COMPOSITION_SEGMENT
cBitmap * Scaled(double FactorX, double FactorY, bool AntiAlias=false)
Creates a copy of this bitmap, scaled by the given factors.
static void SetupChanged(void)
#define OBJECT_DATA_SEGMENT
cDvbSubtitleAssembler * dvbSubtitleAssembler
bool PesHasPts(const uchar *p)
int windowHorizontalOffset
virtual void GetOsdSize(int &Width, int &Height, double &PixelAspect)
Returns the Width, Height and PixelAspect ratio the OSD should use to best fit the resolution of the ...
void SetHorizontalAddress(int HorizontalAddress)
static bool DebugSegments
virtual ~cDvbSubtitlePage()
cSubtitleClut * GetClutById(int ClutId, bool New=false)
bool Decode4BppCodeString(cBitStream *bs, int &x, int y, const uint8_t *MapTable)
cSubtitleClut(int ClutId)
const char * Convert(const char *From, char *To=NULL, size_t ToLength=0)
Converts the given Text from FromCode to ToCode (as set in the constructor).
unsigned char * Get(int &Length)
cList< cSubtitleRegion > regions
void UpdateTextData(cSubtitleClut *Clut)
void DecodeCharacterString(const uchar *Data, int NumberOfCodes)
cSubtitleObject * GetObjectById(int ObjectId)
virtual void Flush(void)
Actually commits all data to the OSD hardware.
cSubtitleRegion * GetRegionById(int RegionId, bool New=false)
cList< cSubtitleClut > cluts
void SetSize(int Width, int Height)
Sets the size of this bitmap to the given values.
const char * TextData(void)
virtual int Height(void) const =0
Returns the height of this font in pixel (all characters have the same height).
void Replace(const cPalette &Palette)
Replaces the colors of this palette with the colors from the given palette.
void SetVersion(int Version)
tColor yuv2rgb(int Y, int Cb, int Cr)
T * Next(const T *object) const
cDvbSubtitleAssembler(void)
void SetBackgroundPixelCode(uchar BackgroundPixelCode)
#define PAGE_COMPOSITION_SEGMENT
int SubtitleFgTransparency
virtual ~cDvbSubtitleConverter()
cSubtitleObject(int ObjectId, cBitmap *Bitmap)
virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas)
Checks whether the OSD can display the given set of sub-areas.
char FontOsd[MAXFONTNAME]
static void SleepMs(int TimeoutMs)
Creates a cCondWait object and uses it to sleep for TimeoutMs milliseconds, immediately giving up the...
void bool Start(void)
Actually starts the thread.
The cOsd class is the interface to the "On Screen Display".
uchar ForegroundPixelCode(void)
static cFont * CreateFont(const char *Name, int CharHeight, int CharWidth=0)
Creates a new font object with the given Name and makes its characters CharHeight pixels high...
bool Running(void)
Returns false if a derived cThread object shall leave its Action() function.
void AddBitmap(cBitmap *Bitmap)
void SetColor(int Index, tColor Color)
Sets the palette entry at Index to Color.
void FillRegion(tIndex Index)
void ShrinkBpp(int NewBpp)
Shrinks the color depth of the bitmap to NewBpp by keeping only the 2^NewBpp most frequently used col...
tColor ArgbToColor(uint8_t A, uint8_t R, uint8_t G, uint8_t B)
void SetTimeout(int Timeout)
uchar foregroundPixelCode
#define OSD_LEVEL_SUBTITLES
void DrawLine(int x, int y, tIndex Index, int Length)
void SetVerticalAddress(int VerticalAddress)
cDvbSubtitleBitmaps(int64_t Pts, int Timeout, tArea *Areas, int NumAreas, double OsdFactorX, double OsdFactorY)
void Del(cListObject *Object, bool DeleteObject=true)
void SetColor(int Bpp, int Index, tColor Color)
tArea * GetAreas(double FactorX, double FactorY)
void FinishPage(cDvbSubtitlePage *Page)
static cDevice * PrimaryDevice(void)
Returns the primary device.
cDvbSubtitlePage(int PageId)
#define DISPLAY_DEFINITION_SEGMENT
virtual int64_t GetSTC(void)
Gets the current System Time Counter, which can be used to synchronize audio, video and subtitles...
int ExtractSegment(const uchar *Data, int Length, int64_t Pts)
void SetCodingMethod(int CodingMethod)
virtual ~cDvbSubtitleAssembler()
void SetPosition(int x, int y)
cList< cDvbSubtitleBitmaps > * bitmaps
virtual int Width(uint c) const =0
Returns the width of the given character in pixel.
#define END_OF_DISPLAY_SET_SEGMENT
bool SetLength(int Length)
void SetVersion(int Version)
void SetBpp(int Bpp)
Sets the color depth of this palette to the given value.
char textData[Utf8BufSize(256)]
#define dbgsegments(a...)
const cPalette * GetPalette(int Bpp)
void Put(const uchar *Data, int Length)
int VerticalAddress(void)
void Cancel(int WaitSeconds=0)
Cancels the thread by first setting 'running' to false, so that the Action() loop can finish in an or...
void SetIndex(int x, int y, tIndex Index)
Sets the index at the given coordinates to Index.
int ConvertFragments(const uchar *Data, int Length)
void SetClutId(int ClutId)
int SubtitleBgTransparency
bool nonModifyingColorFlag
cSubtitleRegion(int RegionId)
static cOsd * NewOsd(int Left, int Top, uint Level=OSD_LEVEL_DEFAULT)
Returns a pointer to a newly created cOsd object, which will be located at the given coordinates...