134 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			134 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * 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
 | |
| }; | 
