MythTV  master
mhi.cpp
Go to the documentation of this file.
1 #include "mhi.h"
2 
3 #include <QRegion>
4 #include <QVector>
5 #include <QUrl>
6 #include <QPoint> // for QPoint
7 #include <QRgb> // for QRgb
8 #include <QVariant> // for QVariant
9 #include <QByteArray> // for QByteArray
10 #include <QStringList> // for QStringList
11 #include <QTime> // for QTime
12 #include <QHash> // for QHash
13 
14 #include <algorithm> // for min
15 #include <cmath> // for round, sqrt
16 #include <cstdint> // for uint8_t
17 #include <cstring> // for memcpy, memset
18 #include <deque> // for _Deque_iterator, operator!=
19 
20 #include "dsmcc.h" // for Dsmcc
21 #include "interactivetv.h" // for InteractiveTV
22 #include "interactivescreen.h"
23 #include "mythpainter.h"
24 #include "mythimage.h"
25 #include "mythuiimage.h"
26 #include "mythdirs.h"
27 #include "mythlogging.h"
28 #include "mythmainwindow.h"
29 #include "mythavutil.h"
30 #include "mthread.h" // for MThread
31 #include "mythcorecontext.h" // for MythCoreContext, etc
32 #include "mythdb.h" // for MythDB
33 #include "mythdbcon.h" // for MSqlQuery
34 #include "mythevent.h" // for MythEvent
35 #include "mythplayerui.h"
36 #include "mythrect.h" // for MythRect
37 #include "mythuiactions.h" // for ACTION_0, ACTION_1, etc
38 #include "tv_actions.h" // for ACTION_MENUTEXT, etc
39 
40 extern "C" {
41 #include "libavutil/imgutils.h"
42 }
43 
44 static bool ft_loaded = false;
45 static FT_Library ft_library;
46 
47 #define FONT_WIDTHRES 54
48 #define FONT_HEIGHTRES 72 // 1 pixel per point
49 #define FONT_TO_USE "FreeSans.ttf" // Tiresias Screenfont.ttf is mandated
50 
51 
52 // LifecycleExtension tuneinfo:
53 const unsigned kTuneQuietly = 1U<<0; // b0 tune quietly
54 const unsigned kTuneKeepApp = 1U<<1; // b1 keep app running
55 const unsigned kTuneCarId = 1U<<2; // b2 carousel id in bits 8..16
56 const unsigned kTuneCarReset = 1U<<3; // b3 get carousel id from gateway info
57 //const unsigned kTuneBcastDisa = 1U<<4; // b4 broadcaster_interrupt disable
58 // b5..7 reserverd
59 // b8..15 carousel id
60 const unsigned kTuneKeepChnl = 1U<<16; // Keep current channel
61 // b17..31 reserved
62 
67 {
68  public:
69  QImage m_image;
70  int m_x {0};
71  int m_y {0};
72  bool m_bUnder {false};
73 };
74 
76  : m_parent(parent), m_dsmcc(new Dsmcc()),
77  m_engine(MHCreateEngine(this))
78 {
79  if (!ft_loaded)
80  {
81  FT_Error error = FT_Init_FreeType(&ft_library);
82  if (!error)
83  ft_loaded = true;
84  }
85 
86  if (ft_loaded)
87  {
88  // TODO: We need bold and italic versions.
89  if (LoadFont(FONT_TO_USE))
90  m_faceLoaded = true;
91  }
92 }
93 
94 // Load the font. Copied, generally, from OSD::LoadFont.
95 bool MHIContext::LoadFont(const QString& name)
96 {
97  QString fullnameA = GetConfDir() + "/" + name;
98  QByteArray fnameA = fullnameA.toLatin1();
99  FT_Error errorA = FT_New_Face(ft_library, fnameA.constData(), 0, &m_face);
100  if (!errorA)
101  return true;
102 
103  QString fullnameB = GetFontsDir() + name;
104  QByteArray fnameB = fullnameB.toLatin1();
105  FT_Error errorB = FT_New_Face(ft_library, fnameB.constData(), 0, &m_face);
106  if (!errorB)
107  return true;
108 
109  QString fullnameC = GetShareDir() + "themes/" + name;
110  QByteArray fnameC = fullnameC.toLatin1();
111  FT_Error errorC = FT_New_Face(ft_library, fnameC.constData(), 0, &m_face);
112  if (!errorC)
113  return true;
114 
115  const QString& fullnameD = name;
116  QByteArray fnameD = fullnameD.toLatin1();
117  FT_Error errorD = FT_New_Face(ft_library, fnameD.constData(), 0, &m_face);
118  if (!errorD)
119  return true;
120 
121  LOG(VB_GENERAL, LOG_ERR, QString("[mhi] Unable to find font: %1").arg(name));
122  return false;
123 }
124 
126 {
127  StopEngine();
128  delete(m_engine);
129  delete(m_dsmcc);
130  if (m_faceLoaded) FT_Done_Face(m_face);
131 
132  ClearDisplay();
133  ClearQueue();
134 }
135 
136 // NB caller must hold m_display_lock
138 {
139  for (auto & it : m_display)
140  delete it;
141  m_display.clear();
142  m_videoDisplayRect = QRect();
143 }
144 
145 // NB caller must hold m_dsmccLock
147 {
148  for (auto & it : m_dsmccQueue)
149  delete it;
150  m_dsmccQueue.clear();
151 }
152 
153 // Ask the engine to stop and block until it has.
155 {
156  if (nullptr == m_engineThread)
157  return;
158 
159  m_stop = true;
160  m_runLock.lock();
161  m_engineWait.wakeAll();
162  m_runLock.unlock();
163 
164  m_engineThread->wait();
165  delete m_engineThread;
166  m_engineThread = nullptr;
167 }
168 
169 
170 // Start or restart the MHEG engine.
171 void MHIContext::Restart(int chanid, int sourceid, bool isLive)
172 {
173  int tuneinfo = m_tuneInfo.isEmpty() ? 0 : m_tuneInfo.takeFirst();
174 
175  LOG(VB_MHEG, LOG_INFO,
176  QString("[mhi] Restart ch=%1 source=%2 live=%3 tuneinfo=0x%4")
177  .arg(chanid).arg(sourceid).arg(isLive).arg(tuneinfo,0,16));
178 
179  if (m_currentSource != sourceid)
180  {
181  m_currentSource = sourceid;
182  QMutexLocker locker(&m_channelMutex);
183  m_channelCache.clear();
184  }
185  m_currentStream = (chanid) ? chanid : -1;
186  if (!(tuneinfo & kTuneKeepChnl))
188 
189  if (tuneinfo & kTuneKeepApp)
190  {
191  // We have tuned to the channel in order to find the streams.
192  // Leave the MHEG engine running but restart the DSMCC carousel.
193  // This is a bit of a mess but it's the only way to be able to
194  // select streams from a different channel.
195  {
196  QMutexLocker locker(&m_dsmccLock);
197  if (tuneinfo & kTuneCarReset)
198  m_dsmcc->Reset();
199  ClearQueue();
200  }
201 
202  if (tuneinfo & (kTuneCarReset|kTuneCarId))
203  {
204  QMutexLocker locker(&m_runLock);
205  m_engine->EngineEvent(10); // NonDestructiveTuneOK
206  }
207  }
208  else
209  {
210  StopEngine();
211 
212  m_audioTag = -1;
213  m_videoTag = -1;
214 
215  {
216  QMutexLocker locker(&m_dsmccLock);
217  m_dsmcc->Reset();
218  ClearQueue();
219  }
220 
221  {
222  QMutexLocker locker(&m_keyLock);
223  m_keyQueue.clear();
224  }
225 
226  m_engine->SetBooting();
227  ClearDisplay();
228  m_updated = true;
229  m_stop = false;
230  m_isLive = isLive;
231  // Don't set the NBI version here. Restart is called
232  // after the PMT is processed.
233  m_engineThread = new MThread("MHEG", this);
235  }
236 }
237 
238 void MHIContext::run(void)
239 {
240  QMutexLocker locker(&m_runLock);
241 
242  while (!m_stop)
243  {
244  std::chrono::milliseconds toWait = 0ms;
245  // Dequeue and process any key presses.
246  int key = 0;
247  do
248  {
251  {
252  QMutexLocker locker2(&m_keyLock);
253  key = m_keyQueue.dequeue();
254  }
255 
256  if (key != 0)
258 
259  // Run the engine and find out how long to pause.
260  toWait = m_engine->RunAll();
261  if (toWait < 0ms)
262  return;
263  } while (key != 0);
264 
265  toWait = (toWait > 1s || toWait <= 0ms) ? 1s : toWait;
266 
267  if (!m_stop && (toWait > 0ms))
268  m_engineWait.wait(locker.mutex(), toWait.count());
269  }
270 }
271 
272 // Dequeue and process any DSMCC packets.
274 {
275  DSMCCPacket *packet = nullptr;
276  do
277  {
278  QMutexLocker locker(&m_dsmccLock);
279  packet = m_dsmccQueue.dequeue();
280  if (packet)
281  {
283  packet->m_data, packet->m_length,
284  packet->m_componentTag, packet->m_carouselId,
285  packet->m_dataBroadcastId);
286 
287  delete packet;
288  }
289  } while (packet);
290 }
291 
293  unsigned char *data, int length, int componentTag,
294  unsigned carouselId, int dataBroadcastId)
295 {
296  auto *dataCopy = (unsigned char*) malloc(length * sizeof(unsigned char));
297 
298  if (dataCopy == nullptr)
299  return;
300 
301  memcpy(dataCopy, data, length*sizeof(unsigned char));
302  {
303  QMutexLocker locker(&m_dsmccLock);
304  m_dsmccQueue.enqueue(new DSMCCPacket(dataCopy, length,
305  componentTag, carouselId,
306  dataBroadcastId));
307  }
308  m_engineWait.wakeAll();
309 }
310 
311 // A NetworkBootInfo sub-descriptor is present in the PMT.
312 void MHIContext::SetNetBootInfo(const unsigned char *data, uint length)
313 {
314  if (length < 2) // A valid descriptor should always have at least 2 bytes.
315  return;
316 
317  LOG(VB_MHEG, LOG_INFO, QString("[mhi] SetNetBootInfo version %1 mode %2 len %3")
318  .arg(data[0]).arg(data[1]).arg(length));
319 
320  QMutexLocker locker(&m_dsmccLock);
321  // The carousel should be reset now as the stream has changed
322  m_dsmcc->Reset();
323  ClearQueue();
324  // Save the data from the descriptor.
325  m_nbiData.resize(0);
326  m_nbiData.reserve(length);
327  m_nbiData.insert(m_nbiData.begin(), data, data+length);
328  // If there is no Network Boot Info or we're setting it
329  // for the first time just update the "last version".
331  m_lastNbiVersion = data[0];
332  else
333  m_engineWait.wakeAll();
334 }
335 
336 // Called only by m_engineThread
338 {
339  QMutexLocker locker(&m_dsmccLock);
340  if (m_nbiData.size() >= 2 && m_nbiData[0] != m_lastNbiVersion)
341  {
342  m_lastNbiVersion = m_nbiData[0]; // Update the saved version
343  switch (m_nbiData[1])
344  {
345  case 1:
346  m_dsmcc->Reset();
347  m_engine->SetBooting();
348  locker.unlock();
349  {QMutexLocker locker2(&m_displayLock);
350  ClearDisplay();
351  m_updated = true;}
352  break;
353  case 2:
354  m_engine->EngineEvent(9); // NetworkBootInfo EngineEvent
355  break;
356  default:
357  LOG(VB_MHEG, LOG_INFO, QString("[mhi] Unknown NetworkBoot type %1")
358  .arg(m_nbiData[1]));
359  break;
360  }
361  }
362 }
363 
364 // Called by the engine to check for the presence of an object in the carousel.
365 bool MHIContext::CheckCarouselObject(const QString& objectPath)
366 {
367  if (objectPath.startsWith("http:") || objectPath.startsWith("https:"))
368  {
369  QByteArray cert;
370 
371  // Verify access to server
372  if (!CheckAccess(objectPath, cert))
373  return false;
374 
375  return m_ic.CheckFile(objectPath, cert);
376  }
377 
378 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
379  QStringList path = objectPath.split(QChar('/'), QString::SkipEmptyParts);
380 #else
381  QStringList path = objectPath.split(QChar('/'), Qt::SkipEmptyParts);
382 #endif
383  QByteArray result; // Unused
384  QMutexLocker locker(&m_dsmccLock);
385  int res = m_dsmcc->GetDSMCCObject(path, result);
386  return res == 0; // It's available now.
387 }
388 
389 bool MHIContext::GetDSMCCObject(const QString &objectPath, QByteArray &result)
390 {
391 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
392  QStringList path = objectPath.split(QChar('/'), QString::SkipEmptyParts);
393 #else
394  QStringList path = objectPath.split(QChar('/'), Qt::SkipEmptyParts);
395 #endif
396  QMutexLocker locker(&m_dsmccLock);
397  int res = m_dsmcc->GetDSMCCObject(path, result);
398  return (res == 0);
399 }
400 
401 bool MHIContext::CheckAccess(const QString &objectPath, QByteArray &cert)
402 {
403  cert.clear();
404 
405  // Verify access to server
406  QByteArray servers;
407  if (!GetDSMCCObject("/auth.servers", servers))
408  {
409  LOG(VB_MHEG, LOG_INFO, QString(
410  "[mhi] CheckAccess(%1) No auth.servers").arg(objectPath) );
411  return false;
412  }
413 
414  QByteArray host = QUrl(objectPath).host().toLocal8Bit();
415  if (!servers.contains(host))
416  {
417  LOG(VB_MHEG, LOG_INFO, QString("[mhi] CheckAccess(%1) Host not known")
418  .arg(objectPath) );
419  LOG(VB_MHEG, LOG_DEBUG, QString("[mhi] Permitted servers: %1")
420  .arg(servers.constData()) );
421 
422  // BUG: https://securegate.iplayer.bbc.co.uk is not listed
423  if (!objectPath.startsWith("https:"))
424  return false;
425  }
426 
427  if (!objectPath.startsWith("https:"))
428  return true;
429 
430  // Use TLS cert from carousel file auth.tls.<x>
431  if (!GetDSMCCObject("/auth.tls.1", cert))
432  return false;
433 
434  // The cert has a 5 byte header: 16b cert_count + 24b cert_len
435  cert = cert.mid(5);
436  return true;
437 }
438 
439 // Called by the engine to request data from the carousel.
440 // Caller must hold m_runLock
441 bool MHIContext::GetCarouselData(const QString& objectPath, QByteArray &result)
442 {
443  QByteArray cert;
444  bool const isIC = objectPath.startsWith("http:") || objectPath.startsWith("https:");
445  if (isIC)
446  {
447  // Verify access to server
448  if (!CheckAccess(objectPath, cert))
449  return false;
450  }
451 
452  // Get the path components. The string will normally begin with "//"
453  // since this is an absolute path but that will be removed by split.
454 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
455  QStringList path = objectPath.split(QChar('/'), QString::SkipEmptyParts);
456 #else
457  QStringList path = objectPath.split(QChar('/'), Qt::SkipEmptyParts);
458 #endif
459  // Since the DSMCC carousel and the MHEG engine are currently on the
460  // same thread this is safe. Otherwise we need to make a deep copy of
461  // the result.
462 
463  bool bReported = false;
464  QElapsedTimer t; t.start();
465  while (!m_stop)
466  {
467  if (isIC)
468  {
469  switch (m_ic.GetFile(objectPath, result, cert))
470  {
472  if (bReported)
473  LOG(VB_MHEG, LOG_INFO, QString("[mhi] Received %1").arg(objectPath));
474  return true;
476  if (bReported)
477  LOG(VB_MHEG, LOG_INFO, QString("[mhi] Not found %1").arg(objectPath));
478  return false;
480  break;
481  }
482  }
483  else
484  {
485  QMutexLocker locker(&m_dsmccLock);
486  int res = m_dsmcc->GetDSMCCObject(path, result);
487  if (res == 0)
488  {
489  if (bReported)
490  LOG(VB_MHEG, LOG_INFO, QString("[mhi] Received %1").arg(objectPath));
491  return true; // Found it
492  }
493  // NB don't exit if -1 (not present) is returned as the object may
494  // arrive later. Exiting can cause the inital app to not be found
495  }
496 
497  if (t.hasExpired(60000)) // TODO get this from carousel info
498  {
499  if (bReported)
500  LOG(VB_MHEG, LOG_INFO, QString("[mhi] timed out %1").arg(objectPath));
501  return false; // Not there.
502  }
503  // Otherwise we block.
504  if (!bReported)
505  {
506  bReported = true;
507  LOG(VB_MHEG, LOG_INFO, QString("[mhi] Waiting for %1").arg(objectPath));
508  }
509  // Process DSMCC packets then block for a while or until we receive
510  // some more packets. We should eventually find out if this item is
511  // present.
513  m_engineWait.wait(&m_runLock, 300);
514  }
515  return false; // Stop has been set. Say the object isn't present.
516 }
517 
518 // Mapping from key name & UserInput register to UserInput EventData
520 {
521  using key_t = QPair< QString, int /*UserInput register*/ >;
522 
523 public:
524  MHKeyLookup();
525 
526  int Find(const QString &name, int reg) const
527  { return m_map.value(key_t(name,reg), 0); }
528 
529 private:
530  void key(const QString &name, int code, int r1,
531  int r2=0, int r3=0, int r4=0, int r5=0, int r6=0, int r7=0, int r8=0, int r9=0);
532 
533  QHash<key_t,int /*EventData*/ > m_map;
534 };
535 
536 void MHKeyLookup::key(const QString &name, int code, int r1,
537  int r2, int r3, int r4, int r5, int r6, int r7, int r8, int r9)
538 {
539  if (r1 > 0)
540  m_map.insert(key_t(name,r1), code);
541  if (r2 > 0)
542  m_map.insert(key_t(name,r2), code);
543  if (r3 > 0)
544  m_map.insert(key_t(name,r3), code);
545  if (r4 > 0)
546  m_map.insert(key_t(name,r4), code);
547  if (r5 > 0)
548  m_map.insert(key_t(name,r5), code);
549  if (r6 > 0)
550  m_map.insert(key_t(name,r6), code);
551  if (r7 > 0)
552  m_map.insert(key_t(name,r7), code);
553  if (r8 > 0)
554  m_map.insert(key_t(name,r8), code);
555  if (r9 > 0)
556  m_map.insert(key_t(name,r9), code);
557 }
558 
560 {
561  // Use a modification of the standard key mapping for RC's with a single
562  // stop button which is used for both Esc and TEXTEXIT (Back).
563  // This mapping doesn't pass Esc to the MHEG app in registers 3 or 5 and
564  // hence allows the user to exit playback when the red button icon is shown
565  QStringList keylist = GET_KEY("TV Playback", "TEXTEXIT").split(QChar(','));
566  bool strict = !keylist.contains("Esc", Qt::CaseInsensitive);
567 
568  // This supports the UK and NZ key profile registers.
569  // The UK uses 3, 4 and 5 and NZ 13, 14 and 15. These are
570  // similar but the NZ profile also provides an EPG key.
571  // ETSI ES 202 184 V2.2.1 (2011-03) adds group 6 for ICE.
572  // The BBC use group 7 for ICE
573  key(ACTION_UP, 1, 4,5,6,7,14,15);
574  key(ACTION_DOWN, 2, 4,5,6,7,14,15);
575  key(ACTION_LEFT, 3, 4,5,6,7,14,15);
576  key(ACTION_RIGHT, 4, 4,5,6,7,14,15);
577  key(ACTION_0, 5, 4,6,7,14);
578  key(ACTION_1, 6, 4,6,7,14);
579  key(ACTION_2, 7, 4,6,7,14);
580  key(ACTION_3, 8, 4,6,7,14);
581  key(ACTION_4, 9, 4,6,7,14);
582  key(ACTION_5, 10, 4,6,7,14);
583  key(ACTION_6, 11, 4,6,7,14);
584  key(ACTION_7, 12, 4,6,7,14);
585  key(ACTION_8, 13, 4,6,7,14);
586  key(ACTION_9, 14, 4,6,7,14);
587  key(ACTION_SELECT, 15, 4,5,6,7,14,15);
588  key(ACTION_TEXTEXIT, 16, strict ? 3 : 0,4,strict ? 5 : 0,6,7,13,14,15); // 16= Cancel
589  // 17= help
590  // 18..99 reserved by DAVIC
591  key(ACTION_MENURED, 100, 3,4,5,6,7,13,14,15);
592  key(ACTION_MENUGREEN, 101, 3,4,5,6,7,13,14,15);
593  key(ACTION_MENUYELLOW, 102, 3,4,5,6,7,13,14,15);
594  key(ACTION_MENUBLUE, 103, 3,4,5,6,7,13,14,15);
595  key(ACTION_MENUTEXT, 104, 3,4,5,6,7);
596  key(ACTION_MENUTEXT, 105, 13,14,15); // NB from original Myth code
597  // 105..119 reserved for future spec
598  key(ACTION_STOP, 120, 6,7);
599  key(ACTION_PLAY, 121, 6,7);
600  key(ACTION_PAUSE, 122, 6,7);
601  key(ACTION_JUMPFFWD, 123, 6,7); // 123= Skip Forward
602  key(ACTION_JUMPRWND, 124, 6,7); // 124= Skip Back
603 #if 0 // These conflict with left & right
604  key(ACTION_SEEKFFWD, 125, 6,7); // 125= Fast Forward
605  key(ACTION_SEEKRWND, 126, 6,7); // 126= Rewind
606 #endif
607  key(ACTION_PLAYBACK, 127, 6,7);
608  // 128..256 reserved for future spec
609  // 257..299 vendor specific
610  key(ACTION_MENUEPG, 300, 13,14,15);
611  // 301.. Vendor specific
612 }
613 
614 // Called from tv_play when a key is pressed.
615 // If it is one in the current profile we queue it for the engine
616 // and return true otherwise we return false.
617 bool MHIContext::OfferKey(const QString& key)
618 {
619  static const MHKeyLookup kKeymap;
620  int action = kKeymap.Find(key, m_keyProfile);
621  if (action == 0)
622  return false;
623 
624  LOG(VB_GENERAL, LOG_INFO, QString("[mhi] Adding MHEG key %1:%2:%3")
625  .arg(key).arg(action).arg(m_keyQueue.size()) );
626  { QMutexLocker locker(&m_keyLock);
628  m_engineWait.wakeAll();
629  return true;
630 }
631 
632 // Called from MythPlayer::VideoStart and MythPlayer::ReinitOSD
633 void MHIContext::Reinit(const QRect videoRect, const QRect dispRect, float aspect)
634 {
635  LOG(VB_MHEG, LOG_INFO,
636  QString("[mhi] Reinit video(y:%1 x:%2 w:%3 h:%4) "
637  "vis(y:%5 x:%6 w:%7 h:%8) aspect=%9")
638  .arg(videoRect.y()).arg(videoRect.x())
639  .arg(videoRect.width()).arg(videoRect.height())
640  .arg(dispRect.y()).arg(dispRect.x())
641  .arg(dispRect.width()).arg(dispRect.height()).arg(aspect));
642  m_videoDisplayRect = QRect();
643 
644  // MHEG presumes square pixels
645  enum { kNone, kHoriz, kBoth };
646  int mode = gCoreContext->GetNumSetting("MhegAspectCorrection", kNone);
647  auto const aspectd = static_cast<double>(aspect);
648  double const vz = (mode == kBoth) ? std::min(1.15, 1. / sqrt(aspectd)) : 1.;
649  double const hz = (mode > kNone) ? vz * aspectd : 1.;
650 
651  m_displayRect = QRect( int(dispRect.width() * (1 - hz) / 2),
652  int(dispRect.height() * (1 - vz) / 2),
653  int(dispRect.width() * hz), int(dispRect.height() * vz) );
654  m_videoRect = QRect( dispRect.x() + m_displayRect.x(),
655  dispRect.y() + int(dispRect.height() * (1 - hz) / 2),
656  int(dispRect.width() * hz), int(dispRect.height() * hz) );
657 }
658 
660 {
661  LOG(VB_MHEG, LOG_INFO, QString("[mhi] SetInputRegister %1").arg(num));
662  QMutexLocker locker(&m_keyLock);
663  m_keyQueue.clear();
664  m_keyProfile = num;
665 }
666 
668 {
669  // 0= Active, 1= Inactive, 2= Disabled
671 }
672 
673 // Called by the video player to redraw the image.
675  MythPainter *osdPainter)
676 {
677  if (!osdWindow || !osdPainter)
678  return;
679 
680  QMutexLocker locker(&m_displayLock);
681 
682  // In MHEG the video is just another item in the display stack
683  // but when we create the OSD we overlay everything over the video.
684  // We need to cut out anything belowthe video on the display stack
685  // to leave the video area clear.
686  auto it = m_display.begin();
687  for (; it != m_display.end(); ++it)
688  {
689  MHIImageData *data = *it;
690  if (!data->m_bUnder)
691  continue;
692 
693  QRect imageRect(data->m_x, data->m_y,
694  data->m_image.width(), data->m_image.height());
695  if (!m_videoDisplayRect.intersects(imageRect))
696  continue;
697 
698  // Replace this item with a set of cut-outs.
699  it = m_display.erase(it);
700 
701  for (const QRect& rect : QRegion(imageRect)-QRegion(m_videoDisplayRect))
702  {
703  QImage image =
704  data->m_image.copy(rect.x()-data->m_x, rect.y()-data->m_y,
705  rect.width(), rect.height());
706  auto *newData = new MHIImageData;
707  newData->m_image = image;
708  newData->m_x = rect.x();
709  newData->m_y = rect.y();
710  newData->m_bUnder = true;
711  it = m_display.insert(it, newData);
712  ++it;
713  }
714  --it;
715  delete data;
716  }
717 
718  m_updated = false;
719  osdWindow->DeleteAllChildren();
720  // Copy all the display items into the display.
721  it = m_display.begin();
722  for (int count = 0; it != m_display.end(); ++it, count++)
723  {
724  MHIImageData *data = *it;
725  MythImage* image = osdPainter->GetFormatImage();
726  if (!image)
727  continue;
728 
729  image->Assign(data->m_image);
730  auto *uiimage = new MythUIImage(osdWindow, QString("itv%1").arg(count));
731  if (uiimage)
732  {
733  uiimage->SetImage(image);
734  uiimage->SetArea(MythRect(data->m_x, data->m_y,
735  data->m_image.width(), data->m_image.height()));
736  }
737  image->DecrRef();
738  }
739  osdWindow->OptimiseDisplayedArea();
740  // N.B. bypasses OSD class hence no expiry set
741  osdWindow->SetVisible(true);
742 }
743 
744 void MHIContext::GetInitialStreams(int &audioTag, int &videoTag) const
745 {
746  audioTag = m_audioTag;
747  videoTag = m_videoTag;
748 }
749 
750 
751 // An area of the screen/image needs to be redrawn.
752 // Called from the MHEG engine.
753 // We always redraw the whole scene.
754 void MHIContext::RequireRedraw(const QRegion & /*region*/)
755 {
756  m_updated = false;
757  m_displayLock.lock();
758  ClearDisplay();
759  m_displayLock.unlock();
760  // Always redraw the whole screen
762  m_updated = true;
763 }
764 
765 inline int MHIContext::ScaleX(int n, bool roundup) const
766 {
767  return (n * m_displayRect.width() + (roundup ? kStdDisplayWidth - 1 : 0)) / kStdDisplayWidth;
768 }
769 
770 inline int MHIContext::ScaleY(int n, bool roundup) const
771 {
772  return (n * m_displayRect.height() + (roundup ? kStdDisplayHeight - 1 : 0)) / kStdDisplayHeight;
773 }
774 
775 inline QRect MHIContext::Scale(const QRect r) const
776 {
777  return { m_displayRect.topLeft() + QPoint(ScaleX(r.x()), ScaleY(r.y())),
778  QSize(ScaleX(r.width(), true), ScaleY(r.height(), true)) };
779 }
780 
781 inline int MHIContext::ScaleVideoX(int n, bool roundup) const
782 {
783  return (n * m_videoRect.width() + (roundup ? kStdDisplayWidth - 1 : 0)) / kStdDisplayWidth;
784 }
785 
786 inline int MHIContext::ScaleVideoY(int n, bool roundup) const
787 {
788  return (n * m_videoRect.height() + (roundup ? kStdDisplayHeight - 1 : 0)) / kStdDisplayHeight;
789 }
790 
791 inline QRect MHIContext::ScaleVideo(const QRect r) const
792 {
793  return { m_videoRect.topLeft() + QPoint(ScaleVideoX(r.x()), ScaleVideoY(r.y())),
794  QSize(ScaleVideoX(r.width(), true), ScaleVideoY(r.height(), true)) };
795 }
796 
797 void MHIContext::AddToDisplay(const QImage &image, const QRect displayRect, bool bUnder /*=false*/)
798 {
799  const QRect scaledRect = Scale(displayRect);
800 
801  auto *data = new MHIImageData;
802 
803  data->m_image = image.convertToFormat(QImage::Format_ARGB32).scaled(
804  scaledRect.width(), scaledRect.height(),
805  Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
806  data->m_x = scaledRect.x();
807  data->m_y = scaledRect.y();
808  data->m_bUnder = bUnder;
809 
810  QMutexLocker locker(&m_displayLock);
811  if (!bUnder)
812  m_display.push_back(data);
813  else
814  {
815  // Replace any existing items under the video with this
816  auto it = m_display.begin();
817  while (it != m_display.end())
818  {
819  MHIImageData *old = *it;
820  if (!old->m_bUnder)
821  ++it;
822  else
823  {
824  it = m_display.erase(it);
825  delete old;
826  }
827  }
828  m_display.push_front(data);
829  }
830 }
831 
832 inline int Roundup(int n, int r)
833 {
834  // NB assumes 2's complement arithmetic
835  return n + (-n & (r - 1));
836 }
837 
838 // The videoRect gives the size and position to which the video must be scaled.
839 // The displayRect gives the rectangle reserved for the video.
840 // e.g. part of the video may be clipped within the displayRect.
841 void MHIContext::DrawVideo(const QRect &videoRect, const QRect &dispRect)
842 {
843  // tell the video player to resize the video stream
844  if (m_parent->GetPlayer())
845  {
846  QRect vidRect;
847  if (videoRect != QRect(QPoint(0,0),QSize(kStdDisplayWidth,kStdDisplayHeight)))
848  {
849  vidRect = ScaleVideo(videoRect);
850  vidRect.setWidth(Roundup(vidRect.width(), 2));
851  vidRect.setHeight(Roundup(vidRect.height(), 2));
852  }
853  emit m_parent->GetPlayer()->ResizeForInteractiveTV(vidRect);
854  }
855 
856  m_videoDisplayRect = Scale(dispRect);
857 
858  // Mark all existing items in the display stack as under the video
859  QMutexLocker locker(&m_displayLock);
860  for (auto & it : m_display)
861  it->m_bUnder = true;
862 }
863 
864 // Caller must hold m_channelMutex
866 {
867  MSqlQuery query(MSqlQuery::InitCon());
868  query.prepare(
869  "SELECT networkid, serviceid, transportid, chanid "
870  "FROM channel, dtv_multiplex "
871  "WHERE channel.deleted IS NULL "
872  " AND channel.mplexid = dtv_multiplex.mplexid "
873  " AND channel.sourceid = dtv_multiplex.sourceid "
874  " AND channel.sourceid = :SOURCEID ;" );
875  query.bindValue(":SOURCEID", m_currentSource);
876  if (!query.exec())
877  {
878  MythDB::DBError("MHIContext::LoadChannelCache", query);
879  return false;
880  }
881  if (!query.isActive())
882  return false;
883  while (query.next())
884  {
885  int nid = query.value(0).toInt();
886  int sid = query.value(1).toInt();
887  int tid = query.value(2).toInt();
888  int cid = query.value(3).toInt();
889  m_channelCache.insert( Key_t(nid, sid), Val_t(tid, cid) );
890  }
891  return true;
892 }
893 
894 // Tuning. Get the index corresponding to a given channel.
895 // The format of the service is dvb://netID.[transPortID].serviceID
896 // where the IDs are in hex.
897 // or rec://svc/lcn/N where N is the "logical channel number"
898 // i.e. the Freeview channel.
899 // Returns -1 if it cannot find it.
900 int MHIContext::GetChannelIndex(const QString &str)
901 {
902  int nResult = -1;
903 
904  do
905  {
906  if (str.startsWith("dvb://"))
907  {
908  QStringList list = str.mid(6).split('.');
909  if (list.size() != 3)
910  break; // Malformed.
911  // The various fields are expressed in hexadecimal.
912  // Convert them to decimal for the DB.
913  bool ok = false;
914  int netID = list[0].toInt(&ok, 16);
915  if (!ok)
916  break;
917  int transportID = !list[1].isEmpty() ? list[1].toInt(&ok, 16) : -1;
918  if (!ok)
919  break;
920  int serviceID = list[2].toInt(&ok, 16);
921  if (!ok)
922  break;
923 
924  QMutexLocker locker(&m_channelMutex);
925  if (m_channelCache.isEmpty())
927 
928  ChannelCache_t::const_iterator it = m_channelCache.constFind(
929  Key_t(netID,serviceID) );
930  if (it == m_channelCache.constEnd())
931  break;
932  if (transportID < 0)
933  nResult = Cid(it);
934  else
935  {
936  do
937  {
938  if (Tid(it) == transportID)
939  {
940  nResult = Cid(it);
941  break;
942  }
943  }
944  while (++it != m_channelCache.constEnd());
945  }
946  }
947  else if (str.startsWith("rec://svc/lcn/"))
948  {
949  // I haven't seen this yet so this is untested.
950  bool ok = false;
951  int channelNo = str.mid(14).toInt(&ok); // Decimal integer
952  if (!ok)
953  break;
954  MSqlQuery query(MSqlQuery::InitCon());
955  query.prepare("SELECT chanid "
956  "FROM channel "
957  "WHERE deleted IS NULL AND "
958  " channum = :CHAN AND "
959  " channel.sourceid = :SOURCEID");
960  query.bindValue(":CHAN", channelNo);
961  query.bindValue(":SOURCEID", m_currentSource);
962  if (query.exec() && query.isActive() && query.next())
963  nResult = query.value(0).toInt();
964  }
965  else if (str == "rec://svc/cur")
967  else if (str == "rec://svc/def")
968  nResult = m_currentChannel;
969  else
970  {
971  LOG(VB_GENERAL, LOG_WARNING,
972  QString("[mhi] GetChannelIndex -- Unrecognized URL %1")
973  .arg(str));
974  }
975  }
976  while (false);
977 
978  LOG(VB_MHEG, LOG_INFO, QString("[mhi] GetChannelIndex %1 => %2")
979  .arg(str).arg(nResult));
980  return nResult;
981 
982 }
983 
984 // Get netId etc from the channel index. This is the inverse of GetChannelIndex.
985 bool MHIContext::GetServiceInfo(int channelId, int &netId, int &origNetId,
986  int &transportId, int &serviceId)
987 {
988  QMutexLocker locker(&m_channelMutex);
989  if (m_channelCache.isEmpty())
991 
992  for (auto it = m_channelCache.cbegin(); it != m_channelCache.cend(); ++it)
993  {
994  if (Cid(it) == channelId)
995  {
996  transportId = Tid(it);
997  netId = Nid(it);
998  origNetId = netId; // We don't have this in the database.
999  serviceId = Sid(it);
1000  LOG(VB_MHEG, LOG_INFO, QString("[mhi] GetServiceInfo %1 => NID=%2 TID=%3 SID=%4")
1001  .arg(channelId).arg(netId).arg(transportId).arg(serviceId));
1002  return true;
1003  }
1004  }
1005 
1006  LOG(VB_MHEG, LOG_WARNING, QString("[mhi] GetServiceInfo %1 failed").arg(channelId));
1007  return false;
1008 }
1009 
1010 bool MHIContext::TuneTo(int channel, int tuneinfo)
1011 {
1012  if (!m_isLive)
1013  {
1014  LOG(VB_MHEG, LOG_WARNING, QString("[mhi] Can't TuneTo %1 0x%2 while not live")
1015  .arg(channel).arg(tuneinfo,0,16));
1016  return false; // Can't tune if this is a recording.
1017  }
1018 
1019  LOG(VB_GENERAL, LOG_INFO, QString("[mhi] TuneTo %1 0x%2")
1020  .arg(channel).arg(tuneinfo,0,16));
1021  m_tuneInfo.append(tuneinfo);
1022 
1023  // Post an event requesting a channel change.
1024  MythEvent me(QString("NETWORK_CONTROL CHANID %1").arg(channel));
1025  gCoreContext->dispatch(me);
1026  // Reset the NBI version here to prevent a reboot.
1027  QMutexLocker locker(&m_dsmccLock);
1029  m_nbiData.resize(0);
1030  return true;
1031 }
1032 
1033 
1034 // Begin playing the specified stream
1035 bool MHIContext::BeginStream(const QString &stream, MHStream *notify)
1036 {
1037  LOG(VB_MHEG, LOG_INFO, QString("[mhi] BeginStream %1 0x%2")
1038  .arg(stream).arg((quintptr)notify,0,16));
1039 
1040  m_audioTag = -1;
1041  m_videoTag = -1;
1042  m_notify = notify;
1043 
1044  if (stream.startsWith("http://") || stream.startsWith("https://"))
1045  {
1046  m_currentStream = -1;
1047 
1048  // The url is sometimes only http:// during stream startup
1049  if (QUrl(stream).authority().isEmpty())
1050  return false;
1051 
1052  emit m_parent->GetPlayer()->SetInteractiveStream(stream);
1053  return !stream.isEmpty();
1054  }
1055 
1056  int chan = GetChannelIndex(stream);
1057  if (chan < 0)
1058  return false;
1059  if (VERBOSE_LEVEL_CHECK(VB_MHEG, LOG_ANY))
1060  {
1061  int netId = 0;
1062  int origNetId = 0;
1063  int transportId = 0;
1064  int serviceId = 0;
1065  GetServiceInfo(chan, netId, origNetId, transportId, serviceId);
1066  }
1067 
1068  if (chan != m_currentStream)
1069  {
1070  // We have to tune to the channel where the stream is to be found.
1071  // Because the audio and video are both components of an MHEG stream
1072  // they will both be on the same channel.
1073  m_currentStream = chan;
1075  }
1076 
1077  return true;
1078 }
1079 
1081 {
1082  LOG(VB_MHEG, LOG_INFO, QString("[mhi] EndStream 0x%1")
1083  .arg((quintptr)m_notify,0,16) );
1084 
1085  m_notify = nullptr;
1086  emit m_parent->GetPlayer()->SetInteractiveStream(QString());
1087 }
1088 
1089 // Callback from MythPlayer when a stream starts or stops
1090 bool MHIContext::StreamStarted(bool bStarted)
1091 {
1092  if (!m_engine || !m_notify)
1093  return false;
1094 
1095  LOG(VB_MHEG, LOG_INFO, QString("[mhi] Stream 0x%1 %2")
1096  .arg((quintptr)m_notify,0,16).arg(bStarted ? "started" : "stopped"));
1097 
1098  QMutexLocker locker(&m_runLock);
1099  m_engine->StreamStarted(m_notify, bStarted);
1100  if (!bStarted)
1101  m_notify = nullptr;
1102  return m_currentStream == -1; // Return true if it's an http stream
1103 }
1104 
1105 // Begin playing audio
1107 {
1108  LOG(VB_MHEG, LOG_INFO, QString("[mhi] BeginAudio %1").arg(tag));
1109 
1110  if (tag < 0)
1111  return true; // Leave it at the default.
1112 
1113  m_audioTag = tag;
1114  if (m_parent->GetPlayer())
1115  return m_parent->GetPlayer()->SetAudioByComponentTag(tag);
1116  return false;
1117  }
1118 
1119 // Stop playing audio
1121 {
1122  // Do nothing at the moment.
1123 }
1124 
1125 // Begin displaying video from the specified stream
1127 {
1128  LOG(VB_MHEG, LOG_INFO, QString("[mhi] BeginVideo %1").arg(tag));
1129 
1130  if (tag < 0)
1131  return true; // Leave it at the default.
1132 
1133  m_videoTag = tag;
1134  if (m_parent->GetPlayer())
1135  return m_parent->GetPlayer()->SetVideoByComponentTag(tag);
1136  return false;
1137 }
1138 
1139  // Stop displaying video
1141 {
1142  // Do nothing at the moment.
1143 }
1144 
1145 // Get current stream position, -1 if unknown
1146 std::chrono::milliseconds MHIContext::GetStreamPos()
1147 {
1148  return m_parent->GetPlayer() ? m_parent->GetPlayer()->GetStreamPos() : -1ms;
1149 }
1150 
1151 // Get current stream size, -1 if unknown
1152 std::chrono::milliseconds MHIContext::GetStreamMaxPos()
1153 {
1154  return m_parent->GetPlayer() ? m_parent->GetPlayer()->GetStreamMaxPos() : -1ms;
1155 }
1156 
1157 // Set current stream position
1158 std::chrono::milliseconds MHIContext::SetStreamPos(std::chrono::milliseconds pos)
1159 {
1160  if (m_parent->GetPlayer())
1162  // Note: return value is never used
1163  return 0ms;
1164 }
1165 
1166 // Play or pause a stream
1167 void MHIContext::StreamPlay(bool play)
1168 {
1169  if (m_parent->GetPlayer())
1170  emit m_parent->GetPlayer()->PlayInteractiveStream(play);
1171 }
1172 
1173 // Create a new object to draw dynamic line art.
1175  bool isBoxed, MHRgba lineColour, MHRgba fillColour)
1176 {
1177  return new MHIDLA(this, isBoxed, lineColour, fillColour);
1178 }
1179 
1180 // Create a new object to draw text.
1182 {
1183  return new MHIText(this);
1184 }
1185 
1186 // Create a new object to draw bitmaps.
1188 {
1189  return new MHIBitmap(this, tiled);
1190 }
1191 
1192 // Draw a rectangle. This is complicated if we want to get transparency right.
1193 void MHIContext::DrawRect(int xPos, int yPos, int width, int height,
1194  MHRgba colour)
1195 {
1196  if (colour.alpha() == 0 || height == 0 || width == 0)
1197  return; // Fully transparent
1198 
1199  QImage qImage(width, height, QImage::Format_ARGB32);
1200  qImage.fill(qRgba(colour.red(), colour.green(), colour.blue(), colour.alpha()));
1201 
1202  AddToDisplay(qImage, QRect(xPos, yPos, width, height));
1203 }
1204 
1205 // Draw an image at the specified position.
1206 // Generally the whole of the image is drawn but sometimes the
1207 // image may be clipped. x and y define the origin of the bitmap
1208 // and usually that will be the same as the origin of the bounding
1209 // box (clipRect).
1210 void MHIContext::DrawImage(int x, int y, const QRect clipRect,
1211  const QImage &qImage, bool bScaled, bool bUnder)
1212 {
1213  if (qImage.isNull())
1214  return;
1215 
1216  QRect imageRect(x, y, qImage.width(), qImage.height());
1217  QRect displayRect = clipRect & imageRect;
1218 
1219  if (bScaled || displayRect == imageRect) // No clipping required
1220  {
1221  AddToDisplay(qImage, displayRect, bUnder);
1222  }
1223  else if (!displayRect.isEmpty())
1224  { // We must clip the image.
1225  QImage clipped = qImage.copy(displayRect.translated(-x, -y));
1226  AddToDisplay(clipped, displayRect, bUnder);
1227  }
1228  // Otherwise draw nothing.
1229 }
1230 
1231 // Fill in the background. This is only called if there is some area of
1232 // the screen that is not covered with other visibles.
1233 void MHIContext::DrawBackground(const QRegion &reg)
1234 {
1235  if (reg.isEmpty())
1236  return;
1237 
1238  QRect bounds = reg.boundingRect();
1239  DrawRect(bounds.x(), bounds.y(), bounds.width(), bounds.height(),
1240  MHRgba(0, 0, 0, 255)/* black. */);
1241 }
1242 
1243 void MHIText::Draw(int x, int y)
1244 {
1245  m_parent->DrawImage(x, y, QRect(x, y, m_width, m_height), m_image);
1246 }
1247 
1248 void MHIText::SetSize(int width, int height)
1249 {
1250  m_width = width;
1251  m_height = height;
1252 }
1253 
1254 void MHIText::SetFont(int size, bool isBold, bool isItalic)
1255 {
1256  m_fontSize = size;
1257  m_fontItalic = isItalic;
1258  m_fontBold = isBold;
1259  // TODO: Only the size is currently used.
1260  // Bold and Italic are currently ignored.
1261 }
1262 
1263 // FT sizes are in 26.6 fixed point form
1264 const int kShift = 6;
1265 static inline FT_F26Dot6 Point2FT(int pt)
1266 {
1267  return pt << kShift;
1268 }
1269 
1270 static inline int FT2Point(FT_F26Dot6 fp)
1271 {
1272  return (fp + (1<<(kShift-1))) >> kShift;
1273 }
1274 
1275 // Return the bounding rectangle for a piece of text drawn in the
1276 // current font. If maxSize is non-negative it sets strLen to the
1277 // number of characters that will fit in the space and returns the
1278 // bounds for those characters.
1279 // N.B. The box is relative to the origin so the y co-ordinate will
1280 // be negative. It's also possible that the x co-ordinate could be
1281 // negative for slanted fonts but that doesn't currently happen.
1282 QRect MHIText::GetBounds(const QString &str, int &strLen, int maxSize)
1283 {
1284  if (!m_parent->IsFaceLoaded())
1285  return {0,0,0,0};
1286 
1287  FT_Face face = m_parent->GetFontFace();
1288  FT_Error error = FT_Set_Char_Size(face, 0, Point2FT(m_fontSize),
1290  if (error)
1291  return {0,0,0,0};
1292 
1293  int maxAscent = face->size->metrics.ascender;
1294  int maxDescent = -face->size->metrics.descender;
1295  int width = 0;
1296  FT_Bool useKerning = FT_HAS_KERNING(face);
1297  FT_UInt previous = 0;
1298 
1299  for (int n = 0; n < strLen; n++)
1300  {
1301  QChar ch = str.at(n);
1302  FT_UInt glyphIndex = FT_Get_Char_Index(face, ch.unicode());
1303 
1304  if (glyphIndex == 0)
1305  {
1306  LOG(VB_MHEG, LOG_INFO, QString("[mhi] Unknown glyph 0x%1")
1307  .arg(ch.unicode(),0,16));
1308  previous = 0;
1309  continue;
1310  }
1311 
1312  int kerning = 0;
1313 
1314  if (useKerning && previous != 0)
1315  {
1316  FT_Vector delta;
1317  FT_Get_Kerning(face, previous, glyphIndex,
1318  FT_KERNING_DEFAULT, &delta);
1319  kerning = delta.x;
1320  }
1321 
1322  error = FT_Load_Glyph(face, glyphIndex, 0); // Don't need to render.
1323 
1324  if (error)
1325  continue; // ignore errors.
1326 
1327  FT_GlyphSlot slot = face->glyph; /* a small shortcut */
1328  FT_Pos advance = slot->metrics.horiAdvance + kerning;
1329 
1330  if (maxSize >= 0)
1331  {
1332  if (FT2Point(width + advance) > maxSize)
1333  {
1334  // There isn't enough space for this character.
1335  strLen = n;
1336  break;
1337  }
1338  }
1339  // Calculate the ascent and descent of this glyph.
1340  int descent = slot->metrics.height - slot->metrics.horiBearingY;
1341 
1342  if (slot->metrics.horiBearingY > maxAscent)
1343  maxAscent = slot->metrics.horiBearingY;
1344 
1345  if (descent > maxDescent)
1346  maxDescent = descent;
1347 
1348  width += advance;
1349  previous = glyphIndex;
1350  }
1351 
1352  return {0, -FT2Point(maxAscent), FT2Point(width), FT2Point(maxAscent + maxDescent)};
1353 }
1354 
1355 // Reset the image and fill it with transparent ink.
1356 // The UK MHEG profile says that we should consider the background
1357 // as paper and the text as ink. We have to consider these as two
1358 // different layers. The background is drawn separately as a rectangle.
1359 void MHIText::Clear(void)
1360 {
1361  m_image = QImage(m_width, m_height, QImage::Format_ARGB32);
1362  // QImage::fill doesn't set the alpha buffer.
1363  for (int i = 0; i < m_height; i++)
1364  {
1365  for (int j = 0; j < m_width; j++)
1366  {
1367  m_image.setPixel(j, i, qRgba(0, 0, 0, 0));
1368  }
1369  }
1370 }
1371 
1372 // Draw a line of text in the given position within the image.
1373 // It would be nice to be able to use TTFFont for this but it doesn't provide
1374 // what we want.
1375 void MHIText::AddText(int x, int y, const QString &str, MHRgba colour)
1376 {
1377  if (!m_parent->IsFaceLoaded()) return;
1378  FT_Face face = m_parent->GetFontFace();
1379 
1380  FT_Set_Char_Size(face, 0, Point2FT(m_fontSize),
1382 
1383  // X positions are computed to 64ths and rounded.
1384  // Y positions are in pixels
1385  int posX = Point2FT(x);
1386  int pixelY = y;
1387  FT_Bool useKerning = FT_HAS_KERNING(face);
1388  FT_UInt previous = 0;
1389 
1390  int len = str.length();
1391  for (int n = 0; n < len; n++)
1392  {
1393  // Load the glyph.
1394  QChar ch = str[n];
1395  FT_UInt glyphIndex = FT_Get_Char_Index(face, ch.unicode());
1396  if (glyphIndex == 0)
1397  {
1398  previous = 0;
1399  continue;
1400  }
1401 
1402  if (useKerning && previous != 0)
1403  {
1404  FT_Vector delta;
1405  FT_Get_Kerning(face, previous, glyphIndex,
1406  FT_KERNING_DEFAULT, &delta);
1407  posX += delta.x;
1408  }
1409  FT_Error error = FT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
1410 
1411  if (error)
1412  continue; // ignore errors
1413 
1414  FT_GlyphSlot slot = face->glyph;
1415  if (slot->format != FT_GLYPH_FORMAT_BITMAP)
1416  continue; // Problem
1417 
1418  if ((enum FT_Pixel_Mode_)slot->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
1419  continue;
1420 
1421  unsigned char *source = slot->bitmap.buffer;
1422  // Get the origin for the bitmap
1423  int baseX = FT2Point(posX) + slot->bitmap_left;
1424  int baseY = pixelY - slot->bitmap_top;
1425  // Copy the bitmap into the image.
1426  for (unsigned int i = 0; i < slot->bitmap.rows; i++)
1427  {
1428  for (unsigned int j = 0; j < slot->bitmap.width; j++)
1429  {
1430  int greyLevel = source[j];
1431  // Set the pixel to the specified colour but scale its
1432  // brightness according to the grey scale of the pixel.
1433  int red = colour.red();
1434  int green = colour.green();
1435  int blue = colour.blue();
1436  int alpha = colour.alpha() *
1437  greyLevel / slot->bitmap.num_grays;
1438  int xBit = j + baseX;
1439  int yBit = i + baseY;
1440 
1441  // The bits ought to be inside the bitmap but
1442  // I guess there's the possibility
1443  // that rounding might put it outside.
1444  if (xBit >= 0 && xBit < m_width &&
1445  yBit >= 0 && yBit < m_height)
1446  {
1447  m_image.setPixel(xBit, yBit,
1448  qRgba(red, green, blue, alpha));
1449  }
1450  }
1451  source += slot->bitmap.pitch;
1452  }
1453  posX += slot->advance.x;
1454  previous = glyphIndex;
1455  }
1456 }
1457 
1458 // Internal function to fill a rectangle with a colour
1459 void MHIDLA::DrawRect(int x, int y, int width, int height, MHRgba colour)
1460 {
1461  QRgb qColour = qRgba(colour.red(), colour.green(),
1462  colour.blue(), colour.alpha());
1463 
1464  // Constrain the drawing within the image.
1465  if (x < 0)
1466  {
1467  width += x;
1468  x = 0;
1469  }
1470 
1471  if (y < 0)
1472  {
1473  height += y;
1474  y = 0;
1475  }
1476 
1477  if (width <= 0 || height <= 0)
1478  return;
1479 
1480  int imageWidth = m_image.width();
1481  int imageHeight = m_image.height();
1482  if (x+width > imageWidth)
1483  width = imageWidth - x;
1484 
1485  if (y+height > imageHeight)
1486  height = imageHeight - y;
1487 
1488  if (width <= 0 || height <= 0)
1489  return;
1490 
1491  for (int i = 0; i < height; i++)
1492  {
1493  for (int j = 0; j < width; j++)
1494  {
1495  m_image.setPixel(x+j, y+i, qColour);
1496  }
1497  }
1498 }
1499 
1500 // Reset the drawing.
1502 {
1503  if (m_width == 0 || m_height == 0)
1504  {
1505  m_image = QImage();
1506  return;
1507  }
1508  m_image = QImage(m_width, m_height, QImage::Format_ARGB32);
1509  // Fill the image with "transparent colour".
1510  DrawRect(0, 0, m_width, m_height, MHRgba(0, 0, 0, 0));
1511 }
1512 
1513 void MHIDLA::Draw(int x, int y)
1514 {
1515  QRect bounds(x, y, m_width, m_height);
1516  if (m_boxed && m_lineWidth != 0)
1517  {
1518  // Draw the lines round the outside.
1519  // These don't form part of the drawing.
1520  m_parent->DrawRect(x, y, m_width,
1522 
1525 
1526  m_parent->DrawRect(x, y + m_lineWidth,
1528  m_boxLineColour);
1529 
1532  m_boxLineColour);
1533 
1534  // Deflate the box to within the border.
1535  bounds = QRect(bounds.x() + m_lineWidth,
1536  bounds.y() + m_lineWidth,
1537  bounds.width() - 2*m_lineWidth,
1538  bounds.height() - 2*m_lineWidth);
1539  }
1540 
1541  // Draw the background.
1543  y + m_lineWidth,
1544  m_width - m_lineWidth * 2,
1545  m_height - m_lineWidth * 2,
1546  m_boxFillColour);
1547 
1548  // Now the drawing.
1549  m_parent->DrawImage(x, y, bounds, m_image);
1550 }
1551 
1552 // The UK MHEG profile defines exactly how transparency is supposed to work.
1553 // The drawings are made using possibly transparent ink with any crossings
1554 // just set to that ink and then the whole drawing is alpha-merged with the
1555 // underlying graphics.
1556 // DynamicLineArt no longer seems to be used in transmissions in the UK
1557 // although it appears that DrawPoly is used in New Zealand. These are
1558 // very basic implementations of the functions.
1559 
1560 // Lines
1561 void MHIDLA::DrawLine(int x1, int y1, int x2, int y2)
1562 {
1563  // Get the arguments so that the lower x comes first and the
1564  // absolute gradient is less than one.
1565  if (abs(y2-y1) > abs(x2-x1))
1566  {
1567  if (y2 > y1)
1568  DrawLineSub(y1, x1, y2, x2, true);
1569  else
1570  DrawLineSub(y2, x2, y1, x1, true);
1571  }
1572  else
1573  {
1574  if (x2 > x1)
1575  DrawLineSub(x1, y1, x2, y2, false);
1576  else
1577  DrawLineSub(x2, y2, x1, y1, false);
1578  }
1579 }
1580 
1581 // Based on the Bresenham line drawing algorithm but extended to draw
1582 // thick lines.
1583 void MHIDLA::DrawLineSub(int x1, int y1, int x2, int y2, bool swapped)
1584 {
1585  QRgb colour = qRgba(m_lineColour.red(), m_lineColour.green(),
1587  int dx = x2-x1;
1588  int dy = abs(y2-y1);
1589  int yStep = y2 >= y1 ? 1 : -1;
1590  // Adjust the starting positions to take account of the
1591  // line width.
1592  int error2 = dx/2;
1593  for (int k = 0; k < m_lineWidth/2; k++)
1594  {
1595  y1--;
1596  y2--;
1597  error2 += dy;
1598  if (error2*2 > dx)
1599  {
1600  error2 -= dx;
1601  x1 += yStep;
1602  x2 += yStep;
1603  }
1604  }
1605  // Main loop
1606  int y = y1;
1607  int error = dx/2;
1608  for (int x = x1; x <= x2; x++) // Include both endpoints
1609  {
1610  error2 = dx/2;
1611  int j = 0;
1612  // Inner loop also uses the Bresenham algorithm to draw lines
1613  // perpendicular to the principal direction.
1614  for (int i = 0; i < m_lineWidth; i++)
1615  {
1616  if (swapped)
1617  {
1618  if (x+j >= 0 && y+i >= 0 && y+i < m_width && x+j < m_height)
1619  m_image.setPixel(y+i, x+j, colour);
1620  }
1621  else
1622  {
1623  if (x+j >= 0 && y+i >= 0 && x+j < m_width && y+i < m_height)
1624  m_image.setPixel(x+j, y+i, colour);
1625  }
1626  error2 += dy;
1627  if (error2*2 > dx)
1628  {
1629  error2 -= dx;
1630  j -= yStep;
1631  if (i < m_lineWidth-1)
1632  {
1633  // Add another pixel in this case.
1634  if (swapped)
1635  {
1636  if (x+j >= 0 && y+i >= 0 && y+i < m_width && x+j < m_height)
1637  m_image.setPixel(y+i, x+j, colour);
1638  }
1639  else
1640  {
1641  if (x+j >= 0 && y+i >= 0 && x+j < m_width && y+i < m_height)
1642  m_image.setPixel(x+j, y+i, colour);
1643  }
1644  }
1645  }
1646  }
1647  error += dy;
1648  if (error*2 > dx)
1649  {
1650  error -= dx;
1651  y += yStep;
1652  }
1653  }
1654 }
1655 
1656 // Rectangles
1657 void MHIDLA::DrawBorderedRectangle(int x, int y, int width, int height)
1658 {
1659  if (m_lineWidth != 0)
1660  {
1661  // Draw the lines round the rectangle.
1662  DrawRect(x, y, width, m_lineWidth,
1663  m_lineColour);
1664 
1665  DrawRect(x, y + height - m_lineWidth,
1666  width, m_lineWidth,
1667  m_lineColour);
1668 
1669  DrawRect(x, y + m_lineWidth,
1670  m_lineWidth, height - m_lineWidth * 2,
1671  m_lineColour);
1672 
1673  DrawRect(x + width - m_lineWidth, y + m_lineWidth,
1674  m_lineWidth, height - m_lineWidth * 2,
1675  m_lineColour);
1676 
1677  // Fill the rectangle.
1678  DrawRect(x + m_lineWidth, y + m_lineWidth,
1679  width - m_lineWidth * 2, height - m_lineWidth * 2,
1680  m_fillColour);
1681  }
1682  else
1683  {
1684  DrawRect(x, y, width, height, m_fillColour);
1685  }
1686 }
1687 
1688 // Ovals (ellipses)
1689 void MHIDLA::DrawOval(int /*x*/, int /*y*/, int /*width*/, int /*height*/)
1690 {
1691  // Not implemented. Not actually used in practice.
1692 }
1693 
1694 // Arcs and sectors
1695 void MHIDLA::DrawArcSector(int /*x*/, int /*y*/, int /*width*/, int /*height*/,
1696  int /*start*/, int /*arc*/, bool /*isSector*/)
1697 {
1698  // Not implemented. Not actually used in practice.
1699 }
1700 
1701 // Polygons. This is used directly and also to draw other figures.
1702 // The UK profile says that MHEG should not contain concave or
1703 // self-crossing polygons but we can get the former at least as
1704 // a result of rounding when drawing ellipses.
1705 struct lineSeg { int m_yBottom, m_yTop, m_xBottom; float m_slope; };
1706 
1707 void MHIDLA::DrawPoly(bool isFilled, const MHPointVec& xArray, const MHPointVec& yArray)
1708 {
1709  int nPoints = xArray.size();
1710  if (nPoints < 2)
1711  return;
1712 
1713  if (isFilled)
1714  {
1715  QVector <lineSeg> lineArray(nPoints);
1716  int nLines = 0;
1717  // Initialise the line segment array. Include all lines
1718  // apart from horizontal. Close the polygon by starting
1719  // with the last point in the array.
1720  int lastX = xArray[nPoints-1]; // Last point
1721  int lastY = yArray[nPoints-1];
1722  int yMin = lastY;
1723  int yMax = lastY;
1724  for (int k = 0; k < nPoints; k++)
1725  {
1726  int thisX = xArray[k];
1727  int thisY = yArray[k];
1728  if (lastY != thisY)
1729  {
1730  if (lastY > thisY)
1731  {
1732  lineArray[nLines].m_yBottom = thisY;
1733  lineArray[nLines].m_yTop = lastY;
1734  lineArray[nLines].m_xBottom = thisX;
1735  }
1736  else
1737  {
1738  lineArray[nLines].m_yBottom = lastY;
1739  lineArray[nLines].m_yTop = thisY;
1740  lineArray[nLines].m_xBottom = lastX;
1741  }
1742  lineArray[nLines++].m_slope =
1743  (float)(thisX-lastX) / (float)(thisY-lastY);
1744  }
1745  if (thisY < yMin)
1746  yMin = thisY;
1747  if (thisY > yMax)
1748  yMax = thisY;
1749  lastX = thisX;
1750  lastY = thisY;
1751  }
1752 
1753  // Find the intersections of each line in the line segment array
1754  // with the scan line. Because UK MHEG says that figures should be
1755  // convex we only need to consider two intersections.
1756  QRgb fillColour = qRgba(m_fillColour.red(), m_fillColour.green(),
1758  for (int y = yMin; y < yMax; y++)
1759  {
1760  int crossings = 0;
1761  int xMin = 0;
1762  int xMax = 0;
1763  for (int l = 0; l < nLines; l++)
1764  {
1765  if (y >= lineArray[l].m_yBottom && y < lineArray[l].m_yTop)
1766  {
1767  int x = (int)round((float)(y - lineArray[l].m_yBottom) *
1768  lineArray[l].m_slope) + lineArray[l].m_xBottom;
1769  if (crossings == 0 || x < xMin)
1770  xMin = x;
1771  if (crossings == 0 || x > xMax)
1772  xMax = x;
1773  crossings++;
1774  }
1775  }
1776  if (crossings == 2)
1777  {
1778  for (int x = xMin; x <= xMax; x++)
1779  m_image.setPixel(x, y, fillColour);
1780  }
1781  }
1782 
1783  // Draw the boundary
1784  int lastXpoint = xArray[nPoints-1]; // Last point
1785  int lastYpoint = yArray[nPoints-1];
1786  for (int i = 0; i < nPoints; i++)
1787  {
1788  DrawLine(xArray[i], yArray[i], lastXpoint, lastYpoint);
1789  lastXpoint = xArray[i];
1790  lastYpoint = yArray[i];
1791  }
1792  }
1793  else // PolyLine - draw lines between the points but don't close it.
1794  {
1795  for (int i = 1; i < nPoints; i++)
1796  {
1797  DrawLine(xArray[i], yArray[i], xArray[i-1], yArray[i-1]);
1798  }
1799  }
1800 }
1801 
1802 MHIBitmap::MHIBitmap(MHIContext *parent, bool tiled)
1803  : m_parent(parent), m_tiled(tiled),
1804  m_copyCtx(new MythAVCopy())
1805 {
1806 }
1807 
1809 {
1810  delete m_copyCtx;
1811 }
1812 
1813 void MHIBitmap::Draw(int x, int y, QRect rect, bool tiled, bool bUnder)
1814 {
1815  if (tiled)
1816  {
1817  if (m_image.width() == 0 || m_image.height() == 0)
1818  return;
1819  // Construct an image the size of the bounding box and tile the
1820  // bitmap over this.
1821  QImage tiledImage = QImage(rect.width(), rect.height(),
1822  QImage::Format_ARGB32);
1823 
1824  for (int i = 0; i < rect.width(); i++)
1825  {
1826  for (int j = 0; j < rect.height(); j++)
1827  {
1828  tiledImage.setPixel(i, j, m_image.pixel(i % m_image.width(), j % m_image.height()));
1829  }
1830  }
1831  m_parent->DrawImage(rect.x(), rect.y(), rect, tiledImage, true, bUnder);
1832  }
1833  else
1834  {
1835  // NB THe BBC expects bitmaps to be scaled, not clipped
1836  m_parent->DrawImage(x, y, rect, m_image, true, bUnder);
1837  }
1838 }
1839 
1840 // Create a bitmap from PNG.
1841 void MHIBitmap::CreateFromPNG(const unsigned char *data, int length)
1842 {
1843  m_image = QImage();
1844 
1845  if (!m_image.loadFromData(data, length, "PNG"))
1846  {
1847  m_image = QImage();
1848  return;
1849  }
1850 
1851  // Assume that if it has an alpha buffer then it's partly transparent.
1852  m_opaque = ! m_image.hasAlphaChannel();
1853 }
1854 
1855 // Create a bitmap from JPEG.
1856 //virtual
1857 void MHIBitmap::CreateFromJPEG(const unsigned char *data, int length)
1858 {
1859  m_image = QImage();
1860 
1861  if (!m_image.loadFromData(data, length, "JPG"))
1862  {
1863  m_image = QImage();
1864  return;
1865  }
1866 
1867  // Assume that if it has an alpha buffer then it's partly transparent.
1868  m_opaque = ! m_image.hasAlphaChannel();
1869 }
1870 
1871 // Convert an MPEG I-frame into a bitmap. This is used as the way of
1872 // sending still pictures. We convert the image to a QImage even
1873 // though that actually means converting it from YUV and eventually
1874 // converting it back again but we do this very infrequently so the
1875 // cost is outweighed by the simplification.
1876 void MHIBitmap::CreateFromMPEG(const unsigned char *data, int length)
1877 {
1878  AVCodecContext *c = nullptr;
1879  MythAVFrame picture;
1880  AVPacket pkt;
1881  uint8_t *buff = nullptr;
1882  bool gotPicture = false;
1883  m_image = QImage();
1884 
1885  // Find the mpeg2 video decoder.
1886  AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_MPEG2VIDEO);
1887  if (!codec)
1888  return;
1889  if (!picture)
1890  return;
1891 
1892  c = avcodec_alloc_context3(nullptr);
1893 
1894  if (avcodec_open2(c, codec, nullptr) < 0)
1895  goto Close;
1896 
1897  // Copy the data into AVPacket
1898  if (av_new_packet(&pkt, length) < 0)
1899  goto Close;
1900 
1901  memcpy(pkt.data, data, length);
1902  buff = pkt.data;
1903 
1904  // Get a picture from the packet. Allow 9 loops for
1905  // packet to be decoded. It should take only 2-3 loops
1906  for (int limit=0; limit<10 && !gotPicture; limit++)
1907  {
1908  int len = avcodec_receive_frame(c, picture);
1909  if (len == 0)
1910  gotPicture = true;
1911  if (len == AVERROR(EAGAIN))
1912  len = 0;
1913  if (len == 0)
1914  len = avcodec_send_packet(c, &pkt);
1915  if (len == AVERROR(EAGAIN) || len == AVERROR_EOF)
1916  len = 0;
1917  if (len < 0) // Error
1918  {
1919  std::string error;
1920  LOG(VB_GENERAL, LOG_ERR,
1921  QString("[mhi] video decode error: %1 (%2)")
1922  .arg(av_make_error_stdstring(error, len))
1923  .arg(gotPicture));
1924  goto Close;
1925  }
1926  else
1927  {
1928  pkt.data = nullptr;
1929  pkt.size = 0;
1930  }
1931  }
1932 
1933  if (gotPicture)
1934  {
1935  int nContentWidth = c->width;
1936  int nContentHeight = c->height;
1937  m_image = QImage(nContentWidth, nContentHeight, QImage::Format_ARGB32);
1938  m_opaque = true; // MPEG images are always opaque.
1939 
1940  AVFrame retbuf;
1941  memset(&retbuf, 0, sizeof(AVFrame));
1942 
1943  int bufflen = nContentWidth * nContentHeight * 3;
1944  auto *outputbuf = (unsigned char*)av_malloc(bufflen);
1945 
1946  av_image_fill_arrays(retbuf.data, retbuf.linesize,
1947  outputbuf, AV_PIX_FMT_RGB24,
1948  nContentWidth, nContentHeight,IMAGE_ALIGN);
1949 
1950  AVFrame *tmp = picture;
1951  m_copyCtx->Copy(&retbuf, AV_PIX_FMT_RGB24, tmp, c->pix_fmt,
1952  nContentWidth, nContentHeight);
1953 
1954  uint8_t * buf = outputbuf;
1955 
1956  // Copy the data a pixel at a time.
1957  // This should handle endianness correctly.
1958  for (int i = 0; i < nContentHeight; i++)
1959  {
1960  for (int j = 0; j < nContentWidth; j++)
1961  {
1962  int red = *buf++;
1963  int green = *buf++;
1964  int blue = *buf++;
1965  m_image.setPixel(j, i, qRgb(red, green, blue));
1966  }
1967  }
1968  av_freep(&outputbuf);
1969  }
1970 
1971 Close:
1972  pkt.data = buff;
1973  av_packet_unref(&pkt);
1974  avcodec_free_context(&c);
1975 }
1976 
1977 // Scale the bitmap. Only used for image derived from MPEG I-frames.
1978 void MHIBitmap::ScaleImage(int newWidth, int newHeight)
1979 {
1980  if (m_image.isNull())
1981  return;
1982 
1983  if (newWidth == m_image.width() && newHeight == m_image.height())
1984  return;
1985 
1986  if (newWidth <= 0 || newHeight <= 0)
1987  { // This would be a bit silly but handle it anyway.
1988  m_image = QImage();
1989  return;
1990  }
1991 
1992  m_image = m_image.scaled(newWidth, newHeight,
1993  Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
1994 }
ACTION_PLAY
#define ACTION_PLAY
Definition: tv_actions.h:30
MHIContext::m_isLive
bool m_isLive
Definition: mhi.h:211
MHIContext::CreateText
MHTextDisplay * CreateText(void) override
Definition: mhi.cpp:1181
MythPlayerCaptionsUI::PlayInteractiveStream
void PlayInteractiveStream(bool Play)
MHIText::Draw
void Draw(int x, int y) override
Definition: mhi.cpp:1243
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:213
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:806
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
ACTION_UP
#define ACTION_UP
Definition: mythuiactions.h:16
mythrect.h
mythevent.h
MHIContext::m_updated
bool m_updated
Definition: mhi.h:200
MHIContext::GetFontFace
FT_Face GetFontFace(void)
Definition: mhi.h:162
MHIImageData::m_y
int m_y
Definition: mhi.cpp:71
ACTION_3
#define ACTION_3
Definition: mythuiactions.h:7
MHIContext::IsFaceLoaded
bool IsFaceLoaded(void) const
Definition: mhi.h:163
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:286
MHIContext::m_notify
MHStream * m_notify
Definition: mhi.h:188
MHIContext::m_ic
MHInteractionChannel m_ic
Definition: mhi.h:187
MHIContext::Restart
void Restart(int chanid, int sourceid, bool isLive)
Restart the MHEG engine.
Definition: mhi.cpp:171
MHIDLA::DrawOval
void DrawOval(int x, int y, int width, int height) override
Definition: mhi.cpp:1689
MHIContext::m_currentStream
int m_currentStream
Definition: mhi.h:210
MHIContext::m_lastNbiVersion
uint m_lastNbiVersion
Definition: mhi.h:218
ACTION_JUMPRWND
#define ACTION_JUMPRWND
Definition: tv_actions.h:45
MythUIImage
Image widget, displays a single image or multiple images in sequence.
Definition: mythuiimage.h:97
MHIContext::EndStream
void EndStream() override
Definition: mhi.cpp:1080
MHIContext::BeginVideo
bool BeginVideo(int tag) override
Begin displaying video.
Definition: mhi.cpp:1126
MHIContext::m_display
std::list< MHIImageData * > m_display
Definition: mhi.h:202
MHIContext::GetStreamMaxPos
std::chrono::milliseconds GetStreamMaxPos() override
Definition: mhi.cpp:1152
MHIText::AddText
void AddText(int x, int y, const QString &str, MHRgba colour) override
Definition: mhi.cpp:1375
error
static void error(const char *str,...)
Definition: vbi.cpp:35
MHIContext::run
void run(void) override
Definition: mhi.cpp:238
MHInteractionChannel::status
static EStatus status()
Definition: mhegic.cpp:46
ACTION_PLAYBACK
#define ACTION_PLAYBACK
Definition: tv_actions.h:7
mythplayerui.h
MHIContext::ScaleVideoY
int ScaleVideoY(int n, bool roundup=false) const
Definition: mhi.cpp:786
MHIContext::MHIContext
MHIContext(InteractiveTV *parent)
Definition: mhi.cpp:75
MHIContext::m_dsmcc
Dsmcc * m_dsmcc
Definition: mhi.h:183
ACTION_6
#define ACTION_6
Definition: mythuiactions.h:10
mythdb.h
MHKeyLookup::MHKeyLookup
MHKeyLookup()
Definition: mhi.cpp:559
MHIContext::m_displayRect
QRect m_displayRect
Definition: mhi.h:222
MHStream
Definition: Stream.h:32
MHIDLA::m_height
int m_height
Height of the drawing.
Definition: mhi.h:356
ACTION_DOWN
#define ACTION_DOWN
Definition: mythuiactions.h:17
ACTION_TEXTEXIT
#define ACTION_TEXTEXIT
Definition: tv_actions.h:81
MHIContext::m_tuneInfo
QList< int > m_tuneInfo
Definition: mhi.h:216
MHInteractionChannel::kError
@ kError
Definition: mhegic.h:35
MHIText::Clear
void Clear(void) override
Definition: mhi.cpp:1359
MHIDLA::DrawRect
void DrawRect(int x, int y, int width, int height, MHRgba colour)
Definition: mhi.cpp:1459
ACTION_0
#define ACTION_0
Definition: mythuiactions.h:4
MHIDLA::m_lineWidth
int m_lineWidth
Current line width.
Definition: mhi.h:362
MHDLADisplay
Definition: freemheg.h:174
MHIContext::GetChannelIndex
int GetChannelIndex(const QString &str) override
Definition: mhi.cpp:900
MHIContext::CheckCarouselObject
bool CheckCarouselObject(const QString &objectPath) override
Definition: mhi.cpp:365
MThread::wait
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:303
MHIContext::Nid
static int Nid(ChannelCache_t::const_iterator it)
Definition: mhi.h:232
x2
static int x2
Definition: mythsocket.cpp:58
MHIDLA::DrawArcSector
void DrawArcSector(int x, int y, int width, int height, int start, int arc, bool isSector) override
Definition: mhi.cpp:1695
MHInteractionChannel::GetFile
EResult GetFile(const QString &csPath, QByteArray &data, const QByteArray &cert=QByteArray())
Definition: mhegic.cpp:109
MHIContext::m_keyProfile
int m_keyProfile
Definition: mhi.h:192
MHIContext::SetStreamPos
std::chrono::milliseconds SetStreamPos(std::chrono::milliseconds pos) override
Definition: mhi.cpp:1158
kTuneKeepChnl
const unsigned kTuneKeepChnl
Definition: mhi.cpp:60
kTuneQuietly
const unsigned kTuneQuietly
Definition: mhi.cpp:53
MHIBitmap::CreateFromPNG
void CreateFromPNG(const unsigned char *data, int length) override
Create bitmap from PNG.
Definition: mhi.cpp:1841
MHIContext::Reinit
void Reinit(QRect videoRect, QRect dispRect, float aspect)
The display area has changed.
Definition: mhi.cpp:633
MythPlayerCaptionsUI::SetInteractiveStream
void SetInteractiveStream(const QString &Stream)
MHRgba::alpha
int alpha() const
Definition: freemheg.h:91
MythPainter::GetFormatImage
MythImage * GetFormatImage()
Returns a blank reference counted image in the format required for the Draw functions for this painte...
Definition: mythpainter.cpp:540
MHIContext::m_engineThread
MThread * m_engineThread
Definition: mhi.h:207
MHIContext::kStdDisplayHeight
static const int kStdDisplayHeight
Definition: mhi.h:168
MythAVFrame
MythAVFrame little utility class that act as a safe way to allocate an AVFrame which can then be allo...
Definition: mythaverror.h:52
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:16
MHIContext::Scale
QRect Scale(QRect r) const
Definition: mhi.cpp:775
MHIBitmap::m_image
QImage m_image
Definition: mhi.h:306
MHKeyLookup::key
void key(const QString &name, int code, int r1, int r2=0, int r3=0, int r4=0, int r5=0, int r6=0, int r7=0, int r8=0, int r9=0)
Definition: mhi.cpp:536
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:202
DSMCCPacket::m_length
int m_length
Definition: mhi.h:386
mythdbcon.h
ACTION_2
#define ACTION_2
Definition: mythuiactions.h:6
GetFontsDir
QString GetFontsDir(void)
Definition: mythdirs.cpp:309
MHEG::StreamStarted
virtual void StreamStarted(MHStream *, bool bStarted=true)=0
ft_loaded
static bool ft_loaded
Definition: mhi.cpp:44
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:607
MHIContext::GetDSMCCObject
bool GetDSMCCObject(const QString &objectPath, QByteArray &result)
Definition: mhi.cpp:389
MythPlayerCaptionsUI::GetStreamPos
std::chrono::milliseconds GetStreamPos()
Definition: mythplayercaptionsui.cpp:636
MHIContext::NetworkBootRequested
void NetworkBootRequested(void)
Definition: mhi.cpp:337
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
ACTION_MENUYELLOW
#define ACTION_MENUYELLOW
Definition: tv_actions.h:79
MHIContext::m_face
FT_Face m_face
Definition: mhi.h:204
FONT_WIDTHRES
#define FONT_WIDTHRES
Definition: mhi.cpp:47
MHIContext::QueueDSMCCPacket
void QueueDSMCCPacket(unsigned char *data, int length, int componentTag, unsigned carouselId, int dataBroadcastId)
Definition: mhi.cpp:292
MHIContext::CheckAccess
bool CheckAccess(const QString &objectPath, QByteArray &cert)
Definition: mhi.cpp:401
MHIText::m_image
QImage m_image
Definition: mhi.h:255
mythdirs.h
MHIBitmap::m_parent
MHIContext * m_parent
Definition: mhi.h:304
MHIContext::m_engineWait
QWaitCondition m_engineWait
Definition: mhi.h:197
MHIContext::m_engine
MHEG * m_engine
Definition: mhi.h:194
MythRect
Wrapper around QRect allowing us to handle percentage and other relative values for areas in mythui.
Definition: mythrect.h:17
MHIContext::BeginStream
bool BeginStream(const QString &str, MHStream *notify) override
Begin playing the specified stream.
Definition: mhi.cpp:1035
MHIContext::m_currentChannel
int m_currentChannel
Definition: mhi.h:209
MHIContext::GetServiceInfo
bool GetServiceInfo(int channelId, int &netId, int &origNetId, int &transportId, int &serviceId) override
Get netId etc from the channel index.
Definition: mhi.cpp:985
MHIContext::ClearQueue
void ClearQueue(void)
Definition: mhi.cpp:146
mythuiimage.h
MythUIType::DeleteAllChildren
void DeleteAllChildren(void)
Delete all child widgets.
Definition: mythuitype.cpp:215
MHIDLA::m_boxFillColour
MHRgba m_boxFillColour
Fill colour for the background.
Definition: mhi.h:359
MHIContext::OfferKey
bool OfferKey(const QString &key)
Definition: mhi.cpp:617
MHIContext::BeginAudio
bool BeginAudio(int tag) override
Begin playing audio.
Definition: mhi.cpp:1106
MHKeyLookup
Definition: mhi.cpp:519
tmp
static guint32 * tmp
Definition: goom_core.cpp:31
MHEG::SetBooting
virtual void SetBooting()=0
lineSeg::m_xBottom
int m_xBottom
Definition: mhi.cpp:1705
MHIImageData::m_image
QImage m_image
Definition: mhi.cpp:69
MHInteractionChannel::kSuccess
@ kSuccess
Definition: mhegic.h:35
MHIContext::m_videoTag
int m_videoTag
Definition: mhi.h:215
MHIContext::DrawRect
void DrawRect(int xPos, int yPos, int width, int height, MHRgba colour) override
Additional drawing functions.
Definition: mhi.cpp:1193
MHIContext::Sid
static int Sid(ChannelCache_t::const_iterator it)
Definition: mhi.h:233
MHIContext::ScaleY
int ScaleY(int n, bool roundup=false) const
Definition: mhi.cpp:770
AVFrame
struct AVFrame AVFrame
Definition: BorderDetector.h:15
ACTION_8
#define ACTION_8
Definition: mythuiactions.h:12
MHIBitmap::m_opaque
bool m_opaque
Definition: mhi.h:307
MHInteractionChannel::kPending
@ kPending
Definition: mhegic.h:35
MHIImageData::m_x
int m_x
Definition: mhi.cpp:70
MHIImageData::m_bUnder
bool m_bUnder
Definition: mhi.cpp:72
MHIText::m_fontSize
int m_fontSize
Definition: mhi.h:256
MHIContext::CreateBitmap
MHBitmapDisplay * CreateBitmap(bool tiled) override
Definition: mhi.cpp:1187
MHIContext::m_keyQueue
MythDeque< int > m_keyQueue
Definition: mhi.h:191
mythlogging.h
ACTION_MENURED
#define ACTION_MENURED
Definition: tv_actions.h:77
GetConfDir
QString GetConfDir(void)
Definition: mythdirs.cpp:224
MHIContext::SetInputRegister
void SetInputRegister(int num) override
Definition: mhi.cpp:659
MHIText::m_width
int m_width
Definition: mhi.h:259
tv_actions.h
MHIContext::Key_t
QPair< int, int > Key_t
Definition: mhi.h:226
ACTION_RIGHT
#define ACTION_RIGHT
Definition: mythuiactions.h:19
MHIDLA::m_lineColour
MHRgba m_lineColour
Current line colour.
Definition: mhi.h:360
MHIContext::m_faceLoaded
bool m_faceLoaded
Definition: mhi.h:205
MHIContext::m_videoRect
QRect m_videoRect
Definition: mhi.h:221
MHIContext::StopVideo
void StopVideo() override
Stop displaying video.
Definition: mhi.cpp:1140
lineSeg
Definition: mhi.cpp:1705
hardwareprofile.i18n.t
t
Definition: i18n.py:36
kTuneCarReset
const unsigned kTuneCarReset
Definition: mhi.cpp:56
MHIContext::m_stop
bool m_stop
Definition: mhi.h:198
MHIBitmap::Draw
void Draw(int x, int y, QRect rect, bool tiled, bool bUnder) override
Draw the completed drawing onto the display.
Definition: mhi.cpp:1813
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:539
MHEG::EngineEvent
virtual void EngineEvent(int)=0
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
MHIBitmap::m_copyCtx
MythAVCopy * m_copyCtx
Definition: mhi.h:308
MythPlayerCaptionsUI::SetAudioByComponentTag
bool SetAudioByComponentTag(int Tag)
Selects the audio stream using the DVB component tag.
Definition: mythplayercaptionsui.cpp:588
MHIDLA::DrawLineSub
void DrawLineSub(int x1, int y1, int x2, int y2, bool swapped)
Definition: mhi.cpp:1583
GetShareDir
QString GetShareDir(void)
Definition: mythdirs.cpp:222
x1
static int x1
Definition: mythsocket.cpp:57
MHIContext::GetInitialStreams
void GetInitialStreams(int &audioTag, int &videoTag) const
Get the initial component tags.
Definition: mhi.cpp:744
DSMCCPacket::m_dataBroadcastId
int m_dataBroadcastId
Definition: mhi.h:389
ACTION_PAUSE
#define ACTION_PAUSE
Definition: tv_actions.h:15
MHEG::RunAll
virtual std::chrono::milliseconds RunAll(void)=0
MHIContext::m_keyLock
QMutex m_keyLock
Definition: mhi.h:190
MythPlayerCaptionsUI::ResizeForInteractiveTV
void ResizeForInteractiveTV(const QRect &Rect)
MHIContext::m_audioTag
int m_audioTag
Definition: mhi.h:214
MythImage::DecrRef
int DecrRef(void) override
Decrements reference count and deletes on 0.
Definition: mythimage.cpp:54
MHIBitmap::~MHIBitmap
~MHIBitmap() override
Definition: mhi.cpp:1808
MHIDLA::m_image
QImage m_image
Definition: mhi.h:354
MHIContext::ScaleVideoX
int ScaleVideoX(int n, bool roundup=false) const
Definition: mhi.cpp:781
MHIContext::m_parent
InteractiveTV * m_parent
Definition: mhi.h:180
Dsmcc::GetDSMCCObject
int GetDSMCCObject(QStringList &objectPath, QByteArray &result)
Definition: dsmcc.cpp:545
MHIContext::m_currentSource
int m_currentSource
Definition: mhi.h:212
MHIText::GetBounds
QRect GetBounds(const QString &str, int &strLen, int maxSize=-1) override
Definition: mhi.cpp:1282
ACTION_SELECT
#define ACTION_SELECT
Definition: mythuiactions.h:15
Dsmcc::ProcessSection
void ProcessSection(const unsigned char *data, int length, int componentTag, unsigned carouselId, int dataBroadcastId)
Definition: dsmcc.cpp:446
MHEG::DrawDisplay
virtual void DrawDisplay(const QRegion &toDraw)=0
ACTION_SEEKRWND
#define ACTION_SEEKRWND
Definition: tv_actions.h:42
DSMCCPacket::m_data
unsigned char * m_data
Definition: mhi.h:385
MHIDLA::m_fillColour
MHRgba m_fillColour
Current fill colour.
Definition: mhi.h:361
MHBitmapDisplay
Definition: freemheg.h:211
MHIBitmap::ScaleImage
void ScaleImage(int newWidth, int newHeight) override
Scale the bitmap. Only used for image derived from MPEG I-frames.
Definition: mhi.cpp:1978
MHIDLA::DrawLine
void DrawLine(int x1, int y1, int x2, int y2) override
Definition: mhi.cpp:1561
ACTION_STOP
#define ACTION_STOP
Definition: tv_actions.h:8
FONT_HEIGHTRES
#define FONT_HEIGHTRES
Definition: mhi.cpp:48
mythpainter.h
MHRgba::blue
int blue() const
Definition: freemheg.h:90
MHCreateEngine
MHEG * MHCreateEngine(MHContext *context)
Definition: Engine.cpp:43
MHInteractionChannel::CheckFile
bool CheckFile(const QString &csPath, const QByteArray &cert=QByteArray())
Definition: mhegic.cpp:75
uint
unsigned int uint
Definition: compat.h:144
ACTION_9
#define ACTION_9
Definition: mythuiactions.h:13
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
MHIText::m_fontItalic
bool m_fontItalic
Definition: mhi.h:257
interactivescreen.h
MHIText::m_fontBold
bool m_fontBold
Definition: mhi.h:258
ACTION_4
#define ACTION_4
Definition: mythuiactions.h:8
MHIContext::m_dsmccQueue
MythDeque< DSMCCPacket * > m_dsmccQueue
Definition: mhi.h:185
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:936
MHIBitmap::MHIBitmap
MHIBitmap(MHIContext *parent, bool tiled)
Definition: mhi.cpp:1802
MHIContext::StreamPlay
void StreamPlay(bool play) override
Definition: mhi.cpp:1167
MHIContext::ScaleVideo
QRect ScaleVideo(QRect r) const
Definition: mhi.cpp:791
ACTION_1
#define ACTION_1
Definition: mythuiactions.h:5
MHIDLA::m_boxed
bool m_boxed
Does it have a border?
Definition: mhi.h:357
ACTION_MENUTEXT
#define ACTION_MENUTEXT
Definition: tv_actions.h:82
Dsmcc::Reset
void Reset()
Definition: dsmcc.cpp:536
GET_KEY
#define GET_KEY(a, b)
Definition: mythmainwindow.h:20
MHIText::SetSize
void SetSize(int width, int height) override
Definition: mhi.cpp:1248
MHIContext::StopEngine
void StopEngine(void)
Stop the MHEG engine if it's running and waits until it has.
Definition: mhi.cpp:154
kShift
const int kShift
Definition: mhi.cpp:1264
MHIContext::m_videoDisplayRect
QRect m_videoDisplayRect
Definition: mhi.h:221
MHKeyLookup::key_t
QPair< QString, int > key_t
Definition: mhi.cpp:521
MHIBitmap::CreateFromMPEG
void CreateFromMPEG(const unsigned char *data, int length) override
Create bitmap from single I frame MPEG.
Definition: mhi.cpp:1876
MHIBitmap
Object for drawing bitmaps.
Definition: mhi.h:266
MythPlayerCaptionsUI::GetStreamMaxPos
std::chrono::milliseconds GetStreamMaxPos()
Definition: mythplayercaptionsui.cpp:642
MHIText::SetFont
void SetFont(int size, bool isBold, bool isItalic) override
Definition: mhi.cpp:1254
ACTION_MENUBLUE
#define ACTION_MENUBLUE
Definition: tv_actions.h:80
ACTION_7
#define ACTION_7
Definition: mythuiactions.h:11
MHIContext::m_dsmccLock
QMutex m_dsmccLock
Definition: mhi.h:184
MHIText::m_parent
MHIContext * m_parent
Definition: mhi.h:254
mythimage.h
InteractiveScreen
Definition: interactivescreen.h:9
MHIContext::Cid
static int Cid(ChannelCache_t::const_iterator it)
Definition: mhi.h:231
MHIDLA::m_parent
MHIContext * m_parent
Definition: mhi.h:353
MHIContext::StreamStarted
bool StreamStarted(bool bStarted=true)
Definition: mhi.cpp:1090
DSMCCPacket
Data for the queued DSMCC tables.
Definition: mhi.h:368
VERBOSE_LEVEL_CHECK
#define VERBOSE_LEVEL_CHECK(_MASK_, _LEVEL_)
Definition: mythlogging.h:14
MHIContext::UpdateOSD
void UpdateOSD(InteractiveScreen *osdWindow, MythPainter *osdPainter)
Update the display.
Definition: mhi.cpp:674
MHIContext::CreateDynamicLineArt
MHDLADisplay * CreateDynamicLineArt(bool isBoxed, MHRgba lineColour, MHRgba fillColour) override
Creation functions for various visibles.
Definition: mhi.cpp:1174
InteractiveScreen::OptimiseDisplayedArea
void OptimiseDisplayedArea()
Definition: interactivescreen.cpp:34
MHIContext::m_channelMutex
QMutex m_channelMutex
Definition: mhi.h:229
Dsmcc
Definition: dsmcc.h:77
MHIContext::LoadFont
bool LoadFont(const QString &name)
Definition: mhi.cpp:95
mythcorecontext.h
FONT_TO_USE
#define FONT_TO_USE
Definition: mhi.cpp:49
MHIBitmap::CreateFromJPEG
void CreateFromJPEG(const unsigned char *data, int length) override
Create bitmap from JPEG.
Definition: mhi.cpp:1857
ACTION_MENUGREEN
#define ACTION_MENUGREEN
Definition: tv_actions.h:78
MythPlayerCaptionsUI::SetInteractiveStreamPos
void SetInteractiveStreamPos(std::chrono::milliseconds Position)
MythPainter
Definition: mythpainter.h:32
MythImage
Definition: mythimage.h:36
MHKeyLookup::m_map
QHash< key_t, int > m_map
Definition: mhi.cpp:533
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:882
MHIDLA::Clear
void Clear(void) override
Clear the drawing.
Definition: mhi.cpp:1501
MHEG::GenerateUserAction
virtual void GenerateUserAction(int nCode)=0
MHIContext::Val_t
QPair< int, int > Val_t
Definition: mhi.h:225
mythavutil.h
MHRgba::red
int red() const
Definition: freemheg.h:88
MHIContext::ClearDisplay
void ClearDisplay(void)
Definition: mhi.cpp:137
MythUIType::SetVisible
virtual void SetVisible(bool visible)
Definition: mythuitype.cpp:1098
MHIContext::m_channelCache
ChannelCache_t m_channelCache
Definition: mhi.h:228
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:48
MHIContext::LoadChannelCache
bool LoadChannelCache()
Definition: mhi.cpp:865
MHIText
Definition: mhi.h:237
Roundup
int Roundup(int n, int r)
Definition: mhi.cpp:832
MHRgba::green
int green() const
Definition: freemheg.h:89
MHIDLA::Draw
void Draw(int x, int y) override
Draw the completed drawing onto the display.
Definition: mhi.cpp:1513
ACTION_JUMPFFWD
#define ACTION_JUMPFFWD
Definition: tv_actions.h:44
mthread.h
Point2FT
static FT_F26Dot6 Point2FT(int pt)
Definition: mhi.cpp:1265
MHIContext::ScaleX
int ScaleX(int n, bool roundup=false) const
Definition: mhi.cpp:765
MHIContext::m_nbiData
std::vector< unsigned char > m_nbiData
Definition: mhi.h:219
build_compdb.action
action
Definition: build_compdb.py:9
MythAVCopy
Definition: mythavutil.h:47
ACTION_LEFT
#define ACTION_LEFT
Definition: mythuiactions.h:18
MHIContext::RequireRedraw
void RequireRedraw(const QRegion &region) override
An area of the screen/image needs to be redrawn.
Definition: mhi.cpp:754
MHIContext::GetCarouselData
bool GetCarouselData(const QString &objectPath, QByteArray &result) override
Definition: mhi.cpp:441
interactivetv.h
ACTION_5
#define ACTION_5
Definition: mythuiactions.h:9
MythPlayerCaptionsUI::SetVideoByComponentTag
bool SetVideoByComponentTag(int Tag)
Selects the video stream using the DVB component tag.
Definition: mythplayercaptionsui.cpp:600
MHIContext
Contains various utility functions for interactive television.
Definition: mhi.h:49
kTuneKeepApp
const unsigned kTuneKeepApp
Definition: mhi.cpp:54
mythuiactions.h
MHIDLA::DrawPoly
void DrawPoly(bool isFilled, const MHPointVec &xArray, const MHPointVec &yArray) override
Definition: mhi.cpp:1707
MHIText::m_height
int m_height
Definition: mhi.h:260
MHIContext::ProcessDSMCCQueue
void ProcessDSMCCQueue(void)
Definition: mhi.cpp:273
lineSeg::m_yTop
int m_yTop
Definition: mhi.cpp:1705
NBI_VERSION_UNSET
#define NBI_VERSION_UNSET
Definition: mhi.h:44
lineSeg::m_yBottom
int m_yBottom
Definition: mhi.cpp:1705
MHIContext::DrawImage
void DrawImage(int x, int y, QRect rect, const QImage &image, bool bScaled=false, bool bUnder=false)
Definition: mhi.cpp:1210
MHIContext::StopAudio
void StopAudio() override
Stop playing audio.
Definition: mhi.cpp:1120
MHIContext::AddToDisplay
void AddToDisplay(const QImage &image, QRect rect, bool bUnder=false)
Definition: mhi.cpp:797
round
#define round(x)
Definition: mythplayer.cpp:59
lineSeg::m_slope
float m_slope
Definition: mhi.cpp:1705
kTuneCarId
const unsigned kTuneCarId
Definition: mhi.cpp:55
MHIImageData
Data for items in the interactive television display stack.
Definition: mhi.cpp:66
MythImage::Assign
void Assign(const QImage &img)
Definition: mythimage.cpp:79
InteractiveTV
This is the interface between an MHEG engine and a MythTV TV object.
Definition: interactivetv.h:15
MythDeque::enqueue
void enqueue(T d)
Adds item to the back of the list. O(1).
Definition: mythdeque.h:42
MythAVCopy::Copy
int Copy(AVFrame *To, const MythVideoFrame *From, unsigned char *Buffer, AVPixelFormat Fmt=AV_PIX_FMT_YUV420P)
Initialise AVFrame and copy contents of VideoFrame frame into it, performing any required conversion.
Definition: mythavutil.cpp:229
MHIContext::SetNetBootInfo
void SetNetBootInfo(const unsigned char *data, uint length)
Definition: mhi.cpp:312
MHIDLA
Object for displaying Dynamic Line Art.
Definition: mhi.h:314
MHIContext::~MHIContext
~MHIContext() override
Definition: mhi.cpp:125
MHIContext::GetStreamPos
std::chrono::milliseconds GetStreamPos() override
Definition: mhi.cpp:1146
FT2Point
static int FT2Point(FT_F26Dot6 fp)
Definition: mhi.cpp:1270
ACTION_MENUEPG
#define ACTION_MENUEPG
Definition: tv_actions.h:83
ft_library
static FT_Library ft_library
Definition: mhi.cpp:45
MHIContext::Tid
static int Tid(ChannelCache_t::const_iterator it)
Definition: mhi.h:230
MHIContext::DrawVideo
void DrawVideo(const QRect &videoRect, const QRect &dispRect) override
Definition: mhi.cpp:841
MythDeque::dequeue
T dequeue()
Removes item from front of list and returns a copy. O(1).
Definition: mythdeque.h:32
MHIDLA::m_width
int m_width
Width of the drawing.
Definition: mhi.h:355
MHTextDisplay
Definition: freemheg.h:195
mythmainwindow.h
MHIDLA::m_boxLineColour
MHRgba m_boxLineColour
Line colour for the background.
Definition: mhi.h:358
MHIContext::TuneTo
bool TuneTo(int channel, int tuneinfo) override
Definition: mhi.cpp:1010
dsmcc.h
MythCoreContext::dispatch
void dispatch(const MythEvent &event)
Definition: mythcorecontext.cpp:1749
MHKeyLookup::Find
int Find(const QString &name, int reg) const
Definition: mhi.cpp:526
mhi.h
ACTION_SEEKFFWD
#define ACTION_SEEKFFWD
Definition: tv_actions.h:43
DSMCCPacket::m_componentTag
int m_componentTag
Definition: mhi.h:387
MHIDLA::DrawBorderedRectangle
void DrawBorderedRectangle(int x, int y, int width, int height) override
Definition: mhi.cpp:1657
av_make_error_stdstring
char * av_make_error_stdstring(std::string &errbuf, int errnum)
Definition: mythaverror.cpp:41
InteractiveTV::GetPlayer
MythPlayerCaptionsUI * GetPlayer(void)
Definition: interactivetv.h:51
MHIContext::DrawBackground
void DrawBackground(const QRegion &reg) override
Definition: mhi.cpp:1233
DSMCCPacket::m_carouselId
unsigned m_carouselId
Definition: mhi.h:388
MHRgba
Definition: freemheg.h:82
MHIContext::m_runLock
QMutex m_runLock
Definition: mhi.h:196
MHPointVec
std::vector< int > MHPointVec
Definition: BaseClasses.h:34
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:831
MHIContext::m_displayLock
QMutex m_displayLock
Definition: mhi.h:199
MHIContext::GetICStatus
int GetICStatus() override
Definition: mhi.cpp:667
MHIContext::kStdDisplayWidth
static const int kStdDisplayWidth
Definition: mhi.h:167