video素材格式转换--mp4转webm(vue3+Nodejs)

总体实现使用ffmpeg


自动化demo实现 vue3+Nodejs+ffmpeg

一、官网下载ffmpeg

https://ffmpeg.org/

1-1选择对应系统下载

1-2下载完成后配置环境变量

1-2-1将下载文件的bin目录配置到环境变量中

例如:D:\ffmpeg\bin

1-3测试ffmpeg是否安装成功

复制代码
ffmpeg -version

如图 证明安装成功!!!!

二、手动使用命令转video格式

cmd 打开视频所在目录

等待完成即可!

三、自动化demo

工作中 有比较大的素材量 可直接上传文件等待转type即可 完成后下载视频

代码示例:

3-1 vue3

复制代码
<template>
  <div>
    <a-upload
      name="file"
      action="http://localhost:3000/uploadWebm"
      @change="handleChange"
    >
      <a-button>
        <upload-outlined></upload-outlined>
        请上传视频
      </a-button>
    </a-upload>
    <video :src="url" controls v-if="url"></video>
  </div>
</template>
<script setup>
import { ref } from "vue";
import { message } from "ant-design-vue";
import { UploadOutlined } from "@ant-design/icons-vue";

const url = ref("");
const checkTaskInterval = ref(null); // 将定时器ID存储在响应式引用中

const checkTaskStatus = async () => {
  try {
    const response = await fetch("http://localhost:3000/status", {
      method: "GET",
    });
    if (response.ok) {
      const data = await response.json();
      console.log(data.event, "data.event");
      if (data.event === "end") {
        console.log("endend");
        clearInterval(checkTaskInterval.value); // 使用响应式引用的值来清除定时器
        checkTaskInterval.value = null; // 将响应式引用的值设置为null
        url.value = data.data.url;
      } else if (data.event === "error") {
        clearInterval(checkTaskInterval.value);
        checkTaskInterval.value = null;
        message.error("上传失败:" + data.data);
      }
    }
  } catch (error) {
    message.error("上传失败");
    console.error("上传失败:", error);
    clearInterval(checkTaskInterval.value);
    checkTaskInterval.value = null;
  }
};

const handleChange = async (info) => {
  console.log(info);
  // 清除之前的定时器(如果有)
  if (checkTaskInterval.value) {
    clearInterval(checkTaskInterval.value);
  }
  checkTaskInterval.value = setInterval(() => {
    checkTaskStatus();
  }, 3000);
};
</script>
<style lang="less" scoped>
</style>

3-2 Nodejs

3-2-1安装 fluent-ffmpeg

复制代码
npm install fluent-ffmpeg --save

3-2-2 完整代码示例

复制代码
var express = require('express');
var router = express.Router();
var multiparty = require('multiparty');
const multer = require('multer')
const upload = multer({ dest: 'upload/' })
const { execFile } = require('child_process');
const path = require('path');
const fs = require('fs');
const ffmpeg = require('fluent-ffmpeg');
const ffmpegPath = path.join('d:', 'ffmpeg', 'bin', 'ffmpeg.exe');//ffmpeg.exe的路径
const iconv = require('iconv-lite'); // 用于处理中文路径
ffmpeg.setFfmpegPath(ffmpegPath);

//video转webm
router.post('/uploadWebm', upload.single('file'), (req, res) => {
  const file = req.file;
  const srcPath = file.path;
  console.log(file.originalname, "file.originalname");

  const originalNameBuffer = Buffer.from(file.originalname, 'binary');
  const utf8Name = iconv.decode(originalNameBuffer, 'UTF-8'); // 将文件名从二进制转换为 UTF-8 编码
  const dstPath = path.join('upload', `${path.basename(utf8Name, path.extname(utf8Name))}.webm`);
  console.log(dstPath, "dstPath");
  // 初始化状态信息
  statusInfo = {
    event: "start",
    data: `Started processing ${file.originalname}`,
    finished: false
  };

  ffmpeg(srcPath)
  .on('start', (commandLine) => {
    statusInfo.event = "start";
    statusInfo.data = commandLine;
  })
  .on('progress', (progress) => {
    statusInfo.event = "progress";
    statusInfo.data = progress;
  })
  .on('error', (err) => {
    statusInfo.event = "error";
    statusInfo.data = err;
    statusInfo.finished = true;
    res.status(500).send({ code: 500, event: "error", data: err });
    fs.unlinkSync(srcPath);
  })
  .on('end', () => {
    statusInfo.event = "end";
    statusInfo.data = {message: "Processing finished", url: `http://localhost:3000/upload/${path.basename(dstPath)}`};
    statusInfo.finished = true;
    fs.unlinkSync(srcPath);
  })
  .addOption('-c:v libvpx-vp9')
  .addOption('-c:a libopus')
  .addOption('-b:v 1M')
  .addOption('-b:a 128k')
  .toFormat('webm')
  .save(dstPath);
});

// 客户端轮询的接口
router.get('/status', (req, res) => {
  const filename = req.params.filename;
  if (statusInfo && !statusInfo.finished) {
    res.send({ code: 200, event: statusInfo.event, data: statusInfo.data });
  } else if (statusInfo) {
    res.send({ code: 200, event: statusInfo.event, data: statusInfo.data });
  } else {
    res.status(404).send({ code: 404, message: "File not found" });
  }
});
相关推荐
敲敲了个代码几秒前
11月3-5年Web前端开发面试需要达到的强度
前端·vue.js·学习·react.js·面试·职场和发展·web
曼巴UE510 分钟前
UE5 C++ JSON 最简单,麻烦的方式,直接读存(一)
java·服务器·前端
半桶水专家13 分钟前
Vue Pinia 插件详解
前端·javascript·vue.js
吃饺子不吃馅16 分钟前
面试官:JWT、Cookie、Session、Token有什么区别?
前端·设计模式·面试
IT_陈寒34 分钟前
React 19新特性实战:5个提升开发效率的技巧与避坑指南
前端·人工智能·后端
mzlogin35 分钟前
解决访问 https 网站时,后端重定向或获取 URL 变成 http 的问题
java·后端·nginx
丙寅1 小时前
微信小程序反编译遇到 TypeError: _typeof3 is not a function
开发语言·javascript·ecmascript
青衫码上行1 小时前
【Java Web学习 | 第十篇】JavaScript(4) 对象
java·开发语言·前端·javascript·学习
CodeLongBear1 小时前
第一次搭建个人主页+GitHub部署全记录:HTML/CSS/JS前端实现+留言板踩坑
前端·个人页面·部署上线
by__csdn1 小时前
Node各版本的区别,如何选择版本以及与NPM版本对照关系
前端·npm·node.js