feat: experimental video preview generator in webm form

This commit is contained in:
Zephyrrus 2020-07-02 20:13:05 +03:00
parent a790d7749e
commit 24157dd1b9
2 changed files with 80 additions and 5 deletions

View File

@ -0,0 +1,74 @@
const ffmpeg = require('fluent-ffmpeg');
const probe = require('ffmpeg-probe');
const path = require('path');
const noop = () => {};
module.exports = async opts => {
const {
log = noop,
// general output options
quality = 2,
width,
height,
input,
output,
numFrames,
numFramesPercent = 0.05
} = opts;
const info = await probe(input);
// const numFramesTotal = parseInt(info.streams[0].nb_frames, 10);
const { avg_frame_rate: avgFrameRate, duration } = info.streams[0];
const [frames, time] = avgFrameRate.split('/').map(e => parseInt(e, 10));
const numFramesTotal = (frames / time) * duration;
let numFramesToCapture = numFrames || numFramesPercent * numFramesTotal;
numFramesToCapture = Math.max(1, Math.min(numFramesTotal, numFramesToCapture)) | 0;
const nthFrame = (numFramesTotal / numFramesToCapture) | 0;
const result = {
output,
numFrames: numFramesToCapture
};
await new Promise((resolve, reject) => {
let scale = null;
if (width && height) {
result.width = width | 0;
result.height = height | 0;
scale = `scale=${width}:${height}`;
} else if (width) {
result.width = width | 0;
result.height = ((info.height * width) / info.width) | 0;
scale = `scale=${width}:-1`;
} else if (height) {
result.height = height | 0;
result.width = ((info.width * height) / info.height) | 0;
scale = `scale=-1:${height}`;
} else {
result.width = info.width;
result.height = info.height;
}
const filter = [`select=not(mod(n\\,${nthFrame}))`, scale].filter(Boolean).join(',');
ffmpeg(input)
.outputOptions(['-vsync', 'vfr'])
.outputOptions(['-q:v', quality, '-vf', filter])
.outputOption('-an')
.outputFormat('webm')
.output(output)
.on('start', cmd => log && log({ cmd }))
.on('end', () => resolve())
.on('error', err => reject(err))
.run();
});
return result;
};

View File

@ -2,7 +2,7 @@ const jetpack = require('fs-jetpack');
const path = require('path');
const sharp = require('sharp');
const ffmpeg = require('fluent-ffmpeg');
const generatePreview = require('ffmpeg-generate-video-preview');
const previewUtil = require('./PreviewUtil');
const log = require('./Log');
@ -17,7 +17,7 @@ class ThumbUtil {
static generateThumbnails(filename) {
const ext = path.extname(filename).toLowerCase();
const output = `${filename.slice(0, -ext.length)}.png`;
const previewOutput = `${filename.slice(0, -ext.length)}.gif`;
const previewOutput = `${filename.slice(0, -ext.length)}.webm`;
if (ThumbUtil.imageExtensions.includes(ext)) return this.generateThumbnailForImage(filename, output);
if (ThumbUtil.videoExtensions.includes(ext)) return this.generateThumbnailForVideo(filename, previewOutput);
@ -38,7 +38,7 @@ class ThumbUtil {
.toFile(path.join(ThumbUtil.thumbPath, output));
}
static generateThumbnailForVideo(filename, output) {
static async generateThumbnailForVideo(filename, output) {
const filePath = path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, filename);
ffmpeg(filePath)
@ -60,10 +60,11 @@ class ThumbUtil {
.on('error', error => log.error(error.message));
try {
generatePreview({
await previewUtil({
input: filePath,
width: 150,
output: path.join(ThumbUtil.videoPreviewPath, output)
output: path.join(ThumbUtil.videoPreviewPath, output),
log: console.log
});
} catch (e) {
console.error(e);