如何用Node.js结合FFmpeg将Stream Chunks推流至RTMP服务器?
问题描述
我有一个ondata函数会持续输出MP4文件的Buffer分块数据,代码如下:
const ondata = (chunk) => { console.log(chunk) //输出 - Buffer 00 00 00 1c 66 74 79 70 64 61.......... Streaming(chunk,"rtmps://live-api-s.facebook.com:443/rtmp/FB-108963845678778") //Streaming函数见下方代码块 };
示例Buffer数据:
<Buffer 00 00 00 1c 66 74 79 70 64 61 73 68 00 00 00 00 69 73 6f 36 61 76 63 31 6d 70 34 31 00 00 02 ca 6d 6f 6f 76 00 00 00 6c 6d 76 68 64 00 00 00 00 df e2 ... 16334 more bytes> <Buffer 14 75 dd ea 7a 72 ef df 4f 24 cb 83 c3 85 a3 17 60 26 87 7a 74 0b 49 e4 6f 09 65 ae c8 6c 7d 0e 02 b1 6b 4a df 63 61 ab d9 44 22 62 3c f6 0d 8c c9 b7 ... 16334 more bytes>
我想把这些Chunk数据通过FFmpeg推流到RTMP服务器,写了如下Streaming函数,但运行后无任何效果:
const child_process = require('child_process'); var Streaming = function (chunk, Rtmp_Uri) { ffmpeg_process = child_process.spawn('ffmpeg', [ '-re', '-i', `${chunk}`, //Buffer 00 00 00 1c 66 74 79 70 64 61.......... '-stream_loop','-1', '-f', 'flv', '-profile:v', 'baseline', '-pix_fmt', 'yuv420p', '-c:a', 'aac', '-acodec', 'mp3', '-ar', '44100', '-b:a', '128k', '-vcodec', 'libx264', '-bufsize', '600k', '-vb', '400k', '-maxrate', '3000k', '-preset', 'ultrafast', '-r', '30', '-g', '30', Rtmp_Uri //"rtmps://live-api-s.facebook.com:443/rtmp/FB-1089638456787788-0..AbzJ3chy775fhjjjkW2"; ]); return ffmpeg_process; }
请问如何实现将Chunk数据推流至RTMP服务器?或有哪些可用的FFmpeg命令?
问题分析与解决方案
核心错误点
- FFmpeg输入方式错误:直接把Buffer转成字符串传给
-i参数,FFmpeg会将其当作文件路径读取,而非解析Buffer数据。 - 重复创建进程:每次
ondata调用都新建FFmpeg进程,既无效又会导致资源泄漏。 - 参数冲突:
-c:a aac与-acodec mp3同时设置,音频编码逻辑冲突;-stream_loop -1对实时流式输入无效,还会打乱推流逻辑。
正确实现方案
应启动单个FFmpeg进程,通过标准输入(stdin)持续将Buffer分块写入进程,让FFmpeg从stdin读取数据流并推流到RTMP服务器。
步骤1:全局初始化FFmpeg进程(仅执行一次)
const child_process = require('child_process'); // 全局维护FFmpeg进程实例,避免重复创建 let ffmpegProcess = null; function initStreaming(rtmpUri) { if (ffmpegProcess) return; ffmpegProcess = child_process.spawn('ffmpeg', [ '-re', '-i', 'pipe:0', // 指定从标准输入读取数据 '-f', 'flv', '-profile:v', 'baseline', '-pix_fmt', 'yuv420p', '-c:a', 'aac', // 统一用AAC编码,适配多数RTMP服务器 '-ar', '44100', '-b:a', '128k', '-vcodec', 'libx264', '-bufsize', '600k', '-b:v', '400k', // 替换非标准参数-vb为-b:v '-maxrate', '3000k', '-preset', 'ultrafast', '-r', '30', '-g', '60', // 关键帧间隔设为2倍帧率,更适配直播场景 rtmpUri ]); // 监听FFmpeg输出,便于调试排查问题 ffmpegProcess.stdout.on('data', (data) => { console.log(`FFmpeg stdout: ${data}`); }); ffmpegProcess.stderr.on('data', (data) => { console.error(`FFmpeg stderr: ${data}`); }); ffmpegProcess.on('close', (code) => { console.log(`FFmpeg进程退出,代码: ${code}`); ffmpegProcess = null; // 进程关闭后重置实例 }); }
步骤2:在ondata中持续写入数据到FFmpeg
const ondata = (chunk) => { if (!ffmpegProcess) { // 首次调用时初始化推流进程 const rtmpUri = "rtmps://live-api-s.facebook.com:443/rtmp/FB-108963845678778"; initStreaming(rtmpUri); } // 将Buffer写入FFmpeg标准输入 ffmpegProcess.stdin.write(chunk, (err) => { if (err) { console.error('写入FFmpeg失败:', err); } }); };
关键说明
pipe:0:告诉FFmpeg从标准输入读取数据,这是处理流式Buffer的正确方式。- 单进程复用:仅创建一次FFmpeg进程,持续写入数据,避免资源浪费。
- 参数优化:移除冲突的音频编码参数,调整关键帧间隔,使用标准FFmpeg参数格式。
- 错误监听:添加stdout/stderr监听,方便排查推流中的问题(如FFmpeg报错、网络异常等)。
本地调试命令
若需验证FFmpeg命令正确性,可先在本地测试静态文件推流:
ffmpeg -re -i input.mp4 -f flv -profile:v baseline -pix_fmt yuv420p -c:a aac -ar 44100 -b:a 128k -vcodec libx264 -bufsize 600k -b:v 400k -maxrate 3000k -preset ultrafast -r 30 -g 60 rtmps://your-rtmp-url
内容的提问来源于stack exchange,提问作者ashutosh karn
相关产品推荐
相关产品推荐

