Fixed parsing of ADTS inside TS spread over multiple PES

This commit is contained in:
Thulinma 2016-07-07 22:30:34 +02:00
parent bd38fd20c3
commit d21c15fcdd
4 changed files with 87 additions and 13 deletions

View file

@ -104,21 +104,21 @@ namespace aac {
return (data[1] & 0x01 ? 7 : 9); return (data[1] & 0x01 ? 7 : 9);
} }
unsigned long adts::getPayloadSize() const{ unsigned long adts::getCompleteSize() const{
if (!data || len < 6){ if (!data || len < 6){
return 0; 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){return ret;}//catch zero length
if (ret >= getHeaderSize()){ if (ret >= getHeaderSize()){
ret -= getHeaderSize(); ret -= getHeaderSize();
}else{ }else{
return 0;//catch size less than header size (corrupt data) 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; return ret;
} }
@ -161,6 +161,9 @@ namespace aac {
return res.str(); return res.str();
} }
adts::operator bool() const{ 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;
} }
} }

View file

@ -16,7 +16,9 @@ namespace aac {
unsigned long getChannelCount() const; unsigned long getChannelCount() const;
unsigned long getHeaderSize() const; unsigned long getHeaderSize() const;
unsigned long getPayloadSize() const; unsigned long getPayloadSize() const;
unsigned long getCompleteSize() const;
unsigned long getSampleCount() const; unsigned long getSampleCount() const;
bool hasSync() const;
char * getPayload(); char * getPayload();
std::string toPrettyString() const; std::string toPrettyString() const;
operator bool() const; operator bool() const;

View file

@ -7,6 +7,46 @@
#include <sys/stat.h> #include <sys/stat.h>
namespace TS { 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){ Stream::Stream(bool _threaded){
threaded = _threaded; threaded = _threaded;
if (threaded){ if (threaded){
@ -412,23 +452,48 @@ namespace TS {
if (pidToCodec[tid] == AAC){ if (pidToCodec[tid] == AAC){
//Parse all the ADTS packets //Parse all the ADTS packets
unsigned long offsetInPes = 0; unsigned long offsetInPes = 0;
unsigned long samplesRead = 0; uint64_t msRead = 0;
if (threaded){ if (threaded){
globalSem.wait(); globalSem.wait();
} }
static std::map<unsigned long, ADTSRemainder> 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){ while (offsetInPes < realPayloadSize){
aac::adts adtsPack(pesPayload + offsetInPes, realPayloadSize - offsetInPes); aac::adts adtsPack(pesPayload + offsetInPes, realPayloadSize - offsetInPes);
if (adtsPack){ if (adtsPack && adtsPack.getCompleteSize() + offsetInPes <= realPayloadSize){
if (!adtsInfo.count(tid) || !adtsInfo[tid].sameHeader(adtsPack)){ if (!adtsInfo.count(tid) || !adtsInfo[tid].sameHeader(adtsPack)){
MEDIUM_MSG("Setting new ADTS header: %s", adtsPack.toPrettyString().c_str()); MEDIUM_MSG("Setting new ADTS header: %s", adtsPack.toPrettyString().c_str());
adtsInfo[tid] = adtsPack; adtsInfo[tid] = adtsPack;
} }
outPackets[tid].push_back(DTSC::Packet()); outPackets[tid].push_back(DTSC::Packet());
outPackets[tid].back().genericFill(timeStamp + ((samplesRead * 1000) / adtsPack.getFrequency()), timeOffset, tid, adtsPack.getPayload(), adtsPack.getPayloadSize(), bPos, 0); outPackets[tid].back().genericFill(timeStamp + msRead, timeOffset, tid, adtsPack.getPayload(), adtsPack.getPayloadSize(), bPos, 0);
samplesRead += adtsPack.getSampleCount(); msRead += (adtsPack.getSampleCount() * 1000) / adtsPack.getFrequency();
offsetInPes += adtsPack.getHeaderSize() + adtsPack.getPayloadSize(); offsetInPes += adtsPack.getCompleteSize();
}else{ }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){ if (threaded){

View file

@ -314,6 +314,10 @@ namespace Mist {
} else { } else {
tsStream.getEarliestPacket(thisPacket); tsStream.getEarliestPacket(thisPacket);
} }
if (!thisPacket){
FAIL_MSG("Could not getNext TS packet!");
return;
}
tsStream.initializeMetadata(myMeta); tsStream.initializeMetadata(myMeta);
if (!myMeta.tracks.count(thisPacket.getTrackId())) { if (!myMeta.tracks.count(thisPacket.getTrackId())) {
getNext(); getNext();