stdout einer SSH-Verbindung (paramiko) an Programm "pipen"

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
qupfer
User
Beiträge: 9
Registriert: Samstag 24. Mai 2014, 22:17

Nachdem mir im letzten Thread so schön geholfen wurde, hoffe ich auf gleiches bei meinen nächstem Problem.

Kurz vorweg, was ich eigentlich vorhabe.
Daheim habe ich einen Server mit tvheadend und halbwegs "viel" Rechenleistung, der via SAT Fernsehen empfängt und aufnimmt.
Mein fertiges Skript soll sich dann via SSH (einzige Verbindung nach Welt des Servers) zu diesem Verbinden,
ffmpeg anstoßen und dabei einen TV-Sender transcodieren, so dass ich hier im Uni-Wohnheim fernsehen kann/Aufnahmen betrachten.

Aktuell habe ich es schon soweit, dass er anhand eine Eingabe und ggf. Nachfrage (wenn mehrere Übereinstimmungen mit dem Suchbegriff) die Playlist nach dem gewünschten Sender durchsucht und die dazugehörige URL ausspuckt (zum Beispiel: http://localhost:9981/stream/channelid/ ... D06A94331E)

Auch das ffmpeg-Starten klappt schon, nur mit dem PIPEN noch nicht.
Die Funktion, die das mal machen soll, sieht bisher so aus. Aktuell noch alles "Hardcodiert"....

Code: Alles auswählen

def runFFmpeg(url):
	ffcommand = "ffmpeg -i http://localhost:9981/stream/channelid/655202758?ticket=2D71F6B1C6185E1778DDB14E309B34C82FCB7063 -acodec libfdk_aac -b:a 128k -ac 2 -vcodec libx264 -preset superfast -b:v 1500k  -profile:v baseline -bufsize 100k -s 720x576 -v quiet -f mpegts -"
	sshstdin, sshstdout, sshstderr = ssh.exec_command(ffcommand)
	player = subprocess.Popen(['C:\\Path\\To\\ffplay.exe', '-infbuf','-i',"-"], stdin=PIPE)
	player.communicate(sshstdout.read())
Vermutlich "seht" ihr das schon, dass klappt nicht ;)
Also ffmpeg wird gestartet und arbeitet auch ordentlich (via paralleler ssh-verbindung überprüft).
Auch ffplay startet und wartet brav auf Input. Nur scheint es keinen zu erhalten.
So völlig verkehrt kann die Funktion dann aber auch nicht sein, denn ändere ich "player.communicate(sshstdout.read())" zu "player.communicate(sshstdout)" meckert ffplay korrekt über ungültigen Input.

Ich vermute meinen Fehler in falscher/fehlender Beachtung, dass es sich um einen "rohen" Videostream handelt und nicht um typsiche "Text"-Dateien.
Oder in Unverständnis bezüglich der Nutzung von PIPE und subprocess.communicate()
Oder beidem.


Also könntet ihr mir abermals helfen? Danke schonmal.
BlackJack

@qupfer: Der `read()` aufruf liest solange bis die ”Datei” am Ende ist, und übergibst *dann* erst die komplette in den Speicher gelesene Datei dem `communicate()`-Aufruf.

Wenn Du die Ausgabe vom `ssh`-Aufruf mit der Eingabe vom lokal gestarteten Programm verbinden willst, dann mach das doch einfach direkt. Da wo Du jetzt `PIPE` stehen hast, kannst Du ein Datei(ähnliches) Objekt übergeben. Das `stdin` soll ja mit dem `sshstdout` verbunden werden.
qupfer
User
Beiträge: 9
Registriert: Samstag 24. Mai 2014, 22:17

Danke für deine Antwort, auch wenn sie leider nicht den erhofften Erfolg brachte. Wobei das sehr wahrscheinlich an meinen noch nicht wirklich vorhandenen Verständnisses bezüglich Python liegt.
Versuche ich ganz trivial stdin=sshstdout gibt mir Windows folgenden Meldungen aus:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\Users\qupfer\Desktop\Stream\stream.py", line 65, in <module>
    main()
  File "C:\Users\qupfer\Desktop\Stream\stream.py", line 18, in main
    runFFmpeg(url)
  File "C:\Users\qupfer\Desktop\Stream\stream.py", line 54, in runFFmpeg
    player = subprocess.Popen(['C:\\Users\\qupfer\\Desktop\\Stream\\tools\\ffpl
ay.exe', '-infbuf','-i',"-"], stdin=sshstdout)
  File "C:\Python33\lib\subprocess.py", line 782, in __init__
    errread, errwrite) = self._get_handles(stdin, stdout, stderr)
  File "C:\Python33\lib\subprocess.py", line 980, in _get_handles
    p2cread = msvcrt.get_osfhandle(stdin.fileno())
AttributeError: 'ChannelFile' object has no attribute 'fileno'

Immerhin, habe ich mit weiteren ge-googel eine scheinbar funktionierende PIPE-Lösung gefunden. Ganz dem Motto:
Nicht schön, aber selten. Aber über Hinweise, was für katastrophale Fehler drinn sind und wie man es besser macht, würde ich mich freuen. Eventuell auch, wie man die von BlackJack erdachte Lösung korrekt umsetzen würde.

Aber ich bin immerhin damit zufrieden, dass ich mein Bild bekomme und beim schließen von ffplay das Skript sich nicht mit eimem "BrokenPipe" oder "invalidArgument" oder ähnlichem verabschiedet.

Code: Alles auswählen

def runFFmpeg(url):
	ffcommand = "ffmpeg -i http://localhost:9981/stream/channelid/655202758?ticket=2D71F6B1C6185E1778DDB14E309B34C82FCB7063 -acodec libfdk_aac -b:a 128 -ac 2 -vcodec libx264 -preset superfast -b:v 1200k  -profile:v baseline -bufsize 100k -s 720x576 -v verbose -f mpegts -"
	sshstdin, sshstdout, sshstderr = ssh.exec_command(ffcommand)
	player = subprocess.Popen(['C:\\Users\\qupfer\\Desktop\\Stream\\tools\\ffplay.exe', '-infbuf','-i',"-"], stdin=PIPE)
	while True:
		try:
			player.stdin.write(sshstdout.read(1024))
		except Exception:
			break
	return 0
Antworten