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天前
|
SpringCloudAlibaba JavaScript 前端开发
谷粒商城笔记+踩坑(2)——分布式组件、前端基础,nacos+feign+gateway+ES6+vue脚手架
分布式组件、nacos注册配置中心、openfegin远程调用、网关gateway、ES6脚本语言规范、vue、elementUI
谷粒商城笔记+踩坑(2)——分布式组件、前端基础,nacos+feign+gateway+ES6+vue脚手架
|
1天前
|
机器学习/深度学习 数据采集 JavaScript
ADR智能监测系统源码,系统采用Java开发,基于SpringBoot框架,前端使用Vue,可自动预警药品不良反应
ADR药品不良反应监测系统是一款智能化工具,用于监测和分析药品不良反应。该系统通过收集和分析病历、处方及实验室数据,快速识别潜在不良反应,提升用药安全性。系统采用Java开发,基于SpringBoot框架,前端使用Vue,具备数据采集、清洗、分析等功能模块,并能生成监测报告辅助医务人员决策。通过集成多种数据源并运用机器学习算法,系统可自动预警药品不良反应,有效减少药害事故,保障公众健康。
ADR智能监测系统源码,系统采用Java开发,基于SpringBoot框架,前端使用Vue,可自动预警药品不良反应
|
11天前
|
JavaScript 前端开发
【前端web入门第一天】03 综合案例 个人简介与vue简介
该网页采用“从上到下,先整体再局部”的制作思路,逐步分析并编写代码实现个人简介页面。内容涵盖尤雨溪的背景、学习经历及主要成就,同时介绍其开发的Vue.js框架特点。代码结构清晰,注重细节处理,如使用快捷键提高效率,预留超链接位置等,确保最终效果符合预期。
|
8天前
|
前端开发 JavaScript 开发者
Express.js与前端框架的集成:React、Vue和Angular的示例与技巧
本文介绍了如何将简洁灵活的Node.js后端框架Express.js与三大流行前端框架——React、Vue及Angular进行集成,以提升开发效率与代码可维护性。文中提供了详细的示例代码和实用技巧,展示了如何利用Express.js处理路由和静态文件服务,同时在React、Vue和Angular中构建用户界面,帮助开发者快速掌握前后端分离的开发方法,实现高效、灵活的Web应用构建。
29 3
|
7天前
|
JavaScript 前端开发 API
如何在前端开发中有效管理状态:React vs. Vue
在现代前端开发中,状态管理是一个关键因素,它直接影响到应用的性能和可维护性。React 和 Vue 是当前最流行的前端框架,它们在状态管理方面各有优势和劣势。本文将深入探讨 React 和 Vue 在状态管理中的不同实现,分析它们的优缺点,并提供实际应用中的最佳实践,以帮助开发者选择最适合他们项目的解决方案。
|
20天前
|
前端开发 Java Spring
Spring与Angular/React/Vue:当后端大佬遇上前端三杰,会擦出怎样的火花?一场技术的盛宴,你准备好了吗?
【8月更文挑战第31天】Spring框架与Angular、React、Vue等前端框架的集成是现代Web应用开发的核心。通过RESTful API、WebSocket及GraphQL等方式,Spring能与前端框架高效互动,提供快速且功能丰富的应用。RESTful API简单有效,适用于基本数据交互;WebSocket支持实时通信,适合聊天应用和数据监控;GraphQL则提供更精确的数据查询能力。开发者可根据需求选择合适的集成方式,提升用户体验和应用功能。
52 0
|
20天前
|
Android开发 iOS开发 C#
Xamarin:用C#打造跨平台移动应用的终极利器——从零开始构建你的第一个iOS与Android通用App,体验前所未有的高效与便捷开发之旅
【8月更文挑战第31天】Xamarin 是一个强大的框架,允许开发者使用单一的 C# 代码库构建高性能的原生移动应用,支持 iOS、Android 和 Windows 平台。作为微软的一部分,Xamarin 充分利用了 .NET 框架的强大功能,提供了丰富的 API 和工具集,简化了跨平台移动应用开发。本文通过一个简单的示例应用介绍了如何使用 Xamarin.Forms 快速创建跨平台应用,包括设置开发环境、定义用户界面和实现按钮点击事件处理逻辑。这个示例展示了 Xamarin.Forms 的基本功能,帮助开发者提高开发效率并实现一致的用户体验。
46 0
|
20天前
|
开发者 Android开发 iOS开发
Xamarin开发者的神器!揭秘你绝不能错过的插件和工具,让你的开发效率飞跃式提升
【8月更文挑战第31天】Xamarin.Forms 是一个强大的框架,让开发者通过单一共享代码库构建跨平台移动应用,支持 iOS、Android 和 Windows。使用 C# 和 XAML,它简化了多平台开发流程,保持一致的用户体验。本指南通过创建一个简单的 “HelloXamarin” 应用介绍 Xamarin.Forms 的基本功能和工作原理。首先配置 Visual Studio 开发环境,然后创建并运行一个包含标题、按钮和消息标签的示例应用,展示如何定义界面布局及处理按钮点击事件。这帮助开发者快速入门 Xamarin.Forms,提高跨平台应用开发效率。
30 0
|
21天前
|
JavaScript 前端开发 开发者
Vue.js的未来已来:掌握最新功能,驾驭前端开发的新浪潮!
【8月更文挑战第30天】Vue.js作为前端开发领域的明星框架,凭借其轻量级、响应式及组件化特性,深受全球开发者喜爱。它持续进化,引入新功能并优化性能,如提升渲染速度和减小打包体积,增强TypeScript支持,简化组件编写流程,进一步提升应用响应性和加载速度,改善开发者体验。活跃的社区和丰富的开源项目如“vuejs-challenges”推动其不断发展。未来,Vue.js将探索更多新特性,如宏和非虚拟DOM模式,巩固其在现代前端框架中的领先地位。
34 0
|
22天前
|
JavaScript 前端开发 测试技术
Vue.js开发者必看!Vue Test Utils携手端到端测试,打造无懈可击的应用体验,引领前端测试新风尚!
【8月更文挑战第30天】随着Vue.js的普及,构建可靠的Vue应用至关重要。测试不仅能确保应用质量,还能提升开发效率。Vue Test Utils作为官方测试库,方便进行单元测试,而结合端到端(E2E)测试,则能构建全面的测试体系,保障应用稳定性。本文将带你深入了解如何使用Vue Test Utils进行单元测试,通过具体示例展示如何测试组件行为;并通过Cypress进行E2E测试,确保整个应用流程的正确性。无论是单元测试还是E2E测试,都能显著提高Vue应用的质量,让你更加自信地交付高质量的应用。
34 0