vue+ffmpeg实现前端视频转码

简介: 如何使用ffmpeg的wasm文件在浏览器实现视频转码

因为做过的项目中,有涉及到视频上传的模块,常规视频的mp4格式可以直接进行预览和展示,但是部分视频文件无法直接预览,需要进行转码成mp4进行处理,我在GitHub上寻找到了ffmpeg的wasm版本,并成功在项目中实现转码。
这里给出一个将asf格式的视频转换mp4的示例
转码.png

这里给出解决思路
首先,我们安装 @ffmpeg/core,@ffmpeg/ffmpeg 两个库,网址如下https://ffmpegwasm.netlify.app/#demo,这里写的简单示例是用element-plus的upload组件+video标签实现
代码如下

  
<script setup lang="ts">
import { UploadFilled } from '@element-plus/icons-vue'
import type { UploadProps } from 'element-plus';
import { fetchFile } from '@ffmpeg/ffmpeg';
import { ComponentInternalInstance, getCurrentInstance, ref } from 'vue';
import { createFFmpeg } from '@ffmpeg/ffmpeg';
const {
  appContext: {
    config: { globalProperties }
  }
} = getCurrentInstance() as ComponentInternalInstance;
const videoPlayURL = ref('')
const videoPreview = ref({} as HTMLVideoElement);

const uploadFileChange: UploadProps['onChange'] = async (uploadFile: any) => {
 
  let ffmpegInstance: any
  if (!globalProperties.$ffmpeg) {
    globalProperties.$ffmpeg = createFFmpeg({
      log: false
    });
  }
  let file: File = uploadFile.raw as File;
  ffmpegInstance = globalProperties.$ffmpeg;
  videoTranscodeFunc(ffmpegInstance, file, 'test').then(() => {
    // 转码进度
    let curProgress: number = 0; // 进度取值不稳定,作为对比
    let startTranscode = false;
    let progressCounter = 0;
    ffmpegInstance.setProgress(({ ratio }: any) => {
      console.log('ratio', ratio);
      // 开始转码时跳转到进度页,只执行一次
      if (!startTranscode) {
        startTranscode = true;

      }
      // ratio is a float number between 0 to 1.
      // ratio可能小于0或者大于1,需要处理
      if (ratio > 0) {
        let progress = parseInt(ratio * 100 + ''); //转为两位数
        if (progress < 100) {
          if (progressCounter === 0 && progress > 90) return; // 规避转码异常
          curProgress = Math.max(curProgress, progress); //取相对更大的值,避免进度倒着走
          curProgress = curProgress < 1 ? 1 : curProgress; // 大文件转码初始进度0.00X,出现长时间为0的情况优化
          progressCounter++;
        }
      }
    });
    // 通过文件格式校验的,在解析时也加一层拦截,检查异常文件,报错中断
    ffmpegInstance.setLogger(({ type, message }: any) => {
      let name = 'test';
      // 异常情况判断
      let invalidMessage = ['Conversion failed!', 'pthread sent an error!'];
      let invalid = invalidMessage.some((item) => message.includes(item));
      if (type === 'fferr' && invalid) {
        console.log("转码异常2")
        return;
      }

      // 转码结束处理
      if (type === 'ffout') {
        try {
          const data = ffmpegInstance.FS('readFile', `${name}.mp4`);
          console.log('转码结束');
          console.timeEnd('videoTranscode');
          let videoUrl = '';
          videoUrl = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));
          videoPlayURL.value = videoUrl
          var result = new File([data.buffer], `${name}.mp4`, {
            type: 'video/mp4',
            lastModified: Date.now()
          });
          uploadFile.size = result.size;
          uploadFile.raw = result;
          uploadFile.status = 'ready';

          // 防止ffmpeg返回值异常,只在结束时才赋值100
          ffmpegInstance.FS('unlink', `${name}.mp4`); // 释放内存中的文件
        } catch (err) {
          console.log('转码失败', err);
          return;
        }
      }
    });
  });
};


const videoTranscodeFunc = async (ffmpeg: any, file: any, name: string) => {

  try {
    if (!ffmpeg.isLoaded()) await ffmpeg.load(); // load过的不需要重复load,否则会转码失败
    // console.log('1', name, `${name}.mp4`);
    ffmpeg.FS('writeFile', name, await fetchFile(file));
    // console.log('2', name, `${name}.mp4`);
    ffmpeg.run('-i', name, `${name}.mp4`);
  } catch (err) {
    console.log('ffmpeg run error', err);
  }
};
</script>


<template>
  <el-upload class="upload-demo" :on-change="uploadFileChange" drag :auto-upload="false">
    <el-icon class="el-icon--upload"><upload-filled /></el-icon>
    <div class="el-upload__text">
      Drop file here or <em>click to upload</em>
    </div>

  </el-upload>

  <div class="videoContainer">
    <video :src="videoPlayURL" :controls="true" ref="videoPreview" crossorigin="Anonymous" class="videoDom"></video>
  </div>
</template>



<style scoped>
.videoDom {
  width: 800px;
  height: 400px;
  border: solid 1px red;
}
</style>
  
相关文章
|
7月前
|
JavaScript 前端开发 Java
制造业ERP源码,工厂ERP管理系统,前端框架:Vue,后端框架:SpringBoot
这是一套基于SpringBoot+Vue技术栈开发的ERP企业管理系统,采用Java语言与vscode工具。系统涵盖采购/销售、出入库、生产、品质管理等功能,整合客户与供应商数据,支持在线协同和业务全流程管控。同时提供主数据管理、权限控制、工作流审批、报表自定义及打印、在线报表开发和自定义表单功能,助力企业实现高效自动化管理,并通过UniAPP实现移动端支持,满足多场景应用需求。
697 1
|
8月前
|
移动开发 前端开发 JavaScript
Vue与React两大前端框架的主要差异点
以上就是Vue和React的主要差异点,希望对你有所帮助。在选择使用哪一个框架时,需要根据项目的具体需求和团队的技术栈来决定。
500 83
|
9月前
|
JSON 自然语言处理 前端开发
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
514 72
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
|
7月前
|
JavaScript 前端开发 编译器
Vue与TypeScript:如何实现更强大的前端开发
Vue.js 以其简洁的语法和灵活的架构在前端开发中广受欢迎,而 TypeScript 作为一种静态类型语言,为 JavaScript 提供了强大的类型系统和编译时检查。将 Vue.js 与 TypeScript 结合使用,不仅可以提升代码的可维护性和可扩展性,还能减少运行时错误,提高开发效率。本文将介绍如何在 Vue.js 项目中使用 TypeScript,并通过一些代码示例展示其强大功能。
321 22
|
9月前
|
人工智能 JavaScript 前端开发
Vue 性能革命:揭秘前端优化的终极技巧;Vue优化技巧,解决Vue项目卡顿问题
Vue在处理少量数据和有限dom的情况下技术已经非常成熟了,但现在随着AI时代的到来,海量数据场景会越来越多,Vue优化技巧也是必备技能。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
JavaScript 前端开发 搜索推荐
Vue的数据驱动视图与其他前端框架的数据驱动方式有何不同?
总的来说,Vue 的数据驱动视图在诸多方面展现出独特的优势,其与其他前端框架的数据驱动方式的不同之处主要体现在绑定方式、性能表现、触发机制、组件化结合、灵活性、语法表达以及与后端数据交互等方面。这些差异使得 Vue 在前端开发领域具有独特的地位和价值。
269 58
|
11月前
|
JavaScript 前端开发 jenkins
抛弃node和vscode,如何用记事本开发出一个完整的vue前端项目
本文探讨了在不依赖Node和VSCode的情况下,仅使用记事本和浏览器开发一个完整的Vue3前端项目的方法。通过CDN引入Vue、Vue Router、Element-UI等库,直接编写HTML文件实现页面功能,展示了前端开发的本质是生成HTML。虽然日常开发离不开现代工具,但掌握这种基础方法有助于快速实现想法或应对特殊环境限制。文章还介绍了如何用Node简单部署HTML文件到服务器,提供了一种高效、轻量的开发思路。
277 10
|
编解码 监控 网络协议
如何使用FFmpeg实现RTSP推送H.264和H.265(HEVC)编码视频
本文详细介绍了如何使用FFmpeg实现RTSP推送H.264和H.265(HEVC)编码视频。内容涵盖环境搭建、编码配置、服务器端与客户端实现等方面,适合视频监控系统和直播平台等应用场景。通过具体命令和示例代码,帮助读者快速上手并实现目标。
3324 6
|
前端开发 JavaScript 开发者
React与Vue:前端框架的巅峰对决与选择策略
【10月更文挑战第23天】React与Vue:前端框架的巅峰对决与选择策略