123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- /**
- * mux.js
- *
- * Copyright (c) Brightcove
- * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
- */
- 'use strict';
- var Stream = require('../utils/stream.js');
- var ONE_SECOND_IN_TS = require('../utils/clock').ONE_SECOND_IN_TS;
- var AdtsStream;
- var
- ADTS_SAMPLING_FREQUENCIES = [
- 96000,
- 88200,
- 64000,
- 48000,
- 44100,
- 32000,
- 24000,
- 22050,
- 16000,
- 12000,
- 11025,
- 8000,
- 7350
- ];
- /*
- * Accepts a ElementaryStream and emits data events with parsed
- * AAC Audio Frames of the individual packets. Input audio in ADTS
- * format is unpacked and re-emitted as AAC frames.
- *
- * @see http://wiki.multimedia.cx/index.php?title=ADTS
- * @see http://wiki.multimedia.cx/?title=Understanding_AAC
- */
- AdtsStream = function(handlePartialSegments) {
- var
- buffer,
- frameNum = 0;
- AdtsStream.prototype.init.call(this);
- this.skipWarn_ = function(start, end) {
- this.trigger('log', {
- level: 'warn',
- message: `adts skiping bytes ${start} to ${end} in frame ${frameNum} outside syncword`
- });
- };
- this.push = function(packet) {
- var
- i = 0,
- frameLength,
- protectionSkipBytes,
- frameEnd,
- oldBuffer,
- sampleCount,
- adtsFrameDuration;
- if (!handlePartialSegments) {
- frameNum = 0;
- }
- if (packet.type !== 'audio') {
- // ignore non-audio data
- return;
- }
- // Prepend any data in the buffer to the input data so that we can parse
- // aac frames the cross a PES packet boundary
- if (buffer && buffer.length) {
- oldBuffer = buffer;
- buffer = new Uint8Array(oldBuffer.byteLength + packet.data.byteLength);
- buffer.set(oldBuffer);
- buffer.set(packet.data, oldBuffer.byteLength);
- } else {
- buffer = packet.data;
- }
- // unpack any ADTS frames which have been fully received
- // for details on the ADTS header, see http://wiki.multimedia.cx/index.php?title=ADTS
- var skip;
- // We use i + 7 here because we want to be able to parse the entire header.
- // If we don't have enough bytes to do that, then we definitely won't have a full frame.
- while ((i + 7) < buffer.length) {
- // Look for the start of an ADTS header..
- if ((buffer[i] !== 0xFF) || (buffer[i + 1] & 0xF6) !== 0xF0) {
- if (typeof skip !== 'number') {
- skip = i;
- }
- // If a valid header was not found, jump one forward and attempt to
- // find a valid ADTS header starting at the next byte
- i++;
- continue;
- }
- if (typeof skip === 'number') {
- this.skipWarn_(skip, i);
- skip = null;
- }
- // The protection skip bit tells us if we have 2 bytes of CRC data at the
- // end of the ADTS header
- protectionSkipBytes = (~buffer[i + 1] & 0x01) * 2;
- // Frame length is a 13 bit integer starting 16 bits from the
- // end of the sync sequence
- // NOTE: frame length includes the size of the header
- frameLength = ((buffer[i + 3] & 0x03) << 11) |
- (buffer[i + 4] << 3) |
- ((buffer[i + 5] & 0xe0) >> 5);
- sampleCount = ((buffer[i + 6] & 0x03) + 1) * 1024;
- adtsFrameDuration = (sampleCount * ONE_SECOND_IN_TS) /
- ADTS_SAMPLING_FREQUENCIES[(buffer[i + 2] & 0x3c) >>> 2];
- // If we don't have enough data to actually finish this ADTS frame,
- // then we have to wait for more data
- if ((buffer.byteLength - i) < frameLength) {
- break;
- }
- // Otherwise, deliver the complete AAC frame
- this.trigger('data', {
- pts: packet.pts + (frameNum * adtsFrameDuration),
- dts: packet.dts + (frameNum * adtsFrameDuration),
- sampleCount: sampleCount,
- audioobjecttype: ((buffer[i + 2] >>> 6) & 0x03) + 1,
- channelcount: ((buffer[i + 2] & 1) << 2) |
- ((buffer[i + 3] & 0xc0) >>> 6),
- samplerate: ADTS_SAMPLING_FREQUENCIES[(buffer[i + 2] & 0x3c) >>> 2],
- samplingfrequencyindex: (buffer[i + 2] & 0x3c) >>> 2,
- // assume ISO/IEC 14496-12 AudioSampleEntry default of 16
- samplesize: 16,
- // data is the frame without it's header
- data: buffer.subarray(i + 7 + protectionSkipBytes, i + frameLength)
- });
- frameNum++;
- i += frameLength;
- }
- if (typeof skip === 'number') {
- this.skipWarn_(skip, i);
- skip = null;
- }
- // remove processed bytes from the buffer.
- buffer = buffer.subarray(i);
- };
- this.flush = function() {
- frameNum = 0;
- this.trigger('done');
- };
- this.reset = function() {
- buffer = void 0;
- this.trigger('reset');
- };
- this.endTimeline = function() {
- buffer = void 0;
- this.trigger('endedtimeline');
- };
- };
- AdtsStream.prototype = new Stream();
- module.exports = AdtsStream;
|