Source: video.js

"use strict";
/**
 * Creates a new instance of VideoRecorder.
 *
 * @class
 * @name VideoRecorder
 * @classdesc contains methods to record video for tests
 * @arg {object} [opts] - Options.
 * @arg {object} [opts._process] - Injected `process` module.
 * @arg {object} [opts._which] - Injected `which` module.
 * @arg {object} [opts._spawn] - Injected `spawn` module.
 * @property {boolean} [isRunning=false] - flag is video recorder running or no
 * @property {?string} [filePath=null] - path video file
 */

var path = require("path");

var spawn = require("cross-spawn");
var which = require("which");
var U = require("glace-utils");
var LOG = U.logger;

var VideoRecorder = function (opts) {
    opts = U.defVal(opts, {});

    this.isRunning = false;
    this.filePath = null;

    this._process = null;
    this._recordOpts = null;

    this.__process = U.defVal(opts._process, process);
    this.__which = U.defVal(opts._which, which);
    this.__spawn = U.defVal(opts._spawn, spawn);
};
/**
 * Configures video recorder.
 *
 * @method
 * @arg {object} [opts] - recorder configuration
 * @arg {string} [opts.path] - video file path
 * @arg {number} [opts.fps=30] - video framerate
 * @arg {number} [opts.width=1024] - video width
 * @arg {number} [opts.height=768] - video height
 * @arg {number} [opts.x=0] - `X`-offset on display
 * @arg {number} [opts.y=0] - `Y`-offset on display
 */
VideoRecorder.prototype.configure = function (opts) {
    opts = U.defVal(opts, {});
    opts.fps = U.defVal(opts.fps, 30);
    opts.width = U.defVal(opts.width, 1024);
    opts.height = U.defVal(opts.height, 768);
    opts.x = U.defVal(opts.x, 0);
    opts.y = U.defVal(opts.y, 0);
    opts.size = opts.width + "x" + opts.height;
    this.filePath = U.defVal(opts.path, path.resolve(U.cwd, "out.avi"));

    if (this.__process.platform === "win32") {

        this.__which.sync("ffmpeg");
        this._recordCmd = "ffmpeg";
        this._recordOpts = [ "-y",
            "-loglevel", "quiet",
            "-video_size", opts.size,
            "-offset_x", opts.x,
            "-offset_y", opts.y,
            "-draw_mouse", 0,
            "-framerate", opts.fps,
            "-f", "gdigrab",
            "-i", "desktop",
            "-vcodec", "libx264",
            this.filePath ];

    } else if (this.__process.platform === "linux") {

        if (this.__which.sync("avconv", { nothrow: true })) {
            this._recordCmd = "avconv";
        } else if (this.__which.sync("ffmpeg", { nothrow: true })) {
            this._recordCmd = "ffmpeg";
        } else {
            throw new Error("not found: avconv or ffmpeg");
        };
        this._recordOpts = [ "-y",
            "-loglevel", "quiet",
            "-f", "x11grab",
            "-r", opts.fps,
            "-s", opts.size,
            "-i", `${process.env.DISPLAY}+${opts.x},${opts.y}`,
            "-codec", "libx264",
            this.filePath ];

    } else if (this.__process.platform === "darwin") {

        this.__which.sync("ffmpeg");
        this._recordCmd = "ffmpeg";
        this._recordOpts = [ "-y",
            "-loglevel", "quiet",
            "-f", "avfoundation",
            "-r", opts.fps,
            "-i", "1:",
            "-vsync", 2,
            this.filePath ];

    } else {
        throw new Error("Video capture isn't supported " +
                        `on platform '${this.__process.platform}'`);
    };
};
/**
 * Starts video recorder.
 *
 * @method
 * @throws {Error} if video recorder is started already
 * @throws {Error} if video recorder isn't configured yet
 */
VideoRecorder.prototype.start = function () {
    if (this.isRunning) return;
    if (!this._recordOpts)
        throw new Error("Video recorder isn't configured yet");

    this._process = this.__spawn(this._recordCmd, this._recordOpts,
        { killSignal: "SIGINT" });
    this.isRunning = true;
};
/**
 * Stops video recorder.
 *
 * @method
 * @throws {Error} if video recorder isn't started yet
 */
VideoRecorder.prototype.stop = function () {
    if (!this.isRunning) return;

    return new Promise((resolve, reject) => {
        this._process.once("exit", (code, signal) => {
            LOG.debug(`${this._recordCmd} was stopped with code ${code} and signal ${signal}`);
            this.isRunning = false;
            resolve();
        });
        this._process.once("error", reject);
        var result = this._process.kill("SIGINT");
        if (!result) reject(new Error(`Oops! Can't kill ${this._recordCmd}`));
    });
};

module.exports = VideoRecorder;