如何使用Node.js与FFmpeg生成视频预览缩略图及对应WEBVTT索引文件
实现方案
前置依赖
你需要先安装两个核心依赖:
- 系统环境安装FFmpeg(确保命令行可调用)
- Node.js项目安装
fluent-ffmpeg库,用于调用FFmpeg获取视频元数据、执行命令
npm install fluent-ffmpeg
核心实现逻辑
你当前用的FFmpeg命令是每60帧抽1张缩略图,按4列8行拼接成雪碧图,生成WEBVTT的逻辑可以和抽帧参数完全对齐,步骤如下:
步骤1:获取视频基础元数据
首先通过ffprobe读取视频的帧率、总时长,用于计算抽帧间隔和总抽帧数量。
步骤2:固定参数对齐你的FFmpeg命令
你现在的命令对应固定参数如下,可根据自己的抽帧规则调整:
- 抽帧间隔帧:60(对应
not(mod(n,60))) - 雪碧图行列:4列、8行(对应
tile=layout=4x8) - 单张缩略图宽度:240(对应
scale=240:-1)
步骤3:完整代码示例
const ffmpeg = require('fluent-ffmpeg'); const fs = require('fs'); // 配置参数,和你的FFmpeg命令保持一致 const CONFIG = { videoPath: './input.mp4', // 输入视频路径 spritePath: 'outputfile.jpg', // 生成的雪碧图路径 vttOutputPath: './thumbnails.vtt', // 输出VTT路径 frameInterval: 60, // 每N帧抽一张 tileCols: 4, // 雪碧图列数 tileRows: 8, // 雪碧图行数 thumbWidth: 240 // 单张缩略图宽度 }; // 秒转成WEBVTT需要的HH:MM:SS.mmm格式 function formatTime(seconds) { const h = String(Math.floor(seconds / 3600)).padStart(2, '0'); const m = String(Math.floor((seconds % 3600) / 60)).padStart(2, '0'); const s = String(Math.floor(seconds % 60)).padStart(2, '0'); const ms = String(Math.floor((seconds % 1) * 1000)).padStart(3, '0'); return `${h}:${m}:${s}.${ms}`; } async function generateVtt() { // 1. 获取视频元数据 const meta = await new Promise((resolve, reject) => { ffmpeg.ffprobe(CONFIG.videoPath, (err, data) => { if (err) reject(err); else resolve(data); }); }); const videoStream = meta.streams.find(s => s.codec_type === 'video'); const fps = eval(videoStream.r_frame_rate); // 帧率转数字,比如24000/1001转换为对应数值 const duration = meta.format.duration; // 视频总时长(秒) const interval = CONFIG.frameInterval / fps; // 每张缩略图对应的时间间隔(秒) const thumbHeight = Math.round(CONFIG.thumbWidth * videoStream.height / videoStream.width); // 按比例计算缩略图高度 const totalThumbs = Math.min(Math.ceil(duration / interval), CONFIG.tileCols * CONFIG.tileRows); // 总缩略图数量,不超过单页雪碧图最大容量 // 2. 生成VTT内容 let vttContent = 'WEBVTT\n\n'; for (let i = 0; i < totalThumbs; i++) { const startTime = i * interval; const endTime = Math.min((i + 1) * interval, duration); const col = i % CONFIG.tileCols; const row = Math.floor(i / CONFIG.tileCols); const x = col * CONFIG.thumbWidth; const y = row * thumbHeight; vttContent += `${formatTime(startTime)} --> ${formatTime(endTime)}\n`; vttContent += `${CONFIG.spritePath}#xywh=${x},${y},${CONFIG.thumbWidth},${thumbHeight}\n\n`; } // 3. 写入VTT文件 fs.writeFileSync(CONFIG.vttOutputPath, vttContent.trim()); console.log('WEBVTT文件生成完成'); } generateVtt().catch(console.error);
注意事项
- 如果视频时长超过单页雪碧图可容纳的总时长(即
CONFIG.tileCols * CONFIG.tileRows * interval),你需要修改FFmpeg命令生成多页雪碧图,同时在生成VTT时按页切换对应雪碧图文件名即可。 - 如果你修改了抽帧规则、雪碧图行列数、缩略图尺寸,只要同步修改
CONFIG里的对应参数即可,不需要调整核心逻辑。
内容的提问来源于stack exchange,提问作者The Dead Man
相关产品推荐
相关产品推荐

