如何获取FFmpeg concat播放列表中当前正在播放的文件?
嘿,这个需求我之前帮别人处理过,针对你用Alpine Docker里的FFmpeg通过concat列表推流到YouTube的场景,有几个实用的办法可以搞定当前播放文件的检测:
从FFmpeg日志实时提取文件名
FFmpeg在切换到concat列表里的下一个文件时,会在日志里输出类似Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/path/to/current-file.mp4':的信息。我们可以把FFmpeg的错误输出(日志默认打在stderr)重定向到管道,用文本过滤工具实时抓取文件名。
举个实际的命令例子,你可以把原FFmpeg命令改成这样:
ffmpeg -loglevel info -f concat -i mylist.txt [你的推流参数] 2>&1 | grep -oP "from '\K[^']+"
这里-loglevel info是确保FFmpeg输出文件打开的日志信息,2>&1把stderr转成stdout让grep能捕获,grep -oP用正则精准提取单引号里的文件路径。每次切换文件时,这个命令就会打印出当前的文件名,你可以把这个输出直接接到你的消息发送脚本里,比如每收到一行新的文件名就触发通知。
监控FFmpeg进程打开的文件
在Linux系统里,我们可以通过进程的文件描述符或者lsof工具,查看FFmpeg当前正在读取的视频文件,这个方法也很靠谱:
- 先找到FFmpeg的进程ID(PID),用
ps aux | grep ffmpeg就能查到。 - 用proc文件系统查看(无需额外安装工具):
直接查看FFmpeg进程的文件描述符链接,过滤掉管道、套接字这些无关项,剩下的就是正在播放的视频文件:ls -l /proc/<FFMPEG_PID>/fd | grep -v "pipe" | grep -v "socket" | awk '{print $NF}' - 用lsof工具(需额外安装):
如果你习惯用lsof,先在Alpine容器里安装:apk add lsof,然后运行:lsof -p <FFMPEG_PID> | grep -E "REG" | grep -v "mylist.txt" | awk '{print $9}'
你可以写个简单的shell脚本,定时(比如每2秒)执行上述命令,对比上次的文件名结果,如果发现变化就发送消息通知。
提前计算时长(不推荐,仅供参考)
如果你能提前拿到每个视频文件的时长,可以先把mylist.txt里的文件和时长一一对应,记录推流开始的时间,通过计算已播放时长来推算当前文件。但这个方法有个明显的缺陷:如果FFmpeg处理速度有波动(比如推流卡顿、不同文件编码导致处理时间变化),推算结果会不准,所以除非你对精度要求不高,否则不建议用这个。
备注:内容来源于stack exchange,提问作者Rambalac

