15 #define __STDC_FORMAT_MACROS // Required for format specifiers
22 #define PAGE_COMPOSITION_SEGMENT 0x10
23 #define REGION_COMPOSITION_SEGMENT 0x11
24 #define CLUT_DEFINITION_SEGMENT 0x12
25 #define OBJECT_DATA_SEGMENT 0x13
26 #define DISPLAY_DEFINITION_SEGMENT 0x14
27 #define DISPARITY_SIGNALING_SEGMENT 0x15 // DVB BlueBook A156
28 #define END_OF_DISPLAY_SET_SEGMENT 0x80
29 #define STUFFING_SEGMENT 0xFF
39 #define dbgconverter(a...) if (DebugConverter) fprintf(stderr, a)
40 #define dbgsegments(a...) if (DebugSegments) fprintf(stderr, a)
41 #define dbgpages(a...) if (DebugPages) fprintf(stderr, a)
42 #define dbgregions(a...) if (DebugRegions) fprintf(stderr, a)
43 #define dbgobjects(a...) if (DebugObjects) fprintf(stderr, a)
44 #define dbgcluts(a...) if (DebugCluts) fprintf(stderr, a)
69 int a = 0, r = 0, g = 0, b = 0;
79 for (
int i = 1; i < 16; ++i) {
81 r = (i & 1) ? 255 : 0;
82 g = (i & 2) ? 255 : 0;
83 b = (i & 4) ? 255 : 0;
86 r = (i & 1) ? 127 : 0;
87 g = (i & 2) ? 127 : 0;
88 b = (i & 4) ? 127 : 0;
94 for (
int i = 1; i < 256; ++i) {
96 r = (i & 1) ? 255 : 0;
97 g = (i & 2) ? 255 : 0;
98 b = (i & 4) ? 255 : 0;
104 r = ((i & 1) ? 85 : 0) + ((i & 0x10) ? 170 : 0);
105 g = ((i & 2) ? 85 : 0) + ((i & 0x20) ? 170 : 0);
106 b = ((i & 4) ? 85 : 0) + ((i & 0x40) ? 170 : 0);
110 r = ((i & 1) ? 85 : 0) + ((i & 0x10) ? 170 : 0);
111 g = ((i & 2) ? 85 : 0) + ((i & 0x20) ? 170 : 0);
112 b = ((i & 4) ? 85 : 0) + ((i & 0x40) ? 170 : 0);
116 r = 127 + ((i & 1) ? 43 : 0) + ((i & 0x10) ? 85 : 0);
117 g = 127 + ((i & 2) ? 43 : 0) + ((i & 0x20) ? 85 : 0);
118 b = 127 + ((i & 4) ? 43 : 0) + ((i & 0x40) ? 85 : 0);
122 r = ((i & 1) ? 43 : 0) + ((i & 0x10) ? 85 : 0);
123 g = ((i & 2) ? 43 : 0) + ((i & 0x20) ? 85 : 0);
124 b = ((i & 4) ? 43 : 0) + ((i & 0x40) ? 85 : 0);
139 default:
esyslog(
"ERROR: wrong Bpp in cSubtitleClut::SetColor(%d, %d, %08X)", Bpp, Index, Color);
149 default:
esyslog(
"ERROR: wrong Bpp in cSubtitleClut::GetPalette(%d)", Bpp);
181 int X(
void) {
return px; }
182 int Y(
void) {
return py; }
211 if (NumberOfCodes > 0) {
213 const uchar *from = &Data[1];
214 int len = NumberOfCodes * 2 - 1;
217 char txt[NumberOfCodes + 1];
219 for (
int i = 2; i < NumberOfCodes; ++i) {
220 uchar c = Data[i * 2 + 1] & 0xFF;
223 if (
' ' <= c && c <=
'~' || c ==
'\n' || 0xA0 <= c)
229 const char *s = conv.
Convert(txt);
241 int y = Even ? 0 : 1;
242 uint8_t map2to4[ 4] = { 0x00, 0x07, 0x08, 0x0F };
243 uint8_t map2to8[ 4] = { 0x00, 0x77, 0x88, 0xFF };
244 uint8_t map4to8[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
245 const uint8_t *mapTable = NULL;
247 while (!bs.
IsEOF()) {
252 case 8: mapTable = map2to8;
break;
253 case 4: mapTable = map2to4;
break;
254 default: mapTable = NULL;
break;
263 case 8: mapTable = map4to8;
break;
264 default: mapTable = NULL;
break;
284 for (
int i = 0; i < 4; ++i)
289 for (
int i = 0; i < 16; ++i)
297 default:
dbgobjects(
"unknown sub block %s %d\n", __FUNCTION__, __LINE__);
308 for (
int pos = x; pos < x + Length; pos++)
346 color = MapTable[color];
361 else if (bs->
GetBit() == 0) {
368 else if (bs->
GetBit() == 0) {
391 color = MapTable[color];
469 for (
int y = 0; y <
Height(); y++) {
470 for (
int x = 0; x <
Width(); x++)
479 if (so->ObjectId() == ObjectId)
482 if (!result && New) {
497 tmp.DrawText(0, 0, so->TextData(), palette->Color(so->ForegroundPixelCode()), palette->Color(so->BackgroundPixelCode()), font);
508 if (Level > 0 && Level < 4)
514 if (Depth > 0 && Depth < 4)
566 a->
x1 = int(round(FactorX * sr->HorizontalAddress()));
567 a->
y1 = int(round(FactorY * sr->VerticalAddress()));
568 a->
x2 = int(round(FactorX * (sr->HorizontalAddress() + sr->Width() - 1)));
569 a->
y2 = int(round(FactorY * (sr->VerticalAddress() + sr->Height() - 1)));
571 while ((a->
Width() & 3) != 0)
584 if (sc->ClutId() == ClutId)
587 if (!result && New) {
598 if (sr->RegionId() == RegionId)
601 if (!result && New) {
612 result = sr->GetObjectById(ObjectId);
634 default:
dbgpages(
"unknown page state (%s %d)\n", __FUNCTION__, __LINE__);
651 unsigned char *
Get(
int &Length);
652 void Put(
const uchar *Data,
int Length);
676 Size =
max(Size, 2048);
682 esyslog(
"ERROR: can't allocate memory for subtitle assembler");
698 unsigned char *result =
data +
pos;
759 bool AntiAlias =
true;
763 for (
int i = 0; i <
numAreas; i++) {
769 Bpp[i] =
areas[i].bpp = Bpp[i];
822 dbgconverter(
"Converter reset -----------------------\n");
839 if (Data && Length > 8) {
841 int SubstreamHeaderLength = 4;
842 bool ResetSubtitleAssembler = Data[PayloadOffset + 3] == 0x00;
845 if ((Data[7] & 0x01) && (Data[PayloadOffset - 3] & 0x81) == 0x01 && Data[PayloadOffset - 2] == 0x81) {
847 SubstreamHeaderLength = 1;
848 ResetSubtitleAssembler = Data[8] >= 5;
851 if (Length > PayloadOffset + SubstreamHeaderLength) {
855 const uchar *data = Data + PayloadOffset + SubstreamHeaderLength;
856 int length = Length - PayloadOffset - SubstreamHeaderLength;
857 if (ResetSubtitleAssembler)
861 if (data[0] == 0x20 && data[1] == 0x00 && data[2] == 0x0F)
869 if (b && b[0] == 0x0F) {
885 if (Data && Length > 8) {
887 if (Length > PayloadOffset) {
891 const uchar *data = Data + PayloadOffset;
892 int length = Length - PayloadOffset;
894 if (data[0] == 0x20 && data[1] == 0x00 && data[2] == 0x0F) {
898 const uchar *b = data;
917 #define LimitTo32Bit(n) ((n) & 0x00000000FFFFFFFFL)
918 #define MAXDELTA 40000 // max. reasonable PTS/STC delta in ms
930 if (Timeout.
TimedOut() || LastSetupLevel != NewSetupLevel) {
933 LastSetupLevel = NewSetupLevel;
938 if (Delta > (int64_t(1) << 31))
939 Delta -= (int64_t(1) << 32);
940 else if (Delta < -((int64_t(1) << 31) - 1))
941 Delta += (int64_t(1) << 32);
948 Timeout.
Set(sb->Timeout() * 1000);
953 else if (Delta < WaitMs)
973 Er =
constrain((298 * Ey + 460 * Epr) / 256, 0, 255);
974 Eg =
constrain((298 * Ey - 55 * Epb - 137 * Epr) / 256, 0, 255);
975 Eb =
constrain((298 * Ey + 543 * Epb ) / 256, 0, 255);
977 return (Er << 16) | (Eg << 8) | Eb;
982 int OsdWidth, OsdHeight;
984 int VideoWidth, VideoHeight;
1013 if (Length > 5 && bs.
GetBits(8) == 0x0F) {
1014 int segmentType = bs.
GetBits(8);
1018 int segmentLength = bs.
GetBits(16);
1024 if (sp->PageId() == pageId) {
1036 switch (segmentType) {
1039 int pageTimeout = bs.
GetBits(8);
1040 int pageVersion = bs.
GetBits(4);
1041 if (pageVersion == page->
Version())
1047 dbgpages(
"Update page id %d version %d pts %"PRId64
" timeout %d state %d\n", pageId, page->
Version(), page->
Pts(), page->
Timeout(), page->
State());
1048 while (!bs.
IsEOF()) {
1061 int regionVersion = bs.
GetBits(4);
1062 if (regionVersion == region->
Version())
1065 bool regionFillFlag = bs.
GetBit();
1067 int regionWidth = bs.
GetBits(16);
1068 if (regionWidth < 1)
1070 int regionHeight = bs.
GetBits(16);
1071 if (regionHeight < 1)
1073 region->
SetSize(regionWidth, regionHeight);
1078 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());
1079 int region8bitPixelCode = bs.
GetBits(8);
1080 int region4bitPixelCode = bs.
GetBits(4);
1081 int region2bitPixelCode = bs.
GetBits(2);
1083 if (regionFillFlag) {
1084 switch (region->
Bpp()) {
1085 case 2: region->
FillRegion(region8bitPixelCode);
break;
1086 case 4: region->
FillRegion(region4bitPixelCode);
break;
1087 case 8: region->
FillRegion(region2bitPixelCode);
break;
1088 default:
dbgregions(
"unknown bpp %d (%s %d)\n", region->
Bpp(), __FUNCTION__, __LINE__);
1091 while (!bs.
IsEOF()) {
1093 int objectType = bs.
GetBits(2);
1094 object->SetCodingMethod(objectType);
1095 object->SetProviderFlag(bs.
GetBits(2));
1096 int objectHorizontalPosition = bs.
GetBits(12);
1098 int objectVerticalPosition = bs.
GetBits(12);
1099 object->SetPosition(objectHorizontalPosition, objectVerticalPosition);
1100 if (objectType == 0x01 || objectType == 0x02) {
1101 object->SetForegroundPixelCode(bs.
GetBits(8));
1102 object->SetBackgroundPixelCode(bs.
GetBits(8));
1110 int clutVersion = bs.
GetBits(4);
1111 if (clutVersion == clut->
Version())
1116 while (!bs.
IsEOF()) {
1118 bool entryClut2Flag = bs.
GetBit();
1119 bool entryClut4Flag = bs.
GetBit();
1120 bool entryClut8Flag = bs.
GetBit();
1140 value =
yuv2rgb(yval, cbval, crval);
1143 dbgcluts(
"%2d %d %d %d %08X\n", clutEntryId, entryClut2Flag ? 2 : 0, entryClut4Flag ? 4 : 0, entryClut8Flag ? 8 : 0, value);
1145 clut->
SetColor(2, clutEntryId, value);
1147 clut->
SetColor(4, clutEntryId, value);
1149 clut->
SetColor(8, clutEntryId, value);
1159 int objectVersion = bs.
GetBits(4);
1160 if (objectVersion == object->
Version())
1162 object->SetVersion(objectVersion);
1163 int codingMethod = bs.
GetBits(2);
1164 object->SetNonModifyingColorFlag(bs.
GetBit());
1166 dbgobjects(
"Object pageId %d id %d version %d method %d modify %d\n", pageId, object->
ObjectId(),
object->Version(),
object->CodingMethod(),
object->NonModifyingColorFlag());
1167 if (codingMethod == 0) {
1168 int topFieldLength = bs.
GetBits(16);
1169 int bottomFieldLength = bs.
GetBits(16);
1170 object->DecodeSubBlock(bs.
GetData(), topFieldLength,
true);
1171 if (bottomFieldLength)
1172 object->DecodeSubBlock(bs.
GetData() + topFieldLength, bottomFieldLength,
false);
1174 object->DecodeSubBlock(bs.
GetData(), topFieldLength,
false);
1177 else if (codingMethod == 1) {
1178 int numberOfCodes = bs.
GetBits(8);
1179 object->DecodeCharacterString(bs.
GetData(), numberOfCodes);
1181 #ifdef FINISHPAGE_HACK
1190 bool displayWindowFlag = bs.
GetBit();
1196 if (displayWindowFlag) {
1211 bool disparity_shift_update_sequence_page_flag = bs.
GetBit();
1214 if (disparity_shift_update_sequence_page_flag) {
1217 int division_period_count = bs.
GetBits(8);
1218 for (
int i = 0; i < division_period_count; ++i) {
1223 while (!bs.
IsEOF()) {
1225 bool disparity_shift_update_sequence_region_flag = bs.
GetBit();
1227 int number_of_subregions_minus_1 = bs.
GetBits(2);
1228 for (
int i = 0; i <= number_of_subregions_minus_1; ++i) {
1229 if (number_of_subregions_minus_1 > 0) {
1236 if (disparity_shift_update_sequence_region_flag) {
1239 int division_period_count = bs.
GetBits(8);
1240 for (
int i = 0; i < division_period_count; ++i) {
1255 dbgsegments(
"*** unknown segment type: %02X\n", segmentType);
1269 bool Reduced =
false;
1271 int HalfBpp = Bpp / 2;
1273 for (
int i = 0; i < NumAreas; i++) {
1274 if (Areas[i].bpp >= Bpp) {
1275 Areas[i].
bpp = HalfBpp;
1286 for (
int i = 0; i < NumAreas; i++) {
1294 if (sr->
Bpp() != Areas[i].
bpp) {