vdr  2.0.6
dvbsubtitle.c
Go to the documentation of this file.
1 /*
2  * dvbsubtitle.c: DVB subtitles
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * Original author: Marco Schluessler <marco@lordzodiac.de>
8  * With some input from the "subtitle plugin" by Pekka Virtanen <pekka.virtanen@sci.fi>
9  *
10  * $Id: dvbsubtitle.c 2.34 2013/02/22 15:25:25 kls Exp $
11  */
12 
13 #include "dvbsubtitle.h"
14 #define __STDC_FORMAT_MACROS // Required for format specifiers
15 #include <inttypes.h>
16 #include "device.h"
17 #include "libsi/si.h"
18 
19 //#define FINISHPAGE_HACK
20 
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
29 
30 // Set these to 'true' for debug output:
31 static bool DebugConverter = false;
32 static bool DebugSegments = false;
33 static bool DebugPages = false;
34 static bool DebugRegions = false;
35 static bool DebugObjects = false;
36 static bool DebugCluts = false;
37 
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)
44 
45 // --- cSubtitleClut ---------------------------------------------------------
46 
47 class cSubtitleClut : public cListObject {
48 private:
49  int clutId;
50  int version;
54 public:
55  cSubtitleClut(int ClutId);
56  int ClutId(void) { return clutId; }
57  int Version(void) { return version; }
58  void SetVersion(int Version) { version = Version; }
59  void SetColor(int Bpp, int Index, tColor Color);
60  const cPalette *GetPalette(int Bpp);
61  };
62 
64 :palette2(2)
65 ,palette4(4)
66 ,palette8(8)
67 {
68  int a = 0, r = 0, g = 0, b = 0;
69  clutId = ClutId;
70  version = -1;
71  // ETSI EN 300 743 10.3: 4-entry CLUT default contents
72  palette2.SetColor(0, ArgbToColor( 0, 0, 0, 0));
73  palette2.SetColor(1, ArgbToColor(255, 255, 255, 255));
74  palette2.SetColor(2, ArgbToColor(255, 0, 0, 0));
75  palette2.SetColor(3, ArgbToColor(255, 127, 127, 127));
76  // ETSI EN 300 743 10.2: 16-entry CLUT default contents
77  palette4.SetColor(0, ArgbToColor(0, 0, 0, 0));
78  for (int i = 1; i < 16; ++i) {
79  if (i < 8) {
80  r = (i & 1) ? 255 : 0;
81  g = (i & 2) ? 255 : 0;
82  b = (i & 4) ? 255 : 0;
83  }
84  else {
85  r = (i & 1) ? 127 : 0;
86  g = (i & 2) ? 127 : 0;
87  b = (i & 4) ? 127 : 0;
88  }
89  palette4.SetColor(i, ArgbToColor(255, r, g, b));
90  }
91  // ETSI EN 300 743 10.1: 256-entry CLUT default contents
92  palette8.SetColor(0, ArgbToColor(0, 0, 0, 0));
93  for (int i = 1; i < 256; ++i) {
94  if (i < 8) {
95  r = (i & 1) ? 255 : 0;
96  g = (i & 2) ? 255 : 0;
97  b = (i & 4) ? 255 : 0;
98  a = 63;
99  }
100  else {
101  switch (i & 0x88) {
102  case 0x00:
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);
106  a = 255;
107  break;
108  case 0x08:
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);
112  a = 127;
113  break;
114  case 0x80:
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);
118  a = 255;
119  break;
120  case 0x88:
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);
124  a = 255;
125  break;
126  }
127  }
128  palette8.SetColor(i, ArgbToColor(a, r, g, b));
129  }
130 }
131 
132 void cSubtitleClut::SetColor(int Bpp, int Index, tColor Color)
133 {
134  switch (Bpp) {
135  case 2: palette2.SetColor(Index, Color); break;
136  case 4: palette4.SetColor(Index, Color); break;
137  case 8: palette8.SetColor(Index, Color); break;
138  default: esyslog("ERROR: wrong Bpp in cSubtitleClut::SetColor(%d, %d, %08X)", Bpp, Index, Color);
139  }
140 }
141 
143 {
144  switch (Bpp) {
145  case 2: return &palette2;
146  case 4: return &palette4;
147  case 8: return &palette8;
148  default: esyslog("ERROR: wrong Bpp in cSubtitleClut::GetPalette(%d)", Bpp);
149  }
150  return &palette8;
151 }
152 
153 // --- cSubtitleObject -------------------------------------------------------
154 
155 class cSubtitleObject : public cListObject {
156 private:
157  int objectId;
158  int version;
164  int px;
165  int py;
167  char textData[Utf8BufSize(256)]; // number of character codes is an 8-bit field
168  void DrawLine(int x, int y, tIndex Index, int Length);
169  bool Decode2BppCodeString(cBitStream *bs, int&x, int y, const uint8_t *MapTable);
170  bool Decode4BppCodeString(cBitStream *bs, int&x, int y, const uint8_t *MapTable);
171  bool Decode8BppCodeString(cBitStream *bs, int&x, int y);
172 public:
173  cSubtitleObject(int ObjectId, cBitmap *Bitmap);
174  int ObjectId(void) { return objectId; }
175  int Version(void) { return version; }
176  int CodingMethod(void) { return codingMethod; }
179  const char *TextData(void) { return &textData[0]; }
180  int X(void) { return px; }
181  int Y(void) { return py; }
183  void DecodeCharacterString(const uchar *Data, int NumberOfCodes);
184  void DecodeSubBlock(const uchar *Data, int Length, bool Even);
185  void SetVersion(int Version) { version = Version; }
189  void SetCodingMethod(int CodingMethod) { codingMethod = CodingMethod; }
190  void SetPosition(int x, int y) { px = x; py = y; }
191  void SetProviderFlag(int ProviderFlag) { providerFlag = ProviderFlag; }
192  };
193 
195 {
196  objectId = ObjectId;
197  version = -1;
198  codingMethod = -1;
199  nonModifyingColorFlag = false;
202  providerFlag = -1;
203  px = py = 0;
204  bitmap = Bitmap;
205  memset(textData, 0, sizeof(textData));
206 }
207 
208 void cSubtitleObject::DecodeCharacterString(const uchar *Data, int NumberOfCodes)
209 {
210  if (NumberOfCodes > 0) {
211  bool singleByte;
212  const uchar *from = &Data[1];
213  int len = NumberOfCodes * 2 - 1;
214  cCharSetConv conv(SI::getCharacterTable(from, len, &singleByte));
215  if (singleByte) {
216  char txt[NumberOfCodes + 1];
217  char *p = txt;
218  for (int i = 2; i < NumberOfCodes; ++i) {
219  uchar c = Data[i * 2 + 1] & 0xFF;
220  if (c == 0)
221  break;
222  if (' ' <= c && c <= '~' || c == '\n' || 0xA0 <= c)
223  *(p++) = c;
224  else if (c == 0x8A)
225  *(p++) = '\n';
226  }
227  *p = 0;
228  const char *s = conv.Convert(txt);
230  }
231  else {
232  // TODO: add proper multibyte support for "UTF-16", "EUC-KR", "GB2312", "GBK", "UTF-8"
233  }
234  }
235 }
236 
237 void cSubtitleObject::DecodeSubBlock(const uchar *Data, int Length, bool Even)
238 {
239  int x = 0;
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;
245  cBitStream bs(Data, Length * 8);
246  while (!bs.IsEOF()) {
247  switch (bs.GetBits(8)) {
248  case 0x10:
249  dbgobjects("2-bit / pixel code string\n");
250  switch (bitmap->Bpp()) {
251  case 8: mapTable = map2to8; break;
252  case 4: mapTable = map2to4; break;
253  default: mapTable = NULL; break;
254  }
255  while (Decode2BppCodeString(&bs, x, y, mapTable) && !bs.IsEOF())
256  ;
257  bs.ByteAlign();
258  break;
259  case 0x11:
260  dbgobjects("4-bit / pixel code string\n");
261  switch (bitmap->Bpp()) {
262  case 8: mapTable = map4to8; break;
263  default: mapTable = NULL; break;
264  }
265  while (Decode4BppCodeString(&bs, x, y, mapTable) && !bs.IsEOF())
266  ;
267  bs.ByteAlign();
268  break;
269  case 0x12:
270  dbgobjects("8-bit / pixel code string\n");
271  while (Decode8BppCodeString(&bs, x, y) && !bs.IsEOF())
272  ;
273  break;
274  case 0x20:
275  dbgobjects("sub block 2 to 4 map\n");
276  map2to4[0] = bs.GetBits(4);
277  map2to4[1] = bs.GetBits(4);
278  map2to4[2] = bs.GetBits(4);
279  map2to4[3] = bs.GetBits(4);
280  break;
281  case 0x21:
282  dbgobjects("sub block 2 to 8 map\n");
283  for (int i = 0; i < 4; ++i)
284  map2to8[i] = bs.GetBits(8);
285  break;
286  case 0x22:
287  dbgobjects("sub block 4 to 8 map\n");
288  for (int i = 0; i < 16; ++i)
289  map4to8[i] = bs.GetBits(8);
290  break;
291  case 0xF0:
292  dbgobjects("end of object line\n");
293  x = 0;
294  y += 2;
295  break;
296  default: dbgobjects("unknown sub block %s %d\n", __FUNCTION__, __LINE__);
297  }
298  }
299 }
300 
301 void cSubtitleObject::DrawLine(int x, int y, tIndex Index, int Length)
302 {
303  if (nonModifyingColorFlag && Index == 1)
304  return;
305  x += px;
306  y += py;
307  for (int pos = x; pos < x + Length; pos++)
308  bitmap->SetIndex(pos, y, Index);
309 }
310 
311 bool cSubtitleObject::Decode2BppCodeString(cBitStream *bs, int &x, int y, const uint8_t *MapTable)
312 {
313  int rl = 0;
314  int color = 0;
315  uchar code = bs->GetBits(2);
316  if (code) {
317  color = code;
318  rl = 1;
319  }
320  else if (bs->GetBit()) { // switch_1
321  rl = bs->GetBits(3) + 3;
322  color = bs->GetBits(2);
323  }
324  else if (bs->GetBit()) // switch_2
325  rl = 1; //color 0
326  else {
327  switch (bs->GetBits(2)) { // switch_3
328  case 0:
329  return false;
330  case 1:
331  rl = 2; //color 0
332  break;
333  case 2:
334  rl = bs->GetBits(4) + 12;
335  color = bs->GetBits(2);
336  break;
337  case 3:
338  rl = bs->GetBits(8) + 29;
339  color = bs->GetBits(2);
340  break;
341  default: ;
342  }
343  }
344  if (MapTable)
345  color = MapTable[color];
346  DrawLine(x, y, color, rl);
347  x += rl;
348  return true;
349 }
350 
351 bool cSubtitleObject::Decode4BppCodeString(cBitStream *bs, int &x, int y, const uint8_t *MapTable)
352 {
353  int rl = 0;
354  int color = 0;
355  uchar code = bs->GetBits(4);
356  if (code) {
357  color = code;
358  rl = 1;
359  }
360  else if (bs->GetBit() == 0) { // switch_1
361  code = bs->GetBits(3);
362  if (code)
363  rl = code + 2; //color 0
364  else
365  return false;
366  }
367  else if (bs->GetBit() == 0) { // switch_2
368  rl = bs->GetBits(2) + 4;
369  color = bs->GetBits(4);
370  }
371  else {
372  switch (bs->GetBits(2)) { // switch_3
373  case 0: // color 0
374  rl = 1;
375  break;
376  case 1: // color 0
377  rl = 2;
378  break;
379  case 2:
380  rl = bs->GetBits(4) + 9;
381  color = bs->GetBits(4);
382  break;
383  case 3:
384  rl = bs->GetBits(8) + 25;
385  color = bs->GetBits(4);
386  break;
387  }
388  }
389  if (MapTable)
390  color = MapTable[color];
391  DrawLine(x, y, color, rl);
392  x += rl;
393  return true;
394 }
395 
397 {
398  int rl = 0;
399  int color = 0;
400  uchar code = bs->GetBits(8);
401  if (code) {
402  color = code;
403  rl = 1;
404  }
405  else if (bs->GetBit()) {
406  rl = bs->GetBits(7);
407  color = bs->GetBits(8);
408  }
409  else {
410  code = bs->GetBits(7);
411  if (code)
412  rl = code; // color 0
413  else
414  return false;
415  }
416  DrawLine(x, y, color, rl);
417  x += rl;
418  return true;
419 }
420 
421 // --- cSubtitleRegion -------------------------------------------------------
422 
423 class cSubtitleRegion : public cListObject, public cBitmap {
424 private:
425  int regionId;
426  int version;
427  int clutId;
430  int level;
433 public:
435  int RegionId(void) { return regionId; }
436  int Version(void) { return version; }
437  int ClutId(void) { return clutId; }
438  int Level(void) { return level; }
439  int Depth(void) { return Bpp(); }
440  void FillRegion(tIndex Index);
441  cSubtitleObject *GetObjectById(int ObjectId, bool New = false);
442  int HorizontalAddress(void) { return horizontalAddress; }
443  int VerticalAddress(void) { return verticalAddress; }
444  void SetVersion(int Version) { version = Version; }
445  void SetClutId(int ClutId) { clutId = ClutId; }
446  void SetLevel(int Level);
447  void SetDepth(int Depth);
448  void SetHorizontalAddress(int HorizontalAddress) { horizontalAddress = HorizontalAddress; }
449  void SetVerticalAddress(int VerticalAddress) { verticalAddress = VerticalAddress; }
450  void UpdateTextData(cSubtitleClut *Clut);
451  };
452 
454 :cBitmap(1, 1, 4)
455 {
456  regionId = RegionId;
457  version = -1;
458  clutId = -1;
459  horizontalAddress = 0;
460  verticalAddress = 0;
461  level = 0;
462  lineHeight = 26; // configurable subtitling font size
463 }
464 
466 {
467  dbgregions("FillRegion %d\n", Index);
468  for (int y = 0; y < Height(); y++) {
469  for (int x = 0; x < Width(); x++)
470  SetIndex(x, y, Index);
471  }
472 }
473 
475 {
476  cSubtitleObject *result = NULL;
477  for (cSubtitleObject *so = objects.First(); so; so = objects.Next(so)) {
478  if (so->ObjectId() == ObjectId)
479  result = so;
480  }
481  if (!result && New) {
482  result = new cSubtitleObject(ObjectId, this);
483  objects.Add(result);
484  }
485  return result;
486 }
487 
489 {
490  const cPalette *palette = Clut ? Clut->GetPalette(Depth()) : NULL;
491  for (cSubtitleObject *so = objects.First(); so && palette; so = objects.Next(so)) {
492  if (Utf8StrLen(so->TextData()) > 0) {
494  cBitmap tmp(font->Width(so->TextData()), font->Height(), Depth());
495  double factor = (double)lineHeight / font->Height();
496  tmp.DrawText(0, 0, so->TextData(), palette->Color(so->ForegroundPixelCode()), palette->Color(so->BackgroundPixelCode()), font);
497  cBitmap *scaled = tmp.Scaled(factor, factor, true);
498  DrawBitmap(so->X(), so->Y(), *scaled);
499  delete scaled;
500  delete font;
501  }
502  }
503 }
504 
506 {
507  if (Level > 0 && Level < 4)
508  level = 1 << Level;
509 }
510 
512 {
513  if (Depth > 0 && Depth < 4)
514  SetBpp(1 << Depth);
515 }
516 
517 // --- cDvbSubtitlePage ------------------------------------------------------
518 
520 private:
521  int pageId;
522  int version;
523  int state;
524  int64_t pts;
525  int timeout;
527 public:
530  virtual ~cDvbSubtitlePage();
531  int PageId(void) { return pageId; }
532  int Version(void) { return version; }
533  int State(void) { return state; }
534  tArea *GetAreas(double FactorX, double FactorY);
535  cSubtitleClut *GetClutById(int ClutId, bool New = false);
536  cSubtitleObject *GetObjectById(int ObjectId);
537  cSubtitleRegion *GetRegionById(int RegionId, bool New = false);
538  int64_t Pts(void) const { return pts; }
539  int Timeout(void) { return timeout; }
540  void SetVersion(int Version) { version = Version; }
541  void SetPts(int64_t Pts) { pts = Pts; }
542  void SetState(int State);
543  void SetTimeout(int Timeout) { timeout = Timeout; }
544  };
545 
547 {
548  pageId = PageId;
549  version = -1;
550  state = -1;
551  pts = 0;
552  timeout = 0;
553 }
554 
556 {
557 }
558 
559 tArea *cDvbSubtitlePage::GetAreas(double FactorX, double FactorY)
560 {
561  if (regions.Count() > 0) {
562  tArea *Areas = new tArea[regions.Count()];
563  tArea *a = Areas;
564  for (cSubtitleRegion *sr = regions.First(); sr; sr = regions.Next(sr)) {
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)));
569  a->bpp = sr->Bpp();
570  while ((a->Width() & 3) != 0)
571  a->x2++; // aligns width to a multiple of 4, so 2, 4 and 8 bpp will work
572  a++;
573  }
574  return Areas;
575  }
576  return NULL;
577 }
578 
580 {
581  cSubtitleClut *result = NULL;
582  for (cSubtitleClut *sc = cluts.First(); sc; sc = cluts.Next(sc)) {
583  if (sc->ClutId() == ClutId)
584  result = sc;
585  }
586  if (!result && New) {
587  result = new cSubtitleClut(ClutId);
588  cluts.Add(result);
589  }
590  return result;
591 }
592 
594 {
595  cSubtitleRegion *result = NULL;
596  for (cSubtitleRegion *sr = regions.First(); sr; sr = regions.Next(sr)) {
597  if (sr->RegionId() == RegionId)
598  result = sr;
599  }
600  if (!result && New) {
601  result = new cSubtitleRegion(RegionId);
602  regions.Add(result);
603  }
604  return result;
605 }
606 
608 {
609  cSubtitleObject *result = NULL;
610  for (cSubtitleRegion *sr = regions.First(); sr && !result; sr = regions.Next(sr))
611  result = sr->GetObjectById(ObjectId);
612  return result;
613 }
614 
616 {
617  state = State;
618  switch (state) {
619  case 0: // normal case - page update
620  dbgpages("page update\n");
621  break;
622  case 1: // acquisition point - page refresh
623  dbgpages("page refresh\n");
624  regions.Clear();
625  break;
626  case 2: // mode change - new page
627  dbgpages("new Page\n");
628  regions.Clear();
629  cluts.Clear();
630  break;
631  case 3: // reserved
632  break;
633  default: dbgpages("unknown page state (%s %d)\n", __FUNCTION__, __LINE__);
634  }
635 }
636 
637 // --- cDvbSubtitleAssembler -------------------------------------------------
638 
640 private:
642  int length;
643  int pos;
644  int size;
645  bool Realloc(int Size);
646 public:
647  cDvbSubtitleAssembler(void);
648  virtual ~cDvbSubtitleAssembler();
649  void Reset(void);
650  unsigned char *Get(int &Length);
651  void Put(const uchar *Data, int Length);
652  };
653 
655 {
656  data = NULL;
657  size = 0;
658  Reset();
659 }
660 
662 {
663  free(data);
664 }
665 
667 {
668  length = 0;
669  pos = 0;
670 }
671 
673 {
674  if (Size > size) {
675  Size = max(Size, 2048);
676  if (uchar *NewBuffer = (uchar *)realloc(data, Size)) {
677  size = Size;
678  data = NewBuffer;
679  }
680  else {
681  esyslog("ERROR: can't allocate memory for subtitle assembler");
682  length = 0;
683  size = 0;
684  free(data);
685  data = NULL;
686  return false;
687  }
688  }
689  return true;
690 }
691 
692 unsigned char *cDvbSubtitleAssembler::Get(int &Length)
693 {
694  if (length > pos + 5) {
695  Length = (data[pos + 4] << 8) + data[pos + 5] + 6;
696  if (length >= pos + Length) {
697  unsigned char *result = data + pos;
698  pos += Length;
699  return result;
700  }
701  }
702  return NULL;
703 }
704 
705 void cDvbSubtitleAssembler::Put(const uchar *Data, int Length)
706 {
707  if (Length && Realloc(length + Length)) {
708  memcpy(data + length, Data, Length);
709  length += Length;
710  }
711 }
712 
713 // --- cDvbSubtitleBitmaps ---------------------------------------------------
714 
716 private:
717  int64_t pts;
718  int timeout;
720  int numAreas;
721  double osdFactorX;
722  double osdFactorY;
724 public:
725  cDvbSubtitleBitmaps(int64_t Pts, int Timeout, tArea *Areas, int NumAreas, double OsdFactorX, double OsdFactorY);
727  int64_t Pts(void) { return pts; }
728  int Timeout(void) { return timeout; }
729  void AddBitmap(cBitmap *Bitmap);
730  void Draw(cOsd *Osd);
731  };
732 
733 cDvbSubtitleBitmaps::cDvbSubtitleBitmaps(int64_t Pts, int Timeout, tArea *Areas, int NumAreas, double OsdFactorX, double OsdFactorY)
734 {
735  pts = Pts;
736  timeout = Timeout;
737  areas = Areas;
738  numAreas = NumAreas;
739  osdFactorX = OsdFactorX;
740  osdFactorY = OsdFactorY;
741 }
742 
744 {
745  delete[] areas;
746  for (int i = 0; i < bitmaps.Size(); i++)
747  delete bitmaps[i];
748 }
749 
751 {
752  bitmaps.Append(Bitmap);
753 }
754 
756 {
757  bool Scale = !(DoubleEqual(osdFactorX, 1.0) && DoubleEqual(osdFactorY, 1.0));
758  bool AntiAlias = true;
759  if (Scale && osdFactorX > 1.0 || osdFactorY > 1.0) {
760  // Upscaling requires 8bpp:
761  int Bpp[MAXOSDAREAS];
762  for (int i = 0; i < numAreas; i++) {
763  Bpp[i] = areas[i].bpp;
764  areas[i].bpp = 8;
765  }
766  if (Osd->CanHandleAreas(areas, numAreas) != oeOk) {
767  for (int i = 0; i < numAreas; i++)
768  Bpp[i] = areas[i].bpp = Bpp[i];
769  AntiAlias = false;
770  }
771  }
772  if (Osd->SetAreas(areas, numAreas) == oeOk) {
773  for (int i = 0; i < bitmaps.Size(); i++) {
774  cBitmap *b = bitmaps[i];
775  if (Scale)
776  b = b->Scaled(osdFactorX, osdFactorY, AntiAlias);
777  Osd->DrawBitmap(int(round(b->X0() * osdFactorX)), int(round(b->Y0() * osdFactorY)), *b);
778  if (b != bitmaps[i])
779  delete b;
780  }
781  Osd->Flush();
782  }
783 }
784 
785 // --- cDvbSubtitleConverter -------------------------------------------------
786 
788 
790 :cThread("subtitleConverter")
791 {
793  osd = NULL;
794  frozen = false;
795  ddsVersionNumber = -1;
796  displayWidth = windowWidth = 720;
797  displayHeight = windowHeight = 576;
802  Start();
803 }
804 
806 {
807  Cancel(3);
808  delete dvbSubtitleAssembler;
809  delete osd;
810  delete bitmaps;
811  delete pages;
812 }
813 
815 {
816  setupLevel++;
817 }
818 
820 {
821  dbgconverter("Converter reset -----------------------\n");
823  Lock();
824  pages->Clear();
825  bitmaps->Clear();
826  DELETENULL(osd);
827  frozen = false;
828  ddsVersionNumber = -1;
829  displayWidth = windowWidth = 720;
830  displayHeight = windowHeight = 576;
833  Unlock();
834 }
835 
836 int cDvbSubtitleConverter::ConvertFragments(const uchar *Data, int Length)
837 {
838  if (Data && Length > 8) {
839  int PayloadOffset = PesPayloadOffset(Data);
840  int SubstreamHeaderLength = 4;
841  bool ResetSubtitleAssembler = Data[PayloadOffset + 3] == 0x00;
842 
843  // Compatibility mode for old subtitles plugin:
844  if ((Data[7] & 0x01) && (Data[PayloadOffset - 3] & 0x81) == 0x01 && Data[PayloadOffset - 2] == 0x81) {
845  PayloadOffset--;
846  SubstreamHeaderLength = 1;
847  ResetSubtitleAssembler = Data[8] >= 5;
848  }
849 
850  if (Length > PayloadOffset + SubstreamHeaderLength) {
851  int64_t pts = PesHasPts(Data) ? PesGetPts(Data) : 0;
852  if (pts)
853  dbgconverter("Converter PTS: %"PRId64"\n", pts);
854  const uchar *data = Data + PayloadOffset + SubstreamHeaderLength; // skip substream header
855  int length = Length - PayloadOffset - SubstreamHeaderLength; // skip substream header
856  if (ResetSubtitleAssembler)
858 
859  if (length > 3) {
860  if (data[0] == 0x20 && data[1] == 0x00 && data[2] == 0x0F)
861  dvbSubtitleAssembler->Put(data + 2, length - 2);
862  else
863  dvbSubtitleAssembler->Put(data, length);
864 
865  int Count;
866  while (true) {
867  unsigned char *b = dvbSubtitleAssembler->Get(Count);
868  if (b && b[0] == 0x0F) {
869  if (ExtractSegment(b, Count, pts) == -1)
870  break;
871  }
872  else
873  break;
874  }
875  }
876  }
877  return Length;
878  }
879  return 0;
880 }
881 
882 int cDvbSubtitleConverter::Convert(const uchar *Data, int Length)
883 {
884  if (Data && Length > 8) {
885  int PayloadOffset = PesPayloadOffset(Data);
886  if (Length > PayloadOffset) {
887  int64_t pts = PesGetPts(Data);
888  if (pts)
889  dbgconverter("Converter PTS: %"PRId64"\n", pts);
890  const uchar *data = Data + PayloadOffset;
891  int length = Length - PayloadOffset;
892  if (length > 3) {
893  if (data[0] == 0x20 && data[1] == 0x00 && data[2] == 0x0F) {
894  data += 2;
895  length -= 2;
896  }
897  const uchar *b = data;
898  while (length > 0) {
899  if (b[0] == 0x0F) {
900  int n = ExtractSegment(b, length, pts);
901  if (n < 0)
902  break;
903  b += n;
904  length -= n;
905  }
906  else
907  break;
908  }
909  }
910  }
911  return Length;
912  }
913  return 0;
914 }
915 
916 #define LimitTo32Bit(n) ((n) & 0x00000000FFFFFFFFL)
917 #define MAXDELTA 40000 // max. reasonable PTS/STC delta in ms
918 
920 {
921  int LastSetupLevel = setupLevel;
922  cTimeMs Timeout;
923  while (Running()) {
924  int WaitMs = 100;
925  if (!frozen) {
926  LOCK_THREAD;
927  if (osd) {
928  int NewSetupLevel = setupLevel;
929  if (Timeout.TimedOut() || LastSetupLevel != NewSetupLevel) {
930  DELETENULL(osd);
931  }
932  LastSetupLevel = NewSetupLevel;
933  }
934  if (cDvbSubtitleBitmaps *sb = bitmaps->First()) {
935  int64_t STC = cDevice::PrimaryDevice()->GetSTC();
936  int64_t Delta = LimitTo32Bit(sb->Pts()) - LimitTo32Bit(STC); // some devices only deliver 32 bits
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);
941  Delta /= 90; // STC and PTS are in 1/90000s
942  if (Delta <= MAXDELTA) {
943  if (Delta <= 0) {
944  dbgconverter("Got %d bitmaps, showing #%d\n", bitmaps->Count(), sb->Index() + 1);
945  if (AssertOsd()) {
946  sb->Draw(osd);
947  Timeout.Set(sb->Timeout() * 1000);
948  dbgconverter("PTS: %"PRId64" STC: %"PRId64" (%"PRId64") timeout: %d\n", sb->Pts(), cDevice::PrimaryDevice()->GetSTC(), Delta, sb->Timeout());
949  }
950  bitmaps->Del(sb);
951  }
952  else if (Delta < WaitMs)
953  WaitMs = Delta;
954  }
955  else
956  bitmaps->Del(sb);
957  }
958  }
959  cCondWait::SleepMs(WaitMs);
960  }
961 }
962 
964 {
965  int Ey, Epb, Epr;
966  int Eg, Eb, Er;
967 
968  Ey = (Y - 16);
969  Epb = (Cb - 128);
970  Epr = (Cr - 128);
971  /* ITU-R 709 */
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);
975 
976  return (Er << 16) | (Eg << 8) | Eb;
977 }
978 
980 {
981  int OsdWidth, OsdHeight;
982  double OsdAspect;
983  int VideoWidth, VideoHeight;
984  double VideoAspect;
985  cDevice::PrimaryDevice()->GetOsdSize(OsdWidth, OsdHeight, OsdAspect);
986  cDevice::PrimaryDevice()->GetVideoSize(VideoWidth, VideoHeight, VideoAspect);
987  if (OsdWidth == displayWidth && OsdHeight == displayHeight) {
988  osdFactorX = osdFactorY = 1.0;
989  osdDeltaX = osdDeltaY = 0;
990  }
991  else {
992  osdFactorX = VideoAspect * OsdHeight / displayWidth;
993  osdFactorY = double(OsdHeight) / displayHeight;
994  osdDeltaX = (OsdWidth - displayWidth * osdFactorX) / 2;
995  osdDeltaY = (OsdHeight - displayHeight * osdFactorY) / 2;
996  }
997 }
998 
1000 {
1001  LOCK_THREAD;
1002  if (!osd) {
1003  SetOsdData();
1005  }
1006  return osd != NULL;
1007 }
1008 
1009 int cDvbSubtitleConverter::ExtractSegment(const uchar *Data, int Length, int64_t Pts)
1010 {
1011  cBitStream bs(Data, Length * 8);
1012  if (Length > 5 && bs.GetBits(8) == 0x0F) { // sync byte
1013  int segmentType = bs.GetBits(8);
1014  if (segmentType == STUFFING_SEGMENT)
1015  return -1;
1016  int pageId = bs.GetBits(16);
1017  int segmentLength = bs.GetBits(16);
1018  if (!bs.SetLength(bs.Index() + segmentLength * 8))
1019  return -1;
1020  cDvbSubtitlePage *page = NULL;
1021  LOCK_THREAD;
1022  for (cDvbSubtitlePage *sp = pages->First(); sp; sp = pages->Next(sp)) {
1023  if (sp->PageId() == pageId) {
1024  page = sp;
1025  break;
1026  }
1027  }
1028  if (!page) {
1029  page = new cDvbSubtitlePage(pageId);
1030  pages->Add(page);
1031  dbgpages("Create SubtitlePage %d (total pages = %d)\n", pageId, pages->Count());
1032  }
1033  if (Pts)
1034  page->SetPts(Pts);
1035  switch (segmentType) {
1036  case PAGE_COMPOSITION_SEGMENT: {
1037  dbgsegments("PAGE_COMPOSITION_SEGMENT\n");
1038  int pageTimeout = bs.GetBits(8);
1039  int pageVersion = bs.GetBits(4);
1040  if (pageVersion == page->Version())
1041  break; // no update
1042  page->SetVersion(pageVersion);
1043  page->SetTimeout(pageTimeout);
1044  page->SetState(bs.GetBits(2));
1045  bs.SkipBits(2); // reserved
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()) {
1048  cSubtitleRegion *region = page->GetRegionById(bs.GetBits(8), true);
1049  bs.SkipBits(8); // reserved
1050  region->SetHorizontalAddress(bs.GetBits(16));
1051  region->SetVerticalAddress(bs.GetBits(16));
1052  }
1053  break;
1054  }
1056  dbgsegments("REGION_COMPOSITION_SEGMENT\n");
1057  cSubtitleRegion *region = page->GetRegionById(bs.GetBits(8));
1058  if (!region)
1059  break;
1060  int regionVersion = bs.GetBits(4);
1061  if (regionVersion == region->Version())
1062  break; // no update
1063  region->SetVersion(regionVersion);
1064  bool regionFillFlag = bs.GetBit();
1065  bs.SkipBits(3); // reserved
1066  int regionWidth = bs.GetBits(16);
1067  if (regionWidth < 1)
1068  regionWidth = 1;
1069  int regionHeight = bs.GetBits(16);
1070  if (regionHeight < 1)
1071  regionHeight = 1;
1072  region->SetSize(regionWidth, regionHeight);
1073  region->SetLevel(bs.GetBits(3));
1074  region->SetDepth(bs.GetBits(3));
1075  bs.SkipBits(2); // reserved
1076  region->SetClutId(bs.GetBits(8));
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);
1081  bs.SkipBits(2); // reserved
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__);
1088  }
1089  }
1090  while (!bs.IsEOF()) {
1091  cSubtitleObject *object = region->GetObjectById(bs.GetBits(16), true);
1092  int objectType = bs.GetBits(2);
1093  object->SetCodingMethod(objectType);
1094  object->SetProviderFlag(bs.GetBits(2));
1095  int objectHorizontalPosition = bs.GetBits(12);
1096  bs.SkipBits(4); // reserved
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));
1102  }
1103  }
1104  break;
1105  }
1106  case CLUT_DEFINITION_SEGMENT: {
1107  dbgsegments("CLUT_DEFINITION_SEGMENT\n");
1108  cSubtitleClut *clut = page->GetClutById(bs.GetBits(8), true);
1109  int clutVersion = bs.GetBits(4);
1110  if (clutVersion == clut->Version())
1111  break; // no update
1112  clut->SetVersion(clutVersion);
1113  bs.SkipBits(4); // reserved
1114  dbgcluts("Clut pageId %d id %d version %d\n", pageId, clut->ClutId(), clut->Version());
1115  while (!bs.IsEOF()) {
1116  uchar clutEntryId = bs.GetBits(8);
1117  bool entryClut2Flag = bs.GetBit();
1118  bool entryClut4Flag = bs.GetBit();
1119  bool entryClut8Flag = bs.GetBit();
1120  bs.SkipBits(4); // reserved
1121  uchar yval;
1122  uchar crval;
1123  uchar cbval;
1124  uchar tval;
1125  if (bs.GetBit()) { // full_range_flag
1126  yval = bs.GetBits(8);
1127  crval = bs.GetBits(8);
1128  cbval = bs.GetBits(8);
1129  tval = bs.GetBits(8);
1130  }
1131  else {
1132  yval = bs.GetBits(6) << 2;
1133  crval = bs.GetBits(4) << 4;
1134  cbval = bs.GetBits(4) << 4;
1135  tval = bs.GetBits(2) << 6;
1136  }
1137  tColor value = 0;
1138  if (yval) {
1139  value = yuv2rgb(yval, cbval, crval);
1140  value |= ((10 - (clutEntryId ? Setup.SubtitleFgTransparency : Setup.SubtitleBgTransparency)) * (255 - tval) / 10) << 24;
1141  }
1142  dbgcluts("%2d %d %d %d %08X\n", clutEntryId, entryClut2Flag ? 2 : 0, entryClut4Flag ? 4 : 0, entryClut8Flag ? 8 : 0, value);
1143  if (entryClut2Flag)
1144  clut->SetColor(2, clutEntryId, value);
1145  if (entryClut4Flag)
1146  clut->SetColor(4, clutEntryId, value);
1147  if (entryClut8Flag)
1148  clut->SetColor(8, clutEntryId, value);
1149  }
1150  dbgcluts("\n");
1151  break;
1152  }
1153  case OBJECT_DATA_SEGMENT: {
1154  dbgsegments("OBJECT_DATA_SEGMENT\n");
1155  cSubtitleObject *object = page->GetObjectById(bs.GetBits(16));
1156  if (!object)
1157  break;
1158  int objectVersion = bs.GetBits(4);
1159  if (objectVersion == object->Version())
1160  break; // no update
1161  object->SetVersion(objectVersion);
1162  int codingMethod = bs.GetBits(2);
1163  object->SetNonModifyingColorFlag(bs.GetBit());
1164  bs.SkipBit(); // reserved
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) { // coding of pixels
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);
1172  else
1173  object->DecodeSubBlock(bs.GetData(), topFieldLength, false);
1174  bs.WordAlign();
1175  }
1176  else if (codingMethod == 1) { // coded as a string of characters
1177  int numberOfCodes = bs.GetBits(8);
1178  object->DecodeCharacterString(bs.GetData(), numberOfCodes);
1179  }
1180 #ifdef FINISHPAGE_HACK
1181  FinishPage(page); // flush to OSD right away
1182 #endif
1183  break;
1184  }
1186  dbgsegments("DISPLAY_DEFINITION_SEGMENT\n");
1187  int version = bs.GetBits(4);
1188  if (version != ddsVersionNumber) {
1189  bool displayWindowFlag = bs.GetBit();
1192  bs.SkipBits(3); // reserved
1193  displayWidth = windowWidth = bs.GetBits(16) + 1;
1194  displayHeight = windowHeight = bs.GetBits(16) + 1;
1195  if (displayWindowFlag) {
1196  windowHorizontalOffset = bs.GetBits(16); // displayWindowHorizontalPositionMinimum
1197  windowWidth = bs.GetBits(16) - windowHorizontalOffset + 1; // displayWindowHorizontalPositionMaximum
1198  windowVerticalOffset = bs.GetBits(16); // displayWindowVerticalPositionMinimum
1199  windowHeight = bs.GetBits(16) - windowVerticalOffset + 1; // displayWindowVerticalPositionMaximum
1200  }
1201  SetOsdData();
1202  SetupChanged();
1203  ddsVersionNumber = version;
1204  }
1205  break;
1206  }
1208  dbgsegments("DISPARITY_SIGNALING_SEGMENT\n");
1209  bs.SkipBits(4); // dss_version_number
1210  bool disparity_shift_update_sequence_page_flag = bs.GetBit();
1211  bs.SkipBits(3); // reserved
1212  bs.SkipBits(8); // page_default_disparity_shift
1213  if (disparity_shift_update_sequence_page_flag) {
1214  bs.SkipBits(8); // disparity_shift_update_sequence_length
1215  bs.SkipBits(24); // interval_duration[23..0]
1216  int division_period_count = bs.GetBits(8);
1217  for (int i = 0; i < division_period_count; ++i) {
1218  bs.SkipBits(8); // interval_count
1219  bs.SkipBits(8); // disparity_shift_update_integer_part
1220  }
1221  }
1222  while (!bs.IsEOF()) {
1223  bs.SkipBits(8); // region_id
1224  bool disparity_shift_update_sequence_region_flag = bs.GetBit();
1225  bs.SkipBits(5); // reserved
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) {
1229  bs.SkipBits(16); // subregion_horizontal_position
1230  bs.SkipBits(16); // subregion_width
1231  }
1232  bs.SkipBits(8); // subregion_disparity_shift_integer_part
1233  bs.SkipBits(4); // subregion_disparity_shift_fractional_part
1234  bs.SkipBits(4); // reserved
1235  if (disparity_shift_update_sequence_region_flag) {
1236  bs.SkipBits(8); // disparity_shift_update_sequence_length
1237  bs.SkipBits(24); // interval_duration[23..0]
1238  int division_period_count = bs.GetBits(8);
1239  for (int i = 0; i < division_period_count; ++i) {
1240  bs.SkipBits(8); // interval_count
1241  bs.SkipBits(8); // disparity_shift_update_integer_part
1242  }
1243  }
1244  }
1245  }
1246  break;
1247  }
1249  dbgsegments("END_OF_DISPLAY_SET_SEGMENT\n");
1250  FinishPage(page);
1251  break;
1252  }
1253  default:
1254  dbgsegments("*** unknown segment type: %02X\n", segmentType);
1255  }
1256  return bs.Length() / 8;
1257  }
1258  return -1;
1259 }
1260 
1262 {
1263  if (!AssertOsd())
1264  return;
1265  tArea *Areas = Page->GetAreas(osdFactorX, osdFactorY);
1266  int NumAreas = Page->regions.Count();
1267  int Bpp = 8;
1268  bool Reduced = false;
1269  while (osd && osd->CanHandleAreas(Areas, NumAreas) != oeOk) {
1270  int HalfBpp = Bpp / 2;
1271  if (HalfBpp >= 2) {
1272  for (int i = 0; i < NumAreas; i++) {
1273  if (Areas[i].bpp >= Bpp) {
1274  Areas[i].bpp = HalfBpp;
1275  Reduced = true;
1276  }
1277  }
1278  Bpp = HalfBpp;
1279  }
1280  else
1281  return; // unable to draw bitmaps
1282  }
1283  cDvbSubtitleBitmaps *Bitmaps = new cDvbSubtitleBitmaps(Page->Pts(), Page->Timeout(), Areas, NumAreas, osdFactorX, osdFactorY);
1284  bitmaps->Add(Bitmaps);
1285  for (int i = 0; i < NumAreas; i++) {
1286  cSubtitleRegion *sr = Page->regions.Get(i);
1287  cSubtitleClut *clut = Page->GetClutById(sr->ClutId());
1288  if (!clut)
1289  continue;
1290  sr->Replace(*clut->GetPalette(sr->Bpp()));
1291  sr->UpdateTextData(clut);
1292  if (Reduced) {
1293  if (sr->Bpp() != Areas[i].bpp) {
1294  if (sr->Level() <= Areas[i].bpp) {
1295  //TODO this is untested - didn't have any such subtitle stream
1296  cSubtitleClut *Clut = Page->GetClutById(sr->ClutId());
1297  if (Clut) {
1298  dbgregions("reduce region %d bpp %d level %d area bpp %d\n", sr->RegionId(), sr->Bpp(), sr->Level(), Areas[i].bpp);
1299  sr->ReduceBpp(*Clut->GetPalette(sr->Bpp()));
1300  }
1301  }
1302  else {
1303  dbgregions("condense region %d bpp %d level %d area bpp %d\n", sr->RegionId(), sr->Bpp(), sr->Level(), Areas[i].bpp);
1304  sr->ShrinkBpp(Areas[i].bpp);
1305  }
1306  }
1307  }
1308  int posX = sr->HorizontalAddress();
1309  int posY = sr->VerticalAddress();
1310  if (sr->Width() > 0 && sr->Height() > 0) {
1311  cBitmap *bm = new cBitmap(sr->Width(), sr->Height(), sr->Bpp(), posX, posY);
1312  bm->DrawBitmap(posX, posY, *sr);
1313  Bitmaps->AddBitmap(bm);
1314  }
1315  }
1316 }
cVector< cBitmap * > bitmaps
Definition: dvbsubtitle.c:723
void ReduceBpp(const cPalette &Palette)
Reduces the color depth of the bitmap to that of the given Palette.
Definition: osd.c:754
int y2
Definition: osd.h:295
unsigned char uchar
Definition: tools.h:30
void SetVersion(int Version)
Definition: dvbsubtitle.c:444
void SetProviderFlag(int ProviderFlag)
Definition: dvbsubtitle.c:191
cList< cDvbSubtitlePage > * pages
Definition: dvbsubtitle.h:40
bool NonModifyingColorFlag(void)
Definition: dvbsubtitle.c:182
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 ...
Definition: osd.c:522
static bool DebugConverter
Definition: dvbsubtitle.c:31
void DecodeSubBlock(const uchar *Data, int Length, bool Even)
Definition: dvbsubtitle.c:237
static bool DebugCluts
Definition: dvbsubtitle.c:36
int Index(void) const
Definition: tools.c:1920
int Utf8StrLen(const char *s)
Returns the number of UTF-8 symbols formed by the given string of character bytes.
Definition: tools.c:784
void Set(int Ms=0)
Definition: tools.c:689
cPalette palette2
Definition: dvbsubtitle.c:51
void SetNonModifyingColorFlag(bool NonModifyingColorFlag)
Definition: dvbsubtitle.c:188
int PesPayloadOffset(const uchar *p)
Definition: remux.h:166
#define dbgconverter(a...)
Definition: dvbsubtitle.c:38
bool Decode2BppCodeString(cBitStream *bs, int &x, int y, const uint8_t *MapTable)
Definition: dvbsubtitle.c:311
void SetForegroundPixelCode(uchar ForegroundPixelCode)
Definition: dvbsubtitle.c:187
uint32_t GetBits(int n)
Definition: tools.c:1286
int PageId(void)
Definition: dvbsubtitle.c:531
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:1945
int Convert(const uchar *Data, int Length)
Definition: dvbsubtitle.c:882
bool Decode8BppCodeString(cBitStream *bs, int &x, int y)
Definition: dvbsubtitle.c:396
virtual eOsdError SetAreas(const tArea *Areas, int NumAreas)
Sets the sub-areas to the given areas.
Definition: osd.c:1800
int Level(void)
Definition: dvbsubtitle.c:438
void SetVersion(int Version)
Definition: dvbsubtitle.c:540
#define CLUT_DEFINITION_SEGMENT
Definition: dvbsubtitle.c:23
cList< cSubtitleObject > objects
Definition: dvbsubtitle.c:432
#define DISPARITY_SIGNALING_SEGMENT
Definition: dvbsubtitle.c:26
int x1
Definition: osd.h:295
virtual void GetVideoSize(int &Width, int &Height, double &VideoAspect)
Returns the Width, Height and VideoAspect ratio of the currently displayed video material.
Definition: device.c:478
const uint8_t * GetData(void) const
Definition: tools.h:320
cSubtitleObject * GetObjectById(int ObjectId, bool New=false)
Definition: dvbsubtitle.c:474
const char * getCharacterTable(const unsigned char *&buffer, int &length, bool *isSingleByte)
Definition: si.c:345
uchar BackgroundPixelCode(void)
Definition: dvbsubtitle.c:177
int HorizontalAddress(void)
Definition: dvbsubtitle.c:442
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 ...
Definition: osd.c:1899
int CodingMethod(void)
Definition: dvbsubtitle.c:176
int64_t PesGetPts(const uchar *p)
Definition: remux.h:181
int Version(void)
Definition: dvbsubtitle.c:532
virtual void Append(T Data)
Definition: tools.h:545
uchar backgroundPixelCode
Definition: dvbsubtitle.c:161
void Action(void)
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
Definition: dvbsubtitle.c:919
void SkipBit(void)
Definition: tools.h:315
#define REGION_COMPOSITION_SEGMENT
Definition: dvbsubtitle.c:22
void Draw(cOsd *Osd)
Definition: dvbsubtitle.c:755
cBitmap * Scaled(double FactorX, double FactorY, bool AntiAlias=false)
Creates a copy of this bitmap, scaled by the given factors.
Definition: osd.c:827
#define esyslog(a...)
Definition: tools.h:34
static void SetupChanged(void)
Definition: dvbsubtitle.c:814
#define OBJECT_DATA_SEGMENT
Definition: dvbsubtitle.c:24
int bpp
Definition: osd.h:296
cDvbSubtitleAssembler * dvbSubtitleAssembler
Definition: dvbsubtitle.h:26
T * Get(int Index) const
Definition: tools.h:481
bool TimedOut(void)
Definition: tools.c:694
#define dbgcluts(a...)
Definition: dvbsubtitle.c:43
T max(T a, T b)
Definition: tools.h:55
#define dbgregions(a...)
Definition: dvbsubtitle.c:41
bool PesHasPts(const uchar *p)
Definition: remux.h:171
int ClutId(void)
Definition: dvbsubtitle.c:56
int Version(void)
Definition: dvbsubtitle.c:175
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 ...
Definition: device.c:485
void SetHorizontalAddress(int HorizontalAddress)
Definition: dvbsubtitle.c:448
static bool DebugSegments
Definition: dvbsubtitle.c:32
int Count(void) const
Definition: tools.h:475
int Version(void)
Definition: dvbsubtitle.c:436
virtual ~cDvbSubtitlePage()
Definition: dvbsubtitle.c:555
cSubtitleClut * GetClutById(int ClutId, bool New=false)
Definition: dvbsubtitle.c:579
bool Decode4BppCodeString(cBitStream *bs, int &x, int y, const uint8_t *MapTable)
Definition: dvbsubtitle.c:351
void WordAlign(void)
Definition: tools.c:1301
cSubtitleClut(int ClutId)
Definition: dvbsubtitle.c:63
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).
Definition: tools.c:906
unsigned char * Get(int &Length)
Definition: dvbsubtitle.c:692
cBitmap * bitmap
Definition: dvbsubtitle.c:166
cList< cSubtitleRegion > regions
Definition: dvbsubtitle.c:528
void UpdateTextData(cSubtitleClut *Clut)
Definition: dvbsubtitle.c:488
void DecodeCharacterString(const uchar *Data, int NumberOfCodes)
Definition: dvbsubtitle.c:208
int Bpp(void) const
Definition: osd.h:111
cSubtitleObject * GetObjectById(int ObjectId)
Definition: dvbsubtitle.c:607
static bool DebugPages
Definition: dvbsubtitle.c:33
virtual void Flush(void)
Actually commits all data to the OSD hardware.
Definition: osd.c:1949
int Length(void) const
Definition: tools.h:318
virtual void Clear(void)
Definition: tools.c:2018
Definition: osd.h:169
int Width(void) const
Definition: osd.h:188
cSubtitleRegion * GetRegionById(int RegionId, bool New=false)
Definition: dvbsubtitle.c:593
int ObjectId(void)
Definition: dvbsubtitle.c:174
cList< cSubtitleClut > cluts
Definition: dvbsubtitle.c:526
void SetSize(int Width, int Height)
Sets the size of this bitmap to the given values.
Definition: osd.c:294
void SetLevel(int Level)
Definition: dvbsubtitle.c:505
void SetPts(int64_t Pts)
Definition: dvbsubtitle.c:541
const char * TextData(void)
Definition: dvbsubtitle.c:179
static bool DebugObjects
Definition: dvbsubtitle.c:35
void Unlock(void)
Definition: thread.h:93
virtual int Height(void) const =0
Returns the height of this font in pixel (all characters have the same height).
int Width(void) const
Definition: osd.h:297
void Replace(const cPalette &Palette)
Replaces the colors of this palette with the colors from the given palette.
Definition: osd.c:208
void SetVersion(int Version)
Definition: dvbsubtitle.c:58
bool IsEOF(void) const
Definition: tools.h:316
tColor yuv2rgb(int Y, int Cb, int Cr)
Definition: dvbsubtitle.c:963
T * Next(const T *object) const
Definition: tools.h:485
void SetBackgroundPixelCode(uchar BackgroundPixelCode)
Definition: dvbsubtitle.c:186
#define PAGE_COMPOSITION_SEGMENT
Definition: dvbsubtitle.c:21
T constrain(T v, T l, T h)
Definition: tools.h:60
static bool DebugRegions
Definition: dvbsubtitle.c:34
int SubtitleFgTransparency
Definition: config.h:283
void SetState(int State)
Definition: dvbsubtitle.c:615
virtual ~cDvbSubtitleConverter()
Definition: dvbsubtitle.c:805
int Height(void) const
Definition: osd.h:189
cSubtitleObject(int ObjectId, cBitmap *Bitmap)
Definition: dvbsubtitle.c:194
virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas)
Checks whether the OSD can display the given set of sub-areas.
Definition: osd.c:1778
char FontOsd[MAXFONTNAME]
Definition: config.h:316
cPalette palette8
Definition: dvbsubtitle.c:53
static void SleepMs(int TimeoutMs)
Creates a cCondWait object and uses it to sleep for TimeoutMs milliseconds, immediately giving up the...
Definition: thread.c:57
#define MAXOSDAREAS
Definition: osd.h:703
#define STUFFING_SEGMENT
Definition: dvbsubtitle.c:28
int x2
Definition: osd.h:295
void bool Start(void)
Actually starts the thread.
Definition: thread.c:273
The cOsd class is the interface to the "On Screen Display".
Definition: osd.h:716
int SubtitleOffset
Definition: config.h:282
uchar ForegroundPixelCode(void)
Definition: dvbsubtitle.c:178
cSetup Setup
Definition: config.c:372
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...
Definition: font.c:423
bool Running(void)
Returns false if a derived cThread object shall leave its Action() function.
Definition: thread.h:99
void AddBitmap(cBitmap *Bitmap)
Definition: dvbsubtitle.c:750
int Size(void) const
Definition: tools.h:533
void SkipBits(int n)
Definition: tools.h:314
void SetColor(int Index, tColor Color)
Sets the palette entry at Index to Color.
Definition: osd.c:172
int ClutId(void)
Definition: dvbsubtitle.c:437
int Y0(void) const
Definition: osd.h:187
void FillRegion(tIndex Index)
Definition: dvbsubtitle.c:465
void ShrinkBpp(int NewBpp)
Shrinks the color depth of the bitmap to NewBpp by keeping only the 2^NewBpp most frequently used col...
Definition: osd.c:785
int64_t Pts(void)
Definition: dvbsubtitle.c:727
tColor ArgbToColor(uint8_t A, uint8_t R, uint8_t G, uint8_t B)
Definition: osd.h:58
void SetTimeout(int Timeout)
Definition: dvbsubtitle.c:543
uchar foregroundPixelCode
Definition: dvbsubtitle.c:162
#define OSD_LEVEL_SUBTITLES
Definition: osd.h:22
void DrawLine(int x, int y, tIndex Index, int Length)
Definition: dvbsubtitle.c:301
void SetVerticalAddress(int VerticalAddress)
Definition: dvbsubtitle.c:449
int Version(void)
Definition: dvbsubtitle.c:57
#define MAXDELTA
Definition: dvbsubtitle.c:917
T * First(void) const
Definition: tools.h:482
cDvbSubtitleBitmaps(int64_t Pts, int Timeout, tArea *Areas, int NumAreas, double OsdFactorX, double OsdFactorY)
Definition: dvbsubtitle.c:733
void Del(cListObject *Object, bool DeleteObject=true)
Definition: tools.c:1977
void SetColor(int Bpp, int Index, tColor Color)
Definition: dvbsubtitle.c:132
int y1
Definition: osd.h:295
tArea * GetAreas(double FactorX, double FactorY)
Definition: dvbsubtitle.c:559
Definition: osd.h:88
#define dbgpages(a...)
Definition: dvbsubtitle.c:40
bool Realloc(int Size)
Definition: dvbsubtitle.c:672
Definition: osd.h:294
void FinishPage(cDvbSubtitlePage *Page)
Definition: dvbsubtitle.c:1261
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition: device.h:132
int Depth(void)
Definition: dvbsubtitle.c:439
cDvbSubtitlePage(int PageId)
Definition: dvbsubtitle.c:546
#define LimitTo32Bit(n)
Definition: dvbsubtitle.c:916
#define DISPLAY_DEFINITION_SEGMENT
Definition: dvbsubtitle.c:25
void DELETENULL(T *&p)
Definition: tools.h:48
virtual int64_t GetSTC(void)
Gets the current System Time Counter, which can be used to synchronize audio, video and subtitles...
Definition: device.c:1178
int ExtractSegment(const uchar *Data, int Length, int64_t Pts)
Definition: dvbsubtitle.c:1009
int GetBit(void)
Definition: tools.c:1277
Definition: thread.h:77
void SetCodingMethod(int CodingMethod)
Definition: dvbsubtitle.c:189
virtual ~cDvbSubtitleAssembler()
Definition: dvbsubtitle.c:661
void SetPosition(int x, int y)
Definition: dvbsubtitle.c:190
int FontOsdSize
Definition: config.h:322
Definition: osd.h:44
cList< cDvbSubtitleBitmaps > * bitmaps
Definition: dvbsubtitle.h:41
virtual int Width(uint c) const =0
Returns the width of the given character in pixel.
int State(void)
Definition: dvbsubtitle.c:533
Definition: tools.h:323
#define END_OF_DISPLAY_SET_SEGMENT
Definition: dvbsubtitle.c:27
#define dbgobjects(a...)
Definition: dvbsubtitle.c:42
int64_t Pts(void) const
Definition: dvbsubtitle.c:538
bool SetLength(int Length)
Definition: tools.c:1308
void SetVersion(int Version)
Definition: dvbsubtitle.c:185
bool DoubleEqual(double a, double b)
Definition: tools.h:85
void SetBpp(int Bpp)
Sets the color depth of this palette to the given value.
Definition: osd.c:165
char textData[Utf8BufSize(256)]
Definition: dvbsubtitle.c:167
#define dbgsegments(a...)
Definition: dvbsubtitle.c:39
const cPalette * GetPalette(int Bpp)
Definition: dvbsubtitle.c:142
void Put(const uchar *Data, int Length)
Definition: dvbsubtitle.c:705
#define LOCK_THREAD
Definition: thread.h:161
int VerticalAddress(void)
Definition: dvbsubtitle.c:443
int X0(void) const
Definition: osd.h:186
char * Utf8Strn0Cpy(char *Dest, const char *Src, int n)
Copies at most n character bytes from Src to Dest, making sure that the resulting copy ends with a co...
Definition: tools.c:796
cPalette palette4
Definition: dvbsubtitle.c:52
int Index(void) const
Definition: tools.h:319
int Timeout(void)
Definition: dvbsubtitle.c:539
void Cancel(int WaitSeconds=0)
Cancels the thread by first setting 'running' to false, so that the Action() loop can finish in an or...
Definition: thread.c:323
void SetIndex(int x, int y, tIndex Index)
Sets the index at the given coordinates to Index.
Definition: osd.c:500
int RegionId(void)
Definition: dvbsubtitle.c:435
int ConvertFragments(const uchar *Data, int Length)
Definition: dvbsubtitle.c:836
void SetClutId(int ClutId)
Definition: dvbsubtitle.c:445
static int setupLevel
Definition: dvbsubtitle.h:25
int SubtitleBgTransparency
Definition: config.h:283
Definition: font.h:37
void ByteAlign(void)
Definition: tools.c:1294
#define Utf8BufSize(s)
Definition: tools.h:131
void SetDepth(int Depth)
Definition: dvbsubtitle.c:511
uint32_t tColor
Definition: font.h:29
void Lock(void)
Definition: thread.h:92
bool nonModifyingColorFlag
Definition: dvbsubtitle.c:160
cSubtitleRegion(int RegionId)
Definition: dvbsubtitle.c:453
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...
Definition: osd.c:1972