HTML5视频截图必须等待loadedmetadata或canplay事件触发后,再用canvas.drawImage(video,0,0)捕获帧并toDataURL导出;需设crossorigin="anonymous"处理跨域,优先用video.videoWidth/Height设canvas尺寸,避免黑图或失真。
直接用 poster 属性最省事,但只适用于静态封面;想从视频里真实截一帧(比如第1秒画面),必须等视频元数据加载完成再画到 canvas 上,否则 video.videoWidth 是 0,drawImage 会失败或输出黑图。
它只在视频还没加载、没播放前显示,一旦视频开始加载或用户点了播放,浏览器就自动切走——不是“一直挂着”的封面。常见误区是以为设了 poster 就能当缩略图复用,其实它不参与 DOM 操作,也不能导出为图片。
poster 值必须是可访问的图片 URL,不能是 base64 字符串(部分旧版 Safari 会拒载)poster 图片也得走同样鉴权逻辑,否则跨域报错导致空白poster 加载有延迟,可加 preload="metadata" 提前触发核心问题是:视频还没解码出尺寸,video.videoWidth 就是 0;还没 ready,drawImage 就画不出东西。不能靠 setTimeout 硬等,得监听事件。
loadedmetadata 事件,此时宽高已知,但画面未必能渲染(尤其本地 file 对象)canplay 或 canplaythrough,表示视频帧已缓冲可绘制video.currentTime = 2,再等 seeked 事件触发后再画File 对象需用 URL.createObjectURL(file) 赋给 video.src,否则跨域污染 canvas,toDataURL() 抛错HTML5 原生不支持 RTSP,<video> 标签根本播不了,更别提截帧。所有“前端生成”方案都是假的——实际是后端用 ffmpeg 定时拉流抽帧,前端只负责轮询一张图。
立即学习“前端免费学习笔记(深入)”;
ffmpeg -i "rtsp://user:[email protected]:554/stream" -vframes 1 -f image2 -y /tmp/thumb.jpg
/api/thumb.jpg?t=1744706000
真正容易被忽略的是:canvas 截帧依赖视频是否已解码并准备好像素数据,而这个状态在不同设备、不同格式(尤其是 H.265 编码 MP4)、不同加载方式(HTTP range 请求 vs 整包下载)下差异极大。别只测 Chrome 桌面版,iOS Safari 和 Android WebView 的 canplay 触发时机经常晚半拍。