From 7b23f24b24325354f32d3a5cb636ccaf2e39a186 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 19 Dec 2023 08:23:38 +0100 Subject: [PATCH] Fix thumbnail generation when on bad input seek --- packages/ffmpeg/src/ffmpeg-command-wrapper.ts | 4 +++ packages/ffmpeg/src/ffmpeg-images.ts | 33 ++++++++++++++++--- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/packages/ffmpeg/src/ffmpeg-command-wrapper.ts b/packages/ffmpeg/src/ffmpeg-command-wrapper.ts index 647ee3996..4a3b04bf1 100644 --- a/packages/ffmpeg/src/ffmpeg-command-wrapper.ts +++ b/packages/ffmpeg/src/ffmpeg-command-wrapper.ts @@ -79,6 +79,10 @@ export class FFmpegCommandWrapper { // --------------------------------------------------------------------------- + resetCommand () { + this.command = undefined + } + buildCommand (input: string) { if (this.command) throw new Error('Command is already built') diff --git a/packages/ffmpeg/src/ffmpeg-images.ts b/packages/ffmpeg/src/ffmpeg-images.ts index 739c96141..f9f352e3c 100644 --- a/packages/ffmpeg/src/ffmpeg-images.ts +++ b/packages/ffmpeg/src/ffmpeg-images.ts @@ -36,26 +36,51 @@ export class FFmpegImage { return this.commandWrapper.runCommand() } + // --------------------------------------------------------------------------- + async generateThumbnailFromVideo (options: { fromPath: string output: string framesToAnalyze: number ffprobe?: FfprobeData }) { - const { fromPath, output, ffprobe, framesToAnalyze } = options + const { fromPath, ffprobe } = options let duration = await getVideoStreamDuration(fromPath, ffprobe) if (isNaN(duration)) duration = 0 - this.commandWrapper.buildCommand(fromPath) + this.buildGenerateThumbnailFromVideo(options) .seekInput(duration / 2) + + try { + return await this.commandWrapper.runCommand() + } catch (err) { + this.commandWrapper.debugLog('Cannot generate thumbnail from video using seek input, fallback to no seek', { err }) + + this.commandWrapper.resetCommand() + + this.buildGenerateThumbnailFromVideo(options) + + return this.commandWrapper.runCommand() + } + } + + private buildGenerateThumbnailFromVideo (options: { + fromPath: string + output: string + framesToAnalyze: number + }) { + const { fromPath, output, framesToAnalyze } = options + + return this.commandWrapper.buildCommand(fromPath) .videoFilter('thumbnail=' + framesToAnalyze) .outputOption('-frames:v 1') + .outputOption('-abort_on empty_output') .output(output) - - return this.commandWrapper.runCommand() } + // --------------------------------------------------------------------------- + async generateStoryboardFromVideo (options: { path: string destination: string