我正在尝试利用强大的远程服务器进行视频编码。
我有一个本地 DVD 驱动器,用于将 DVD 翻录到内存中,最终驻留在 mbuffer 中。
从那里,我想分割流,通过网络将原始视频流重定向到远程代理进行编码并将结果流传输回来,同时在本地将音频流转换为另一种格式的流。最后,我想将两个结果流合并到一个新文件中。
部分问题可以通过tee
修改 mbuffer 内容并进行适当重定向来解决:
(reading commands) | mbuffer -p 1 -m 5G | tee <(ffmpeg -i - (splitting video stream here) -f avi | ssh 1.2.3.4 'ffmpeg -i - (doing some encoding here) -f <format> - ') | <( ffmpeg -i (processing audio adequately) )
但这样一来,我就有两个管道被重定向,没有逻辑上的分离。简而言之:我该如何再次连接这两个流(我需要接收另一个命令的不同输入流:ffmpeg -i <s -tream1> -i <stream2> (doing final conversion)
?有机会这样做吗?
答案1
我不完全理解该命令,但您的描述看起来它可能是命名管道的工作。为了使这个概念清晰,我的示例使用了其中四个。通过适当的替换,我认为您可以将这个数字减少到两个,甚至可能减少到一个;但现在让我们保持简单。
mkfifo pre-audio-pipe pre-video-pipe audio-pipe video-pipe # creating pipes
(reading commands) | mbuffer -p 1 -m 5G | tee pre-audio-pipe > pre-video-pipe # splitting
该过程将填充为两个命名管道创建的所有缓冲区,然后等待在其他地方读取这些数据。
“其他地方”是在另一个控制台中:
<pre-audio-pipe (isolate audio) | (process audio) > audio-pipe
在另一个控制台中:
<pre-video-pipe (isolate video) | (process video) > video-pipe
再次,这两个命令将等待我们从管道读取一些数据。在最后的控制台中:
ffmpeg -i video-pipe -i audio-pipe (doing final conversion)
如果最后一条命令想要先读取一个流,然后读取另一个流,则可能会遇到锁定。我不知道这种情况有多大可能。额外的缓冲区可能有助于避免这种情况。我的第一个尝试是删除mbuffer
(之前的)并在相应的和tee
之间插入两个独立的缓冲区。(isolate)
(process)
一切完成后:
rm pre-audio-pipe pre-video-pipe audio-pipe video-pipe # cleaning
编辑
来自OP的评论:
您是否认为有可能在不使用单独命名管道的情况下实现解决方案?
我一直在思考共同进程(coproc
内置)但我不太了解它们。这个全面的答案关于他们。搜索短语“为什么他们不那么受欢迎”。从中:
使用的唯一好处
coproc
是,您不必在使用后清理这些命名管道。
我完全同意。看看那里的例子——基本上就是数据流分叉为三向而不是双向的情况。该示例使用了除 之外的 shell,bash
但根据我的经验,在 中同样糟糕bash
。
理想情况下,应该有一个仅使用未命名管道的单行命令,因为该作业应该以命令提示符中的“经济努力”启动。
真的吗?所有这些都(doing some encoding here)
扩展了?在我看来,无论您使用命名管道还是未命名管道,这里的“经济努力”都是编写脚本,即使这是一次性的工作。比较长一行代码和等效的编写良好的脚本,我发现后者更容易调试。
但既然你要求一句话,你就会得到它,但仍然使用命名管道。我维护命名管道的想法是为它们创建一个临时目录。一般概念:
my_temp=`mktemp -d` ; pre_audio_pipe="${my_temp}/pre-audio-pipe" ; pre_video_pipe="${my_temp}/pre-video-pipe" ; audio_pipe="${my_temp}/audio-pipe" ; video_pipe="${my_temp}/video-pipe" ; mkfifo "$pre_audio_pipe" "$pre_video_pipe" "$audio_pipe" "$video_pipe" ; (reading commands) | tee "$pre_audio_pipe" > "$pre_video_pipe" & <"$pre_audio_pipe" (isolate audio) | mbuffer -p 1 -m 1G | (process audio) > "$audio_pipe" & <"$pre_video_pipe" (isolate video) | mbuffer -p 1 -m 4G | (process video) > "$video_pipe" & ffmpeg -i "$video_pipe" -i "$audio_pipe" (doing final conversion) ; rm -rf "$my_temp"
根据这个答案即使在深入研究命令并扩展所有(do something)
占位符之后,您也可能将其放入一个命令行中。
好的,一行形式是为了向您展示它有多么不方便。与脚本相同的概念:
#!/bin/bash
my_temp=`mktemp -d`
pre_audio_pipe="${my_temp}/pre-audio-pipe"
pre_video_pipe="${my_temp}/pre-video-pipe"
audio_pipe="${my_temp}/audio-pipe"
video_pipe="${my_temp}/video-pipe"
mkfifo "$pre_audio_pipe" "$pre_video_pipe" "$audio_pipe" "$video_pipe" #creating actual pipes
# Main code here.
# Notice we put few commands into the background.
# In this example there are two separate mbuffers.
(reading commands) | tee "$pre_audio_pipe" > "$pre_video_pipe" & # splitting
<"$pre_audio_pipe" (isolate audio) | mbuffer -p 1 -m 1G | (process audio) > "$audio_pipe" &
<"$pre_video_pipe" (isolate video) | mbuffer -p 1 -m 4G | (process video) > "$video_pipe" &
ffmpeg -i "$video_pipe" -i "$audio_pipe" (doing final conversion)
# Then cleaning:
rm -rf "$my_temp"