视频 9 宫格预览

contact sheet/等距抽帧合成预览图

413 次访问
VIDEO 9-GRID PREVIEW

视频 9 宫格预览

均匀截取 N 帧拼接为预览图 · Canvas 本地渲染

🎞️
点击 / 拖拽视频

关于本工具

了解工具定位 · 使用场景 · 对比优势

使用场景

🎬

视频素材速览

视频剪辑师或自媒体创作者面对大量长视频素材,逐一拖入播放器查看费时费力。本工具自动等距抽帧合成 9 宫格预览图,一眼看清每个视频的关键画面、构图和内容转折点,快速定位需要的片段,将素材筛选时间从半小时缩短到几分钟。

🎞️

课程内容概览

在线教育平台运营者需要为数十节录播课生成封面或内容索引。本工具对每节课视频等距提取 9 帧,合成一张预览图,直观展示课程从引入到总结的完整知识脉络。学生可凭预览图判断课程难度和节奏,运营者也能批量生成标准化的课程缩略图。

📹

监控录像检索

安防管理员需从 24 小时监控录像中查找特定事件,逐秒回放效率极低。本工具将长视频压缩为 9 帧时间轴预览,异常画面(如人员走动、车辆进出)在抽帧中一目了然。管理员仅需浏览几张预览图就能锁定可疑时间点,大幅提升检索效率。

🛒

商品展示优化

电商运营需要为产品视频制作详情页的“视频看点”模块,手动截图拼接耗时且不统一。本工具自动从产品演示视频中等距抽取 9 帧,合成一张展示产品外观、功能、使用场景的完整预览图,可直接用于商品主图或详情页,提升用户浏览体验。

📱

短视频封面制作

短视频创作者发布作品前,常需从视频中挑选一张最具吸引力的帧作为封面。本工具提供 9 张等距抽帧结果,创作者无需手动拖动进度条寻找精彩瞬间,直接从中选择构图最优、信息最丰富的画面作为封面,提高视频点击率。

对比矩阵本工具 vs 竞品 vs 传统方法

维度本工具竞品 A传统方法
数据隐私纯浏览器/WASM 处理,视频不上传服务器上传到服务器处理依赖工作人员操作,存在数据泄露风险
处理速度秒级,取决于本地设备性能取决于服务器负载和网络传输速度数小时,需人工截取和排版
离线可用支持,完全离线运行不支持,必须联网支持,但需要专业软件和操作技能
费用免费,无使用次数限制免费/付费,通常有次数或功能限制需购买专业软件(如 Adobe Premiere)或付费外包
操作门槛上传视频即生成,无学习成本需注册账号,上传后等待需掌握视频剪辑和图像处理软件
输出格式PNG/JPG 图片,可自定义网格行列数PNG/JPG 图片,部分支持自定义取决于软件,通常为图片格式
视频格式支持主流格式(MP4, MOV, AVI, WebM 等)主流格式,部分限制文件大小支持所有格式,但需解码器
批量处理单次单视频部分支持批量上传可批量处理,但操作繁琐

使用指南

上手步骤 · 输入输出 · 避坑提示

输入输出示例7 个典型场景,覆盖常规、边界与易错

输入输出说明
https://example.com/video.mp4生成一张 3x3 的预览图,包含 9 个等距抽帧画面,每个画面带时间戳水印典型场景:在线视频 URL 直接输入
本地文件上传(10 秒短视频)生成一张 3x3 的预览图,9 帧均匀分布在 0-10 秒区间,每帧间隔约 1.1 秒典型场景:短时长视频,抽帧间隔自动适配
本地文件上传(2 小时长视频)生成一张 3x3 的预览图,9 帧均匀分布在 0-7200 秒区间,每帧间隔约 800 秒边界 case:长视频仍只抽 9 帧,帧间距大
视频分辨率 1920x1080预览图总尺寸 1920x1080(原分辨率),每个小格 640x360,排列为 3x3典型场景:高清视频,预览图保持原比例
视频分辨率 320x240预览图总尺寸 320x240(原分辨率),每个小格约 106x80,排列为 3x3边界 case:低分辨率视频,小格可能模糊
视频时长不足 1 秒(0.5 秒)生成一张 3x3 的预览图,9 帧全部取自视频唯一可用的关键帧(重复帧)易错 case:超短视频,9 帧可能完全相同
视频仅 1 帧(静态图片格式伪装为视频)生成一张 3x3 的预览图,9 格全部为同一帧画面易错 case:用户误传静态图片,工具仍输出 9 宫格

常见错误对照8 个常踩的坑 · 错误 → 修复

1. 输入非视频文件(图片/音频)

错误
上传一个 .jpg 或 .mp3 文件
修复
上传 .mp4 / .mov / .avi / .mkv 等视频文件

工具底层用 FFmpeg 解码视频流,图片和音频文件没有视频帧序列,抽帧会失败或输出空白

2. 视频时长太短,抽不出9帧

错误
上传一段 0.5 秒的视频
修复
视频时长至少 1 秒以上(推荐 ≥ 3 秒)

等距抽帧算法将时长除以 9 得到帧间隔;若时长 < 1 秒,帧间隔 < 0.11 秒,部分编码器可能输出重复帧或黑帧

3. 帧数参数填了小数或负数

错误
frames=8.5 或 frames=-3
修复
frames=9(整数,1~99)

抽帧数量必须是正整数;小数会被 FFmpeg 截断取整,负数直接导致参数解析错误

4. 输出分辨率超过原始视频尺寸

错误
width=1920, height=1080,但原始视频是 640×480
修复
保持宽高比,宽度不超过原始宽度(如 640×480 视频设 width=640)

FFmpeg 可以放大但会严重模糊;工具未做超分辨率,放大后画质劣化明显

5. 直接上传超大文件(>500MB)

错误
上传一个 2GB 的 4K 视频
修复
先压缩或裁剪视频,或使用浏览器端 WASM 模式(受浏览器内存限制)

后端 Go 处理有内存上限;超大文件会导致 OOM 或超时。浏览器 WASM 模式受 WebAssembly 内存限制(默认 256MB~2GB)

6. 使用不支持的编码格式(如 VP9 / AV1)

错误
上传一个 .webm 文件(VP9 编码)
修复
使用 H.264 / H.265 编码的 .mp4 文件

FFmpeg 支持解码 VP9/AV1,但浏览器原生解码器可能不支持;后端处理无问题,但浏览器预览可能黑屏

7. 期望输出视频而非图片拼接

错误
以为工具会生成一段 9 帧的 GIF 或短视频
修复
工具输出一张拼接了 9 帧缩略图的静态 PNG/JPG 图片

contact sheet 是静态拼图,不是动画;若需要动态预览,请使用 GIF 或视频截取工具

8. 忽略帧间隔不均匀导致内容丢失

错误
视频内容变化极快(如 1 秒内场景切换 10 次),只抽 9 帧
修复
增加抽帧数量(如 18 帧)或分段处理

等距抽帧固定间隔,快速变化的内容可能漏掉关键场景;增加帧数可提高采样密度

工作原理

公式推导 · 流程图解 · 依据出处

核心公式

W = ceil(T / (R × 9))

变量说明

  • W — 合成预览图的总宽度(像素)
  • T — 视频总帧数(总时长 × 帧率)
  • R — 抽帧间隔(每 R 帧取一帧)
  • 9 — 固定值,9 宫格每行 3 列共 9 格

示例

一段 30 秒视频,帧率 25fps,总帧数 T=750。设定抽帧间隔 R=10(每 10 帧取一帧),则抽得帧数 = 750/10=75 帧。9 宫格每格宽 100px,则 W = ceil(75 / 9) × 100 = 9 × 100 = 900px。最终输出 900×300px 的 3 行 3 列预览图。

适用范围

适用于等距抽帧合成 contact sheet 场景。当视频时长极短(<1秒)或抽帧间隔过大导致不足 9 帧时,工具会自动补黑帧或调整间隔,公式仅作基础布局计算。

原理图

上传视频MP4 / MOV / AVIFFmpeg 抽帧等距提取 9 帧(WASM 本地执行)合成 9 宫格3×3 排列 + 时间戳预览图下载输出选项PNG / JPG / WebP自定义列数 / 间隔输入参数抽帧数量(1-25)输出尺寸 / 质量处理流程解码 → 缩放 → 抽帧→ 拼图 → 编码输出① 选择视频文件② 浏览器内 FFmpeg 处理③ 生成并下载预览图
用户输入 本地处理 输出结果

开发者集成

3 种主流语言 · 复制即用

import subprocess
import json

# 使用 FFmpeg 生成 3x3 等距抽帧预览图(contact sheet)
# 输入:本地视频文件路径
# 输出:合成后的预览图文件

def generate_contact_sheet(video_path: str, output_path: str = "preview.jpg"):
    # 先获取视频总时长(秒)
    probe = subprocess.run([
        "ffprobe", "-v", "quiet", "-print_format", "json",
        "-show_format", video_path
    ], capture_output=True, text=True)
    info = json.loads(probe.stdout)
    duration = float(info["format"]["duration"])

    # 等距取 9 帧的时间点(0 到 duration 之间均匀分布)
    interval = duration / 10  # 留出首尾缓冲
    timestamps = [interval * (i + 1) for i in range(9)]

    # 用 select 滤镜按时间点抽帧,再 tile 合成 3x3
    filter_str = "+".join([f"eq(n,{int(t*25)})" for t in timestamps])
    filter_str = f"select='{filter_str}',setpts=N/FRAME_RATE/TB,tile=3x3"

    cmd = [
        "ffmpeg", "-i", video_path,
        "-vf", filter_str,
        "-frames:v", "1",
        "-q:v", "2",
        output_path
    ]
    subprocess.run(cmd, check=True)
    print(f"预览图已生成:{output_path}")

# 示例用法
generate_contact_sheet("input.mp4", "contact_sheet.jpg")
package main

import (
	"fmt"
	"os/exec"
	"strconv"
	"strings"
)

// 使用 FFmpeg 生成 3x3 视频预览图
// 输入:视频文件路径
// 输出:合成后的 JPG 文件
func generateContactSheet(videoPath, outputPath string) error {
	// 1. 用 ffprobe 获取视频时长
	probe := exec.Command("ffprobe", "-v", "quiet", "-print_format", "json", "-show_format", videoPath)
	out, err := probe.Output()
	if err != nil {
		return fmt.Errorf("ffprobe 失败: %w", err)
	}

	// 简单解析 JSON 获取 duration(生产环境建议用 encoding/json)
	durationStr := extractDuration(string(out))
	duration, _ := strconv.ParseFloat(durationStr, 64)

	// 2. 等距取 9 帧的时间点
	interval := duration / 10
	var timestamps []string
	for i := 1; i <= 9; i++ {
		t := interval * float64(i)
		timestamps = append(timestamps, fmt.Sprintf("%.2f", t))
	}

	// 3. 用 select 滤镜 + tile 合成
	selectExpr := "select='" + strings.Join(timestamps, "+") + "'"
	filter := fmt.Sprintf("%s,setpts=N/FRAME_RATE/TB,tile=3x3", selectExpr)

	cmd := exec.Command("ffmpeg", "-i", videoPath, "-vf", filter, "-frames:v", "1", "-q:v", "2", outputPath)
	return cmd.Run()
}

// 辅助:从 JSON 中提取 duration 字段(简化版)
func extractDuration(jsonStr string) string {
	start := strings.Index(jsonStr, `"duration":"`)
	if start == -1 {
		return "0"
	}
	start += len(`"duration":"`)
	end := strings.Index(jsonStr[start:], `"`)
	return jsonStr[start : start+end]
}

func main() {
	err := generateContactSheet("input.mp4", "preview.jpg")
	if err != nil {
		fmt.Println("错误:", err)
		return
	}
	fmt.Println("预览图已生成: preview.jpg")
}
// 浏览器端纯 JS 实现:用 Canvas 对视频等距抽帧合成 3x3 预览图
// 注意:需用户上传视频文件或提供 video 元素

async function generateContactSheet(videoFile) {
  // 1. 加载视频到 video 元素
  const video = document.createElement('video');
  video.src = URL.createObjectURL(videoFile);
  await video.play();

  // 2. 获取视频时长,计算 9 个等距时间点
  const duration = video.duration;
  const interval = duration / 10;
  const timestamps = Array.from({ length: 9 }, (_, i) => interval * (i + 1));

  // 3. 创建 Canvas(3x3 网格,每格 160x90)
  const cellW = 160, cellH = 90;
  const canvas = document.createElement('canvas');
  canvas.width = cellW * 3;
  canvas.height = cellH * 3;
  const ctx = canvas.getContext('2d');

  // 4. 逐帧 seek 并绘制到对应位置
  for (let i = 0; i < timestamps.length; i++) {
    video.currentTime = timestamps[i];
    await new Promise(resolve => video.onseeked = resolve);
    
    const col = i % 3;
    const row = Math.floor(i / 3);
    ctx.drawImage(video, col * cellW, row * cellH, cellW, cellH);
  }

  // 5. 导出为图片
  const dataUrl = canvas.toDataURL('image/jpeg', 0.85);
  video.pause();
  URL.revokeObjectURL(video.src);
  
  return dataUrl; // 可直接用于 <img src="..."> 或下载
}

// 示例:在文件上传 change 事件中使用
// document.querySelector('input[type="file"]').onchange = async (e) => {
//   const url = await generateContactSheet(e.target.files[0]);
//   document.querySelector('img').src = url;
// };

常见问题

7 个高频疑问

这个视频9宫格预览工具怎么用?需要上传整个视频吗?
不需要上传整个视频。工具基于FFmpeg在服务端处理,只需粘贴视频的直链地址(支持.mp4、.webm、.mov等常见格式),点击生成即可。等距抽帧后合成一张9宫格预览图。视频越长,处理时间越久,建议视频时长控制在30分钟以内。如果视频地址需要登录才能访问,工具会无法下载,请先确保链接可公开访问。
生成的9宫格图片是按什么时间点抽帧的?能保证覆盖视频全程吗?
工具将视频总时长均匀分成9段,分别取每段中间位置的一帧(首帧和末帧不剔除)。例如一个90秒的视频,每10秒取一帧,分别在第5、15、25……85秒处抽帧。这样能保证9宫格覆盖视频从开头到结尾的完整时间轴,避免集中在开头或结尾。如果视频时长不足9秒,则按实际帧数生成,不足9格。
为什么生成的预览图里有些画面是黑的或模糊的?
黑帧常见于视频开头或结尾的淡入淡出、黑场过渡段落——FFmpeg抽帧时如果刚好落在这些位置,就会截到纯黑画面。模糊则是因为视频本身分辨率低(如480p以下)或抽帧时遇到运动模糊严重的镜头。建议先确认视频源是否清晰,如果频繁出现黑帧,可以检查视频是否存在大量黑场片段。工具无法自动跳过黑帧,如需更精准的缩略图,建议手动选择关键帧截图。
这个工具和直接截图或用播放器预览相比,有什么优势?
手动截图需要播放、暂停、截取、拼接,操作繁琐且时间点不统一;播放器预览(如YouTube进度条缩略图)依赖平台方生成。本工具一键生成等距9宫格,保证时间间隔均匀,适合快速浏览视频内容结构(如课程章节、活动录像)。劣势是无法自定义截取位置,如果视频重点集中在某一段,均匀抽帧可能漏掉关键内容。
上传的视频会被保存到服务器吗?隐私安全吗?
不会保存。工具通过FFmpeg在服务端临时下载视频文件,处理完成后立即删除原始视频和生成的预览图,服务器不保留任何副本。处理过程中视频流仅占用临时内存和磁盘缓存,关闭页面或刷新后缓存自动清理。如果视频包含敏感内容,建议先确认链接是否为临时分享链接,或使用短时长片段测试。
支持哪些视频格式?有没有文件大小或时长限制?
支持主流格式:MP4、MOV、WebM、AVI、FLV、MKV等。时长建议不超过30分钟,文件大小建议不超过500MB(超过可能因服务器超时或内存不足而失败)。如果视频是H.265编码(HEVC),部分老旧浏览器可能无法直接预览,但工具后端仍可正常处理。不支持m3u8直播流或需要认证的私有链接。
生成的9宫格图能下载吗?分辨率是多少?
可以下载。预览图生成后页面会显示下载按钮,点击即可保存为PNG格式。每格缩略图的分辨率取决于原视频尺寸,工具会等比缩放至宽度约320像素(原视频宽度超过320则缩放,否则保持原尺寸)。9宫格整体宽度约为960像素(3列×320),高度根据视频比例自适应。如果原视频是竖屏(如手机拍摄),9宫格会按竖屏比例排列。
选择 打开 +新窗口 esc关闭