You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
3.9 KiB
134 lines
3.9 KiB
/**
|
|
* mux.js
|
|
*
|
|
* Copyright (c) Brightcove
|
|
* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
|
|
*/
|
|
'use strict';
|
|
|
|
var tagTypes = {
|
|
0x08: 'audio',
|
|
0x09: 'video',
|
|
0x12: 'metadata'
|
|
},
|
|
hex = function hex(val) {
|
|
return '0x' + ('00' + val.toString(16)).slice(-2).toUpperCase();
|
|
},
|
|
hexStringList = function hexStringList(data) {
|
|
var arr = [],
|
|
i;
|
|
|
|
while (data.byteLength > 0) {
|
|
i = 0;
|
|
arr.push(hex(data[i++]));
|
|
data = data.subarray(i);
|
|
}
|
|
|
|
return arr.join(' ');
|
|
},
|
|
parseAVCTag = function parseAVCTag(tag, obj) {
|
|
var avcPacketTypes = ['AVC Sequence Header', 'AVC NALU', 'AVC End-of-Sequence'],
|
|
compositionTime = tag[1] & parseInt('01111111', 2) << 16 | tag[2] << 8 | tag[3];
|
|
obj = obj || {};
|
|
obj.avcPacketType = avcPacketTypes[tag[0]];
|
|
obj.CompositionTime = tag[1] & parseInt('10000000', 2) ? -compositionTime : compositionTime;
|
|
|
|
if (tag[0] === 1) {
|
|
obj.nalUnitTypeRaw = hexStringList(tag.subarray(4, 100));
|
|
} else {
|
|
obj.data = hexStringList(tag.subarray(4));
|
|
}
|
|
|
|
return obj;
|
|
},
|
|
parseVideoTag = function parseVideoTag(tag, obj) {
|
|
var frameTypes = ['Unknown', 'Keyframe (for AVC, a seekable frame)', 'Inter frame (for AVC, a nonseekable frame)', 'Disposable inter frame (H.263 only)', 'Generated keyframe (reserved for server use only)', 'Video info/command frame'],
|
|
codecID = tag[0] & parseInt('00001111', 2);
|
|
obj = obj || {};
|
|
obj.frameType = frameTypes[(tag[0] & parseInt('11110000', 2)) >>> 4];
|
|
obj.codecID = codecID;
|
|
|
|
if (codecID === 7) {
|
|
return parseAVCTag(tag.subarray(1), obj);
|
|
}
|
|
|
|
return obj;
|
|
},
|
|
parseAACTag = function parseAACTag(tag, obj) {
|
|
var packetTypes = ['AAC Sequence Header', 'AAC Raw'];
|
|
obj = obj || {};
|
|
obj.aacPacketType = packetTypes[tag[0]];
|
|
obj.data = hexStringList(tag.subarray(1));
|
|
return obj;
|
|
},
|
|
parseAudioTag = function parseAudioTag(tag, obj) {
|
|
var formatTable = ['Linear PCM, platform endian', 'ADPCM', 'MP3', 'Linear PCM, little endian', 'Nellymoser 16-kHz mono', 'Nellymoser 8-kHz mono', 'Nellymoser', 'G.711 A-law logarithmic PCM', 'G.711 mu-law logarithmic PCM', 'reserved', 'AAC', 'Speex', 'MP3 8-Khz', 'Device-specific sound'],
|
|
samplingRateTable = ['5.5-kHz', '11-kHz', '22-kHz', '44-kHz'],
|
|
soundFormat = (tag[0] & parseInt('11110000', 2)) >>> 4;
|
|
obj = obj || {};
|
|
obj.soundFormat = formatTable[soundFormat];
|
|
obj.soundRate = samplingRateTable[(tag[0] & parseInt('00001100', 2)) >>> 2];
|
|
obj.soundSize = (tag[0] & parseInt('00000010', 2)) >>> 1 ? '16-bit' : '8-bit';
|
|
obj.soundType = tag[0] & parseInt('00000001', 2) ? 'Stereo' : 'Mono';
|
|
|
|
if (soundFormat === 10) {
|
|
return parseAACTag(tag.subarray(1), obj);
|
|
}
|
|
|
|
return obj;
|
|
},
|
|
parseGenericTag = function parseGenericTag(tag) {
|
|
return {
|
|
tagType: tagTypes[tag[0]],
|
|
dataSize: tag[1] << 16 | tag[2] << 8 | tag[3],
|
|
timestamp: tag[7] << 24 | tag[4] << 16 | tag[5] << 8 | tag[6],
|
|
streamID: tag[8] << 16 | tag[9] << 8 | tag[10]
|
|
};
|
|
},
|
|
inspectFlvTag = function inspectFlvTag(tag) {
|
|
var header = parseGenericTag(tag);
|
|
|
|
switch (tag[0]) {
|
|
case 0x08:
|
|
parseAudioTag(tag.subarray(11), header);
|
|
break;
|
|
|
|
case 0x09:
|
|
parseVideoTag(tag.subarray(11), header);
|
|
break;
|
|
|
|
case 0x12:
|
|
}
|
|
|
|
return header;
|
|
},
|
|
inspectFlv = function inspectFlv(bytes) {
|
|
var i = 9,
|
|
// header
|
|
dataSize,
|
|
parsedResults = [],
|
|
tag; // traverse the tags
|
|
|
|
i += 4; // skip previous tag size
|
|
|
|
while (i < bytes.byteLength) {
|
|
dataSize = bytes[i + 1] << 16;
|
|
dataSize |= bytes[i + 2] << 8;
|
|
dataSize |= bytes[i + 3];
|
|
dataSize += 11;
|
|
tag = bytes.subarray(i, i + dataSize);
|
|
parsedResults.push(inspectFlvTag(tag));
|
|
i += dataSize + 4;
|
|
}
|
|
|
|
return parsedResults;
|
|
},
|
|
textifyFlv = function textifyFlv(flvTagArray) {
|
|
return JSON.stringify(flvTagArray, null, 2);
|
|
};
|
|
|
|
module.exports = {
|
|
inspectTag: inspectFlvTag,
|
|
inspect: inspectFlv,
|
|
textify: textifyFlv
|
|
}; |