3

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

У меня есть локальный DVD-привод для копирования DVD в память, и, наконец, в Mbuffer.

Оттуда я хотел бы разделить потоки, перенаправив необработанный видеопоток по сети на удаленный агент для кодирования и передачи результирующего потока обратно, в то же время одновременно преобразовывая аудиопоток локально в поток другого формата. Затем, наконец, я хотел бы объединить оба полученных потока в новый файл.

Часть этого может быть решена с помощью tee ING содержания 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 ответ1

2

Я не совсем понимаю команду, но ваше описание выглядит так, как будто это работа для именованных каналов. Чтобы прояснить эту концепцию, мой пример использует четыре из них. С правильными заменами вы можете уменьшить это число до двух, я думаю, возможно даже до одного; но пока давайте будем простыми.

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

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

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

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

Я думал о сопроцессах (coproc встроенный), но я их мало знаю. Есть исчерпывающий ответ о них. Ищите фразу "почему они не так популярны". Оттуда:

Единственное преимущество использования coproc заключается в том, что вам не нужно очищать эти именованные каналы после использования.

Я полностью согласен. Посмотрите на пример там - это в основном ваш случай с потоком данных раздвоенным, а не двусторонним. В примере используются оболочки, отличные от 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"

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .