ich versuche folgendes zu lösen:
- 1. subprocess läuft im main Thread durchgehend.
- 2. subprocess läuft in Thread und schickt Pakete von stdout in Queue, welche im main Thread gelesen werden soll und dort an stdin vom 1. subprocess gepipet wird.
- 3. subprocess läuft in weiteren Thread.
- Nach einem Ereignis (in meinem Codebeispiel wenn couter auf 70000 angelangt ist) soll der 2. subprocess gestoppt werden und der 3. subprocess gestartet werden und Pakete in gleiche Queue schicken um damit den 1. subprocess zu füttern.
Das funktioniert soweit auch prinzipiell, wenn ich allerdings vom 3. subprocess wieder auf den 2. subprocess wechseln möchte, bleibt meine while Schleife stehen.
Hier ist dazu der Code den ich provisorisch dafür zusammen gezimmert habe:
Code: Alles auswählen
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from threading import Thread
from subprocess import Popen, PIPE
from queue import Queue
SOURCES = [
"/Users/jonathan/DEV/watch/intro.mp4",
"/Users/jonathan/DEV/watch/abenteuer.mp4",
"/Users/jonathan/DEV/watch/kontinent.mp4",
"/Users/jonathan/DEV/watch/terra1.mp4",
"/Users/jonathan/DEV/watch/terra2.mp4",
"/Users/jonathan/DEV/watch/terra3.mp4",
"/Users/jonathan/DEV/watch/test.mp4"
]
class Player(Thread):
def __init__(self, buffer):
Thread.__init__(self)
self._buffer = buffer
self.decoder = None
self.index = 0
self.is_running = True
def run(self):
self.play()
def play(self):
while self.index < len(SOURCES) - 1 and self.is_running:
self.decoder = Popen([
'ffmpeg', '-hide_banner', '-v', 'error', '-nostats',
'-i', SOURCES[self.index], '-r', '25', '-s', '1024x576',
'-c:v', 'mpeg2video', '-intra', '-b:v', '50M',
'-minrate', '50M', '-maxrate', '50M', '-bufsize', '50M',
'-c:a', 's302m', '-strict', '-2', '-ar', '48k',
'-ac', '2', '-f', 'mpegts', '-'], stdout=PIPE)
print('Play:', SOURCES[self.index])
for data in iter(self.decoder.stdout.readline, ''):
if not data:
break
self._buffer.put(data)
self.index += 1
else:
self.index = 0
def next(self):
self.is_running = True
self.play()
def stop_decoder(self):
if self.decoder is not None:
self.decoder.terminate()
self.is_running = False
self.decoder = None
class Inject(Thread):
def __init__(self, buffer):
Thread.__init__(self)
self._buffer = buffer
self.decoder = None
self.index = 0
self.is_running = True
def run(self):
self.play()
def play(self):
if self.is_running:
self.decoder = Popen([
'ffmpeg', '-hide_banner', '-nostats', '-v', 'error',
'-i', SOURCES[6], '-r', '25', '-s', '1024x576',
'-c:v', 'mpeg2video', '-intra', '-b:v', '50M',
'-minrate', '50M', '-maxrate', '50M', '-bufsize', '50M',
'-c:a', 's302m', '-strict', '-2', '-ar', '48k', '-ac', '2',
'-f', 'mpegts', '-'], stdout=PIPE)
for data in iter(self.decoder.stdout.readline, ''):
if not data:
self._buffer.put(None)
break
self._buffer.put(data)
self.stop_decoder()
def next(self):
self.is_running = True
self.play()
def stop_decoder(self):
if self.decoder is not None:
self.decoder.terminate()
self.is_running = False
self.decoder = None
def main():
buffer = Queue(maxsize=1024)
try:
encoder = Popen([
'ffplay', '-v', 'error', '-hide_banner', '-nostats',
'-i', 'pipe:0'], stderr=None, stdin=PIPE, stdout=None)
play_thread = Player(buffer)
play_thread.daemon = True
play_thread.start()
inject_thread = Inject(buffer)
inject_thread.daemon = True
counter = 0
while True:
data = buffer.get()
print("Counter: {}".format(counter), end="\r")
counter += 1
if data is None:
play_thread.next()
else:
encoder.stdin.write(data)
if counter == 70000:
print("switch source")
play_thread.stop_decoder()
if inject_thread.is_alive():
inject_thread.next()
else:
inject_thread.start()
counter = 0
finally:
encoder.wait()
if __name__ == '__main__':
main()
Die Inject Klasse soll später mal durch einen rtmp Server ersetzt werden, der denn übers www sein Signal bekommen soll. Daher der Aufwand.