Quiet
  • 主页
  • 归档
  • 分类
  • 标签
  • 链接
  • 关于我

bajiu

  • 主页
  • 归档
  • 分类
  • 标签
  • 链接
  • 关于我
Quiet主题
  • NodeJs
  • Electron
  • 流媒体

electron中使用FFmpeg处理流媒体

bajiu
前端

2024-05-19 12:33:00

fluent-ffmpeg

鉴于ffmpeg的原生命令行比较复杂, fluent-ffmpeg 提供了一个有好的API用于和FFmpeg进行交互,主要就是简化了一些命令行调用,让NodeJs相关应用可以更容易的处理音视频,以下是一些基本用法:

1.视频转码转格式

ffmpeg('input.mp4')
  .output('output.mp4')
  .videoBitrate('1000k') // 设置视频码流
  .fps(30) // 设置帧率
  .on('end', () => {
    console.log('转换完成');
  })
  .on('error', (err) => {
    console.error('发生错误:', err);
  })
  .run();

2.调整码流和帧率

ffmpeg('input.mp4')
  .output('output.mp4')
  .videoBitrate('1000k') // 设置视频码流
  .fps(30) // 设置帧率
  .on('end', () => {
    console.log('转换完成');
  })
  .on('error', (err) => {
    console.error('发生错误:', err);
  })
  .run();

3.提取音频

ffmpeg('input.mp4')
  .output('output.mp3')
  .audioCodec('libmp3lame') // 设置音频编码
  .on('end', () => {
    console.log('音频提取完成');
  })
  .on('error', (err) => {
    console.error('发生错误:', err);
  })
  .run();

4.合并视频

ffmpeg()
  .input('video1.mp4')
  .input('video2.mp4')
  .output('output.mp4')
  .on('end', () => {
    console.log('合并完成');
  })
  .on('error', (err) => {
    console.error('发生错误:', err);
  })
  .run();

5.事件处理

  • on('end'):在转换完成时触发。
  • on('error'):在转换出错时触发,可以获取错误信息。

ffmpeg-static

ffmpeg-static 提供了 FFmpeg 的静态可执行文件,可以轻松地在跨平台应用中使用。下面是如何在一个项目中集成 ffmpeg-static:

const ffmpeg = require('fluent-ffmpeg');
const ffmpegPath = require('ffmpeg-static');

// 设置 FFmpeg 路径
ffmpeg.setFfmpegPath(ffmpegPath);

const inputFile = 'input.mp4';  // 输入文件
const outputFile = 'output.mp4'; // 输出文件

ffmpeg(inputFile)
  .output(outputFile)
  .on('end', () => {
    console.log('转换完成!');
  })
  .on('error', (err) => {
    console.error('错误: ' + err.message);
  })
  .run();

优点:

  • 多平台应用:开发一个需要 FFmpeg 的跨平台应用,使用 ffmpeg-static 可以避免在每个平台上手动配置 FFmpeg。
  • 快速原型开发:快速测试和原型开发时,可以立即获得 FFmpeg 的功能而无需复杂的设置。

不足:

  • 包大小:由于 ffmpeg-static 包含了多个平台的 FFmpeg 可执行文件,包的大小可能会比不使用该库要大。
  • 功能限制:虽然 ffmpeg-static 提供了 FFmpeg 的可执行文件,但它并不提供 FFmpeg 的所有功能或完整的文档。你仍然需要参考 FFmpeg 的官方文档以了解可用的命令和选项。

举个栗子

主进程中使用 fluent-ffmpeg 处理视频转换,并通过 IPC 发送进度和结果。

const { app, BrowserWindow, ipcMain, dialog } = require('electron');
const ffmpeg = require('fluent-ffmpeg');
const path = require('path');
const ffmpegPath = require('ffmpeg-static');

function createWindow() {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      contextIsolation: true,
      enableRemoteModule: false,
    },
  });

  win.loadFile('index.html');
}

// 打开文件对话框并返回选择的文件路径
ipcMain.handle('dialog:openFile', async () => {
  const result = await dialog.showOpenDialog({
    properties: ['openFile'],
    filters: [{ name: 'Videos', extensions: ['mp4', 'avi', 'mov'] }],
  });
  return result.filePaths[0];
});

// 处理视频转换
ipcMain.handle('convert-video', async (event, inputFile, outputFile) => {
  return new Promise((resolve, reject) => {
    ffmpeg(inputFile)
      .setFfmpegPath(ffmpegPath) // 设置 FFmpeg 路径
      .output(outputFile)
      .on('end', () => {
        resolve('转换成功!');
      })
      .on('error', (err) => {
        reject(`转换失败: ${err.message}`);
      })
      .run();
  });
});

app.whenReady().then(createWindow);

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

用户界面

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Video Converter</title>
</head>
<body>
  <h1>视频转换</h1>
  <button id="selectFile">选择视频文件</button>
  <input type="text" id="outputFile" placeholder="输出文件名(包括格式)" />
  <button id="convert">转换视频</button>
  <script src="renderer.js"></script>
</body>
</html>

渲染进程IPC

const { ipcRenderer } = require('electron');

document.getElementById('selectFile').addEventListener('click', async () => {
  const filePath = await ipcRenderer.invoke('dialog:openFile');
  document.getElementById('outputFile').value = filePath.replace(/\.[^/.]+$/, '.mp4'); // 默认输出为 mp4
});

document.getElementById('convert').addEventListener('click', async () => {
  const inputFile = document.getElementById('outputFile').value;
  const outputFile = document.getElementById('outputFile').value.replace(/\.[^/.]+$/, '.mp4');

  try {
    const message = await ipcRenderer.invoke('convert-video', inputFile, outputFile);
    alert(message);
  } catch (error) {
    alert('错误: ' + error);
  }
});

具体 fluent-ffmpeg 里有没有调用新进程这个,有时间或者有业务需要看看源码就知道了,因为总感觉需要 child_process 开个进程心里才稳当。

上一篇

NodeJs之事件循环以及I/O多路复用

下一篇

NodeJs之Cluster

©2024 By bajiu.