使用命名管道时如何防止死锁?

Posted

技术标签:

【中文标题】使用命名管道时如何防止死锁?【英文标题】:How to prevent a deadlock when using named pipes? 【发布时间】:2011-11-02 05:10:23 【问题描述】:

我有一个将原始视频数据和音频数据写入文件的捕获过程。像这样的东西将捕获 100 帧数据。

./capture -n 100 -f video_file -a audio_file

给我一​​个 768000 字节的音频文件和一个 414720000 字节的视频文件。这些似乎按预期加起来:

414720000 == 1920x1080(像素/帧)* 2(字节/像素)* 100(帧) 768000 == 48k (Hz) * 2(字节/样本)* 2 通道 * 100(帧)/25(帧/秒)

然后当我像

这样对数据进行编码时

ffmpeg -i audio_file -i video_file out.flv

我确实得到了一个带声音的可播放视频(实际上我在命令行中有更多的东西,但这些是这个问题的重要部分)

现在,我实际上想要一个实时流,而不是一个文件,我可以只用这样的视频来做这个:

./capture -f /dev/stdout | ffmpeg -i - udp://127.0.0.1:10000

我在 udp 上获得了一个没有音频广播的视频流,并且我能够正常接收和播放该流。但是当我想在图片中添加音频时,我遇到了一些麻烦。我想我不能同时在stdout 上发送它们,我也不能使用stderr,因为捕获过程已经在上面聊天了。所以我试图用这样的命名管道来做到这一点:

mkfifo audio_pipe
mkfifo video_pipe
ffmpeg -i audio_pipe -i video_pipe out.flv &
./capture -f video_pipe -a audio_pipe

但它不起作用,似乎一切都陷入了僵局。我已经测试了只运行./capture -f video_file -a audio_file,然后打开两个新的shell 并执行cat video_file > /dev/nullcat audio_file > /dev/null,一旦两只猫都在运行这会解除捕获过程的阻塞,所以看起来写入管道没有问题。我看了一眼捕获代码的来源,它的工作方式是使用来自更深层 API 的“帧到达”回调,然后按该顺序(它是阻塞的)写入视频帧和音频数据。我不知道 ffmpeg 是做什么的,它是按任意顺序顺序读取输入视频文件或音频文件,还是在线程中同时读取它们。我尝试将订单更改为ffmpeg -i video_pipe -i audio_pipe out.flv,但不幸的是一切仍然锁定。仅对视频数据使用一个命名管道可以正常工作。

如何解决我的问题?一旦我了解了避免阻塞问题的最佳方法,我将使用 python 子进程模块编写脚本。

【问题讨论】:

我相信这是 ffmpeg 的一个限制。它不使用非阻塞模式从 FIFO 中读取。 【参考方案1】:

在 Linux 中,管道缓冲区被限制为 65k,您可能会遇到死锁,在捕获可以写入更多视频之前,捕获不会写入更多音频,而 ffmpeg 在获得更多视频之前不会读取更多视频更多音频。

【讨论】:

我知道,我正在寻找解决此类死锁的常用方法。如果可以轻松避免,我宁愿不手动处理捕获和编码器之间的通信。【参考方案2】:

最后,我无法让 ffmpeg 在不阻塞 FIFO 的情况下读取,因此修改了捕获应用程序源代码以从单独的工作线程而不是顺序写入音频帧和视频帧。

【讨论】:

以上是关于使用命名管道时如何防止死锁?的主要内容,如果未能解决你的问题,请参考以下文章

命名管道中的 C# 死锁

关于命名管道,通常如何实现“握手”

尝试编写命名管道时如何修复“Broken Pipe”错误?

命名管道 232 管道正在关闭

c中的命名管道

使用命名管道向 ffmpeg 提供输入