视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
vue 录制视频并压缩视频文件的方法
2020-11-27 22:11:01 责编:小采
文档


文件上传框<input type="file">,除了可以选择文件上传之外,还可以调用摄像头来拍摄照片或者视频并上传。capture属性可以判断前置or后置摄像头。在视频播放的过程中,用canvas定时截取一张图片,然后用gif.js生成一张GIF图,从而完成前端的视频压缩。

我这里使用的是Vue写的,以下是我的流程及代码:

一、下载gif.js相关文件,可以到这里下载,然后将这几个文件放在根目录的static/js里面。

gif.js相关文件及存放路径

二、下载依赖包:

npm i timers

三、在页面中声明:

import { setInterval, clearInterval } from "timers";
import GIF from "../../static/js/gif.js"

四、html代码块:

<template>
 <div>
 <input ref="changeInput" type="file" accept="video/*" capture="user" @change="changeVideo" />
 <div>
 <div>视频大小:{{videoSize}}</div>
 <div>视频时长:{{videoLength}}</div>
 <div>
 <video id="myvideo" :src="videoSrc" :width="winWidth" :height="winHeight" ref="videoId" autoplay="true" controls muted></video>
 <canvas id="canvas" :width="winWidth" :height="winHeight"></canvas>
 </div>
 </div>
 </div>
</template>

五、在页面加载完成时初始化GIF:

mounted(){
 //初始gif
 this.gif = new GIF({
 workers: 1,
 quality: 1000,
 width: window.innerWidth,
 height: window.innerHeight,
 workerScript: '../../static/js/gif.worker.js',
 });
 },

六、当input录制完视频返回页面中,获取到这个视频文件,每次拿到视频文件需要先移除之前的监听:

//input文件走向
 changeVideo(e){
 var file = e.target.files[0];
 const video = document.getElementById('myvideo');
 //视频开始播放
 video.removeEventListener('play', this.videoPlay, false);
 //视频播放完
 video.removeEventListener('ended', this.videoEnded, false); 
 this.androidFile(file);
 },

七、上一步提到的this.androidFile方法,是通过这个视频文件,在页面播放一遍,在这个播放过程处理视频,完成整个转换过程,获取到最终的文件:

//安卓拍摄视频
 androidFile(file){
 //视频字节大小
 this.videoSize = file.size;

 const that = this;
 const video = document.getElementById('myvideo');
 const canvas = document.getElementById('canvas');
 var context = canvas.getContext('2d');

 this.gifSetTime = true;
 this.gif.abort()
 this.gif.frames = [];

 //file转base
 var reader = new FileReader();
 reader.readAsDataURL(file);
 reader.onload = function () {
 that.videoSrc = this.result;
 video.play();
 }
 //视频开始播放
 video.addEventListener('play', this.videoPlay, false);
 //视频播放完
 video.addEventListener('ended', this.videoEnded, false); 
 //获取到所有的图片并渲染完后执行
 this.gif.on('finished', function(blob) {
 if(that.fileAndroid.size == blob.size) return;
 console.log("gif的blob文件",blob);
 //file
 that.fileAndroid = that.convertBaseUrlToFile(blob);
 //上传视频文件
 that.uploadVideo(that.fileAndroid);
 });
 },

八、步骤七所说的this.videoPlay方法。视频在页面播放过程中,每200毫秒通过canvas截取一张图片,把这些图片一张张给gif.js堆叠:

//视频开始播放
 videoPlay(){
 const that = this;
 const video = document.getElementById('myvideo');
 const canvas = document.getElementById('canvas');
 var context = canvas.getContext('2d');
 console.log("视频时长",video.duration);
 this.videoLength = video.duration;
 //画布上画视频,需要动态地获取它,一帧一帧地画出来
 var times = setInterval(function(){
 context.drawImage(video, 0, 0, that.winWidth, that.winHeight);
 that.gif.addFrame(context, {
 copy: true
 });
 if(that.gifSetTime == false){
 clearInterval(times);
 }
 }, 200);
 },

九、步骤七所说的this.videoEnded方法。视频播放完,通过gif.js将图片堆叠的动态图渲染出来:

//视频播放完
 videoEnded(){
 this.gifSetTime = false;
 console.log("视频播放完毕!")
 this.gif.render();
 },

十、步骤七所说的that.convertBaseUrlToFile方法。将gif.js生成的Blob文件转换成File格式:

//blob to file
 convertBaseUrlToFile(blob) {
 var d = new Date().getTime();
 var type = 'image/gif'
 return new File([blob],"fileGif-" + d + '.gif', {type:type});
 },

最后通过步骤七所说的that.uploadVideo方法,上传图片给服务器:

//上传视频
 uploadVideo(file){
 console.log("上传的视频文件", file)
 },

在这提供我的全部代码,Android的视频文件比较大所以做压缩,而IOS本身存在视频压缩,所以我这里做了区分

<template>
 <div>
 <input ref="changeInput" type="file" accept="video/*" capture="user" @change="changeVideo" />
 <div>
 <div>视频大小:{{videoSize}}</div>
 <div>视频时长:{{videoLength}}</div>
 <div>
 <video id="myvideo" :src="videoSrc" :width="winWidth" :height="winHeight" ref="videoId" autoplay="true" controls muted></video>
 <canvas id="canvas" :width="winWidth" :height="winHeight"></canvas>
 </div>
 </div>
 </div>
</template>

<script>
import { setInterval, clearInterval } from "timers";
import GIF from "../../static/js/gif.js"
export default {
 data(){
 return {
 videoSize: '',
 videoSrc: '',
 videoLength: '',
 isAndroid: false,
 fileAndroid: {},
 winWidth: window.innerWidth,
 winHeight: window.innerHeight,
 gifSetTime: false,
 gif: '',
 }
 },
 created() {
 //判断终端
 var u = navigator.userAgent;
 var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1; //android终端
 var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
 if(isAndroid){
 console.log('isAndroid')
 this.isAndroid = true;
 }else if(isiOS){
 console.log('isiOS')
 this.isAndroid = false;
 }
 },
 mounted(){
 //初始gif
 this.gif = new GIF({
 workers: 1,
 quality: 1000,
 width: this.winWidth,
 height:this.winHeight,
 workerScript: '../../static/js/gif.worker.js',
 });
 },
 methods:{
 //input文件走向
 changeVideo(e){
 var file = e.target.files[0];
 const video = document.getElementById('myvideo');
 
 if(file !== undefined){
 //判断走向
 if(this.isAndroid){
 //视频开始播放
 video.removeEventListener('play', this.videoPlay, false);
 //视频播放完
 video.removeEventListener('ended', this.videoEnded, false); 
 this.androidFile(file);
 }else{
 this.iphoneFile(file);
 }
 }
 },
 //IOS拍摄视频
 iphoneFile(file){
 const that = this;
 //视频字节大小
 this.videoSize = file.size;
 
 var url = null ; 
 //file转换成blob
 if (window.createObjectURL!=undefined) { // basic
 url = window.createObjectURL(file) ;
 } else if (window.URL!=undefined) { // mozilla(firefox)
 url = window.URL.createObjectURL(file) ;
 } else if (window.webkitURL!=undefined) { // webkit or chrome
 url = window.webkitURL.createObjectURL(file) ;
 }
 this.videoSrc = url;
 if(file.size < 2100000 && file.size > 500000){
 this.uploadVideo(file);
 }else if(file.size >= 2100000){
 this.$vux.toast.text('视频太大,请在10秒内');
 }else{
 this.$vux.toast.text('视频录制不能少于5秒');
 }
 },
 //安卓拍摄视频
 androidFile(file){
 //视频字节大小
 this.videoSize = file.size;

 const that = this;
 const video = document.getElementById('myvideo');
 const canvas = document.getElementById('canvas');
 var context = canvas.getContext('2d');

 this.gifSetTime = true;
 this.gif.abort()
 this.gif.frames = [];

 //file转base
 var reader = new FileReader();
 reader.readAsDataURL(file);
 reader.onload = function () {
 that.videoSrc = this.result;
 video.play();
 }
 //视频开始播放
 video.addEventListener('play', this.videoPlay, false);
 //视频播放完
 video.addEventListener('ended', this.videoEnded, false); 
 
 this.gif.on('finished', function(blob) {
 if(that.fileAndroid.size == blob.size) return;
 console.log("gif的blob文件",blob);
 that.fileAndroid = that.convertBaseUrlToFile(blob);
 that.uploadVideo(that.fileAndroid);
 });
 },
 //视频开始播放
 videoPlay(){
 const that = this;
 const video = document.getElementById('myvideo');
 const canvas = document.getElementById('canvas');
 var context = canvas.getContext('2d');
 console.log("视频时长",video.duration);
 this.videoLength = video.duration;
 //画布上画视频,需要动态地获取它,一帧一帧地画出来
 var times = setInterval(function(){
 context.drawImage(video, 0, 0, that.winWidth, that.winHeight);
 that.gif.addFrame(context, {
 copy: true
 });
 if(that.gifSetTime == false){
 clearInterval(times);
 }
 }, 200);
 },
 //视频播放完
 videoEnded(){
 this.gifSetTime = false;
 console.log("视频播放完毕!")
 this.gif.render();
 },
 //blob to file
 convertBaseUrlToFile(blob) {
 var d = new Date().getTime();
 var type = 'image/gif'
 return new File([blob],"fileGif-" + d + '.gif', {type:type});
 },
 //上传视频
 uploadVideo(file){
 console.log("上传的视频文件", file)
 },
 }
};
</script>
<style scoped>

</style>

试过很多种方法,而这种在移动端浏览器(特别是微信浏览器!)的兼容性是最好的。但是这个生成的视频文件将会失去音频,如果需要音频的可以看我另一篇简书有说明几种方法。有更好的方法欢迎大家留言,互相学习~

下载本文
显示全文
专题