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.

173 lines
4.2 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(val) {
return '0x' + ('00' + val.toString(16)).slice(-2).toUpperCase();
},
hexStringList = function(data) {
var arr = [], i;
while (data.byteLength > 0) {
i = 0;
arr.push(hex(data[i++]));
data = data.subarray(i);
}
return arr.join(' ');
},
parseAVCTag = function(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(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(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(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(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(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(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(flvTagArray) {
return JSON.stringify(flvTagArray, null, 2);
};
module.exports = {
inspectTag: inspectFlvTag,
inspect: inspectFlv,
textify: textifyFlv
};