Skip to content

Commit

Permalink
tsdemuxer: parse all PMTs in order to detect tracks not signaled in f…
Browse files Browse the repository at this point in the history
  • Loading branch information
mangui committed Jul 27, 2016
1 parent 528fa2a commit 1ecb6f1
Showing 1 changed file with 54 additions and 35 deletions.
89 changes: 54 additions & 35 deletions src/demux/tsdemuxer.js
Expand Up @@ -84,7 +84,15 @@
var pmtParsed = this.pmtParsed,
avcId = this._avcTrack.id,
aacId = this._aacTrack.id,
id3Id = this._id3Track.id;
id3Id = this._id3Track.id,
pmtId = this._pmtId;

var parsePAT = this._parsePAT,
parsePMT = this._parsePMT,
parsePES = this._parsePES,
parseAVCPES = this._parseAVCPES.bind(this),
parseAACPES = this._parseAACPES.bind(this),
parseID3PES = this._parseID3PES.bind(this);

// don't parse last TS packet if incomplete
len -= len % 188;
Expand All @@ -105,11 +113,11 @@
} else {
offset = start + 4;
}
if (pmtParsed) {
if (pid === avcId) {
switch(pid) {

This comment has been minimized.

Copy link
@itsbonczek

itsbonczek Aug 9, 2016

Contributor

@mangui Does this patch need to preserve the if (pmtParsed) check? We've been seeing some strange stream parsing errors in bleeding edge, and adding the check back in seems to resolve them.

This comment has been minimized.

Copy link
@mangui

mangui Aug 9, 2016

Author Member

the issue with Adobe AMS is that the first PMT only references the video PID.
it is then followed by the first video packets.
then a second PMT comes, referencing both audio and video PIDs, then followed by audio+video packets.
as a consequence parsing the first PMT is not enough in that case.

This comment has been minimized.

Copy link
@mangui

mangui Aug 9, 2016

Author Member

if you could share streams, I would be glad to have a look

This comment has been minimized.

Copy link
@itsbonczek

itsbonczek Aug 10, 2016

Contributor

Thanks for the fantastic explanation. I'll open up a proper issue and see what I can do about a stream.

case avcId:
if (stt) {
if (avcData) {
this._parseAVCPES(this._parsePES(avcData));
parseAVCPES(parsePES(avcData));
if (codecsOnly) {
// if we have video codec info AND
// if audio PID is undefined OR if we have audio codec info,
Expand All @@ -126,10 +134,11 @@
avcData.data.push(data.subarray(offset, start + 188));
avcData.size += start + 188 - offset;
}
} else if (pid === aacId) {
break;
case aacId:
if (stt) {
if (aacData) {
this._parseAACPES(this._parsePES(aacData));
parseAACPES(parsePES(aacData));
if (codecsOnly) {
// here we now that we have audio codec info
// if video PID is undefined OR if we have video codec info,
Expand All @@ -146,54 +155,61 @@
aacData.data.push(data.subarray(offset, start + 188));
aacData.size += start + 188 - offset;
}
} else if (pid === id3Id) {
break;
case id3Id:
if (stt) {
if (id3Data) {
this._parseID3PES(this._parsePES(id3Data));
parseID3PES(parsePES(id3Data));
}
id3Data = {data: [], size: 0};
}
if (id3Data) {
id3Data.data.push(data.subarray(offset, start + 188));
id3Data.size += start + 188 - offset;
}
}
} else {
if (stt) {
offset += data[offset] + 1;
}
if (pid === 0) {
this._parsePAT(data, offset);
} else if (pid === this._pmtId) {
this._parsePMT(data, offset);
pmtParsed = this.pmtParsed = true;
avcId = this._avcTrack.id;
aacId = this._aacTrack.id;
id3Id = this._id3Track.id;
if (unknownPIDs) {
break;
case 0:
if (stt) {
offset += data[offset] + 1;
}
pmtId = this._pmtId = parsePAT(data, offset);
break;
case pmtId:
if (stt) {
offset += data[offset] + 1;
}
let parsedPIDs = parsePMT(data, offset);
avcId = this._avcTrack.id = parsedPIDs.avc;
aacId = this._aacTrack.id = parsedPIDs.aac;
id3Id = this._id3Track.id = parsedPIDs.id3;
if (unknownPIDs && !pmtParsed) {
logger.log('reparse from beginning');
unknownPIDs = false;
// we set it to -188, the += 188 in the for loop will reset start to 0
start = -188;
}
} else {
logger.log('unknown PID found before PAT/PMT');
pmtParsed = this.pmtParsed = true;
break;
case 17:
case 0x1fff:
break;
default:
unknownPIDs = true;
}
break;
}
} else {
this.observer.trigger(Event.ERROR, {type : ErrorTypes.MEDIA_ERROR, id : this.id, details: ErrorDetails.FRAG_PARSING_ERROR, fatal: false, reason: 'TS packet did not start with 0x47'});
}
}
// parse last PES packet
if (avcData) {
this._parseAVCPES(this._parsePES(avcData));
parseAVCPES(parsePES(avcData));
}
if (aacData) {
this._parseAACPES(this._parsePES(aacData));
parseAACPES(parsePES(aacData));
}
if (id3Data) {
this._parseID3PES(this._parsePES(id3Data));
parseID3PES(parsePES(id3Data));
}
this.remux(level,sn,null);
}
Expand All @@ -210,12 +226,12 @@

_parsePAT(data, offset) {
// skip the PSI header and parse the first PMT entry
this._pmtId = (data[offset + 10] & 0x1F) << 8 | data[offset + 11];
return (data[offset + 10] & 0x1F) << 8 | data[offset + 11];
//logger.log('PMT PID:' + this._pmtId);
}

_parsePMT(data, offset) {
var sectionLength, tableEnd, programInfoLength, pid;
var sectionLength, tableEnd, programInfoLength, pid, result = { aac : -1, avc : -1, id3 : -1};
sectionLength = (data[offset + 1] & 0x0f) << 8 | data[offset + 2];
tableEnd = offset + 3 + sectionLength - 4;
// to determine where the table is, we have to figure out how
Expand All @@ -229,20 +245,22 @@
// ISO/IEC 13818-7 ADTS AAC (MPEG-2 lower bit-rate audio)
case 0x0f:
//logger.log('AAC PID:' + pid);
if (this._aacTrack.id === -1) {
this._aacTrack.id = pid;
if (result.aac === -1) {
result.aac = pid;
}
break;
// Packetized metadata (ID3)
case 0x15:
//logger.log('ID3 PID:' + pid);
this._id3Track.id = pid;
if (result.id3 === -1) {
result.id3 = pid;
}
break;
// ITU-T Rec. H.264 and ISO/IEC 14496-10 (lower bit-rate video)
case 0x1b:
//logger.log('AVC PID:' + pid);
if (this._avcTrack.id === -1) {
this._avcTrack.id = pid;
if (result.avc === -1) {
result.avc = pid;
}
break;
default:
Expand All @@ -253,6 +271,7 @@
// skip past the elementary stream descriptors, if present
offset += ((data[offset + 3] & 0x0F) << 8 | data[offset + 4]) + 5;
}
return result;
}

_parsePES(stream) {
Expand Down

1 comment on commit 1ecb6f1

@sompylasar
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Please sign in to comment.