uni-app 中视频首帧截取需分平台调用原生API:小程序用 wx.getVideoInfo 获取 coverUrl,App 用 plus.video.getThumbnail 生成缩略图,H5 才可用 canvas.drawImage 兜底。

uni-app 中无法直接用 canvas 截取视频首帧
因为 uni-app 的 组件在非 H5 平台(如小程序、App)不支持 drawImage 操作,canvas.getContext('2d').drawImage(video, ...) 在微信小程序或 App 端会静默失败或报错 canvas is not supported on this platform。H5 端虽可行,但跨端一致性差,不能作为通用方案。
真正可靠的方式是:交由原生能力处理——小程序调用 wx.getVideoInfo(基础库 2.27.0+),App 端调用 plus.video.getThumbnail,H5 则退化为 canvas 方案(仅作兜底)。
- 微信小程序必须使用
wx.getVideoInfo,它返回coverUrl(平台自动生成的首帧截图地址),无需手动绘制 - App 端(iOS/Android)需通过
plus.video.getThumbnail指定时间点(如0秒)生成缩略图,支持自定义尺寸和质量 - H5 端可走
canvas+video+drawImage,但需监听loadeddata事件确保视频元数据就绪
微信小程序:用 wx.getVideoInfo 拿 coverUrl
这是最省事、最稳定的方式,不需要自己控制 canvas 或解码逻辑,微信后台已为你截好首帧。
注意:该 API 要求传入的是**本地临时文件路径**(tempFilePath),不是网络 URL;且需基础库 ≥ 2.27.0,低版本会 fallback 失败。
- 上传视频后拿到
tempFilePath,立刻调用wx.getVideoInfo({ src }) - 成功回调中取
res.coverUrl,它就是一张可用的首帧图片 URL(HTTPS 协议,可直接用于) - 若需更高清封面,可额外调用
wx.chooseMedia(新版媒体 API)并设置capture: 'camera'+mediaType: ['video'],其返回对象自带thumbTempFilePath
uni.chooseVideo({
success: (res) => {
const tempPath = res.tempFilePath;
wx.getVideoInfo({
src: tempPath,
success: (infoRes) => {
const coverUrl = infoRes.coverUrl; // ✅ 直接可用
this.videoCover = coverUrl;
}
});
}
});
App 端:用 plus.video.getThumbnail 精确控制截图时间与尺寸
App 环境下,plus.video.getThumbnail 是唯一可控、稳定的首帧提取方式,支持指定毫秒级时间点(如 0)、输出宽高、质量(1–100)及格式(jpg 或 png)。
它不依赖 video 元素渲染,而是直接读取视频文件头和关键帧,因此比 canvas 更快、更准,也不会出现黑屏或空白帧问题。
- 路径必须是本地绝对路径(
_www、documents://、cache://等开头),不能是 HTTP URL - 时间参数设为
0通常能取到 I 帧,但某些编码(如 B-frame 前置)可能导致首帧偏移,可尝试100~300ms 安全起见 - 回调返回的是本地图片路径(
file://),需用uni.getImageInfo或直接赋值给的src
if (uni.getSystemInfoSync().platform === 'app') {
plus.video.getThumbnail(
videoPath, // 如 'documents://xxx.mp4'
{
time: 0,
width: 720,
height: 1280,
quality: 90,
format: 'jpg'
},
(path) => {
this.videoCover = path; // ✅ file:// 开头路径
},
(err) => {
console.error('getThumbnail failed:', err);
}
);
}
为什么不能用 video.currentTime = 0 + canvas.draw 跨端?
这个思路在 H5 上成立,但在小程序和 App 中根本走不通:小程序的 是原生组件,无法被 canvas 绘制;App 的 webview 中 video 元素受系统限制,drawImage 调用会直接报 SecurityError: The operation is insecure 或静默忽略。
即使强行在小程序里用 canvas,也会遇到:video.readyState === 0、video.videoWidth === 0、canvas.drawImage 无效果等问题——不是代码写错了,是平台能力缺失。
- 不要试图用
setTimeout等待loadeddata后再 draw:小程序里该事件可能不触发,或触发时 video 仍不可绘 - 不要把网络视频 URL 直接传给
wx.getVideoInfo:它只认本地tempFilePath,否则报错invalid src - App 端若传入 HTTP URL 给
plus.video.getThumbnail,会直接失败,必须先uni.downloadFile到本地再处理
跨端视频封面的本质,是放弃“一套代码通吃”的幻想,按平台分发原生能力调用。最容易被忽略的,是路径协议和环境判断顺序——比如没做 plus.video 存在性校验就直接调用,App 启动时会因 JS 异常卡死。











