From 52c0c3aff5962665949d87d1722b878a1d7ffb1a Mon Sep 17 00:00:00 2001 From: thzxx Date: Thu, 18 Jun 2026 11:42:42 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=A7=86=E9=A2=91=E6=8F=90=E5=8F=96?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BC=80=E5=A7=8B=E6=97=A5=E5=BF=97=E5=92=8C?= =?UTF-8?q?=E5=AE=9E=E6=97=B6=E8=BF=9B=E5=BA=A6=E6=8E=A8=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 提取开始时发送 '开始提取视频帧' 日志 - ffmpeg 执行中每秒解析 stderr 的 frame=N 输出并推送进度 - 完成日志从 info 改为 success 级别 --- src/main/ipc.ts | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/main/ipc.ts b/src/main/ipc.ts index 26ac129..21dff9b 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -544,9 +544,14 @@ function extractVideoFrames(filePath: string, maxFrames: number, maxWidth: numbe try { await fs.promises.mkdir(tmpDir, { recursive: true }); - // ffmpeg 提取帧:1fps,同时捕获 stderr 解析视频信息 + const fileName = path.basename(filePath); + sendLog('info', `🎬 开始提取视频帧: 1fps`, fileName); + + // ffmpeg 提取帧:1fps,同时捕获 stderr 解析进度和视频信息 const outPattern = path.join(tmpDir, 'frame_%04d.jpg'); let ffmpegStderr = ''; + let lastProgressFrame = 0; + let lastProgressTime = Date.now(); await new Promise((ffResolve, ffReject) => { const child = execFile(getFFmpegPath(), [ @@ -556,6 +561,7 @@ function extractVideoFrames(filePath: string, maxFrames: number, maxWidth: numbe '-q:v', '3', '-frames:v', String(maxFrames), '-threads', '2', + '-progress', 'pipe:1', // 结构化进度输出到 stdout outPattern ], { timeout: 120_000 }, (err) => { if (err) { ffReject(new Error(`ffmpeg 执行失败: ${err.message}`)); return; } @@ -563,6 +569,17 @@ function extractVideoFrames(filePath: string, maxFrames: number, maxWidth: numbe }); child.stderr?.on('data', (data: Buffer) => { ffmpegStderr += data.toString(); + // 实时解析进度 frame=\d+ + const progressMatch = ffmpegStderr.match(/frame=\s*(\d+)/g); + if (progressMatch) { + const last = progressMatch[progressMatch.length - 1]; + const currentFrame = parseInt(last.replace(/\D/g, '')); + if (currentFrame > lastProgressFrame && Date.now() - lastProgressTime > 1000) { + lastProgressFrame = currentFrame; + lastProgressTime = Date.now(); + sendLog('debug', `🎬 提取进度`, `${currentFrame} 帧`); + } + } }); }); @@ -601,7 +618,7 @@ function extractVideoFrames(filePath: string, maxFrames: number, maxWidth: numbe await fs.promises.rm(tmpDir, { recursive: true, force: true }); - sendLog('info', `🎬 视频帧提取完成: 1fps`, `${filePath} → ${frames.length} 帧 / ${videoInfo.duration.toFixed(1)}s (${videoInfo.width}x${videoInfo.height})`); + sendLog('success', `🎬 视频帧提取完成: 1fps`, `${filePath} → ${frames.length} 帧 / ${videoInfo.duration.toFixed(1)}s (${videoInfo.width}x${videoInfo.height})`); resolve({ success: true, frames, videoInfo }); } catch (err) {