UNPKG

sp-streams

Version:

Streamplace Streams for Piping Video Around and Stuff

121 lines (94 loc) 4.24 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DEFAULT_WINDOW_SIZE = exports.DEFAULT_SEG_DURATION = exports.MANIFEST_NAME = undefined; exports.default = dashStream; var _ffmpeg = require("./ffmpeg"); var _ffmpeg2 = _interopRequireDefault(_ffmpeg); var _stream = require("stream"); var _socketEgressStream = require("./socket-egress-stream"); var _socketEgressStream2 = _interopRequireDefault(_socketEgressStream); var _express = require("express"); var _express2 = _interopRequireDefault(_express); var _debug = require("debug"); var _debug2 = _interopRequireDefault(_debug); var _fs = require("fs"); var _fs2 = _interopRequireDefault(_fs); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var MANIFEST_NAME = exports.MANIFEST_NAME = "manifest.mpd"; var DEFAULT_SEG_DURATION = exports.DEFAULT_SEG_DURATION = 5000; var DEFAULT_WINDOW_SIZE = exports.DEFAULT_WINDOW_SIZE = 3; var log = (0, _debug2.default)("sp:dash-stream"); function dashStream() { var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var socketEgress = (0, _socketEgressStream2.default)({ useFirstBuffer: false }); var passThrough = new _stream.PassThrough(); passThrough.segDuration = opts.segDuration || DEFAULT_SEG_DURATION; passThrough.windowSize = opts.windowSize || DEFAULT_WINDOW_SIZE; var app = (0, _express2.default)(); var ffmpeg = void 0; app.post("*", function (req, res) { // weird bug where the HLS manifest from ffmpeg has two leading slashes var filename = req.url.replace(/^\/+/, ""); log("got " + filename); // No matter what, tell ffmpeg that it's chill when we're done req.on("end", function () { res.sendStatus(200); }); if (filename === MANIFEST_NAME) { // If it's the manifest, assemble the chunks and emit when done var manifest = ""; req.on("data", function (chunk) { manifest += chunk.toString(); }); req.on("end", function () { // hack... this is usually accurate but I can't get ffmpeg to output it passThrough.emit("manifest", manifest.replace("mp4a.40", "mp4a.40.2")); }); } else { // If it's data, pass the stream right on through passThrough.emit("chunk", filename, req); } }); passThrough.on("end", function () { listener.close(function () { log("DASH HTTP ingress closed on port " + socketEgress.httpPort); }); }); var listener = void 0; Promise.resolve().then(function (resolve, reject) { listener = app.listen(0, resolve); }).then(function () { socketEgress.httpPort = listener.address().port; log("DASH HTTP ingress listening on port " + socketEgress.httpPort); ffmpeg = (0, _ffmpeg2.default)().input("unix://" + socketEgress.path).inputFormat("mpegts").videoCodec("copy").audioCodec("copy").outputOptions([ // This section from default options at https://ffmpeg.org/ffmpeg-all.html#dash-2 "-bf 1", "-keyint_min 120", "-g 120", "-sc_threshold 0", "-b_strategy 0", "-ar:a:1 22050", "-use_timeline 1", "-use_template 1", // hls too! "-hls_playlist 1", // Avoids Tag [15][0][0][0] incompatible with output codec id '86018' (mp4a) "-tag:v avc1", "-tag:a mp4a", "-window_size " + passThrough.windowSize, "-min_seg_duration " + passThrough.segDuration * 1000 // ms ==> microseconds ]).output("http://127.0.0.1:" + socketEgress.httpPort + "/" + MANIFEST_NAME).outputFormat("dash"); return socketEgress.getPath(); }).then(function () { passThrough.pipe(socketEgress); // hack hack hack, but for now we need a newer version var FFMPEG_UNSTABLE_PATH = "/usr/bin/ffmpeg-unstable"; if (!_fs2.default.existsSync(FFMPEG_UNSTABLE_PATH)) { throw new Error("ffmpeg-unstable not found"); } else { log("using " + FFMPEG_UNSTABLE_PATH); // ugh, this is a global setting for some reason ffmpeg._getFfmpegPath = function (cb) { return cb(null, FFMPEG_UNSTABLE_PATH); }; ffmpeg.run(); } }).catch(function (err) { log(err); throw err; }); passThrough.getPath = socketEgress.getPath.bind(socketEgress); return passThrough; }