@deepauto/ffcreatorlite
Version:
FFCreatorLite is a lightweight and flexible short video production library
129 lines (111 loc) • 3.62 kB
JavaScript
'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;