JS获取视频第N秒作为封面图片(js获取视频第一帧图片)
引言
最近开发的时候遇到了一个需求,截取视频第一帧作为视频的封面,结果第一帧是黑屏,所以产品提出,希望可以截取的不是黑屏的作为封面。
于是我们先定一个小目标:实现截取第N秒作为视频封面。
注意事项
视频地址必须
同源
或者是支持跨域访问
。设置视频播放时间后,再监听
canplay
事件。
整体步骤
获取视频基本配置信息。
视频当前播放时间设置到第
N
秒。当视频可以播放时,我们截取视频作为图片地址。
详细步骤
封装:获取视频基本配置信息
通过获取视频的基本信息,我们可以知道视频分辨率与时长,为后面的步骤提供必要的信息。
// 获取视频基本信息 function getVideoBasicInfo(videoSrc) { return new Promise((resolve, reject) => { const video = document.createElement('video') video.src = videoSrc // 视频一定要添加预加载 video.preload = 'auto' // 视频一定要同源或者必须允许跨域 video.crossOrigin = 'Anonymous' // 监听:异常 video.addEventListener('error', error => { reject(error) }) // 监听:加载完成基本信息,设置要播放的时常 video.addEventListener('loadedmetadata', () => { const videoInfo = { video, width: video.videoWidth, height: video.videoHeight, duration: video.duration } resolve(videoInfo) }) }) } 复制代码
封装:截取视频作为图片地址
这里我们进行封装,传入视频信息,当视频可以播放后,再视频绘入canvas
,否则会导致在将canvas
转换成图片地址,因为绘入canvas
的缘故,所以我们的视频才需要同源或者允许跨域。
// 将视频信息转化为canvas function getPosterUrlByVideo(videoInfo) { return new Promise(resolve => { const { video, width, height } = videoInfo video.addEventListener('canplay', () => { const canvas = document.createElement('canvas') canvas.width = width canvas.height = height const ctx = canvas.getContext('2d') // 绘制到canvas中 ctx.drawImage(video, 0, 0, width, height) // 将canvas转化为图片url const posterUrl = canvas.toDataURL('image/png') resolve(posterUrl) }) }) } 复制代码
串联代码
我们将整体串联起来,先获取视频信息,在判断指定的秒数是否超出视频最大的时长,再设置视频的当前播放时间为指定的秒数,当视频可以播放了,再截取当前的视频为图片地址。
// 根据视频url截取视频第N秒 function getVideoPosterByFrame(videoSrc, targetTime) { return getVideoBasicInfo(videoSrc).then(videoInfo => { const { video, duration } = videoInfo // 判断时长是否超出 if (targetTime > duration) { throw new Error('指定的时长大于播放时长') } // 设置视频到指定时长 video.currentTime = targetTime return getPosterUrlByVideo(videoInfo) }) } 复制代码
整体代码与调试
// 获取视频基本信息 function getVideoBasicInfo(videoSrc) { return new Promise((resolve, reject) => { const video = document.createElement('video') video.src = videoSrc // 视频一定要添加预加载 video.preload = 'auto' // 视频一定要同源或者必须允许跨域 video.crossOrigin = 'Anonymous' // 监听:异常 video.addEventListener('error', error => { reject(error) }) // 监听:加载完成基本信息,设置要播放的时常 video.addEventListener('loadedmetadata', () => { const videoInfo = { video, width: video.videoWidth, height: video.videoHeight, duration: video.duration } resolve(videoInfo) }) }) } // 将获取到的视频信息,转化为图片地址 function getPosterUrlByVideo(videoInfo) { return new Promise(resolve => { const { video, width, height } = videoInfo video.addEventListener('canplay', () => { const canvas = document.createElement('canvas') canvas.width = width canvas.height = height const ctx = canvas.getContext('2d') ctx.drawImage(video, 0, 0, width, height) const posterUrl = canvas.toDataURL('image/jpg') resolve(posterUrl) }) }) } // 根据视频url截取视频第N秒 function getVideoPosterByFrame(videoSrc, targetTime) { return getVideoBasicInfo(videoSrc).then(videoInfo => { const { video, duration } = videoInfo // 判断时长是否超出 if (targetTime > duration) { throw new Error('指定的时长大于播放时长') } // 设置视频到指定时长 video.currentTime = targetTime return getPosterUrlByVideo(videoInfo) }) } // 这里是通过http-server开启本地服务,让视频与本地的代码同源了 const videoSrc = 'http://127.0.0.1:8081/trailer.mp4' const targetTime = 15 const src = getVideoPosterByFrame(videoSrc, targetTime).then(posterSrc => { const image = new Image() image.src = posterSrc document.body.append(image) }).catch(error => { console.log(error) })
作者:春道
链接:https://juejin.cn/post/7036289153578827812