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 相关文章推荐
转一个日期输入控件,支持FF
Apr 27 Javascript
IE8下关于querySelectorAll()的问题
May 13 Javascript
JQuery验证工具类搜集整理
Jan 16 Javascript
深入理解javascript严格模式(Strict Mode)
Nov 28 Javascript
扒一扒JavaScript 预解释
Jan 28 Javascript
JavaScript实现将UPC转换成ISBN的方法
May 26 Javascript
bootstrap table小案例
Oct 21 Javascript
vue中动态绑定表单元素的属性方法
Feb 23 Javascript
Vue 中的compile操作方法
Feb 26 Javascript
Angular4集成ng2-file-upload的上传组件
Mar 14 Javascript
在 Vue-CLI 中引入 simple-mock实现简易的 API Mock 接口数据模拟
Nov 28 Javascript
微信小程序封装的HTTP请求示例【附升级版】
May 11 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的memory_limit限制的方法分享
2012/02/21 PHP
php解析json数据实例
2014/08/19 PHP
php根据数据id自动生成编号的实现方法
2016/10/16 PHP
CI框架常用经典操作类总结(路由,伪静态,分页,session,验证码等)
2016/11/21 PHP
JS效率个人经验谈(8-15更新),加入range技巧
2007/01/09 Javascript
extjs 学习笔记(三) 最基本的grid
2009/10/15 Javascript
javascript 广告后加载,加载完页面再加载广告
2010/11/25 Javascript
textarea不能通过maxlength属性来限制字数的解决方法
2014/09/01 Javascript
浅谈Javascript中的12种DOM节点类型
2016/08/19 Javascript
jquery把int类型转换成字符串类型的方法
2016/10/07 Javascript
touch.js 拖动、缩放、旋转 (鼠标手势)功能代码
2017/02/04 Javascript
JQuery 进入页面默认给已赋值的复选框打钩
2017/03/23 jQuery
jQuery手风琴的简单制作
2017/05/12 jQuery
vue.js的安装方法
2017/05/12 Javascript
JS实现简单打字测试
2020/06/24 Javascript
如何实现vue的tree组件
2020/12/03 Vue.js
node.js 基于 STMP 协议和 EWS 协议发送邮件
2021/02/14 Javascript
python基础教程之实现石头剪刀布游戏示例
2014/02/11 Python
python数据结构之二叉树的遍历实例
2014/04/29 Python
Python 结巴分词实现关键词抽取分析
2017/10/21 Python
python在ubuntu中的几种安装方法(小结)
2017/12/08 Python
使用python实现knn算法
2017/12/20 Python
python代码实现ID3决策树算法
2017/12/20 Python
Python元字符的用法实例解析
2018/01/17 Python
Python代码使用 Pyftpdlib实现FTP服务器功能
2019/07/22 Python
django序列化时使用外键的真实值操作
2020/07/15 Python
基于python实现简单网页服务器代码实例
2020/09/14 Python
Django自带的用户验证系统实现
2020/12/18 Python
新加坡航空官方网站:Singapore Airlines
2016/10/13 全球购物
Java方面的关于数组和继承的笔面试题
2015/09/18 面试题
酒店总经理欢迎词
2014/01/08 职场文书
装修五一活动策划案
2014/01/23 职场文书
保险公司早会主持词
2014/03/22 职场文书
2015年物业公司保洁工作总结
2015/10/22 职场文书
javascript之Object.assign()的痛点分析
2022/03/03 Javascript
vue生命周期钩子函数以及触发时机
2022/04/26 Vue.js