10 #include <QStringList>
42 #include "libavutil/imgutils.h"
77 : m_parent(parent), m_dsmcc(new
Dsmcc()),
99 QByteArray fnameA = fullnameA.toLatin1();
105 QByteArray fnameB = fullnameB.toLatin1();
110 QString fullnameC =
GetShareDir() +
"themes/" + name;
111 QByteArray fnameC = fullnameC.toLatin1();
116 const QString& fullnameD = name;
117 QByteArray fnameD = fullnameD.toLatin1();
122 LOG(VB_GENERAL, LOG_ERR, QString(
"[mhi] Unable to find font: %1").arg(name));
176 LOG(VB_MHEG, LOG_INFO,
177 QString(
"[mhi] Restart ch=%1 source=%2 live=%3 tuneinfo=0x%4")
178 .arg(chanid).arg(sourceid).arg(isLive).arg(tuneinfo,0,16));
245 std::chrono::milliseconds toWait = 0ms;
266 toWait = (toWait > 1s || toWait <= 0ms) ? 1s : toWait;
268 if (!
m_stop && (toWait > 0ms))
294 unsigned char *data,
int length,
int componentTag,
295 unsigned carouselId,
int dataBroadcastId)
297 auto *dataCopy = (
unsigned char*) malloc(length *
sizeof(
unsigned char));
299 if (dataCopy ==
nullptr)
302 memcpy(dataCopy, data, length*
sizeof(
unsigned char));
306 componentTag, carouselId,
318 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] SetNetBootInfo version %1 mode %2 len %3")
319 .arg(data[0]).arg(data[1]).arg(length));
358 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Unknown NetworkBoot type %1")
368 if (objectPath.startsWith(
"http:") || objectPath.startsWith(
"https:"))
379 QStringList path = objectPath.split(QChar(
'/'), Qt::SkipEmptyParts);
388 QStringList path = objectPath.split(QChar(
'/'), Qt::SkipEmptyParts);
402 LOG(VB_MHEG, LOG_INFO, QString(
403 "[mhi] CheckAccess(%1) No auth.servers").arg(objectPath) );
407 QByteArray host = QUrl(objectPath).host().toLocal8Bit();
408 if (!servers.contains(host))
410 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] CheckAccess(%1) Host not known")
412 LOG(VB_MHEG, LOG_DEBUG, QString(
"[mhi] Permitted servers: %1")
413 .arg(servers.constData()) );
416 if (!objectPath.startsWith(
"https:"))
420 if (!objectPath.startsWith(
"https:"))
437 bool const isIC = objectPath.startsWith(
"http:") || objectPath.startsWith(
"https:");
447 QStringList path = objectPath.split(QChar(
'/'), Qt::SkipEmptyParts);
452 bool bReported =
false;
453 QElapsedTimer
t;
t.start();
462 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Received %1").arg(objectPath));
466 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Not found %1").arg(objectPath));
479 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Received %1").arg(objectPath));
486 if (
t.hasExpired(60000))
489 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] timed out %1").arg(objectPath));
496 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Waiting for %1").arg(objectPath));
510 using key_t = QPair< QString,
int >;
515 int Find(
const QString &name,
int reg)
const
519 void key(
const QString &name,
int code,
int r1,
520 int r2=0,
int r3=0,
int r4=0,
int r5=0,
int r6=0,
int r7=0,
int r8=0,
int r9=0);
526 int r2,
int r3,
int r4,
int r5,
int r6,
int r7,
int r8,
int r9)
554 QStringList keylist =
GET_KEY(
"TV Playback",
"TEXTEXIT").split(QChar(
','));
555 bool strict = !keylist.contains(
"Esc", Qt::CaseInsensitive);
592 #if 0 // These conflict with left & right
613 LOG(VB_GENERAL, LOG_INFO, QString(
"[mhi] Adding MHEG key %1:%2:%3")
624 LOG(VB_MHEG, LOG_INFO,
625 QString(
"[mhi] Reinit video(y:%1 x:%2 w:%3 h:%4) "
626 "vis(y:%5 x:%6 w:%7 h:%8) aspect=%9")
627 .arg(videoRect.y()).arg(videoRect.x())
628 .arg(videoRect.width()).arg(videoRect.height())
629 .arg(dispRect.y()).arg(dispRect.x())
630 .arg(dispRect.width()).arg(dispRect.height()).arg(aspect));
634 enum { kNone, kHoriz, kBoth };
636 auto const aspectd =
static_cast<double>(aspect);
637 double const vz = (mode == kBoth) ? std::min(1.15, 1. / sqrt(aspectd)) : 1.;
638 double const hz = (mode > kNone) ? vz * aspectd : 1.;
641 int(dispRect.height() * (1 - vz) / 2),
642 int(dispRect.width() * hz),
int(dispRect.height() * vz) );
644 dispRect.y() +
int(dispRect.height() * (1 - hz) / 2),
645 int(dispRect.width() * hz),
int(dispRect.height() * hz) );
650 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] SetInputRegister %1").arg(num));
666 if (!osdWindow || !osdPainter)
682 QRect imageRect(data->
m_x, data->
m_y,
694 rect.width(), rect.height());
697 newData->m_x = rect.x();
698 newData->m_y = rect.y();
699 newData->m_bUnder =
true;
711 for (
int count = 0; it !=
m_display.end(); ++it, count++)
719 auto *uiimage =
new MythUIImage(osdWindow, QString(
"itv%1").arg(count));
722 uiimage->SetImage(image);
767 QSize(
ScaleX(r.width(),
true),
ScaleY(r.height(),
true)) };
788 const QRect scaledRect =
Scale(displayRect);
792 data->
m_image = image.convertToFormat(QImage::Format_ARGB32).scaled(
793 scaledRect.width(), scaledRect.height(),
794 Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
795 data->m_x = scaledRect.x();
796 data->m_y = scaledRect.y();
797 data->m_bUnder = bUnder;
824 return n + (-n & (r - 1));
839 vidRect.setWidth(
Roundup(vidRect.width(), 2));
840 vidRect.setHeight(
Roundup(vidRect.height(), 2));
858 "SELECT networkid, serviceid, transportid, chanid "
859 "FROM channel, dtv_multiplex "
860 "WHERE channel.deleted IS NULL "
861 " AND channel.mplexid = dtv_multiplex.mplexid "
862 " AND channel.sourceid = dtv_multiplex.sourceid "
863 " AND channel.sourceid = :SOURCEID ;" );
874 int nid = query.
value(0).toInt();
875 int sid = query.
value(1).toInt();
876 int tid = query.
value(2).toInt();
877 int cid = query.
value(3).toInt();
895 if (str.startsWith(
"dvb://"))
897 QStringList list = str.mid(6).split(
'.');
898 if (list.size() != 3)
903 int netID = list[0].toInt(&ok, 16);
906 int transportID = !list[1].isEmpty() ? list[1].toInt(&ok, 16) : -1;
909 int serviceID = list[2].toInt(&ok, 16);
918 Key_t(netID,serviceID) );
927 if (
Tid(it) == transportID)
936 else if (str.startsWith(
"rec://svc/lcn/"))
940 int channelNo = str.mid(14).toInt(&ok);
946 "WHERE deleted IS NULL AND "
947 " channum = :CHAN AND "
948 " channel.sourceid = :SOURCEID");
952 nResult = query.
value(0).toInt();
954 else if (str ==
"rec://svc/cur")
956 else if (str ==
"rec://svc/def")
960 LOG(VB_GENERAL, LOG_WARNING,
961 QString(
"[mhi] GetChannelIndex -- Unrecognized URL %1")
967 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] GetChannelIndex %1 => %2")
968 .arg(str).arg(nResult));
975 int &transportId,
int &serviceId)
983 if (
Cid(it) == channelId)
985 transportId =
Tid(it);
989 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] GetServiceInfo %1 => NID=%2 TID=%3 SID=%4")
990 .arg(channelId).arg(netId).arg(transportId).arg(serviceId));
995 LOG(VB_MHEG, LOG_WARNING, QString(
"[mhi] GetServiceInfo %1 failed").arg(channelId));
1003 LOG(VB_MHEG, LOG_WARNING, QString(
"[mhi] Can't TuneTo %1 0x%2 while not live")
1004 .arg(channel).arg(tuneinfo,0,16));
1008 LOG(VB_GENERAL, LOG_INFO, QString(
"[mhi] TuneTo %1 0x%2")
1009 .arg(channel).arg(tuneinfo,0,16));
1013 MythEvent me(QString(
"NETWORK_CONTROL CHANID %1").arg(channel));
1026 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] BeginStream %1 0x%2")
1027 .arg(stream).arg((quintptr)notify,0,16));
1033 if (stream.startsWith(
"http://") || stream.startsWith(
"https://"))
1038 if (QUrl(stream).authority().isEmpty())
1042 return !stream.isEmpty();
1052 int transportId = 0;
1071 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] EndStream 0x%1")
1084 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Stream 0x%1 %2")
1085 .arg((quintptr)
m_notify,0,16).arg(bStarted ?
"started" :
"stopped"));
1097 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] BeginAudio %1").arg(tag));
1117 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] BeginVideo %1").arg(tag));
1166 return new MHIDLA(
this, isBoxed, lineColour, fillColour);
1185 if (colour.
alpha() == 0 || height == 0 || width == 0)
1188 QImage qImage(width, height, QImage::Format_ARGB32);
1189 qImage.fill(qRgba(colour.
red(), colour.
green(), colour.
blue(), colour.
alpha()));
1191 AddToDisplay(qImage, QRect(xPos, yPos, width, height));
1200 const QImage &qImage,
bool bScaled,
bool bUnder)
1202 if (qImage.isNull())
1205 QRect imageRect(x, y, qImage.width(), qImage.height());
1206 QRect displayRect = clipRect & imageRect;
1208 if (bScaled || displayRect == imageRect)
1212 else if (!displayRect.isEmpty())
1214 QImage clipped = qImage.copy(displayRect.translated(-x, -y));
1227 QRect bounds = reg.boundingRect();
1228 DrawRect(bounds.x(), bounds.y(), bounds.width(), bounds.height(),
1282 int maxAscent = face->size->metrics.ascender;
1283 int maxDescent = -face->size->metrics.descender;
1285 FT_Bool useKerning = FT_HAS_KERNING(face);
1286 FT_UInt previous = 0;
1288 for (
int n = 0; n < strLen; n++)
1290 QChar ch = str.at(n);
1291 FT_UInt glyphIndex = FT_Get_Char_Index(face, ch.unicode());
1293 if (glyphIndex == 0)
1295 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Unknown glyph 0x%1")
1296 .arg(ch.unicode(),0,16));
1303 if (useKerning && previous != 0)
1306 FT_Get_Kerning(face, previous, glyphIndex,
1307 FT_KERNING_DEFAULT, &delta);
1311 error = FT_Load_Glyph(face, glyphIndex, 0);
1316 FT_GlyphSlot slot = face->glyph;
1317 FT_Pos advance = slot->metrics.horiAdvance + kerning;
1321 if (
FT2Point(width + advance) > maxSize)
1329 int descent = slot->metrics.height - slot->metrics.horiBearingY;
1331 if (slot->metrics.horiBearingY > maxAscent)
1332 maxAscent = slot->metrics.horiBearingY;
1334 if (descent > maxDescent)
1335 maxDescent = descent;
1338 previous = glyphIndex;
1354 for (
int j = 0; j <
m_width; j++)
1356 m_image.setPixel(j, i, qRgba(0, 0, 0, 0));
1376 FT_Bool useKerning = FT_HAS_KERNING(face);
1377 FT_UInt previous = 0;
1379 int len = str.length();
1380 for (
int n = 0; n < len; n++)
1384 FT_UInt glyphIndex = FT_Get_Char_Index(face, ch.unicode());
1385 if (glyphIndex == 0)
1391 if (useKerning && previous != 0)
1394 FT_Get_Kerning(face, previous, glyphIndex,
1395 FT_KERNING_DEFAULT, &delta);
1398 FT_Error
error = FT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
1403 FT_GlyphSlot slot = face->glyph;
1404 if (slot->format != FT_GLYPH_FORMAT_BITMAP)
1407 if ((
enum FT_Pixel_Mode_)slot->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
1410 unsigned char *source = slot->bitmap.buffer;
1412 int baseX =
FT2Point(posX) + slot->bitmap_left;
1413 int baseY = pixelY - slot->bitmap_top;
1415 for (
unsigned int i = 0; i < slot->bitmap.rows; i++)
1417 for (
unsigned int j = 0; j < slot->bitmap.width; j++)
1419 int greyLevel = source[j];
1422 int red = colour.
red();
1423 int green = colour.
green();
1424 int blue = colour.
blue();
1425 int alpha = colour.
alpha() *
1426 greyLevel / slot->bitmap.num_grays;
1427 int xBit = j + baseX;
1428 int yBit = i + baseY;
1433 if (xBit >= 0 && xBit <
m_width &&
1437 qRgba(red, green, blue, alpha));
1440 source += slot->bitmap.pitch;
1442 posX += slot->advance.x;
1443 previous = glyphIndex;
1450 QRgb qColour = qRgba(colour.
red(), colour.
green(),
1466 if (width <= 0 || height <= 0)
1469 int imageWidth =
m_image.width();
1470 int imageHeight =
m_image.height();
1471 if (x+width > imageWidth)
1472 width = imageWidth - x;
1474 if (y+height > imageHeight)
1475 height = imageHeight - y;
1477 if (width <= 0 || height <= 0)
1480 for (
int i = 0; i < height; i++)
1482 for (
int j = 0; j < width; j++)
1484 m_image.setPixel(x+j, y+i, qColour);
1554 if (abs(y2-y1) > abs(
x2-
x1))
1577 int dy = abs(y2-y1);
1578 int yStep = y2 >= y1 ? 1 : -1;
1597 for (
int x =
x1; x <=
x2; x++)
1608 m_image.setPixel(y+i, x+j, colour);
1613 m_image.setPixel(x+j, y+i, colour);
1626 m_image.setPixel(y+i, x+j, colour);
1631 m_image.setPixel(x+j, y+i, colour);
1698 int nPoints = xArray.size();
1704 QVector <lineSeg> lineArray(nPoints);
1709 int lastX = xArray[nPoints-1];
1710 int lastY = yArray[nPoints-1];
1713 for (
int k = 0; k < nPoints; k++)
1715 int thisX = xArray[k];
1716 int thisY = yArray[k];
1721 lineArray[nLines].m_yBottom = thisY;
1722 lineArray[nLines].m_yTop = lastY;
1723 lineArray[nLines].m_xBottom = thisX;
1727 lineArray[nLines].m_yBottom = lastY;
1728 lineArray[nLines].m_yTop = thisY;
1729 lineArray[nLines].m_xBottom = lastX;
1731 lineArray[nLines++].m_slope =
1732 (float)(thisX-lastX) / (float)(thisY-lastY);
1747 for (
int y = yMin; y < yMax; y++)
1752 for (
int l = 0; l < nLines; l++)
1754 if (y >= lineArray[l].m_yBottom && y < lineArray[l].m_yTop)
1756 int x = (int)round((
float)(y - lineArray[l].m_yBottom) *
1757 lineArray[l].m_slope) + lineArray[l].m_xBottom;
1758 if (crossings == 0 || x < xMin)
1760 if (crossings == 0 || x > xMax)
1767 for (
int x = xMin; x <= xMax; x++)
1768 m_image.setPixel(x, y, fillColour);
1773 int lastXpoint = xArray[nPoints-1];
1774 int lastYpoint = yArray[nPoints-1];
1775 for (
int i = 0; i < nPoints; i++)
1777 DrawLine(xArray[i], yArray[i], lastXpoint, lastYpoint);
1778 lastXpoint = xArray[i];
1779 lastYpoint = yArray[i];
1784 for (
int i = 1; i < nPoints; i++)
1786 DrawLine(xArray[i], yArray[i], xArray[i-1], yArray[i-1]);
1792 : m_parent(parent), m_tiled(tiled),
1810 QImage tiledImage = QImage(rect.width(), rect.height(),
1811 QImage::Format_ARGB32);
1813 for (
int i = 0; i < rect.width(); i++)
1815 for (
int j = 0; j < rect.height(); j++)
1834 if (!
m_image.loadFromData(data, length,
"PNG"))
1850 if (!
m_image.loadFromData(data, length,
"JPG"))
1867 AVCodecContext *c =
nullptr;
1870 uint8_t *buff =
nullptr;
1871 bool gotPicture =
false;
1875 const AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_MPEG2VIDEO);
1881 c = avcodec_alloc_context3(
nullptr);
1883 if (avcodec_open2(c, codec,
nullptr) < 0)
1887 if (av_new_packet(&pkt, length) < 0)
1890 memcpy(pkt.data, data, length);
1895 for (
int limit=0; limit<10 && !gotPicture; limit++)
1897 int len = avcodec_receive_frame(c, picture);
1900 if (len == AVERROR(EAGAIN))
1903 len = avcodec_send_packet(c, &pkt);
1904 if (len == AVERROR(EAGAIN) || len == AVERROR_EOF)
1909 LOG(VB_GENERAL, LOG_ERR,
1910 QString(
"[mhi] video decode error: %1 (%2)")
1924 int nContentWidth = c->width;
1925 int nContentHeight = c->height;
1926 m_image = QImage(nContentWidth, nContentHeight, QImage::Format_ARGB32);
1930 memset(&retbuf, 0,
sizeof(
AVFrame));
1932 int bufflen = nContentWidth * nContentHeight * 3;
1933 auto *outputbuf = (
unsigned char*)av_malloc(bufflen);
1935 av_image_fill_arrays(retbuf.data, retbuf.linesize,
1936 outputbuf, AV_PIX_FMT_RGB24,
1937 nContentWidth, nContentHeight,IMAGE_ALIGN);
1941 nContentWidth, nContentHeight);
1943 uint8_t * buf = outputbuf;
1947 for (
int i = 0; i < nContentHeight; i++)
1949 for (
int j = 0; j < nContentWidth; j++)
1954 m_image.setPixel(j, i, qRgb(red, green, blue));
1957 av_freep(&outputbuf);
1962 av_packet_unref(&pkt);
1963 avcodec_free_context(&c);
1972 if (newWidth ==
m_image.width() && newHeight ==
m_image.height())
1975 if (newWidth <= 0 || newHeight <= 0)
1982 Qt::IgnoreAspectRatio, Qt::SmoothTransformation);