vue 录制视频并压缩视频文件的方法


Posted in Javascript onJuly 27, 2018

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

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

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

vue 录制视频并压缩视频文件的方法

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转base64
   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.convertBase64UrlToFile(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.convertBase64UrlToFile方法。将gif.js生成的Blob文件转换成File格式:

//blob to file
  convertBase64UrlToFile(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转base64
   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.convertBase64UrlToFile(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
  convertBase64UrlToFile(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>

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
基本jquery的控制tabs打开的数量的代码
Oct 17 Javascript
JavaScript之HTMLCollection接口代码
Apr 27 Javascript
JavaScript中OnLoad几种使用方法
Dec 15 Javascript
js将iframe中控件的值传到主页面控件中的实现方法
Mar 11 Javascript
javascript eval(func())使用示例
Dec 05 Javascript
jquery任意位置浮动固定层插件用法实例
May 29 Javascript
javascript中使用正则表达式清理table样式的代码
Apr 01 Javascript
JavaScript必知必会(五) eval 的使用
Jun 08 Javascript
详解如何较好的使用js
Dec 16 Javascript
JS+canvas实现的五子棋游戏【人机大战版】
Jul 19 Javascript
vue移动端模态框(可传参)的实现
Nov 20 Javascript
JavaScript实现模态对话框实例
Jan 13 Javascript
JavaScript事件对象event用法分析
Jul 27 #Javascript
详解vue.js下引入百度地图jsApi的两种方法
Jul 27 #Javascript
JavaScript中为事件指定处理程序的五种方式分析
Jul 27 #Javascript
浅谈Redux中间件的实践
Jul 27 #Javascript
JavaScript多态与封装实例分析
Jul 27 #Javascript
Vue配合iView实现省市二级联动的示例代码
Jul 27 #Javascript
react native 文字轮播的实现示例
Jul 27 #Javascript
You might like
PHP使用者状态管理功能的应用
2006/10/09 PHP
PHP登陆后跳转到登陆前页面实现思路及代码
2014/01/17 PHP
PHP把小数转成整数3种方法
2014/06/30 PHP
php发送get、post请求的6种方法简明总结
2014/07/08 PHP
大家在抢红包,程序员在研究红包算法
2015/08/31 PHP
Windows2003下php5.4安装配置教程(IIS)
2016/06/30 PHP
PHPCMS手机站伪静态设置详细教程
2017/02/06 PHP
jQuery html() in Firefox (uses .innerHTML) ignores DOM changes
2010/03/05 Javascript
jQuery Selector选择器小结
2010/05/06 Javascript
网站接入QQ登录的两种方法
2014/07/22 Javascript
js实现鼠标移到链接文字弹出一个提示层的方法
2015/05/11 Javascript
jQuery Validate初步体验(一)
2015/12/12 Javascript
关于Javascript回调函数的一个妙用
2016/08/29 Javascript
微信小程序 教程之WXSS
2016/10/18 Javascript
Vue 2.0+Vue-router构建一个简单的单页应用(附源码)
2017/03/14 Javascript
three.js加载obj模型的实例代码
2017/11/10 Javascript
从零开始用electron手撸一个截屏工具的示例代码
2018/10/10 Javascript
移动端图片上传旋转、压缩问题的方法
2018/10/16 Javascript
JavaScript 性能提升之路(推荐)
2019/04/10 Javascript
vue父组件触发事件改变子组件的值的方法实例详解
2019/05/07 Javascript
layui 对table中的数据进行转义的实例
2019/09/12 Javascript
[01:38]女王驾到——至宝魔廷新尊技能&特效展示
2020/06/16 DOTA
Python标准库内置函数complex介绍
2014/11/25 Python
python将字符串转换成数组的方法
2015/04/29 Python
Python实用日期时间处理方法汇总
2015/05/09 Python
简单解析Django框架中的表单验证
2015/07/17 Python
python实现图片处理和特征提取详解
2017/11/13 Python
Python Flask框架模板操作实例分析
2019/05/03 Python
Net-A-Porter美国官网:全球时尚奢侈品名站
2017/02/11 全球购物
e路東瀛(JAPANiCAN)香港:日本旅游、日本酒店和温泉旅馆预订
2018/11/21 全球购物
在子网210.27.48.21/30种有多少个可用地址?分别是什么?
2014/07/27 面试题
医院办公室主任职责
2013/12/29 职场文书
学校采购员岗位职责
2014/01/02 职场文书
云台山导游词
2015/02/03 职场文书
素质教育培训心得体会
2016/01/19 职场文书
MySQL中几种插入和批量语句实例详解
2021/09/14 MySQL