flv-inspector.js
3.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/**
* 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
};