error handling
This commit is contained in:
parent
7339f52bcf
commit
2399277971
|
@ -75,9 +75,8 @@ class ScreenStreamerGUI(QtWidgets.QMainWindow):
|
||||||
def stream_pressed(self):
|
def stream_pressed(self):
|
||||||
if self.streamer:
|
if self.streamer:
|
||||||
# stream already running -> stopping
|
# stream already running -> stopping
|
||||||
self.streamer = None
|
self.streamer.stop()
|
||||||
self.ui.statusbar.showMessage('stream stopped')
|
self.ui.streamBtn.setEnabled(False)
|
||||||
self.ui.streamBtn.setText('Stream')
|
|
||||||
return
|
return
|
||||||
|
|
||||||
displaydata = self.ui.displaySelect.currentData()
|
displaydata = self.ui.displaySelect.currentData()
|
||||||
|
@ -88,18 +87,17 @@ class ScreenStreamerGUI(QtWidgets.QMainWindow):
|
||||||
self.ui.protocolSelect.currentText().lower(),
|
self.ui.protocolSelect.currentText().lower(),
|
||||||
"{}:{}".format(self.ui.sendto.text(), self.ui.streamPort.value())
|
"{}:{}".format(self.ui.sendto.text(), self.ui.streamPort.value())
|
||||||
)
|
)
|
||||||
|
self.streamer.process_manager.process_terminated.connect(self.stream_terminated)
|
||||||
self.streamer.start()
|
self.streamer.start()
|
||||||
self.ui.streamBtn.setText('Stop Stream')
|
self.set_stream_status(True)
|
||||||
# TODO: add feedback on error
|
|
||||||
self.ui.statusbar.showMessage('stream started')
|
self.ui.statusbar.showMessage('stream started')
|
||||||
|
|
||||||
@QtCore.Slot()
|
@QtCore.Slot()
|
||||||
def recieve_pressed(self):
|
def recieve_pressed(self):
|
||||||
if self.receiver:
|
if self.receiver:
|
||||||
# stream already running -> stopping
|
# recieve already running -> stopping
|
||||||
self.receiver = None
|
self.receiver.stop()
|
||||||
self.ui.statusbar.showMessage('recieve stopped')
|
self.ui.recieveBtn.setEnabled(False)
|
||||||
self.ui.recieveBtn.setText('Recieve')
|
|
||||||
return
|
return
|
||||||
|
|
||||||
self.receiver = Reciever(
|
self.receiver = Reciever(
|
||||||
|
@ -107,7 +105,44 @@ class ScreenStreamerGUI(QtWidgets.QMainWindow):
|
||||||
"{}:{}".format(self.ui.listenAddr.text(), self.ui.listenPort.value()),
|
"{}:{}".format(self.ui.listenAddr.text(), self.ui.listenPort.value()),
|
||||||
self.ui.disableAudio.checkState() == 'Checked'
|
self.ui.disableAudio.checkState() == 'Checked'
|
||||||
)
|
)
|
||||||
|
self.receiver.process_manager.process_terminated.connect(self.recieve_terminated)
|
||||||
self.receiver.start()
|
self.receiver.start()
|
||||||
self.ui.recieveBtn.setText('Stop Recieve')
|
self.set_recieve_status(True)
|
||||||
# TODO: add feedback on error
|
|
||||||
self.ui.statusbar.showMessage('recieve started')
|
self.ui.statusbar.showMessage('recieve started')
|
||||||
|
|
||||||
|
def set_recieve_status(self, status: bool):
|
||||||
|
"""status = True - stream is running"""
|
||||||
|
self.ui.recieveBtn.setEnabled(True)
|
||||||
|
if status:
|
||||||
|
self.ui.recieveBtn.setText('Stop Recieve')
|
||||||
|
else:
|
||||||
|
self.ui.recieveBtn.setText('Recieve')
|
||||||
|
|
||||||
|
def set_stream_status(self, status: bool):
|
||||||
|
"""status = True - stream is running"""
|
||||||
|
self.ui.streamBtn.setEnabled(True)
|
||||||
|
if status:
|
||||||
|
self.ui.streamBtn.setText('Stop Stream')
|
||||||
|
else:
|
||||||
|
self.ui.streamBtn.setText('Stream')
|
||||||
|
|
||||||
|
def show_error(self, tag: str, returncode: int, errormsg: str):
|
||||||
|
if errormsg:
|
||||||
|
error = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Critical, tag + ' Error', tag + ' Error: ' + errormsg, QtWidgets.QMessageBox.Ok, self)
|
||||||
|
error.show()
|
||||||
|
error.exec()
|
||||||
|
|
||||||
|
@QtCore.Slot(int, str)
|
||||||
|
def recieve_terminated(self, returncode, errormsg):
|
||||||
|
self.receiver = None
|
||||||
|
self.ui.statusbar.showMessage('recieve stopped')
|
||||||
|
self.show_error('Recieve', returncode, errormsg)
|
||||||
|
self.set_recieve_status(False)
|
||||||
|
|
||||||
|
@QtCore.Slot(int, str)
|
||||||
|
def stream_terminated(self, returncode, errormsg):
|
||||||
|
self.streamer = None
|
||||||
|
self.ui.statusbar.showMessage('stream stopped')
|
||||||
|
self.show_error('Stream', returncode, errormsg)
|
||||||
|
self.set_stream_status(False)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
from PySide6.QtCore import QObject, Signal
|
||||||
|
from threading import Thread
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
class ProcManager(QObject):
|
||||||
|
|
||||||
|
process_terminated = Signal(int, str)
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super(ProcManager, self).__init__()
|
||||||
|
|
||||||
|
self.thre = None
|
||||||
|
self.proc = None
|
||||||
|
|
||||||
|
def start(self, proc):
|
||||||
|
# this method might override the old process and thread
|
||||||
|
self.proc = proc
|
||||||
|
|
||||||
|
self.thre = Thread(target=self.detect_end)
|
||||||
|
self.thre.start()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
if self.proc:
|
||||||
|
self.proc.terminate()
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.proc.wait(1)
|
||||||
|
except subprocess.TimeoutExpired as e:
|
||||||
|
self.proc.kill()
|
||||||
|
|
||||||
|
if self.thre:
|
||||||
|
self.thre.join()
|
||||||
|
self.thre = None
|
||||||
|
|
||||||
|
def detect_end(self):
|
||||||
|
# wait for the process to terminate
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
self.proc.wait(1)
|
||||||
|
break
|
||||||
|
except subprocess.TimeoutExpired as e:
|
||||||
|
continue
|
||||||
|
|
||||||
|
returncode = self.proc.returncode
|
||||||
|
errorstream = self.proc.stderr.read()
|
||||||
|
if isinstance(errorstream, bytes):
|
||||||
|
errorstream = errorstream.decode('utf-8')
|
||||||
|
|
||||||
|
self.proc = None
|
||||||
|
|
||||||
|
print('Process Terminated:', returncode, errorstream)
|
||||||
|
|
||||||
|
self.process_terminated.emit(returncode, errorstream)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from procmanager import ProcManager
|
||||||
|
|
||||||
class Reciever:
|
class Reciever:
|
||||||
|
|
||||||
|
@ -6,7 +7,7 @@ class Reciever:
|
||||||
self.protocol = protocol # should be 'tcp' or 'udp'
|
self.protocol = protocol # should be 'tcp' or 'udp'
|
||||||
self.target = target
|
self.target = target
|
||||||
self.disable_audio = disable_audio
|
self.disable_audio = disable_audio
|
||||||
self.proc = None
|
self.process_manager = ProcManager()
|
||||||
|
|
||||||
def __del__(self) -> None:
|
def __del__(self) -> None:
|
||||||
self.stop()
|
self.stop()
|
||||||
|
@ -14,7 +15,7 @@ class Reciever:
|
||||||
def start(self):
|
def start(self):
|
||||||
# currently there is no direct ffplay support in the ffmpeg package
|
# currently there is no direct ffplay support in the ffmpeg package
|
||||||
|
|
||||||
args = ['ffplay', '-fflags', 'nobuffer', '-flags', 'low_delay', '-f', 'mpegts']
|
args = ['ffplay', '-hide_banner', '-loglevel', 'error', '-fflags', 'nobuffer', '-flags', 'low_delay', '-f', 'mpegts']
|
||||||
|
|
||||||
if self.disable_audio:
|
if self.disable_audio:
|
||||||
args.append('-an')
|
args.append('-an')
|
||||||
|
@ -22,12 +23,9 @@ class Reciever:
|
||||||
# the address
|
# the address
|
||||||
args.append(self.protocol+ '://' + self.target + '?listen')
|
args.append(self.protocol+ '://' + self.target + '?listen')
|
||||||
|
|
||||||
self.proc = subprocess.Popen(args)
|
proc = subprocess.Popen(args, encoding='utf-8', shell=False, text=True, stderr=subprocess.PIPE)
|
||||||
|
self.process_manager.start(proc)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
if self.proc:
|
self.process_manager.stop()
|
||||||
self.proc.terminate()
|
|
||||||
self.proc.wait(1)
|
|
||||||
self.proc.kill()
|
|
||||||
self.proc = None
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import ffmpeg
|
import ffmpeg
|
||||||
|
from procmanager import ProcManager
|
||||||
|
|
||||||
class Streamer:
|
class Streamer:
|
||||||
|
|
||||||
|
@ -8,14 +9,14 @@ class Streamer:
|
||||||
self.audioindex = audioindex
|
self.audioindex = audioindex
|
||||||
self.protocol = protocol # should be 'tcp' or 'udp'
|
self.protocol = protocol # should be 'tcp' or 'udp'
|
||||||
self.target = target
|
self.target = target
|
||||||
self.proc = None
|
self.process_manager = ProcManager()
|
||||||
|
|
||||||
def __del__(self) -> None:
|
def __del__(self) -> None:
|
||||||
self.stop()
|
self.stop()
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
streams = []
|
streams = []
|
||||||
self.input = ffmpeg.input(self.screendef, f='x11grab', r=60, s=self.screensize)
|
self.input = ffmpeg.input(self.screendef, f='x11grab', r=60, s=self.screensize, hide_banner='-y', loglevel='error')
|
||||||
streams.append(self.input)
|
streams.append(self.input)
|
||||||
|
|
||||||
if self.audioindex != -1:
|
if self.audioindex != -1:
|
||||||
|
@ -23,13 +24,10 @@ class Streamer:
|
||||||
streams.append(self.audio)
|
streams.append(self.audio)
|
||||||
|
|
||||||
self.output = ffmpeg.output(*streams, self.protocol + '://' + self.target, f='mpegts', vcodec='nvenc_hevc', tune='zerolatency')
|
self.output = ffmpeg.output(*streams, self.protocol + '://' + self.target, f='mpegts', vcodec='nvenc_hevc', tune='zerolatency')
|
||||||
self.proc = ffmpeg.run_async(self.output)
|
proc = ffmpeg.run_async(self.output, pipe_stderr=True)
|
||||||
|
self.process_manager.start(proc)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
if self.proc:
|
self.process_manager.stop()
|
||||||
self.proc.terminate()
|
|
||||||
self.proc.wait(1)
|
|
||||||
self.proc.kill()
|
|
||||||
self.proc = None
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue