如何为 n8n 安装并使用 FFmpeg 实现音频格式转换

本教程介绍如何为 n8n 自定义 Docker 镜像添加 FFmpeg,实现语音合成后自动将 PCM 格式音频转换为 WAV 或 MP3 格式。适用于基于 Gemini API 或任何音频处理场景的自动化需求。

阅读时长: 6 分钟
共 2940字
作者: eimoon.com

背景说明

在使用 n8n 构建自动化流程时,越来越多场景需要处理音视频格式,例如使用 Gemini 接口生成语音后,返回的是 .pcm 原始音频格式。此时我们通常希望将其转换为 .wav 或 .mp3,以便播放、下载或嵌入其他平台。

此时,强大的 FFmpeg 就是你的救星!通过自定义 n8n 的 Docker 环境来集成 FFmpeg,你就能解锁音频转码、格式转换、甚至视频合成等高级技能。这篇指南将手把手教你如何在 n8n 中引入并使用 FFmpeg,让你的自动化流程如虎添翼。

准备工作

在开始之前,请确保你已经:

  • 安装了 Docker 和 Docker Compose。
  • 对 n8n 和 Docker 的基本操作有所了解。

为什么不能直接在 Docker Compose 中添加 FFmpeg 服务

有些用户可能会考虑通过在 docker-compose.yml 中添加一个 ffmpeg 服务(例如使用 jrottenberg/ffmpeg 镜像)来实现音频处理。但在 n8n 的使用场景中,这种方式并不适用,原因如下:

  1. n8n 无法跨容器调用 ffmpeg 命令: n8n 的 Execute Command 节点在容器内部运行命令,默认无法访问其他容器的可执行文件。即使两个容器共享 volume,命令也无法跨容器调用。
  2. 性能和效率低下: 为了让 n8n 使用另一个容器中的 ffmpeg,你需要配置复杂的容器间通信或远程执行机制(如 gRPC、HTTP API),这远比在同一容器中安装 ffmpeg 更麻烦、效率更低。
  3. 维护复杂度增加: 多容器协调会带来额外的维护成本,且增加出错概率。尤其在 n8n 自动化流程中,稳定性比拆分服务更重要。 因此,将 FFmpeg 安装进 n8n 容器本身,是当前最直接、高效、兼容性最佳的做法。

第一步:定制你的 n8n Docker 镜像 (Dockerfile)

n8n 官方镜像默认不包含 FFmpeg。我们需要创建一个自定义的 Dockerfile,在官方镜像的基础上添砖加瓦。

在你的 n8n 项目根目录下 (通常是 docker-compose.yml 所在的目录),新建一个名为 Dockerfile 的文件。

将以下内容复制到 Dockerfile 中:

# 基于你正在使用的 n8n 官方 Alpine 镜像版本 以1.97.0 为例
FROM n8nio/n8n:1.97.0

# 切换到 root 用户以安装软件包
USER root

# Alpine Linux 使用 apk 包管理器安装 ffmpeg
# --no-cache 选项表示不保留下载的包索引,以减小镜像体积
RUN apk add --no-cache ffmpeg

# 切换回 n8n 默认的非 root 用户 node,增强安全性
USER node

第二步:更新 Docker Compose 配置

接下来,我们需要告诉 Docker Compose 使用我们刚刚创建的 Dockerfile 来构建 n8n 服务,而不是直接拉取官方镜像。

编辑你的 docker-compose.yml 文件,找到 services -> n8n 部分,将 image: 指令替换为 build: 指令:


services:
  n8n:
    build: # <--- 修改这里
      context: . # Dockerfile 所在的目录,"." 代表当前目录
      dockerfile: Dockerfile # 指定 Dockerfile 文件名
    container_name: n8n
    restart: always
    ports:
      - "5678:5678"
    env_file:
      - .env
    environment:
      - N8N_HOST=${N8N_HOST}
      - N8N_PORT=${N8N_PORT}
      - N8N_PROTOCOL=${N8N_PROTOCOL}
      - WEBHOOK_URL=${WEBHOOK_URL}
      - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
      - N8N_RUNNERS_ENABLED=true 
    volumes:
      - n8n_data:/home/node/.n8n
      - ./local-files:/files

volumes:
  n8n_data: # n8n 的核心数据,如工作流、凭证等

重点改动解释:

  • build: 指示 Docker Compose 从本地构建镜像。
  • context: .:Docker 构建上下文的路径。. 表示 docker-compose.yml 文件所在的当前目录。Docker 会将此目录下的文件(包括 Dockerfile)发送给 Docker 守护进程。
  • dockerfile: Dockerfile:指定用于构建的 Dockerfile 文件名。

第三步:构建镜像并启动 n8n

万事俱备,只欠东风!在你的项目根目录下打开终端,执行以下命令:

构建自定义镜像:

docker compose build

这个过程可能需要几分钟,Docker 会下载基础镜像并执行 Dockerfile 中的指令。

启动 n8n 服务:

docker compose up -d

-d 参数表示在后台运行。

现在,你的 n8n 实例已经拥有了 FFmpeg 的能力!

第四步:在 n8n 工作流中使用 FFmpeg

拥有了 FFmpeg,我们就可以在 n8n 工作流中大展拳脚了。通常,一个音频转换流程包含以下节点:

Code 节点 (可选,但常用):

功能: 如果你的音频数据是 Base64 编码的字符串 (很多 API 返回的就是这种格式),你需要用此节点将其解码为二进制数据。

示例代码:

// 假设上一个节点输出的 Base64 音频数据在 'base64Audio' 字段
const base64Data = $input.item.json.base64Audio; 
if (!base64Data) {
  throw new Error("Base64 audio data not found!");
}
const binaryData = Buffer.from(base64Data, 'base64');

// 返回 n8n 期望的二进制数据结构
return [{
  // 你可以在 json 中保留一些元数据
  json: { 
    fileName: 'input.pcm', 
    originalFormat: 'pcm_s16le', // 记录原始PCM格式
    sampleRate: 24000,
    channels: 1
  }, 
  binary: {
    // 'data' 属性会被 Write Binary File 节点识别
    data: binaryData 
  }
}];

Write Binary File 节点:

功能: 将上一步得到的二进制音频数据(.pcm 原始数据)写入到容器内的临时文件。FFmpeg 需要从文件读取输入。

配置:

  • File Name: {{ $json.fileName || 'input.pcm' }} (可以从上个节点动态获取)
  • Binary Property: data (Code 节点输出的二进制数据属性名)

Execute Command 节点:

功能: 调用 FFmpeg 执行转换命令。

配置:

  • Command: ffmpeg
  • Arguments: -f s16le -ar 24000 -ac 1 -i /tmp/input.pcm /tmp/output.wav

示例完整命令行:

ffmpeg -f s16le -ar 24000 -ac 1 -i /tmp/input.pcm /tmp/output.wav

参数详解 :

  • -f s16le: 指定输入文件的格式 (Format)。s16le 代表“有符号16位小端PCM (signed 16-bit little-endian PCM)”。你需要根据你的 PCM 源的具体格式来设置。 例如,Gemini API 返回的可能是 24kHz, 16-bit linear PCM。常见的 PCM 格式还有 u8 (无符号8位), s32le (有符号32位小端)等。如果这个参数与实际PCM数据不符,转换会失败或产生噪音!
  • -ar 24000: 指定输入文件的采样率 (Audio Rate)。例如 24000 Hz (24kHz)。必须与你的 PCM 源采样率一致。 常见的有 16000, 44100, 48000。
  • -ac 1: 指定输入文件的声道数 (Audio Channels)。1 代表单声道 (Mono),2 代表立体声 (Stereo)。必须与你的 PCM 源声道数一致。
  • -i /tmp/input.pcm: 指定输入文件名和路径。
  • /tmp/data/output.wav: 指定输出文件名和路径以及期望的格式 (通过扩展名 .wav FFmpeg 通常能自动识别)。

转换为 MP3 示例:

ffmpeg -f s16le -ar 24000 -ac 1 -i /tmp/input.pcm -codec:a libmp3lame -qscale:a 2 /tmp/data/output.mp3
  • -codec:a libmp3lame: 指定使用 libmp3lame 编码器来输出 MP3。
  • -qscale:a 2: 设置可变比特率编码的质量。数值越小,质量越高,文件越大。0-3 通常是高质量范围。

💡 如何确定PCM参数? 查阅生成PCM的API(如Gemini)的文档,它们通常会说明输出音频的格式、采样率和声道数。

Read Binary File 节点:

功能: 读取转换后的音频文件 (例如 output.wav 或 output.mp3),以便在工作流中继续使用,例如上传到云存储、作为API响应返回或发送给其他服务。

配置:

  • File Path: /tmp/output.wav (或 output.mp3)
  • Property Name: data (读取到的二进制数据会放在这个属性下)

使用 /tmp 存储的推荐建议

在本教程中,我们默认将中间音频文件(如 input.pcm、output.wav)写入到容器的 /tmp 目录中。这种做法适合 临时处理并上传的场景,例如你将在后续流程中将音频上传到 Google Drive、S3、Telegram 等。

但如果你希望将音频文件 长期保留、复用或供外部访问,则推荐使用挂载的持久目录,例如 /home/node/data/audio/,并在 docker-compose.yml 中挂载宿主机目录,例如:

volumes:
  - ./n8n_files/audio:/home/node/data/audio

这样可以确保文件不会因容器重启而丢失,也方便手动管理和备份。

常见问题与解答

Q: 如何确认 FFmpeg 是否安装成功?

A: 在 n8n 容器内执行命令。首先找到你的 n8n 容器名或ID (可以用 docker ps 查看),然后:

docker exec -it <your_n8n_container_name_or_id> ffmpeg -version

如果看到 FFmpeg 的版本信息,说明安装成功。

Q: FFmpeg 命令执行失败怎么办?

A:

  • 仔细检查 Execute Command 节点的输出,FFmpeg 通常会给出详细的错误信息。
  • 核对 -f, -ar, -ac 参数 是否与你的输入 PCM 文件完全匹配。这是最常见的错误原因。
  • 检查文件路径 是否正确,确保 FFmpeg 能找到输入文件,并且有权限写入输出文件。
  • 尝试在容器内手动执行 ffmpeg 命令进行调试:
docker exec -it <container_name> bash
cd /home/node/data
# 然后执行你的 ffmpeg 命令

Q: 容器重启后 /tmp 或 /home/node/data 内的文件丢失了怎么办?

A:

  • 对于 /tmp:这是正常的,/tmp 目录通常是临时的,容器重启后内容会丢失。
  • 对于 /home/node/data/ (如果你按照上面 docker-compose.yml 的建议挂载了 n8n_local_files):
volumes:
  - ./n8n_local_files:/home/node/data

这种方式下,/home/node/data 目录的内容会持久化到你宿主机的 ./n8n_local_files 文件夹中,容器重启不会丢失。这种方式非常适合调试和管理临时文件,但请注意,长期运行可能导致文件持续积累,占用磁盘空间,建议定期清理或设置自动清理策略。

总结

通过自定义 Dockerfile 并集成 FFmpeg,你的 n8n 工作流在音视频处理方面将获得质的飞跃。无论是语音合成后的格式转换、简单的音频编辑,还是更复杂的媒体处理任务,FFmpeg 都能为你提供强大的支持。

如果你正在构建与语音相关的自动化应用,不妨为你的 n8n 环境加上 FFmpeg 吧!


关注我获取更多资讯

📬 关注我获取更多资讯

公众号
📢 公众号
个人号
💬 个人号
使用 Hugo 构建
主题 StackJimmy 设计