10 #include <QStringList>
44 #include "libavutil/imgutils.h"
79 : m_parent(parent), m_dsmcc(new
Dsmcc()),
100 QString fullnameA =
GetConfDir() +
"/" + name;
101 QByteArray fnameA = fullnameA.toLatin1();
107 QByteArray fnameB = fullnameB.toLatin1();
112 QString fullnameC =
GetShareDir() +
"themes/" + name;
113 QByteArray fnameC = fullnameC.toLatin1();
118 const QString& fullnameD = name;
119 QByteArray fnameD = fullnameD.toLatin1();
124 LOG(VB_GENERAL, LOG_ERR, QString(
"[mhi] Unable to find font: %1").arg(name));
178 LOG(VB_MHEG, LOG_INFO,
179 QString(
"[mhi] Restart ch=%1 source=%2 live=%3 tuneinfo=0x%4")
180 .arg(chanid).arg(sourceid).arg(isLive).arg(tuneinfo,0,16));
247 std::chrono::milliseconds toWait = 0ms;
268 toWait = (toWait > 1s || toWait <= 0ms) ? 1s : toWait;
270 if (!
m_stop && (toWait > 0ms))
296 unsigned char *data,
int length,
int componentTag,
297 unsigned carouselId,
int dataBroadcastId)
299 auto *dataCopy = (
unsigned char*) malloc(length *
sizeof(
unsigned char));
301 if (dataCopy ==
nullptr)
304 memcpy(dataCopy, data, length*
sizeof(
unsigned char));
308 componentTag, carouselId,
320 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] SetNetBootInfo version %1 mode %2 len %3")
321 .arg(data[0]).arg(data[1]).arg(length));
360 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Unknown NetworkBoot type %1")
370 if (objectPath.startsWith(
"http:") || objectPath.startsWith(
"https:"))
381 QStringList path = objectPath.split(QChar(
'/'), Qt::SkipEmptyParts);
390 QStringList path = objectPath.split(QChar(
'/'), Qt::SkipEmptyParts);
404 LOG(VB_MHEG, LOG_INFO, QString(
405 "[mhi] CheckAccess(%1) No auth.servers").arg(objectPath) );
409 QByteArray host = QUrl(objectPath).host().toLocal8Bit();
410 if (!servers.contains(host))
412 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] CheckAccess(%1) Host not known")
414 LOG(VB_MHEG, LOG_DEBUG, QString(
"[mhi] Permitted servers: %1")
415 .arg(servers.constData()) );
418 if (!objectPath.startsWith(
"https:"))
422 if (!objectPath.startsWith(
"https:"))
439 bool const isIC = objectPath.startsWith(
"http:") || objectPath.startsWith(
"https:");
449 QStringList path = objectPath.split(QChar(
'/'), Qt::SkipEmptyParts);
454 bool bReported =
false;
455 QElapsedTimer
t;
t.start();
464 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Received %1").arg(objectPath));
468 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Not found %1").arg(objectPath));
481 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Received %1").arg(objectPath));
488 if (
t.hasExpired(60000))
491 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] timed out %1").arg(objectPath));
498 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Waiting for %1").arg(objectPath));
512 using key_t = QPair< QString,
int >;
517 int Find(
const QString &name,
int reg)
const
521 void key(
const QString &name,
int code,
int r1,
522 int r2=0,
int r3=0,
int r4=0,
int r5=0,
int r6=0,
int r7=0,
int r8=0,
int r9=0);
528 int r2,
int r3,
int r4,
int r5,
int r6,
int r7,
int r8,
int r9)
556 QStringList keylist =
GET_KEY(
"TV Playback",
"TEXTEXIT").split(QChar(
','));
557 bool strict = !keylist.contains(
"Esc", Qt::CaseInsensitive);
594 #if 0 // These conflict with left & right
615 LOG(VB_GENERAL, LOG_INFO, QString(
"[mhi] Adding MHEG key %1:%2:%3")
626 LOG(VB_MHEG, LOG_INFO,
627 QString(
"[mhi] Reinit video(y:%1 x:%2 w:%3 h:%4) "
628 "vis(y:%5 x:%6 w:%7 h:%8) aspect=%9")
629 .arg(videoRect.y()).arg(videoRect.x())
630 .arg(videoRect.width()).arg(videoRect.height())
631 .arg(dispRect.y()).arg(dispRect.x())
632 .arg(dispRect.width()).arg(dispRect.height()).arg(aspect));
636 enum : std::uint8_t { kNone, kHoriz, kBoth };
638 auto const aspectd =
static_cast<double>(aspect);
639 double const vz = (mode == kBoth) ? std::min(1.15, 1. / sqrt(aspectd)) : 1.;
640 double const hz = (mode > kNone) ? vz * aspectd : 1.;
643 int(dispRect.height() * (1 - vz) / 2),
644 int(dispRect.width() * hz),
int(dispRect.height() * vz) );
646 dispRect.y() +
int(dispRect.height() * (1 - hz) / 2),
647 int(dispRect.width() * hz),
int(dispRect.height() * hz) );
652 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] SetInputRegister %1").arg(num));
668 if (!osdWindow || !osdPainter)
684 QRect imageRect(data->
m_x, data->
m_y,
696 rect.width(), rect.height());
699 newData->m_x = rect.x();
700 newData->m_y = rect.y();
701 newData->m_bUnder =
true;
713 for (
int count = 0; it !=
m_display.end(); ++it, count++)
721 auto *uiimage =
new MythUIImage(osdWindow, QString(
"itv%1").arg(count));
724 uiimage->SetImage(image);
769 QSize(
ScaleX(r.width(),
true),
ScaleY(r.height(),
true)) };
790 const QRect scaledRect =
Scale(displayRect);
794 data->
m_image = image.convertToFormat(QImage::Format_ARGB32).scaled(
795 scaledRect.width(), scaledRect.height(),
796 Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
797 data->m_x = scaledRect.x();
798 data->m_y = scaledRect.y();
799 data->m_bUnder = bUnder;
826 return n + (-n & (r - 1));
841 vidRect.setWidth(
Roundup(vidRect.width(), 2));
842 vidRect.setHeight(
Roundup(vidRect.height(), 2));
860 "SELECT networkid, serviceid, transportid, chanid "
861 "FROM channel, dtv_multiplex "
862 "WHERE channel.deleted IS NULL "
863 " AND channel.mplexid = dtv_multiplex.mplexid "
864 " AND channel.sourceid = dtv_multiplex.sourceid "
865 " AND channel.sourceid = :SOURCEID ;" );
876 int nid = query.
value(0).toInt();
877 int sid = query.
value(1).toInt();
878 int tid = query.
value(2).toInt();
879 int cid = query.
value(3).toInt();
897 if (str.startsWith(
"dvb://"))
899 QStringList list = str.mid(6).split(
'.');
900 if (list.size() != 3)
905 int netID = list[0].toInt(&ok, 16);
908 int transportID = !list[1].isEmpty() ? list[1].toInt(&ok, 16) : -1;
911 int serviceID = list[2].toInt(&ok, 16);
920 Key_t(netID,serviceID) );
929 if (
Tid(it) == transportID)
938 else if (str.startsWith(
"rec://svc/lcn/"))
942 int channelNo = str.mid(14).toInt(&ok);
948 "WHERE deleted IS NULL AND "
949 " channum = :CHAN AND "
950 " channel.sourceid = :SOURCEID");
954 nResult = query.
value(0).toInt();
956 else if (str ==
"rec://svc/cur")
960 else if (str ==
"rec://svc/def")
966 LOG(VB_GENERAL, LOG_WARNING,
967 QString(
"[mhi] GetChannelIndex -- Unrecognized URL %1")
973 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] GetChannelIndex %1 => %2")
974 .arg(str).arg(nResult));
981 int &transportId,
int &serviceId)
989 if (
Cid(it) == channelId)
991 transportId =
Tid(it);
995 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] GetServiceInfo %1 => NID=%2 TID=%3 SID=%4")
996 .arg(channelId).arg(netId).arg(transportId).arg(serviceId));
1001 LOG(VB_MHEG, LOG_WARNING, QString(
"[mhi] GetServiceInfo %1 failed").arg(channelId));
1009 LOG(VB_MHEG, LOG_WARNING, QString(
"[mhi] Can't TuneTo %1 0x%2 while not live")
1010 .arg(channel).arg(tuneinfo,0,16));
1014 LOG(VB_GENERAL, LOG_INFO, QString(
"[mhi] TuneTo %1 0x%2")
1015 .arg(channel).arg(tuneinfo,0,16));
1019 MythEvent me(QString(
"NETWORK_CONTROL CHANID %1").arg(channel));
1032 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] BeginStream %1 0x%2")
1033 .arg(stream).arg((quintptr)notify,0,16));
1039 if (stream.startsWith(
"http://") || stream.startsWith(
"https://"))
1044 if (QUrl(stream).authority().isEmpty())
1048 return !stream.isEmpty();
1058 int transportId = 0;
1077 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] EndStream 0x%1")
1090 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Stream 0x%1 %2")
1091 .arg((quintptr)
m_notify,0,16).arg(bStarted ?
"started" :
"stopped"));
1103 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] BeginAudio %1").arg(tag));
1123 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] BeginVideo %1").arg(tag));
1172 return new MHIDLA(
this, isBoxed, lineColour, fillColour);
1191 if (colour.
alpha() == 0 || height == 0 || width == 0)
1194 QImage qImage(width, height, QImage::Format_ARGB32);
1195 qImage.fill(qRgba(colour.
red(), colour.
green(), colour.
blue(), colour.
alpha()));
1197 AddToDisplay(qImage, QRect(xPos, yPos, width, height));
1206 const QImage &qImage,
bool bScaled,
bool bUnder)
1208 if (qImage.isNull())
1211 QRect imageRect(x, y, qImage.width(), qImage.height());
1212 QRect displayRect = clipRect & imageRect;
1214 if (bScaled || displayRect == imageRect)
1218 else if (!displayRect.isEmpty())
1220 QImage clipped = qImage.copy(displayRect.translated(-x, -y));
1233 QRect bounds = reg.boundingRect();
1234 DrawRect(bounds.x(), bounds.y(), bounds.width(), bounds.height(),
1288 int maxAscent = face->size->metrics.ascender;
1289 int maxDescent = -face->size->metrics.descender;
1291 FT_Bool useKerning = FT_HAS_KERNING(face);
1292 FT_UInt previous = 0;
1294 for (
int n = 0; n < strLen; n++)
1296 QChar ch = str.at(n);
1297 FT_UInt glyphIndex = FT_Get_Char_Index(face, ch.unicode());
1299 if (glyphIndex == 0)
1301 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Unknown glyph 0x%1")
1302 .arg(ch.unicode(),0,16));
1309 if (useKerning && previous != 0)
1312 FT_Get_Kerning(face, previous, glyphIndex,
1313 FT_KERNING_DEFAULT, &delta);
1317 error = FT_Load_Glyph(face, glyphIndex, 0);
1322 FT_GlyphSlot slot = face->glyph;
1323 FT_Pos advance = slot->metrics.horiAdvance + kerning;
1327 if (
FT2Point(width + advance) > maxSize)
1335 int descent = slot->metrics.height - slot->metrics.horiBearingY;
1337 maxAscent = std::max<FT_Pos>(slot->metrics.horiBearingY, maxAscent);
1339 maxDescent = std::max(descent, maxDescent);
1342 previous = glyphIndex;
1358 for (
int j = 0; j <
m_width; j++)
1360 m_image.setPixel(j, i, qRgba(0, 0, 0, 0));
1380 FT_Bool useKerning = FT_HAS_KERNING(face);
1381 FT_UInt previous = 0;
1383 int len = str.length();
1384 for (
int n = 0; n < len; n++)
1388 FT_UInt glyphIndex = FT_Get_Char_Index(face, ch.unicode());
1389 if (glyphIndex == 0)
1395 if (useKerning && previous != 0)
1398 FT_Get_Kerning(face, previous, glyphIndex,
1399 FT_KERNING_DEFAULT, &delta);
1402 FT_Error
error = FT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
1407 FT_GlyphSlot slot = face->glyph;
1408 if (slot->format != FT_GLYPH_FORMAT_BITMAP)
1411 if ((
enum FT_Pixel_Mode_)slot->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
1414 unsigned char *source = slot->bitmap.buffer;
1416 int baseX =
FT2Point(posX) + slot->bitmap_left;
1417 int baseY = pixelY - slot->bitmap_top;
1419 for (
unsigned int i = 0; i < slot->bitmap.rows; i++)
1421 for (
unsigned int j = 0; j < slot->bitmap.width; j++)
1423 int greyLevel = source[j];
1426 int red = colour.
red();
1427 int green = colour.
green();
1428 int blue = colour.
blue();
1429 int alpha = colour.
alpha() *
1430 greyLevel / slot->bitmap.num_grays;
1431 int xBit = j + baseX;
1432 int yBit = i + baseY;
1437 if (xBit >= 0 && xBit <
m_width &&
1441 qRgba(red, green, blue, alpha));
1444 source += slot->bitmap.pitch;
1446 posX += slot->advance.x;
1447 previous = glyphIndex;
1454 QRgb qColour = qRgba(colour.
red(), colour.
green(),
1470 if (width <= 0 || height <= 0)
1473 int imageWidth =
m_image.width();
1474 int imageHeight =
m_image.height();
1475 if (x+width > imageWidth)
1476 width = imageWidth - x;
1478 if (y+height > imageHeight)
1479 height = imageHeight - y;
1481 if (width <= 0 || height <= 0)
1484 for (
int i = 0; i < height; i++)
1486 for (
int j = 0; j < width; j++)
1488 m_image.setPixel(x+j, y+i, qColour);
1558 if (abs(y2-y1) > abs(
x2-
x1))
1581 int dy = abs(y2-y1);
1582 int yStep = y2 >= y1 ? 1 : -1;
1601 for (
int x =
x1; x <=
x2; x++)
1612 m_image.setPixel(y+i, x+j, colour);
1617 m_image.setPixel(x+j, y+i, colour);
1630 m_image.setPixel(y+i, x+j, colour);
1635 m_image.setPixel(x+j, y+i, colour);
1702 int nPoints = xArray.size();
1708 QVector <lineSeg> lineArray(nPoints);
1713 int lastX = xArray[nPoints-1];
1714 int lastY = yArray[nPoints-1];
1717 for (
int k = 0; k < nPoints; k++)
1719 int thisX = xArray[k];
1720 int thisY = yArray[k];
1725 lineArray[nLines].m_yBottom = thisY;
1726 lineArray[nLines].m_yTop = lastY;
1727 lineArray[nLines].m_xBottom = thisX;
1731 lineArray[nLines].m_yBottom = lastY;
1732 lineArray[nLines].m_yTop = thisY;
1733 lineArray[nLines].m_xBottom = lastX;
1735 lineArray[nLines++].m_slope =
1736 (float)(thisX-lastX) / (float)(thisY-lastY);
1738 yMin = std::min(thisY, yMin);
1739 yMax = std::max(thisY, yMax);
1749 for (
int y = yMin; y < yMax; y++)
1754 for (
int l = 0; l < nLines; l++)
1756 if (y >= lineArray[l].m_yBottom && y < lineArray[l].m_yTop)
1758 int x = (int)round((
float)(y - lineArray[l].m_yBottom) *
1759 lineArray[l].m_slope) + lineArray[l].m_xBottom;
1760 if (crossings == 0 || x < xMin)
1762 if (crossings == 0 || x > xMax)
1769 for (
int x = xMin; x <= xMax; x++)
1770 m_image.setPixel(x, y, fillColour);
1775 int lastXpoint = xArray[nPoints-1];
1776 int lastYpoint = yArray[nPoints-1];
1777 for (
int i = 0; i < nPoints; i++)
1779 DrawLine(xArray[i], yArray[i], lastXpoint, lastYpoint);
1780 lastXpoint = xArray[i];
1781 lastYpoint = yArray[i];
1786 for (
int i = 1; i < nPoints; i++)
1788 DrawLine(xArray[i], yArray[i], xArray[i-1], yArray[i-1]);
1794 : m_parent(parent), m_tiled(tiled),
1812 QImage tiledImage = QImage(rect.width(), rect.height(),
1813 QImage::Format_ARGB32);
1815 for (
int i = 0; i < rect.width(); i++)
1817 for (
int j = 0; j < rect.height(); j++)
1836 if (!
m_image.loadFromData(data, length,
"PNG"))
1852 if (!
m_image.loadFromData(data, length,
"JPG"))
1869 AVCodecContext *c =
nullptr;
1872 uint8_t *buff =
nullptr;
1873 bool gotPicture =
false;
1877 const AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_MPEG2VIDEO);
1883 c = avcodec_alloc_context3(
nullptr);
1885 if (avcodec_open2(c, codec,
nullptr) < 0)
1889 if (av_new_packet(&pkt, length) < 0)
1892 memcpy(pkt.data, data, length);
1897 for (
int limit=0; limit<10 && !gotPicture; limit++)
1899 int len = avcodec_receive_frame(c, picture);
1902 if (len == AVERROR(EAGAIN))
1905 len = avcodec_send_packet(c, &pkt);
1906 if (len == AVERROR(EAGAIN) || len == AVERROR_EOF)
1911 LOG(VB_GENERAL, LOG_ERR,
1912 QString(
"[mhi] video decode error: %1 (%2)")
1926 int nContentWidth = c->width;
1927 int nContentHeight = c->height;
1928 m_image = QImage(nContentWidth, nContentHeight, QImage::Format_ARGB32);
1932 memset(&retbuf, 0,
sizeof(
AVFrame));
1934 int bufflen = nContentWidth * nContentHeight * 3;
1935 auto *outputbuf = (
unsigned char*)av_malloc(bufflen);
1937 av_image_fill_arrays(retbuf.data, retbuf.linesize,
1938 outputbuf, AV_PIX_FMT_RGB24,
1939 nContentWidth, nContentHeight,IMAGE_ALIGN);
1943 nContentWidth, nContentHeight);
1945 uint8_t * buf = outputbuf;
1949 for (
int i = 0; i < nContentHeight; i++)
1951 for (
int j = 0; j < nContentWidth; j++)
1956 m_image.setPixel(j, i, qRgb(red, green, blue));
1959 av_freep(
reinterpret_cast<void*
>(&outputbuf));
1964 av_packet_unref(&pkt);
1965 avcodec_free_context(&c);
1974 if (newWidth ==
m_image.width() && newHeight ==
m_image.height())
1977 if (newWidth <= 0 || newHeight <= 0)
1984 Qt::IgnoreAspectRatio, Qt::SmoothTransformation);