Fixed parsing of ADTS inside TS spread over multiple PES
This commit is contained in:
parent
bd38fd20c3
commit
d21c15fcdd
4 changed files with 87 additions and 13 deletions
17
lib/adts.cpp
17
lib/adts.cpp
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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){
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Add table
Reference in a new issue