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 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
380 QStringList path = objectPath.split(QChar(
'/'), QString::SkipEmptyParts);
382 QStringList path = objectPath.split(QChar(
'/'), Qt::SkipEmptyParts);
392 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
393 QStringList path = objectPath.split(QChar(
'/'), QString::SkipEmptyParts);
395 QStringList path = objectPath.split(QChar(
'/'), Qt::SkipEmptyParts);
410 LOG(VB_MHEG, LOG_INFO, QString(
411 "[mhi] CheckAccess(%1) No auth.servers").arg(objectPath) );
415 QByteArray host = QUrl(objectPath).host().toLocal8Bit();
416 if (!servers.contains(host))
418 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] CheckAccess(%1) Host not known")
420 LOG(VB_MHEG, LOG_DEBUG, QString(
"[mhi] Permitted servers: %1")
421 .arg(servers.constData()) );
424 if (!objectPath.startsWith(
"https:"))
428 if (!objectPath.startsWith(
"https:"))
445 bool const isIC = objectPath.startsWith(
"http:") || objectPath.startsWith(
"https:");
455 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
456 QStringList path = objectPath.split(QChar(
'/'), QString::SkipEmptyParts);
458 QStringList path = objectPath.split(QChar(
'/'), Qt::SkipEmptyParts);
464 bool bReported =
false;
465 QElapsedTimer
t;
t.start();
474 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Received %1").arg(objectPath));
478 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Not found %1").arg(objectPath));
491 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Received %1").arg(objectPath));
498 if (
t.hasExpired(60000))
501 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] timed out %1").arg(objectPath));
508 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Waiting for %1").arg(objectPath));
522 using key_t = QPair< QString,
int >;
527 int Find(
const QString &name,
int reg)
const
531 void key(
const QString &name,
int code,
int r1,
532 int r2=0,
int r3=0,
int r4=0,
int r5=0,
int r6=0,
int r7=0,
int r8=0,
int r9=0);
538 int r2,
int r3,
int r4,
int r5,
int r6,
int r7,
int r8,
int r9)
566 QStringList keylist =
GET_KEY(
"TV Playback",
"TEXTEXIT").split(QChar(
','));
567 bool strict = !keylist.contains(
"Esc", Qt::CaseInsensitive);
604 #if 0 // These conflict with left & right
625 LOG(VB_GENERAL, LOG_INFO, QString(
"[mhi] Adding MHEG key %1:%2:%3")
636 LOG(VB_MHEG, LOG_INFO,
637 QString(
"[mhi] Reinit video(y:%1 x:%2 w:%3 h:%4) "
638 "vis(y:%5 x:%6 w:%7 h:%8) aspect=%9")
639 .arg(videoRect.y()).arg(videoRect.x())
640 .arg(videoRect.width()).arg(videoRect.height())
641 .arg(dispRect.y()).arg(dispRect.x())
642 .arg(dispRect.width()).arg(dispRect.height()).arg(aspect));
646 enum { kNone, kHoriz, kBoth };
648 auto const aspectd =
static_cast<double>(aspect);
649 double const vz = (mode == kBoth) ? std::min(1.15, 1. / sqrt(aspectd)) : 1.;
650 double const hz = (mode > kNone) ? vz * aspectd : 1.;
653 int(dispRect.height() * (1 - vz) / 2),
654 int(dispRect.width() * hz),
int(dispRect.height() * vz) );
656 dispRect.y() +
int(dispRect.height() * (1 - hz) / 2),
657 int(dispRect.width() * hz),
int(dispRect.height() * hz) );
662 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] SetInputRegister %1").arg(num));
678 if (!osdWindow || !osdPainter)
694 QRect imageRect(data->
m_x, data->
m_y,
706 rect.width(), rect.height());
709 newData->m_x = rect.x();
710 newData->m_y = rect.y();
711 newData->m_bUnder =
true;
723 for (
int count = 0; it !=
m_display.end(); ++it, count++)
731 auto *uiimage =
new MythUIImage(osdWindow, QString(
"itv%1").arg(count));
734 uiimage->SetImage(image);
779 QSize(
ScaleX(r.width(),
true),
ScaleY(r.height(),
true)) };
800 const QRect scaledRect =
Scale(displayRect);
804 data->
m_image = image.convertToFormat(QImage::Format_ARGB32).scaled(
805 scaledRect.width(), scaledRect.height(),
806 Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
807 data->m_x = scaledRect.x();
808 data->m_y = scaledRect.y();
809 data->m_bUnder = bUnder;
836 return n + (-n & (r - 1));
851 vidRect.setWidth(
Roundup(vidRect.width(), 2));
852 vidRect.setHeight(
Roundup(vidRect.height(), 2));
870 "SELECT networkid, serviceid, transportid, chanid "
871 "FROM channel, dtv_multiplex "
872 "WHERE channel.deleted IS NULL "
873 " AND channel.mplexid = dtv_multiplex.mplexid "
874 " AND channel.sourceid = dtv_multiplex.sourceid "
875 " AND channel.sourceid = :SOURCEID ;" );
886 int nid = query.
value(0).toInt();
887 int sid = query.
value(1).toInt();
888 int tid = query.
value(2).toInt();
889 int cid = query.
value(3).toInt();
907 if (str.startsWith(
"dvb://"))
909 QStringList list = str.mid(6).split(
'.');
910 if (list.size() != 3)
915 int netID = list[0].toInt(&ok, 16);
918 int transportID = !list[1].isEmpty() ? list[1].toInt(&ok, 16) : -1;
921 int serviceID = list[2].toInt(&ok, 16);
930 Key_t(netID,serviceID) );
939 if (
Tid(it) == transportID)
948 else if (str.startsWith(
"rec://svc/lcn/"))
952 int channelNo = str.mid(14).toInt(&ok);
958 "WHERE deleted IS NULL AND "
959 " channum = :CHAN AND "
960 " channel.sourceid = :SOURCEID");
964 nResult = query.
value(0).toInt();
966 else if (str ==
"rec://svc/cur")
968 else if (str ==
"rec://svc/def")
972 LOG(VB_GENERAL, LOG_WARNING,
973 QString(
"[mhi] GetChannelIndex -- Unrecognized URL %1")
979 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] GetChannelIndex %1 => %2")
980 .arg(str).arg(nResult));
987 int &transportId,
int &serviceId)
995 if (
Cid(it) == channelId)
997 transportId =
Tid(it);
1000 serviceId =
Sid(it);
1001 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] GetServiceInfo %1 => NID=%2 TID=%3 SID=%4")
1002 .arg(channelId).arg(netId).arg(transportId).arg(serviceId));
1007 LOG(VB_MHEG, LOG_WARNING, QString(
"[mhi] GetServiceInfo %1 failed").arg(channelId));
1015 LOG(VB_MHEG, LOG_WARNING, QString(
"[mhi] Can't TuneTo %1 0x%2 while not live")
1016 .arg(channel).arg(tuneinfo,0,16));
1020 LOG(VB_GENERAL, LOG_INFO, QString(
"[mhi] TuneTo %1 0x%2")
1021 .arg(channel).arg(tuneinfo,0,16));
1025 MythEvent me(QString(
"NETWORK_CONTROL CHANID %1").arg(channel));
1038 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] BeginStream %1 0x%2")
1039 .arg(stream).arg((quintptr)notify,0,16));
1045 if (stream.startsWith(
"http://") || stream.startsWith(
"https://"))
1050 if (QUrl(stream).authority().isEmpty())
1054 return !stream.isEmpty();
1064 int transportId = 0;
1083 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] EndStream 0x%1")
1096 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Stream 0x%1 %2")
1097 .arg((quintptr)
m_notify,0,16).arg(bStarted ?
"started" :
"stopped"));
1109 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] BeginAudio %1").arg(tag));
1129 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] BeginVideo %1").arg(tag));
1178 return new MHIDLA(
this, isBoxed, lineColour, fillColour);
1197 if (colour.
alpha() == 0 || height == 0 || width == 0)
1200 QImage qImage(width, height, QImage::Format_ARGB32);
1201 qImage.fill(qRgba(colour.
red(), colour.
green(), colour.
blue(), colour.
alpha()));
1203 AddToDisplay(qImage, QRect(xPos, yPos, width, height));
1212 const QImage &qImage,
bool bScaled,
bool bUnder)
1214 if (qImage.isNull())
1217 QRect imageRect(x, y, qImage.width(), qImage.height());
1218 QRect displayRect = clipRect & imageRect;
1220 if (bScaled || displayRect == imageRect)
1224 else if (!displayRect.isEmpty())
1226 QImage clipped = qImage.copy(displayRect.translated(-x, -y));
1239 QRect bounds = reg.boundingRect();
1240 DrawRect(bounds.x(), bounds.y(), bounds.width(), bounds.height(),
1294 int maxAscent = face->size->metrics.ascender;
1295 int maxDescent = -face->size->metrics.descender;
1297 FT_Bool useKerning = FT_HAS_KERNING(face);
1298 FT_UInt previous = 0;
1300 for (
int n = 0; n < strLen; n++)
1302 QChar ch = str.at(n);
1303 FT_UInt glyphIndex = FT_Get_Char_Index(face, ch.unicode());
1305 if (glyphIndex == 0)
1307 LOG(VB_MHEG, LOG_INFO, QString(
"[mhi] Unknown glyph 0x%1")
1308 .arg(ch.unicode(),0,16));
1315 if (useKerning && previous != 0)
1318 FT_Get_Kerning(face, previous, glyphIndex,
1319 FT_KERNING_DEFAULT, &delta);
1323 error = FT_Load_Glyph(face, glyphIndex, 0);
1328 FT_GlyphSlot slot = face->glyph;
1329 FT_Pos advance = slot->metrics.horiAdvance + kerning;
1333 if (
FT2Point(width + advance) > maxSize)
1341 int descent = slot->metrics.height - slot->metrics.horiBearingY;
1343 if (slot->metrics.horiBearingY > maxAscent)
1344 maxAscent = slot->metrics.horiBearingY;
1346 if (descent > maxDescent)
1347 maxDescent = descent;
1350 previous = glyphIndex;
1366 for (
int j = 0; j <
m_width; j++)
1368 m_image.setPixel(j, i, qRgba(0, 0, 0, 0));
1388 FT_Bool useKerning = FT_HAS_KERNING(face);
1389 FT_UInt previous = 0;
1391 int len = str.length();
1392 for (
int n = 0; n < len; n++)
1396 FT_UInt glyphIndex = FT_Get_Char_Index(face, ch.unicode());
1397 if (glyphIndex == 0)
1403 if (useKerning && previous != 0)
1406 FT_Get_Kerning(face, previous, glyphIndex,
1407 FT_KERNING_DEFAULT, &delta);
1410 FT_Error
error = FT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
1415 FT_GlyphSlot slot = face->glyph;
1416 if (slot->format != FT_GLYPH_FORMAT_BITMAP)
1419 if ((
enum FT_Pixel_Mode_)slot->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
1422 unsigned char *source = slot->bitmap.buffer;
1424 int baseX =
FT2Point(posX) + slot->bitmap_left;
1425 int baseY = pixelY - slot->bitmap_top;
1427 for (
unsigned int i = 0; i < slot->bitmap.rows; i++)
1429 for (
unsigned int j = 0; j < slot->bitmap.width; j++)
1431 int greyLevel = source[j];
1434 int red = colour.
red();
1435 int green = colour.
green();
1436 int blue = colour.
blue();
1437 int alpha = colour.
alpha() *
1438 greyLevel / slot->bitmap.num_grays;
1439 int xBit = j + baseX;
1440 int yBit = i + baseY;
1445 if (xBit >= 0 && xBit <
m_width &&
1449 qRgba(red, green, blue, alpha));
1452 source += slot->bitmap.pitch;
1454 posX += slot->advance.x;
1455 previous = glyphIndex;
1462 QRgb qColour = qRgba(colour.
red(), colour.
green(),
1478 if (width <= 0 || height <= 0)
1481 int imageWidth =
m_image.width();
1482 int imageHeight =
m_image.height();
1483 if (x+width > imageWidth)
1484 width = imageWidth - x;
1486 if (y+height > imageHeight)
1487 height = imageHeight - y;
1489 if (width <= 0 || height <= 0)
1492 for (
int i = 0; i < height; i++)
1494 for (
int j = 0; j < width; j++)
1496 m_image.setPixel(x+j, y+i, qColour);
1566 if (abs(y2-y1) > abs(
x2-
x1))
1589 int dy = abs(y2-y1);
1590 int yStep = y2 >= y1 ? 1 : -1;
1609 for (
int x =
x1; x <=
x2; x++)
1620 m_image.setPixel(y+i, x+j, colour);
1625 m_image.setPixel(x+j, y+i, colour);
1638 m_image.setPixel(y+i, x+j, colour);
1643 m_image.setPixel(x+j, y+i, colour);
1710 int nPoints = xArray.size();
1716 QVector <lineSeg> lineArray(nPoints);
1721 int lastX = xArray[nPoints-1];
1722 int lastY = yArray[nPoints-1];
1725 for (
int k = 0; k < nPoints; k++)
1727 int thisX = xArray[k];
1728 int thisY = yArray[k];
1733 lineArray[nLines].m_yBottom = thisY;
1734 lineArray[nLines].m_yTop = lastY;
1735 lineArray[nLines].m_xBottom = thisX;
1739 lineArray[nLines].m_yBottom = lastY;
1740 lineArray[nLines].m_yTop = thisY;
1741 lineArray[nLines].m_xBottom = lastX;
1743 lineArray[nLines++].m_slope =
1744 (float)(thisX-lastX) / (float)(thisY-lastY);
1759 for (
int y = yMin; y < yMax; y++)
1764 for (
int l = 0; l < nLines; l++)
1766 if (y >= lineArray[l].m_yBottom && y < lineArray[l].m_yTop)
1768 int x = (int)round((
float)(y - lineArray[l].m_yBottom) *
1769 lineArray[l].m_slope) + lineArray[l].m_xBottom;
1770 if (crossings == 0 || x < xMin)
1772 if (crossings == 0 || x > xMax)
1779 for (
int x = xMin; x <= xMax; x++)
1780 m_image.setPixel(x, y, fillColour);
1785 int lastXpoint = xArray[nPoints-1];
1786 int lastYpoint = yArray[nPoints-1];
1787 for (
int i = 0; i < nPoints; i++)
1789 DrawLine(xArray[i], yArray[i], lastXpoint, lastYpoint);
1790 lastXpoint = xArray[i];
1791 lastYpoint = yArray[i];
1796 for (
int i = 1; i < nPoints; i++)
1798 DrawLine(xArray[i], yArray[i], xArray[i-1], yArray[i-1]);
1804 : m_parent(parent), m_tiled(tiled),
1822 QImage tiledImage = QImage(rect.width(), rect.height(),
1823 QImage::Format_ARGB32);
1825 for (
int i = 0; i < rect.width(); i++)
1827 for (
int j = 0; j < rect.height(); j++)
1846 if (!
m_image.loadFromData(data, length,
"PNG"))
1862 if (!
m_image.loadFromData(data, length,
"JPG"))
1879 AVCodecContext *c =
nullptr;
1882 uint8_t *buff =
nullptr;
1883 bool gotPicture =
false;
1887 const AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_MPEG2VIDEO);
1893 c = avcodec_alloc_context3(
nullptr);
1895 if (avcodec_open2(c, codec,
nullptr) < 0)
1899 if (av_new_packet(&pkt, length) < 0)
1902 memcpy(pkt.data, data, length);
1907 for (
int limit=0; limit<10 && !gotPicture; limit++)
1909 int len = avcodec_receive_frame(c, picture);
1912 if (len == AVERROR(EAGAIN))
1915 len = avcodec_send_packet(c, &pkt);
1916 if (len == AVERROR(EAGAIN) || len == AVERROR_EOF)
1921 LOG(VB_GENERAL, LOG_ERR,
1922 QString(
"[mhi] video decode error: %1 (%2)")
1936 int nContentWidth = c->width;
1937 int nContentHeight = c->height;
1938 m_image = QImage(nContentWidth, nContentHeight, QImage::Format_ARGB32);
1942 memset(&retbuf, 0,
sizeof(
AVFrame));
1944 int bufflen = nContentWidth * nContentHeight * 3;
1945 auto *outputbuf = (
unsigned char*)av_malloc(bufflen);
1947 av_image_fill_arrays(retbuf.data, retbuf.linesize,
1948 outputbuf, AV_PIX_FMT_RGB24,
1949 nContentWidth, nContentHeight,IMAGE_ALIGN);
1953 nContentWidth, nContentHeight);
1955 uint8_t * buf = outputbuf;
1959 for (
int i = 0; i < nContentHeight; i++)
1961 for (
int j = 0; j < nContentWidth; j++)
1966 m_image.setPixel(j, i, qRgb(red, green, blue));
1969 av_freep(&outputbuf);
1974 av_packet_unref(&pkt);
1975 avcodec_free_context(&c);
1984 if (newWidth ==
m_image.width() && newHeight ==
m_image.height())
1987 if (newWidth <= 0 || newHeight <= 0)
1994 Qt::IgnoreAspectRatio, Qt::SmoothTransformation);