jb_alvarado
Lieutenant
- Registriert
- Sep. 2015
- Beiträge
- 596
Hallo Allerseits,
seit ein paar Jahren entwickle ich eine Playout-Software basierend auf Python. Das Programm spielt Video-Playlisten im 24/7 Betrieb ab und das fast Zeitgenau. Da ich mit diesem Programm angefangen habe Python zu lernen, ist der Code stellenweise sicher verbesserungsfähig, aber darum soll es jetzt nicht gehen.
Was immer wieder mal gewünscht wird, ist die Möglichkeit einen Livestream mit einzubinden. Also die Playlist soll normal abspielen, aber zusätzlich soll die Möglichkeit bestehen z.B. per rtmp an das Programm zu streamen und dieses spielt dann diesen Stream weiter. Ist der Livestream vorbei, soll die Playliste weiterspielen.
Ich habe das mal ein bisschen getestet und grundsätzlich scheint es mit diesem Code zu funktionieren:
War nur schnell zusammengeschustert...
Bei meinem Programm ist mir Stabilität wichtiger, als Funktionsumfang. Da ich schon mal eine Meldung bekommen habe, wegen Speicherüberlauf, diesen selbst aber noch nicht reproduzieren konnte, mache ich mir jetzt natürlich Gedanke ob es bei dieser Konstruktion hier langfristig Probleme geben kann. Vielleicht erst nach Woche, aber das wäre schlimm genug, weil man das schwierig debuggen kann.
Wenn ihr das so überfliegt, fallen euch dabei problematische Stellen auf? Abgesehen von Schönheitsfehlern und der Gleichen.
seit ein paar Jahren entwickle ich eine Playout-Software basierend auf Python. Das Programm spielt Video-Playlisten im 24/7 Betrieb ab und das fast Zeitgenau. Da ich mit diesem Programm angefangen habe Python zu lernen, ist der Code stellenweise sicher verbesserungsfähig, aber darum soll es jetzt nicht gehen.
Was immer wieder mal gewünscht wird, ist die Möglichkeit einen Livestream mit einzubinden. Also die Playlist soll normal abspielen, aber zusätzlich soll die Möglichkeit bestehen z.B. per rtmp an das Programm zu streamen und dieses spielt dann diesen Stream weiter. Ist der Livestream vorbei, soll die Playliste weiterspielen.
Ich habe das mal ein bisschen getestet und grundsätzlich scheint es mit diesem Code zu funktionieren:
Python:
#!/usr/bin/env python3
from subprocess import PIPE, Popen
from threading import Thread
from time import sleep
from types import SimpleNamespace
from queue import Queue
buffer_size = 65424
streaming_queue = Queue(maxsize=0)
pre_settings = [
'-pix_fmt', 'yuv420p', '-s', '1024x576', '-r', '25', '-c:v', 'mpeg2video',
'-g', '1', '-b:v', '50000k', '-minrate', '50000k', '-maxrate', '50000k',
'-bufsize', '25000k', '-c:a', 'mp2', '-b:a', '384k', '-ar', '48000',
'-ac', '2', '-f', 'mpegts', '-']
ff_proc = SimpleNamespace(live=None, decoder=None, encoder=None)
dec_cmd = [
'ffmpeg', '-v', f'level+error',
'-hide_banner', '-nostats', '-f', 'lavfi',
'-i', 'testsrc=duration=3600:size=1024x576:rate=25',
'-f', 'lavfi', '-i', 'anoisesrc=d=3600:c=pink:r=48000:a=0.2'
] + pre_settings
enc_cmd = [
'ffplay', '-hide_banner', '-nostats', '-v', 'level+error', '-i', 'pipe:0']
ff_proc.encoder = Popen(enc_cmd, stderr=None, stdin=PIPE, stdout=None)
def rtmp_server(que):
server_cmd = [
'ffmpeg', '-hide_banner', '-nostats', '-v', 'level+error',
'-f', 'live_flv', '-listen', '1',
'-i', 'rtmp://localhost:1935/live/stream'] + pre_settings
while True:
with Popen(server_cmd, stderr=None, stdout=PIPE) as ff_proc.live:
while True:
buffer = ff_proc.live.stdout.read(buffer_size)
if not buffer:
break
que.put(buffer)
sleep(.33)
def terminate_processes():
"""
kill orphaned processes
"""
if ff_proc.decoder and ff_proc.decoder.poll() is None:
ff_proc.decoder.terminate()
if ff_proc.live and ff_proc.live.poll() is None:
ff_proc.live.terminate()
if ff_proc.encoder and ff_proc.encoder.poll() is None:
ff_proc.encoder.kill()
rtmp_server_thread = Thread(target=rtmp_server, args=(streaming_queue,))
rtmp_server_thread.daemon = True
rtmp_server_thread.start()
try:
with Popen(dec_cmd, stdout=PIPE, stderr=None) as ff_proc.decoder:
while True:
buf_dec = ff_proc.decoder.stdout.read(buffer_size)
if not streaming_queue.empty():
buf_live = streaming_queue.get()
ff_proc.encoder.stdin.write(buf_live)
del buf_dec
elif buf_dec:
ff_proc.encoder.stdin.write(buf_dec)
else:
break
except (KeyboardInterrupt, BrokenPipeError):
terminate_processes()
War nur schnell zusammengeschustert...
Bei meinem Programm ist mir Stabilität wichtiger, als Funktionsumfang. Da ich schon mal eine Meldung bekommen habe, wegen Speicherüberlauf, diesen selbst aber noch nicht reproduzieren konnte, mache ich mir jetzt natürlich Gedanke ob es bei dieser Konstruktion hier langfristig Probleme geben kann. Vielleicht erst nach Woche, aber das wäre schlimm genug, weil man das schwierig debuggen kann.
Wenn ihr das so überfliegt, fallen euch dabei problematische Stellen auf? Abgesehen von Schönheitsfehlern und der Gleichen.