Upgrade segmentreader to support (f)MP4 segments, add such support to HLS input
This commit is contained in:
parent
b01df1f3f1
commit
57655f1b21
4 changed files with 159 additions and 57 deletions
|
@ -29,6 +29,8 @@ namespace Mist{
|
||||||
#endif
|
#endif
|
||||||
currBuf = 0;
|
currBuf = 0;
|
||||||
packetPtr = 0;
|
packetPtr = 0;
|
||||||
|
mp4PacksLeft = 0;
|
||||||
|
lastMoof = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SegmentReader::onProgress(bool (*callback)(uint8_t)){
|
void SegmentReader::onProgress(bool (*callback)(uint8_t)){
|
||||||
|
@ -49,6 +51,9 @@ namespace Mist{
|
||||||
// Buffered? Just return false - we can't download more.
|
// Buffered? Just return false - we can't download more.
|
||||||
if (buffered){return false;}
|
if (buffered){return false;}
|
||||||
|
|
||||||
|
// Past end of file? Always return false.
|
||||||
|
if (_offset > currBuf->rsize()){return false;}
|
||||||
|
|
||||||
#ifdef SSL
|
#ifdef SSL
|
||||||
// Encrypted? Round up to nearest multiple of 16
|
// Encrypted? Round up to nearest multiple of 16
|
||||||
if (encrypted && _offset % 16){
|
if (encrypted && _offset % 16){
|
||||||
|
@ -86,7 +91,34 @@ namespace Mist{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SegmentReader::initializeMetadata(DTSC::Meta &meta, size_t tid, size_t mappingId){
|
void SegmentReader::initializeMetadata(DTSC::Meta &meta, size_t tid, size_t mappingId){
|
||||||
|
if (parser == STRM_TS){
|
||||||
tsStream.initializeMetadata(meta, tid, mappingId);
|
tsStream.initializeMetadata(meta, tid, mappingId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser == STRM_MP4){
|
||||||
|
for (std::deque<MP4::TrackHeader>::iterator it = mp4Headers.begin(); it != mp4Headers.end(); ++it){
|
||||||
|
if (it->trackId != tid){continue;}
|
||||||
|
size_t tNumber = meta.addTrack();
|
||||||
|
INFO_MSG("Found track %zu of type %s -> %s", tNumber, it->sType.c_str(), it->codec.c_str());
|
||||||
|
meta.setID(tNumber, mappingId);
|
||||||
|
meta.setCodec(tNumber, it->codec);
|
||||||
|
meta.setInit(tNumber, it->initData);
|
||||||
|
meta.setLang(tNumber, it->lang);
|
||||||
|
if (it->trackType == "video"){
|
||||||
|
meta.setType(tNumber, "video");
|
||||||
|
meta.setWidth(tNumber, it->vidWidth);
|
||||||
|
meta.setHeight(tNumber, it->vidHeight);
|
||||||
|
}
|
||||||
|
if (it->trackType == "audio"){
|
||||||
|
meta.setType(tNumber, "audio");
|
||||||
|
meta.setChannels(tNumber, it->audChannels);
|
||||||
|
meta.setRate(tNumber, it->audRate);
|
||||||
|
meta.setSize(tNumber, it->audSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to read a single TS packet from the current segment, setting packetPtr on success
|
/// Attempts to read a single TS packet from the current segment, setting packetPtr on success
|
||||||
|
@ -101,7 +133,7 @@ namespace Mist{
|
||||||
parser = STRM_TS;
|
parser = STRM_TS;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!memcmp(*currBuf + 4, "ftyp", 4) || !memcmp(*currBuf + 4, "moof", 4) || !memcmp(*currBuf + 4, "moov", 4)){
|
if (!memcmp(*currBuf + 4, "ftyp", 4) || !memcmp(*currBuf + 4, "styp", 4) || !memcmp(*currBuf + 4, "moof", 4) || !memcmp(*currBuf + 4, "moov", 4)){
|
||||||
parser = STRM_MP4;
|
parser = STRM_MP4;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -122,34 +154,118 @@ namespace Mist{
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parser == STRM_MP4){
|
if (parser == STRM_MP4){
|
||||||
/// \TODO Implement parsing MP4 data
|
if (mp4PacksLeft){
|
||||||
|
std::deque<size_t>::iterator pIt = mp4PackNo.begin();
|
||||||
|
for (std::deque<MP4::TrackHeader>::iterator it = mp4Headers.begin(); it != mp4Headers.end(); ++it){
|
||||||
|
if (*pIt < it->size()){
|
||||||
|
uint64_t prtBpos = 0, prtTime = 0;
|
||||||
|
uint32_t prtBlen = 0;
|
||||||
|
int32_t prtTimeOff = 0;
|
||||||
|
bool prtKey = false;
|
||||||
|
it->getPart(*pIt, &prtBpos, &prtBlen, &prtTime, &prtTimeOff, &prtKey, lastMoof);
|
||||||
|
// Increase/decrease counters
|
||||||
|
--mp4PacksLeft;
|
||||||
|
++(*pIt);
|
||||||
|
// Abort reading if we cannot read this part, try the next part
|
||||||
|
if (!readTo(prtBpos + prtBlen)){continue;}
|
||||||
|
// Fill the packet and return true
|
||||||
|
thisPacket.genericFill(prtTime, prtTimeOff, it->trackId, *currBuf + prtBpos, prtBlen, bytePos, prtKey);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
++pIt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!mp4PacksLeft){
|
||||||
|
// Read more boxes!
|
||||||
|
if (offset >= currBuf->rsize()){return false;}
|
||||||
|
if (!readTo(offset + 12)){
|
||||||
|
INFO_MSG("Could not read next MP4 box!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::string boxType = std::string(*currBuf+offset+4, 4);
|
||||||
|
uint64_t boxSize = MP4::calcBoxSize(*currBuf+offset);
|
||||||
|
if (!readTo(offset + boxSize)){
|
||||||
|
INFO_MSG("Could not read next MP4 box!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (boxType == "moov"){
|
||||||
|
mp4PacksLeft = 0;
|
||||||
|
mp4Headers.clear();
|
||||||
|
mp4PackNo.clear();
|
||||||
|
MP4::Box moovBox(*currBuf+offset, false);
|
||||||
|
std::deque<MP4::TRAK> trak = ((MP4::MOOV*)&moovBox)->getChildren<MP4::TRAK>();
|
||||||
|
for (std::deque<MP4::TRAK>::iterator trakIt = trak.begin(); trakIt != trak.end(); trakIt++){
|
||||||
|
mp4Headers.push_back(MP4::TrackHeader());
|
||||||
|
mp4PackNo.push_back(0);
|
||||||
|
mp4Headers.rbegin()->read(*trakIt);
|
||||||
|
mp4PacksLeft += mp4Headers.rbegin()->size();
|
||||||
|
}
|
||||||
|
MEDIUM_MSG("Read moov box");
|
||||||
|
}
|
||||||
|
if (boxType == "moof"){
|
||||||
|
if (!mp4Headers.size()){
|
||||||
|
FAIL_MSG("Attempting to read moof box without reading moov box first!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
lastMoof = offset;
|
||||||
|
MP4::Box moofBox(*currBuf+offset, false);
|
||||||
|
// Indicate that we're reading the next moof box to all track headers
|
||||||
|
for (std::deque<MP4::TrackHeader>::iterator it = mp4Headers.begin(); it != mp4Headers.end(); ++it){
|
||||||
|
it->nextMoof();
|
||||||
|
}
|
||||||
|
// Loop over traf boxes inside the moof box, but them in our header parser
|
||||||
|
std::deque<MP4::TRAF> trafs = ((MP4::MOOF*)&moofBox)->getChildren<MP4::TRAF>();
|
||||||
|
for (std::deque<MP4::TRAF>::iterator t = trafs.begin(); t != trafs.end(); ++t){
|
||||||
|
if (!(t->getChild<MP4::TFHD>())){
|
||||||
|
WARN_MSG("Could not find thfd box inside traf box!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
uint32_t trackId = t->getChild<MP4::TFHD>().getTrackID();
|
||||||
|
for (std::deque<MP4::TrackHeader>::iterator it = mp4Headers.begin(); it != mp4Headers.end(); ++it){
|
||||||
|
if (it->trackId == trackId){
|
||||||
|
it->read(*t);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mp4PacksLeft = 0;
|
||||||
|
std::deque<size_t>::iterator pIt = mp4PackNo.begin();
|
||||||
|
for (std::deque<MP4::TrackHeader>::iterator it = mp4Headers.begin(); it != mp4Headers.end(); ++it){
|
||||||
|
mp4PacksLeft += it->size();
|
||||||
|
(*pIt) = 0;
|
||||||
|
++pIt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset += boxSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SegmentReader::setInit(const std::string & data){
|
void SegmentReader::setInit(const std::string & data){
|
||||||
/// \TODO Implement detecting/parsing MP4 init data
|
char * ptr = (char *)data.data();
|
||||||
/*
|
size_t len = data.size();
|
||||||
std::string boxType = std::string(readBuffer+4, 4);
|
size_t offset = 0;
|
||||||
uint64_t boxSize = MP4::calcBoxSize(readBuffer);
|
while (offset + 8 <= len){
|
||||||
|
std::string boxType = std::string(ptr+offset+4, 4);
|
||||||
|
uint64_t boxSize = MP4::calcBoxSize(ptr+offset);
|
||||||
if (boxType == "moov"){
|
if (boxType == "moov"){
|
||||||
while (readBuffer.size() < boxSize && inFile && keepRunning()){inFile.readSome(boxSize-readBuffer.size(), *this);}
|
mp4PacksLeft = 0;
|
||||||
if (readBuffer.size() < boxSize){
|
mp4Headers.clear();
|
||||||
Util::logExitReason(ER_FORMAT_SPECIFIC, "Could not read entire MOOV box into memory");
|
mp4PackNo.clear();
|
||||||
break;
|
MP4::Box moovBox(ptr+offset, false);
|
||||||
}
|
|
||||||
MP4::Box moovBox(readBuffer, false);
|
|
||||||
|
|
||||||
// for all box in moov
|
|
||||||
std::deque<MP4::TRAK> trak = ((MP4::MOOV*)&moovBox)->getChildren<MP4::TRAK>();
|
std::deque<MP4::TRAK> trak = ((MP4::MOOV*)&moovBox)->getChildren<MP4::TRAK>();
|
||||||
for (std::deque<MP4::TRAK>::iterator trakIt = trak.begin(); trakIt != trak.end(); trakIt++){
|
for (std::deque<MP4::TRAK>::iterator trakIt = trak.begin(); trakIt != trak.end(); trakIt++){
|
||||||
trackHeaders.push_back(MP4::TrackHeader());
|
mp4Headers.push_back(MP4::TrackHeader());
|
||||||
trackHeaders.rbegin()->read(*trakIt);
|
mp4PackNo.push_back(0);
|
||||||
|
mp4Headers.rbegin()->read(*trakIt);
|
||||||
|
mp4PacksLeft += mp4Headers.rbegin()->size();
|
||||||
}
|
}
|
||||||
hasMoov = true;
|
MEDIUM_MSG("Read moov box");
|
||||||
|
}
|
||||||
|
offset += boxSize;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores data in currBuf, decodes if/as necessary, in whole 16-byte blocks
|
/// Stores data in currBuf, decodes if/as necessary, in whole 16-byte blocks
|
||||||
|
@ -212,6 +328,11 @@ namespace Mist{
|
||||||
/// Loads the given segment URL into the segment buffer.
|
/// Loads the given segment URL into the segment buffer.
|
||||||
bool SegmentReader::load(const std::string &path, uint64_t startAt, uint64_t stopAt, const char * ivec, const char * keyAES, Util::ResizeablePointer * bufPtr){
|
bool SegmentReader::load(const std::string &path, uint64_t startAt, uint64_t stopAt, const char * ivec, const char * keyAES, Util::ResizeablePointer * bufPtr){
|
||||||
tsStream.partialClear();
|
tsStream.partialClear();
|
||||||
|
lastMoof = 0;
|
||||||
|
for (std::deque<MP4::TrackHeader>::iterator it = mp4Headers.begin(); it != mp4Headers.end(); ++it){
|
||||||
|
it->nextMoof();
|
||||||
|
}
|
||||||
|
|
||||||
isOpen = false;
|
isOpen = false;
|
||||||
parser = STRM_UNKN;
|
parser = STRM_UNKN;
|
||||||
if (ivec && keyAES && memcmp(keyAES, "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16)){
|
if (ivec && keyAES && memcmp(keyAES, "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16)){
|
||||||
|
|
|
@ -42,6 +42,9 @@ namespace Mist{
|
||||||
streamType parser;
|
streamType parser;
|
||||||
TS::Stream tsStream;
|
TS::Stream tsStream;
|
||||||
std::deque<MP4::TrackHeader> mp4Headers;
|
std::deque<MP4::TrackHeader> mp4Headers;
|
||||||
|
std::deque<size_t> mp4PackNo;
|
||||||
|
size_t mp4PacksLeft;
|
||||||
|
uint64_t lastMoof;
|
||||||
|
|
||||||
|
|
||||||
#ifdef SSL
|
#ifdef SSL
|
||||||
|
|
|
@ -1,21 +1,5 @@
|
||||||
#include "input_hls.h"
|
#include "input_hls.h"
|
||||||
#include <cerrno>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include <mist/bitfields.h>
|
|
||||||
#include <mist/defines.h>
|
#include <mist/defines.h>
|
||||||
#include <mist/flv_tag.h>
|
|
||||||
#include <mist/http_parser.h>
|
|
||||||
#include <mist/mp4_generic.h>
|
|
||||||
#include <mist/stream.h>
|
|
||||||
#include <mist/timing.h>
|
|
||||||
#include <mist/tinythread.h>
|
|
||||||
#include <mist/ts_packet.h>
|
|
||||||
#include <string>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#define SEM_TS_CLAIM "/MstTSIN%s"
|
#define SEM_TS_CLAIM "/MstTSIN%s"
|
||||||
|
|
||||||
|
@ -217,7 +201,7 @@ namespace Mist{
|
||||||
}
|
}
|
||||||
|
|
||||||
pls.reload();
|
pls.reload();
|
||||||
playlistMapping[plsTotalCount] = pls;
|
playlistMapping[pls.id] = pls;
|
||||||
plsInitCount++;
|
plsInitCount++;
|
||||||
if (initOnly){
|
if (initOnly){
|
||||||
return;
|
return;
|
||||||
|
@ -275,14 +259,6 @@ namespace Mist{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void flipKey(char *d){
|
|
||||||
for (size_t i = 0; i < 8; i++){
|
|
||||||
char tmp = d[i];
|
|
||||||
d[i] = d[15 - i];
|
|
||||||
d[15 - i] = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Handles both initial load and future reloads.
|
/// Handles both initial load and future reloads.
|
||||||
/// Returns how many segments were added to the internal segment list.
|
/// Returns how many segments were added to the internal segment list.
|
||||||
bool Playlist::reload(){
|
bool Playlist::reload(){
|
||||||
|
@ -411,8 +387,8 @@ namespace Mist{
|
||||||
if (key == "MAP"){
|
if (key == "MAP"){
|
||||||
size_t mapLen = 0, mapOffset = 0;
|
size_t mapLen = 0, mapOffset = 0;
|
||||||
size_t tmpPos = val.find("BYTERANGE=\"");
|
size_t tmpPos = val.find("BYTERANGE=\"");
|
||||||
size_t tmpPos2 = val.substr(tmpPos).find('"');
|
|
||||||
if (tmpPos != std::string::npos){
|
if (tmpPos != std::string::npos){
|
||||||
|
size_t tmpPos2 = val.substr(tmpPos).find('"');
|
||||||
mapRange = val.substr(tmpPos + 11, tmpPos2 - tmpPos - 11);
|
mapRange = val.substr(tmpPos + 11, tmpPos2 - tmpPos - 11);
|
||||||
|
|
||||||
size_t atSign = mapRange.find('@');
|
size_t atSign = mapRange.find('@');
|
||||||
|
@ -427,8 +403,8 @@ namespace Mist{
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpPos = val.find("URI=\"");
|
tmpPos = val.find("URI=\"");
|
||||||
tmpPos2 = val.substr(tmpPos + 5).find('"');
|
|
||||||
if (tmpPos != std::string::npos){
|
if (tmpPos != std::string::npos){
|
||||||
|
size_t tmpPos2 = val.substr(tmpPos + 5).find('"');
|
||||||
mapUri = val.substr(tmpPos + 5, tmpPos2);
|
mapUri = val.substr(tmpPos + 5, tmpPos2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,12 +426,13 @@ namespace Mist{
|
||||||
mapPLen = 0;
|
mapPLen = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!mapLen){mapLen = mapPLen;}
|
||||||
if (mapLen < mapPLen){mapPLen = mapLen;}
|
if (mapLen < mapPLen){mapPLen = mapLen;}
|
||||||
if (!mapPLen){
|
if (!mapPLen){
|
||||||
FAIL_MSG("Could not retrieve map from '%s'", root.link(mapUri).getUrl().c_str());
|
FAIL_MSG("Could not retrieve map from '%s'", root.link(mapUri).getUrl().c_str());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
maps.insert(std::pair<std::string, std::string>(keyUri, std::string(mapPtr, mapPLen)));
|
maps.insert(std::pair<std::string, std::string>(mapUri+mapRange, std::string(mapPtr, mapPLen)));
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -665,9 +642,6 @@ namespace Mist{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InputHLS::~InputHLS(){
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InputHLS::checkArguments(){
|
bool InputHLS::checkArguments(){
|
||||||
config->is_active = true;
|
config->is_active = true;
|
||||||
if (config->getString("input") == "-"){
|
if (config->getString("input") == "-"){
|
||||||
|
@ -751,6 +725,9 @@ namespace Mist{
|
||||||
if (thisEntry.size() >= 11){
|
if (thisEntry.size() >= 11){
|
||||||
newEntry.startAtByte = thisEntry[9u].asInt();
|
newEntry.startAtByte = thisEntry[9u].asInt();
|
||||||
newEntry.stopAtByte = thisEntry[10u].asInt();
|
newEntry.stopAtByte = thisEntry[10u].asInt();
|
||||||
|
if (thisEntry.size() >= 12){
|
||||||
|
newEntry.mapName = thisEntry[11u].asStringRef();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
newList.push_back(newEntry);
|
newList.push_back(newEntry);
|
||||||
}
|
}
|
||||||
|
@ -904,9 +881,12 @@ namespace Mist{
|
||||||
thisEntries.append(entryIt->wait);
|
thisEntries.append(entryIt->wait);
|
||||||
thisEntries.append(entryIt->ivec);
|
thisEntries.append(entryIt->ivec);
|
||||||
thisEntries.append(entryIt->keyAES);
|
thisEntries.append(entryIt->keyAES);
|
||||||
if (entryIt->startAtByte || entryIt->stopAtByte){
|
if (entryIt->startAtByte || entryIt->stopAtByte || entryIt->mapName.size()){
|
||||||
thisEntries.append(entryIt->startAtByte);
|
thisEntries.append(entryIt->startAtByte);
|
||||||
thisEntries.append(entryIt->stopAtByte);
|
thisEntries.append(entryIt->stopAtByte);
|
||||||
|
if (entryIt->mapName.size()){
|
||||||
|
thisEntries.append(entryIt->mapName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
thisPlaylist.append(thisEntries);
|
thisPlaylist.append(thisEntries);
|
||||||
}
|
}
|
||||||
|
@ -1166,7 +1146,6 @@ namespace Mist{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: bpos is overloaded here for playlist entry!
|
|
||||||
void InputHLS::seek(uint64_t seekTime, size_t idx){
|
void InputHLS::seek(uint64_t seekTime, size_t idx){
|
||||||
if (idx == INVALID_TRACK_ID){return;}
|
if (idx == INVALID_TRACK_ID){return;}
|
||||||
plsTimeOffset.clear();
|
plsTimeOffset.clear();
|
||||||
|
@ -1174,10 +1153,10 @@ namespace Mist{
|
||||||
plsInterval.clear();
|
plsInterval.clear();
|
||||||
segDowner.reset();
|
segDowner.reset();
|
||||||
uint64_t trackId = M.getID(idx);
|
uint64_t trackId = M.getID(idx);
|
||||||
|
currentPlaylist = getMappedTrackPlaylist(trackId);
|
||||||
|
|
||||||
unsigned long plistEntry = 0;
|
unsigned long plistEntry = 0;
|
||||||
|
DTSC::Keys keys = M.getKeys(idx);
|
||||||
DTSC::Keys keys(M.keys(idx));
|
|
||||||
for (size_t i = keys.getFirstValid(); i < keys.getEndValid(); i++){
|
for (size_t i = keys.getFirstValid(); i < keys.getEndValid(); i++){
|
||||||
if (keys.getTime(i) > seekTime){
|
if (keys.getTime(i) > seekTime){
|
||||||
VERYHIGH_MSG("Found elapsed key with a time of %" PRIu64 " ms. Using playlist index %zu to match requested time %lu", keys.getTime(i), plistEntry, seekTime);
|
VERYHIGH_MSG("Found elapsed key with a time of %" PRIu64 " ms. Using playlist index %zu to match requested time %lu", keys.getTime(i), plistEntry, seekTime);
|
||||||
|
@ -1191,9 +1170,8 @@ namespace Mist{
|
||||||
plistEntry = keys.getBpos(i) - 1 - playlistMapping[currentPlaylist].firstIndex;
|
plistEntry = keys.getBpos(i) - 1 - playlistMapping[currentPlaylist].firstIndex;
|
||||||
INSANE_MSG("Found valid key with a time of %" PRIu64 " ms at playlist index %zu while seeking", keys.getTime(i), plistEntry);
|
INSANE_MSG("Found valid key with a time of %" PRIu64 " ms at playlist index %zu while seeking", keys.getTime(i), plistEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
currentIndex = plistEntry;
|
currentIndex = plistEntry;
|
||||||
currentPlaylist = getMappedTrackPlaylist(trackId);
|
|
||||||
VERYHIGH_MSG("Seeking to index %zu on playlist %" PRIu64, currentIndex, currentPlaylist);
|
VERYHIGH_MSG("Seeking to index %zu on playlist %" PRIu64, currentIndex, currentPlaylist);
|
||||||
|
|
||||||
{// Lock mutex for listEntries
|
{// Lock mutex for listEntries
|
||||||
|
|
|
@ -100,7 +100,7 @@ namespace Mist{
|
||||||
class InputHLS : public Input{
|
class InputHLS : public Input{
|
||||||
public:
|
public:
|
||||||
InputHLS(Util::Config *cfg);
|
InputHLS(Util::Config *cfg);
|
||||||
~InputHLS();
|
~InputHLS(){}
|
||||||
bool needsLock(){return !config->getBool("realtime");}
|
bool needsLock(){return !config->getBool("realtime");}
|
||||||
bool openStreamSource();
|
bool openStreamSource();
|
||||||
bool callback();
|
bool callback();
|
||||||
|
|
Loading…
Add table
Reference in a new issue