UNPKG

@deepauto/ffcreatorlite

Version:

FFCreatorLite is a lightweight and flexible short video production library

129 lines (111 loc) 3.62 kB
'use strict'; /** * * @class */ const Utils = require('../utils/utils'); const FFmpegUtil = require('../utils/ffmpeg'); const FFCon = require('./cons'); const FFContext = require('../core/context'); const ffmpeg = require('fluent-ffmpeg'); const fse = require('fs-extra'); const path = require('path'); class FFAlbumScene extends FFCon { constructor(conf) { super({ type: 'scene', ...conf }); this.percent = 0; this.directory = ''; this.context = null; this.command = null; this.transition = null; this.pathId = Utils.uid(); this.time = conf.time || 3; this.imagePaths = conf.imagePaths || []; this.duration = this.imagePaths.length * this.time; this.fill = conf.fill; this.fillOffsetRandom = conf.fillOffsetRandom; } async start() { this.createNewCommand(); const output = this.addCommandOutputs(this.command); const conf = this.rootConf().conf; const command = this.command; // const command = ffmpeg(); FFmpegUtil.addDefaultOptions({ command, conf: this.rootConf(), audio: false }); const fileListFile = path.join(this.directory, `${Utils.uid()}.txt`); const fileListContent = this.imagePaths.map(image => `file '${image}'\nduration ${this.time}`).join('\n') + '\n'; fse.writeFileSync(fileListFile, fileListContent, { encoding: 'utf8' }); command.addInput(fileListFile); command.inputOptions(['-f', 'concat', '-safe', '0']); if (this.fill) { const num = this.fillOffsetRandom ? Math.floor(Math.random() * conf.width) : 0; command.videoFilters([ `scale=w=${conf.width}:h=${conf.height}:force_original_aspect_ratio=increase`, `crop=${conf.width}:${conf.height}:(iw-${conf.width + num})/2:(ih-${conf.height})/2`, ]); } else { command.videoFilters( `scale=w=${conf.width}:h=${conf.height}:force_original_aspect_ratio=decrease,pad=${conf.width}:${conf.height}:(ow-iw)/2:(oh-ih)/2`, ); } return await new Promise((resolve, reject) => { command .once('end', res => { return resolve(output); }) .once('error', reject); command.run(); }); } getFile() { return this.filepath; } getTotalFrames() { return this.rootConf().getVal('fps') * this.duration; } // about command createNewCommand() { const conf = this.rootConf(); const threads = conf.getVal('threads'); const command = FFmpegUtil.createCommand({ threads }); // command.setDuration(this.duration); this.command = command; this.context = new FFContext(); } addCommandOutputs(command) { let filepath; filepath = this.createFilepath(); command.output(filepath); return filepath; } createFilepath() { const { id, pathId } = this; const cacheDir = this.rootConf('cacheDir').replace(/[\/\\]$/, ''); const format = this.rootConf('cacheFormat'); const directory = path.join(cacheDir, pathId); const filepath = path.join(directory, `${id}.${format}`); // 确保(directory)存在 fse.ensureDirSync(directory); this.filepath = filepath; this.directory = directory; return filepath; } rootConf(key) { if (key) { return this.conf[key]; } return { conf: this.conf, getVal: k => this.conf[k], }; } async isReady() { return true; } destroy() { // 删除文件夹(this.directory); fse.removeSync(this.directory); } } module.exports = FFAlbumScene;