UNPKG

wibbitz-puppeteer-screen-recorder

Version:

A puppeteer Plugin that uses the native chrome devtool protocol for capturing video frame by frame. Also supports an option to follow pages that are opened by the current page object

185 lines 14.4 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); const events_1 = require("events"); const stream_1 = require("stream"); const fluent_ffmpeg_1 = __importStar(require("fluent-ffmpeg")); const StreamTypes_1 = require("./StreamTypes"); /** * @ignore */ class FFMPEGStreamWriter extends events_1.EventEmitter { constructor(savePath, options) { super(); this.streamBatchSize = 300; this.screencastFrames = []; this.duration = '00:00:00:00'; this.status = StreamTypes_1.VIDEO_WRITE_STATUS.NOT_STARTED; this.videoMediatorStream = new stream_1.PassThrough(); if (options) { this.options = options; } this.configureVideoFile(savePath); console.log(`Successfully created new FFMPEGStreamWriter object with the following options: ${JSON.stringify(options)} and the following savePath: ${JSON.stringify(savePath)}`); } get videoFrameSize() { const { width, height } = this.options.videoFrame; return width !== null && height !== null ? `${width}x${height}` : '100%'; } getFFMPEGPath() { if (this.options.ffmpeg_Path) { return this.options.ffmpeg_Path; } try { // eslint-disable-next-line @typescript-eslint/no-var-requires const ffmpeg = require('@ffmpeg-installer/ffmpeg'); if (ffmpeg.path) { return ffmpeg.path; } return null; } catch (e) { return null; } } configureFFMPEGPath() { const ffmpegPath = this.getFFMPEGPath(); if (!ffmpegPath) { throw new Error('Missing path for FFmpeg, \n Set the FFMPEG_PATH env variable'); } fluent_ffmpeg_1.setFfmpegPath(ffmpegPath); console.log(`Successfully set FFMPEG path to: ${ffmpegPath}`); } configureVideoFile(savePath) { this.configureFFMPEGPath(); this.writerPromise = new Promise((resolve) => { fluent_ffmpeg_1.default({ source: this.videoMediatorStream, priority: 20 }) .videoCodec('libvpx-vp9') .size(this.videoFrameSize) .aspect(this.options.aspectRatio || '4:3') .inputFormat('image2pipe') .inputFPS(this.options.fps) .outputFPS(this.options.fps) .outputOptions('-b:v 2M') // .outputOptions('-pix_fmt +') .on('progress', (progressDetails) => { this.duration = progressDetails.timemark; }) .on('error', (e) => { this.handleWriteStreamError(e.message); resolve(false); }) .on('end', () => resolve(true)) .save(savePath); }); } handleWriteStreamError(errorMessage) { this.emit('videoStreamWriterError', errorMessage); if (this.status !== StreamTypes_1.VIDEO_WRITE_STATUS.IN_PROGRESS && errorMessage.includes('pipe:0: End of file')) { return; } return console.error(`Error unable to capture video stream: ${errorMessage}`); } findVacantIndexInScreencastFrames(timestamp) { console.log(`Searching for a vacant index in the frame array...`); if (this.screencastFrames.length === 0) { return 0; } let i; let frame; for (i = this.screencastFrames.length - 1; i >= 0; i--) { frame = this.screencastFrames[i]; if (timestamp > frame.timestamp) { break; } } console.log(`Successfully found a vacant index in the frames array: [${i + 1}]`); return i + 1; } insert(frame) { console.log(`About to insert new frame to frame array. Current array length is: [${this.screencastFrames.length}]`); if (this.screencastFrames.length === this.streamBatchSize) { console.log(`Writing the first half of the frames to ffmpeg`); const numberOfFramesToSplice = Math.floor(this.streamBatchSize / 2); // const numberOfFramesToSplice = this.streamBatchSize; const framesToProcess = this.screencastFrames.splice(0, numberOfFramesToSplice); this.processFramesAndWrite(framesToProcess); } const insertionIndex = this.findVacantIndexInScreencastFrames(frame.timestamp); if (insertionIndex === this.screencastFrames.length) { // if end of frames array this.screencastFrames.push(frame); console.log(`Successfully pushed new frame to END of frames array at index [${insertionIndex}]`); } else { this.screencastFrames.splice(insertionIndex, 0, frame); console.log(`Successfully pushed new frame to MIDDLE of frames array at index [${insertionIndex}]`); } } trimFrames(frameList) { if (!this.lastProcessedFrame) { this.lastProcessedFrame = frameList[0]; } return frameList.map((currentFrame) => { const duration = currentFrame.timestamp - this.lastProcessedFrame.timestamp; this.lastProcessedFrame = currentFrame; return Object.assign(Object.assign({}, currentFrame), { duration }); }); } processFramesAndWrite(frames) { const processedFrames = this.trimFrames(frames); processedFrames.forEach(({ blob }) => { this.write(blob); }); console.log(`Successfully finished writing all frames to ffmpeg`); } write(data) { this.status = StreamTypes_1.VIDEO_WRITE_STATUS.IN_PROGRESS; this.videoMediatorStream.write(data); // const NUMBER_OF_FPS = Math.max( // Math.floor(durationSeconds * this.options.fps), // 1 // ); // // for (let i = 0; i < NUMBER_OF_FPS; i++) { // this.videoMediatorStream.write(data); // } } drainFrames() { this.processFramesAndWrite(this.screencastFrames); this.screencastFrames = []; if (!this.lastProcessedFrame) return; this.write(this.lastProcessedFrame.blob); } stop() { if (this.status === StreamTypes_1.VIDEO_WRITE_STATUS.COMPLETED) { return this.writerPromise; } this.drainFrames(); this.videoMediatorStream.end(); this.status = StreamTypes_1.VIDEO_WRITE_STATUS.COMPLETED; return this.writerPromise; } } exports.default = FFMPEGStreamWriter; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRkZNUEVHU3RyZWFtV3JpdGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi9GRk1QRUdTdHJlYW1Xcml0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsbUNBQXNDO0FBQ3RDLG1DQUFxQztBQUVyQywrREFBc0Q7QUFFdEQsK0NBSXVCO0FBRXZCOztHQUVHO0FBQ0gsTUFBcUIsa0JBQW1CLFNBQVEscUJBQVk7SUFZMUQsWUFBWSxRQUFnQixFQUFFLE9BQXNCO1FBQ2xELEtBQUssRUFBRSxDQUFDO1FBWk8sb0JBQWUsR0FBRyxHQUFHLENBQUM7UUFDL0IscUJBQWdCLEdBQUcsRUFBRSxDQUFDO1FBRXZCLGFBQVEsR0FBRyxhQUFhLENBQUM7UUFFeEIsV0FBTSxHQUFHLGdDQUFrQixDQUFDLFdBQVcsQ0FBQztRQUd4Qyx3QkFBbUIsR0FBZ0IsSUFBSSxvQkFBVyxFQUFFLENBQUM7UUFNM0QsSUFBSSxPQUFPLEVBQUU7WUFDWCxJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztTQUN4QjtRQUVELElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNsQyxPQUFPLENBQUMsR0FBRyxDQUFDLGtGQUFrRixJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxnQ0FBZ0MsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDbkwsQ0FBQztJQUVELElBQVksY0FBYztRQUN4QixNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDO1FBRWxELE9BQU8sS0FBSyxLQUFLLElBQUksSUFBSSxNQUFNLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLEtBQUssSUFBSSxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQzNFLENBQUM7SUFFTyxh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