视频缩略图九宫格
把整段视频等间隔抽帧拼成一张网格预览图,每格标上时间点,导出一张 PNG。抓帧全部在本机完成,视频不会上传。
视频只在这台浏览器里解码,抓帧用画布完成,不上传也不联网。能读什么格式取决于浏览器自带的解码器,mp4(H.264)最稳。
使用说明
整张图的做法只有两步:先把整段时长等分成 N 格,在每格的中点定位播放器抓一帧;再把抓到的帧按行列画到一张大画布上,顺手在每格底部写时间点,最后编码成 PNG。时间点取中点而不是每格开头,是因为很多视频开头有半秒淡入、片尾是纯黑,章节切换处也可能夹一帧黑,取中点能稳定拿到有内容的画面;同时最后一格的中点永远落在时长之内(上界还会再收回 1 毫秒),避开了「定位到末尾之后取不到帧」的情况。
抓帧必须串行,一格一格来。每一格都是一次独立的随机定位:把播放器挪到指定时间,等解码器找到最近的关键帧解出来,再等这一帧真正上屏(seeked 只代表定位完成,画面未必已经交给合成器,所以还要等一次画面呈现回调)。单帧快的几十毫秒、慢的几百毫秒,所以格数直接决定等待时间:9 格通常几秒内完成,25 格要十几秒,关键帧稀疏的 webm 或从流媒体保存下来的文件会更久。同一个播放器并发定位只会互相打断,所以没有更快并行办法。
画布尺寸是算出来的,不是猜的:宽等于左右留白乘 2,加上列数乘格宽,再加上间距乘列数减 1;高同理,只是格高按视频的宽高比从格宽推出来,因此每格画面保持原始比例,不会被拉长压扁。改任何一项参数,结果区里的「导出尺寸」都会立刻更新。要留意浏览器的画布上限——Safari 单张画布约 1670 万像素,Chrome 宽松得多,但为了到处都能导出,超过上限时页面会直接提醒并拦下导出。
时间文字是「先铺半透明黑底条、再写白字」的写法,而不是直接把字画在画面上。原因是同一套样式要应付所有画面:雪景、白底幻灯片、亮色皮肤上白字会糊成一片,反过来在夜景和暗场里写黑字又完全看不见,底条是两种情况下都能看清的通用做法。想让画面更干净,可以把标注方式切到「只在第一格标总时长」,那样就只有第一格带底条。
常见的坑有三个。抓到黑块:那一秒本来就是黑场或淡入,或者这个文件的关键帧间隔太长、浏览器只能近似定位。格子发糊:格宽超过了源视频宽度除以列数,也就是在放大画面,细节补不回来;把格宽降到源宽度除以列数以内即可。导出失败:画布面积超了上限,减少格数或格宽。这些情况都可以先用页面上那个播放器确认:能正常播放和拖动,抓帧才不会出岔子。
拼图本身适合当预览,不适合当封面——多数视频站点要求 16:9 的单张图,那种情况用视频截图取帧导出一张原分辨率 PNG。想直接截出要用的片段,用视频截取片段;要一小段会动的画面,用视频转 GIF;只要声音,用视频提取音频。
常见问题
每格的时间点是怎么定的?
把整段时长等分成 N 份(N 等于列数乘行数),每格取这一格的中点:第 k 格的时间是总时长乘以 k 减 0.5 再除以 N。这样做有两个好处:第一格落在整段的 1/(2N) 处,避开了不少视频开头的淡入黑场;最后一格落在 1 减 1/(2N) 处,靠近结尾但不是结尾——定位到正好等于时长会停在末尾之后,取到黑帧甚至取不到帧。
为什么最后一格不是视频的最后一秒?
两个原因。一是播放器定位到正好等于时长的位置时会停在末尾之后,拿到的要么是黑帧要么根本没有帧,所以上界要收回 1 毫秒;二是大量视频的片尾本来就是纯黑或渐隐,真取到最后一帧反而是一块黑。取每格中点是两头都能兼顾的做法。想确认具体取到了哪些时间点,结果区里会列出首帧和末帧的实际时间。
为什么要等这么久?
每一格都是一次独立的随机定位:要把播放器挪到指定时间,等解码器找到最近的关键帧解出来,再等这一帧真正上屏。单帧快的几十毫秒、慢的几百毫秒,所以 25 格可能几秒,关键帧稀疏的 webm 或从流媒体保存的文件会更慢。抓帧是串行的——同一个播放器并发定位只会互相打断,所以只能一帧一帧来,进度条会显示当前抓到第几格。
导出的图片尺寸是怎么算的?
宽等于左右留白乘 2,加上列数乘格宽,再加上间距乘列数减 1;高同理,只是把格宽换成格高。格高是按视频的宽高比从格宽推出来的,所以每格画面不会被拉长压扁。结果区里的「导出尺寸」就是按当前参数实时算出来的,改任何一项都会立刻变。注意 Safari 的单张画布上限约 1670 万像素,超过就会导出失败。
格子里的时间在亮画面上看不清怎么办?
标签是先铺一条半透明黑底条再写白字,所以雪景、白底 PPT 这类亮画面上也能看清。如果连底条都觉得干扰,可以关掉所有标签——把标注模式切到「只在第一格标总时长」,就只有第一格有一条底条。另外格子越宽、字越大越清楚,格子宽度低于 200 像素时两位小数的秒数会比较挤。
两种标注模式分别适合什么场合?
「每格标时间」适合剪辑定位:一眼看出想要的画面在哪一秒,再去截取或用视频截图取帧导出原图。「只在第一格标总时长」适合当预览图或封面拼图:画面干净,只有一处说明这段视频有多长,也适合交给不关心时间轴的人看。两种模式的抓帧结果完全一样,切换标注模式不需要重新抓帧,只是重画一遍。
抓出来的格子有黑块或者糊了?
黑块通常是那一秒本来就是黑场、淡入,或者这个文件的关键帧间隔特别长、浏览器只能近似定位。糊则多半是格子宽度超过了视频本身的分辨率:视频只有 640 像素宽却要排成 5 列 480 像素的格子,只能靠放大,细节是补不回来的。把格宽调到不超过源视频宽度除以列数,就不会糊。