Трубопровод с заменой процесса и повторное соединение с выходом

Я пытаюсь использовать мощный удаленный сервер с точки зрения кодирования видео.

У меня есть локальный 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

редактировать

Из комментария ОП:

Вы видите какой-либо шанс реализовать решение без использования отдельных именованных каналов?

I've been thinking about coprocesses (coproc builtin) but I don't know them much. There is this comprehensive answer about them. Search for the phrase "why they are not so popular". Оттуда:

The only benefit of using coproc is that you don't have to clean up of those named pipes after use.

Я полностью согласен. Look at the example there – it's basically your case with data stream forked three-way instead of two-way. The example uses shells other than bash but from my experience it would be similarly awful in bash,

Ideally, there would be a one-line-command working with unnamed pipes only, since the job should be started with an "economic effort" from the command prompt.

Шутки в сторону? With all those (doing some encoding here) expanded? In my opinion, no matter whether you use named or unnamed pipes, an "economic effort" here will be to write a script, even if it's a one-time job. Comparing long one-liner and equivalent well written script, I find the latter easier to debug.

But since you asked for one-liner, you'll get it, still with named pipes though. My idea for maintaining named pipes is to create a temporary directory for them. The general concept:

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"

According to this answer you probably can fit it into one command line, even after you dig into the command and expand all those (do something) placeholders.

OK, the one-liner form was to show you how inconvenient it could be. The same concept as a script:

#!/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"
Другие вопросы по тегам