背景说明
在使用 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 的使用场景中,这种方式并不适用,原因如下:
- n8n 无法跨容器调用 ffmpeg 命令: n8n 的
Execute Command
节点在容器内部运行命令,默认无法访问其他容器的可执行文件。即使两个容器共享 volume,命令也无法跨容器调用。 - 性能和效率低下: 为了让 n8n 使用另一个容器中的 ffmpeg,你需要配置复杂的容器间通信或远程执行机制(如 gRPC、HTTP API),这远比在同一容器中安装 ffmpeg 更麻烦、效率更低。
- 维护复杂度增加: 多容器协调会带来额外的维护成本,且增加出错概率。尤其在 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 吧!
关注我获取更多资讯
📬 关注我获取更多资讯

