vdr  1.7.31
hdffosd.c
Go to the documentation of this file.
1 /*
2  * hdffosd.c: Implementation of the DVB HD Full Featured On Screen Display
3  *
4  * See the README file for copyright information and how to reach the author.
5  *
6  * $Id: hdffosd.c 1.17 2012/06/16 11:17:11 kls Exp $
7  */
8 
9 #include "hdffosd.h"
10 #include <linux/dvb/osd.h>
11 #include <sys/ioctl.h>
12 #include <sys/time.h>
13 #include "hdffcmd.h"
14 #include "setup.h"
15 
16 #define MAX_NUM_FONTFACES 8
17 #define MAX_NUM_FONTS 8
18 #define MAX_BITMAP_SIZE (1024*1024)
19 
20 typedef struct _tFontFace
21 {
23  uint32_t Handle;
24 } tFontFace;
25 
26 typedef struct _tFont
27 {
28  uint32_t hFontFace;
29  int Size;
30  uint32_t Handle;
31 } tFont;
32 
33 class cHdffOsd : public cOsd
34 {
35 private:
37  int mLeft;
38  int mTop;
41  bool shown;
42  bool mChanged;
43  uint32_t mDisplay;
46  uint32_t mBitmapPalette;
47  uint32_t mBitmapColors[256];
48  uint32_t mBitmapNumColors;
49 
51 
52 protected:
53  virtual void SetActive(bool On);
54 public:
55  cHdffOsd(int Left, int Top, HDFF::cHdffCmdIf * pHdffCmdIf, uint Level);
56  virtual ~cHdffOsd();
57  virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas);
58  virtual eOsdError SetAreas(const tArea *Areas, int NumAreas);
59  virtual void SaveRegion(int x1, int y1, int x2, int y2);
60  virtual void RestoreRegion(void);
61  virtual void DrawPixel(int x, int y, tColor Color);
62  virtual void DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg = 0, tColor ColorBg = 0, bool ReplacePalette = false, bool Overlay = false);
63  virtual void DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width = 0, int Height = 0, int Alignment = taDefault);
64  virtual void DrawRectangle(int x1, int y1, int x2, int y2, tColor Color);
65  virtual void DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants = 0);
66  virtual void DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type);
67  virtual void Flush(void);
68 };
69 
70 cHdffOsd::cHdffOsd(int Left, int Top, HDFF::cHdffCmdIf * pHdffCmdIf, uint Level)
71 : cOsd(Left, Top, Level)
72 {
73  double pixelAspect;
74  HdffOsdConfig_t config;
75 
76  //printf("cHdffOsd %d, %d, %d\n", Left, Top, Level);
77  mHdffCmdIf = pHdffCmdIf;
78  mLeft = Left;
79  mTop = Top;
80  shown = false;
81  mChanged = false;
83 
84  mSupportsUtf8Text = false;
85  if (mHdffCmdIf->CmdGetFirmwareVersion(NULL, 0) >= 0x309)
86  mSupportsUtf8Text = true;
87 
88  memset(&config, 0, sizeof(config));
89  config.FontKerning = true;
90  config.FontAntialiasing = Setup.AntiAlias ? true : false;
91  mHdffCmdIf->CmdOsdConfigure(&config);
92 
96  for (int i = 0; i < MAX_NUM_FONTFACES; i++)
97  {
98  mFontFaces[i].Name = "";
100  }
101  for (int i = 0; i < MAX_NUM_FONTS; i++)
102  {
104  mFonts[i].Size = 0;
106  }
107 }
108 
110 {
111  //printf("~cHdffOsd %d %d\n", mLeft, mTop);
112  SetActive(false);
113 
114  for (int i = 0; i < MAX_NUM_FONTS; i++)
115  {
116  if (mFonts[i].Handle == HDFF_INVALID_HANDLE)
117  break;
118  mHdffCmdIf->CmdOsdDeleteFont(mFonts[i].Handle);
119  }
120  for (int i = 0; i < MAX_NUM_FONTFACES; i++)
121  {
122  if (mFontFaces[i].Handle == HDFF_INVALID_HANDLE)
123  break;
125  }
126 
132 }
133 
134 eOsdError cHdffOsd::CanHandleAreas(const tArea *Areas, int NumAreas)
135 {
136  eOsdError Result = cOsd::CanHandleAreas(Areas, NumAreas);
137  if (Result == oeOk)
138  {
139  for (int i = 0; i < NumAreas; i++)
140  {
141  if (Areas[i].bpp != 1 && Areas[i].bpp != 2 && Areas[i].bpp != 4 && Areas[i].bpp != 8)
142  return oeBppNotSupported;
143  }
144  }
145  return Result;
146 }
147 
148 eOsdError cHdffOsd::SetAreas(const tArea *Areas, int NumAreas)
149 {
150  eOsdError error;
151  cBitmap * bitmap;
152 
153  for (int i = 0; i < NumAreas; i++)
154  {
155  //printf("SetAreas %d: %d %d %d %d %d\n", i, Areas[i].x1, Areas[i].y1, Areas[i].x2, Areas[i].y2, Areas[i].bpp);
156  }
157  if (shown)
158  {
161  shown = false;
162  }
163  error = cOsd::SetAreas(Areas, NumAreas);
164 
165  for (int i = 0; (bitmap = GetBitmap(i)) != NULL; i++)
166  {
167  bitmap->Clean();
168  }
169 
170  return error;
171 }
172 
173 void cHdffOsd::SetActive(bool On)
174 {
175  if (On != Active())
176  {
177  cOsd::SetActive(On);
178  if (On)
179  {
180  if (GetBitmap(0)) // only flush here if there are already bitmaps
181  Flush();
182  }
183  else if (shown)
184  {
187  shown = false;
188  }
189  }
190 }
191 
192 void cHdffOsd::SaveRegion(int x1, int y1, int x2, int y2)
193 {
194  mHdffCmdIf->CmdOsdSaveRegion(mDisplay, mLeft + x1, mTop + y1, x2 - x1 + 1, y2 - y1 + 1);
195  mChanged = true;
196 }
197 
199 {
201  mChanged = true;
202 }
203 
204 void cHdffOsd::DrawPixel(int x, int y, tColor Color)
205 {
206  //printf("DrawPixel\n");
207 }
208 
209 void cHdffOsd::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay)
210 {
211  //printf("DrawBitmap %d %d %d x %d\n", x, y, Bitmap.Width(), Bitmap.Height());
212  int i;
213  int numColors;
214  const tColor * colors = Bitmap.Colors(numColors);
215 
216  for (i = 0; i < numColors; i++)
217  {
218  mBitmapColors[i] = colors[i];
219  if (ColorFg || ColorBg)
220  {
221  if (i == 0)
222  mBitmapColors[i] = ColorBg;
223  else if (i == 1)
224  mBitmapColors[i] = ColorFg;
225  }
226  }
228  {
231  }
232  else
233  {
235  HDFF_COLOR_FORMAT_ARGB, 0, numColors, mBitmapColors);
236  }
237  int width = Bitmap.Width();
238  int height = Bitmap.Height();
239  int chunk = MAX_BITMAP_SIZE / width;
240  if (chunk > height)
241  chunk = height;
242  for (int yc = 0; yc < height; yc += chunk)
243  {
244  int hc = chunk;
245  if (yc + hc > height)
246  hc = height - yc;
248  (uint8_t *) Bitmap.Data(0, yc), width, hc,
250  }
251  mChanged = true;
252 }
253 
254 void cHdffOsd::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
255 {
256  int w = Font->Width(s);
257  int h = Font->Height();
258  int limit = 0;
259  int cw = Width ? Width : w;
260  int ch = Height ? Height : h;
261  int i;
262  int size = Font->Size();
263  tFontFace * pFontFace;
264  tFont * pFont;
265 
266  if (ColorBg != clrTransparent)
267  mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, mLeft + x, mTop + y, cw, ch, ColorBg);
268 
269  if (s == NULL)
270  return;
271 
272  pFontFace = NULL;
273  for (i = 0; i < MAX_NUM_FONTFACES; i++)
274  {
275  if (mFontFaces[i].Handle == HDFF_INVALID_HANDLE)
276  break;
277 
278  if (strcmp(mFontFaces[i].Name, Font->FontName()) == 0)
279  {
280  pFontFace = &mFontFaces[i];
281  break;
282  }
283  }
284  if (pFontFace == NULL)
285  {
286  if (i < MAX_NUM_FONTFACES)
287  {
288  cString fontFileName = Font->FontName();
289  FILE * fp = fopen(fontFileName, "rb");
290  if (fp)
291  {
292  fseek(fp, 0, SEEK_END);
293  long fileSize = ftell(fp);
294  fseek(fp, 0, SEEK_SET);
295  if (fileSize > 0)
296  {
297  uint8_t * buffer = new uint8_t[fileSize];
298  if (buffer)
299  {
300  if (fread(buffer, fileSize, 1, fp) == 1)
301  {
302  mFontFaces[i].Handle = mHdffCmdIf->CmdOsdCreateFontFace(buffer, fileSize);
303  if (mFontFaces[i].Handle != HDFF_INVALID_HANDLE)
304  {
305  mFontFaces[i].Name = Font->FontName();
306  pFontFace = &mFontFaces[i];
307  }
308  }
309  delete[] buffer;
310  }
311  }
312  fclose(fp);
313  }
314  }
315  }
316  if (pFontFace == NULL)
317  return;
318 
319  pFont = NULL;
320  for (i = 0; i < MAX_NUM_FONTS; i++)
321  {
322  if (mFonts[i].Handle == HDFF_INVALID_HANDLE)
323  break;
324 
325  if (mFonts[i].hFontFace == pFontFace->Handle
326  && mFonts[i].Size == size)
327  {
328  pFont = &mFonts[i];
329  break;
330  }
331  }
332  if (pFont == NULL)
333  {
334  if (i < MAX_NUM_FONTS)
335  {
336  mFonts[i].Handle = mHdffCmdIf->CmdOsdCreateFont(pFontFace->Handle, size);
337  if (mFonts[i].Handle != HDFF_INVALID_HANDLE)
338  {
339  mFonts[i].hFontFace = pFontFace->Handle;
340  mFonts[i].Size = size;
341  pFont = &mFonts[i];
342  }
343  }
344  }
345  if (pFont == NULL)
346  return;
347 
348  mHdffCmdIf->CmdOsdSetDisplayClippingArea(mDisplay, true, mLeft + x, mTop + y, cw, ch);
349 
350  if (Width || Height)
351  {
352  limit = x + cw;// - mLeft;
353  if (Width)
354  {
355  if ((Alignment & taLeft) != 0)
356  {
357 #if (APIVERSNUM >= 10728)
358  if ((Alignment & taBorder) != 0)
359  x += max(h / TEXT_ALIGN_BORDER, 1);
360 #endif
361  }
362  else if ((Alignment & taRight) != 0)
363  {
364  if (w < Width)
365  x += Width - w;
366 #if (APIVERSNUM >= 10728)
367  if ((Alignment & taBorder) != 0)
368  x -= max(h / TEXT_ALIGN_BORDER, 1);
369 #endif
370  }
371  else
372  { // taCentered
373  if (w < Width)
374  x += (Width - w) / 2;
375  }
376  }
377  if (Height)
378  {
379  if ((Alignment & taTop) != 0)
380  ;
381  else if ((Alignment & taBottom) != 0)
382  {
383  if (h < Height)
384  y += Height - h;
385  }
386  else
387  { // taCentered
388  if (h < Height)
389  y += (Height - h) / 2;
390  }
391  }
392  }
393  if (mSupportsUtf8Text)
394  {
395  mHdffCmdIf->CmdOsdDrawUtf8Text(mDisplay, pFont->Handle, x + mLeft, y + mTop + h, s, ColorFg);
396  }
397  else
398  {
399  uint16_t tmp[1000];
400  uint16_t len = 0;
401  while (*s && (len < (sizeof(tmp) - 1)))
402  {
403  int sl = Utf8CharLen(s);
404  uint sym = Utf8CharGet(s, sl);
405  s += sl;
406  tmp[len] = sym;
407  len++;
408  }
409  tmp[len] = 0;
410  mHdffCmdIf->CmdOsdDrawTextW(mDisplay, pFont->Handle, x + mLeft, y + mTop + h, tmp, ColorFg);
411  }
412  mHdffCmdIf->CmdOsdSetDisplayClippingArea(mDisplay, false, 0, 0, 0, 0);
413  mChanged = true;
414 }
415 
416 void cHdffOsd::DrawRectangle(int x1, int y1, int x2, int y2, tColor Color)
417 {
418  mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, mLeft + x1, mTop + y1, x2 - x1 + 1, y2 - y1 + 1, Color);
419  mChanged = true;
420 }
421 
422 void cHdffOsd::DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants)
423 {
424  uint32_t flags;
425  int cx;
426  int cy;
427  int rx;
428  int ry;
429 
430  switch (abs(Quadrants))
431  {
432  case 1:
433  if (Quadrants > 0)
435  else
437  cx = x1;
438  cy = y2;
439  rx = x2 - x1;
440  ry = y2 - y1;
441  break;
442  case 2:
443  if (Quadrants > 0)
445  else
447  cx = x2;
448  cy = y2;
449  rx = x2 - x1;
450  ry = y2 - y1;
451  break;
452  case 3:
453  if (Quadrants > 0)
455  else
457  cx = x2;
458  cy = y1;
459  rx = x2 - x1;
460  ry = y2 - y1;
461  break;
462  case 4:
463  if (Quadrants > 0)
465  else
467  cx = x1;
468  cy = y1;
469  rx = x2 - x1;
470  ry = y2 - y1;
471  break;
472  case 5:
473  flags = HDFF_DRAW_HALF_RIGHT;
474  cx = x1;
475  cy = (y1 + y2) / 2;
476  rx = x2 - x1;
477  ry = (y2 - y1) / 2;
478  break;
479  case 6:
480  flags = HDFF_DRAW_HALF_TOP;
481  cx = (x1 + x2) / 2;
482  cy = y2;
483  rx = (x2 - x1) / 2;
484  ry = y2 - y1;
485  break;
486  case 7:
487  flags = HDFF_DRAW_HALF_LEFT;
488  cx = x2;
489  cy = (y1 + y2) / 2;
490  rx = x2 - x1;
491  ry = (y2 - y1) / 2;
492  break;
493  case 8:
494  flags = HDFF_DRAW_HALF_BOTTOM;
495  cx = (x1 + x2) / 2;
496  cy = y1;
497  rx = (x2 - x1) / 2;
498  ry = y2 - y1;
499  break;
500  default:
501  flags = HDFF_DRAW_FULL;
502  cx = (x1 + x2) / 2;
503  cy = (y1 + y2) / 2;
504  rx = (x2 - x1) / 2;
505  ry = (y2 - y1) / 2;
506  break;
507  }
508  mHdffCmdIf->CmdOsdDrawEllipse(mDisplay, mLeft + cx, mTop + cy, rx, ry, Color, flags);
509  mChanged = true;
510 }
511 
512 void cHdffOsd::DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type)
513 {
514  //printf("DrawSlope\n");
515  mChanged = true;
516 }
517 
518 void cHdffOsd::Flush(void)
519 {
520  if (!Active())
521  return;
522 
523  //printf("Flush\n");
524  cBitmap * Bitmap;
525 
526  for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++)
527  {
528  int x1;
529  int y1;
530  int x2;
531  int y2;
532 
533  if (Bitmap->Dirty(x1, y1, x2, y2))
534  {
535  //printf("dirty %d %d, %d %d\n", x1, y1, x2, y2);
536  DrawBitmap(0, 0, *Bitmap);
537  Bitmap->Clean();
538  }
539  }
540 
541  if (!mChanged)
542  return;
543 
545 
546  mChanged = false;
547 }
548 
549 
550 class cHdffOsdRaw : public cOsd
551 {
552 private:
556  bool refresh;
557  uint32_t mDisplay;
558  uint32_t mBitmapPalette;
559  uint32_t mBitmapColors[256];
561 
562 protected:
563  virtual void SetActive(bool On);
564 public:
565  cHdffOsdRaw(int Left, int Top, HDFF::cHdffCmdIf * pHdffCmdIf, uint Level);
566  virtual ~cHdffOsdRaw();
567  virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas);
568  virtual eOsdError SetAreas(const tArea *Areas, int NumAreas);
569  virtual void Flush(void);
570 };
571 
572 cHdffOsdRaw::cHdffOsdRaw(int Left, int Top, HDFF::cHdffCmdIf * pHdffCmdIf, uint Level)
573 : cOsd(Left, Top, Level)
574 {
575  double pixelAspect;
576 
577  //printf("cHdffOsdRaw %d, %d, %d\n", Left, Top, Level);
578  mHdffCmdIf = pHdffCmdIf;
579  refresh = true;
582 
584 }
585 
587 {
588  //printf("~cHdffOsdRaw %d %d\n", Left(), Top());
590  {
593  }
600 }
601 
603 {
604  if (On != Active())
605  {
606  cOsd::SetActive(On);
607  if (On)
608  {
610  {
614  }
615  refresh = true;
616  if (GetBitmap(0)) // only flush here if there are already bitmaps
617  Flush();
618  }
619  else
620  {
622  {
625  }
632  }
633  }
634 }
635 
636 eOsdError cHdffOsdRaw::CanHandleAreas(const tArea *Areas, int NumAreas)
637 {
638  eOsdError Result = cOsd::CanHandleAreas(Areas, NumAreas);
639  if (Result == oeOk)
640  {
641  for (int i = 0; i < NumAreas; i++)
642  {
643  if (Areas[i].bpp != 1 && Areas[i].bpp != 2 && Areas[i].bpp != 4 && Areas[i].bpp != 8
644  && (Areas[i].bpp != 32 || !gHdffSetup.TrueColorOsd))
645  return oeBppNotSupported;
646  }
647  }
648  return Result;
649 }
650 
651 eOsdError cHdffOsdRaw::SetAreas(const tArea *Areas, int NumAreas)
652 {
653  for (int i = 0; i < NumAreas; i++)
654  {
655  //printf("SetAreas %d: %d %d %d %d %d\n", i, Areas[i].x1, Areas[i].y1, Areas[i].x2, Areas[i].y2, Areas[i].bpp);
656  }
658  {
661  refresh = true;
662  }
663  return cOsd::SetAreas(Areas, NumAreas);
664 }
665 
667 {
668  if (!Active() || (mDisplay == HDFF_INVALID_HANDLE))
669  return;
670  //struct timeval start;
671  //struct timeval end;
672  //struct timezone timeZone;
673  //gettimeofday(&start, &timeZone);
674 
675  bool render = false;
676  if (IsTrueColor())
677  {
678  LOCK_PIXMAPS;
679  while (cPixmapMemory *pm = RenderPixmaps())
680  {
681  int w = pm->ViewPort().Width();
682  int h = pm->ViewPort().Height();
683  int d = w * sizeof(tColor);
684  int Chunk = MAX_BITMAP_SIZE / w / sizeof(tColor);
685  if (Chunk > h)
686  Chunk = h;
687  for (int y = 0; y < h; y += Chunk)
688  {
689  int hc = Chunk;
690  if (y + hc > h)
691  hc = h - y;
693  Left() + pm->ViewPort().X(), Top() + pm->ViewPort().Y() + y,
694  pm->Data() + y * d, w, hc, hc * d,
696  }
697  delete pm;
698  render = true;
699  }
700  }
701  else
702  {
703  uint8_t * buffer = new uint8_t[MAX_BITMAP_SIZE];
704  if (!buffer)
705  return;
706  cBitmap * bitmap;
707  for (int i = 0; (bitmap = GetBitmap(i)) != NULL; i++)
708  {
709  int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
710  if (refresh || bitmap->Dirty(x1, y1, x2, y2))
711  {
712  if (refresh)
713  {
714  x2 = bitmap->Width() - 1;
715  y2 = bitmap->Height() - 1;
716  }
717  // commit colors:
718  int numColors;
719  const tColor * colors = bitmap->Colors(numColors);
720  if (colors)
721  {
722  for (int c = 0; c < numColors; c++)
723  mBitmapColors[c] = colors[c];
725  {
728  }
729  else
730  {
732  HDFF_COLOR_FORMAT_ARGB, 0, numColors, mBitmapColors);
733  }
734  }
735  // commit modified data:
736  int width = x2 - x1 + 1;
737  int height = y2 - y1 + 1;
738  int chunk = MAX_BITMAP_SIZE / width;
739  if (chunk > height)
740  chunk = height;
741  for (int y = 0; y < height; y += chunk)
742  {
743  int hc = chunk;
744  if (y + hc > height)
745  hc = height - y;
746  for (int r = 0; r < hc; r++)
747  memcpy(buffer + r * width, bitmap->Data(x1, y1 + y + r), width);
749  Left() + bitmap->X0() + x1, Top() + bitmap->Y0() + y1 + y,
750  buffer, width, hc, hc * width,
752  }
753  render = true;
754  }
755  bitmap->Clean();
756  }
757  delete[] buffer;
758  }
759  if (render)
760  {
762  //gettimeofday(&end, &timeZone);
763  //int timeNeeded = end.tv_usec - start.tv_usec;
764  //timeNeeded += (end.tv_sec - start.tv_sec) * 1000000;
765  //printf("time = %d\n", timeNeeded);
766  }
767  refresh = false;
768 }
769 
770 
771 
772 
774 {
775  mHdffCmdIf = HdffCmdIf;
776 }
777 
778 cOsd *cHdffOsdProvider::CreateOsd(int Left, int Top, uint Level)
779 {
780  //printf("CreateOsd %d %d %d\n", Left, Top, Level);
782  return new cHdffOsd(Left, Top, mHdffCmdIf, Level);
783  else
784  return new cHdffOsdRaw(Left, Top, mHdffCmdIf, Level);
785 }
786 
788 {
790 }