uniapp获取视频第一帧做封面图
需求:uniapp获取视频第一帧做封面图。
介绍:通过canvas来截取视频的某一帧,然后把这一帧转成base64编码的图片格式即可,canvas需要在document中获取,但是uniapp没有documen元素,所以这时候就要使用renderjs来获取documen元素。
场景:uniapp。
renderjs
先介绍一下renderjs: renderjs是一个运行在视图层的js。
官方介绍renderjs的主要作用有2个:
- 大幅降低逻辑层和视图层的通讯损耗,提供高性能视图交互能力
- 在视图层操作dom,运行 for web 的 js库。
- 仅支持在
APP(vue页面)、H5页面使用。nvue无法使用。
解释一下:因为uniapp的逻辑层和视图层是分离的,所以我们无法在vue代码中获取到这个视图层的documen。这种机制就造成了逻辑层和视图层的通信阻塞。renderjs运行在视图层,直接就可以操作dom元素了。
基础的使用方式:
- moudule这个名称后面是需要拿去使用的。
<script module="test" lang="renderjs">
export default {
mounted() {
// ...
},
methods: {
// ...
}
}
</script>
下面来介绍如何通过renderjs和canvas获取视频第一帧
- 当srcVideo变化时候会触发canvas的getVideoCanvas方法
canvas对应renderjs模块module的名称- video给宽高都是0,是因为点击封面图我会让他自动全屏播放,这样video元素就不会占住布局位置
<template>
<video style="width: 0px; height: 0px;" class="preview-file" id='video_play' ref="video_play" :src="videoSrc"
@fullscreenchange="onVideoFullScreenChange" autoplay></video>
<view style="display: flex; flex-wrap: wrap;" :prop="srcVideo" :change:prop="canvas.getVideoCanvas">
<view class="upload-video" v-for="(item1, index1) in srcVideo" :key="index1">
<view class="image-view">
<!-- 获取到的封面图 -->
<image style="width: 520rpx; height: 320rpx; border: 1px solid;" :src="item1.imgSrc"></image>
</view>
</view>
</view>
</template>
tip:红色标注的值必须一致
vue代码
- onVideoFullScreenChange : 视频全屏状态改变触发的函数
- getVideoCover :
renderjs传来的数据 - 计时器为了触发srcVideo发生变化,从而触发renderjs。
唯一要思考的点:使用本文代码的时候,只要控制好什么时候改变srcVideo就可以了,比如我选择完视频后,改变srcVideo数据,那么就获取到了视频第一帧。
<script>
export default {
data() {
return {
srcVideo: [], //视频存放的地址
videoSrc: null, //视频src
playVideoing: null, //video本身
}
},
created() {
//计时器为了触发srcVideo发生变化,从而触发renderjs
setTimeout(() => {
let videoFileObj = {
imgSrc: 'https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/2minute-demo.mp4',
}
this.srcVideo.push(videoFileObj)
})
},
methods: {
//视频全屏状态改变触发的函数
onVideoFullScreenChange(e) {
if (this.videoSrc && !e.detail.fullScreen) {
this.videoSrc = null;
this.playVideoing.stop();
}
},
getVideoCover({index,cover}) {
this.srcVideo[index].imgSrc = cover
},
}
}
<script>
renderjs模块
module的命名在上面的html标签里面会用到instance拿到整个html标签元素getVideoCanvas是用来接收逻辑层的数据- 利用documen创建video元素,进行自动播放,加上静音,来获取帧数
- currentTime选择
第几秒,如果切出来是黑色的话,那么换一下秒数。这里我选择了第40秒,因为很多视频可能第一秒是黑色画面不太友好。 - toDataURL把数据转成
base64编码格式,直接在图片上渲染就行了。
drawImage(img,sx,sy,swidth,sheight,x,y,width,height)
- img:image是画布绘制的图像源,绘制到画布上的元素,可以是canvasElement,imageElement,svgImageElement ,videoElement等一系列具有图像的元素。
- sx:绘制裁剪的图像源的x 坐标位置;
- sy:绘制裁剪的图像源的y坐标位置;
- sWidth:绘制裁剪的图像源的宽度;
- sHeight:绘制裁剪的图像源的高度;
- dx:目标源在canvas画布上绘制的左上角的x坐标;
- dy:目标源在canvas画布上绘制的左上角的y坐标;
- width:目标源在canvas画布上绘制的宽度,会自动根据图像源截取的宽度对比做缩放;
- height:目标源在canvas画布上绘制的高度,会自动根据图像源截取的高度对比做缩放;
<script module="canvas" lang="renderjs">
export default {
methods: {
// 接受逻辑层的数据
getVideoCanvas(newVal, oldValue, instance) {
//先判断有没有数据
if (Array.isArray(newVal) && newVal.length > 0) {
newVal.forEach((item, index) => {
// 创建video标签
let video = document.createElement("video")
// 设置为自动播放和静音
video.setAttribute('autoplay', 'autoplay')
video.setAttribute('muted', 'true')
// 宽高看自己想要获取多大的,随意设置
video.setAttribute("width", "300px")
video.setAttribute("height", "200px")
video.setAttribute('crossOrigin', 'anonymous')
video.setAttribute("src",
"https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/2minute-demo.mp4"
)
// 选择第几秒
video.currentTime = 40
// 创建 canvas 元素和 2d 画布
let canvas = document.createElement('canvas')
video.addEventListener("loadeddata", function () {
const canvas = document.createElement("canvas")
let width = video.width //canvas的尺寸和图片一样
let height = video.height
canvas.width = width
canvas.height = height
canvas.getContext('2d').drawImage(video, 0, 0, width,
height) // 绘制canvas
let imgSrc = canvas.toDataURL("image/jpeg") //获取base46格式的图片文件
// 下面这个可以转成二进制流
// let imgText = canvas.toBlob(res => {
// console.log('res', res);
// })
instance.callMethod('getVideoCover', {
index,
cover: imgSrc
})
})
})
}
}
}
}
</script>
总体代码:
<template>
<view>
<video style="width: 0px; height: 0px;" class="preview-file" id='video_play' ref="video_play" :src="videoSrc"
@fullscreenchange="onVideoFullScreenChange" autoplay></video>
<view style="display: flex; flex-wrap: wrap;" :prop="srcVideo" :change:prop="canvas.getVideoCanvas">
<view class="upload-video" v-for="(item1, index1) in srcVideo" :key="index1">
<view class="image-view">
<!-- 获取到的封面图 -->
<image style="width: 520rpx; height: 320rpx; border: 1px solid;" :src="item1.imgSrc"></image>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
srcVideo: [], //视频存放的地址
videoSrc: null, //视频src
playVideoing: null, //video本身
}
},
created() {
//计时器为了触发srcVideo发生变化,从而触发renderjs
setTimeout(() => {
let videoFileObj = {
imgSrc: 'https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/2minute-demo.mp4',
}
this.srcVideo.push(videoFileObj)
})
},
methods: {
//视频全屏状态改变触发的函数
onVideoFullScreenChange(e) {
if (this.videoSrc && !e.detail.fullScreen) {
this.videoSrc = null;
this.playVideoing.stop();
}
},
getVideoCover({index,cover}) {
this.srcVideo[index].imgSrc = cover
},
}
}
</script>
<script module="canvas" lang="renderjs">
export default {
methods: {
// 接受逻辑层的数据
getVideoCanvas(newVal, oldValue, instance) {
//先判断有没有数据
if (Array.isArray(newVal) && newVal.length > 0) {
newVal.forEach((item, index) => {
// 创建video标签
let video = document.createElement("video")
// 设置为自动播放和静音
video.setAttribute('autoplay', 'autoplay')
video.setAttribute('muted', 'true')
// 宽高看自己想要获取多大的,随意设置
video.setAttribute("width", "300px")
video.setAttribute("height", "200px")
video.setAttribute('crossOrigin', 'anonymous')
video.setAttribute("src",
"https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/2minute-demo.mp4"
)
// 选择第几秒
video.currentTime = 40
// 创建 canvas 元素和 2d 画布
let canvas = document.createElement('canvas')
video.addEventListener("loadeddata", function () {
const canvas = document.createElement("canvas")
let width = video.width //canvas的尺寸和图片一样
let height = video.height
canvas.width = width
canvas.height = height
canvas.getContext('2d').drawImage(video, 0, 0, width,
height) // 绘制canvas
let imgSrc = canvas.toDataURL("image/jpeg") //获取base46格式的图片文件
// 下面这个可以转成二进制流
// let imgText = canvas.toBlob(res => {
// console.log('res', res);
// })
instance.callMethod('getVideoCover', {
index,
cover: imgSrc
})
})
})
}
}
}
}
</script>
以上介绍就是uniapp如何获取视频第一帧做封面图。