Tubulação com substituição de processo e junção de saída novamente

3

Estou tentando usar um poderoso servidor remoto em termos de codificação de vídeo.

Eu tenho uma unidade de DVD local para ripar o DVD para a memória, finalmente residindo em um mbuffer.

A partir daí, eu gostaria de dividir fluxos, redirecionando o fluxo de vídeo bruto para o agente remoto para codificar e canalizar o fluxo resultante de volta, enquanto, ao mesmo tempo, convertia o fluxo de áudio localmente em outro fluxo de formato . Então, finalmente, gostaria de unir os dois fluxos resultantes a um novo arquivo.

Parte disso pode ser resolvido por tee ing o conteúdo do buffer de objeto e redirecionando apropriadamente:

(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) )

mas isso me deixa com dois tubos redirecionados sem separação lógica. Em claro: como faço para juntar os dois fluxos novamente (preciso receber fluxos de entrada distintos para outro comando: ffmpeg -i <s -tream1> -i <stream2> (doing final conversion) ? Alguma chance de fazer isso?

    
por user415275 30.03.2017 / 22:20

1 resposta

2

Eu não entendo completamente o comando, mas sua descrição parece ser um trabalho para pipes nomeados. Para tornar claro esse conceito, meu exemplo usa quatro deles. Com as devidas substituições, você pode reduzir esse número para dois, eu acho, talvez até para um; mas por enquanto vamos simplificar.

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

Este processo preencherá os buffers criados para os dois pipes nomeados e, em seguida, aguardará que esses dados sejam lidos em outro lugar.

O "outro lugar" está em outro console:

<pre-audio-pipe (isolate audio) | (process audio) > audio-pipe

e ainda em outro console:

<pre-video-pipe (isolate video) | (process video) > video-pipe

Novamente, esses dois comandos aguardarão até lermos alguns dados dos pipes. No console final:

ffmpeg -i video-pipe -i audio-pipe (doing final conversion)

Você pode ter um bloqueio no caso de o comando final desejar ler um fluxo antes do outro. Eu não sei qual é a probabilidade disso. Buffers adicionais podem ser úteis para evitar isso. Minha primeira tentativa seria remover o mbuffer (antes de tee ) e inserir dois buffers independentes entre os respectivos (isolate) e (process) .

Depois disso tudo é feito:

rm pre-audio-pipe pre-video-pipe audio-pipe video-pipe # cleaning

Editar

Do comentário do OP:

do you see any chance to implement a solution without using separate named pipes?

Estou pensando em coprocessos ( coproc builtin), mas não os conheço muito. Existe esta resposta abrangente sobre eles. Procure a frase "por que eles não são tão populares". De lá:

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

Eu concordo totalmente. Veja o exemplo lá - é basicamente o seu caso com o fluxo de dados bifurcado de três vias em vez de bidirecional. O exemplo usa shells diferentes de bash , mas, da minha experiência, seria igualmente horrível em 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.

Sério? Com todos aqueles (doing some encoding here) expandidos? Na minha opinião, não importa se você usa pipes nomeados ou não nomeados, um "esforço econômico" aqui será escrever um roteiro, mesmo que seja um trabalho único. Comparando o longo one-liner e o equivalente em um script bem escrito, acho que o último é mais fácil de depurar.

Mas desde que você pediu por um-liner, você o terá , ainda com pipes nomeados. Minha ideia para manter pipes nomeados é criar um diretório temporário para eles. O conceito geral:

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"

De acordo com esta resposta , você provavelmente pode encaixá-la em uma linha de comando, mesmo depois de entrar no comando e expandir todos (do something) placeholders.

OK, o formulário de uma linha era mostrar a você o quão inconveniente isso poderia ser. O mesmo conceito que um 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"
    
por 30.03.2017 / 23:01