yuv-rx
Version:
Reading videos as Rx Observables of decoded frames
85 lines (84 loc) • 3.82 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.yuv4mpegStreamForPath = exports.yuv4mpegStreamForCustomInput = void 0;
const child_process_1 = require("child_process");
const rxjs_1 = require("rxjs");
const log_handler_1 = require("./log-handler");
function inputArgs(path, options) {
var _a, _b;
const params = [];
params.push('-flags2', '+showall');
const seekseconds = (_a = options === null || options === void 0 ? void 0 : options.seekSeconds) !== null && _a !== void 0 ? _a : 0;
if (seekseconds > 0) {
params.push('-ss', seekseconds.toString());
}
if (options === null || options === void 0 ? void 0 : options.iFramesOnly) {
params.push('-skip_frame', 'nokey');
}
params.push('-i', path);
const vstream = options === null || options === void 0 ? void 0 : options.videoStream;
if (vstream != null) {
params.push('-map', `0:v:${vstream}`);
}
const vframes = (_b = options === null || options === void 0 ? void 0 : options.vframes) !== null && _b !== void 0 ? _b : null;
if (vframes != null) {
params.push('-vframes', vframes.toString());
}
return params;
}
function outputArgs(pixFmt) {
return ['-loglevel', 'error', '-f', 'yuv4mpegpipe', '-pix_fmt', pixFmt !== null && pixFmt !== void 0 ? pixFmt : 'yuv420p', '-strict', '-1', '-threads', '0', '-'];
}
function yuv4mpeg(path, options) {
return [...inputArgs(path, options), ...outputArgs(options === null || options === void 0 ? void 0 : options.pixFmt)];
}
function yuv4mpegStream(ffmpeg, args, options) {
return new rxjs_1.Observable(subscriber => {
var _a;
if (options === null || options === void 0 ? void 0 : options.verbose) {
console.log('FFMpeg:', ffmpeg);
console.log('Arguments:', args.join(' '));
}
const handleFfmpegLog = (0, log_handler_1.logHandlerFn)((_a = options === null || options === void 0 ? void 0 : options.ffmpegLogHandler) !== null && _a !== void 0 ? _a : 'none');
let exited = false;
const child = (0, child_process_1.spawn)(ffmpeg, args, { stdio: 'pipe' });
child.on('exit', (code, signal) => {
exited = true;
if (options === null || options === void 0 ? void 0 : options.verbose) {
console.log(new Error(`FFMpeg exited with code ${code}, signal ${signal}`));
}
if (code != null && code == 0) {
if (child.stdout.readableEnded) {
subscriber.complete();
}
}
else {
subscriber.error(new Error(`FFMpeg exited with exit code ${code}, signal ${signal}`));
}
});
child.stdout.on('end', () => {
if (options === null || options === void 0 ? void 0 : options.verbose) {
console.log('Output stream ended');
}
if (exited) {
subscriber.complete();
}
});
child.stdout.on('data', data => {
if (options === null || options === void 0 ? void 0 : options.verbose) {
console.log(`Received data (${data.length} bytes)`);
}
subscriber.next(data);
});
child.stderr.on('data', handleFfmpegLog);
return () => child.kill();
});
}
function yuv4mpegStreamForCustomInput(ffmpeg, args, options) {
return yuv4mpegStream(ffmpeg, [...args, ...outputArgs(options === null || options === void 0 ? void 0 : options.pixFmt)], options);
}
exports.yuv4mpegStreamForCustomInput = yuv4mpegStreamForCustomInput;
function yuv4mpegStreamForPath(ffmpeg, path, options) {
return yuv4mpegStream(ffmpeg, yuv4mpeg(path, options), options);
}
exports.yuv4mpegStreamForPath = yuv4mpegStreamForPath;