diff --git a/lib/ts_stream.cpp b/lib/ts_stream.cpp index 1cb1537c..b8bf156e 100644 --- a/lib/ts_stream.cpp +++ b/lib/ts_stream.cpp @@ -2,25 +2,24 @@ #include "defines.h" #include "h264.h" #include "h265.h" -#include "nal.h" #include "mp4_generic.h" +#include "nal.h" #include -namespace TS { +namespace TS{ - void ADTSRemainder::setRemainder(const aac::adts & p, const void * source, const uint32_t avail, const uint32_t bPos) { - if (!p.getCompleteSize()) { - return; - } + void ADTSRemainder::setRemainder(const aac::adts &p, const void *source, const uint32_t avail, + const uint32_t bPos){ + if (!p.getCompleteSize()){return;} - if (max < p.getCompleteSize()) { - void * newmainder = realloc(data, p.getCompleteSize()); - if (newmainder) { + if (max < p.getCompleteSize()){ + void *newmainder = realloc(data, p.getCompleteSize()); + if (newmainder){ max = p.getCompleteSize(); data = (char *)newmainder; } } - if (max >= p.getCompleteSize()) { + if (max >= p.getCompleteSize()){ len = p.getCompleteSize(); now = avail; bpos = bPos; @@ -28,8 +27,8 @@ namespace TS { } } - void ADTSRemainder::append(const char * p, uint32_t pLen) { - if (now + pLen > len) { + void ADTSRemainder::append(const char *p, uint32_t pLen){ + if (now + pLen > len){ FAIL_MSG("Data to append does not fit into the remainder"); return; } @@ -38,53 +37,41 @@ namespace TS { now += pLen; } - bool ADTSRemainder::isComplete() { - return (len == now); - } + bool ADTSRemainder::isComplete(){return (len == now);} - void ADTSRemainder::clear() { + void ADTSRemainder::clear(){ len = 0; now = 0; bpos = 0; } - - ADTSRemainder::ADTSRemainder() { + ADTSRemainder::ADTSRemainder(){ data = 0; max = 0; now = 0; len = 0; bpos = 0; } - ADTSRemainder::~ADTSRemainder() { - if (data) { + ADTSRemainder::~ADTSRemainder(){ + if (data){ free(data); data = 0; } } - uint32_t ADTSRemainder::getLength() { - return len; - } + uint32_t ADTSRemainder::getLength(){return len;} - uint32_t ADTSRemainder::getBpos() { - return bpos; - } + uint32_t ADTSRemainder::getBpos(){return bpos;} + uint32_t ADTSRemainder::getTodo(){return len - now;} + char *ADTSRemainder::getData(){return data;} - uint32_t ADTSRemainder::getTodo() { - return len - now; - } - char * ADTSRemainder::getData() { - return data; - } - - Stream::Stream(bool _threaded) { + Stream::Stream(bool _threaded){ threaded = _threaded; firstPacketFound = false; - if (threaded) { + if (threaded){ globalSem.open("MstTSInputLock", O_CREAT | O_RDWR, ACCESSPERMS, 1); - if (!globalSem) { + if (!globalSem){ FAIL_MSG("Creating semaphore failed: %s", strerror(errno)); threaded = false; DEBUG_MSG(DLVL_FAIL, "Creating semaphore failed: %s", strerror(errno)); @@ -93,37 +80,29 @@ namespace TS { } } - Stream::~Stream() { - if (threaded) { - globalSem.unlink(); - } + Stream::~Stream(){ + if (threaded){globalSem.unlink();} } - void Stream::parse(char * newPack, unsigned long long bytePos) { + void Stream::parse(char *newPack, unsigned long long bytePos){ Packet newPacket; newPacket.FromPointer(newPack); parse(newPacket, bytePos); } - void Stream::partialClear() { - if (threaded) { - globalSem.wait(); - } + void Stream::partialClear(){ + if (threaded){globalSem.wait();} pesStreams.clear(); pesPositions.clear(); outPackets.clear(); buildPacket.clear(); partialBuffer.clear(); - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} } - void Stream::clear() { + void Stream::clear(){ partialClear(); - if (threaded) { - globalSem.wait(); - } + if (threaded){globalSem.wait();} pidToCodec.clear(); adtsInfo.clear(); spsInfo.clear(); @@ -137,315 +116,236 @@ namespace TS { pmtTracks.clear(); remainders.clear(); associationTable = ProgramAssociationTable(); - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} } void Stream::finish(){ - if(!pesStreams.size()){return;} + if (!pesStreams.size()){return;} - for(std::map >::const_iterator i = pesStreams.begin(); i != pesStreams.end();i++){ - parsePES(i->first,true); + for (std::map>::const_iterator i = pesStreams.begin(); + i != pesStreams.end(); i++){ + parsePES(i->first, true); } } - void Stream::add(char * newPack, unsigned long long bytePos) { + void Stream::add(char *newPack, unsigned long long bytePos){ Packet newPacket; newPacket.FromPointer(newPack); add(newPacket, bytePos); } - void Stream::add(Packet & newPack, unsigned long long bytePos) { - if (threaded) { - globalSem.wait(); - } + void Stream::add(Packet &newPack, unsigned long long bytePos){ + if (threaded){globalSem.wait();} int tid = newPack.getPID(); - if ((pidToCodec.count(tid) || tid == 0 || newPack.isPMT()) && (pesStreams[tid].size() || newPack.getUnitStart())) { + if ((pidToCodec.count(tid) || tid == 0 || newPack.isPMT()) && + (pesStreams[tid].size() || newPack.getUnitStart())){ pesStreams[tid].push_back(newPack); pesPositions[tid].push_back(bytePos); } - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} } - bool Stream::isDataTrack(unsigned long tid) { - if (tid == 0) { - return false; - } - if (threaded) { - globalSem.wait(); - } + bool Stream::isDataTrack(unsigned long tid){ + if (tid == 0){return false;} + if (threaded){globalSem.wait();} bool result = !pmtTracks.count(tid); - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} return result; } - void Stream::parse(unsigned long tid) { - if (threaded) { - globalSem.wait(); - } - if (!pesStreams.count(tid) || pesStreams[tid].size() == 0) { - if (threaded) { - globalSem.post(); - } + void Stream::parse(unsigned long tid){ + if (threaded){globalSem.wait();} + if (!pesStreams.count(tid) || pesStreams[tid].size() == 0){ + if (threaded){globalSem.post();} return; } - std::deque & trackPackets = pesStreams[tid]; + std::deque &trackPackets = pesStreams[tid]; - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} - //Handle PAT packets - if (tid == 0) { + // Handle PAT packets + if (tid == 0){ ///\todo Keep track of updates in PAT instead of keeping only the last PAT as a reference - if (threaded) { - globalSem.wait(); - } + if (threaded){globalSem.wait();} associationTable = trackPackets.back(); associationTable.parsePIDs(); lastPAT = Util::bootSecs(); - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} int pmtCount = associationTable.getProgramCount(); - for (int i = 0; i < pmtCount; i++) { - pmtTracks.insert(associationTable.getProgramPID(i)); - } + for (int i = 0; i < pmtCount; i++){pmtTracks.insert(associationTable.getProgramPID(i));} - if (threaded) { - globalSem.wait(); - } + if (threaded){globalSem.wait();} pesStreams.erase(0); pesPositions.erase(0); - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} return; } + // Ignore conditional access packets. We don't care. + if (tid == 1){return;} - //Ignore conditional access packets. We don't care. - if (tid == 1) { - return; - } - - //Handle PMT packets - if (pmtTracks.count(tid)) { - ///\todo Keep track of updates in PMT instead of keeping only the last PMT per program as a reference - if (threaded) { - globalSem.wait(); - } + // Handle PMT packets + if (pmtTracks.count(tid)){ + ///\todo Keep track of updates in PMT instead of keeping only the last PMT per program as a + ///reference + if (threaded){globalSem.wait();} mappingTable[tid] = trackPackets.back(); lastPMT[tid] = Util::bootSecs(); - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} ProgramMappingEntry entry = mappingTable[tid].getEntry(0); - while (entry) { + while (entry){ unsigned long pid = entry.getElementaryPid(); unsigned long sType = entry.getStreamType(); - switch (sType) { - case H264: - case AAC: - case H265: - case AC3: - case ID3: - pidToCodec[pid] = sType; - if (sType == ID3) { - metaInit[pid] = std::string(entry.getESInfo(), entry.getESInfoLength()); - } - break; - default: - break; + switch (sType){ + case H264: + case AAC: + case H265: + case AC3: + case ID3: + pidToCodec[pid] = sType; + if (sType == ID3){ + metaInit[pid] = std::string(entry.getESInfo(), entry.getESInfoLength()); + } + break; + default: break; } entry.advance(); } - if (threaded) { - globalSem.wait(); - } + if (threaded){globalSem.wait();} pesStreams.erase(tid); pesPositions.erase(tid); - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} return; } - if (threaded) { - globalSem.wait(); - } + if (threaded){globalSem.wait();} bool parsePes = false; int packNum = 1; - std::deque & inStream = pesStreams[tid]; + std::deque &inStream = pesStreams[tid]; if (!inStream.rbegin()->getUnitStart()){ - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} return; } std::deque::iterator lastPack = inStream.end(); std::deque::iterator curPack = inStream.begin(); curPack++; - while (curPack != lastPack && !curPack->getUnitStart()) { + while (curPack != lastPack && !curPack->getUnitStart()){ curPack++; packNum++; } - if (curPack != lastPack) { - parsePes = true; - } + if (curPack != lastPack){parsePes = true;} - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} - if (parsePes) { - parsePES(tid); - } + if (parsePes){parsePES(tid);} } - void Stream::parse(Packet & newPack, unsigned long long bytePos) { + void Stream::parse(Packet &newPack, unsigned long long bytePos){ add(newPack, bytePos); int tid = newPack.getPID(); parse(tid); } - bool Stream::hasPacketOnEachTrack() const { - if (threaded) { - globalSem.wait(); - } - if (!pidToCodec.size() ) { - - if (threaded) { - globalSem.post(); - } + bool Stream::hasPacketOnEachTrack() const{ + if (threaded){globalSem.wait();} + if (!pidToCodec.size()){ - //INFO_MSG("no packet on each track 1, pidtocodec.size: %d, outpacket.size: %d", pidToCodec.size(), outPackets.size()); + if (threaded){globalSem.post();} + + // INFO_MSG("no packet on each track 1, pidtocodec.size: %d, outpacket.size: %d", + // pidToCodec.size(), outPackets.size()); return false; } - + unsigned int missing = 0; uint64_t firstTime = 0xffffffffffffffffull, lastTime = 0; - for (std::map::const_iterator it = pidToCodec.begin(); it != pidToCodec.end(); it++) { - if (!hasPacket(it->first)) { + for (std::map::const_iterator it = pidToCodec.begin(); + it != pidToCodec.end(); it++){ + if (!hasPacket(it->first)){ missing++; }else{ - if(outPackets.at(it->first).front().getTime() < firstTime){ + if (outPackets.at(it->first).front().getTime() < firstTime){ firstTime = outPackets.at(it->first).front().getTime(); } - if(outPackets.at(it->first).back().getTime() > lastTime){ + if (outPackets.at(it->first).back().getTime() > lastTime){ lastTime = outPackets.at(it->first).back().getTime(); } } } - if (threaded) { - globalSem.post(); - } - + if (threaded){globalSem.post();} + return (!missing || (missing != pidToCodec.size() && lastTime - firstTime > 2000)); } - bool Stream::hasPacket(unsigned long tid) const { - if (threaded) { - globalSem.wait(); - } - if (!pesStreams.count(tid)) { - if (threaded) { - globalSem.post(); - } + bool Stream::hasPacket(unsigned long tid) const{ + if (threaded){globalSem.wait();} + if (!pesStreams.count(tid)){ + if (threaded){globalSem.post();} return false; } - if (outPackets.count(tid) && outPackets.at(tid).size()) { - if (threaded) { - globalSem.post(); - } + if (outPackets.count(tid) && outPackets.at(tid).size()){ + if (threaded){globalSem.post();} return true; } std::deque::const_iterator curPack = pesStreams.at(tid).begin(); - if (curPack != pesStreams.at(tid).end()) { - curPack++; - } + if (curPack != pesStreams.at(tid).end()){curPack++;} - while (curPack != pesStreams.at(tid).end() && !curPack->getUnitStart()) { - curPack++; - } + while (curPack != pesStreams.at(tid).end() && !curPack->getUnitStart()){curPack++;} - if (curPack != pesStreams.at(tid).end()) { - if (threaded) { - globalSem.post(); - } + if (curPack != pesStreams.at(tid).end()){ + if (threaded){globalSem.post();} return true; } - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} return false; } - bool Stream::hasPacket() const { - if (threaded) { - globalSem.wait(); - } - if (!pesStreams.size()) { - if (threaded) { - globalSem.post(); - } + bool Stream::hasPacket() const{ + if (threaded){globalSem.wait();} + if (!pesStreams.size()){ + if (threaded){globalSem.post();} return false; } - - if (outPackets.size()) { - for(std::map >::const_iterator i = outPackets.begin(); i != outPackets.end();i++){ - if(i->second.size()){ - if (threaded) { - globalSem.post(); - } + + if (outPackets.size()){ + for (std::map>::const_iterator i = outPackets.begin(); + i != outPackets.end(); i++){ + if (i->second.size()){ + if (threaded){globalSem.post();} return true; } } } - - - for(std::map >::const_iterator i = pesStreams.begin(); i != pesStreams.end();i++){ + for (std::map>::const_iterator i = pesStreams.begin(); + i != pesStreams.end(); i++){ std::deque::const_iterator curPack = i->second.begin(); - - if(curPack != i->second.end()){ - curPack++; - } - while(curPack != i->second.end() && !curPack->getUnitStart()){ - curPack++; - } - - if(curPack != i->second.end()){ - if (threaded) { - globalSem.post(); - } + if (curPack != i->second.end()){curPack++;} + + while (curPack != i->second.end() && !curPack->getUnitStart()){curPack++;} + + if (curPack != i->second.end()){ + if (threaded){globalSem.post();} return true; } } - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} return false; } - unsigned long long decodePTS(const char * data) { + unsigned long long decodePTS(const char *data){ unsigned long long time; time = ((data[0] >> 1) & 0x07); time <<= 15; @@ -456,59 +356,54 @@ namespace TS { return time; } - void Stream::parsePES(unsigned long tid, bool finished) { - if (!pidToCodec.count(tid)) { - return; //skip unknown codecs + void Stream::parsePES(unsigned long tid, bool finished){ + if (!pidToCodec.count(tid)){ + return; // skip unknown codecs } - if (threaded) { - globalSem.wait(); - } - std::deque & inStream = pesStreams[tid]; - std::deque & inPositions = pesPositions[tid]; - if (inStream.size() <= 1) { - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.wait();} + std::deque &inStream = pesStreams[tid]; + std::deque &inPositions = pesPositions[tid]; + if (inStream.size() <= 1){ + if (threaded){globalSem.post();} return; } - //Find number of packets before unit Start + // Find number of packets before unit Start int packNum = 1; std::deque::iterator curPack = inStream.begin(); curPack++; - while (curPack != inStream.end() && !curPack->getUnitStart()) { + while (curPack != inStream.end() && !curPack->getUnitStart()){ curPack++; packNum++; } - if (!finished && curPack == inStream.end()) { - if (threaded) { - globalSem.post(); - } + if (!finished && curPack == inStream.end()){ + if (threaded){globalSem.post();} return; } unsigned long long bPos = inPositions.front(); - //Create a buffer for the current PES, and remove it from the pesStreams buffer. - int paySize = 0; + // Create a buffer for the current PES, and remove it from the pesStreams buffer. + int paySize = 0; curPack = inStream.begin(); - for (int i = 0; i < packNum; i++) { + for (int i = 0; i < packNum; i++){ paySize += curPack->getPayloadLength(); curPack++; } VERYHIGH_MSG("Parsing PES for track %lu, length %i", tid, paySize); - char * payload = (char *)malloc(paySize); + char *payload = (char *)malloc(paySize); paySize = 0; curPack = inStream.begin(); int lastCtr = curPack->getContinuityCounter() - 1; - for (int i = 0; i < packNum; i++) { - if (curPack->getContinuityCounter() == lastCtr) { + for (int i = 0; i < packNum; i++){ + if (curPack->getContinuityCounter() == lastCtr){ curPack++; continue; } - if (curPack->getContinuityCounter() - lastCtr != 1 && curPack->getContinuityCounter()) { - INFO_MSG("Parsing a pes on track %d, missed %d packets", tid, curPack->getContinuityCounter() - lastCtr - 1); + if (curPack->getContinuityCounter() - lastCtr != 1 && curPack->getContinuityCounter()){ + INFO_MSG("Parsing a pes on track %d, missed %d packets", tid, + curPack->getContinuityCounter() - lastCtr - 1); } lastCtr = curPack->getContinuityCounter(); memcpy(payload + paySize, curPack->getPayload(), curPack->getPayloadLength()); @@ -517,48 +412,49 @@ namespace TS { } inStream.erase(inStream.begin(), curPack); inPositions.erase(inPositions.begin(), inPositions.begin() + packNum); - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} - //Parse the PES header + // Parse the PES header int offset = 0; - while (offset < paySize) { - const char * pesHeader = payload + offset; + while (offset < paySize){ + const char *pesHeader = payload + offset; - //Check for large enough buffer - if ((paySize - offset) < 9 || (paySize - offset) < 9 + pesHeader[8]) { - INFO_MSG("Not enough data on track %lu (%d / %d), discarding remainder of data", tid, paySize - offset, 9 + pesHeader[8]); + // Check for large enough buffer + if ((paySize - offset) < 9 || (paySize - offset) < 9 + pesHeader[8]){ + INFO_MSG("Not enough data on track %lu (%d / %d), discarding remainder of data", tid, + paySize - offset, 9 + pesHeader[8]); break; } - //Check for valid PES lead-in - if (pesHeader[0] != 0 || pesHeader[1] != 0x00 || pesHeader[2] != 0x01) { + // Check for valid PES lead-in + if (pesHeader[0] != 0 || pesHeader[1] != 0x00 || pesHeader[2] != 0x01){ INFO_MSG("Invalid PES Lead in on track %lu, discarding it", tid); break; } - //Read the payload size. - //Note: if the payload size is 0, then we assume the pes packet will cover the entire TS Unit. - //Note: this is technically only allowed for video pes streams. + // Read the payload size. + // Note: if the payload size is 0, then we assume the pes packet will cover the entire TS + // Unit. + // Note: this is technically only allowed for video pes streams. unsigned long long realPayloadSize = (((int)pesHeader[4] << 8) | pesHeader[5]); - if (!realPayloadSize) { + if (!realPayloadSize){ realPayloadSize = paySize; - } else { + }else{ realPayloadSize += 6; } realPayloadSize -= (9 + pesHeader[8]); - //Read the metadata for this PES Packet + // Read the metadata for this PES Packet ///\todo Determine keyframe-ness unsigned int timeStamp = 0; int64_t timeOffset = 0; unsigned int pesOffset = 9; - if ((pesHeader[7] >> 6) & 0x02) { //Check for PTS presence + if ((pesHeader[7] >> 6) & 0x02){// Check for PTS presence timeStamp = decodePTS(pesHeader + pesOffset); pesOffset += 5; - if (((pesHeader[7] & 0xC0) >> 6) & 0x01) { //Check for DTS presence (yes, only if PTS present) + if (((pesHeader[7] & 0xC0) >> 6) & + 0x01){// Check for DTS presence (yes, only if PTS present) timeOffset = timeStamp; timeStamp = decodePTS(pesHeader + pesOffset); pesOffset += 5; @@ -566,216 +462,214 @@ namespace TS { } } - if (pesHeader[7] & 0x20) { //ESCR - ignored + if (pesHeader[7] & 0x20){// ESCR - ignored pesOffset += 6; } - if (pesHeader[7] & 0x10) { //ESR - ignored + if (pesHeader[7] & 0x10){// ESR - ignored pesOffset += 3; } - if (pesHeader[7] & 0x08) { //trick mode - ignored + if (pesHeader[7] & 0x08){// trick mode - ignored pesOffset += 1; } - if (pesHeader[7] & 0x04) { //additional copy - ignored + if (pesHeader[7] & 0x04){// additional copy - ignored pesOffset += 1; } - if (pesHeader[7] & 0x02) { //crc - ignored + if (pesHeader[7] & 0x02){// crc - ignored pesOffset += 2; } - if (paySize - offset - pesOffset < realPayloadSize) { + if (paySize - offset - pesOffset < realPayloadSize){ WARN_MSG("Packet loss detected, glitches will occur"); realPayloadSize = paySize - offset - pesOffset; } - const char * pesPayload = pesHeader + pesOffset; - - if (memmem(pesPayload, realPayloadSize, "DTP2", 4) != 0) { - INFO_MSG("dtp found"); - } + const char *pesPayload = pesHeader + pesOffset; + if (memmem(pesPayload, realPayloadSize, "DTP2", 4) != 0){INFO_MSG("dtp found");} parseBitstream(tid, pesPayload, realPayloadSize, timeStamp, timeOffset, bPos); -//We are done with the realpayload size, reverse calculation so we know the correct offset increase. + // We are done with the realpayload size, reverse calculation so we know the correct offset + // increase. realPayloadSize += (9 + pesHeader[8]); offset += realPayloadSize; } free(payload); } + void Stream::parseBitstream(uint32_t tid, const char *pesPayload, uint32_t realPayloadSize, + uint64_t timeStamp, int64_t timeOffset, uint64_t bPos){ - void Stream::parseBitstream(uint32_t tid, const char * pesPayload, uint32_t realPayloadSize, uint64_t timeStamp, int64_t timeOffset, uint64_t bPos) { - - //Create a new (empty) DTSC Packet at the end of the buffer - if (pidToCodec[tid] == AAC) { - //Parse all the ADTS packets + // Create a new (empty) DTSC Packet at the end of the buffer + if (pidToCodec[tid] == AAC){ + // Parse all the ADTS packets unsigned long offsetInPes = 0; uint64_t msRead = 0; - if (threaded) { - globalSem.wait(); - } + if (threaded){globalSem.wait();} - if (remainders.count(tid) && remainders[tid].getLength()) { - offsetInPes = std::min((unsigned long)(remainders[tid].getTodo()), (unsigned long)realPayloadSize); + if (remainders.count(tid) && remainders[tid].getLength()){ + offsetInPes = + std::min((unsigned long)(remainders[tid].getTodo()), (unsigned long)realPayloadSize); remainders[tid].append(pesPayload, offsetInPes); - if (remainders[tid].isComplete()) { + if (remainders[tid].isComplete()){ aac::adts adtsPack(remainders[tid].getData(), remainders[tid].getLength()); - if (adtsPack) { - if (!adtsInfo.count(tid) || !adtsInfo[tid].sameHeader(adtsPack)) { + if (adtsPack){ + if (!adtsInfo.count(tid) || !adtsInfo[tid].sameHeader(adtsPack)){ MEDIUM_MSG("Setting new ADTS header: %s", adtsPack.toPrettyString().c_str()); adtsInfo[tid] = adtsPack; } outPackets[tid].push_back(DTSC::Packet()); - outPackets[tid].back().genericFill(timeStamp - ((adtsPack.getSampleCount() * 1000) / adtsPack.getFrequency()), timeOffset, tid, adtsPack.getPayload(), adtsPack.getPayloadSize(), remainders[tid].getBpos(), 0); + outPackets[tid].back().genericFill( + timeStamp - ((adtsPack.getSampleCount() * 1000) / adtsPack.getFrequency()), + timeOffset, tid, adtsPack.getPayload(), adtsPack.getPayloadSize(), + remainders[tid].getBpos(), 0); } remainders[tid].clear(); } } - while (offsetInPes < realPayloadSize) { + while (offsetInPes < realPayloadSize){ aac::adts adtsPack(pesPayload + offsetInPes, realPayloadSize - offsetInPes); - if (adtsPack && adtsPack.getCompleteSize() + offsetInPes <= realPayloadSize) { - if (!adtsInfo.count(tid) || !adtsInfo[tid].sameHeader(adtsPack)) { + if (adtsPack && adtsPack.getCompleteSize() + offsetInPes <= realPayloadSize){ + if (!adtsInfo.count(tid) || !adtsInfo[tid].sameHeader(adtsPack)){ MEDIUM_MSG("Setting new ADTS header: %s", adtsPack.toPrettyString().c_str()); adtsInfo[tid] = adtsPack; } outPackets[tid].push_back(DTSC::Packet()); - outPackets[tid].back().genericFill(timeStamp + msRead, timeOffset, tid, adtsPack.getPayload(), adtsPack.getPayloadSize(), bPos, 0); + outPackets[tid].back().genericFill(timeStamp + msRead, timeOffset, tid, + adtsPack.getPayload(), adtsPack.getPayloadSize(), bPos, + 0); msRead += (adtsPack.getSampleCount() * 1000) / adtsPack.getFrequency(); offsetInPes += adtsPack.getCompleteSize(); - } else { + }else{ /// \todo What about the case that we have an invalid start, going over the PES boundary? - if (!adtsPack.hasSync()) { + if (!adtsPack.hasSync()){ offsetInPes++; - } else { - //remainder, keep it, use it next time - remainders[tid].setRemainder(adtsPack, pesPayload + offsetInPes, realPayloadSize - offsetInPes, bPos); - offsetInPes = realPayloadSize;//skip to end of PES + }else{ + // remainder, keep it, use it next time + remainders[tid].setRemainder(adtsPack, pesPayload + offsetInPes, + realPayloadSize - offsetInPes, bPos); + offsetInPes = realPayloadSize; // skip to end of PES } } } - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} } - if (pidToCodec[tid] == ID3 || pidToCodec[tid] == AC3) { - if (threaded) { - globalSem.wait(); - } + if (pidToCodec[tid] == ID3 || pidToCodec[tid] == AC3){ + if (threaded){globalSem.wait();} outPackets[tid].push_back(DTSC::Packet()); - outPackets[tid].back().genericFill(timeStamp, timeOffset, tid, pesPayload, realPayloadSize, bPos, 0); + outPackets[tid].back().genericFill(timeStamp, timeOffset, tid, pesPayload, realPayloadSize, + bPos, 0); - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} } - - if (pidToCodec[tid] == H264 || pidToCodec[tid] == H265) { - //loop through scanAnnexB until startcode is found, if packetPointer equals NULL, then read next PES packet + if (pidToCodec[tid] == H264 || pidToCodec[tid] == H265){ + // loop through scanAnnexB until startcode is found, if packetPointer equals NULL, then read + // next PES packet bool completePES = false; - const char * packetPtr; - const char * nalEnd; + const char *packetPtr; + const char *nalEnd; bool checkForKeyFrame = true; bool isKeyFrame = false; int nalRemove = 0; bool clearKey = false; nalu::scanAnnexB(pesPayload, realPayloadSize, packetPtr); -// std::cerr << "\t\tNew PES Packet" << std::endl; - while (!completePES) { + // std::cerr << "\t\tNew PES Packet" << std::endl; + while (!completePES){ - if (packetPtr) { - //when startcode is found, check if we were already constructing a packet. - if (!partialBuffer[tid].empty()) { - parseNal(tid, partialBuffer[tid].c_str(), partialBuffer[tid].c_str() + partialBuffer[tid].length(), isKeyFrame); - } else { + if (packetPtr){ + // when startcode is found, check if we were already constructing a packet. + if (!partialBuffer[tid].empty()){ + parseNal(tid, partialBuffer[tid].c_str(), + partialBuffer[tid].c_str() + partialBuffer[tid].length(), isKeyFrame); + }else{ parseNal(tid, pesPayload, packetPtr, isKeyFrame); } - if (!isKeyFrame || clearKey) { - clearKey = true; - } + if (!isKeyFrame || clearKey){clearKey = true;} nalEnd = nalu::nalEndPosition(pesPayload, packetPtr - pesPayload); nalRemove = packetPtr - nalEnd; - if (firstPacketFound && checkForKeyFrame) { - checkForKeyFrame = false; - } + if (firstPacketFound && checkForKeyFrame){checkForKeyFrame = false;} - if (!buildPacket[tid] && !firstPacketFound) { - //clean start - //remove everything before this point as this is the very first hal packet. - if (partialBuffer[tid].empty() && !firstPacketFound) { //if buffer is empty - //very first packet, check for keyframe + if (!buildPacket[tid] && !firstPacketFound){ + // clean start + // remove everything before this point as this is the very first hal packet. + if (partialBuffer[tid].empty() && !firstPacketFound){// if buffer is empty + // very first packet, check for keyframe checkForKeyFrame = true; - } + } firstPacketFound = true; - } else { - if (!buildPacket[tid]) { //when no data in packet -> genericFill - buildPacket[tid].genericFill(timeStamp, timeOffset, tid, "\000\000\000\002\011\360", 6, bPos, true); + }else{ + if (!buildPacket[tid]){// when no data in packet -> genericFill + buildPacket[tid].genericFill(timeStamp, timeOffset, tid, "\000\000\000\002\011\360", + 6, bPos, true); } - //if the timestamp differs from current PES timestamp, send the previous packet out and fill a new one. - if (buildPacket[tid].getTime() != timeStamp) { - //next packet's timestamp differs from current timestamp, add hal packet to buildpacket and send it out. - if (!partialBuffer[tid].empty()) { - //std::cerr << "append remaining data to partialbuffer" << std::endl; + // if the timestamp differs from current PES timestamp, send the previous packet out and + // fill a new one. + if (buildPacket[tid].getTime() != timeStamp){ + // next packet's timestamp differs from current timestamp, add hal packet to + // buildpacket and send it out. + if (!partialBuffer[tid].empty()){ + // std::cerr << "append remaining data to partialbuffer" << std::endl; buildPacket[tid].appendNal(partialBuffer[tid].c_str(), partialBuffer[tid].length(), - partialBuffer[tid].length() + (packetPtr - pesPayload) - nalRemove); + partialBuffer[tid].length() + (packetPtr - pesPayload) - + nalRemove); buildPacket[tid].appendData(pesPayload, (packetPtr - pesPayload) - nalRemove); - if (clearKey) { - buildPacket[tid].clearKeyFrame(); - } + if (clearKey){buildPacket[tid].clearKeyFrame();} outPackets[tid].push_back(buildPacket[tid]); buildPacket[tid].null(); - buildPacket[tid].genericFill(timeStamp, timeOffset, tid, "\000\000\000\002\011\360", 6, bPos, true); + buildPacket[tid].genericFill(timeStamp, timeOffset, tid, "\000\000\000\002\011\360", + 6, bPos, true); partialBuffer[tid].clear(); - } else { - if (clearKey) { - buildPacket[tid].clearKeyFrame(); - } + }else{ + if (clearKey){buildPacket[tid].clearKeyFrame();} outPackets[tid].push_back(buildPacket[tid]); buildPacket[tid].null(); - buildPacket[tid].genericFill(timeStamp, timeOffset, tid, "\000\000\000\002\011\360", 6, bPos, true); + buildPacket[tid].genericFill(timeStamp, timeOffset, tid, "\000\000\000\002\011\360", + 6, bPos, true); - buildPacket[tid].appendNal(pesPayload, (packetPtr - pesPayload) - nalRemove, (packetPtr - pesPayload) - nalRemove); + buildPacket[tid].appendNal(pesPayload, (packetPtr - pesPayload) - nalRemove, + (packetPtr - pesPayload) - nalRemove); } - if (threaded) { - globalSem.wait(); - } + if (threaded){globalSem.wait();} - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} - } else { - //we have a partial packet which belongs to the previous packet in partialBuffer. - if (!partialBuffer[tid].empty()) { //if buffer is used + }else{ + // we have a partial packet which belongs to the previous packet in partialBuffer. + if (!partialBuffer[tid].empty()){// if buffer is used buildPacket[tid].appendNal(partialBuffer[tid].c_str(), partialBuffer[tid].length(), - partialBuffer[tid].length() + (packetPtr - pesPayload) - nalRemove); + partialBuffer[tid].length() + (packetPtr - pesPayload) - + nalRemove); buildPacket[tid].appendData(pesPayload, (packetPtr - pesPayload) - nalRemove); - partialBuffer.clear(); + partialBuffer.clear(); - } else { - //hal packet at first position -// buildPacket[tid].appendData(pesPayload, packetPtr-pesPayload); //append part before the startcode. - buildPacket[tid].appendNal(pesPayload, (packetPtr - pesPayload) - nalRemove, (packetPtr - pesPayload) - nalRemove); //append part before the startcode. + }else{ + // hal packet at first position + // buildPacket[tid].appendData(pesPayload, packetPtr-pesPayload); + // //append part before the startcode. + buildPacket[tid].appendNal(pesPayload, (packetPtr - pesPayload) - nalRemove, + (packetPtr - pesPayload) - + nalRemove); // append part before the startcode. } } } - realPayloadSize -= ((packetPtr - pesPayload) + 3); //decrease the total size + realPayloadSize -= ((packetPtr - pesPayload) + 3); // decrease the total size pesPayload = packetPtr + 3; - } else { //no startcode found... - if (partialBuffer[tid].empty()) { + }else{// no startcode found... + if (partialBuffer[tid].empty()){ partialBuffer[tid].assign(pesPayload, realPayloadSize); - } else { + }else{ partialBuffer[tid].append(pesPayload, realPayloadSize); } @@ -784,349 +678,295 @@ namespace TS { nalu::scanAnnexB(pesPayload, realPayloadSize, packetPtr); } - } - } - void Stream::getPacket(unsigned long tid, DTSC::Packet & pack) { + void Stream::getPacket(unsigned long tid, DTSC::Packet &pack){ pack.null(); - if (!hasPacket(tid)) { + if (!hasPacket(tid)){ ERROR_MSG("Trying to obtain a packet on track %lu, but no full packet is available", tid); return; } - if (threaded) { - globalSem.wait(); - } + if (threaded){globalSem.wait();} bool packetReady = outPackets.count(tid) && outPackets[tid].size(); - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} - if (!packetReady) { - parse(tid); - } + if (!packetReady){parse(tid);} - if (threaded) { - globalSem.wait(); - } + if (threaded){globalSem.wait();} packetReady = outPackets.count(tid) && outPackets[tid].size(); - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} - if (!packetReady) { + if (!packetReady){ ERROR_MSG("Obtaining a packet on track %lu failed", tid); return; } - if (threaded) { - globalSem.wait(); - } + if (threaded){globalSem.wait();} pack = outPackets[tid].front(); outPackets[tid].pop_front(); - if (!outPackets[tid].size()) { - outPackets.erase(tid); - } + if (!outPackets[tid].size()){outPackets.erase(tid);} - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} } - void Stream::parseNal(uint32_t tid, const char * pesPayload, const char * packetPtr, bool & isKeyFrame) { - //bool isKeyFrame = false; - //const char * packetPtr; + void Stream::parseNal(uint32_t tid, const char *pesPayload, const char *packetPtr, + bool &isKeyFrame){ + // bool isKeyFrame = false; + // const char * packetPtr; bool firstSlice = true; char typeNal; isKeyFrame = false; typeNal = pesPayload[0] & 0x1F; - if (pidToCodec[tid] == H264) { - switch (typeNal) { - case 0x01: { - if (firstSlice) { - firstSlice = false; - if (!isKeyFrame) { - Utils::bitstream bs; - for (size_t i = 1; i < 10 && i < (packetPtr - pesPayload); i++) { - if (i + 2 < (packetPtr - pesPayload) && (memcmp(pesPayload + i, "\000\000\003", 3) == 0)) { //Emulation prevention bytes - bs.append(pesPayload + i, 2); - i += 2; - } else { - bs.append(pesPayload + i, 1); - } - } - bs.getExpGolomb();//Discard first_mb_in_slice - uint64_t sliceType = bs.getUExpGolomb(); - if (sliceType == 2 || sliceType == 4 || sliceType == 7 || sliceType == 9) { - isKeyFrame = true; - } + if (pidToCodec[tid] == H264){ + switch (typeNal){ + case 0x01:{ + if (firstSlice){ + firstSlice = false; + if (!isKeyFrame){ + Utils::bitstream bs; + for (size_t i = 1; i < 10 && i < (packetPtr - pesPayload); i++){ + if (i + 2 < (packetPtr - pesPayload) && + (memcmp(pesPayload + i, "\000\000\003", 3) == 0)){// Emulation prevention bytes + bs.append(pesPayload + i, 2); + i += 2; + }else{ + bs.append(pesPayload + i, 1); } } - break; - } - case 0x05: { - isKeyFrame = true; - break; - } - case 0x07: { - if (threaded) { - globalSem.wait(); + bs.getExpGolomb(); // Discard first_mb_in_slice + uint64_t sliceType = bs.getUExpGolomb(); + if (sliceType == 2 || sliceType == 4 || sliceType == 7 || sliceType == 9){ + isKeyFrame = true; } - spsInfo[tid] = std::string(pesPayload, (packetPtr - pesPayload)); - if (threaded) { - globalSem.post(); - } - break; } - case 0x08: { - if (threaded) { - globalSem.wait(); - } - ppsInfo[tid] = std::string(pesPayload, (packetPtr - pesPayload)); - if (threaded) { - globalSem.post(); - } - break; - } - default: - break; + } + break; } - } else if (pidToCodec[tid] == H265) { - switch (typeNal) { - case 2: - case 3: //TSA Picture - case 4: - case 5: //STSA Picture - case 6: - case 7: //RADL Picture - case 8: - case 9: //RASL Picture - case 16: - case 17: - case 18: //BLA Picture - case 19: - case 20: //IDR Picture - case 21: { //CRA Picture - isKeyFrame = true; - break; - } - case 32: - case 33: - case 34: { - if (threaded) { - globalSem.wait(); - } - hevcInfo[tid].addUnit((char *)pesPayload);//may i convert to (char *)? - if (threaded) { - globalSem.post(); - } - break; - } - default: - break; + case 0x05:{ + isKeyFrame = true; + break; + } + case 0x07:{ + if (threaded){globalSem.wait();} + spsInfo[tid] = std::string(pesPayload, (packetPtr - pesPayload)); + if (threaded){globalSem.post();} + break; + } + case 0x08:{ + if (threaded){globalSem.wait();} + ppsInfo[tid] = std::string(pesPayload, (packetPtr - pesPayload)); + if (threaded){globalSem.post();} + break; + } + default: break; + } + }else if (pidToCodec[tid] == H265){ + switch (typeNal){ + case 2: + case 3: // TSA Picture + case 4: + case 5: // STSA Picture + case 6: + case 7: // RADL Picture + case 8: + case 9: // RASL Picture + case 16: + case 17: + case 18: // BLA Picture + case 19: + case 20: // IDR Picture + case 21:{// CRA Picture + isKeyFrame = true; + break; + } + case 32: + case 33: + case 34:{ + if (threaded){globalSem.wait();} + hevcInfo[tid].addUnit((char *)pesPayload); // may i convert to (char *)? + if (threaded){globalSem.post();} + break; + } + default: break; } } } - void Stream::getEarliestPacket(DTSC::Packet & pack) { - if (threaded) { - globalSem.wait(); - } + void Stream::getEarliestPacket(DTSC::Packet &pack){ + if (threaded){globalSem.wait();} pack.null(); unsigned long packTime = 0xFFFFFFFFull; unsigned long packTrack = 0; - for (std::map >::iterator it = outPackets.begin(); it != outPackets.end(); it++) { - if (it->second.front().getTime() < packTime) { + for (std::map>::iterator it = outPackets.begin(); + it != outPackets.end(); it++){ + if (it->second.front().getTime() < packTime){ packTrack = it->first; packTime = it->second.front().getTime(); } } - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} - if(packTrack){ - getPacket(packTrack, pack); - } + if (packTrack){getPacket(packTrack, pack);} } - void Stream::initializeMetadata(DTSC::Meta & meta, unsigned long tid, unsigned long mappingId) { - if (threaded) { - globalSem.wait(); - } + void Stream::initializeMetadata(DTSC::Meta &meta, unsigned long tid, unsigned long mappingId){ + if (threaded){globalSem.wait();} unsigned long mId = mappingId; - for (std::map::const_iterator it = pidToCodec.begin(); it != pidToCodec.end(); it++) { - if (tid && it->first != tid) { - continue; - } + for (std::map::const_iterator it = pidToCodec.begin(); + it != pidToCodec.end(); it++){ + if (tid && it->first != tid){continue;} - if (mId == 0) { - mId = it->first; - } + if (mId == 0){mId = it->first;} - if (meta.tracks.count(mId) && meta.tracks[mId].codec.size()) { - continue; - } + if (meta.tracks.count(mId) && meta.tracks[mId].codec.size()){continue;} - switch (it->second) { - case H264: { - if (!spsInfo.count(it->first) || !ppsInfo.count(it->first)) { - MEDIUM_MSG("Aborted meta fill for h264 track %lu: no SPS/PPS", it->first); - continue; + switch (it->second){ + case H264:{ + if (!spsInfo.count(it->first) || !ppsInfo.count(it->first)){ + MEDIUM_MSG("Aborted meta fill for h264 track %lu: no SPS/PPS", it->first); + continue; + } + meta.tracks[mId].type = "video"; + meta.tracks[mId].codec = "H264"; + meta.tracks[mId].trackID = mId; + std::string tmpBuffer = spsInfo[it->first]; + h264::sequenceParameterSet sps(spsInfo[it->first].data(), spsInfo[it->first].size()); + h264::SPSMeta spsChar = sps.getCharacteristics(); + meta.tracks[mId].width = spsChar.width; + meta.tracks[mId].height = spsChar.height; + meta.tracks[mId].fpks = spsChar.fps * 1000; + MP4::AVCC avccBox; + avccBox.setVersion(1); + avccBox.setProfile(spsInfo[it->first][1]); + avccBox.setCompatibleProfiles(spsInfo[it->first][2]); + avccBox.setLevel(spsInfo[it->first][3]); + avccBox.setSPSNumber(1); + avccBox.setSPS(spsInfo[it->first]); + avccBox.setPPSNumber(1); + avccBox.setPPS(ppsInfo[it->first]); + meta.tracks[mId].init = std::string(avccBox.payload(), avccBox.payloadSize()); + }break; + case H265:{ + if (!hevcInfo.count(it->first) || !hevcInfo[it->first].haveRequired()){ + MEDIUM_MSG("Aborted meta fill for hevc track %lu: no info nal unit", it->first); + continue; + } + meta.tracks[mId].type = "video"; + meta.tracks[mId].codec = "HEVC"; + meta.tracks[mId].trackID = mId; + meta.tracks[mId].init = hevcInfo[it->first].generateHVCC(); + int pmtCount = associationTable.getProgramCount(); + for (int i = 0; i < pmtCount; i++){ + int pid = associationTable.getProgramPID(i); + ProgramMappingEntry entry = mappingTable[pid].getEntry(0); + while (entry){ + if (entry.getElementaryPid() == tid){ + meta.tracks[mId].lang = + ProgramDescriptors(entry.getESInfo(), entry.getESInfoLength()).getLanguage(); } - meta.tracks[mId].type = "video"; - meta.tracks[mId].codec = "H264"; - meta.tracks[mId].trackID = mId; - std::string tmpBuffer = spsInfo[it->first]; - h264::sequenceParameterSet sps(spsInfo[it->first].data(), spsInfo[it->first].size()); - h264::SPSMeta spsChar = sps.getCharacteristics(); - meta.tracks[mId].width = spsChar.width; - meta.tracks[mId].height = spsChar.height; - meta.tracks[mId].fpks = spsChar.fps * 1000; - MP4::AVCC avccBox; - avccBox.setVersion(1); - avccBox.setProfile(spsInfo[it->first][1]); - avccBox.setCompatibleProfiles(spsInfo[it->first][2]); - avccBox.setLevel(spsInfo[it->first][3]); - avccBox.setSPSNumber(1); - avccBox.setSPS(spsInfo[it->first]); - avccBox.setPPSNumber(1); - avccBox.setPPS(ppsInfo[it->first]); - meta.tracks[mId].init = std::string(avccBox.payload(), avccBox.payloadSize()); + entry.advance(); } - break; - case H265: { - if (!hevcInfo.count(it->first) || !hevcInfo[it->first].haveRequired()) { - MEDIUM_MSG("Aborted meta fill for hevc track %lu: no info nal unit", it->first); - continue; - } - meta.tracks[mId].type = "video"; - meta.tracks[mId].codec = "HEVC"; - meta.tracks[mId].trackID = mId; - meta.tracks[mId].init = hevcInfo[it->first].generateHVCC(); - int pmtCount = associationTable.getProgramCount(); - for (int i = 0; i < pmtCount; i++) { - int pid = associationTable.getProgramPID(i); - ProgramMappingEntry entry = mappingTable[pid].getEntry(0); - while (entry) { - if (entry.getElementaryPid() == tid) { - meta.tracks[mId].lang = ProgramDescriptors(entry.getESInfo(), entry.getESInfoLength()).getLanguage(); - } - entry.advance(); - } - } - } - break; - case ID3: { - meta.tracks[mId].type = "meta"; - meta.tracks[mId].codec = "ID3"; - meta.tracks[mId].trackID = mId; - meta.tracks[mId].init = metaInit[it->first]; - } - break; - case AC3: { - meta.tracks[mId].type = "audio"; - meta.tracks[mId].codec = "AC3"; - meta.tracks[mId].trackID = mId; - meta.tracks[mId].size = 16; - ///\todo Fix these 2 values - meta.tracks[mId].rate = 0; - meta.tracks[mId].channels = 0; - } - break; - case AAC: { - meta.tracks[mId].type = "audio"; - meta.tracks[mId].codec = "AAC"; - meta.tracks[mId].trackID = mId; - meta.tracks[mId].size = 16; - meta.tracks[mId].rate = adtsInfo[it->first].getFrequency(); - meta.tracks[mId].channels = adtsInfo[it->first].getChannelCount(); - char audioInit[2];//5 bits object type, 4 bits frequency index, 4 bits channel index - audioInit[0] = ((adtsInfo[it->first].getAACProfile() & 0x1F) << 3) | ((adtsInfo[it->first].getFrequencyIndex() & 0x0E) >> 1); - audioInit[1] = ((adtsInfo[it->first].getFrequencyIndex() & 0x01) << 7) | ((adtsInfo[it->first].getChannelConfig() & 0x0F) << 3); - meta.tracks[mId].init = std::string(audioInit, 2); - } - break; + } + }break; + case ID3:{ + meta.tracks[mId].type = "meta"; + meta.tracks[mId].codec = "ID3"; + meta.tracks[mId].trackID = mId; + meta.tracks[mId].init = metaInit[it->first]; + }break; + case AC3:{ + meta.tracks[mId].type = "audio"; + meta.tracks[mId].codec = "AC3"; + meta.tracks[mId].trackID = mId; + meta.tracks[mId].size = 16; + ///\todo Fix these 2 values + meta.tracks[mId].rate = 0; + meta.tracks[mId].channels = 0; + }break; + case AAC:{ + meta.tracks[mId].type = "audio"; + meta.tracks[mId].codec = "AAC"; + meta.tracks[mId].trackID = mId; + meta.tracks[mId].size = 16; + meta.tracks[mId].rate = adtsInfo[it->first].getFrequency(); + meta.tracks[mId].channels = adtsInfo[it->first].getChannelCount(); + char audioInit[2]; // 5 bits object type, 4 bits frequency index, 4 bits channel index + audioInit[0] = ((adtsInfo[it->first].getAACProfile() & 0x1F) << 3) | + ((adtsInfo[it->first].getFrequencyIndex() & 0x0E) >> 1); + audioInit[1] = ((adtsInfo[it->first].getFrequencyIndex() & 0x01) << 7) | + ((adtsInfo[it->first].getChannelConfig() & 0x0F) << 3); + meta.tracks[mId].init = std::string(audioInit, 2); + }break; } int pmtCount = associationTable.getProgramCount(); - for (int i = 0; i < pmtCount; i++) { + for (int i = 0; i < pmtCount; i++){ int pid = associationTable.getProgramPID(i); ProgramMappingEntry entry = mappingTable[pid].getEntry(0); - while (entry) { - if (entry.getElementaryPid() == tid) { - meta.tracks[mId].lang = ProgramDescriptors(entry.getESInfo(), entry.getESInfoLength()).getLanguage(); + while (entry){ + if (entry.getElementaryPid() == tid){ + meta.tracks[mId].lang = + ProgramDescriptors(entry.getESInfo(), entry.getESInfoLength()).getLanguage(); } entry.advance(); } } - MEDIUM_MSG("Initialized track %lu as %s %s", it->first, meta.tracks[mId].codec.c_str(), meta.tracks[mId].type.c_str()); - } - if (threaded) { - globalSem.post(); + MEDIUM_MSG("Initialized track %lu as %s %s", it->first, meta.tracks[mId].codec.c_str(), + meta.tracks[mId].type.c_str()); } + if (threaded){globalSem.post();} } - std::set Stream::getActiveTracks() { - if (threaded) { - globalSem.wait(); - } + std::set Stream::getActiveTracks(){ + if (threaded){globalSem.wait();} std::set result; - //Track 0 is always active + // Track 0 is always active result.insert(0); - //IF PAT updated in the last 5 seconds, check for contents - if (Util::bootSecs() - lastPAT < 5) { + // IF PAT updated in the last 5 seconds, check for contents + if (Util::bootSecs() - lastPAT < 5){ int pmtCount = associationTable.getProgramCount(); - //For each PMT - for (int i = 0; i < pmtCount; i++) { + // For each PMT + for (int i = 0; i < pmtCount; i++){ int pid = associationTable.getProgramPID(i); - //Add PMT track + // Add PMT track result.insert(pid); - //IF PMT updated in last 5 seconds, check for contents - if (Util::bootSecs() - lastPMT[pid] < 5) { + // IF PMT updated in last 5 seconds, check for contents + if (Util::bootSecs() - lastPMT[pid] < 5){ ProgramMappingEntry entry = mappingTable[pid].getEntry(0); - //Add all tracks in PMT - while (entry) { - switch (entry.getStreamType()) { - case H264: - case AAC: - case H265: - case AC3: - case ID3: - result.insert(entry.getElementaryPid()); - break; - default: - break; + // Add all tracks in PMT + while (entry){ + switch (entry.getStreamType()){ + case H264: + case AAC: + case H265: + case AC3: + case ID3: result.insert(entry.getElementaryPid()); break; + default: break; } entry.advance(); } } } } - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} return result; } - void Stream::eraseTrack(unsigned long tid) { - if (threaded) { - globalSem.wait(); - } + void Stream::eraseTrack(unsigned long tid){ + if (threaded){globalSem.wait();} pesStreams.erase(tid); pesPositions.erase(tid); outPackets.erase(tid); - if (threaded) { - globalSem.post(); - } + if (threaded){globalSem.post();} } } + diff --git a/lib/ts_stream.h b/lib/ts_stream.h index 7dffa8ad..46cb92a4 100644 --- a/lib/ts_stream.h +++ b/lib/ts_stream.h @@ -1,94 +1,92 @@ -#include "ts_packet.h" #include "adts.h" +#include "h265.h" +#include "ts_packet.h" +#include #include #include -#include -#include "h265.h" #include "shared_memory.h" -namespace TS { - enum codecType { - H264 = 0x1B, - AAC = 0x0F, - AC3 = 0x81, - MP3 = 0x03, - H265 = 0x24, - ID3 = 0x15 - }; - +namespace TS{ + enum codecType{H264 = 0x1B, AAC = 0x0F, AC3 = 0x81, MP3 = 0x03, H265 = 0x24, ID3 = 0x15}; + class ADTSRemainder{ - private: - char * data; - uint32_t max; - uint32_t now; - uint32_t len; - uint32_t bpos; - public: - void setRemainder(const aac::adts & p, const void * source, const uint32_t avail, const uint32_t bPos); - - ADTSRemainder(); - ~ADTSRemainder(); - uint32_t getLength(); - uint32_t getBpos(); - uint32_t getTodo(); - char* getData(); - - void append(const char *p,uint32_t pLen); - bool isComplete(); - void clear(); + private: + char *data; + uint32_t max; + uint32_t now; + uint32_t len; + uint32_t bpos; + + public: + void setRemainder(const aac::adts &p, const void *source, const uint32_t avail, + const uint32_t bPos); + + ADTSRemainder(); + ~ADTSRemainder(); + uint32_t getLength(); + uint32_t getBpos(); + uint32_t getTodo(); + char *getData(); + + void append(const char *p, uint32_t pLen); + bool isComplete(); + void clear(); }; class Stream{ - public: - Stream(bool _threaded = false); - ~Stream(); - void add(char * newPack, unsigned long long bytePos = 0); - void add(Packet & newPack, unsigned long long bytePos = 0); - void parse(Packet & newPack, unsigned long long bytePos); - void parse(char * newPack, unsigned long long bytePos); - void parse(unsigned long tid); - void parseNal(uint32_t tid, const char *pesPayload, const char * packetPtr, bool &isKeyFrame); - bool hasPacketOnEachTrack() const; - bool hasPacket(unsigned long tid) const; - bool hasPacket() const; - void getPacket(unsigned long tid, DTSC::Packet & pack); - void getEarliestPacket(DTSC::Packet & pack); - void initializeMetadata(DTSC::Meta & meta, unsigned long tid = 0, unsigned long mappingId = 0); - void partialClear(); - void clear(); - void finish(); - void eraseTrack(unsigned long tid); - bool isDataTrack(unsigned long tid); - void parseBitstream(uint32_t tid, const char * pesPayload, uint32_t realPayloadSize,uint64_t timeStamp, int64_t timeOffset, uint64_t bPos); - std::set getActiveTracks(); - private: - unsigned long long lastPAT; - ProgramAssociationTable associationTable; - std::map remainders; - - bool firstPacketFound; - std::map lastPMT; - std::map mappingTable; + public: + Stream(bool _threaded = false); + ~Stream(); + void add(char *newPack, unsigned long long bytePos = 0); + void add(Packet &newPack, unsigned long long bytePos = 0); + void parse(Packet &newPack, unsigned long long bytePos); + void parse(char *newPack, unsigned long long bytePos); + void parse(unsigned long tid); + void parseNal(uint32_t tid, const char *pesPayload, const char *packetPtr, bool &isKeyFrame); + bool hasPacketOnEachTrack() const; + bool hasPacket(unsigned long tid) const; + bool hasPacket() const; + void getPacket(unsigned long tid, DTSC::Packet &pack); + void getEarliestPacket(DTSC::Packet &pack); + void initializeMetadata(DTSC::Meta &meta, unsigned long tid = 0, unsigned long mappingId = 0); + void partialClear(); + void clear(); + void finish(); + void eraseTrack(unsigned long tid); + bool isDataTrack(unsigned long tid); + void parseBitstream(uint32_t tid, const char *pesPayload, uint32_t realPayloadSize, + uint64_t timeStamp, int64_t timeOffset, uint64_t bPos); + std::set getActiveTracks(); - std::map > pesStreams; - std::map > pesPositions; - std::map > outPackets; - std::map buildPacket; - std::map pidToCodec; - std::map adtsInfo; - std::map spsInfo; - std::map ppsInfo; - std::map hevcInfo; - std::map metaInit; - std::map descriptors; - std::map partialBuffer; - mutable IPC::semaphore globalSem; + private: + unsigned long long lastPAT; + ProgramAssociationTable associationTable; + std::map remainders; - bool threaded; + bool firstPacketFound; + std::map lastPMT; + std::map mappingTable; - std::set pmtTracks; + std::map> pesStreams; + std::map> pesPositions; + std::map> outPackets; + std::map buildPacket; + std::map pidToCodec; + std::map adtsInfo; + std::map spsInfo; + std::map ppsInfo; + std::map hevcInfo; + std::map metaInit; + std::map descriptors; + std::map partialBuffer; + mutable IPC::semaphore globalSem; - void parsePES(unsigned long tid, bool finished = false); + bool threaded; + + std::set pmtTracks; + + void parsePES(unsigned long tid, bool finished = false); }; } + diff --git a/src/input/input_hls.cpp b/src/input/input_hls.cpp index c37cb54c..06643df0 100644 --- a/src/input/input_hls.cpp +++ b/src/input/input_hls.cpp @@ -1,38 +1,34 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "input_hls.h" -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #define SEM_TS_CLAIM "/MstTSIN%s" - -namespace Mist { - //remove trailing \r for windows generated playlist files - int cleanLine(std::string & s) { - if (s.length() > 0 && s.at(s.length() - 1) == '\r') { - s.erase(s.size() - 1); - } +namespace Mist{ + // remove trailing \r for windows generated playlist files + int cleanLine(std::string &s){ + if (s.length() > 0 && s.at(s.length() - 1) == '\r'){s.erase(s.size() - 1);} } - - Playlist::Playlist(const std::string & uriSrc) { + Playlist::Playlist(const std::string &uriSrc){ lastFileIndex = 0; entryCount = 0; waitTime = 2; @@ -42,7 +38,7 @@ namespace Mist { lastTimestamp = 0; uri = uriSrc; startTime = Util::bootSecs(); - + if (uri.size()){ std::string line; std::string key; @@ -50,7 +46,7 @@ namespace Mist { int count = 0; uint64_t totalBytes = 0; uri_root = uri.substr(0, uri.rfind("/") + 1); - playlistType = LIVE;//Temporary value + playlistType = LIVE; // Temporary value INFO_MSG("readplaylist: %s", uri.c_str()); std::istringstream urlSource; @@ -59,52 +55,48 @@ namespace Mist { if (isUrl()){ loadURL(uri); urlSource.str(source); - } else { + }else{ fileSource.open(uri.c_str()); } - std::istream & input = (isUrl() ? (std::istream &)urlSource : (std::istream &)fileSource); + std::istream &input = (isUrl() ? (std::istream &)urlSource : (std::istream &)fileSource); std::getline(input, line); - while (std::getline(input, line)) { + while (std::getline(input, line)){ cleanLine(line); - if (!line.empty()) { - if (line.compare(0, 7, "#EXT-X-") == 0) { + if (!line.empty()){ + if (line.compare(0, 7, "#EXT-X-") == 0){ size_t pos = line.find(":"); key = line.substr(7, pos - 7); val = line.c_str() + pos + 1; - if (key == "VERSION") { - version = atoi(val.c_str()); - } + if (key == "VERSION"){version = atoi(val.c_str());} - if (key == "TARGETDURATION") { - waitTime = atoi(val.c_str()); - } + if (key == "TARGETDURATION"){waitTime = atoi(val.c_str());} - if (key == "MEDIA-SEQUENCE") { + if (key == "MEDIA-SEQUENCE"){ media_sequence = atoi(val.c_str()); lastFileIndex = media_sequence; } - if (key == "PLAYLIST-TYPE") { - if (val == "VOD") { + if (key == "PLAYLIST-TYPE"){ + if (val == "VOD"){ playlistType = VOD; - } else if (val == "LIVE") { + }else if (val == "LIVE"){ playlistType = LIVE; - } else if (val == "EVENT") { + }else if (val == "EVENT"){ playlistType = EVENT; } } - if (key == "ENDLIST") { - //end of playlist reached! + if (key == "ENDLIST"){ + // end of playlist reached! playlistEnd = true; playlistType = VOD; } continue; - } else if (line.compare(0, 7, "#EXTINF") != 0) { + }else if (line.compare(0, 7, "#EXTINF") != 0){ VERYHIGH_MSG("ignoring wrong line: %s.", line.c_str()); continue; } @@ -116,33 +108,31 @@ namespace Mist { } } - if (isUrl()) { - playlistType = LIVE;//VOD over HTTP needs to be processed as LIVE. + if (isUrl()){ + playlistType = LIVE; // VOD over HTTP needs to be processed as LIVE. fileSource.close(); } } initDone = true; } - bool Playlist::atEnd() const { - return (packetPtr - source.data() + 188) > source.size(); - } + bool Playlist::atEnd() const{return (packetPtr - source.data() + 188) > source.size();} - bool Playlist::isUrl() const { + bool Playlist::isUrl() const{ return (uri_root.size() ? uri_root.find("http://") == 0 : uri.find("http://") == 0); } - bool Playlist::loadURL(const std::string & loadUrl){ + bool Playlist::loadURL(const std::string &loadUrl){ HIGH_MSG("opening URL: %s", loadUrl.c_str()); HTTP::URL url(loadUrl); - if (url.protocol != "http") { + if (url.protocol != "http"){ FAIL_MSG("Protocol %s is not supported", url.protocol.c_str()); return false; } Socket::Connection conn(url.host, url.getPort(), false); - if (!conn) { + if (!conn){ FAIL_MSG("Failed to reach %s on port %lu", url.host.c_str(), url.getPort()); return false; } @@ -159,9 +149,9 @@ namespace Mist { uint64_t startTime = Util::epoch(); source.clear(); packetPtr = 0; - while ((Util::epoch() - startTime < 10) && (conn || conn.Received().size())) { - if (conn.spool() || conn.Received().size()) { - if (http.Read(conn)) { + while ((Util::epoch() - startTime < 10) && (conn || conn.Received().size())){ + if (conn.spool() || conn.Received().size()){ + if (http.Read(conn)){ source = http.body; packetPtr = source.data(); conn.close(); @@ -171,14 +161,12 @@ namespace Mist { } FAIL_MSG("Failed to load %s: %s", loadUrl.c_str(), conn ? "timeout" : "connection closed"); - if (conn) { - conn.close(); - } + if (conn){conn.close();} return false; } - - ///Function for reloading the playlist in case of live streams. - bool Playlist::reload() { + + /// Function for reloading the playlist in case of live streams. + bool Playlist::reload(){ int skip = lastFileIndex - media_sequence; bool ret = false; std::string line; @@ -191,33 +179,31 @@ namespace Mist { std::istringstream urlSource; std::ifstream fileSource; - if (isUrl()) { - loadURL(uri.c_str()); //get size only! + if (isUrl()){ + loadURL(uri.c_str()); // get size only! urlSource.str(source); - } else { + }else{ fileSource.open(uri.c_str()); } - std::istream & input = (isUrl() ? (std::istream &)urlSource : (std::istream &)fileSource); + std::istream &input = (isUrl() ? (std::istream &)urlSource : (std::istream &)fileSource); std::getline(input, line); - while (std::getline(input, line)) { + while (std::getline(input, line)){ cleanLine(line); - if (line.compare(0, 21, "#EXT-X-MEDIA-SEQUENCE") == 0) { + if (line.compare(0, 21, "#EXT-X-MEDIA-SEQUENCE") == 0){ media_sequence = atoi(line.c_str() + line.find(":") + 1); skip = (lastFileIndex - media_sequence); continue; } - if (line.compare(0, 7, "#EXTINF") != 0) { - continue; - } + if (line.compare(0, 7, "#EXTINF") != 0){continue;} float f = atof(line.c_str() + 8); - //next line belongs to this item + // next line belongs to this item std::string filename; std::getline(input, filename); - //check for already added segments - if (skip) { + // check for already added segments + if (skip){ skip--; }else{ cleanLine(filename); @@ -226,26 +212,22 @@ namespace Mist { } } - if (!isUrl()) { - fileSource.close(); - } + if (!isUrl()){fileSource.close();} ret = (count > 0); - if (ret) { + if (ret){ noChangeCount = 0; - } else { + }else{ ++noChangeCount; - if (noChangeCount > 3) { - VERYHIGH_MSG("enough!"); - } + if (noChangeCount > 3){VERYHIGH_MSG("enough!");} } return ret; } - - ///function for adding segments to the playlist to be processed. used for VOD and live - void Playlist::addEntry(const std::string & filename, float duration, uint64_t & totalBytes) { + + /// function for adding segments to the playlist to be processed. used for VOD and live + void Playlist::addEntry(const std::string &filename, float duration, uint64_t &totalBytes){ playListEntries entry; entry.filename = filename; cleanLine(entry.filename); @@ -254,36 +236,33 @@ namespace Mist { std::istringstream urlSource; std::ifstream fileSource; - if (isUrl()) { + if (isUrl()){ urlSource.str(source); - } else { + }else{ fileSource.open(test.c_str(), std::ios::ate | std::ios::binary); - if ((fileSource.rdstate() & std::ifstream::failbit) != 0) { + if ((fileSource.rdstate() & std::ifstream::failbit) != 0){ WARN_MSG("file: %s, error: %s", test.c_str(), strerror(errno)); } } entry.bytePos = totalBytes; entry.duration = duration; - if (!isUrl()) { - totalBytes += fileSource.tellg(); - } + if (!isUrl()){totalBytes += fileSource.tellg();} - if (initDone) { + if (initDone){ lastTimestamp += duration; entry.timestamp = lastTimestamp + startTime; entry.wait = entryCount * duration; - } else { - entry.timestamp = 0; //read all segments immediatly at the beginning, then use delays + }else{ + entry.timestamp = 0; // read all segments immediatly at the beginning, then use delays } ++entryCount; entries.push_back(entry); ++lastFileIndex; - } /// Constructor of HLS Input - inputHLS::inputHLS(Util::Config * cfg) : Input(cfg) { + inputHLS::inputHLS(Util::Config *cfg) : Input(cfg){ currentPlaylist = 0; capa["name"] = "HLS"; @@ -300,124 +279,121 @@ namespace Mist { inFile = NULL; } - inputHLS::~inputHLS() { - if (inFile) { - fclose(inFile); - } + inputHLS::~inputHLS(){ + if (inFile){fclose(inFile);} } - bool inputHLS::setup() { - if (config->getString("input") == "-") { - return false; - } + bool inputHLS::setup(){ + if (config->getString("input") == "-"){return false;} - if (!initPlaylist(config->getString("input"))) { - return false; - } + if (!initPlaylist(config->getString("input"))){return false;} if (Util::Config::printDebugLevel >= DLVL_HIGH){ - for (std::vector::iterator pListIt = playlists.begin(); pListIt != playlists.end(); pListIt++){ + for (std::vector::iterator pListIt = playlists.begin(); pListIt != playlists.end(); + pListIt++){ std::cout << pListIt->id << ": " << pListIt->uri << std::endl; int j = 0; - for (std::deque::iterator entryIt = pListIt->entries.begin(); entryIt != pListIt->entries.end(); entryIt++){ - std::cout << " " << j++ << ": " << entryIt->filename << " bytePos: " << entryIt->bytePos << std::endl; + for (std::deque::iterator entryIt = pListIt->entries.begin(); + entryIt != pListIt->entries.end(); entryIt++){ + std::cout << " " << j++ << ": " << entryIt->filename + << " bytePos: " << entryIt->bytePos << std::endl; } } } return true; } - void inputHLS::trackSelect(std::string trackSpec) { + void inputHLS::trackSelect(std::string trackSpec){ selectedTracks.clear(); size_t index; - while (trackSpec != "") { + while (trackSpec != ""){ index = trackSpec.find(' '); selectedTracks.insert(atoi(trackSpec.substr(0, index).c_str())); - if (index != std::string::npos) { + if (index != std::string::npos){ trackSpec.erase(0, index + 1); - } else { + }else{ trackSpec = ""; } } } - void inputHLS::parseStreamHeader() { + void inputHLS::parseStreamHeader(){ bool hasHeader = false; - if (!hasHeader) { - myMeta = DTSC::Meta(); - } + if (!hasHeader){myMeta = DTSC::Meta();} - TS::Packet packet;//to analyse and extract data + TS::Packet packet; // to analyse and extract data int counter = 1; int packetId = 0; - char * data; + char *data; unsigned int dataLen; bool keepReading = false; - for (std::vector::iterator pListIt = playlists.begin(); pListIt != playlists.end(); pListIt++){ - if (!pListIt->entries.size()) { - continue; - } + for (std::vector::iterator pListIt = playlists.begin(); pListIt != playlists.end(); + pListIt++){ + if (!pListIt->entries.size()){continue;} std::deque::iterator entryIt = pListIt->entries.begin(); tsStream.clear(); uint64_t lastBpos = entryIt->bytePos; - if (pListIt->isUrl()) { + if (pListIt->isUrl()){ pListIt->loadURL(pListIt->uri_root + entryIt->filename); keepReading = packet.FromPointer(pListIt->packetPtr); pListIt->packetPtr += 188; - } else { + }else{ in.open((pListIt->uri_root + entryIt->filename).c_str()); keepReading = packet.FromStream(in); } - while (keepReading) { + while (keepReading){ tsStream.parse(packet, lastBpos); - if (pListIt->isUrl()) { + if (pListIt->isUrl()){ lastBpos = entryIt->bytePos + pListIt->source.size(); ///\todo get size... - } else { + }else{ lastBpos = entryIt->bytePos + in.tellg(); } - while (tsStream.hasPacketOnEachTrack()) { + while (tsStream.hasPacketOnEachTrack()){ DTSC::Packet headerPack; tsStream.getEarliestPacket(headerPack); int tmpTrackId = headerPack.getTrackId(); packetId = pidMapping[(pListIt->id << 16) + tmpTrackId]; - if (packetId == 0) { + if (packetId == 0){ pidMapping[(pListIt->id << 16) + headerPack.getTrackId()] = counter; pidMappingR[counter] = (pListIt->id << 16) + headerPack.getTrackId(); packetId = counter; - HIGH_MSG("Added file %s, trackid: %d, mapped to: %d", (pListIt->uri_root + entryIt->filename).c_str(), headerPack.getTrackId(), counter); + HIGH_MSG("Added file %s, trackid: %d, mapped to: %d", + (pListIt->uri_root + entryIt->filename).c_str(), headerPack.getTrackId(), + counter); counter++; } myMeta.live = (playlists.size() && playlists[0].playlistType == LIVE); myMeta.vod = !myMeta.live; -// myMeta.live = true; -// myMeta.vod = false; + // myMeta.live = true; + // myMeta.vod = false; myMeta.live = false; myMeta.vod = true; - if (!hasHeader && (!myMeta.tracks.count(packetId) || !myMeta.tracks[packetId].codec.size())) { + if (!hasHeader && + (!myMeta.tracks.count(packetId) || !myMeta.tracks[packetId].codec.size())){ tsStream.initializeMetadata(myMeta, tmpTrackId, packetId); } } - if (pListIt->isUrl()) { + if (pListIt->isUrl()){ keepReading = !pListIt->atEnd(); if (keepReading){ packet.FromPointer(pListIt->packetPtr); pListIt->packetPtr += 188; } - } else { + }else{ keepReading = packet.FromStream(in); } } @@ -427,19 +403,15 @@ namespace Mist { tsStream.clear(); INFO_MSG("end stream header tracks: %d", myMeta.tracks.size()); - if (hasHeader) { - return; - } + if (hasHeader){return;} -// myMeta.live = true; -// myMeta.vod = false; + // myMeta.live = true; + // myMeta.vod = false; in.close(); } - bool inputHLS::readHeader() { - if (playlists.size() && playlists[0].playlistType == LIVE) { - return true; - } + bool inputHLS::readHeader(){ + if (playlists.size() && playlists[0].playlistType == LIVE){return true;} std::istringstream urlSource; std::ifstream fileSource; @@ -447,46 +419,42 @@ namespace Mist { bool endOfFile = false; bool hasHeader = false; - //See whether a separate header file exists. + // See whether a separate header file exists. DTSC::File tmp(config->getString("input") + ".dtsh"); - if (tmp) { + if (tmp){ myMeta = tmp.getMeta(); - if (myMeta) { - hasHeader = true; - } + if (myMeta){hasHeader = true;} } - if (!hasHeader) { - myMeta = DTSC::Meta(); - } + if (!hasHeader){myMeta = DTSC::Meta();} - TS::Packet packet;//to analyse and extract data + TS::Packet packet; // to analyse and extract data int counter = 1; int packetId = 0; - char * data; + char *data; unsigned int dataLen; - for (std::vector::iterator pListIt = playlists.begin(); pListIt != playlists.end(); pListIt++){ + for (std::vector::iterator pListIt = playlists.begin(); pListIt != playlists.end(); + pListIt++){ tsStream.clear(); uint32_t entId = 0; - for (std::deque::iterator entryIt = pListIt->entries.begin(); entryIt != pListIt->entries.end(); entryIt++) { - //WORK + for (std::deque::iterator entryIt = pListIt->entries.begin(); + entryIt != pListIt->entries.end(); entryIt++){ + // WORK tsStream.partialClear(); endOfFile = false; - if (pListIt->isUrl()) { + if (pListIt->isUrl()){ pListIt->loadURL(pListIt->uri_root + entryIt->filename); urlSource.str(pListIt->source); endOfFile = !pListIt->atEnd(); - if (!endOfFile){ - packet.FromPointer(pListIt->packetPtr); - } + if (!endOfFile){packet.FromPointer(pListIt->packetPtr);} pListIt->packetPtr += 188; - } else { + }else{ in.close(); in.open((pListIt->uri_root + entryIt->filename).c_str()); packet.FromStream(in); @@ -495,102 +463,106 @@ namespace Mist { entId++; uint64_t lastBpos = entryIt->bytePos; - while (!endOfFile) { + while (!endOfFile){ tsStream.parse(packet, lastBpos); - if (pListIt->isUrl()) { + if (pListIt->isUrl()){ lastBpos = entryIt->bytePos + pListIt->source.size(); - } else { + }else{ lastBpos = entryIt->bytePos + in.tellg(); } - while (tsStream.hasPacketOnEachTrack()) { + while (tsStream.hasPacketOnEachTrack()){ DTSC::Packet headerPack; tsStream.getEarliestPacket(headerPack); int tmpTrackId = headerPack.getTrackId(); packetId = pidMapping[(pListIt->id << 16) + tmpTrackId]; - if (packetId == 0) { + if (packetId == 0){ pidMapping[(pListIt->id << 16) + headerPack.getTrackId()] = counter; pidMappingR[counter] = (pListIt->id << 16) + headerPack.getTrackId(); packetId = counter; - INFO_MSG("Added file %s, trackid: %d, mapped to: %d", (pListIt->uri_root + entryIt->filename).c_str(), headerPack.getTrackId(), counter); + INFO_MSG("Added file %s, trackid: %d, mapped to: %d", + (pListIt->uri_root + entryIt->filename).c_str(), headerPack.getTrackId(), + counter); counter++; } - if (!hasHeader && (!myMeta.tracks.count(packetId) || !myMeta.tracks[packetId].codec.size())) { + if (!hasHeader && + (!myMeta.tracks.count(packetId) || !myMeta.tracks[packetId].codec.size())){ tsStream.initializeMetadata(myMeta, tmpTrackId, packetId); } - if (!hasHeader) { + if (!hasHeader){ headerPack.getString("data", data, dataLen); - uint64_t pBPos = headerPack.getInt("bpos"); + uint64_t pBPos = headerPack.getInt("bpos"); - //keyframe data exists, so always add 19 bytes keyframedata. - long long packOffset = headerPack.hasMember("offset") ? headerPack.getInt("offset") : 0; - long long packSendSize = 24 + (packOffset ? 17 : 0) + (entId >= 0 ? 15 : 0) + 19 + dataLen + 11; - myMeta.update(headerPack.getTime(), packOffset, packetId, dataLen, entId, headerPack.hasMember("keyframe"), packSendSize); + // keyframe data exists, so always add 19 bytes keyframedata. + long long packOffset = + headerPack.hasMember("offset") ? headerPack.getInt("offset") : 0; + long long packSendSize = + 24 + (packOffset ? 17 : 0) + (entId >= 0 ? 15 : 0) + 19 + dataLen + 11; + myMeta.update(headerPack.getTime(), packOffset, packetId, dataLen, entId, + headerPack.hasMember("keyframe"), packSendSize); } } - if (pListIt->isUrl()) { + if (pListIt->isUrl()){ endOfFile = pListIt->atEnd(); if (!endOfFile){ packet.FromPointer(pListIt->packetPtr); pListIt->packetPtr += 188; } - } else { + }else{ packet.FromStream(in); endOfFile = in.eof(); } } -//get last packets + // get last packets tsStream.finish(); DTSC::Packet headerPack; tsStream.getEarliestPacket(headerPack); - while (headerPack) { + while (headerPack){ int tmpTrackId = headerPack.getTrackId(); packetId = pidMapping[(pListIt->id << 16) + tmpTrackId]; - if (packetId == 0) { + if (packetId == 0){ pidMapping[(pListIt->id << 16) + headerPack.getTrackId()] = counter; pidMappingR[counter] = (pListIt->id << 16) + headerPack.getTrackId(); packetId = counter; - INFO_MSG("Added file %s, trackid: %d, mapped to: %d", (pListIt->uri_root + entryIt->filename).c_str(), headerPack.getTrackId(), counter); + INFO_MSG("Added file %s, trackid: %d, mapped to: %d", + (pListIt->uri_root + entryIt->filename).c_str(), headerPack.getTrackId(), + counter); counter++; } - if (!hasHeader && (!myMeta.tracks.count(packetId) || !myMeta.tracks[packetId].codec.size())) { + if (!hasHeader && + (!myMeta.tracks.count(packetId) || !myMeta.tracks[packetId].codec.size())){ tsStream.initializeMetadata(myMeta, tmpTrackId, packetId); } - if (!hasHeader) { + if (!hasHeader){ headerPack.getString("data", data, dataLen); - uint64_t pBPos = headerPack.getInt("bpos"); + uint64_t pBPos = headerPack.getInt("bpos"); - //keyframe data exists, so always add 19 bytes keyframedata. + // keyframe data exists, so always add 19 bytes keyframedata. long long packOffset = headerPack.hasMember("offset") ? headerPack.getInt("offset") : 0; - long long packSendSize = 24 + (packOffset ? 17 : 0) + (entId >= 0 ? 15 : 0) + 19 + dataLen + 11; - myMeta.update(headerPack.getTime(), packOffset, packetId, dataLen, entId, headerPack.hasMember("keyframe"), packSendSize); + long long packSendSize = + 24 + (packOffset ? 17 : 0) + (entId >= 0 ? 15 : 0) + 19 + dataLen + 11; + myMeta.update(headerPack.getTime(), packOffset, packetId, dataLen, entId, + headerPack.hasMember("keyframe"), packSendSize); } tsStream.getEarliestPacket(headerPack); } - if (!pListIt->isUrl()) { - in.close(); - } + if (!pListIt->isUrl()){in.close();} - if (hasHeader) { - break; - } + if (hasHeader){break;} } } - if (hasHeader || (playlists.size() && playlists[0].isUrl())) { - return true; - } - + if (hasHeader || (playlists.size() && playlists[0].isUrl())){return true;} INFO_MSG("write header file..."); std::ofstream oFile((config->getString("input") + ".dtsh").c_str()); @@ -602,24 +574,22 @@ namespace Mist { return true; } - bool inputHLS::needsLock() { - if (playlists.size() && playlists[0].isUrl()) { - return false; - } - return (playlists.size() <= currentPlaylist) || !(playlists[currentPlaylist].playlistType == LIVE); + bool inputHLS::needsLock(){ + if (playlists.size() && playlists[0].isUrl()){return false;} + return (playlists.size() <= currentPlaylist) || + !(playlists[currentPlaylist].playlistType == LIVE); } - bool inputHLS::openStreamSource() { - return true; - } + bool inputHLS::openStreamSource(){return true;} - int inputHLS::getFirstPlaylistToReload() { - //at this point, we need to check which playlist we need to reload, and keep reading from that playlist until EndOfPlaylist + int inputHLS::getFirstPlaylistToReload(){ + // at this point, we need to check which playlist we need to reload, and keep reading from that + // playlist until EndOfPlaylist std::vector::iterator result = std::min_element(reloadNext.begin(), reloadNext.end()); return std::distance(reloadNext.begin(), result); } - void inputHLS::getNext(bool smart) { + void inputHLS::getNext(bool smart){ INSANE_MSG("Getting next"); uint32_t tid; bool hasPacket = false; @@ -629,8 +599,8 @@ namespace Mist { thisPacket.null(); - while (!hasPacket && config->is_active && nProxy.userClient.isAlive()) { - if (playlists[currentPlaylist].isUrl()) { + while (!hasPacket && config->is_active && nProxy.userClient.isAlive()){ + if (playlists[currentPlaylist].isUrl()){ endOfFile = playlists[currentPlaylist].atEnd(); if (!endOfFile){ @@ -638,51 +608,44 @@ namespace Mist { playlists[currentPlaylist].packetPtr += 188; } - } else { + }else{ tsBuf.FromStream(in); endOfFile = in.eof(); } + // eof flag is set after unsuccesful read, so check again + if (endOfFile){tsStream.finish();} - //eof flag is set after unsuccesful read, so check again - if (endOfFile) { - tsStream.finish(); - } - - if (playlists[currentPlaylist].playlistType == LIVE) { + if (playlists[currentPlaylist].playlistType == LIVE){ hasPacket = tsStream.hasPacketOnEachTrack() || (endOfFile && tsStream.hasPacket()); - } else { + }else{ - if (!selectedTracks.size()) { - return; - } + if (!selectedTracks.size()){return;} tid = *selectedTracks.begin(); hasPacket = tsStream.hasPacket(getMappedTrackId(tid)); } - if (endOfFile && !hasPacket) { - if (playlists[currentPlaylist].playlistType == LIVE) { + if (endOfFile && !hasPacket){ + if (playlists[currentPlaylist].playlistType == LIVE){ int a = getFirstPlaylistToReload(); int segmentTime = 30; HIGH_MSG("need to reload playlist %d, time: %d", a, reloadNext[a] - Util::bootSecs()); int f = firstSegment(); - if (f >= 0) { - segmentTime = playlists[f].entries.front().timestamp - Util::bootSecs(); - } + if (f >= 0){segmentTime = playlists[f].entries.front().timestamp - Util::bootSecs();} int playlistTime = reloadNext.at(currentPlaylist) - Util::bootSecs() - 1; - if (playlistTime < segmentTime) { - while (playlistTime > 0 && nProxy.userClient.isAlive()) { + if (playlistTime < segmentTime){ + while (playlistTime > 0 && nProxy.userClient.isAlive()){ Util::wait(900); nProxy.userClient.keepAlive(); playlistTime--; } - //update reloadTime before reading the playlist + // update reloadTime before reading the playlist reloadNext.at(playlists[a].id) = Util::bootSecs() + playlists[a].waitTime; playlists[a].reload(); } @@ -692,133 +655,134 @@ namespace Mist { int b = Util::bootSecs(); - if (!readNextFile()) { + if (!readNextFile()){ - if (playlists[currentPlaylist].playlistType != LIVE) { - return; - } - //need to reload all available playlists. update the map with the amount of ms to wait before the next check. + if (playlists[currentPlaylist].playlistType != LIVE){return;} + // need to reload all available playlists. update the map with the amount of ms to wait + // before the next check. - //set specific elements with the correct bootsecs() + // set specific elements with the correct bootsecs() reloadNext.at(currentPlaylist) = b + playlists[currentPlaylist].waitTime; int timeToWait = reloadNext.at(currentPlaylist) - Util::bootSecs(); - //at this point, we need to check which playlist we need to reload, and keep reading from that playlist until EndOfPlaylist - std::vector::iterator result = std::min_element(reloadNext.begin(), reloadNext.end()); + // at this point, we need to check which playlist we need to reload, and keep reading from + // that playlist until EndOfPlaylist + std::vector::iterator result = + std::min_element(reloadNext.begin(), reloadNext.end()); int playlistToReload = std::distance(reloadNext.begin(), result); currentPlaylist = playlistToReload; - //dont wait the first time. - if (timeToWait > 0 && playlists[currentPlaylist].initDone && playlists[currentPlaylist].noChangeCount > 0) { - if (timeToWait > playlists[currentPlaylist].waitTime) { + // dont wait the first time. + if (timeToWait > 0 && playlists[currentPlaylist].initDone && + playlists[currentPlaylist].noChangeCount > 0){ + if (timeToWait > playlists[currentPlaylist].waitTime){ WARN_MSG("something is not right..."); return; } - if (playlists[currentPlaylist].noChangeCount < 2) { - timeToWait /= 2;//wait half of the segment size when no segments are found. + if (playlists[currentPlaylist].noChangeCount < 2){ + timeToWait /= 2; // wait half of the segment size when no segments are found. } } - if (playlists[currentPlaylist].playlistEnd) { + if (playlists[currentPlaylist].playlistEnd){ INFO_MSG("Playlist %d has reached his end!"); thisPacket.null(); return; } - } - if (playlists[currentPlaylist].isUrl()) { + if (playlists[currentPlaylist].isUrl()){ endOfFile = playlists[currentPlaylist].atEnd(); if (!endOfFile){ tsBuf.FromPointer(playlists[currentPlaylist].packetPtr); playlists[currentPlaylist].packetPtr += 188; } - } else { + }else{ tsBuf.FromStream(in); endOfFile = in.eof(); } } - if (!endOfFile) { + if (!endOfFile){ tsStream.parse(tsBuf, 0); - if (playlists[currentPlaylist].playlistType == LIVE) { + if (playlists[currentPlaylist].playlistType == LIVE){ hasPacket = tsStream.hasPacketOnEachTrack() || (endOfFile && tsStream.hasPacket()); - } else { + }else{ hasPacket = tsStream.hasPacket(getMappedTrackId(tid)); } } } - if (playlists[currentPlaylist].playlistType == LIVE) { + if (playlists[currentPlaylist].playlistType == LIVE){ tsStream.getEarliestPacket(thisPacket); tid = getOriginalTrackId(currentPlaylist, thisPacket.getTrackId()); - } else { + }else{ tsStream.getPacket(getMappedTrackId(tid), thisPacket); } - if (!thisPacket) { + if (!thisPacket){ FAIL_MSG("Could not getNExt TS packet!"); return; } - //overwrite trackId + // overwrite trackId Bit::htobl(thisPacket.getData() + 8, tid); } - - void inputHLS::readPMT() { - if (playlists[currentPlaylist].isUrl()) { + void inputHLS::readPMT(){ + if (playlists[currentPlaylist].isUrl()){ size_t bpos; TS::Packet tsBuffer; - const char * tmpPtr = playlists[currentPlaylist].source.data(); + const char *tmpPtr = playlists[currentPlaylist].source.data(); - while (!tsStream.hasPacketOnEachTrack() && (tmpPtr - playlists[currentPlaylist].source.c_str() + 188 <= playlists[currentPlaylist].source.size())) { + while (!tsStream.hasPacketOnEachTrack() && + (tmpPtr - playlists[currentPlaylist].source.c_str() + 188 <= + playlists[currentPlaylist].source.size())){ tsBuffer.FromPointer(tmpPtr); tsStream.parse(tsBuffer, 0); tmpPtr += 188; } tsStream.partialClear(); - } else { + }else{ size_t bpos = in.tellg(); in.seekg(0, in.beg); TS::Packet tsBuffer; - while (!tsStream.hasPacketOnEachTrack() && tsBuffer.FromStream(in)) { + while (!tsStream.hasPacketOnEachTrack() && tsBuffer.FromStream(in)){ tsStream.parse(tsBuffer, 0); } - //tsStream.clear(); - tsStream.partialClear(); //?? partialclear gebruiken?, input raakt hierdoor inconsistent.. + // tsStream.clear(); + tsStream.partialClear(); //?? partialclear gebruiken?, input raakt hierdoor inconsistent.. in.seekg(bpos, in.beg); } } - //Note: bpos is overloaded here for playlist entry! - void inputHLS::seek(int seekTime) { + // Note: bpos is overloaded here for playlist entry! + void inputHLS::seek(int seekTime){ INFO_MSG("SEEK"); tsStream.clear(); readPMT(); int trackId = 0; unsigned long plistEntry = 0xFFFFFFFFull; - for (std::set::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++) { + for (std::set::iterator it = selectedTracks.begin(); it != selectedTracks.end(); + it++){ unsigned long thisBPos = 0; - for (std::deque::iterator keyIt = myMeta.tracks[*it].keys.begin(); keyIt != myMeta.tracks[*it].keys.end(); keyIt++) { - if (keyIt->getTime() > seekTime) { - break; - } + for (std::deque::iterator keyIt = myMeta.tracks[*it].keys.begin(); + keyIt != myMeta.tracks[*it].keys.end(); keyIt++){ + if (keyIt->getTime() > seekTime){break;} thisBPos = keyIt->getBpos(); } - if (thisBPos < plistEntry) { + if (thisBPos < plistEntry){ plistEntry = thisBPos; trackId = *it; } } - if (plistEntry < 1){ WARN_MSG("attempted to seek outside the file"); return; @@ -827,44 +791,36 @@ namespace Mist { currentIndex = plistEntry - 1; currentPlaylist = getMappedTrackPlaylist(trackId); - Playlist & curPlaylist = playlists[currentPlaylist]; - playListEntries & entry = curPlaylist.entries.at(currentIndex); - if (curPlaylist.isUrl()) { + Playlist &curPlaylist = playlists[currentPlaylist]; + playListEntries &entry = curPlaylist.entries.at(currentIndex); + if (curPlaylist.isUrl()){ curPlaylist.loadURL(curPlaylist.uri_root + entry.filename); - } else { + }else{ in.close(); in.open((curPlaylist.uri_root + entry.filename).c_str()); } } - int inputHLS::getEntryId(int playlistId, uint64_t bytePos) { - if (bytePos == 0) { - return 0; - } + int inputHLS::getEntryId(int playlistId, uint64_t bytePos){ + if (bytePos == 0){return 0;} - for (int i = 0; i < playlists[playlistId].entries.size(); i++) { - if (playlists[playlistId].entries.at(i).bytePos > bytePos) { - return i - 1; - } + for (int i = 0; i < playlists[playlistId].entries.size(); i++){ + if (playlists[playlistId].entries.at(i).bytePos > bytePos){return i - 1;} } return playlists[playlistId].entries.size() - 1; } - int inputHLS::getOriginalTrackId(int playlistId, int id) { + int inputHLS::getOriginalTrackId(int playlistId, int id){ return pidMapping[(playlistId << 16) + id]; } - int inputHLS::getMappedTrackId(int id) { - return (pidMappingR[id] & 0xFFFF); - } + int inputHLS::getMappedTrackId(int id){return (pidMappingR[id] & 0xFFFF);} - int inputHLS::getMappedTrackPlaylist(int id) { - return (pidMappingR[id] >> 16); - } + int inputHLS::getMappedTrackPlaylist(int id){return (pidMappingR[id] >> 16);} - ///Very first function to be called on a regular playlist or variant playlist. - bool inputHLS::initPlaylist(const std::string & uri) { + /// Very first function to be called on a regular playlist or variant playlist. + bool inputHLS::initPlaylist(const std::string &uri){ std::string line; bool ret = false; startTime = Util::bootSecs(); @@ -874,79 +830,75 @@ namespace Mist { std::istringstream urlSource; std::ifstream fileSource; - + bool isUrl = false; - if (uri.compare(0, 7, "http://") == 0) { + if (uri.compare(0, 7, "http://") == 0){ isUrl = true; Playlist p; p.loadURL(uri); init_source = p.source; urlSource.str(init_source); - } else { + }else{ fileSource.open(uri.c_str()); } - std::istream & input = (isUrl ? (std::istream &)urlSource : (std::istream &)fileSource); + std::istream &input = (isUrl ? (std::istream &)urlSource : (std::istream &)fileSource); std::getline(input, line); - while (std::getline(input, line)) { - if (!line.empty()) { //skip empty lines in the playlist - if (line.compare(0, 17, "#EXT-X-STREAM-INF") == 0) { - //this is a variant playlist file.. next line is an uri to a playlist file + while (std::getline(input, line)){ + if (!line.empty()){// skip empty lines in the playlist + if (line.compare(0, 17, "#EXT-X-STREAM-INF") == 0){ + // this is a variant playlist file.. next line is an uri to a playlist file std::getline(input, line); ret = readPlaylist(playlistRootPath + line); - } else if (line.compare(0, 12, "#EXT-X-MEDIA") == 0) { - //this is also a variant playlist, but streams need to be processed another way + }else if (line.compare(0, 12, "#EXT-X-MEDIA") == 0){ + // this is also a variant playlist, but streams need to be processed another way std::string mediafile; - if (line.compare(18, 5, "AUDIO") == 0) { - //find URI attribute + if (line.compare(18, 5, "AUDIO") == 0){ + // find URI attribute int pos = line.find("URI"); - if (pos != std::string::npos) { + if (pos != std::string::npos){ mediafile = line.substr(pos + 5, line.length() - pos - 6); ret = readPlaylist(playlistRootPath + mediafile); } } - } else if (line.compare(0, 7, "#EXTINF") == 0) { - //current file is not a variant playlist, but regular playlist. + }else if (line.compare(0, 7, "#EXTINF") == 0){ + // current file is not a variant playlist, but regular playlist. ret = readPlaylist(uri); break; - } else { - //ignore wrong lines + }else{ + // ignore wrong lines WARN_MSG("ignore wrong line: %s", line.c_str()); } } } - if (!isUrl){ - fileSource.close(); - } + if (!isUrl){fileSource.close();} return ret; } - ///Function for reading every playlist. - bool inputHLS::readPlaylist(const std::string & uri) { + /// Function for reading every playlist. + bool inputHLS::readPlaylist(const std::string &uri){ Playlist p(uri); p.id = playlists.size(); - //set size of reloadNext to playlist count with default value 0 + // set size of reloadNext to playlist count with default value 0 playlists.push_back(p); - if (reloadNext.size() < playlists.size()) { - reloadNext.resize(playlists.size()); - } + if (reloadNext.size() < playlists.size()){reloadNext.resize(playlists.size());} reloadNext.at(p.id) = Util::bootSecs() + p.waitTime; return true; } - ///Read next .ts file from the playlist. (from the list of entries which needs to be processed) - bool inputHLS::readNextFile() { + /// Read next .ts file from the playlist. (from the list of entries which needs to be processed) + bool inputHLS::readNextFile(){ tsStream.clear(); - Playlist & curList = playlists[currentPlaylist]; + Playlist &curList = playlists[currentPlaylist]; - if (!curList.entries.size()) { + if (!curList.entries.size()){ VERYHIGH_MSG("no entries found in playlist: %d!", currentPlaylist); return false; } @@ -954,21 +906,21 @@ namespace Mist { std::string url = (curList.uri_root + curList.entries.front().filename).c_str(); if (curList.isUrl() && curList.loadURL(url)){ - curList.entries.pop_front(); //remove the item which is opened for reading. + curList.entries.pop_front(); // remove the item which is opened for reading. } - if (curList.playlistType == LIVE) { + if (curList.playlistType == LIVE){ in.close(); in.open(url.c_str()); - if (in.good()) { - curList.entries.pop_front(); //remove the item which is opened for reading. + if (in.good()){ + curList.entries.pop_front(); // remove the item which is opened for reading. return true; } return false; } ++currentIndex; - if (curList.entries.size() <= currentIndex) { + if (curList.entries.size() <= currentIndex){ INFO_MSG("end of playlist reached!"); return false; } @@ -979,14 +931,16 @@ namespace Mist { return true; } - ///return the playlist id from which we need to read the first upcoming segment by timestamp. this will keep the playlists in sync while reading segments. - int inputHLS::firstSegment() { + /// return the playlist id from which we need to read the first upcoming segment by timestamp. + /// this will keep the playlists in sync while reading segments. + int inputHLS::firstSegment(){ uint64_t firstTimeStamp = 0; int tmpId = -1; - for (std::vector::iterator pListIt = playlists.begin(); pListIt != playlists.end(); pListIt++){ - if (pListIt->entries.size()) { - if (pListIt->entries.front().timestamp < firstTimeStamp || tmpId < 0) { + for (std::vector::iterator pListIt = playlists.begin(); pListIt != playlists.end(); + pListIt++){ + if (pListIt->entries.size()){ + if (pListIt->entries.front().timestamp < firstTimeStamp || tmpId < 0){ firstTimeStamp = pListIt->entries.front().timestamp; tmpId = pListIt->id; } @@ -995,8 +949,8 @@ namespace Mist { return tmpId; } - //read the next segment - void inputHLS::waitForNextSegment() { + // read the next segment + void inputHLS::waitForNextSegment(){ uint32_t pListId = firstSegment(); if (pListId == -1){ VERYHIGH_MSG("no segments found!"); @@ -1005,7 +959,7 @@ namespace Mist { int segmentTime = playlists[pListId].entries.front().timestamp - Util::bootSecs(); if (segmentTime){ --segmentTime; - while (segmentTime > 1 && nProxy.userClient.isAlive()) { + while (segmentTime > 1 && nProxy.userClient.isAlive()){ Util::wait(1000); --segmentTime; continueNegotiate(); diff --git a/src/input/input_hls.h b/src/input/input_hls.h index 30b09d5a..762abe7a 100644 --- a/src/input/input_hls.h +++ b/src/input/input_hls.h @@ -1,24 +1,22 @@ #pragma once #include "input.h" +#include #include #include #include #include -#include -#include #include +#include #include //#include #define BUFFERTIME 10 -namespace Mist { +namespace Mist{ - enum PlaylistType { VOD, LIVE, EVENT }; + enum PlaylistType{VOD, LIVE, EVENT}; - - struct playListEntries - { + struct playListEntries{ std::string filename; uint64_t bytePos; float duration; @@ -26,105 +24,103 @@ namespace Mist { unsigned int wait; }; - class Playlist { - public: - Playlist(const std::string & uriSrc = ""); - bool atEnd() const; - bool isUrl() const; - bool reload(); - void addEntry(const std::string & filename, float duration, uint64_t & totalBytes); - bool loadURL(const std::string & loadUrl); + class Playlist{ + public: + Playlist(const std::string &uriSrc = ""); + bool atEnd() const; + bool isUrl() const; + bool reload(); + void addEntry(const std::string &filename, float duration, uint64_t &totalBytes); + bool loadURL(const std::string &loadUrl); - std::string uri; - std::string uri_root; + std::string uri; + std::string uri_root; - std::string source; - const char *packetPtr; + std::string source; + const char *packetPtr; - int id; - bool initDone; - bool playlistEnd; - int noChangeCount; - int version; - uint64_t media_sequence; - int lastFileIndex; + int id; + bool initDone; + bool playlistEnd; + int noChangeCount; + int version; + uint64_t media_sequence; + int lastFileIndex; - - int waitTime; - PlaylistType playlistType; - std::deque entries; - int entryCount; - unsigned int lastTimestamp; - unsigned int startTime; + int waitTime; + PlaylistType playlistType; + std::deque entries; + int entryCount; + unsigned int lastTimestamp; + unsigned int startTime; }; - - struct entryBuffer - { + struct entryBuffer{ int timestamp; playListEntries entry; int playlistIndex; }; - class inputHLS : public Input { - public: - inputHLS(Util::Config * cfg); - ~inputHLS(); - bool needsLock(); - bool openStreamSource(); - protected: - //Private Functions - - unsigned int startTime; - PlaylistType playlistType; - int version; - int targetDuration; - int media_sequence; - bool endPlaylist; - int currentPlaylist; + class inputHLS : public Input{ + public: + inputHLS(Util::Config *cfg); + ~inputHLS(); + bool needsLock(); + bool openStreamSource(); - //std::vector entries; - std::vector playlists; - //std::vector pidMapping; - std::map pidMapping; - std::map pidMappingR; + protected: + // Private Functions - std::vector reloadNext; + unsigned int startTime; + PlaylistType playlistType; + int version; + int targetDuration; + int media_sequence; + bool endPlaylist; + int currentPlaylist; - int currentIndex; - std::string currentFile; - std::ifstream in; + // std::vector entries; + std::vector playlists; + // std::vector pidMapping; + std::map pidMapping; + std::map pidMappingR; - TS::Stream tsStream;/// reloadNext; - Socket::Connection conn; - TS::Packet tsBuf; + int currentIndex; + std::string currentFile; + std::ifstream in; - int getFirstPlaylistToReload(); + TS::Stream tsStream; ///