First release
This commit is contained in:
commit
fa6c85266e
2339 changed files with 761050 additions and 0 deletions
299
node_modules/mux.js/es/m2ts/probe.js
generated
vendored
Normal file
299
node_modules/mux.js/es/m2ts/probe.js
generated
vendored
Normal file
|
@ -0,0 +1,299 @@
|
|||
/**
|
||||
* mux.js
|
||||
*
|
||||
* Copyright (c) Brightcove
|
||||
* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
|
||||
*
|
||||
* Utilities to detect basic properties and metadata about TS Segments.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var StreamTypes = require('./stream-types.js');
|
||||
|
||||
var parsePid = function parsePid(packet) {
|
||||
var pid = packet[1] & 0x1f;
|
||||
pid <<= 8;
|
||||
pid |= packet[2];
|
||||
return pid;
|
||||
};
|
||||
|
||||
var parsePayloadUnitStartIndicator = function parsePayloadUnitStartIndicator(packet) {
|
||||
return !!(packet[1] & 0x40);
|
||||
};
|
||||
|
||||
var parseAdaptionField = function parseAdaptionField(packet) {
|
||||
var offset = 0; // if an adaption field is present, its length is specified by the
|
||||
// fifth byte of the TS packet header. The adaptation field is
|
||||
// used to add stuffing to PES packets that don't fill a complete
|
||||
// TS packet, and to specify some forms of timing and control data
|
||||
// that we do not currently use.
|
||||
|
||||
if ((packet[3] & 0x30) >>> 4 > 0x01) {
|
||||
offset += packet[4] + 1;
|
||||
}
|
||||
|
||||
return offset;
|
||||
};
|
||||
|
||||
var parseType = function parseType(packet, pmtPid) {
|
||||
var pid = parsePid(packet);
|
||||
|
||||
if (pid === 0) {
|
||||
return 'pat';
|
||||
} else if (pid === pmtPid) {
|
||||
return 'pmt';
|
||||
} else if (pmtPid) {
|
||||
return 'pes';
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
var parsePat = function parsePat(packet) {
|
||||
var pusi = parsePayloadUnitStartIndicator(packet);
|
||||
var offset = 4 + parseAdaptionField(packet);
|
||||
|
||||
if (pusi) {
|
||||
offset += packet[offset] + 1;
|
||||
}
|
||||
|
||||
return (packet[offset + 10] & 0x1f) << 8 | packet[offset + 11];
|
||||
};
|
||||
|
||||
var parsePmt = function parsePmt(packet) {
|
||||
var programMapTable = {};
|
||||
var pusi = parsePayloadUnitStartIndicator(packet);
|
||||
var payloadOffset = 4 + parseAdaptionField(packet);
|
||||
|
||||
if (pusi) {
|
||||
payloadOffset += packet[payloadOffset] + 1;
|
||||
} // PMTs can be sent ahead of the time when they should actually
|
||||
// take effect. We don't believe this should ever be the case
|
||||
// for HLS but we'll ignore "forward" PMT declarations if we see
|
||||
// them. Future PMT declarations have the current_next_indicator
|
||||
// set to zero.
|
||||
|
||||
|
||||
if (!(packet[payloadOffset + 5] & 0x01)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var sectionLength, tableEnd, programInfoLength; // the mapping table ends at the end of the current section
|
||||
|
||||
sectionLength = (packet[payloadOffset + 1] & 0x0f) << 8 | packet[payloadOffset + 2];
|
||||
tableEnd = 3 + sectionLength - 4; // to determine where the table is, we have to figure out how
|
||||
// long the program info descriptors are
|
||||
|
||||
programInfoLength = (packet[payloadOffset + 10] & 0x0f) << 8 | packet[payloadOffset + 11]; // advance the offset to the first entry in the mapping table
|
||||
|
||||
var offset = 12 + programInfoLength;
|
||||
|
||||
while (offset < tableEnd) {
|
||||
var i = payloadOffset + offset; // add an entry that maps the elementary_pid to the stream_type
|
||||
|
||||
programMapTable[(packet[i + 1] & 0x1F) << 8 | packet[i + 2]] = packet[i]; // move to the next table entry
|
||||
// skip past the elementary stream descriptors, if present
|
||||
|
||||
offset += ((packet[i + 3] & 0x0F) << 8 | packet[i + 4]) + 5;
|
||||
}
|
||||
|
||||
return programMapTable;
|
||||
};
|
||||
|
||||
var parsePesType = function parsePesType(packet, programMapTable) {
|
||||
var pid = parsePid(packet);
|
||||
var type = programMapTable[pid];
|
||||
|
||||
switch (type) {
|
||||
case StreamTypes.H264_STREAM_TYPE:
|
||||
return 'video';
|
||||
|
||||
case StreamTypes.ADTS_STREAM_TYPE:
|
||||
return 'audio';
|
||||
|
||||
case StreamTypes.METADATA_STREAM_TYPE:
|
||||
return 'timed-metadata';
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
var parsePesTime = function parsePesTime(packet) {
|
||||
var pusi = parsePayloadUnitStartIndicator(packet);
|
||||
|
||||
if (!pusi) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var offset = 4 + parseAdaptionField(packet);
|
||||
|
||||
if (offset >= packet.byteLength) {
|
||||
// From the H 222.0 MPEG-TS spec
|
||||
// "For transport stream packets carrying PES packets, stuffing is needed when there
|
||||
// is insufficient PES packet data to completely fill the transport stream packet
|
||||
// payload bytes. Stuffing is accomplished by defining an adaptation field longer than
|
||||
// the sum of the lengths of the data elements in it, so that the payload bytes
|
||||
// remaining after the adaptation field exactly accommodates the available PES packet
|
||||
// data."
|
||||
//
|
||||
// If the offset is >= the length of the packet, then the packet contains no data
|
||||
// and instead is just adaption field stuffing bytes
|
||||
return null;
|
||||
}
|
||||
|
||||
var pes = null;
|
||||
var ptsDtsFlags; // PES packets may be annotated with a PTS value, or a PTS value
|
||||
// and a DTS value. Determine what combination of values is
|
||||
// available to work with.
|
||||
|
||||
ptsDtsFlags = packet[offset + 7]; // PTS and DTS are normally stored as a 33-bit number. Javascript
|
||||
// performs all bitwise operations on 32-bit integers but javascript
|
||||
// supports a much greater range (52-bits) of integer using standard
|
||||
// mathematical operations.
|
||||
// We construct a 31-bit value using bitwise operators over the 31
|
||||
// most significant bits and then multiply by 4 (equal to a left-shift
|
||||
// of 2) before we add the final 2 least significant bits of the
|
||||
// timestamp (equal to an OR.)
|
||||
|
||||
if (ptsDtsFlags & 0xC0) {
|
||||
pes = {}; // the PTS and DTS are not written out directly. For information
|
||||
// on how they are encoded, see
|
||||
// http://dvd.sourceforge.net/dvdinfo/pes-hdr.html
|
||||
|
||||
pes.pts = (packet[offset + 9] & 0x0E) << 27 | (packet[offset + 10] & 0xFF) << 20 | (packet[offset + 11] & 0xFE) << 12 | (packet[offset + 12] & 0xFF) << 5 | (packet[offset + 13] & 0xFE) >>> 3;
|
||||
pes.pts *= 4; // Left shift by 2
|
||||
|
||||
pes.pts += (packet[offset + 13] & 0x06) >>> 1; // OR by the two LSBs
|
||||
|
||||
pes.dts = pes.pts;
|
||||
|
||||
if (ptsDtsFlags & 0x40) {
|
||||
pes.dts = (packet[offset + 14] & 0x0E) << 27 | (packet[offset + 15] & 0xFF) << 20 | (packet[offset + 16] & 0xFE) << 12 | (packet[offset + 17] & 0xFF) << 5 | (packet[offset + 18] & 0xFE) >>> 3;
|
||||
pes.dts *= 4; // Left shift by 2
|
||||
|
||||
pes.dts += (packet[offset + 18] & 0x06) >>> 1; // OR by the two LSBs
|
||||
}
|
||||
}
|
||||
|
||||
return pes;
|
||||
};
|
||||
|
||||
var parseNalUnitType = function parseNalUnitType(type) {
|
||||
switch (type) {
|
||||
case 0x05:
|
||||
return 'slice_layer_without_partitioning_rbsp_idr';
|
||||
|
||||
case 0x06:
|
||||
return 'sei_rbsp';
|
||||
|
||||
case 0x07:
|
||||
return 'seq_parameter_set_rbsp';
|
||||
|
||||
case 0x08:
|
||||
return 'pic_parameter_set_rbsp';
|
||||
|
||||
case 0x09:
|
||||
return 'access_unit_delimiter_rbsp';
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
var videoPacketContainsKeyFrame = function videoPacketContainsKeyFrame(packet) {
|
||||
var offset = 4 + parseAdaptionField(packet);
|
||||
var frameBuffer = packet.subarray(offset);
|
||||
var frameI = 0;
|
||||
var frameSyncPoint = 0;
|
||||
var foundKeyFrame = false;
|
||||
var nalType; // advance the sync point to a NAL start, if necessary
|
||||
|
||||
for (; frameSyncPoint < frameBuffer.byteLength - 3; frameSyncPoint++) {
|
||||
if (frameBuffer[frameSyncPoint + 2] === 1) {
|
||||
// the sync point is properly aligned
|
||||
frameI = frameSyncPoint + 5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (frameI < frameBuffer.byteLength) {
|
||||
// look at the current byte to determine if we've hit the end of
|
||||
// a NAL unit boundary
|
||||
switch (frameBuffer[frameI]) {
|
||||
case 0:
|
||||
// skip past non-sync sequences
|
||||
if (frameBuffer[frameI - 1] !== 0) {
|
||||
frameI += 2;
|
||||
break;
|
||||
} else if (frameBuffer[frameI - 2] !== 0) {
|
||||
frameI++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (frameSyncPoint + 3 !== frameI - 2) {
|
||||
nalType = parseNalUnitType(frameBuffer[frameSyncPoint + 3] & 0x1f);
|
||||
|
||||
if (nalType === 'slice_layer_without_partitioning_rbsp_idr') {
|
||||
foundKeyFrame = true;
|
||||
}
|
||||
} // drop trailing zeroes
|
||||
|
||||
|
||||
do {
|
||||
frameI++;
|
||||
} while (frameBuffer[frameI] !== 1 && frameI < frameBuffer.length);
|
||||
|
||||
frameSyncPoint = frameI - 2;
|
||||
frameI += 3;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// skip past non-sync sequences
|
||||
if (frameBuffer[frameI - 1] !== 0 || frameBuffer[frameI - 2] !== 0) {
|
||||
frameI += 3;
|
||||
break;
|
||||
}
|
||||
|
||||
nalType = parseNalUnitType(frameBuffer[frameSyncPoint + 3] & 0x1f);
|
||||
|
||||
if (nalType === 'slice_layer_without_partitioning_rbsp_idr') {
|
||||
foundKeyFrame = true;
|
||||
}
|
||||
|
||||
frameSyncPoint = frameI - 2;
|
||||
frameI += 3;
|
||||
break;
|
||||
|
||||
default:
|
||||
// the current byte isn't a one or zero, so it cannot be part
|
||||
// of a sync sequence
|
||||
frameI += 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
frameBuffer = frameBuffer.subarray(frameSyncPoint);
|
||||
frameI -= frameSyncPoint;
|
||||
frameSyncPoint = 0; // parse the final nal
|
||||
|
||||
if (frameBuffer && frameBuffer.byteLength > 3) {
|
||||
nalType = parseNalUnitType(frameBuffer[frameSyncPoint + 3] & 0x1f);
|
||||
|
||||
if (nalType === 'slice_layer_without_partitioning_rbsp_idr') {
|
||||
foundKeyFrame = true;
|
||||
}
|
||||
}
|
||||
|
||||
return foundKeyFrame;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
parseType: parseType,
|
||||
parsePat: parsePat,
|
||||
parsePmt: parsePmt,
|
||||
parsePayloadUnitStartIndicator: parsePayloadUnitStartIndicator,
|
||||
parsePesType: parsePesType,
|
||||
parsePesTime: parsePesTime,
|
||||
videoPacketContainsKeyFrame: videoPacketContainsKeyFrame
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue