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" });
  }
});
相关推荐
小镇程序员10 分钟前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐12 分钟前
前端图像处理(一)
前端
程序猿阿伟19 分钟前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
疯狂的沙粒21 分钟前
对 TypeScript 中函数如何更好的理解及使用?与 JavaScript 函数有哪些区别?
前端·javascript·typescript
瑞雨溪30 分钟前
AJAX的基本使用
前端·javascript·ajax
新知图书30 分钟前
Rust编程与项目实战-模块std::thread(之一)
开发语言·后端·rust
力透键背32 分钟前
display: none和visibility: hidden的区别
开发语言·前端·javascript
程楠楠&M43 分钟前
node.js第三方Express 框架
前端·javascript·node.js·express
weiabc43 分钟前
学习electron
javascript·学习·electron
盛夏绽放1 小时前
Node.js 和 Socket.IO 实现实时通信
前端·后端·websocket·node.js