From 1ea77ebc6c41cf71a68448e14119d2da636259c4 Mon Sep 17 00:00:00 2001 From: kimsible Date: Sat, 21 Nov 2020 03:38:23 +0100 Subject: [PATCH] Add ffmpeg GIF process --- server/helpers/ffmpeg-utils.ts | 35 ++++++++++++++++++++++++++++++++++ server/helpers/image-utils.ts | 10 +++++++++- server/lib/avatar.ts | 8 +------- 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts index 1d610eff2452..4fa613633bac 100644 --- a/server/helpers/ffmpeg-utils.ts +++ b/server/helpers/ffmpeg-utils.ts @@ -355,6 +355,40 @@ function convertWebPToJPG (path: string, destination: string): Promise { }) } +function processGIF ( + path: string, + destination: string, + newSize: { width: number, height: number }, + keepOriginal = false +): Promise { + return new Promise(async (res, rej) => { + if (path === destination) { + throw new Error('FFmpeg needs an input path different that the output path.') + } + + logger.debug('Processing gif %s to %s.', path, destination) + + try { + const command = ffmpeg(path) + .fps(20) + .size(`${newSize.width}x${newSize.height}`) + .output(destination) + + command.on('error', (err, stdout, stderr) => { + logger.error('Error in ffmpeg gif resizing process.', { stdout, stderr }) + return rej(err) + }) + .on('end', async () => { + if (keepOriginal !== true) await remove(path) + res() + }) + .run() + } catch (err) { + return rej(err) + } + }) +} + function runLiveTranscoding (rtmpUrl: string, outPath: string, resolutions: number[], fps, deleteSegments: boolean) { const command = getFFmpeg(rtmpUrl) command.inputOption('-fflags nobuffer') @@ -474,6 +508,7 @@ export { getAudioStreamCodec, runLiveMuxing, convertWebPToJPG, + processGIF, getVideoStreamSize, getVideoFileResolution, getMetadataFromFile, diff --git a/server/helpers/image-utils.ts b/server/helpers/image-utils.ts index 5f254a7aaf04..fdf06e848b86 100644 --- a/server/helpers/image-utils.ts +++ b/server/helpers/image-utils.ts @@ -1,5 +1,6 @@ +import { extname } from 'path' import { remove, rename } from 'fs-extra' -import { convertWebPToJPG } from './ffmpeg-utils' +import { convertWebPToJPG, processGIF } from './ffmpeg-utils' import { logger } from './logger' const Jimp = require('jimp') @@ -10,6 +11,13 @@ async function processImage ( newSize: { width: number, height: number }, keepOriginal = false ) { + const extension = extname(path) + + // Use FFmpeg to process GIF + if (extension === '.gif') { + return processGIF(path, destination, newSize, keepOriginal) + } + if (path === destination) { throw new Error('Jimp needs an input path different that the output path.') } diff --git a/server/lib/avatar.ts b/server/lib/avatar.ts index 976ffef04ecb..15a27cc2b35f 100644 --- a/server/lib/avatar.ts +++ b/server/lib/avatar.ts @@ -1,5 +1,4 @@ import 'multer' -import { move } from 'fs-extra' import { sendUpdateActor } from './activitypub/send' import { AVATARS_SIZE, LRU_CACHE, QUEUE_CONCURRENCY } from '../initializers/constants' import { updateActorAvatarInstance } from './activitypub/actor' @@ -22,12 +21,7 @@ async function updateActorAvatarFile ( const avatarName = uuidv4() + extension const destination = join(CONFIG.STORAGE.AVATARS_DIR, avatarName) - // For gif do not resize, just move - if (extension === '.gif') { - await move(avatarPhysicalFile.path, destination) - } else { - await processImage(avatarPhysicalFile.path, destination, AVATARS_SIZE) - } + await processImage(avatarPhysicalFile.path, destination, AVATARS_SIZE) return retryTransactionWrapper(() => { return sequelizeTypescript.transaction(async t => {