Node.js中使用FFmpeg Spawn将MP4转HLS时,如何实现TS分段输出流与stdio流的管道传输?
Node.js中使用FFmpeg Spawn将MP4转HLS时,如何实现TS分段输出流与stdio流的管道传输?
我最近在Node.js里搭建一个自动化媒体处理流水线,流程是先压缩MP4文件,拿到压缩后的文件Buffer,再传给另一个FFmpeg命令,把它转成HLS格式的.m3u8文件。
但现在遇到了一个棘手的问题:没法把生成的TS分段文件的数据流直接通过管道传输到云存储——毕竟这是云函数环境,根本不能把文件存到磁盘上。
目前的困境是:
- 要么只能在内存目录里生成TS分段文件,再基于它们生成播放清单;
- 要么就得到一个把TS二进制数据和
.m3u8清单数据混在一起的大Buffer。
本地环境里存磁盘的话一切正常,但云函数完全走不通。
我现在用的FFmpeg转换命令是这样的:
const ffmpeg = spawn( "ffmpeg", [ "-i", `pipe:0`, "-codec", "copy", "-start_number", "0", "-hls_time", "10", "-hls_list_size", "0", "-f", "hls", "-hls_flags", "delete_segments", "pipe:1", ], { stdio: ["pipe", "pipe", "pipe", "pipe"] } );
我是把输入Buffer写到FFmpeg的stdin里的。试了各种方法后发现,只有加上delete_segments这个flag,才能避免生成物理TS文件,同时还不会触发EPIPE错误(之前直接把分段输出到stdout时一直报这个错)。之后我监听stdout的流,得到的是一个包含所有TS二进制数据和.m3u8清单数据的大Buffer——清单是UTF-8编码的,我能把它解析出来。
哪怕我手动把TS的Buffer解析出来上传成Blob,再把云存储的下载URL替换到清单里对应TS文件的位置,整个HLS流还是没法正常工作。
如果有需要,我可以补充更多细节~
更新:找到可行解决方案
后来我找到了一个靠谱的解决办法,和之前收到的一条评论思路一致,分享给大家:
- 合并FFmpeg命令:不再启动多个FFmpeg子进程,而是把压缩参数和HLS转换参数合并到一个命令里,这样就不用手动把Buffer存在内存再传给下一个FFmpeg进程了。
- 手动配置编码参数:我手动设置了视频的比特率、最大缓冲区大小,同时重新编码了音频。之前试过自适应比特率流,不过我的场景暂时用不上,以后需要的话再加也没问题。
- 实时监听并处理TS文件:在FFmpeg运行的时候,我用Chokidar做了文件监听——每生成一个TS文件,就立刻上传到云存储,然后删除本地文件,这样能最大限度减少云环境里的内存占用。
- 替换清单中的文件路径:我把每个TS文件对应的云存储下载URL存在一个Map里,key就是分段文件名。等清单文件生成后,再把里面的分段文件名逐个替换成对应的下载URL。
如果有人想看具体的代码或者完整的FFmpeg命令,可以告诉我~
备注:内容来源于stack exchange,提问作者Jacob L
相关产品推荐
相关产品推荐

