3#include <QRegularExpression>
7#include "libmythbase/mythconfig.h"
13 static const QRegularExpression
kQuotes{
"^\"|\"$"};
17 QByteArray ba = uri.toLatin1();
18 QUrl url = QUrl::fromEncoded(ba);
19 return url.toString();
22 QString
RelativeURI(
const QString& surl,
const QString& spath)
24 QUrl url = QUrl(surl);
25 QUrl path = QUrl(spath);
27 if (!path.isRelative())
30 return url.resolved(path).toString();
35 int p = line.indexOf(QLatin1String(
":"));
39 QStringList list = line.mid(
p + 1).split(
',');
40 for (
const auto & it : std::as_const(list))
42 QString arg = it.trimmed();
43 if (arg.startsWith(attr))
45 int pos = arg.indexOf(QLatin1String(
"="));
48 return arg.mid(pos+1);
60 int p = line.indexOf(QLatin1String(
":"));
64 for ( ; i < line.size(); i++)
65 if (!line[i].isNumber())
69#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
70 target = line.midRef(
p + 1, i -
p - 1).toInt();
72 target = QStringView(line).mid(
p + 1, i -
p - 1).toInt();
83 int p = line.indexOf(QLatin1String(
":"));
87 for ( ; i < line.size(); i++)
88 if (!line[i].isNumber())
92#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
93 target = line.midRef(
p + 1, i -
p - 1).toInt();
95 target = QStringView(line).mid(
p + 1, i -
p - 1).toInt();
116 LOG(VB_RECORD, LOG_ERR, loc +
117 "#EXT-X-VERSION: no protocol version found, should be version 1.");
122 if (version < 1 || version > 7)
124 LOG(VB_RECORD, LOG_ERR, loc +
125 QString(
"#EXT-X-VERSION is %1, but we only understand 1 to 7")
143 LOG(VB_RECORD, LOG_INFO, loc +
144 QString(
"Parsing stream from %1").arg(url));
158 LOG(VB_RECORD, LOG_INFO, loc +
159 "#EXT-X-STREAM-INF: No PROGRAM-ID=<value>, using 1");
170 LOG(VB_RECORD, LOG_ERR, loc +
171 "#EXT-X-STREAM-INF: expected BANDWIDTH=<value>");
174 bandwidth = attr.toInt();
178 LOG(VB_RECORD, LOG_ERR, loc +
179 "#EXT-X-STREAM-INF: bandwidth cannot be 0");
193 if (!audio.isEmpty())
196 LOG(VB_RECORD, LOG_INFO, loc +
197 QString(
"#EXT-X-STREAM-INF: attribute AUDIO=%1").arg(audio));
202 if (!video.isEmpty())
205 LOG(VB_RECORD, LOG_INFO, loc +
206 QString(
"#EXT-X-STREAM-INF: attribute VIDEO=%1").arg(video));
210 LOG(VB_RECORD, LOG_INFO, loc +
211 QString(
"bandwidth adaptation detected (program-id=%1, bandwidth=%2)")
212 .arg(
id).arg(bandwidth));
226 LOG(VB_RECORD, LOG_INFO, loc + QString(
"Parsing EXT-X-MEDIA line"));
252 LOG(VB_RECORD, LOG_ERR, loc +
"expected #EXT-X-TARGETDURATION:<s>");
260 int& duration, QString& title,
277 int p = line.indexOf(QLatin1String(
":"));
280 LOG(VB_RECORD, LOG_ERR, loc +
281 QString(
"ParseSegmentInformation: Missing ':' in '%1'")
286 QStringList list = line.mid(
p + 1).split(
',');
291 LOG(VB_RECORD, LOG_ERR, loc +
292 QString(
"ParseSegmentInformation: Missing arguments in '%1'")
299 const QString& val = list[0];
302 int duration_seconds = val.toInt(&ok);
305 duration = duration_seconds * 1000;
309 LOG(VB_RECORD, LOG_ERR, loc +
310 QString(
"ParseSegmentInformation: invalid duration in '%1'")
317 double d = val.toDouble(&ok);
320 LOG(VB_RECORD, LOG_ERR, loc +
321 QString(
"ParseSegmentInformation: invalid duration in '%1'")
325 duration =
static_cast<int>(
d * 1000);
328 if (list.size() >= 2)
338 const QString& line,
const QString& loc)
351 LOG(VB_RECORD, LOG_ERR, loc +
"expected #EXT-X-MEDIA-SEQUENCE:<s>");
359 [[maybe_unused]]
bool& aesmsg,
360 const QString& loc, QString &path, QString &iv)
375 LOG(VB_RECORD, LOG_ERR, loc +
"#EXT-X-KEY: expected METHOD=<value>");
379 if (attr.startsWith(QLatin1String(
"NONE")))
384 LOG(VB_RECORD, LOG_ERR, loc +
"#EXT-X-KEY: URI not expected");
391 if (!parsed_iv.isEmpty())
393 LOG(VB_RECORD, LOG_ERR, loc +
"#EXT-X-KEY: IV not expected");
399 else if (attr.startsWith(QLatin1String(
"AES-128")))
404 LOG(VB_RECORD, LOG_INFO, loc +
405 "playback of AES-128 encrypted HTTP Live media detected.");
411 LOG(VB_RECORD, LOG_ERR, loc +
"#EXT-X-KEY: URI not found for "
412 "encrypted HTTP Live media in AES-128");
417 path =
DecodedURI(uri.remove(QChar(QLatin1Char(
'"'))));
420 LOG(VB_RECORD, LOG_DEBUG, QString(
"M3U::ParseKey #EXT-X-KEY: %1").arg(line));
421 LOG(VB_RECORD, LOG_DEBUG, QString(
"M3U::ParseKey path:%1 IV:%2").arg(path, iv));
423 else if (attr.startsWith(QLatin1String(
"SAMPLE-AES")))
425 LOG(VB_RECORD, LOG_ERR, loc +
"encryption SAMPLE-AES not supported.");
431 LOG(VB_RECORD, LOG_ERR, loc +
432 "invalid encryption type, only NONE "
434 "and AES-128 are supported"
467 LOG(VB_RECORD, LOG_ERR, loc +
468 QString(
"Attribute URI not present in: #EXT-X-MAP %1")
481 int p = line.indexOf(QLatin1String(
":"));
484 LOG(VB_RECORD, LOG_ERR, loc +
485 QString(
"ParseProgramDateTime: Missing ':' in '%1'")
490 QString dt_string = line.mid(
p+1);
509 int pos = line.indexOf(QLatin1String(
":"));
512 LOG(VB_RECORD, LOG_ERR, loc +
513 QString(
"ParseAllowCache: missing ':' in '%1'")
517 QString answer = line.mid(pos+1, 3);
518 if (answer.size() < 2)
520 LOG(VB_RECORD, LOG_ERR, loc +
"#EXT-X-ALLOW-CACHE, ignoring ...");
523 do_cache = (!answer.startsWith(QLatin1String(
"NO")));
543 LOG(VB_RECORD, LOG_ERR, loc +
"expected #EXT-X-DISCONTINUITY-SEQUENCE:<s>");
547 LOG(VB_RECORD, LOG_DEBUG, loc + QString(
"#EXT-X-DISCONTINUITY-SEQUENCE %1")
555 LOG(VB_RECORD, LOG_DEBUG, loc + QString(
"#EXT-X-DISCONTINUITY %1")
568 LOG(VB_RECORD, LOG_INFO, loc +
" video on demand (vod) mode");
586 LOG(VB_RECORD, LOG_DEBUG, loc + QString(
"#EXT-X-INDEPENDENT-SEGMENTS %1")
static const iso6937table * d
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
bool ParseDecimalValue(const QString &line, int &target)
Return the decimal argument in a line of type: blah:<decimal> presence of value <decimal> is compulso...
bool ParseDiscontinuitySequence(const QString &line, const QString &loc, int &discontinuity_sequence)
bool ParseVersion(const QString &line, const QString &loc, int &version)
bool ParseAllowCache(const QString &line, const QString &loc, bool &do_cache)
bool ParseEndList(const QString &loc, bool &is_vod)
bool ParseMap(const QString &line, const QString &loc, QString &uri)
QString RelativeURI(const QString &surl, const QString &spath)
bool ParseTargetDuration(const QString &line, const QString &loc, int &duration)
QString ParseAttributes(const QString &line, const char *attr)
bool ParseIndependentSegments(const QString &line, const QString &loc)
bool ParseMedia(const QString &line, const QString &loc, QString &media_type, QString &group_id, QString &uri, QString &name)
bool ParseMediaSequence(int64_t &sequence_num, const QString &line, const QString &loc)
bool ParseDiscontinuity(const QString &line, const QString &loc)
bool ParseProgramDateTime(const QString &line, const QString &loc, QDateTime &dt)
static const QRegularExpression kQuotes
bool ParseSegmentInformation(int version, const QString &line, int &duration, QString &title, const QString &loc)
QString DecodedURI(const QString &uri)
bool ParseKey(int version, const QString &line, bool &aesmsg, const QString &loc, QString &path, QString &iv)
bool ParseStreamInformation(const QString &line, const QString &url, const QString &loc, int &id, uint64_t &bandwidth, QString &audio, QString &video)
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.