@sqhead/mux.js
Version:
A collection of lightweight utilities for inspecting and manipulating video container formats.
95 lines (75 loc) • 2.76 kB
JavaScript
var Stream = require('../utils/stream.js');
var H264Stream = require('../codecs/h264').H264Stream;
var VideoSegmentStream = require('../mp4/transmuxer').VideoSegmentStream;
var CoalesceStream = require('./coalesce-stream.js');
// object types
var Transmuxer;
var TIMESCALE = 90000; // Hz
var ACCESS_UNIT_DELIMITER = new Uint8Array([0, 0, 0, 1, 9]);
/**
* A Stream that takes raw H264 frames as binary data as input and produces
* corresponding media segments, suitable for use with Media Source
* Extension (MSE) implementations that support the ISO BMFF byte
* stream format, like Chrome.
*/
Transmuxer = function(options) {
Transmuxer.prototype.init.call(this);
options = options || {};
this.baseMediaDecodeTime = options.baseMediaDecodeTime || 0;
this.transmuxPipeline_;
this.setupPipeline = function() {
var pipeline = {};
this.transmuxPipeline_ = pipeline;
pipeline.type = 'rawh264';
var videoTrack = {
timelineStartInfo: {
baseMediaDecodeTime: 0
},
id: 0,
codec: 'avc',
type: 'video'
};
// Setup pipelines
pipeline.h264Stream = new H264Stream();
pipeline.videoSegmentStream = new VideoSegmentStream(videoTrack, options);
pipeline.coalesceStream = new CoalesceStream(options);
pipeline.coalesceStream.numberOfTracks++;
pipeline.h264Stream
.pipe(pipeline.videoSegmentStream)
.pipe(pipeline.coalesceStream);
// Re-emit any data coming from the coalesce stream to the outside world
pipeline.coalesceStream.on('data', this.trigger.bind(this, 'data'));
// Let the consumer know we have finished flushing the entire pipeline
pipeline.coalesceStream.on('done', this.trigger.bind(this, 'done'));
// Set head of pipeline
pipeline.headOfPipeline = pipeline.h264Stream;
};
this.setupPipeline();
// feed incoming data to the front of the parsing pipeline
// data must be object with `data` and `timestamp` fields
this.push = function(data) {
// Set correct pts/dts values
pts = dts = data.timestamp * TIMESCALE;
// Prepend Access Unit Delimiter
packetData = new Uint8Array(data.data.byteLength + ACCESS_UNIT_DELIMITER.byteLength);
packetData.set(ACCESS_UNIT_DELIMITER);
packetData.set(data.data, ACCESS_UNIT_DELIMITER.byteLength);
var packet = {
type: 'video',
trackId: 0,
pts: pts,
dts: dts,
data: packetData
};
this.transmuxPipeline_.headOfPipeline.push(packet);
};
// flush any buffered data
this.flush = function() {
// Start at the top of the pipeline and flush all pending work
this.transmuxPipeline_.headOfPipeline.flush();
};
};
Transmuxer.prototype = new Stream();
module.exports = {
Transmuxer: Transmuxer
};