From d21c15fcdddf0ca6ca4d8d882af2ac5587b5da78 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Thu, 7 Jul 2016 22:30:34 +0200 Subject: [PATCH] Fixed parsing of ADTS inside TS spread over multiple PES --- lib/adts.cpp | 17 ++++++---- lib/adts.h | 2 ++ lib/ts_stream.cpp | 77 ++++++++++++++++++++++++++++++++++++++---- src/input/input_ts.cpp | 4 +++ 4 files changed, 87 insertions(+), 13 deletions(-) diff --git a/lib/adts.cpp b/lib/adts.cpp index ade36849..9756ff83 100644 --- a/lib/adts.cpp +++ b/lib/adts.cpp @@ -104,21 +104,21 @@ namespace aac { return (data[1] & 0x01 ? 7 : 9); } - unsigned long adts::getPayloadSize() const{ + unsigned long adts::getCompleteSize() const{ if (!data || len < 6){ return 0; } - unsigned long ret = (((data[3] & 0x03) << 11) | (data[4] << 3) | ((data[5] >> 5) & 0x07)); + return (((data[3] & 0x03) << 11) | (data[4] << 3) | ((data[5] >> 5) & 0x07)); + } + + unsigned long adts::getPayloadSize() const{ + unsigned long ret = getCompleteSize(); if (!ret){return ret;}//catch zero length if (ret >= getHeaderSize()){ ret -= getHeaderSize(); }else{ return 0;//catch size less than header size (corrupt data) } - if (len < ret + getHeaderSize() ){ - ret = len - getHeaderSize(); - //catch size less than length (corrupt data) - } return ret; } @@ -161,6 +161,9 @@ namespace aac { return res.str(); } adts::operator bool() const{ - return (((int)data[0] << 4) | ((data[1] >> 4) & 0x0F)) == 0xfff && getFrequency(); + return hasSync() && len && len >= getHeaderSize() && getFrequency(); + } + bool adts::hasSync() const{ + return len && (((int)data[0] << 4) | ((data[1] >> 4) & 0x0F)) == 0xfff; } } diff --git a/lib/adts.h b/lib/adts.h index 64195990..a40eba5f 100644 --- a/lib/adts.h +++ b/lib/adts.h @@ -16,7 +16,9 @@ namespace aac { unsigned long getChannelCount() const; unsigned long getHeaderSize() const; unsigned long getPayloadSize() const; + unsigned long getCompleteSize() const; unsigned long getSampleCount() const; + bool hasSync() const; char * getPayload(); std::string toPrettyString() const; operator bool() const; diff --git a/lib/ts_stream.cpp b/lib/ts_stream.cpp index 6fbf7ada..54c0721f 100644 --- a/lib/ts_stream.cpp +++ b/lib/ts_stream.cpp @@ -7,6 +7,46 @@ #include namespace TS { + + class ADTSRemainder{ + public: + char * data; + uint32_t max; + uint32_t now; + uint32_t len; + uint32_t bpos; + void setRemainder(const aac::adts & p, const void * source, const uint32_t avail, const uint32_t bPos){ + if (max < p.getCompleteSize()){ + void * newmainder = realloc(data, p.getCompleteSize()); + if (newmainder){ + max = p.getCompleteSize(); + data = (char*)newmainder; + } + } + if (max >= p.getCompleteSize()){ + len = p.getCompleteSize(); + now = avail; + bpos = bPos; + memcpy(data, source, now); + } + } + ADTSRemainder(){ + data = 0; + max = 0; + now = 0; + len = 0; + bpos = 0; + } + ~ADTSRemainder(){ + if (data){ + free(data); + data = 0; + } + } + + }; + + Stream::Stream(bool _threaded){ threaded = _threaded; if (threaded){ @@ -412,23 +452,48 @@ namespace TS { if (pidToCodec[tid] == AAC){ //Parse all the ADTS packets unsigned long offsetInPes = 0; - unsigned long samplesRead = 0; + uint64_t msRead = 0; if (threaded){ globalSem.wait(); } + static std::map remainders; + if (remainders.count(tid) && remainders[tid].len){ + offsetInPes = std::min((unsigned long)(remainders[tid].len - remainders[tid].now), (unsigned long)realPayloadSize); + memcpy(remainders[tid].data+remainders[tid].now, pesPayload, offsetInPes); + remainders[tid].now += offsetInPes; + if (remainders[tid].now == remainders[tid].len){ + aac::adts adtsPack(remainders[tid].data, remainders[tid].len); + 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].bpos, 0); + } + remainders[tid].len = 0; + } + } while (offsetInPes < realPayloadSize){ aac::adts adtsPack(pesPayload + offsetInPes, realPayloadSize - offsetInPes); - if (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 + ((samplesRead * 1000) / adtsPack.getFrequency()), timeOffset, tid, adtsPack.getPayload(), adtsPack.getPayloadSize(), bPos, 0); - samplesRead += adtsPack.getSampleCount(); - offsetInPes += adtsPack.getHeaderSize() + adtsPack.getPayloadSize(); + outPackets[tid].back().genericFill(timeStamp + msRead, timeOffset, tid, adtsPack.getPayload(), adtsPack.getPayloadSize(), bPos, 0); + msRead += (adtsPack.getSampleCount() * 1000) / adtsPack.getFrequency(); + offsetInPes += adtsPack.getCompleteSize(); }else{ - offsetInPes++; + /// \todo What about the case that we have an invalid start, going over the PES boundary? + 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 + } } } if (threaded){ diff --git a/src/input/input_ts.cpp b/src/input/input_ts.cpp index 2ae05ffc..84c5644f 100755 --- a/src/input/input_ts.cpp +++ b/src/input/input_ts.cpp @@ -314,6 +314,10 @@ namespace Mist { } else { tsStream.getEarliestPacket(thisPacket); } + if (!thisPacket){ + FAIL_MSG("Could not getNext TS packet!"); + return; + } tsStream.initializeMetadata(myMeta); if (!myMeta.tracks.count(thisPacket.getTrackId())) { getNext();