UNPKG

mp3player

Version:

A mp3 player,get data by ajax and play by audiocontext or mediasource.it can download and reprocessing while playing

173 lines (155 loc) 5.83 kB
/** * MP3音频帧头信息模块 * http://www.docin.com/p-1261649617.html * https://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header */ import BitStream from '../common/bitstream'; //比特率对应表(bit/s) MEPG1.0 LayerIII var bitRateMap = { '1': 32000, '10': 40000, '11': 48000, '100': 56000, '101': 64000, '110': 80000, '111': 96000, '1000': 112000, '1001': 128000, '1010': 160000, '1011': 192000, '1100': 224000, '1101': 256000, '1110': 320000 } //采样率对应表(Hz) MEPG1.0 LayerIII var sampleRateMap = { '0': 44100, '1': 48000, '10': 32000 } var HEADER_MASK = 0xffe0 >> 5; //同步头 var MPEG1 = 3; var LAYER3 = 1; var MAX_TAG_OFF = 10 * 1024; //查找帧头,最多查找10K var hasParseVbr = false; function Header(_bitStream) { this.init(_bitStream); } var _proto_ = Header.prototype; /** * 初始化 * @param {object} arrayBuffer 二进制数组 */ _proto_.init = function(_bitStream) { this.bitStream = _bitStream; } /** * 解析帧头信息 * @return object 比特流 */ _proto_.parseHeader = function() { var mask = 0; var beginPos = this.bitStream.getBytePos(); do { mask = this.bitStream.getBits(11); //获取11位同步头 if (mask != HEADER_MASK) { if (this.bitStream.isEnd()) { break; } this.bitStream.rewindBits(3); continue; } this.verID = this.bitStream.getBits(2); //MPEG版本 this.layer = this.bitStream.getBits(2); //MPEG层数 this.protectionBit = this.bitStream.getBits(1); //保护位 if (!this.frameSync) { this.bitStream.rewindBytes(2); this.frameSync = this.bitStream.getBits(8).toString(16) + ',' + this.bitStream.getBits(8).toString(16); this.frameSync = this.frameSync.toUpperCase(); //同步头 } this.bitrateIndex = this.bitStream.getBitsStr(4); this.bitRate = bitRateMap[this.bitrateIndex]; //比特率 this.sampleRateIndex = this.bitStream.getBitsStr(2); this.sampleRate = sampleRateMap[this.sampleRateIndex]; //采样路索引 this.paddingBit = this.bitStream.getBits(1); //填充位 this.privateBit = this.bitStream.getBits(1); //私有位 this.channelMode = this.bitStream.getBits(2); //声道模式 this.channelModeExtension = this.bitStream.getBits(2); //声道扩展模式 this.copyright = this.bitStream.getBits(1); //版权 this.original = this.bitStream.getBits(1); //填充位 this.emphasis = this.bitStream.getBits(2); //强调 if (this.verID != MPEG1 || this.layer != LAYER3) { return false; } this.frameSize = bitRateMap[this.bitrateIndex] * 1152 / 8; this.frameSize /= sampleRateMap[this.sampleRateIndex]; this.frameSize += this.paddingBit; //帧长度 this.sideInfoSize = (this.channelMode == 3) ? 17 : 32; //帧边信息长度 this.duration = 1152 / sampleRateMap[this.sampleRateIndex]; //本帧时长 //计算主数据长度 this.mainDataSize = (this.frameSize - 4 - this.sideInfoSize) >> 0; //主数据长度 if (this.protectionBit == 0) this.mainDataSize -= 2; //CRC break; } while (this.bitStream.getBytePos() - beginPos < MAX_TAG_OFF); if (this.bitStream.getBytePos() - beginPos >= MAX_TAG_OFF || this.bitStream.isEnd()) { return false; } this.endBytePos = this.bitStream.getBytePos(); if (!hasParseVbr) { hasParseVbr = true; this.parseVbr(); if (this.toc) { this.totalDuration = this.totalFrames * 1152 / sampleRateMap[this.sampleRateIndex]; //总时长 } } return this.bitStream; } /** * 解析vbr信息 */ _proto_.parseVbr = function() { var flags = 0; var tag = ''; do { tag = String.fromCharCode(this.bitStream.getByte(), this.bitStream.getByte(), this.bitStream.getByte(), this.bitStream.getByte()); if (tag == 'Xing' || tag == 'Info') { //Xing,Info头 this.tocSize = 100; //vbr索引表长度 flags = this.bitStream.getBits(32); if (flags & 1) { this.totalFrames = this.bitStream.getBits(32); //总帧数 } if (flags & 2) { this.totalBytes = this.bitStream.getBits(32); //总长度 } if (flags & 4) { this.toc = []; //vbr索引表 for (var i = 0; i < this.tocSize; i++) { this.toc[i] = this.bitStream.getByte(); } } this.bitStream.setBytePos(this.endBytePos); return this.bitStream; } else if (tag == 'VBRI') { //VBRI头 this.bitStream.skipBytes(6); this.totalBytes = this.bitStream.getBits(32); this.totalFrames = this.bitStream.getBits(32); this.tocSize = this.bitStream.getBits(16); this.bitStream.skipBytes(6); this.toc = []; for (var i = 0; i < tocSize; i++) { this.toc[i] = this.bitStream.getByte(); } this.bitStream.setBytePos(this.endBytePos); return this.bitStream; } else { if (this.bitStream.isEnd()) { break; } this.bitStream.rewindBytes(3); } } while (tag != 'Xing' && tag != 'Info' && tag != 'VBRI' && this.bitStream.getBytePos() < MAX_TAG_OFF) this.bitStream.setBytePos(this.endBytePos); return false; } export default Header;