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