uni-app从后端返回的mp4链接视频截取一帧为封面

  • Post author:
  • Post category:其他




一、需求:

后端返回包含视频链接的数组对象,格式如下:

[
   {
      url: 'xxxxx.mp4',
   },
   {
      url: 'xxxxx.mp4',
   },
   {
      url: 'xxxxx.mp4',
   },
]

从上面的mp4视频中截取一帧设置为封面,如下图,下面的封面图从视频中截取而来。

在这里插入图片描述



二、代码实现:
<script>
	export default {
		onLoad() 
			this.getViedoList();
		},
		data() {
			return{
	            videoLists:[], // 获取到的视频列表数组
				posterList: [] ,// 视频封面图数组
			}
		},
		methods: {
			getViedoList(){
				this.$uniReq({
					url:"doc/api/doc's/@freevideo",
					method:"GET",
				}).then((re)=>
					this.videoLists = re
			        this.createPoster();
				}).catch((err)=>{
					console.log(err);
				})
			}
			createPoster() { // 截取封面 封装函数
				var videoCanList = []
				this.videoLists.forEach((item,index) => {
					var promise = new Promise((reslove, reject) => {
						// 在缓存中创建video标签
						var video = document.createElement("VIDEO")
						// 通过setAttribute给video dom元素添加自动播放的属性,因为视频播放才能获取封面图
						video.currentTime = 1; // 截取视频的第1秒
						video.setAttribute('crossOrigin', 'anonymous');
						video.setAttribute('autoplay', 'autoplay')
						// 再添加一个静音的属性,否则自动播放会有声音
						video.setAttribute('muted', 'muted')
						// 上面我们只是创建了video标签,视频播放需要内部的source的标签,scr为播放源
						video.innerHTML = '<source src=' + item.url + ' type="audio/mp4">'
						// 再创建canvas画布标签
						var canvas = document.createElement('canvas');
						var ctx = canvas.getContext('2d');
						// video注册canplay自动播放事件
						video.addEventListener('canplay', function() {
							// 创建画布的宽高属性节点,就是图片的大小,单位PX
							var anw = document.createAttribute("width");
							anw.nodeValue = 500;
							var anh = document.createAttribute("height");
							anh.nodeValue = 300;
							canvas.setAttributeNode(anw);
							canvas.setAttributeNode(anh);
							// 画布渲染
							ctx.drawImage(video, 0, 0, 500, 300);
							// 生成图片
							var base64 = canvas.toDataURL('image/png') // 这就是封面图片的base64编码
							// 视频结束播放的事件
							video.pause()
							reslove(base64)  // promise函数成功的回调
						}, false)
					})
					videoCanList.push(promise)
				})
				Promise.all(videoCanList).then(res => {
					this.posterList = res
				})
			}
		}
	}
</script>

按照上面的代码,其中posterList就是对应的每一个视频的封面base64数组,一切看起来都挺好,在H5正常运行,但是在APP端使用,明显是不可以的,因为在app端,document为undefined,那么怎么弄呢,查阅了资料,发现使用renderjs即可以识别。

<view class='healthPromotion' :videoLists="videoLists" :change:videoLists="renderScript.createPoster"></view>

<script>
	export default {
		onLoad() 
			this.getViedoList();
		},
		data() {
			return{
	            videoLists:[], // 获取到的视频列表数组
				posterList: [] ,// 视频封面图数组
			}
		},
		methods: {
			getViedoList(){
				this.$uniReq({
					url:"doc/api/doc's/@freevideo",
					method:"GET",
				}).then((re)=>
					this.videoLists = re
				}).catch((err)=>{
					console.log(err);
				})
			},
            reciveMessage(val) {
				this.posterList = val
			}
		}
	}
</script>

<script module="renderScript" lang="renderjs">
	export default {
		methods: {
			createPoster(val) {
				var videoCanList = [],curDateList = []
				val.forEach((item,index) => {
					var promise = new Promise((reslove, reject) => {
						// 在缓存中创建video标签
						var video = document.createElement("VIDEO")
						// 通过setAttribute给video dom元素添加自动播放的属性,因为视频播放才能获取封面图
						video.currentTime = 5
						video.setAttribute('crossOrigin', 'anonymous');
						video.setAttribute('autoplay', 'autoplay')
						// 再添加一个静音的属性,否则自动播放会有声音
						video.setAttribute('muted', 'muted')
						// 上面我们只是创建了video标签,视频播放需要内部的source的标签,scr为播放源
						video.innerHTML = '<source src=' + item.url + ' type="audio/mp4">'
						// 再创建canvas画布标签
						var canvas = document.createElement('canvas');
						var ctx = canvas.getContext('2d');
						// video注册canplay自动播放事件
						video.addEventListener('canplay', function() {
							// 创建画布的宽高属性节点,就是图片的大小,单位PX
							var anw = document.createAttribute("width");
							anw.nodeValue = 500;
							var anh = document.createAttribute("height");
							anh.nodeValue = 300;
							canvas.setAttributeNode(anw);
							canvas.setAttributeNode(anh);
							// 画布渲染
							ctx.drawImage(video, 0, 0, 500, 300);
							// 生成图片
							var base64 = canvas.toDataURL('image/png') // 这就是封面图片的base64编码
							// 视频结束播放的事件
							video.pause()
							curDateList.unshift({ // 这里是我自己的数据处理模块
								type: 'video',
								videoUrl: item.url,
								img: base64
							})
							reslove(base64)  // promise函数成功的回调
						}, false)
					})
					videoCanList.push(promise)
				})
				Promise.all(videoCanList).then(res => {
					this.$ownerInstance.callMethod('reciveMessage', res)
				})
			},
		}
	}
</script>



1)当 videoLists变化时,通过 :change:videoLists=”renderScript.createPoster”这一段代码, renderjs 中的createPoster被调用

2)renderjs给script传递数据 this.$ownerInstance.callMethod(‘reciveMessage’, res),调用reciveMessage代码,给posterList 赋值

通过上面的方法完成renderjs与常规script的通信,这样就达到了开篇的需求图的封面列表,H5,APP端都可以生成封面图,亲测有效



版权声明:本文为yuanqi3131原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。