Piping mit Prozessersetzung und erneutes Verbinden der Ausgabe

586
user415275

Ich versuche, einen leistungsfähigen Remote-Server in Bezug auf die Videocodierung zu verwenden.

Ich habe ein lokales DVD-Laufwerk, um die DVD in den Speicher zu kopieren und schließlich in einem MBuffer zu speichern.

Von dort aus möchte ich Streams aufteilen, den Rohvideostream über das Netzwerk an den Remote-Agenten weiterleiten, um den entstehenden Stream zu codieren und zurückzuleiten, während er gleichzeitig den Audiostream lokal in einen anderen Formatstream umwandelt. Dann möchte ich schließlich die beiden resultierenden Streams zu einer neuen Datei zusammenfügen.

Ein Teil davon kann gelöst werden, indem teeder Inhalt von mbuffer entsprechend geändert wird:

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

Das lässt mich jedoch mit zwei umgeleiteten Rohren ohne logische Trennung zurück. Im Klaren: Wie füge ich beide Streams wieder zusammen (ich muss verschiedene Eingabestreams für einen anderen Befehl erhalten ffmpeg -i <s -tream1> -i <stream2> (doing final conversion) ? Gibt es eine Chance, dies zu tun?

3

1 Antwort auf die Frage

2
Kamil Maciorowski

Ich verstehe den Befehl nicht vollständig, aber Ihre Beschreibung sieht so aus, als ob es sich um einen Auftrag für Named Pipes handelt. Um dieses Konzept zu verdeutlichen, verwendet mein Beispiel vier davon. Mit geeigneten Substitutionen kann man diese Zahl auf zwei reduzieren, denke ich, vielleicht sogar auf eins; aber jetzt halten wir es einfach.

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 

Dieser Prozess füllt die Puffer, die für die beiden genannten Pipes erstellt werden, und wartet, bis diese Daten an anderer Stelle gelesen werden.

Das "Anderswo" befindet sich in einer anderen Konsole:

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

und in noch einer anderen Konsole:

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

Wieder warten diese beiden Befehle, bis wir einige Daten aus den Pipes lesen. In der letzten Konsole:

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

Es kann zu einer Sperrung kommen, falls der letzte Befehl einen Stream vor dem anderen lesen möchte. Ich weiß nicht, wie wahrscheinlich das ist. Zusätzliche Puffer können hilfreich sein, um dies zu vermeiden. Mein erster Versuch wäre, die mbuffer(zuvor tee) zu entfernen und zwei unabhängige Puffer zwischen den jeweiligen (isolate)und einzufügen (process).

Nachdem alles fertig ist:

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

Bearbeiten

Aus dem Kommentar der OP:

sehen Sie eine Chance, eine Lösung ohne separate Named Pipes zu implementieren?

Ich habe über Koprozessecoproc nachgedacht ( eingebaut), aber ich kenne sie nicht viel. Es gibt diese umfassende Antwort darauf . Suchen Sie nach dem Satz "Warum sie nicht so beliebt sind". Von dort:

Der einzige Vorteil der Verwendung coprocist, dass Sie die benannten Pipes nach der Verwendung nicht bereinigen müssen.

Ich bin völlig einverstanden. Sehen Sie sich das Beispiel dort an. Dies ist im Grunde Ihr Fall, wenn der Datenstrom drei- statt zweiwege-gegabelt ist. Das Beispiel verwendet andere Schalen als, bashaber aus meiner Erfahrung wäre es in ähnlicher Weise schrecklich bash.

Im Idealfall würde es einen einzeiligen Befehl geben, der nur mit unbenannten Pipes arbeitet, da der Job mit einem "wirtschaftlichen Aufwand" von der Eingabeaufforderung aus gestartet werden sollte.

Ernst? Mit all denen (doing some encoding here)erweitert? Meiner Meinung nach, egal ob Sie benannte oder unbenannte Pipes verwenden, wird es "wirtschaftlich" sein, ein Skript zu schreiben, auch wenn es sich um einen einmaligen Job handelt. Ich vergleiche lange Einzeiler und gleichwertige gut geschriebene Skripte und finde das Debuggen einfacher.

Aber da Sie nach einem Einzeiler gefragt haben, erhalten Sie ihn immer noch mit Named Pipes. Meine Idee zur Verwaltung von Named Pipes ist das Erstellen eines temporären Verzeichnisses für sie. Das allgemeine Konzept:

my_temp=`mktemp -d` ; pre_audio_pipe="$/pre-audio-pipe" ; pre_video_pipe="$/pre-video-pipe" ; audio_pipe="$/audio-pipe" ; video_pipe="$/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" 

Laut dieser Antwort können Sie sie wahrscheinlich in eine Befehlszeile einfügen, auch nachdem Sie den Befehl eingraviert und alle (do something)Platzhalter erweitert haben.

OK, das One-Liner-Formular sollte Ihnen zeigen, wie unpraktisch es sein kann. Das gleiche Konzept wie ein Skript:

#!/bin/bash  my_temp=`mktemp -d` pre_audio_pipe="$/pre-audio-pipe" pre_video_pipe="$/pre-video-pipe" audio_pipe="$/audio-pipe" video_pipe="$/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" 
Interessant, ist das den Benennungsdateideskriptoren ähnlich (oder identisch)? Xen2050 vor 7 Jahren 0
@ Xen2050 Ehrlich gesagt weiß ich es nicht. Meine expliziten Erfahrungen mit Dateideskriptoren (in `bash` oder anderswo) sind sehr begrenzt. Ich benutze sie natürlich immer implizit. :) Unbenannte Pipes (`|`) sind flüchtige FIFOs; Named Pipes sind persistentere FIFOs mit Namen (Pfaden). Fürs Erste scheint es mir höchstens eine Ähnlichkeit zu geben, keine Identität. Kamil Maciorowski vor 7 Jahren 0
Vielen Dank, dass Sie auf meine Frage geantwortet haben. Ich verstehe deine Herangehensweise. sehen Sie eine Chance, eine Lösung ohne separate Named Pipes zu implementieren? Im Idealfall würde es einen einzeiligen Befehl geben, der nur mit unbenannten Pipes arbeitet, da der Job mit einem "wirtschaftlichen Aufwand" von der Eingabeaufforderung aus gestartet werden sollte. user415275 vor 7 Jahren 0
@ user415275 Ich habe meine Antwort erweitert. Kamil Maciorowski vor 7 Jahren 0
Vielen Dank für Ihre Antwort. Ihr großer "Einzeiler" verwendet ohnehin immer noch Fifos / Named Pipes. Gibt es eine Chance, Folgendes zu erreichen: - Nur einmaliges Eingeben des Datums - Gehen Sie von hier aus, verarbeiten Sie alle Daten - und: Fügen Sie die resultierenden Daten anschließend zusammen wieder ohne benannte Pipes? Ich schätze Ihre Arbeit und Ihr Engagement absolut, und natürlich funktioniert es, aber es ist nicht die pragmatische Art und Weise, die ich wählen möchte, sofern dies möglich ist. user415275 vor 7 Jahren 0
@ user415275 Wie gesagt: Coprozesse; aber ich werde sie hier nicht in meinen Code aufnehmen, weil ich sie nicht genug kenne und ich denke, Sie haben bereits alle Mittel, um es selbst zu tun, da Sie darauf bestehen, Named Pipes aufzugeben. Sie können Ihre eigene Antwort posten und andere von Ihnen lernen lassen. Falls es ein spezifisches Problem mit Coprozessen gibt, das Sie trotz Ihres vernünftigen Forschungsaufwands nicht lösen können, möchte ich Sie dazu auffordern, explizit eine gesonderte Frage dazu zu stellen (Super User oder [Unix & Linux] (http://unix.stackexchange.com/). ). Kamil Maciorowski vor 7 Jahren 0