Reference::Reference(const std::string &ref) : m_ref(ref) { const std::size_t pound = ref.find('#'); if (pound != std::string::npos) { m_uri = ref.substr(0, pound); m_pointer = Pointer(ref.substr(pound + 1)); m_isValid = (m_uri.empty() || isURI(m_uri)) && m_pointer.isValid(); } }
//--------------------------------------------------------------------------- // //! \brief check for playlist type // //! \author Jo2003 //! \date 12.12.2013 // //! \param pl (QString&) ref. to playlist content // //! \return m3u::M3U_MASTER_PL -> master playlist; //! m3u::M3U_MEDIA_PL -> media playlist //! m3u::M3U_UNKWN_PL -> unknown playlist type //--------------------------------------------------------------------------- m3u::t_type QExtM3uParser::plType(const QString &pl) { m3u::t_type trv = m3u::M3U_UNKWN_PL; QStringList sl = pl.split(QRegExp("[\r\n]"), QString::SkipEmptyParts); int iM3u = 0, iTok = 0; // to find out which type of playlist this is we should look // for all URIs there. // If this file only contains of playlists it is a master playlist. // If this file only contains media URIs it is a media playlist. // Else it is an unknown list type. for (int i = 0; i < sl.count(); i++) { // no tag, but URI ... if (!isTag(sl.at(i)) && isURI(sl.at(i))) { // playlist extension in URI ... ? if (sl.at(i).indexOf("m3u", 0, Qt::CaseInsensitive) > -1) { // count ... iM3u ++; } else { // count .. iTok ++; } } } // make the final check ... if (iM3u && !iTok) { trv = m3u::M3U_MASTER_PL; } else if (!iM3u && iTok) { trv = m3u::M3U_MEDIA_PL; } return trv; }
//--------------------------------------------------------------------------- // //! \brief get stream parts / tokens from media playlist // //! \author Jo2003 //! \date 12.12.2013 // //! \param pl (QString&) ref. to one line from playlist //! \param sTVec (m3u::StreamTokVector&) ref. to stream token vector // //! \return 0 -> ok; 1 -> playlist already handled; -1 -> any error //--------------------------------------------------------------------------- int QExtM3uParser::getStreamToks(const QString& pl, m3u::StreamTokVector& sTVec) { int iRet = -1; int iTokCount = 0; QRegExp rx; m3u::t_StreamTok stok; QStringList sl = pl.split(QRegExp("[\r\n]"), QString::SkipEmptyParts); // reset endlist tag ... _bEndList = false; sTVec.clear(); // can be handled on media playlist only ... if (plType(pl) == m3u::M3U_MEDIA_PL) { for (int i = 0; i < sl.count(); i++) { if (isTag(sl.at(i))) { if (sl.at(i).contains("#EXT-X-MEDIA-SEQUENCE:")) { rx.setPattern("#EXT-X-MEDIA-SEQUENCE:([0-9]*)"); if (rx.indexIn(sl.at(i)) > -1) { if (rx.cap(1).toInt() > _iMediaIndex) { _iMediaIndex = rx.cap(1).toInt(); if (_iMediaIdxUsed == -1) { _iMediaIdxUsed = _iMediaIndex; } } else { // we already handled this playlist ... iRet = 1; break; } } } else if(sl.at(i).contains("#EXT-X-TARGETDURATION:")) { rx.setPattern("#EXT-X-TARGETDURATION:([0-9]*)"); if (rx.indexIn(sl.at(i)) > -1) { _iTrgDuration = rx.cap(1).toInt(); } } else if(sl.at(i).contains("#EXTINF:")) { rx.setPattern("#EXTINF:([^,]*),"); if (rx.indexIn(sl.at(i)) > -1) { stok.iDuration = qRound(rx.cap(1).toFloat()); } rx.setPattern("#EXTINF:.*,(.*)$"); if (rx.indexIn(sl.at(i)) > -1) { stok.sTitle = rx.cap(1); } } else if(sl.at(i).contains("#EXT-X-BYTERANGE:")) { if (sl.at(i).indexOf('@') > -1) { // offset given ... rx.setPattern("#EXT-X-BYTERANGE:([0-9]*)@([0-9]*)"); if (rx.indexIn(sl.at(i)) > -1) { stok.iByteCount = rx.cap(1).toInt(); stok.iBOffset = rx.cap(2).toInt(); } } else { // without offset ... rx.setPattern("#EXT-X-BYTERANGE:([0-9]*)"); if (rx.indexIn(sl.at(i)) > -1) { stok.iByteCount = rx.cap(1).toInt(); stok.iBOffset = 0; } } } else if(sl.at(i).contains("#EXT-X-ENDLIST")) { _bEndList = true; } // other tags not supported so far ... } else if(isURI(sl.at(i))) { iTokCount ++; if ((_iMediaIndex + iTokCount) > _iMediaIdxUsed) { stok.sUri = completeUri(sl.at(i).simplified()); _iMediaIdxUsed ++; sTVec.append(stok); } // reset stream structure ... stok.iBOffset = -1; stok.iByteCount = -1; stok.iDuration = -1; stok.sTitle = ""; stok.sUri = ""; } } } if (!sTVec.isEmpty() && (iRet != 1)) { iRet = 0; } return iRet; }
//--------------------------------------------------------------------------- // //! \brief get available streams from master playlist // //! \author Jo2003 //! \date 12.12.2013 // //! \param pl (QString&) ref. to one line from playlist //! \param sVec (m3u::StreamVector&) ref. to stream vector // //! \return 0 -> ok; -1 -> any error //--------------------------------------------------------------------------- int QExtM3uParser::getStreams(const QString& pl, m3u::StreamVector& sVec) { int iRet = -1; QRegExp rx; m3u::t_Stream stream; QStringList sl = pl.split(QRegExp("[\r\n]"), QString::SkipEmptyParts); sVec.clear(); // can be handled on master playlist only ... if (plType(pl) == m3u::M3U_MASTER_PL) { for (int i = 0; i < sl.count(); i++) { if (isTag(sl.at(i))) { // get stream info ... if (sl.at(i).indexOf("#EXT-X-STREAM-INF") > -1) { rx.setPattern("PROGRAM-ID=([0-9]*)"); if (rx.indexIn(sl.at(i)) > -1) { stream.iId = rx.cap(1).toInt(); } rx.setPattern("RESOLUTION=([0-9]*)x([0-9]*)"); if (rx.indexIn(sl.at(i)) > -1) { stream.szRes.setWidth(rx.cap(1).toInt()); stream.szRes.setHeight(rx.cap(2).toInt()); } rx.setPattern("BANDWIDTH=([0-9]*)"); if (rx.indexIn(sl.at(i)) > -1) { stream.iBandWidth = rx.cap(1).toInt(); } } // other tags not supported so far ... } else if(isURI(sl.at(i))) { // get url of media playlist ... stream.sUri = completeUri(sl.at(i).simplified()); // add element to vector ... sVec.append(stream); // reset stream structure ... stream.iBandWidth = -1; stream.iId = -1; stream.szRes = QSize(); stream.sUri = ""; } } } if (!sVec.isEmpty()) { iRet = 0; } return iRet; }