123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- 'use strict';
- var Stream = require('../utils/stream.js');
- var mp4 = require('../mp4/mp4-generator.js');
- var audioFrameUtils = require('../mp4/audio-frame-utils');
- var trackInfo = require('../mp4/track-decode-info.js');
- var ONE_SECOND_IN_TS = require('../utils/clock').ONE_SECOND_IN_TS;
- var AUDIO_PROPERTIES = require('../constants/audio-properties.js');
- /**
- * Constructs a single-track, ISO BMFF media segment from AAC data
- * events. The output of this stream can be fed to a SourceBuffer
- * configured with a suitable initialization segment.
- */
- var AudioSegmentStream = function AudioSegmentStream(track, options) {
- var adtsFrames = [],
- sequenceNumber = 0,
- earliestAllowedDts = 0,
- audioAppendStartTs = 0,
- videoBaseMediaDecodeTime = Infinity,
- segmentStartPts = null,
- segmentEndPts = null;
- options = options || {};
- AudioSegmentStream.prototype.init.call(this);
- this.push = function (data) {
- trackInfo.collectDtsInfo(track, data);
- if (track) {
- AUDIO_PROPERTIES.forEach(function (prop) {
- track[prop] = data[prop];
- });
- } // buffer audio data until end() is called
- adtsFrames.push(data);
- };
- this.setEarliestDts = function (earliestDts) {
- earliestAllowedDts = earliestDts;
- };
- this.setVideoBaseMediaDecodeTime = function (baseMediaDecodeTime) {
- videoBaseMediaDecodeTime = baseMediaDecodeTime;
- };
- this.setAudioAppendStart = function (timestamp) {
- audioAppendStartTs = timestamp;
- };
- this.processFrames_ = function () {
- var frames, moof, mdat, boxes, timingInfo; // return early if no audio data has been observed
- if (adtsFrames.length === 0) {
- return;
- }
- frames = audioFrameUtils.trimAdtsFramesByEarliestDts(adtsFrames, track, earliestAllowedDts);
- if (frames.length === 0) {
- // return early if the frames are all after the earliest allowed DTS
- // TODO should we clear the adtsFrames?
- return;
- }
- track.baseMediaDecodeTime = trackInfo.calculateTrackBaseMediaDecodeTime(track, options.keepOriginalTimestamps);
- audioFrameUtils.prefixWithSilence(track, frames, audioAppendStartTs, videoBaseMediaDecodeTime); // we have to build the index from byte locations to
- // samples (that is, adts frames) in the audio data
- track.samples = audioFrameUtils.generateSampleTable(frames); // concatenate the audio data to constuct the mdat
- mdat = mp4.mdat(audioFrameUtils.concatenateFrameData(frames));
- adtsFrames = [];
- moof = mp4.moof(sequenceNumber, [track]); // bump the sequence number for next time
- sequenceNumber++;
- track.initSegment = mp4.initSegment([track]); // it would be great to allocate this array up front instead of
- // throwing away hundreds of media segment fragments
- boxes = new Uint8Array(moof.byteLength + mdat.byteLength);
- boxes.set(moof);
- boxes.set(mdat, moof.byteLength);
- trackInfo.clearDtsInfo(track);
- if (segmentStartPts === null) {
- segmentEndPts = segmentStartPts = frames[0].pts;
- }
- segmentEndPts += frames.length * (ONE_SECOND_IN_TS * 1024 / track.samplerate);
- timingInfo = {
- start: segmentStartPts
- };
- this.trigger('timingInfo', timingInfo);
- this.trigger('data', {
- track: track,
- boxes: boxes
- });
- };
- this.flush = function () {
- this.processFrames_(); // trigger final timing info
- this.trigger('timingInfo', {
- start: segmentStartPts,
- end: segmentEndPts
- });
- this.resetTiming_();
- this.trigger('done', 'AudioSegmentStream');
- };
- this.partialFlush = function () {
- this.processFrames_();
- this.trigger('partialdone', 'AudioSegmentStream');
- };
- this.endTimeline = function () {
- this.flush();
- this.trigger('endedtimeline', 'AudioSegmentStream');
- };
- this.resetTiming_ = function () {
- trackInfo.clearDtsInfo(track);
- segmentStartPts = null;
- segmentEndPts = null;
- };
- this.reset = function () {
- this.resetTiming_();
- adtsFrames = [];
- this.trigger('reset');
- };
- };
- AudioSegmentStream.prototype = new Stream();
- module.exports = AudioSegmentStream;
|