视频截图取帧
定位到某一秒把这一帧抓下来导出 PNG,也可以按时长均分 4、9、16 格先预览,挑中哪一格就单独下原图。
视频只在这台浏览器里解码,抓帧用画布完成,不上传也不联网。能读什么格式取决于浏览器自带的解码器,mp4(H.264)最稳。
为什么抓帧要等两次
抓一帧分两步:先把播放器的位置改到目标时间,再等浏览器把这一帧解码并交给合成器。第一步完成会触发 seeked 事件,但这个事件只代表「定位好了」,不代表画面已经更新——这时候立刻 drawImage,抓到的往往是上一个位置留下的画面,表现就是「抓到的帧总比填的时间点慢一帧」。所以定位完成之后还要再等一次画面呈现回调(requestVideoFrameCallback),确认新画面已经上屏才取。没有这个接口的浏览器会退化成等两帧动画,命中率略低但比不等强得多。
时间点的上界是时长减 1 毫秒,不是时长本身。定位到正好等于时长的位置,多数浏览器会停在末尾之后,抓到的是黑帧或者干脆取不到帧;往回退 1 毫秒才能稳定拿到最后一帧。同理,视频开头那半秒经常是淡入,九宫格预览取的是每一格的中点而不是开头,为的就是避开这些黑场和渐变。
导出的是无损 PNG,尺寸等于视频本身的分辨率,不缩放不重采样。九宫格里的缩略图压到 320 像素宽只是为了排得下,点下载会按原始尺寸重新抓一遍,所以不会拿到糊的小图。PNG 的体积通常比同画面的 JPEG 大几倍,如果只是想发到聊天窗口,可以用图片压缩再压一道,或者用图片格式转换转成 WebP。
能读什么格式完全取决于浏览器自带的解码器。mp4(H.264 + AAC)和 webm(VP8/VP9 + Opus)最稳;mkv、avi、flv 以及 HEVC 编码的 mp4 在部分浏览器上读不出画面,这时先用 ffmpeg 重封装或转码成 mp4。判断方法很简单:页面上那个播放器能正常播放和拖动,抓帧就没问题;播放器本身就一片空白,抓帧也不会有画面。
截图取帧要和别的处理凑在一起时,可以用九宫格切图把一张封面切成多块,或者用图片加水印给素材打上来源标记;要的是一小段会动的画面而不是单张图,用视频转 GIF。
常见问题
抓到的帧总是慢一帧,是我时间点填错了吗?
不是。seeked 事件只代表播放器定位完成,解码出来的那一帧未必已经交给合成器,这时候立刻用画布抓取,抓到的往往是上一个位置留下的画面。所以页面在定位之后还会再等一次画面呈现回调(requestVideoFrameCallback),确认新画面真的就位了才取。
为什么某些时间点抓出来是黑屏?
多半是那一秒本来就是黑场:不少视频开头有半秒淡入、片尾是纯黑,章节切换处也可能夹一帧黑。另外定位到 0 秒时部分浏览器还没解出第一帧。错开 0.2 秒再抓通常就好了,九宫格预览取每格中点也是为了避开这些黑场。
九宫格预览是按哪些时间点抓的?
把视频时长等分成 4、9 或 16 格,每格抓这一格正中间的位置。例如 10 秒的视频切 9 格,时间点就是 0.56 秒、1.67 秒、2.78 秒一直到 9.44 秒。取中点而不是每格开头,是因为开头经常是黑场或渐变,取中点更容易拿到有内容的画面。
导出的图片被压缩过吗?
没有。导出的是无损 PNG,像素尺寸就是视频本身的分辨率,不缩放也不重新采样。九宫格预览里的小图缩到 320 像素宽只是为了排得下,点「下载这一帧」会按原始尺寸重新抓一遍。PNG 体积一般比 JPEG 大几倍,画面简单时反而可能更小。
什么视频浏览器解不开?
取决于浏览器自带的解码器。mp4(H.264 + AAC)最稳;mkv、avi、flv 和 HEVC 编码的 mp4 在部分浏览器上直接读不出画面。能通过本地视频预览确认,预览能正常播放,抓帧就没问题。读不出来时先用 ffmpeg 转成 mp4 再传上来。
拖进度条拖不动,或者跳到别的位置去了?
随机定位依赖文件里的关键帧索引。有些 webm 或从流媒体保存下来的文件缺少索引,浏览器只能近似定位到最近的关键帧,看起来就是跳偏了。用 ffmpeg 重封装一次即可修复:ffmpeg -i in.mp4 -c copy out.mp4,重新生成索引后再抓帧就准了。
抓出来的图会自动加水印吗?
不会。抓帧只读取画面像素,不做任何加工,画面上原有的台标、水印会原样保留,工具不会额外添加自己的标记。需要给截图加水印或打码,可以再走一遍图片加水印工具。