MythTV  master
subtitlescreen.cpp
Go to the documentation of this file.
1 #include <QFontMetrics>
2 
9 
11 
12 #define LOC QString("Subtitles: ")
13 #define LOC_WARN QString("Subtitles Warning: ")
14 
15 #ifdef DEBUG_SUBTITLES
16 static QString toString(MythVideoFrame const * const frame)
17 {
18  std::chrono::milliseconds time = frame->m_timecode;
19  return QString("%1(%2)")
20  .arg(MythDate::formatTime(time,"HH:mm:ss.zzz"))
21  .arg(time.count());
22 }
23 #endif
24 
25 // Class SubWrapper is used to attach caching structures to MythUIType
26 // objects in the SubtitleScreen's m_ChildrenList. If these objects
27 // inherit from SubWrapper, they can carry relevant information and an
28 // external caching object is not required.
29 //
30 // The following caching information is represented here:
31 // 1. Original m_Area, used for OptimiseDisplayedArea().
32 // 2. Which cc708 window it belongs to, used for Clear708Cache().
33 // 3. Subtitle expire time, primarily for AV subtitles.
35 {
36 protected:
37  SubWrapper(const MythRect &rect,
38  std::chrono::milliseconds expireTime,
39  int whichImageCache = -1) :
40  m_swOrigArea(rect),
41  m_swWhichImageCache(whichImageCache),
42  m_swExpireTime(expireTime)
43  {
44  }
45 public:
46  std::chrono::milliseconds GetExpireTime(void) const { return m_swExpireTime; }
47  MythRect GetOrigArea(void) const { return m_swOrigArea; }
48  int GetWhichImageCache(void) const { return m_swWhichImageCache; }
49 protected:
50  // Returns true if the object was deleted.
52  const int m_swWhichImageCache; // cc708 only; -1 = none
53  const std::chrono::milliseconds m_swExpireTime; // avsubs only; -1 = none
54 };
55 
57 {
58 public:
59  SubSimpleText(const QString &text, const MythFontProperties &font,
60  QRect rect, Qt::Alignment align,
61  MythUIType *parent, const QString &name,
62  int whichImageCache, std::chrono::milliseconds expireTime) :
63  MythUISimpleText(text, font, rect, align, parent, name),
64  SubWrapper(MythRect(rect), expireTime, whichImageCache) {}
65 };
66 
67 class SubShape : public MythUIShape, public SubWrapper
68 {
69 public:
70  SubShape(MythUIType *parent, const QString &name, const MythRect &area,
71  int whichImageCache, std::chrono::milliseconds expireTime) :
72  MythUIShape(parent, name),
73  SubWrapper(area, expireTime, whichImageCache) {}
74 };
75 
76 class SubImage : public MythUIImage, public SubWrapper
77 {
78 public:
79  SubImage(MythUIType *parent, const QString &name, const MythRect &area,
80  std::chrono::milliseconds expireTime) :
81  MythUIImage(parent, name),
82  SubWrapper(area, expireTime) {}
83  MythImage *GetImage(void) { return m_images[0]; }
84 };
85 
87 
88 // Class SubtitleFormat manages fonts and backgrounds for subtitles.
89 //
90 // Formatting is specified by the theme in the new file
91 // osd_subtitle.xml, in the osd_subtitle window. Subtitle types are
92 // text, teletext, 608, 708_0, 708_1, ..., 708_7. Each subtitle type
93 // has a fontdef component for the text and a shape component for the
94 // background. By default, the attributes of a subtitle type come
95 // from either the provider (e.g. font color, italics) or the system
96 // default (e.g. font family). These attributes can be overridden by
97 // the xml file.
98 //
99 // The fontdef name and the background shape name are both simply the
100 // name of the subtitle type. The fontdef and shape should ultimately
101 // inherit from the special value "provider", otherwise all provider
102 // values will be ignored.
103 //
104 // The following example forces .srt subtitles to be rendered in
105 // yellow text, FreeSans font, black shadow, with a translucent black
106 // background. The fontdef and shape names are "text" since the
107 // subtitles come from a .srt file. Note that in this example, color
108 // formatting controls in the .srt file will be ignored due to the
109 // explicit setting of yellow text.
110 //
111 // <?xml version="1.0" encoding="utf-8"?>
112 // <!DOCTYPE mythuitheme SYSTEM "http://www.mythtv.org/schema/mythuitheme.dtd">
113 // <mythuitheme>
114 // <window name="osd_subtitle">
115 // <fontdef name="text" face="FreeSans" from="provider">
116 // <color>#FFFF00</color>
117 // <shadowoffset>2,2</shadowoffset>
118 // <shadowcolor>#000000</shadowcolor>
119 // </fontdef>
120 // <shape name="text" from="provider">
121 // <fill color="#000000" alpha="100" />
122 // </shape>
123 // </window>
124 // </mythuitheme>
125 //
126 // All elements/attributes of fontdef and shape can be used. Note
127 // however that area and position are explicitly ignored, as these are
128 // dictated by the subtitle layout.
129 //
130 // This is implemented with almost no MythUI changes. Two copies of a
131 // "provider" object are created, with default/representative provider
132 // attributes. One copy is then "complemented" to have a different
133 // value for each attribute that a provider might change. The
134 // osd_subtitle.xml file is loaded twice, once with respect to each
135 // provider object, and the desired fontdef or shape is looked up.
136 // The two fontdefs or shapes are compared attribute by attribute, and
137 // each attribute that is different is an attribute that the provider
138 // may modify, whereas each identical attribute represents one that is
139 // fixed by the theme.
140 
142 {
143 public:
144  SubtitleFormat(void) = default;
145  ~SubtitleFormat(void);
146  MythFontProperties *GetFont(const QString &family,
147  const CC708CharacterAttribute &attr,
148  int pixelSize, int zoom, int stretch);
149  SubShape *GetBackground(MythUIType *parent, const QString &name,
150  const QString &family,
151  const CC708CharacterAttribute &attr,
152  const MythRect &area,
153  int whichImageCache,
154  std::chrono::milliseconds start,
155  std::chrono::milliseconds duration);
156  int GetBackgroundAlpha(const QString &family);
157  static QString MakePrefix(const QString &family,
158  const CC708CharacterAttribute &attr);
159 private:
160  void Load(const QString &family,
161  const CC708CharacterAttribute &attr);
162  bool IsUnlocked(const QString &prefix, const QString &property) const
163  {
164  return m_changeMap[prefix].contains(property);
165  }
166  static void CreateProviderDefault(const QString &family,
167  const CC708CharacterAttribute &attr,
168  MythUIType *parent,
169  bool isComplement,
170  MythFontProperties **font,
171  MythUIShape **bg);
172  static void Complement(MythFontProperties *font, MythUIShape *bg);
173  static QSet<QString> Diff(const QString &family,
174  const CC708CharacterAttribute &attr,
175  MythFontProperties *font1,
176  MythFontProperties *font2,
177  MythUIShape *bg1,
178  MythUIShape *bg2);
179 
180  QHash<QString, MythFontProperties *> m_fontMap;
181  QHash<QString, MythUIShape *> m_shapeMap;
182  QHash<QString, QSet<QString> > m_changeMap;
183  // The following m_*Map fields are the original values from the
184  // m_fontMap, which are preserved because the text font zoom
185  // factor affects the actual values stored in the font.
186  QHash<QString, int> m_pixelSizeMap;
187  QHash<QString, int> m_outlineSizeMap;
188  QHash<QString, QPoint> m_shadowOffsetMap;
189  QVector<MythUIType *> m_cleanup;
190 };
191 
192 static const QString kSubProvider("provider");
193 static const QString kSubFileName ("osd_subtitle.xml");
194 static const QString kSubWindowName("osd_subtitle");
195 static const QString kSubFamily608 ("608");
196 static const QString kSubFamily708 ("708");
197 static const QString kSubFamilyText ("text");
198 static const QString kSubFamilyAV ("AV");
199 static const QString kSubFamilyTeletext("teletext");
200 
201 static const QString kSubAttrItalics ("italics");
202 static const QString kSubAttrBold ("bold");
203 static const QString kSubAttrUnderline("underline");
204 static const QString kSubAttrPixelsize("pixelsize");
205 static const QString kSubAttrColor ("color");
206 static const QString kSubAttrBGfill ("bgfill");
207 static const QString kSubAttrShadow ("shadow"); // unused
208 static const QString kSubAttrShadowoffset("shadowoffset");
209 static const QString kSubAttrShadowcolor ("shadowcolor");
210 static const QString kSubAttrShadowalpha ("shadowalpha");
211 static const QString kSubAttrOutline ("outline"); // unused
212 static const QString kSubAttrOutlinecolor("outlinecolor");
213 static const QString kSubAttrOutlinesize ("outlinesize");
214 static const QString kSubAttrOutlinealpha("outlinealpha");
215 
216 static QString srtColorString(const QColor& color)
217 {
218  return QString("#%1%2%3")
219  .arg(color.red(), 2, 16, QLatin1Char('0'))
220  .arg(color.green(), 2, 16, QLatin1Char('0'))
221  .arg(color.blue(), 2, 16, QLatin1Char('0'));
222 }
223 
225 {
226  QString result;
227  result = QString("face=%1 pixelsize=%2 color=%3 "
228  "italics=%4 weight=%5 underline=%6")
229  .arg(f->GetFace()->family())
230  .arg(f->GetFace()->pixelSize())
231  .arg(srtColorString(f->color()))
232  .arg(static_cast<int>(f->GetFace()->italic()))
233  .arg(f->GetFace()->weight())
234  .arg(static_cast<int>(f->GetFace()->underline()));
235  QPoint offset;
236  QColor color;
237  int alpha = 0;
238  int size = 0;
239  f->GetShadow(offset, color, alpha);
240  result += QString(" shadow=%1 shadowoffset=%2 "
241  "shadowcolor=%3 shadowalpha=%4")
242  .arg(QString::number(static_cast<int>(f->hasShadow())),
243  QString("(%1,%2)").arg(offset.x()).arg(offset.y()),
244  srtColorString(color),
245  QString::number(alpha));
246  f->GetOutline(color, size, alpha);
247  result += QString(" outline=%1 outlinecolor=%2 "
248  "outlinesize=%3 outlinealpha=%4")
249  .arg(static_cast<int>(f->hasOutline()))
250  .arg(srtColorString(color))
251  .arg(size)
252  .arg(alpha);
253  return result;
254 }
255 
257 SubtitleFormat::GetFont(const QString &family,
258  const CC708CharacterAttribute &attr,
259  int pixelSize, int zoom, int stretch)
260 {
261  int origPixelSize = pixelSize;
262  float scale = zoom / 100.0;
263  if ((attr.m_penSize & 0x3) == k708AttrSizeSmall)
264  scale = scale * 32 / 42;
265  else if ((attr.m_penSize & 0x3) == k708AttrSizeLarge)
266  scale = scale * 42 / 32;
267 
268  QString prefix = MakePrefix(family, attr);
269  if (!m_fontMap.contains(prefix))
270  Load(family, attr);
272 
273  // Apply the scaling factor to pixelSize even if the theme
274  // explicitly sets pixelSize.
276  pixelSize = m_pixelSizeMap[prefix];
277  pixelSize *= scale;
278  result->GetFace()->setPixelSize(pixelSize);
279 
280  result->GetFace()->setStretch(stretch);
282  result->GetFace()->setItalic(attr.m_italics);
284  result->GetFace()->setUnderline(attr.m_underline);
286  result->GetFace()->setBold(attr.m_boldface);
288  result->SetColor(attr.GetFGColor());
289 
290  MythPoint offset;
291  QColor color;
292  int alpha = 0;
293  bool shadow = result->hasShadow();
294  result->GetShadow(offset, color, alpha);
296  color = attr.GetEdgeColor();
298  alpha = attr.GetFGAlpha();
300  {
301  int off = lroundf(scale * pixelSize / 20);
302  offset = QPoint(off, off);
304  {
305  shadow = true;
306  offset.setX(-off);
307  }
308  else if (attr.m_edgeType == k708AttrEdgeRightDropShadow)
309  shadow = true;
310  else
311  shadow = false;
312  }
313  else
314  {
315  offset = m_shadowOffsetMap[prefix];
316  offset.NormPoint();
317  offset.setX(lroundf(offset.x() * scale));
318  offset.setY(lroundf(offset.y() * scale));
319  }
320  result->SetShadow(shadow, offset, color, alpha);
321 
322  int off = 0;
323  bool outline = result->hasOutline();
324  result->GetOutline(color, off, alpha);
326  color = attr.GetEdgeColor();
328  alpha = attr.GetFGAlpha();
330  {
331  if (attr.m_edgeType == k708AttrEdgeUniform ||
332  attr.m_edgeType == k708AttrEdgeRaised ||
334  {
335  outline = true;
336  off = lroundf(scale * pixelSize / 20);
337  }
338  else
339  outline = false;
340  }
341  else
342  {
343  off = m_outlineSizeMap[prefix];
344  MythPoint point(off, off);
345  point.NormPoint();
346  off = lroundf(point.x() * scale);
347  }
348  result->SetOutline(outline, color, off, alpha);
349 
350  LOG(VB_VBI, LOG_DEBUG,
351  QString("GetFont(family=%1, prefix=%2, orig pixelSize=%3, "
352  "new pixelSize=%4 zoom=%5) = %6")
353  .arg(family, prefix).arg(origPixelSize).arg(pixelSize)
354  .arg(zoom).arg(fontToString(result)));
355  return result;
356 }
357 
359 {
360  // NOLINTNEXTLINE(modernize-loop-convert)
361  for (int i = 0; i < m_cleanup.size(); ++i)
362  {
363  m_cleanup[i]->DeleteAllChildren();
364  m_cleanup[i]->deleteLater();
365  m_cleanup[i] = nullptr; // just to be safe
366  }
367 }
368 
369 QString SubtitleFormat::MakePrefix(const QString &family,
370  const CC708CharacterAttribute &attr)
371 {
372  if (family == kSubFamily708)
373  return family + "_" + QString::number(attr.m_fontTag & 0x7);
374  return family;
375 }
376 
377 void SubtitleFormat::CreateProviderDefault(const QString &family,
378  const CC708CharacterAttribute &attr,
379  MythUIType *parent,
380  bool isComplement,
381  MythFontProperties **returnFont,
382  MythUIShape **returnBg)
383 {
384  auto *font = new MythFontProperties();
385  auto *bg = new MythUIShape(parent, kSubProvider);
386  if (family == kSubFamily608)
387  {
388  font->GetFace()->setFamily("FreeMono");
389  QBrush brush(Qt::black);
390  bg->SetFillBrush(brush);
391  bg->SetLinePen(QPen(brush, 0));
392  }
393  else if (family == kSubFamily708)
394  {
395  static const std::array<const std::string,8> s_cc708Fonts {
396  "FreeMono", // default
397  "FreeMono", // mono serif
398  "Droid Serif", // prop serif
399  "Droid Sans Mono", // mono sans
400  "Droid Sans", // prop sans
401  "Purisa", // casual
402  "TeX Gyre Chorus", // cursive
403  "Droid Serif" // small caps, QFont::SmallCaps will be applied
404  };
405  font->GetFace()->setFamily(QString::fromStdString(s_cc708Fonts[attr.m_fontTag & 0x7]));
406  }
407  else if (family == kSubFamilyText)
408  {
409  font->GetFace()->setFamily("Droid Sans");
410  QBrush brush(Qt::black);
411  bg->SetFillBrush(brush);
412  bg->SetLinePen(QPen(brush, 0));
413  }
414  else if (family == kSubFamilyTeletext)
415  {
416  font->GetFace()->setFamily("FreeMono");
417  // Set up a background with default alpha=100% so that the theme can
418  // override the background alpha.
419  QBrush brush(Qt::black);
420  bg->SetFillBrush(brush);
421  bg->SetLinePen(QPen(brush, 0));
422  }
423  font->GetFace()->setPixelSize(10);
424 
425  if (isComplement)
426  Complement(font, bg);
427  parent->AddFont(kSubProvider, font);
428 
429  *returnFont = font;
430  *returnBg = bg;
431 }
432 
433 static QColor differentColor(const QColor &color)
434 {
435  return color == Qt::white ? Qt::black : Qt::white;
436 }
437 
438 // Change everything (with respect to the == operator) that the
439 // provider might define or override.
441 {
442  QPoint offset;
443  QColor color;
444  int alpha = 0;
445  int size = 0;
446  QFont *face = font->GetFace();
447  face->setItalic(!face->italic());
448  face->setPixelSize(face->pixelSize() + 1);
449  face->setUnderline(!face->underline());
450 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
451  face->setWeight((face->weight() + 1) % 32);
452 #else
453  // qt6: Weight has become an enum. Leave it alone.
454 #endif
455  font->SetColor(differentColor(font->color()));
456 
457  font->GetShadow(offset, color, alpha);
458  offset.setX(offset.x() + 1);
459  font->SetShadow(!font->hasShadow(), offset, differentColor(color),
460  255 - alpha);
461 
462  font->GetOutline(color, size, alpha);
463  font->SetOutline(!font->hasOutline(), differentColor(color),
464  size + 1, 255 - alpha);
465 
466  bg->SetFillBrush(bg->m_fillBrush == Qt::NoBrush ?
467  Qt::SolidPattern : Qt::NoBrush);
468 }
469 
470 void SubtitleFormat::Load(const QString &family,
471  const CC708CharacterAttribute &attr)
472 {
473  // Widgets for the actual values
474  auto *baseParent = new MythUIType(nullptr, "base");
475  m_cleanup += baseParent;
476  MythFontProperties *providerBaseFont = nullptr;
477  MythUIShape *providerBaseShape = nullptr;
478  CreateProviderDefault(family, attr, baseParent, false,
479  &providerBaseFont, &providerBaseShape);
480 
481  // Widgets for the "negative" values
482  auto *negParent = new MythUIType(nullptr, "base");
483  m_cleanup += negParent;
484  MythFontProperties *negFont = nullptr;
485  MythUIShape *negBG = nullptr;
486  CreateProviderDefault(family, attr, negParent, true, &negFont, &negBG);
487 
488  bool posResult =
490  baseParent);
491  bool negResult =
493  negParent);
494  if (!posResult || !negResult)
495  LOG(VB_VBI, LOG_INFO,
496  QString("Couldn't load theme file %1").arg(kSubFileName));
497  QString prefix = MakePrefix(family, attr);
498  MythFontProperties *resultFont = baseParent->GetFont(prefix);
499  if (!resultFont)
500  resultFont = providerBaseFont;
501  auto *resultBG = dynamic_cast<MythUIShape *>(baseParent->GetChild(prefix));
502 
503  // The providerBaseShape object is not leaked here. It is added
504  // to a list of children in its base class constructor.
505  if (!resultBG)
506  resultBG = providerBaseShape;
507  // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
508  MythFontProperties *testFont = negParent->GetFont(prefix);
509  if (!testFont)
510  testFont = negFont;
511  auto *testBG = dynamic_cast<MythUIShape *>(negParent->GetChild(prefix));
512  if (!testBG)
513  testBG = negBG;
514  if (family == kSubFamily708 &&
515  (attr.m_fontTag & 0x7) == k708AttrFontSmallCaps)
516  resultFont->GetFace()->setCapitalization(QFont::SmallCaps);
517  m_fontMap[prefix] = resultFont;
518  m_shapeMap[prefix] = resultBG;
519  LOG(VB_VBI, LOG_DEBUG,
520  QString("providerBaseFont = %1").arg(fontToString(providerBaseFont)));
521  LOG(VB_VBI, LOG_DEBUG,
522  QString("negFont = %1").arg(fontToString(negFont)));
523  LOG(VB_VBI, LOG_DEBUG,
524  QString("resultFont = %1").arg(fontToString(resultFont)));
525  LOG(VB_VBI, LOG_DEBUG,
526  QString("testFont = %1").arg(fontToString(testFont)));
527  m_changeMap[prefix] = Diff(family, attr, resultFont, testFont,
528  resultBG, testBG);
529  QPoint offset;
530  QColor color;
531  int alpha = 0;
532  int size = 0;
533  resultFont->GetShadow(offset, color, alpha);
534  resultFont->GetOutline(color, size, alpha);
535  m_outlineSizeMap[prefix] = size;
536  m_shadowOffsetMap[prefix] = offset;
537  m_pixelSizeMap[prefix] = resultFont->GetFace()->pixelSize();
538 
539  delete negFont;
540 }
541 
542 QSet<QString> SubtitleFormat::Diff(const QString &family,
543  const CC708CharacterAttribute &attr,
544  MythFontProperties *font1,
545  MythFontProperties *font2,
546  MythUIShape *bg1,
547  MythUIShape *bg2)
548 {
549  bool is708 = (family == kSubFamily708);
550  QSet<QString> result;
551  QFont *face1 = font1->GetFace();
552  QFont *face2 = font2->GetFace();
553  if (face1->italic() != face2->italic())
554  result << kSubAttrItalics;
555  if (face1->weight() != face2->weight())
556  result << kSubAttrBold;
557  if (face1->underline() != face2->underline())
558  result << kSubAttrUnderline;
559  if (face1->pixelSize() != face2->pixelSize())
560  result << kSubAttrPixelsize;
561  if (font1->color() != font2->color())
562  result << kSubAttrColor;
563  if (is708 && font1->hasShadow() != font2->hasShadow())
564  {
565  result << kSubAttrShadow;
566  QPoint offset1;
567  QPoint offset2;
568  QColor color1;
569  QColor color2;
570  int alpha1 = 0;
571  int alpha2 = 0;
572  font1->GetShadow(offset1, color1, alpha1);
573  font2->GetShadow(offset2, color2, alpha2);
574  if (offset1 != offset2)
575  result << kSubAttrShadowoffset;
576  if (color1 != color2)
577  result << kSubAttrShadowcolor;
578  if (alpha1 != alpha2)
579  result << kSubAttrShadowalpha;
580  }
581  if (is708 && font1->hasOutline() != font2->hasOutline())
582  {
583  result << kSubAttrOutline;
584  QColor color1;
585  QColor color2;
586  int size1 = 0;
587  int size2 = 0;
588  int alpha1 = 0;
589  int alpha2 = 0;
590  font1->GetOutline(color1, size1, alpha1);
591  font2->GetOutline(color2, size2, alpha2);
592  if (color1 != color2)
593  result << kSubAttrOutlinecolor;
594  if (size1 != size2)
595  result << kSubAttrOutlinesize;
596  if (alpha1 != alpha2)
597  result << kSubAttrOutlinealpha;
598  }
599  if (bg1->m_fillBrush != bg2->m_fillBrush)
600  result << kSubAttrBGfill;
601 
602  QString values = "";
603  for (auto i = result.constBegin(); i != result.constEnd(); ++i)
604  values += " " + (*i);
605  LOG(VB_VBI, LOG_INFO,
606  QString("Subtitle family %1 allows provider to change:%2")
607  .arg(MakePrefix(family, attr), values));
608 
609  return result;
610 }
611 
612 SubShape *
613 SubtitleFormat::GetBackground(MythUIType *parent, const QString &name,
614  const QString &family,
615  const CC708CharacterAttribute &attr,
616  const MythRect &area,
617  int whichImageCache,
618  std::chrono::milliseconds start,
619  std::chrono::milliseconds duration)
620 {
621  QString prefix = MakePrefix(family, attr);
622  if (!m_shapeMap.contains(prefix))
623  Load(family, attr);
624  if (m_shapeMap[prefix]->GetAlpha() == 0)
625  return nullptr;
626  auto *result = new SubShape(parent, name, area, whichImageCache,
627  start + duration);
628  result->CopyFrom(m_shapeMap[prefix]);
629  if (family == kSubFamily708)
630  {
632  {
633  QBrush brush(attr.GetBGColor());
634  result->SetFillBrush(brush);
635  result->SetLinePen(QPen(brush, 0));
636  }
637  }
638  else if (family == kSubFamilyTeletext)
639  {
640  // add code here when teletextscreen.cpp is refactored
641  }
642  LOG(VB_VBI, LOG_DEBUG,
643  QString("GetBackground(prefix=%1) = "
644  "{type=%2 alpha=%3 brushstyle=%4 brushcolor=%5}")
645  .arg(prefix, result->m_type, QString::number(result->GetAlpha()),
646  QString::number(result->m_fillBrush.style()),
647  srtColorString(result->m_fillBrush.color())));
648  return result;
649 }
650 
651 int SubtitleFormat::GetBackgroundAlpha(const QString &family)
652 {
653  // This is a "temporary" hack for allowing teletextscreen.cpp to get the
654  // background alpha value from osd_subtitle.xml.
655  CC708CharacterAttribute attr(false, false, false, Qt::white);
656  SubShape *bgShape = GetBackground(nullptr, "dummyName", family, attr,
657  MythRect(), -1, 0ms, -1ms);
658  return bgShape->m_fillBrush.color().alpha();
659 }
660 
662 
663 QSize FormattedTextChunk::CalcSize(float layoutSpacing) const
664 {
665  return m_parent->CalcTextSize(m_text, m_format, layoutSpacing);
666 }
667 
668 void FormattedTextChunk::CalcPadding(bool isFirst, bool isLast,
669  int &left, int &right) const
670 {
671  m_parent->CalcPadding(m_format, isFirst, isLast, left, right);
672 }
673 
675 {
676  LOG(VB_VBI, LOG_INFO,
677  QString("Attempting to split chunk '%1'").arg(m_text));
678  int lastSpace = m_text.lastIndexOf(' ', -2); // -2 to ignore trailing space
679  if (lastSpace < 0)
680  {
681  LOG(VB_VBI, LOG_INFO,
682  QString("Failed to split chunk '%1'").arg(m_text));
683  return false;
684  }
685  newChunk.m_parent = m_parent;
686  newChunk.m_format = m_format;
687  newChunk.m_text = m_text.mid(lastSpace + 1).trimmed() + ' ';
688  m_text = m_text.left(lastSpace).trimmed();
689  LOG(VB_VBI, LOG_INFO,
690  QString("Split chunk into '%1' + '%2'").arg(m_text, newChunk.m_text));
691  return true;
692 }
693 
695 {
696  QString str("");
697  str += QString("fg=%1.%2 ")
699  .arg(m_format.GetFGAlpha());
700  str += QString("bg=%1.%2 ")
702  .arg(m_format.GetBGAlpha());
703  str += QString("edge=%1.%2 ")
705  .arg(m_format.m_edgeType);
706  str += QString("off=%1 pensize=%2 ")
707  .arg(m_format.m_offset)
708  .arg(m_format.m_penSize);
709  str += QString("it=%1 ul=%2 bf=%3 ")
710  .arg(static_cast<int>(m_format.m_italics))
711  .arg(static_cast<int>(m_format.m_underline))
712  .arg(static_cast<int>(m_format.m_boldface));
713  str += QString("font=%1 ").arg(m_format.m_fontTag);
714  str += QString(" text='%1'").arg(m_text);
715  return str;
716 }
717 
718 bool FormattedTextChunk::PreRender(bool isFirst, bool isLast,
719  int &x, int y, int height)
720 {
722  if (!m_textFont)
723  return false;
724  QFontMetrics font(*(m_textFont->GetFace()));
725  // If the chunk starts with whitespace, the leading whitespace
726  // ultimately gets lost due to the text.trimmed() operation in the
727  // MythUISimpleText constructor. To compensate, we manually
728  // indent the chunk accordingly.
729  int count = 0;
730  while (count < m_text.length() && m_text.at(count) == ' ')
731  {
732  ++count;
733  }
734  int x_adjust = count * font.horizontalAdvance(" ");
735  int leftPadding = 0;
736  int rightPadding = 0;
737  CalcPadding(isFirst, isLast, leftPadding, rightPadding);
738  // Account for extra padding before the first chunk.
739  if (isFirst)
740  x += leftPadding;
741  QSize chunk_sz = CalcSize();
742  QRect bgrect(x - leftPadding, y,
743  chunk_sz.width() + leftPadding + rightPadding,
744  height);
745  // Don't draw a background behind leading spaces.
746  if (isFirst)
747  bgrect.setLeft(bgrect.left() + x_adjust);
748  m_bgShapeName = QString("subbg%1x%2@%3,%4")
749  .arg(chunk_sz.width()).arg(height).arg(x).arg(y);
750  m_bgShapeRect = bgrect;
751  // Shift to the right to account for leading spaces that
752  // are removed by the MythUISimpleText constructor. Also
753  // add in padding at the end to avoid clipping.
754  m_textName = QString("subtxt%1x%2@%3,%4")
755  .arg(chunk_sz.width()).arg(height).arg(x).arg(y);
756  m_textRect = QRect(x + x_adjust, y,
757  chunk_sz.width() - x_adjust + rightPadding, height);
758 
759  x += chunk_sz.width();
760  return true;
761 }
762 
763 QSize FormattedTextLine::CalcSize(float layoutSpacing) const
764 {
765  int height = 0;
766  int width = 0;
767  int leftPadding = 0;
768  int rightPadding = 0;
769  QList<FormattedTextChunk>::const_iterator it;
770  bool isFirst = true;
771  for (it = chunks.constBegin(); it != chunks.constEnd(); ++it)
772  {
773  bool isLast = (it + 1 == chunks.constEnd());
774  QSize tmp = (*it).CalcSize(layoutSpacing);
775  height = std::max(height, tmp.height());
776  width += tmp.width();
777  (*it).CalcPadding(isFirst, isLast, leftPadding, rightPadding);
778  if (it == chunks.constBegin())
779  width += leftPadding;
780  isFirst = false;
781  }
782  return {width + rightPadding, height};
783 }
784 
785 // Normal font height is designed to be 1/20 of safe area height, with
786 // extra blank space between lines to make 17 lines within the safe
787 // area.
788 static const float LINE_SPACING = (20.0 / 17.0);
789 static const float PAD_WIDTH = 0.5;
790 static const float PAD_HEIGHT = 0.04;
791 
792 // Resolves any TBD x_indent and y_indent values in FormattedTextLine
793 // objects. Calculates m_bounds. Prunes most leading and all
794 // trailing whitespace from each line so that displaying with a black
795 // background doesn't look clumsy.
797 {
798  // Calculate dimensions of bounding rectangle
799  int anchor_width = 0;
800  int anchor_height = 0;
801  for (const auto & line : qAsConst(m_lines))
802  {
803  QSize sz = line.CalcSize(LINE_SPACING);
804  anchor_width = std::max(anchor_width, sz.width());
805  anchor_height += sz.height();
806  }
807 
808  // Adjust the anchor point according to actual width and height
809  int anchor_x = m_xAnchor;
810  int anchor_y = m_yAnchor;
811  if (m_xAnchorPoint == 1)
812  anchor_x -= anchor_width / 2;
813  else if (m_xAnchorPoint == 2)
814  anchor_x -= anchor_width;
815  if (m_yAnchorPoint == 1)
816  anchor_y -= anchor_height / 2;
817  else if (m_yAnchorPoint == 2)
818  anchor_y -= anchor_height;
819 
820  // Shift the anchor point back into the safe area if necessary/possible.
821  anchor_y = std::max(0, std::min(anchor_y, m_safeArea.height() - anchor_height));
822  anchor_x = std::max(0, std::min(anchor_x, m_safeArea.width() - anchor_width));
823 
824  m_bounds = QRect(anchor_x, anchor_y, anchor_width, anchor_height);
825 
826  // Fill in missing coordinates
827  int y = anchor_y;
828  // NOLINTNEXTLINE(modernize-loop-convert)
829  for (int i = 0; i < m_lines.size(); i++)
830  {
831  if (m_lines[i].m_xIndent < 0)
832  m_lines[i].m_xIndent = anchor_x;
833  if (m_lines[i].m_yIndent < 0)
834  m_lines[i].m_yIndent = y;
835  y += m_lines[i].CalcSize(LINE_SPACING).height();
836  // Prune leading all-whitespace chunks.
837  while (!m_lines[i].chunks.isEmpty() &&
838  m_lines[i].chunks.first().m_text.trimmed().isEmpty())
839  {
840  m_lines[i].m_xIndent +=
841  m_lines[i].chunks.first().CalcSize().width();
842  m_lines[i].chunks.removeFirst();
843  }
844  // Prune trailing all-whitespace chunks.
845  while (!m_lines[i].chunks.isEmpty() &&
846  m_lines[i].chunks.last().m_text.trimmed().isEmpty())
847  {
848  m_lines[i].chunks.removeLast();
849  }
850  // Trim trailing whitespace from last chunk. (Trimming
851  // leading whitespace from all chunks is handled in the Draw()
852  // routine.)
853  if (!m_lines[i].chunks.isEmpty())
854  {
855  QString *str = &m_lines[i].chunks.last().m_text;
856  int idx = str->length() - 1;
857  while (idx >= 0 && str->at(idx) == ' ')
858  --idx;
859  str->truncate(idx + 1);
860  }
861  }
862 }
863 
865 {
866  // NOLINTNEXTLINE(modernize-loop-convert)
867  for (int i = 0; i < m_lines.size(); i++)
868  {
869  int x = m_lines[i].m_xIndent;
870  int y = m_lines[i].m_yIndent;
871  int height = m_lines[i].CalcSize().height();
872  QList<FormattedTextChunk>::iterator chunk;
873  bool isFirst = true;
874  for (chunk = m_lines[i].chunks.begin();
875  chunk != m_lines[i].chunks.end();
876  ++chunk)
877  {
878  bool isLast = (chunk + 1 == m_lines[i].chunks.end());
879  (*chunk).PreRender(isFirst, isLast, x, y, height);
880  isFirst = false;
881  }
882  }
883 }
884 
885 // Returns true if anything new was drawn, false if not. The caller
886 // should call SubtitleScreen::OptimiseDisplayedArea() if true is
887 // returned.
889 {
890  QList<MythUIType *> textList;
891  QList<MythUIType *> shapeList;
892  for (auto & line : m_lines)
893  {
894  QList<FormattedTextChunk>::const_iterator chunk;
895  for (chunk = line.chunks.constBegin();
896  chunk != line.chunks.constEnd();
897  ++chunk)
898  {
899  MythFontProperties *mythfont =
900  m_subScreen->GetFont((*chunk).m_format);
901  if (!mythfont)
902  continue;
903  // Note: nullptr is passed as the parent argument to the
904  // MythUI constructors so that we can control the drawing
905  // order of the children. In particular, background
906  // shapes should be added/drawn first, and text drawn on
907  // top.
908  if ((*chunk).m_textRect.width() > 0) {
909  auto *text = new SubSimpleText((*chunk).m_text, *mythfont,
910  (*chunk).m_textRect,
911  Qt::AlignLeft|Qt::AlignTop,
912  /*m_subScreen*/nullptr,
913  (*chunk).m_textName, CacheNum(),
914  m_start + m_duration);
915  textList += text;
916  }
917  if ((*chunk).m_bgShapeRect.width() > 0) {
919  GetBackground(/*m_subScreen*/nullptr,
920  (*chunk).m_bgShapeName,
921  m_base, (*chunk).m_format,
922  MythRect((*chunk).m_bgShapeRect), CacheNum(),
924  if (bgshape)
925  {
926  bgshape->SetArea(MythRect((*chunk).m_bgShapeRect));
927  shapeList += bgshape;
928  }
929  }
930  }
931  }
932  while (!shapeList.isEmpty())
933  m_subScreen->AddChild(shapeList.takeFirst());
934  while (!textList.isEmpty())
935  m_subScreen->AddChild(textList.takeFirst());
936 }
937 
938 QStringList FormattedTextSubtitle::ToSRT(void) const
939 {
940  QStringList result;
941  for (const auto & ftl : qAsConst(m_lines))
942  {
943  QString line;
944  if (ftl.m_origX > 0)
945  line.fill(' ', ftl.m_origX);
946  QList<FormattedTextChunk>::const_iterator chunk;
947  for (chunk = ftl.chunks.constBegin();
948  chunk != ftl.chunks.constEnd();
949  ++chunk)
950  {
951  const QString &text = (*chunk).m_text;
952  const CC708CharacterAttribute &attr = (*chunk).m_format;
953  bool isBlank = !attr.m_underline && text.trimmed().isEmpty();
954  if (!isBlank)
955  {
956  if (attr.m_boldface)
957  line += "<b>";
958  if (attr.m_italics)
959  line += "<i>";
960  if (attr.m_underline)
961  line += "<u>";
962  if (attr.GetFGColor() != Qt::white)
963  line += QString("<font color=\"%1\">")
964  .arg(srtColorString(attr.GetFGColor()));
965  }
966  line += text;
967  if (!isBlank)
968  {
969  if (attr.GetFGColor() != Qt::white)
970  line += QString("</font>");
971  if (attr.m_underline)
972  line += "</u>";
973  if (attr.m_italics)
974  line += "</i>";
975  if (attr.m_boldface)
976  line += "</b>";
977  }
978  }
979  if (!line.trimmed().isEmpty())
980  result += line;
981  }
982  return result;
983 }
984 
985 void FormattedTextSubtitleSRT::Init(const QStringList &subs)
986 {
987  // Does a simplistic parsing of HTML tags from the strings.
988  // Nesting is not implemented. Stray whitespace may cause
989  // legitimate tags to be ignored. All other HTML tags are
990  // stripped and ignored.
991  //
992  // <i> - enable italics
993  // </i> - disable italics
994  // <b> - enable boldface
995  // </b> - disable boldface
996  // <u> - enable underline
997  // </u> - disable underline
998  // <font color="#xxyyzz"> - change font color
999  // </font> - reset font color to white
1000 
1001  int pixelSize = m_safeArea.height() / 20;
1002  if (m_subScreen)
1003  m_subScreen->SetFontSize(pixelSize);
1004  m_xAnchorPoint = 1; // center
1005  m_yAnchorPoint = 2; // bottom
1006  m_xAnchor = m_safeArea.width() / 2;
1007  m_yAnchor = m_safeArea.height();
1008 
1009  bool isItalic = false;
1010  bool isBold = false;
1011  bool isUnderline = false;
1012  QColor color(Qt::white);
1013  static const QRegularExpression htmlTag {
1014  "</?.+>", QRegularExpression::InvertedGreedinessOption };
1015  QString htmlPrefix("<font color=\"");
1016  QString htmlSuffix("\">");
1017  for (const QString& subtitle : qAsConst(subs))
1018  {
1019  FormattedTextLine line;
1020  QString text(subtitle);
1021  while (!text.isEmpty())
1022  {
1023  auto match = htmlTag.match(text);
1024  int pos = match.capturedStart();
1025  if (pos != 0) // don't add a zero-length string
1026  {
1027  CC708CharacterAttribute attr(isItalic, isBold, isUnderline,
1028  color);
1029  FormattedTextChunk chunk(text.left(pos), attr, m_subScreen);
1030  line.chunks += chunk;
1031  text = (pos < 0 ? "" : text.mid(pos));
1032  LOG(VB_VBI, LOG_INFO, QString("Adding SRT chunk: %1")
1033  .arg(chunk.ToLogString()));
1034  }
1035  if (pos >= 0)
1036  {
1037  int htmlLen = match.capturedLength();
1038  QString html = text.left(htmlLen).toLower();
1039  text = text.mid(htmlLen);
1040  if (html == "<i>")
1041  isItalic = true;
1042  else if (html == "</i>")
1043  isItalic = false;
1044  else if (html.startsWith(htmlPrefix) &&
1045  html.endsWith(htmlSuffix))
1046  {
1047  int colorLen = html.length() -
1048  (htmlPrefix.length() + htmlSuffix.length());
1049  QString colorString(
1050  html.mid(htmlPrefix.length(), colorLen));
1051  QColor newColor(colorString);
1052  if (newColor.isValid())
1053  {
1054  color = newColor;
1055  }
1056  else
1057  {
1058  LOG(VB_VBI, LOG_INFO,
1059  QString("Ignoring invalid SRT color specification: "
1060  "'%1'").arg(colorString));
1061  }
1062  }
1063  else if (html == "</font>")
1064  color = Qt::white;
1065  else if (html == "<b>")
1066  isBold = true;
1067  else if (html == "</b>")
1068  isBold = false;
1069  else if (html == "<u>")
1070  isUnderline = true;
1071  else if (html == "</u>")
1072  isUnderline = false;
1073  else
1074  {
1075  LOG(VB_VBI, LOG_INFO,
1076  QString("Ignoring unknown SRT formatting: '%1'")
1077  .arg(html));
1078  }
1079 
1080  LOG(VB_VBI, LOG_INFO,
1081  QString("SRT formatting change '%1', "
1082  "new ital=%2 bold=%3 uline=%4 color=%5)")
1083  .arg(html).arg(isItalic).arg(isBold).arg(isUnderline)
1084  .arg(srtColorString(color)));
1085  }
1086  }
1087  m_lines += line;
1088  }
1089 }
1090 
1092 {
1093  int maxWidth = m_safeArea.width();
1094  for (int i = 0; i < m_lines.size(); i++)
1095  {
1096  int width = m_lines[i].CalcSize().width();
1097  // Move entire chunks to the next line as necessary. Leave at
1098  // least one chunk on the current line.
1099  while (width > maxWidth && m_lines[i].chunks.size() > 1)
1100  {
1101  width -= m_lines[i].chunks.back().CalcSize().width();
1102  // Make sure there's a next line to wrap into.
1103  if (m_lines.size() == i + 1)
1104  m_lines += FormattedTextLine(m_lines[i].m_xIndent,
1105  m_lines[i].m_yIndent);
1106  m_lines[i+1].chunks.prepend(m_lines[i].chunks.takeLast());
1107  LOG(VB_VBI, LOG_INFO,
1108  QString("Wrapping chunk to next line: '%1'")
1109  .arg(m_lines[i+1].chunks[0].m_text));
1110  }
1111  // Split the last chunk until width is small enough or until
1112  // no more splits are possible.
1113  bool isSplitPossible = true;
1114  while (width > maxWidth && isSplitPossible)
1115  {
1116  FormattedTextChunk newChunk;
1117  isSplitPossible = m_lines[i].chunks.back().Split(newChunk);
1118  if (isSplitPossible)
1119  {
1120  // Make sure there's a next line to split into.
1121  if (m_lines.size() == i + 1)
1122  m_lines += FormattedTextLine(m_lines[i].m_xIndent,
1123  m_lines[i].m_yIndent);
1124  m_lines[i+1].chunks.prepend(newChunk);
1125  width = m_lines[i].CalcSize().width();
1126  }
1127  }
1128  }
1129 }
1130 
1136 static QString extract_cc608(QString &text, int &color,
1137  bool &isItalic, bool &isUnderline)
1138 {
1139  QString result;
1140 
1141  // Handle an initial control sequence.
1142  if (text.length() >= 1 && text[0] >= QChar(0x7000))
1143  {
1144  int op = text[0].unicode() - 0x7000;
1145  isUnderline = ((op & 0x1) != 0);
1146  switch (op & ~1)
1147  {
1148  case 0x0e:
1149  // color unchanged
1150  isItalic = true;
1151  break;
1152  case 0x1e:
1153  color = op >> 1;
1154  isItalic = true;
1155  break;
1156  case 0x20:
1157  // color unchanged
1158  // italics unchanged
1159  break;
1160  default:
1161  color = (op & 0xf) >> 1;
1162  isItalic = false;
1163  break;
1164  }
1165  text = text.mid(1);
1166  }
1167 
1168  // Copy the string into the result, up to the next control
1169  // character.
1170  static const QRegularExpression kControlCharsRE { "[\\x{7000}-\\x{7fff}]" };
1171  int nextControl = text.indexOf(kControlCharsRE);
1172  if (nextControl < 0)
1173  {
1174  result = text;
1175  text.clear();
1176  }
1177  else
1178  {
1179  result = text.left(nextControl);
1180  text = text.mid(nextControl);
1181  }
1182 
1183  return result;
1184 }
1185 
1186 // Adjusts the Y coordinates to avoid overlap, which could happen as a
1187 // result of a large text zoom factor. Then, if the total height
1188 // exceeds the safe area, compresses each piece of vertical blank
1189 // space proportionally to make it fit.
1191 {
1192  int totalHeight = 0;
1193  int totalSpace = 0;
1194  int firstY = 0;
1195  int prevY = 0;
1196  QVector<int> heights(m_lines.size());
1197  QVector<int> spaceBefore(m_lines.size());
1198  // Calculate totalHeight and totalSpace
1199  for (int i = 0; i < m_lines.size(); i++)
1200  {
1201  m_lines[i].m_yIndent = std::max(m_lines[i].m_yIndent, prevY); // avoid overlap
1202  int y = m_lines[i].m_yIndent;
1203  if (i == 0)
1204  firstY = prevY = y;
1205  int height = m_lines[i].CalcSize().height();
1206  heights[i] = height;
1207  spaceBefore[i] = y - prevY;
1208  totalSpace += (y - prevY);
1209  prevY = y + height;
1210  totalHeight += height;
1211  }
1212  int safeHeight = m_safeArea.height();
1213  int overage = std::min(totalHeight - safeHeight, totalSpace);
1214 
1215  // Recalculate Y coordinates, applying the shrink factor to space
1216  // between each line.
1217  if (overage > 0 && totalSpace > 0)
1218  {
1219  float shrink = (totalSpace - overage) / (float)totalSpace;
1220  prevY = firstY;
1221  for (int i = 0; i < m_lines.size(); i++)
1222  {
1223  m_lines[i].m_yIndent = prevY + spaceBefore[i] * shrink;
1224  prevY = m_lines[i].m_yIndent + heights[i];
1225  }
1226  }
1227 
1228  // Shift Y coordinates back up into the safe area.
1229  int shift = std::min(firstY, std::max(0, prevY - safeHeight));
1230  // NOLINTNEXTLINE(modernize-loop-convert)
1231  for (int i = 0; i < m_lines.size(); i++)
1232  m_lines[i].m_yIndent -= shift;
1233 
1235 }
1236 
1237 void FormattedTextSubtitle608::Init(const std::vector<CC608Text*> &buffers)
1238 {
1239  static const std::array<const QColor,8> kClr
1240  {
1241  Qt::white, Qt::green, Qt::blue, Qt::cyan,
1242  Qt::red, Qt::yellow, Qt::magenta, Qt::white,
1243  };
1244 
1245  if (buffers.empty())
1246  return;
1247  auto i = buffers.cbegin();
1248  int xscale = 36;
1249  int yscale = 17;
1250  int pixelSize = m_safeArea.height() / (yscale * LINE_SPACING);
1251  int fontwidth = 0;
1252  int xmid = 0;
1253  int zoom = 100;
1254  if (m_subScreen)
1255  {
1256  zoom = m_subScreen->GetZoom();
1257  m_subScreen->SetFontSize(pixelSize);
1258  CC708CharacterAttribute def_attr(false, false, false, kClr[0]);
1259  QFont *font = m_subScreen->GetFont(def_attr)->GetFace();
1260  QFontMetrics fm(*font);
1261  fontwidth = fm.averageCharWidth();
1262  xmid = m_safeArea.width() / 2;
1263  // Disable centering for zoom factor >= 100%
1264  if (zoom >= 100)
1265  xscale = m_safeArea.width() / fontwidth;
1266  }
1267 
1268  for (; i != buffers.cend(); ++i)
1269  {
1270  CC608Text *cc = (*i);
1271  int color = 0;
1272  bool isItalic = false;
1273  bool isUnderline = false;
1274  const bool isBold = false;
1275  QString text(cc->m_text);
1276 
1277  int orig_x = cc->m_x;
1278  // position as if we use a fixed size font
1279  // - font size already has zoom factor applied
1280 
1281  int x = 0;
1282  if (xmid)
1283  {
1284  // center horizontally
1285  x = xmid + (orig_x - xscale / 2) * fontwidth;
1286  }
1287  else
1288  {
1289  // fallback
1290  x = (orig_x + 3) * m_safeArea.width() / xscale;
1291  }
1292 
1293  int orig_y = cc->m_y;
1294  int y = 0;
1295  if (orig_y < yscale / 2)
1296  {
1297  // top half -- anchor up
1298  y = (orig_y * m_safeArea.height() * zoom / (yscale * 100));
1299  }
1300  else
1301  {
1302  // bottom half -- anchor down
1303  y = m_safeArea.height() -
1304  ((yscale - orig_y - 0.5) * m_safeArea.height() * zoom /
1305  (yscale * 100));
1306  }
1307 
1308  FormattedTextLine line(x, y, orig_x, orig_y);
1309  while (!text.isNull())
1310  {
1311  QString captionText =
1312  extract_cc608(text, color, isItalic, isUnderline);
1313  CC708CharacterAttribute attr(isItalic, isBold, isUnderline,
1314  kClr[std::min(std::max(0, color), 7)]);
1315  FormattedTextChunk chunk(captionText, attr, m_subScreen);
1316  line.chunks += chunk;
1317  LOG(VB_VBI, LOG_INFO,
1318  QString("Adding cc608 chunk (%1,%2): %3")
1319  .arg(cc->m_x).arg(cc->m_y).arg(chunk.ToLogString()));
1320  }
1321  m_lines += line;
1322  }
1323 }
1324 
1326 {
1327  // Draw the window background after calculating bounding rectangle
1328  // in Layout()
1329  if (m_bgFillAlpha) // TODO border?
1330  {
1331  QBrush fill(m_bgFillColor, Qt::SolidPattern);
1332  auto *shape = new SubShape(m_subScreen, QString("cc708bg%1").arg(m_num),
1334  shape->SetFillBrush(fill);
1335  shape->SetArea(MythRect(m_bounds));
1336  }
1337  // The background is drawn first so that it appears behind
1338  // everything else.
1340 }
1341 
1343  const std::vector<CC708String*> &list,
1344  float aspect)
1345 {
1346  LOG(VB_VBI, LOG_DEBUG,LOC +
1347  QString("Display Win %1, Anchor_id %2, x_anch %3, y_anch %4, "
1348  "relative %5")
1349  .arg(m_num).arg(win.m_anchor_point).arg(win.m_anchor_horizontal)
1350  .arg(win.m_anchor_vertical).arg(win.m_relative_pos));
1351  int pixelSize = m_safeArea.height() / 20;
1352  if (m_subScreen)
1353  m_subScreen->SetFontSize(pixelSize);
1354 
1355  float xrange = win.m_relative_pos ? 100.0F :
1356  (aspect > 1.4F) ? 210.0F : 160.0F;
1357  float yrange = win.m_relative_pos ? 100.0F : 75.0F;
1358  float xmult = (float)m_safeArea.width() / xrange;
1359  float ymult = (float)m_safeArea.height() / yrange;
1360  uint anchor_x = (uint)(xmult * (float)win.m_anchor_horizontal);
1361  uint anchor_y = (uint)(ymult * (float)win.m_anchor_vertical);
1362  m_xAnchorPoint = win.m_anchor_point % 3;
1363  m_yAnchorPoint = win.m_anchor_point / 3;
1364  m_xAnchor = anchor_x;
1365  m_yAnchor = anchor_y;
1366 
1367  for (auto *str708 : list)
1368  {
1369  if (str708->m_y >= (uint)m_lines.size())
1370  m_lines.resize(str708->m_y + 1);
1371  FormattedTextChunk chunk(str708->m_str, str708->m_attr, m_subScreen);
1372  m_lines[str708->m_y].chunks += chunk;
1373  LOG(VB_VBI, LOG_INFO, QString("Adding cc708 chunk: win %1 row %2: %3")
1374  .arg(m_num).arg(str708->m_y).arg(chunk.ToLogString()));
1375  }
1376 }
1377 
1379 
1381  const QString &Name, int FontStretch)
1382  : MythScreenType(static_cast<MythScreenType*>(nullptr), Name),
1383  m_player(Player),
1384  m_fontStretch(FontStretch),
1385  m_format(new SubtitleFormat)
1386 {
1387  m_painter = Painter;
1388 
1389  connect(m_player, &MythPlayer::SeekingDone, this, [&]()
1390  {
1391  LOG(VB_PLAYBACK, LOG_INFO, LOC + "SeekingDone signal received.");
1392  m_atEnd = false;
1393  });
1394 }
1395 
1397 {
1399  delete m_format;
1400 #ifdef USING_LIBASS
1402 #endif
1403 }
1404 
1405 void SubtitleScreen::EnableSubtitles(int type, bool forced_only)
1406 {
1407  int prevType = m_subtitleType;
1408  m_subtitleType = type;
1409 
1410  if (forced_only)
1411  {
1412  if (prevType == kDisplayNone)
1413  {
1415  SetVisible(true);
1416  SetArea(MythRect());
1417  }
1418  }
1419  else
1420  {
1421  if (m_subreader)
1422  {
1426  }
1427  if (m_cc608reader)
1429  if (m_cc708reader)
1433  SetArea(MythRect());
1434  }
1435  if (!forced_only || m_family.isEmpty()) {
1436  switch (m_subtitleType)
1437  {
1438  case kDisplayTextSubtitle:
1441  m_textFontZoom = gCoreContext->GetNumSetting("OSDCC708TextZoom", 100);
1442  break;
1443  case kDisplayCC608:
1445  m_textFontZoom = gCoreContext->GetNumSetting("OSDCC708TextZoom", 100);
1446  break;
1447  case kDisplayCC708:
1449  m_textFontZoom = gCoreContext->GetNumSetting("OSDCC708TextZoom", 100);
1450  break;
1451  case kDisplayAVSubtitle:
1453  m_textFontZoom = gCoreContext->GetNumSetting("OSDAVSubZoom", 100);
1454  break;
1455  }
1456  }
1461 }
1462 
1464 {
1466  return;
1468  SetVisible(false);
1469  SetArea(MythRect());
1470 }
1471 
1473 {
1476 #ifdef USING_LIBASS
1477  if (m_assTrack)
1478  ass_flush_events(m_assTrack);
1479 #endif
1480 }
1481 
1483 {
1489  m_cc608reader->ClearBuffers(true, true);
1492 }
1493 
1495 {
1498 }
1499 
1500 void SubtitleScreen::DisplayDVDButton(AVSubtitle* dvdButton, QRect &buttonPos)
1501 {
1502  if (!dvdButton || !m_player)
1503  return;
1504 
1506  if (!vo)
1507  return;
1508 
1511 
1512  float tmp = 0.0;
1513  QRect dummy;
1514  vo->GetOSDBounds(dummy, m_safeArea, tmp, tmp, tmp);
1515 
1516  AVSubtitleRect *hl_button = dvdButton->rects[0];
1517  uint h = hl_button->h;
1518  uint w = hl_button->w;
1519  QRect rect = QRect(hl_button->x, hl_button->y, w, h);
1520  QImage bg_image(hl_button->data[0], w, h, w, QImage::Format_Indexed8);
1521  auto *bgpalette = (uint32_t *)(hl_button->data[1]);
1522 
1523  QVector<uint32_t> bg_palette(4);
1524  for (int i = 0; i < 4; i++)
1525  bg_palette[i] = bgpalette[i];
1526  bg_image.setColorTable(bg_palette);
1527 
1528  // copy button region of background image
1529  const QRect fg_rect(buttonPos.translated(-hl_button->x, -hl_button->y));
1530  QImage fg_image = bg_image.copy(fg_rect);
1531  QVector<uint32_t> fg_palette(4);
1532  auto *fgpalette = (uint32_t *)(dvdButton->rects[1]->data[1]);
1533  if (fgpalette)
1534  {
1535  for (int i = 0; i < 4; i++)
1536  fg_palette[i] = fgpalette[i];
1537  fg_image.setColorTable(fg_palette);
1538  }
1539 
1540  bg_image = bg_image.convertToFormat(QImage::Format_ARGB32);
1541  fg_image = fg_image.convertToFormat(QImage::Format_ARGB32);
1542 
1543  // set pixel of highlight area to highlight color
1544  for (int x=fg_rect.x(); x < fg_rect.x()+fg_rect.width(); ++x)
1545  {
1546  if ((x < 0) || (x > hl_button->w))
1547  continue;
1548  for (int y=fg_rect.y(); y < fg_rect.y()+fg_rect.height(); ++y)
1549  {
1550  if ((y < 0) || (y > hl_button->h))
1551  continue;
1552  bg_image.setPixel(x, y, fg_image.pixel(x-fg_rect.x(),y-fg_rect.y()));
1553  }
1554  }
1555 
1556  AddScaledImage(bg_image, rect);
1557 }
1558 
1559 void SubtitleScreen::SetZoom(int percent)
1560 {
1561  m_textFontZoom = percent;
1562  if (m_family == kSubFamilyAV)
1563  gCoreContext->SaveSetting("OSDAVSubZoom", percent);
1564  else
1565  gCoreContext->SaveSetting("OSDCC708TextZoom", percent);
1566 }
1567 
1569 {
1570  return m_textFontZoom;
1571 }
1572 
1573 void SubtitleScreen::SetDelay(std::chrono::milliseconds ms)
1574 {
1575  m_textFontDelayMs = ms;
1576 }
1577 
1578 std::chrono::milliseconds SubtitleScreen::GetDelay(void) const
1579 {
1580  return m_textFontDelayMs;
1581 }
1582 
1584 {
1585  QList<MythUIType *> list = m_childrenList;
1586  QList<MythUIType *>::iterator it;
1587  for (it = list.begin(); it != list.end(); ++it)
1588  {
1589  MythUIType *child = *it;
1590  auto *wrapper = dynamic_cast<SubWrapper *>(child);
1591  if (wrapper)
1592  {
1593  int whichImageCache = wrapper->GetWhichImageCache();
1594  if (whichImageCache != -1 && (mask & (1UL << whichImageCache)))
1595  {
1597  DeleteChild(child);
1598  }
1599  }
1600  }
1601 }
1602 
1603 // SetElementAdded() should be called after a new element is added to
1604 // the subtitle screen.
1606 {
1607  m_refreshModified = true;
1608 }
1609 
1610 // SetElementResized() should be called after a subtitle screen
1611 // element's size is changed.
1613 {
1614  SetElementAdded();
1615 }
1616 
1617 // SetElementAdded() should be called *before* an element is deleted
1618 // from the subtitle screen.
1620 {
1621  if (!m_refreshDeleted)
1622  SetRedraw();
1623  m_refreshDeleted = true;
1624 }
1625 
1626 // The QFontMetrics class does not account for the MythFontProperties
1627 // shadow and offset properties. This method calculates the
1628 // additional padding to the right and below that is needed for proper
1629 // bounding box computation.
1631 {
1632  QColor color;
1633  int alpha = 0;
1634  int outlineSize = 0;
1635  int shadowWidth = 0;
1636  int shadowHeight = 0;
1637  if (mythfont->hasOutline())
1638  {
1639  mythfont->GetOutline(color, outlineSize, alpha);
1640  MythPoint outline(outlineSize, outlineSize);
1641  outline.NormPoint();
1642  outlineSize = outline.x();
1643  }
1644  if (mythfont->hasShadow())
1645  {
1646  MythPoint shadowOffset;
1647  mythfont->GetShadow(shadowOffset, color, alpha);
1648  shadowOffset.NormPoint();
1649  shadowWidth = abs(shadowOffset.x());
1650  shadowHeight = abs(shadowOffset.y());
1651  // Shadow and outline overlap, so don't just add them.
1652  shadowWidth = std::max(shadowWidth, outlineSize);
1653  shadowHeight = std::max(shadowHeight, outlineSize);
1654  }
1655  return {shadowWidth + outlineSize, shadowHeight + outlineSize};
1656 }
1657 
1658 QSize SubtitleScreen::CalcTextSize(const QString &text,
1659  const CC708CharacterAttribute &format,
1660  float layoutSpacing) const
1661 {
1662  MythFontProperties *mythfont = GetFont(format);
1663  QFont *font = mythfont->GetFace();
1664  QFontMetrics fm(*font);
1665  int width = fm.horizontalAdvance(text);
1666  int height = fm.height() * (1 + PAD_HEIGHT);
1667  if (layoutSpacing > 0 && !text.trimmed().isEmpty())
1668  height = std::max(height, (int)(font->pixelSize() * layoutSpacing));
1669  height += CalcShadowOffsetPadding(mythfont).height();
1670  return {width, height};
1671 }
1672 
1673 // Padding calculation is different depending on whether the padding
1674 // is on the left side or the right side of the text. Padding on the
1675 // right needs to add the shadow and offset padding.
1677  bool isFirst, bool isLast,
1678  int &left, int &right) const
1679 {
1680  MythFontProperties *mythfont = GetFont(format);
1681  QFont *font = mythfont->GetFace();
1682  QFontMetrics fm(*font);
1683  int basicPadding = fm.maxWidth() * PAD_WIDTH;
1684  left = isFirst ? basicPadding : 0;
1685  right = CalcShadowOffsetPadding(mythfont).width() +
1686  (isLast ? basicPadding : 0);
1687 }
1688 
1691 {
1692  return m_format->GetFont(m_family, attr, m_fontSize,
1694 }
1695 
1697 {
1698  SubtitleFormat format;
1699  CC708CharacterAttribute attr(false, false, false, Qt::white);
1700  MythFontProperties *mythfont =
1701  format.GetFont(kSubFamilyTeletext, attr,
1702  /*pixelsize*/20, /*zoom*/100, /*stretch*/100);
1703  return mythfont->face().family();
1704 }
1705 
1707 {
1708  SubtitleFormat format;
1709  return format.GetBackgroundAlpha(kSubFamilyTeletext);
1710 }
1711 
1713 {
1714  if (!m_player)
1715  return false;
1716 
1720  if (!m_subreader)
1721  LOG(VB_GENERAL, LOG_WARNING, LOC + "Failed to get subtitle reader.");
1722  if (!m_cc608reader)
1723  LOG(VB_GENERAL, LOG_WARNING, LOC + "Failed to get CEA-608 reader.");
1724  if (!m_cc708reader)
1725  LOG(VB_GENERAL, LOG_WARNING, LOC + "Failed to get CEA-708 reader.");
1726 
1727  return true;
1728 }
1729 
1731 {
1732  QList<MythUIType *>::iterator it;
1733  QList<MythUIType *>::iterator itNext;
1734 
1735  MythVideoOutput *videoOut = m_player->GetVideoOutput();
1736  MythVideoFrame *currentFrame = videoOut ? videoOut->GetLastShownFrame() : nullptr;
1737  std::chrono::milliseconds now =
1738  currentFrame ? currentFrame->m_timecode : std::chrono::milliseconds::max();
1739  bool needRescale = (m_textFontZoom != m_textFontZoomPrev);
1740 
1741  for (it = m_childrenList.begin(); it != m_childrenList.end(); it = itNext)
1742  {
1743  itNext = it + 1;
1744  MythUIType *child = *it;
1745  auto *wrapper = dynamic_cast<SubWrapper *>(child);
1746  if (!wrapper)
1747  continue;
1748 
1749  // Expire the subtitle object if needed.
1750  std::chrono::milliseconds expireTime = wrapper->GetExpireTime();
1751  if (expireTime > 0ms && expireTime < now)
1752  {
1753  DeleteChild(child);
1755  continue;
1756  }
1757 
1758  // Rescale the AV subtitle image if the zoom changed.
1759  if (expireTime > 0ms && needRescale)
1760  {
1761  auto *image = dynamic_cast<SubImage *>(child);
1762  if (image)
1763  {
1764  double factor = m_textFontZoom / (double)m_textFontZoomPrev;
1765  QSize size = image->GetImage()->size();
1766  size *= factor;
1767  image->GetImage()->Resize(size);
1769  }
1770  }
1771  }
1772 
1773  DisplayAVSubtitles(); // allow forced subtitles to work
1774 
1777  else if (kDisplayCC708 == m_subtitleType)
1781  while (!m_qInited.isEmpty())
1782  {
1783  FormattedTextSubtitle *fsub = m_qInited.takeFirst();
1784  fsub->WrapLongLines();
1785  fsub->Layout();
1786  fsub->PreRender();
1787  fsub->Draw();
1788  delete fsub;
1789  SetElementAdded();
1790  }
1791 
1799 }
1800 
1802 {
1803  m_refreshModified = false;
1804  m_refreshDeleted = false;
1805 }
1806 
1808 {
1809  if (!m_refreshModified)
1810  return;
1811 
1812  QRegion visible;
1813  QListIterator<MythUIType *> i(m_childrenList);
1814  while (i.hasNext())
1815  {
1816  MythUIType *img = i.next();
1817  auto *wrapper = dynamic_cast<SubWrapper *>(img);
1818  if (wrapper && img->IsVisible())
1819  visible = visible.united(wrapper->GetOrigArea());
1820  }
1821 
1822  if (visible.isEmpty())
1823  return;
1824 
1825  QRect bounding = visible.boundingRect();
1826  bounding = bounding.translated(m_safeArea.topLeft());
1827  bounding = m_safeArea.intersected(bounding);
1828  int left = m_safeArea.left() - bounding.left();
1829  int top = m_safeArea.top() - bounding.top();
1830  SetArea(MythRect(bounding));
1831 
1832  i.toFront();
1833  while (i.hasNext())
1834  {
1835  MythUIType *img = i.next();
1836  auto *wrapper = dynamic_cast<SubWrapper *>(img);
1837  if (wrapper && img->IsVisible())
1838  img->SetArea(MythRect(wrapper->GetOrigArea().translated(left, top)));
1839  }
1840 }
1841 
1843 {
1844  if (!m_player || !m_subreader)
1845  return;
1846 
1848  QMutexLocker lock(&(subs->m_lock));
1849  if (subs->m_buffers.empty()
1852  return;
1853 
1854  MythVideoOutput *videoOut = m_player->GetVideoOutput();
1855  MythVideoFrame *currentFrame = videoOut ? videoOut->GetLastShownFrame() : nullptr;
1856  int ret {0};
1857 
1858  if (!currentFrame || !videoOut)
1859  return;
1860 
1861  if (subs->m_buffers.empty() && (m_subreader->GetParser() != nullptr))
1862  {
1863  if (subs->m_needSync)
1864  {
1865  // Seeking on a subtitle stream is a pain. The internals
1866  // of ff_subtitles_queue_seek() calls search_sub_ts(),
1867  // which always returns the subtitle that starts on or
1868  // before the current timestamp.
1869  //
1870  // If avformat_seek_file() has been asked to search
1871  // forward, then the subsequent range check will always
1872  // fail because avformat_seek_file() has set the minimum
1873  // timestamp to the requested timestamp. This call only
1874  // succeeds if the timestamp matches to the millisecond.
1875  //
1876  // If avformat_seek_file() has been asked to search
1877  // backward then a subtitle will be returned, but because
1878  // that subtitle is in the past the code below this
1879  // comment will always consume that subtitle, resulting in
1880  // a new seek every time this function is called.
1881  //
1882  // The solution seems to be to seek backwards so that we
1883  // get the subtitle that should have most recently been
1884  // displayed, then skip that subtitle to get the one that
1885  // should be displayed next.
1886  lock.unlock();
1887  m_subreader->SeekFrame(currentFrame->m_timecode.count()*1000,
1888  AVSEEK_FLAG_BACKWARD);
1889  ret = m_subreader->ReadNextSubtitle();
1890  if (ret < 0)
1891  {
1892  m_atEnd = true;
1893 #ifdef DEBUG_SUBTITLES
1894  if (VERBOSE_LEVEL_CHECK(VB_PLAYBACK, LOG_DEBUG))
1895  {
1896  LOG(VB_PLAYBACK, LOG_DEBUG,
1897  LOC + QString("time %1, no subtitle available after seek")
1898  .arg(toString(currentFrame)));
1899  }
1900 #endif
1901  }
1902  lock.relock();
1903  subs->m_needSync = false;
1904 
1905  // extra check to avoid segfault
1906  if (subs->m_buffers.empty())
1907  return;
1908  AVSubtitle subtitle = subs->m_buffers.front();
1909  if (subtitle.end_display_time < currentFrame->m_timecode.count())
1910  {
1911  subs->m_buffers.pop_front();
1912 #ifdef DEBUG_SUBTITLES
1913  if (VERBOSE_LEVEL_CHECK(VB_PLAYBACK, LOG_DEBUG))
1914  {
1915  LOG(VB_PLAYBACK, LOG_DEBUG,
1916  LOC + QString("time %1, drop %2")
1917  .arg(toString(currentFrame), toString(subtitle)));
1918  }
1919 #endif
1920  }
1921  }
1922 
1923  // Always add one subtitle.
1924  lock.unlock();
1925  if (!m_atEnd)
1926  {
1927  ret = m_subreader->ReadNextSubtitle();
1928  if (ret < 0)
1929  {
1930  m_atEnd = true;
1931 #ifdef DEBUG_SUBTITLES
1932  if (VERBOSE_LEVEL_CHECK(VB_PLAYBACK, LOG_DEBUG))
1933  {
1934  LOG(VB_PLAYBACK, LOG_DEBUG,
1935  LOC + QString("time %1, no subtitle available")
1936  .arg(toString(currentFrame)));
1937  }
1938 #endif
1939  }
1940  }
1941  lock.relock();
1942  }
1943 
1944  float tmp = 0.0;
1945  QRect dummy;
1946  videoOut->GetOSDBounds(dummy, m_safeArea, tmp, tmp, tmp);
1947 
1948  [[maybe_unused]] bool assForceNext {false};
1949  while (!subs->m_buffers.empty())
1950  {
1951  AVSubtitle subtitle = subs->m_buffers.front();
1952  if (subtitle.start_display_time > currentFrame->m_timecode.count())
1953  {
1954 #ifdef DEBUG_SUBTITLES
1955  if (VERBOSE_LEVEL_CHECK(VB_PLAYBACK, LOG_DEBUG))
1956  {
1957  LOG(VB_PLAYBACK, LOG_DEBUG,
1958  LOC + QString("time %1, next %2")
1959  .arg(toString(currentFrame), toString(subtitle)));
1960  }
1961 #endif
1962  break;
1963  }
1964 
1965  // If this is the most recently displayed subtitle and a
1966  // backward jump means that it needs to be displayed again,
1967  // the call to ass_render_frame will say there is no work to
1968  // be done. Force RenderAssTrack to display the subtitle
1969  // anyway.
1970  assForceNext = true;
1971 
1972  auto displayfor = std::chrono::milliseconds(subtitle.end_display_time -
1973  subtitle.start_display_time);
1974 #ifdef DEBUG_SUBTITLES
1975  if (VERBOSE_LEVEL_CHECK(VB_PLAYBACK, LOG_DEBUG))
1976  {
1977  LOG(VB_PLAYBACK, LOG_DEBUG,
1978  LOC + QString("time %1, show %2")
1979  .arg(toString(currentFrame), toString(subtitle)));
1980  }
1981 #endif
1982  if (displayfor == 0ms)
1983  displayfor = 60s;
1984  displayfor = (displayfor < 50ms) ? 50ms : displayfor;
1985  std::chrono::milliseconds late = currentFrame->m_timecode -
1986  std::chrono::milliseconds(subtitle.start_display_time);
1987 
1989  subs->m_buffers.pop_front();
1990  for (std::size_t i = 0; i < subtitle.num_rects; ++i)
1991  {
1992  AVSubtitleRect* rect = subtitle.rects[i];
1993 
1994  bool displaysub = true;
1995  if (!subs->m_buffers.empty() &&
1996  subs->m_buffers.front().end_display_time <
1997  currentFrame->m_timecode.count())
1998  {
1999  displaysub = false;
2000  }
2001 
2002  if (displaysub && rect->type == SUBTITLE_BITMAP)
2003  {
2004  QRect display(rect->display_x, rect->display_y,
2005  rect->display_w, rect->display_h);
2006 
2007  // XSUB and some DVD/DVB subs are based on the original video
2008  // size before the video was converted. We need to guess the
2009  // original size and allow for the difference
2010 
2011  int right = rect->x + rect->w;
2012  int bottom = rect->y + rect->h;
2013  if (subs->m_fixPosition || (currentFrame->m_height < bottom) ||
2014  (currentFrame->m_width < right) ||
2015  !display.width() || !display.height())
2016  {
2017  int sd_height = 576;
2018  if ((m_player->GetFrameRate() > 26.0F ||
2019  m_player->GetFrameRate() < 24.0F) && bottom <= 480)
2020  sd_height = 480;
2021  int height = ((currentFrame->m_height <= sd_height) &&
2022  (bottom <= sd_height)) ? sd_height :
2023  ((currentFrame->m_height <= 720) && bottom <= 720)
2024  ? 720 : 1080;
2025  int width = ((currentFrame->m_width <= 720) &&
2026  (right <= 720)) ? 720 :
2027  ((currentFrame->m_width <= 1280) &&
2028  (right <= 1280)) ? 1280 : 1920;
2029  display = QRect(0, 0, width, height);
2030  }
2031 
2032  // split into upper/lower to allow zooming
2033  QRect bbox;
2034  int uh = display.height() / 2 - rect->y;
2035  std::chrono::milliseconds displayuntil = currentFrame->m_timecode + displayfor;
2036  if (uh > 0)
2037  {
2038  bbox = QRect(0, 0, rect->w, uh);
2039  uh = DisplayScaledAVSubtitles(rect, bbox, true, display,
2040  rect->flags & AV_SUBTITLE_FLAG_FORCED,
2041  QString("avsub%1t").arg(i),
2042  displayuntil, late);
2043  }
2044  else
2045  uh = 0;
2046  int lh = rect->h - uh;
2047  if (lh > 0)
2048  {
2049  bbox = QRect(0, uh, rect->w, lh);
2050  DisplayScaledAVSubtitles(rect, bbox, false, display,
2051  rect->flags & AV_SUBTITLE_FLAG_FORCED,
2052  QString("avsub%1b").arg(i),
2053  displayuntil, late);
2054  }
2055  }
2056 #ifdef USING_LIBASS
2057  else if (displaysub && rect->type == SUBTITLE_ASS)
2058  {
2060  AddAssEvent(rect->ass, subtitle.start_display_time, subtitle.end_display_time);
2061  }
2062 #endif
2063  }
2065  }
2066 #ifdef USING_LIBASS
2067  RenderAssTrack(currentFrame->m_timecode, assForceNext);
2068 #endif
2069 }
2070 
2071 int SubtitleScreen::DisplayScaledAVSubtitles(const AVSubtitleRect *rect,
2072  QRect &bbox, bool top,
2073  QRect &display, int forced,
2074  const QString& imagename,
2075  std::chrono::milliseconds displayuntil,
2076  std::chrono::milliseconds late)
2077 {
2078  // split image vertically if it spans middle of display
2079  // - split point is empty line nearest the middle
2080  // crop image to reduce scaling time
2081  bool prev_empty = false;
2082 
2083  // initialize to opposite edges
2084  int xmin = bbox.right();
2085  int xmax = bbox.left();
2086  int ymin = bbox.bottom();
2087  int ymax = bbox.top();
2088  int ylast = bbox.top();
2089  int ysplit = bbox.bottom();
2090 
2091  // find bounds of active image
2092  for (int y = bbox.top(); y <= bbox.bottom(); ++y)
2093  {
2094  if (y >= rect->h)
2095  {
2096  // end of image
2097  if (!prev_empty)
2098  ylast = y;
2099  break;
2100  }
2101 
2102  bool empty = true;
2103  for (int x = bbox.left(); x <= bbox.right(); ++x)
2104  {
2105  const uint8_t color =
2106  rect->data[0][y * rect->linesize[0] + x];
2107  const uint32_t pixel = *((uint32_t *)rect->data[1] + color);
2108  if (pixel & 0xff000000)
2109  {
2110  empty = false;
2111  if (x < xmin)
2112  xmin = x;
2113  if (x > xmax)
2114  xmax = x;
2115  }
2116  }
2117 
2118  if (!empty)
2119  {
2120  if (y < ymin)
2121  ymin = y;
2122  if (y > ymax)
2123  ymax = y;
2124  }
2125  else if (!prev_empty)
2126  {
2127  // remember uppermost empty line
2128  ylast = y;
2129  }
2130  prev_empty = empty;
2131  }
2132 
2133  if (ymax <= ymin)
2134  return 0;
2135 
2136  if (top)
2137  {
2138  if (ylast < ymin)
2139  // no empty lines
2140  return 0;
2141 
2142  if (ymax == bbox.bottom())
2143  {
2144  ymax = ylast;
2145  ysplit = ylast;
2146  }
2147  }
2148 
2149  // set new bounds
2150  bbox.setLeft(xmin);
2151  bbox.setRight(xmax);
2152  bbox.setTop(ymin);
2153  bbox.setBottom(ymax);
2154 
2155  // copy active region
2156  // AVSubtitleRect's image data's not guaranteed to be 4 byte
2157  // aligned.
2158 
2159  QRect orig_rect(bbox.left(), bbox.top(), bbox.width(), bbox.height());
2160 
2161  QImage qImage(bbox.width(), bbox.height(), QImage::Format_ARGB32);
2162  for (int y = 0; y < bbox.height(); ++y)
2163  {
2164  int ysrc = y + bbox.top();
2165  for (int x = 0; x < bbox.width(); ++x)
2166  {
2167  int xsrc = x + bbox.left();
2168  const uint8_t color =
2169  rect->data[0][ysrc * rect->linesize[0] + xsrc];
2170  const uint32_t pixel = *((uint32_t *)rect->data[1] + color);
2171  qImage.setPixel(x, y, pixel);
2172  }
2173  }
2174 
2175  // translate to absolute coordinates
2176  bbox.translate(rect->x, rect->y);
2177 
2178  // scale and move according to zoom factor
2179  bbox.setWidth(bbox.width() * m_textFontZoom / 100);
2180  bbox.setHeight(bbox.height() * m_textFontZoom / 100);
2181 
2182  MythVideoOutput *videoOut = m_player->GetVideoOutput();
2183  QRect scaled = videoOut->GetImageRect(bbox, &display);
2184 
2185  if (scaled.size() != orig_rect.size())
2186  qImage = qImage.scaled(scaled.width(), scaled.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
2187 
2188  int hsize = m_safeArea.width();
2189  int vsize = m_safeArea.height();
2190 
2191  scaled.moveLeft(((100 - m_textFontZoom) * hsize / 2 + m_textFontZoom * scaled.left()) / 100);
2192  if (top)
2193  {
2194  // anchor up
2195  scaled.moveTop(scaled.top() * m_textFontZoom / 100);
2196  }
2197  else
2198  {
2199  // anchor down
2200  scaled.moveTop(((100 - m_textFontZoom) * vsize + m_textFontZoom * scaled.top()) / 100);
2201  }
2202 
2203  MythImage* image = m_painter->GetFormatImage();
2204  SubImage *uiimage = nullptr;
2205 
2206  if (image)
2207  {
2208  image->Assign(qImage);
2209  uiimage = new SubImage(this, imagename, MythRect(scaled), displayuntil);
2210  if (uiimage)
2211  {
2212  uiimage->SetImage(image);
2213  uiimage->SetArea(MythRect(scaled));
2214  SetElementAdded();
2215  }
2216  image->DecrRef();
2217  image = nullptr;
2218  }
2219 
2220  if (uiimage)
2221  {
2222  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Display %1AV sub until %2ms")
2223  .arg(forced ? "FORCED " : "").arg(displayuntil.count()));
2224  if (late > 50ms)
2225  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("AV Sub was %1ms late").arg(late.count()));
2226  }
2227 
2228  return (ysplit + 1);
2229 }
2230 
2232 {
2233  if (!m_player || !m_subreader)
2234  return;
2235 
2236  std::chrono::milliseconds duration = 0ms;
2237  QStringList subs = m_subreader->GetRawTextSubtitles(duration);
2238  if (subs.empty())
2239  return;
2240 
2242  if (!vo)
2243  return;
2244 
2245  MythVideoFrame *currentFrame = vo->GetLastShownFrame();
2246  if (!currentFrame)
2247  return;
2248 
2249  m_safeArea = vo->GetSafeRect();
2250 
2251  // delete old subs that may still be on screen
2254  DrawTextSubtitles(subs, currentFrame->m_timecode, duration);
2255 }
2256 
2257 void SubtitleScreen::DrawTextSubtitles(const QStringList &subs,
2258  std::chrono::milliseconds start,
2259  std::chrono::milliseconds duration)
2260 {
2261  auto *fsub = new FormattedTextSubtitleSRT(m_family, m_safeArea, start,
2262  duration, this, subs);
2263  m_qInited.append(fsub);
2264 }
2265 
2267 {
2268  if (!m_cc608reader)
2269  return;
2270 
2271  bool changed = (m_textFontZoom != m_textFontZoomPrev);
2272 
2273  if (!m_player || !m_player->GetVideoOutput())
2274  return;
2276 
2277  CC608Buffer* textlist = m_cc608reader->GetOutputText(changed);
2278  if (!changed)
2279  return;
2280 
2283 
2284  if (!textlist)
2285  return;
2286 
2287  QMutexLocker locker(&textlist->m_lock);
2288 
2289  if (textlist->m_buffers.empty())
2290  return;
2291 
2292  auto *fsub = new FormattedTextSubtitle608(textlist->m_buffers, m_family,
2293  m_safeArea, this/*, m_textFontZoom*/);
2294  m_qInited.append(fsub);
2295 }
2296 
2298 {
2300  return;
2301 
2302  CC708Service *cc708service = m_cc708reader->GetCurrentService();
2303  float video_aspect = m_player->GetVideoAspect();
2304  QRect oldsafe = m_safeArea;
2306  bool changed = (oldsafe != m_safeArea || m_textFontZoom != m_textFontZoomPrev);
2307  if (changed)
2308  {
2309  for (auto & window : cc708service->m_windows)
2310  window.SetChanged();
2311  }
2312 
2313  uint64_t clearMask = 0;
2314  QList<FormattedTextSubtitle *> addList;
2315  for (int i = 0; i < k708MaxWindows; i++)
2316  {
2317  CC708Window &win = cc708service->m_windows[i];
2318  if (win.GetExists() && win.GetVisible() && !win.GetChanged())
2319  continue;
2320  if (!win.GetChanged())
2321  continue;
2322 
2323  clearMask |= (1UL << i);
2324  win.ResetChanged();
2325  if (!win.GetExists() || !win.GetVisible())
2326  continue;
2327 
2328  QMutexLocker locker(&win.m_lock);
2329  std::vector<CC708String*> list = win.GetStrings();
2330  if (!list.empty())
2331  {
2332  auto *fsub = new FormattedTextSubtitle708(win, i, list, m_family,
2333  m_safeArea, this, video_aspect);
2334  addList.append(fsub);
2335  }
2337  }
2338  if (clearMask)
2339  {
2340  Clear708Cache(clearMask);
2341  }
2342  if (!addList.empty())
2343  m_qInited.append(addList);
2344 }
2345 
2346 void SubtitleScreen::AddScaledImage(QImage &img, QRect &pos)
2347 {
2349  if (!vo)
2350  return;
2351 
2352  QRect scaled = vo->GetImageRect(pos);
2353  if (scaled.size() != pos.size())
2354  {
2355  img = img.scaled(scaled.width(), scaled.height(),
2356  Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
2357  }
2358 
2359  MythImage* image = m_painter->GetFormatImage();
2360  if (image)
2361  {
2362  image->Assign(img);
2363  MythUIImage *uiimage = new SubImage(this, "dvd_button", MythRect(scaled), 0ms);
2364  if (uiimage)
2365  {
2366  uiimage->SetImage(image);
2367  uiimage->SetArea(MythRect(scaled));
2368  SetElementAdded();
2369  }
2370  image->DecrRef();
2371  }
2372 }
2373 
2374 #ifdef USING_LIBASS
2375 static void myth_libass_log(int level, const char *fmt, va_list vl, void */*ctx*/)
2376 {
2377  uint64_t verbose_mask = VB_GENERAL;
2378  LogLevel_t verbose_level = LOG_INFO;
2379 
2380  switch (level)
2381  {
2382  case 0: //MSGL_FATAL
2383  verbose_level = LOG_EMERG;
2384  break;
2385  case 1: //MSGL_ERR
2386  verbose_level = LOG_ERR;
2387  break;
2388  case 2: //MSGL_WARN
2389  verbose_level = LOG_WARNING;
2390  break;
2391  case 4: //MSGL_INFO
2392  verbose_level = LOG_INFO;
2393  break;
2394  case 6: //MSGL_V
2395  case 7: //MSGL_DBG2
2396  verbose_level = LOG_DEBUG;
2397  break;
2398  default:
2399  return;
2400  }
2401 
2402  if (!VERBOSE_LEVEL_CHECK(verbose_mask, verbose_level))
2403  return;
2404 
2405  static QMutex s_stringLock;
2406  s_stringLock.lock();
2407 
2408  QString str = QString::vasprintf(fmt, vl);
2409  LOG(verbose_mask, verbose_level, QString("libass: %1").arg(str));
2410  s_stringLock.unlock();
2411 }
2412 
2414 {
2415  if (m_assLibrary && m_assRenderer)
2416  return true;
2417 
2418  if (!m_assLibrary)
2419  {
2420  m_assLibrary = ass_library_init();
2421  if (!m_assLibrary)
2422  return false;
2423 
2424  ass_set_message_cb(m_assLibrary, myth_libass_log, nullptr);
2425  ass_set_extract_fonts(m_assLibrary, static_cast<int>(true));
2426  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Initialised libass object.");
2427  }
2428 
2429  LoadAssFonts();
2430 
2431  if (!m_assRenderer)
2432  {
2433  m_assRenderer = ass_renderer_init(m_assLibrary);
2434  if (!m_assRenderer)
2435  return false;
2436 
2437 #ifdef Q_OS_ANDROID
2438  // fontconfig doesn't yet work for us on Android. For the
2439  // time being, more explicitly set a font we know should
2440  // exist. This was adapted from VLC master as of 2019-01-21.
2441  const char *psz_font = "/system/fonts/DroidSans.ttf";
2442  const char *psz_font_family = "Droid Sans";
2443 #else
2444  const char *psz_font = nullptr;
2445  const char *psz_font_family = "sans-serif";
2446 #endif
2447  ass_set_fonts(m_assRenderer, psz_font, psz_font_family, 1, nullptr, 1);
2448  ass_set_hinting(m_assRenderer, ASS_HINTING_LIGHT);
2449  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Initialised libass renderer.");
2450  }
2451 
2452  return true;
2453 }
2454 
2456 {
2457  if (!m_assLibrary || !m_player)
2458  return;
2459 
2461  if (m_assFontCount == count)
2462  return;
2463 
2464  ass_clear_fonts(m_assLibrary);
2465  m_assFontCount = 0;
2466 
2467  // TODO these need checking and/or reinitialising after a stream change
2468  for (uint i = 0; i < count; ++i)
2469  {
2470  QByteArray filename;
2471  QByteArray font;
2473  ass_add_font(m_assLibrary, filename.data(), font.data(), font.size());
2474  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Retrieved font '%1'")
2475  .arg(filename.constData()));
2476  m_assFontCount++;
2477  }
2478 }
2479 
2481 {
2482  CleanupAssTrack();
2483 
2484  if (m_assRenderer)
2485  ass_renderer_done(m_assRenderer);
2486  m_assRenderer = nullptr;
2487 
2488  if (m_assLibrary)
2489  {
2490  ass_clear_fonts(m_assLibrary);
2491  m_assFontCount = 0;
2492  ass_library_done(m_assLibrary);
2493  }
2494  m_assLibrary = nullptr;
2495 }
2496 
2498 {
2499  if (!InitialiseAssLibrary() || !m_player)
2500  return;
2501 
2502  if (tracknum == m_assTrackNum && m_assTrack)
2503  return;
2504 
2505  LoadAssFonts();
2506  CleanupAssTrack();
2507  m_assTrack = ass_new_track(m_assLibrary);
2508  m_assTrackNum = tracknum;
2509 
2510  QByteArray header = m_player->GetDecoder()->GetSubHeader(tracknum);
2511  if (header.isNull())
2512  {
2514  if (parser)
2515  header = parser->GetSubHeader();
2516  }
2517  if (!header.isNull())
2518  ass_process_codec_private(m_assTrack, header.data(), header.size());
2519 
2522 }
2523 
2525 {
2526  if (m_assTrack)
2527  ass_free_track(m_assTrack);
2528  m_assTrack = nullptr;
2529 }
2530 
2531 void SubtitleScreen::AddAssEvent(char *event, uint32_t starttime, uint32_t endtime)
2532 {
2533  if (m_assTrack && event)
2534  ass_process_chunk(m_assTrack, event, strlen(event), starttime, endtime-starttime);
2535 }
2536 
2538 {
2539  ass_set_frame_size(m_assRenderer, m_safeArea.width(), m_safeArea.height());
2540  ass_set_margins(m_assRenderer, 0, 0, 0, 0);
2541  ass_set_use_margins(m_assRenderer, static_cast<int>(true));
2542  ass_set_font_scale(m_assRenderer, 1.0);
2543 }
2544 
2545 void SubtitleScreen::RenderAssTrack(std::chrono::milliseconds timecode, bool force)
2546 {
2547  if (!m_player || !m_assRenderer || !m_assTrack)
2548  return;
2549 
2551  if (!vo )
2552  return;
2553 
2554  QRect oldscreen = m_safeArea;
2556  if (oldscreen != m_safeArea)
2558 
2559  int changed = 0;
2560  ASS_Image *images = ass_render_frame(m_assRenderer, m_assTrack, timecode.count(), &changed);
2561  if (!changed && !force)
2562  return;
2563 
2564  int count = 0;
2567  while (images)
2568  {
2569  if (images->w == 0 || images->h == 0)
2570  {
2571  images = images->next;
2572  continue;
2573  }
2574 
2575  uint8_t alpha = images->color & 0xFF;
2576  uint8_t blue = images->color >> 8 & 0xFF;
2577  uint8_t green = images->color >> 16 & 0xFF;
2578  uint8_t red = images->color >> 24 & 0xFF;
2579 
2580  if (alpha == 255)
2581  {
2582  images = images->next;
2583  continue;
2584  }
2585 
2586  QSize img_size(images->w, images->h);
2587  QRect img_rect(images->dst_x,images->dst_y,
2588  images->w, images->h);
2589  QImage qImage(img_size, QImage::Format_ARGB32);
2590  qImage.fill(0x00000000);
2591 
2592  unsigned char *src = images->bitmap;
2593  for (int y = 0; y < images->h; ++y)
2594  {
2595  for (int x = 0; x < images->w; ++x)
2596  {
2597  uint8_t value = src[x];
2598  if (value)
2599  {
2600  uint32_t pixel = (value * (255 - alpha) / 255 << 24) |
2601  (red << 16) | (green << 8) | blue;
2602  qImage.setPixel(x, y, pixel);
2603  }
2604  }
2605  src += images->stride;
2606  }
2607 
2608  MythImage* image = m_painter->GetFormatImage();
2609  SubImage *uiimage = nullptr;
2610 
2611  if (image)
2612  {
2613  image->Assign(qImage);
2614  QString name = QString("asssub%1").arg(count);
2615  uiimage = new SubImage(this, name, MythRect(img_rect), 0ms);
2616  if (uiimage)
2617  {
2618  uiimage->SetImage(image);
2619  uiimage->SetArea(MythRect(img_rect));
2620  SetElementAdded();
2621  }
2622  image->DecrRef();
2623  }
2624 
2625  images = images->next;
2626  count++;
2627  }
2628 }
2629 #endif // USING_LIBASS
SubtitleScreen::DisplayRawTextSubtitles
void DisplayRawTextSubtitles(void)
Definition: subtitlescreen.cpp:2231
kSubAttrOutlinealpha
static const QString kSubAttrOutlinealpha("outlinealpha")
FormattedTextSubtitle
Definition: subtitlescreen.h:75
CC608Buffer::m_lock
QMutex m_lock
Definition: cc608reader.h:49
MythVideoOutput::GetOSDBounds
virtual void GetOSDBounds(QRect &Total, QRect &Visible, float &VisibleAspect, float &FontScaling, float ThemeAspect) const
Definition: mythvideoout.cpp:207
SubImage::SubImage
SubImage(MythUIType *parent, const QString &name, const MythRect &area, std::chrono::milliseconds expireTime)
Definition: subtitlescreen.cpp:79
FormattedTextSubtitle::CacheNum
virtual int CacheNum(void) const
Definition: subtitlescreen.h:96
kSubAttrShadowcolor
static const QString kSubAttrShadowcolor("shadowcolor")
k708AttrEdgeDepressed
const uint k708AttrEdgeDepressed
Definition: cc708window.cpp:95
FormattedTextSubtitle608::Init
void Init(const std::vector< CC608Text * > &buffers)
Definition: subtitlescreen.cpp:1237
FormattedTextSubtitle::Layout
virtual void Layout(void)
Definition: subtitlescreen.cpp:796
CC608Text
Definition: cc608reader.h:17
SubtitleFormat::GetBackgroundAlpha
int GetBackgroundAlpha(const QString &family)
Definition: subtitlescreen.cpp:651
LINE_SPACING
static const float LINE_SPACING
Definition: subtitlescreen.cpp:788
differentColor
static QColor differentColor(const QColor &color)
Definition: subtitlescreen.cpp:433
SubtitleFormat::IsUnlocked
bool IsUnlocked(const QString &prefix, const QString &property) const
Definition: subtitlescreen.cpp:162
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:84
SubtitleScreen::m_textFontZoom
int m_textFontZoom
Definition: subtitlescreen.h:246
SubtitleScreen::m_cc708reader
CC708Reader * m_cc708reader
Definition: subtitlescreen.h:242
DecoderBase::GetTrack
int GetTrack(uint Type)
Definition: decoderbase.cpp:957
SubtitleScreen::Pulse
void Pulse(void) override
Pulse is called 70 times a second to trigger a single frame of an animation.
Definition: subtitlescreen.cpp:1730
CC708CharacterAttribute::GetEdgeColor
QColor GetEdgeColor(void) const
Definition: cc708window.h:133
SubtitleScreen::m_textFontMinDurationMs
std::chrono::milliseconds m_textFontMinDurationMs
Definition: subtitlescreen.h:250
MythPlayer::GetVideoOutput
MythVideoOutput * GetVideoOutput(void)
Definition: mythplayer.h:167
SubWrapper
Definition: subtitlescreen.cpp:34
TextSubtitleParser
Definition: textsubtitleparser.h:90
SubtitleFormat::m_shapeMap
QHash< QString, MythUIShape * > m_shapeMap
Definition: subtitlescreen.cpp:181
MythUIImage
Image widget, displays a single image or multiple images in sequence.
Definition: mythuiimage.h:97
MythVideoOutput
Definition: mythvideoout.h:35
FormattedTextSubtitle::m_base
QString m_base
Definition: subtitlescreen.h:100
MythUIType::DeleteChild
void DeleteChild(const QString &name)
Delete a named child of this UIType.
Definition: mythuitype.cpp:148
FormattedTextSubtitleSRT::Init
void Init(const QStringList &subs)
Definition: subtitlescreen.cpp:985
CC708Service::m_windows
std::array< CC708Window, k708MaxWindows > m_windows
Definition: cc708window.h:328
SubtitleScreen::m_assLibrary
ASS_Library * m_assLibrary
Definition: subtitlescreen.h:273
FormattedTextChunk::Split
bool Split(FormattedTextChunk &newChunk)
Definition: subtitlescreen.cpp:674
FormattedTextLine
Definition: subtitlescreen.h:60
SubSimpleText::SubSimpleText
SubSimpleText(const QString &text, const MythFontProperties &font, QRect rect, Qt::Alignment align, MythUIType *parent, const QString &name, int whichImageCache, std::chrono::milliseconds expireTime)
Definition: subtitlescreen.cpp:59
MythUIImage::m_images
QHash< int, MythImage * > m_images
Definition: mythuiimage.h:170
kDisplayNone
@ kDisplayNone
Definition: videoouttypes.h:12
CC708CharacterAttribute::m_edgeType
uint m_edgeType
Definition: cc708window.h:94
CC708Window::m_lock
QRecursiveMutex m_lock
Definition: cc708window.h:317
SubtitleScreen::GetDelay
std::chrono::milliseconds GetDelay(void) const
Definition: subtitlescreen.cpp:1578
SubtitleScreen::GetTeletextBackgroundAlpha
static int GetTeletextBackgroundAlpha(void)
Definition: subtitlescreen.cpp:1706
kSubAttrOutlinecolor
static const QString kSubAttrOutlinecolor("outlinecolor")
SubtitleScreen::InitialiseAssLibrary
bool InitialiseAssLibrary(void)
Definition: subtitlescreen.cpp:2413
CC708Reader::ClearBuffers
void ClearBuffers(void)
Definition: cc708reader.cpp:41
CC708CharacterAttribute::m_penSize
uint m_penSize
Definition: cc708window.h:90
CC708Window
Definition: cc708window.h:198
SubtitleScreen::AddScaledImage
void AddScaledImage(QImage &img, QRect &pos)
Definition: subtitlescreen.cpp:2346
kSubAttrUnderline
static const QString kSubAttrUnderline("underline")
FormattedTextSubtitle::m_duration
std::chrono::milliseconds m_duration
Definition: subtitlescreen.h:104
MythPainter::GetFormatImage
MythImage * GetFormatImage()
Returns a blank reference counted image in the format required for the Draw functions for this painte...
Definition: mythpainter.cpp:534
CC708CharacterAttribute::m_fontTag
uint m_fontTag
Definition: cc708window.h:93
kTrackTypeAttachment
@ kTrackTypeAttachment
Definition: decoderbase.h:37
CC708Reader::GetCurrentService
CC708Service * GetCurrentService(void)
Definition: cc708reader.h:23
CC708Reader::SetEnabled
void SetEnabled(bool enable)
Definition: cc708reader.h:24
SubWrapper::m_swOrigArea
const MythRect m_swOrigArea
Definition: subtitlescreen.cpp:51
kSubWindowName
static const QString kSubWindowName("osd_subtitle")
MythFontProperties::GetFace
QFont * GetFace(void)
Definition: mythfontproperties.h:18
mythuisimpletext.h
FormattedTextSubtitle708::m_num
int m_num
Definition: subtitlescreen.h:171
cc
Definition: cc.h:9
DecoderBase::GetAttachmentData
virtual void GetAttachmentData(uint, QByteArray &, QByteArray &)
Definition: decoderbase.h:251
CC608Buffer::m_buffers
std::vector< CC608Text * > m_buffers
Definition: cc608reader.h:50
kSubAttrShadowoffset
static const QString kSubAttrShadowoffset("shadowoffset")
SubtitleScreen::m_assRenderer
ASS_Renderer * m_assRenderer
Definition: subtitlescreen.h:274
SubtitleScreen::DisplayCC708Subtitles
void DisplayCC708Subtitles(void)
Definition: subtitlescreen.cpp:2297
VERBOSE_LEVEL_CHECK
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
FormattedTextSubtitleSRT
Definition: subtitlescreen.h:113
SubWrapper::m_swExpireTime
const std::chrono::milliseconds m_swExpireTime
Definition: subtitlescreen.cpp:53
SubtitleScreen::DisplayScaledAVSubtitles
int DisplayScaledAVSubtitles(const AVSubtitleRect *rect, QRect &bbox, bool top, QRect &display, int forced, const QString &imagename, std::chrono::milliseconds displayuntil, std::chrono::milliseconds late)
Definition: subtitlescreen.cpp:2071
FormattedTextSubtitle::m_yAnchor
int m_yAnchor
Definition: subtitlescreen.h:109
MythFontProperties::face
QFont face(void) const
Definition: mythfontproperties.cpp:40
MythDate::formatTime
QString formatTime(std::chrono::milliseconds msecs, QString fmt)
Format a milliseconds time value.
Definition: mythdate.cpp:233
SubtitleScreen::Create
bool Create(void) override
Definition: subtitlescreen.cpp:1712
CC708CharacterAttribute
Definition: cc708window.h:87
kSubProvider
static const QString kSubProvider("provider")
MythUIType::AddFont
bool AddFont(const QString &text, MythFontProperties *fontProp)
Definition: mythuitype.cpp:1330
MythVideoFrame::m_width
int m_width
Definition: mythframe.h:121
x3
static int x3
Definition: mythsocket.cpp:52
MythUIType::SetArea
virtual void SetArea(const MythRect &rect)
Definition: mythuitype.cpp:609
MythFontProperties::hasShadow
bool hasShadow(void) const
Definition: mythfontproperties.h:29
MythPlayer::GetFrameRate
float GetFrameRate(void) const
Definition: mythplayer.h:135
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
SubtitleFormat::MakePrefix
static QString MakePrefix(const QString &family, const CC708CharacterAttribute &attr)
Definition: subtitlescreen.cpp:369
kSubFileName
static const QString kSubFileName("osd_subtitle.xml")
SubtitleFormat::~SubtitleFormat
~SubtitleFormat(void)
Definition: subtitlescreen.cpp:358
MythScreenType
Screen in which all other widgets are contained and rendered.
Definition: mythscreentype.h:45
FormattedTextSubtitle708::m_bgFillAlpha
uint m_bgFillAlpha
Definition: subtitlescreen.h:172
SubtitleScreen::DisplayAVSubtitles
void DisplayAVSubtitles(void)
Definition: subtitlescreen.cpp:1842
SubtitleScreen::m_assTrack
ASS_Track * m_assTrack
Definition: subtitlescreen.h:276
SubtitleFormat::GetBackground
SubShape * GetBackground(MythUIType *parent, const QString &name, const QString &family, const CC708CharacterAttribute &attr, const MythRect &area, int whichImageCache, std::chrono::milliseconds start, std::chrono::milliseconds duration)
Definition: subtitlescreen.cpp:613
SubtitleScreen::CleanupAssLibrary
void CleanupAssLibrary(void)
Definition: subtitlescreen.cpp:2480
MythFontProperties::SetColor
void SetColor(const QColor &color)
Definition: mythfontproperties.cpp:49
MythPlayer::GetCC708Reader
virtual CC708Reader * GetCC708Reader(uint=0)
Definition: mythplayer.h:196
CC708Window::m_anchor_vertical
uint m_anchor_vertical
Definition: cc708window.h:256
pixel
static guint32 * pixel
--------------------------------------------------—**
Definition: goom_core.cpp:24
build_compdb.parser
parser
Definition: build_compdb.py:7
FormattedTextSubtitle::m_xAnchor
int m_xAnchor
Definition: subtitlescreen.h:108
SubtitleScreen::m_refreshModified
bool m_refreshModified
Definition: subtitlescreen.h:254
MythPlayer
Definition: mythplayer.h:84
SubtitleReader::EnableAVSubtitles
void EnableAVSubtitles(bool enable)
Definition: subtitlereader.cpp:33
FormattedTextChunk::m_bgShapeRect
QRect m_bgShapeRect
Definition: subtitlescreen.h:54
FormattedTextLine::CalcSize
QSize CalcSize(float layoutSpacing=0.0F) const
Definition: subtitlescreen.cpp:763
force
bool force
Definition: mythcommflag.cpp:70
LOC
#define LOC
Definition: subtitlescreen.cpp:12
MythFontProperties::SetShadow
void SetShadow(bool on, QPoint offset, const QColor &color, int alpha)
Definition: mythfontproperties.cpp:55
SubtitleScreen::m_textFontDelayMs
std::chrono::milliseconds m_textFontDelayMs
Definition: subtitlescreen.h:248
MythRect
Wrapper around QRect allowing us to handle percentage and other relative values for areas in mythui.
Definition: mythrect.h:17
MythUIType::Pulse
virtual void Pulse(void)
Pulse is called 70 times a second to trigger a single frame of an animation.
Definition: mythuitype.cpp:455
k708AttrEdgeUniform
const uint k708AttrEdgeUniform
Definition: cc708window.cpp:96
MythVideoBounds::GetDisplayVideoRect
QRect GetDisplayVideoRect(void) const
Definition: mythvideobounds.h:77
kSubAttrShadowalpha
static const QString kSubAttrShadowalpha("shadowalpha")
FormattedTextSubtitle708
Definition: subtitlescreen.h:147
hardwareprofile.distros.mythtv_data.data_mythtv.prefix
string prefix
Definition: data_mythtv.py:40
mythuiimage.h
FormattedTextSubtitle608
Definition: subtitlescreen.h:131
SubtitleFormat::m_shadowOffsetMap
QHash< QString, QPoint > m_shadowOffsetMap
Definition: subtitlescreen.cpp:188
MythUIType::DeleteAllChildren
void DeleteAllChildren(void)
Delete all child widgets.
Definition: mythuitype.cpp:217
FormattedTextSubtitle::m_safeArea
const QRect m_safeArea
Definition: subtitlescreen.h:102
SubtitleScreen::GetZoom
int GetZoom(void) const
Definition: subtitlescreen.cpp:1568
SubtitleScreen::m_fontStretch
int m_fontStretch
Definition: subtitlescreen.h:257
PAD_WIDTH
static const float PAD_WIDTH
Definition: subtitlescreen.cpp:789
SubtitleScreen::RenderAssTrack
void RenderAssTrack(std::chrono::milliseconds timecode, bool force)
Definition: subtitlescreen.cpp:2545
SubtitleFormat::m_changeMap
QHash< QString, QSet< QString > > m_changeMap
Definition: subtitlescreen.cpp:182
SubtitleScreen::m_family
QString m_family
Definition: subtitlescreen.h:258
MythUIShape::SetFillBrush
void SetFillBrush(QBrush fill)
Definition: mythuishape.cpp:42
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
CC608Reader::GetOutputText
CC608Buffer * GetOutputText(bool &changed, int &streamIdx)
Definition: cc608reader.cpp:52
MythFontProperties::hasOutline
bool hasOutline(void) const
Definition: mythfontproperties.h:32
SubWrapper::GetExpireTime
std::chrono::milliseconds GetExpireTime(void) const
Definition: subtitlescreen.cpp:46
SubtitleScreen::m_refreshDeleted
bool m_refreshDeleted
Definition: subtitlescreen.h:255
SubtitleReader::ClearAVSubtitles
void ClearAVSubtitles(void)
Definition: subtitlereader.cpp:135
MythUIType::AddChild
void AddChild(MythUIType *child)
Add a child UIType.
Definition: mythuitype.cpp:88
SubtitleScreen::~SubtitleScreen
~SubtitleScreen() override
Definition: subtitlescreen.cpp:1396
SubImage::GetImage
MythImage * GetImage(void)
Definition: subtitlescreen.cpp:83
SubtitleFormat::SubtitleFormat
SubtitleFormat(void)=default
CC708Window::GetVisible
bool GetVisible(void) const
Definition: cc708window.h:292
SubtitleFormat::Diff
static QSet< QString > Diff(const QString &family, const CC708CharacterAttribute &attr, MythFontProperties *font1, MythFontProperties *font2, MythUIShape *bg1, MythUIShape *bg2)
Definition: subtitlescreen.cpp:542
CC708CharacterAttribute::m_boldface
bool m_boldface
Definition: cc708window.h:97
kDisplayCC708
@ kDisplayCC708
Definition: videoouttypes.h:17
SubtitleScreen::DisplayCC608Subtitles
void DisplayCC608Subtitles(void)
Definition: subtitlescreen.cpp:2266
SubtitleScreen::m_textFontDelayMsPrev
std::chrono::milliseconds m_textFontDelayMsPrev
Definition: subtitlescreen.h:249
DecoderBase::GetTrackCount
virtual uint GetTrackCount(uint Type)
Definition: decoderbase.cpp:909
CC708Window::m_relative_pos
uint m_relative_pos
Definition: cc708window.h:255
FormattedTextChunk::CalcPadding
void CalcPadding(bool isFirst, bool isLast, int &left, int &right) const
Definition: subtitlescreen.cpp:668
srtColorString
static QString srtColorString(const QColor &color)
Definition: subtitlescreen.cpp:216
mythfontproperties.h
FormattedTextChunk
Definition: subtitlescreen.h:32
mythlogging.h
kSubFamilyText
static const QString kSubFamilyText("text")
subtitlescreen.h
CC708CharacterAttribute::GetFGColor
QColor GetFGColor(void) const
Definition: cc708window.h:120
SubtitleReader::ReadNextSubtitle
int ReadNextSubtitle(void)
Definition: subtitlereader.cpp:162
SubtitleScreen::LoadAssFonts
void LoadAssFonts(void)
Definition: subtitlescreen.cpp:2455
SubtitleScreen::ResetElementState
void ResetElementState(void)
Definition: subtitlescreen.cpp:1801
SubtitleScreen::CalcTextSize
QSize CalcTextSize(const QString &text, const CC708CharacterAttribute &format, float layoutSpacing) const
Definition: subtitlescreen.cpp:1658
kSubFamilyTeletext
static const QString kSubFamilyTeletext("teletext")
MythVideoFrame::m_timecode
std::chrono::milliseconds m_timecode
Definition: mythframe.h:131
SubtitleScreen::SetDelay
void SetDelay(std::chrono::milliseconds ms)
Definition: subtitlescreen.cpp:1573
SubtitleScreen::GetTeletextFontName
static QString GetTeletextFontName(void)
Definition: subtitlescreen.cpp:1696
SubtitleReader::EnableTextSubtitles
void EnableTextSubtitles(bool enable)
Definition: subtitlereader.cpp:38
SubtitleScreen::Clear708Cache
void Clear708Cache(uint64_t mask)
Definition: subtitlescreen.cpp:1583
CC708Service
Definition: cc708window.h:321
SubtitleScreen::EnableSubtitles
void EnableSubtitles(int type, bool forced_only=false)
Definition: subtitlescreen.cpp:1405
SubtitleScreen::m_qInited
QList< FormattedTextSubtitle * > m_qInited
Definition: subtitlescreen.h:260
MythFontProperties
Definition: mythfontproperties.h:13
CC608Buffer
Definition: cc608reader.h:36
CC708CharacterAttribute::GetFGAlpha
uint GetFGAlpha(void) const
Definition: cc708window.h:135
k708AttrEdgeLeftDropShadow
const uint k708AttrEdgeLeftDropShadow
Definition: cc708window.cpp:97
SubShape::SubShape
SubShape(MythUIType *parent, const QString &name, const MythRect &area, int whichImageCache, std::chrono::milliseconds expireTime)
Definition: subtitlescreen.cpp:70
kSubAttrShadow
static const QString kSubAttrShadow("shadow")
FormattedTextSubtitle::m_xAnchorPoint
int m_xAnchorPoint
Definition: subtitlescreen.h:106
MythPlayer::GetCC608Reader
virtual CC608Reader * GetCC608Reader(uint=0)
Definition: mythplayer.h:197
SubtitleScreen::m_fontSize
int m_fontSize
Definition: subtitlescreen.h:245
FormattedTextSubtitleSRT::WrapLongLines
void WrapLongLines(void) override
Definition: subtitlescreen.cpp:1091
SubtitleScreen::DrawTextSubtitles
void DrawTextSubtitles(const QStringList &subs, std::chrono::milliseconds start, std::chrono::milliseconds duration)
Definition: subtitlescreen.cpp:2257
FormattedTextChunk::m_parent
const SubtitleScreen * m_parent
Definition: subtitlescreen.h:50
PAD_HEIGHT
static const float PAD_HEIGHT
Definition: subtitlescreen.cpp:790
AVSubtitles
Definition: subtitlereader.h:22
MythVideoOutput::GetImageRect
QRect GetImageRect(QRect Rect, QRect *DisplayRect=nullptr)
translates caption/dvd button rectangle into 'screen' space
Definition: mythvideoout.cpp:322
MythPoint::setY
void setY(const QString &sY)
Definition: mythrect.cpp:540
SubtitleReader::SeekFrame
void SeekFrame(int64_t ts, int flags)
Definition: subtitlereader.cpp:48
MythFontProperties::color
QColor color(void) const
Definition: mythfontproperties.h:26
MythImage::DecrRef
int DecrRef(void) override
Decrements reference count and deletes on 0.
Definition: mythimage.cpp:52
SubtitleReader::ClearRawTextSubtitles
void ClearRawTextSubtitles(void)
Definition: subtitlereader.cpp:198
SubtitleScreen::CleanupAssTrack
void CleanupAssTrack(void)
Definition: subtitlescreen.cpp:2524
SubtitleScreen::ClearDisplayedSubtitles
void ClearDisplayedSubtitles(void)
Definition: subtitlescreen.cpp:1494
SubtitleScreen::ResizeAssRenderer
void ResizeAssRenderer(void)
Definition: subtitlescreen.cpp:2537
MythUIType::m_childrenList
QList< MythUIType * > m_childrenList
Definition: mythuitype.h:253
SubtitleReader::FreeAVSubtitle
static void FreeAVSubtitle(AVSubtitle &sub)
Definition: subtitlereader.cpp:146
MythFontProperties::GetOutline
void GetOutline(QColor &color, int &size, int &alpha) const
Definition: mythfontproperties.cpp:82
SubtitleScreen::m_textFontDurationExtensionMs
std::chrono::milliseconds m_textFontDurationExtensionMs
Definition: subtitlescreen.h:252
SubtitleFormat::m_pixelSizeMap
QHash< QString, int > m_pixelSizeMap
Definition: subtitlescreen.cpp:186
SubtitleScreen::DisplayDVDButton
void DisplayDVDButton(AVSubtitle *dvdButton, QRect &buttonPos)
Definition: subtitlescreen.cpp:1500
SubtitleFormat::Load
void Load(const QString &family, const CC708CharacterAttribute &attr)
Definition: subtitlescreen.cpp:470
FormattedTextChunk::m_textFont
MythFontProperties * m_textFont
Definition: subtitlescreen.h:55
SubtitleFormat::CreateProviderDefault
static void CreateProviderDefault(const QString &family, const CC708CharacterAttribute &attr, MythUIType *parent, bool isComplement, MythFontProperties **font, MythUIShape **bg)
Definition: subtitlescreen.cpp:377
SubtitleFormat::GetFont
MythFontProperties * GetFont(const QString &family, const CC708CharacterAttribute &attr, int pixelSize, int zoom, int stretch)
Definition: subtitlescreen.cpp:257
mythpainter.h
FormattedTextSubtitle608::Layout
void Layout(void) override
Definition: subtitlescreen.cpp:1190
kDisplayRawTextSubtitle
@ kDisplayRawTextSubtitle
Definition: videoouttypes.h:20
SubShape
Definition: subtitlescreen.cpp:67
SubtitleReader::EnableRawTextSubtitles
void EnableRawTextSubtitles(bool enable)
Definition: subtitlereader.cpp:43
MythPoint::NormPoint
void NormPoint(void)
Definition: mythrect.cpp:471
FormattedTextChunk::m_textRect
QRect m_textRect
Definition: subtitlescreen.h:57
kSubFamilyAV
static const QString kSubFamilyAV("AV")
uint
unsigned int uint
Definition: compat.h:81
SubtitleScreen::m_assTrackNum
int m_assTrackNum
Definition: subtitlescreen.h:275
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
SubtitleScreen::m_textFontZoomPrev
int m_textFontZoomPrev
Definition: subtitlescreen.h:247
SubtitleScreen::DisableForcedSubtitles
void DisableForcedSubtitles(void)
Definition: subtitlescreen.cpp:1463
SubtitleScreen::SetZoom
void SetZoom(int percent)
Definition: subtitlescreen.cpp:1559
FormattedTextSubtitle708::Draw
void Draw(void) override
Definition: subtitlescreen.cpp:1325
k708AttrSizeLarge
const uint k708AttrSizeLarge
Definition: cc708window.cpp:78
CC708CharacterAttribute::GetBGColor
QColor GetBGColor(void) const
Definition: cc708window.h:127
CC708CharacterAttribute::GetBGAlpha
uint GetBGAlpha(void) const
Definition: cc708window.h:142
SubtitleReader::GetRawTextSubtitles
QStringList GetRawTextSubtitles(std::chrono::milliseconds &duration)
Definition: subtitlereader.cpp:175
myth_libass_log
static void myth_libass_log(int level, const char *fmt, va_list vl, void *)
Definition: subtitlescreen.cpp:2375
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:911
SubtitleScreen::SetElementDeleted
void SetElementDeleted(void)
Definition: subtitlescreen.cpp:1619
MythFontProperties::GetShadow
void GetShadow(QPoint &offset, QColor &color, int &alpha) const
Definition: mythfontproperties.cpp:75
MythPlayer::GetDecoder
DecoderBase * GetDecoder(void)
Returns the stream decoder currently in use.
Definition: mythplayer.h:187
kTrackTypeSubtitle
@ kTrackTypeSubtitle
Definition: decoderbase.h:31
kSubAttrBGfill
static const QString kSubAttrBGfill("bgfill")
FormattedTextChunk::m_textName
QString m_textName
Definition: subtitlescreen.h:56
FormattedTextChunk::m_text
QString m_text
Definition: subtitlescreen.h:48
DecoderBase::GetSubHeader
virtual QByteArray GetSubHeader(uint)
Definition: decoderbase.h:250
MythPlayer::GetSubReader
virtual SubtitleReader * GetSubReader(uint=0)
Definition: mythplayer.h:198
kSubAttrItalics
static const QString kSubAttrItalics("italics")
AVSubtitles::m_needSync
bool m_needSync
Definition: subtitlereader.h:29
MythUIType
The base class on which all widgets and screens are based.
Definition: mythuitype.h:85
kSubAttrBold
static const QString kSubAttrBold("bold")
MythUIShape
A widget for rendering primitive shapes and lines.
Definition: mythuishape.h:21
FormattedTextSubtitle::m_lines
QVector< FormattedTextLine > m_lines
Definition: subtitlescreen.h:101
k708MaxWindows
const int k708MaxWindows
Definition: cc708window.h:76
SubtitleReader::GetAVSubtitles
AVSubtitles * GetAVSubtitles(void)
Definition: subtitlereader.h:57
SubtitleFormat::m_cleanup
QVector< MythUIType * > m_cleanup
Definition: subtitlescreen.cpp:189
k708AttrSizeSmall
const uint k708AttrSizeSmall
Definition: cc708window.cpp:76
buffers
Definition: freesurround.cpp:50
prevY
unsigned int prevY
Definition: filters.cpp:110
CalcShadowOffsetPadding
static QSize CalcShadowOffsetPadding(MythFontProperties *mythfont)
Definition: subtitlescreen.cpp:1630
SubtitleScreen::AddAssEvent
void AddAssEvent(char *event, uint32_t starttime, uint32_t endtime)
Definition: subtitlescreen.cpp:2531
FormattedTextSubtitle708::m_bgFillColor
QColor m_bgFillColor
Definition: subtitlescreen.h:173
kSubAttrPixelsize
static const QString kSubAttrPixelsize("pixelsize")
k708AttrEdgeRightDropShadow
const uint k708AttrEdgeRightDropShadow
Definition: cc708window.cpp:98
MythFontProperties::SetOutline
void SetOutline(bool on, const QColor &color, int size, int alpha)
Definition: mythfontproperties.cpp:65
FormattedTextChunk::CalcSize
QSize CalcSize(float layoutSpacing=0.0F) const
Definition: subtitlescreen.cpp:663
k708AttrEdgeRaised
const uint k708AttrEdgeRaised
Definition: cc708window.cpp:94
CC708Window::GetChanged
bool GetChanged(void) const
Definition: cc708window.h:293
SubtitleFormat::m_outlineSizeMap
QHash< QString, int > m_outlineSizeMap
Definition: subtitlescreen.cpp:187
AVSubtitles::m_buffers
MythDeque< AVSubtitle > m_buffers
Definition: subtitlereader.h:26
FormattedTextChunk::ToLogString
QString ToLogString(void) const
Definition: subtitlescreen.cpp:694
SubtitleScreen::ClearNonDisplayedSubtitles
void ClearNonDisplayedSubtitles(void)
Definition: subtitlescreen.cpp:1482
SubtitleScreen::InitialiseAssTrack
void InitialiseAssTrack(int tracknum)
Definition: subtitlescreen.cpp:2497
XMLParseBase::LoadWindowFromXML
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
Definition: xmlparsebase.cpp:695
MythPainter
Definition: mythpainter.h:34
SubtitleScreen::GetSubtitleFormat
class SubtitleFormat * GetSubtitleFormat(void)
Definition: subtitlescreen.h:197
MythImage
Definition: mythimage.h:36
fontToString
static QString fontToString(MythFontProperties *f)
Definition: subtitlescreen.cpp:224
SubtitleScreen::m_format
class SubtitleFormat * m_format
Definition: subtitlescreen.h:261
SubtitleFormat::Complement
static void Complement(MythFontProperties *font, MythUIShape *bg)
Definition: subtitlescreen.cpp:440
Name
Definition: channelsettings.cpp:71
SubtitleFormat::m_fontMap
QHash< QString, MythFontProperties * > m_fontMap
Definition: subtitlescreen.cpp:180
AVSubtitles::m_fixPosition
bool m_fixPosition
Definition: subtitlereader.h:28
SubtitleReader::GetParser
TextSubtitleParser * GetParser(void)
Definition: subtitlereader.h:63
kSubAttrOutline
static const QString kSubAttrOutline("outline")
SubtitleScreen::m_atEnd
bool m_atEnd
Definition: subtitlescreen.h:256
FormattedTextSubtitle708::Init
void Init(const CC708Window &win, const std::vector< CC708String * > &list, float aspect)
Definition: subtitlescreen.cpp:1342
SubtitleScreen::m_assFontCount
uint m_assFontCount
Definition: subtitlescreen.h:277
MythUIShape::m_fillBrush
QBrush m_fillBrush
Definition: mythuishape.h:42
SubtitleScreen::SetElementResized
void SetElementResized(void)
Definition: subtitlescreen.cpp:1612
MythPlayer::GetVideoAspect
float GetVideoAspect(void) const
Definition: mythplayer.h:134
FormattedTextSubtitle::PreRender
virtual void PreRender(void)
Definition: subtitlescreen.cpp:864
FormattedTextChunk::m_bgShapeName
QString m_bgShapeName
Definition: subtitlescreen.h:53
FormattedTextChunk::m_format
CC708CharacterAttribute m_format
Definition: subtitlescreen.h:49
CC708Window::GetStrings
std::vector< CC708String * > GetStrings(void) const
Definition: cc708window.cpp:284
CC708Window::DisposeStrings
static void DisposeStrings(std::vector< CC708String * > &strings)
Definition: cc708window.cpp:376
SubtitleScreen::OptimiseDisplayedArea
void OptimiseDisplayedArea(void)
Definition: subtitlescreen.cpp:1807
kDisplayCC608
@ kDisplayCC608
Definition: videoouttypes.h:16
MythVideoOutput::GetSafeRect
QRect GetSafeRect()
Returns a QRect describing an area of the screen on which it is 'safe' to render the On Screen Displa...
Definition: mythvideoout.cpp:376
AVSubtitles::m_lock
QMutex m_lock
Definition: subtitlereader.h:27
SubtitleScreen::SetElementAdded
void SetElementAdded(void)
Definition: subtitlescreen.cpp:1605
MythUIType::SetVisible
virtual void SetVisible(bool visible)
Definition: mythuitype.cpp:1108
SubWrapper::GetOrigArea
MythRect GetOrigArea(void) const
Definition: subtitlescreen.cpp:47
MythUIType::m_painter
MythPainter * m_painter
Definition: mythuitype.h:295
CC708CharacterAttribute::m_offset
uint m_offset
Definition: cc708window.h:91
SubSimpleText
Definition: subtitlescreen.cpp:56
FormattedTextSubtitle::m_subScreen
SubtitleScreen * m_subScreen
Definition: subtitlescreen.h:105
CC708Window::ResetChanged
void ResetChanged(void)
Definition: cc708window.h:310
FormattedTextSubtitle::ToSRT
QStringList ToSRT(void) const
Definition: subtitlescreen.cpp:938
SubtitleScreen::m_subtitleType
int m_subtitleType
Definition: subtitlescreen.h:244
MythVideoFrame::m_height
int m_height
Definition: mythframe.h:122
SubtitleScreen::SubtitleScreen
SubtitleScreen(MythPlayer *Player, MythPainter *Painter, const QString &Name, int FontStretch)
Definition: subtitlescreen.cpp:1380
MythUIImage::SetImage
void SetImage(MythImage *img)
Should not be used unless absolutely necessary since it bypasses the image caching and threaded loade...
Definition: mythuiimage.cpp:746
SubtitleScreen::m_textFontMinDurationMsPrev
std::chrono::milliseconds m_textFontMinDurationMsPrev
Definition: subtitlescreen.h:251
FormattedTextSubtitle::m_yAnchorPoint
int m_yAnchorPoint
Definition: subtitlescreen.h:107
kSubAttrColor
static const QString kSubAttrColor("color")
k708AttrFontSmallCaps
const uint k708AttrFontSmallCaps
Definition: cc708window.cpp:91
FormattedTextSubtitle::m_start
std::chrono::milliseconds m_start
Definition: subtitlescreen.h:103
SubtitleScreen::m_safeArea
QRect m_safeArea
Definition: subtitlescreen.h:243
CC608Reader::ClearBuffers
void ClearBuffers(bool input, bool output, int outputStreamIdx=-1)
Definition: cc608reader.cpp:447
SubtitleScreen::m_cc608reader
CC608Reader * m_cc608reader
Definition: subtitlescreen.h:241
CC708Window::m_anchor_point
uint m_anchor_point
Definition: cc708window.h:254
CC708CharacterAttribute::m_italics
bool m_italics
Definition: cc708window.h:96
CC608Reader::SetEnabled
void SetEnabled(bool enable)
Definition: cc608reader.h:85
SubtitleScreen::m_subreader
SubtitleReader * m_subreader
Definition: subtitlescreen.h:240
Player
Definition: zmliveplayer.h:34
MythPoint::setX
void setX(const QString &sX)
Definition: mythrect.cpp:530
MythVideoFrame
Definition: mythframe.h:88
MythUISimpleText
Simplified text widget, displays a text string.
Definition: mythuisimpletext.h:22
MythCoreContext::SaveSetting
void SaveSetting(const QString &key, int newValue)
Definition: mythcorecontext.cpp:880
MythImage::Assign
void Assign(const QImage &img)
Definition: mythimage.cpp:77
FormattedTextChunk::PreRender
bool PreRender(bool isFirst, bool isLast, int &x, int y, int height)
Definition: subtitlescreen.cpp:718
kDisplayAVSubtitle
@ kDisplayAVSubtitle
Definition: videoouttypes.h:15
SubtitleFormat
Definition: subtitlescreen.cpp:141
SubWrapper::m_swWhichImageCache
const int m_swWhichImageCache
Definition: subtitlescreen.cpp:52
SubtitleScreen::m_player
MythPlayer * m_player
Definition: subtitlescreen.h:239
MythVideoOutput::GetLastShownFrame
virtual MythVideoFrame * GetLastShownFrame()
Returns frame from the head of the ready to be displayed queue, if StartDisplayingFrame has been call...
Definition: mythvideoout.cpp:316
build_compdb.filename
filename
Definition: build_compdb.py:21
kDisplayTextSubtitle
@ kDisplayTextSubtitle
Definition: videoouttypes.h:18
SubWrapper::GetWhichImageCache
int GetWhichImageCache(void) const
Definition: subtitlescreen.cpp:48
SubtitleScreen::CalcPadding
void CalcPadding(const CC708CharacterAttribute &format, bool isFirst, bool isLast, int &left, int &right) const
Definition: subtitlescreen.cpp:1676
MythUIType::SetRedraw
void SetRedraw(void)
Definition: mythuitype.cpp:308
SubWrapper::SubWrapper
SubWrapper(const MythRect &rect, std::chrono::milliseconds expireTime, int whichImageCache=-1)
Definition: subtitlescreen.cpp:37
kSubFamily608
static const QString kSubFamily608("608")
MythUIType::IsVisible
bool IsVisible(bool recurse=false) const
Definition: mythuitype.cpp:902
SubtitleScreen::SetFontSize
void SetFontSize(int pixelSize)
Definition: subtitlescreen.h:210
SubtitleScreen::GetFont
MythFontProperties * GetFont(const CC708CharacterAttribute &attr) const
Definition: subtitlescreen.cpp:1690
kSubFamily708
static const QString kSubFamily708("708")
FormattedTextLine::chunks
QList< FormattedTextChunk > chunks
Definition: subtitlescreen.h:68
SubImage
Definition: subtitlescreen.cpp:76
MythPlayer::SeekingDone
void SeekingDone()
CC708Window::m_anchor_horizontal
uint m_anchor_horizontal
Definition: cc708window.h:257
kSubAttrOutlinesize
static const QString kSubAttrOutlinesize("outlinesize")
mythuishape.h
FormattedTextSubtitle::Draw
virtual void Draw(void)
Definition: subtitlescreen.cpp:888
FormattedTextSubtitle::m_bounds
QRect m_bounds
Definition: subtitlescreen.h:110
FormattedTextSubtitle::WrapLongLines
virtual void WrapLongLines(void)
Definition: subtitlescreen.h:91
SubtitleScreen::m_textFontDurationExtensionMsPrev
std::chrono::milliseconds m_textFontDurationExtensionMsPrev
Definition: subtitlescreen.h:253
SubtitleScreen::ClearAllSubtitles
void ClearAllSubtitles(void)
Definition: subtitlescreen.cpp:1472
CC708CharacterAttribute::m_underline
bool m_underline
Definition: cc708window.h:95
extract_cc608
static QString extract_cc608(QString &text, int &color, bool &isItalic, bool &isUnderline)
Extract everything from the text buffer up until the next format control character.
Definition: subtitlescreen.cpp:1136
MythPoint
Wrapper around QPoint allowing us to handle percentage and other relative values for positioning in m...
Definition: mythrect.h:88
CC708Window::GetExists
bool GetExists(void) const
Definition: cc708window.h:291