I have a gui application in which I am showing video using udp.If my udp_server.py is running it will start streaming camera video.
I was testing different functionalities and found multiple scenarios where my python is not responding issue occurs.
Everything works fine when connected for the first time but when i press stop udp button on app it stops showing video but when i again put ip and port it doesnot work. I have to re run the server file to again connect. it works fine. but during disconnecting and everything,if i press any button app stops working.
I am sharing my code too as I am new to network programming and pyqt.this is the code of udp_server.py
import cv2
import imutils
import socket
import numpy as np
import time
import base64
BUFF_SIZE = 65536
PORT = 9999
HOST_IP = '127.0.0.1'
def main():
# Set up UDP socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, BUFF_SIZE)
server_socket.bind((HOST_IP, PORT))
print(f"Listening at: {(HOST_IP, PORT)}")
# Capture video from webcam
cap = cv2.VideoCapture(0) # Use 0 for the default webcam
if not cap.isOpened():
print("Error: Could not open video device.")
return
print(f"Sending video stream to {HOST_IP}:{PORT}")
fps, st, frames_to_count, cnt = (0, 0, 20, 0)
while True:
msg, client_addr = server_socket.recvfrom(BUFF_SIZE)
print('GOT connection from ', client_addr)
WIDTH = 400
while cap.isOpened():
ret, frame = cap.read()
if not ret:
print("Error: Could not read frame.")
break
frame = imutils.resize(frame, width=WIDTH)
encoded, buffer = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 80])
if not encoded:
print("Error: Could not encode frame.")
break
# Encode frame as base64
message = base64.b64encode(buffer)
message_size = len(message)
# Split the message into smaller chunks
for i in range(0, message_size, BUFF_SIZE - 10): # Subtracting 10 for safety
chunk = message[i:i + BUFF_SIZE - 10]
server_socket.sendto(chunk, client_addr)
# Display the frame (for debugging purposes)
frame = cv2.putText(frame, 'FPS: ' + str(fps), (10, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
cv2.imshow('TRANSMITTING VIDEO', frame)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
cap.release()
server_socket.close()
cv2.destroyAllWindows()
return
if cnt == frames_to_count:
try:
fps = round(frames_to_count / (time.time() - st))
st = time.time()
cnt = 0
except ZeroDivisionError:
pass
cnt += 1
if __name__ == '__main__':
main()
here is code of udp_client.py
import cv2
import numpy as np
import socket
import base64
from PyQt5.QtCore import QThread, pyqtSignal
class UdpClient(QThread):
change_pixmap_signal = pyqtSignal(np.ndarray)
error_signal = pyqtSignal(str)
def __init__(self, ip, port):
super().__init__()
self.ip = ip
self.port = int(port)
self.running = True
self.client_socket = None
def run(self):
BUFF_SIZE = 65536
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, BUFF_SIZE)
message = b'Hello'
try:
self.client_socket.sendto(message, (self.ip, self.port))
print(f"UDP Client started. Listening on {self.ip}:{self.port}")
data = b""
while self.running:
try:
packet, _ = self.client_socket.recvfrom(BUFF_SIZE)
data += packet
try:
frame_data = base64.b64decode(data, ' /')
np_data = np.frombuffer(frame_data, dtype=np.uint8)
frame = cv2.imdecode(np_data, 1)
if frame is not None:
print("Frame received, emitting signal") # Debugging information
self.change_pixmap_signal.emit(frame)
data = b""
else:
print("Failed to decode frame") # Debugging information
self.error_signal.emit("Failed to decode frame")
except base64.binascii.Error:
continue
except Exception as e:
print(f"Error receiving data: {e}")
self.error_signal.emit(f"Error: {e}")
except Exception as e:
print(f"Error setting up client socket: {e}")
self.error_signal.emit(f"Error: {e}")
finally:
if self.client_socket:
self.client_socket.close()
self.client_socket = None
print("UDP Client stopped.")
def stop(self):
self.running = False
self.quit()
self.wait()
if self.client_socket:
self.client_socket.close()
self.client_socket = None
print("UDP Client stopped.")
def reset(self, ip, port):
self.stop()
self.ip = ip
self.port = int(port)
self.running = True
self.start()
My video_fram.py code.I have only shared the related code.
import cv2
import numpy as np
from PyQt5.QtWidgets import QVBoxLayout, QFrame, QLabel, QPushButton, QSizePolicy, QSlider, QHBoxLayout, QFileDialog, QMessageBox, QApplication
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtCore import Qt
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from PyQt5.QtCore import QUrl
from udp_dialog import UdpDialog
from udp_client import UdpClient
def create_live_video_frame(app):
"""
Create the live video frame with a button to input UDP stream details.
"""
live_video_frame = QFrame()
live_layout = QVBoxLayout()
live_label = QLabel('Live Surveillance Video')
live_label.setAlignment(Qt.AlignCenter)
live_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
live_layout.addWidget(live_label)
live_video_widget = QLabel() # Using QLabel to display video frames
live_video_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
live_video_widget.setAlignment(Qt.AlignCenter)
live_video_widget.setStyleSheet("background-color: black;") # Add a background color to see the frame
live_layout.addWidget(live_video_widget)
# Add UDP Stream button
udp_button = QPushButton('Set UDP Stream')
udp_button.clicked.connect(lambda: open_udp_dialog(app))
live_layout.addWidget(udp_button)
# Add Stop Stream button
stop_button = QPushButton('Stop UDP Stream')
stop_button.clicked.connect(lambda: stop_udp_stream(app))
live_layout.addWidget(stop_button)
live_video_frame.setLayout(live_layout)
live_video_frame.setFrameShape(QFrame.StyledPanel)
return live_video_frame, live_video_widget, live_label
def stop_udp_stream(app):
"""
Stop the UDP stream.
"""
try:
if hasattr(app, 'udp_client') and app.udp_client:
app.udp_client.change_pixmap_signal.disconnect()
app.udp_client.error_signal.disconnect()
app.udp_client.stop()
app.udp_client = None
print("Stopped UDP stream.")
except Exception as e:
print(f"Error while stopping UDP stream: {e}")
def open_udp_dialog(app):
"""
Open the UDP dialog to input IP and port for the UDP stream.
"""
dialog = UdpDialog()
if dialog.exec_():
ip, port = dialog.get_details()
if ip and port:
app.ip = ip
app.port = int(port)
start_udp_stream(app, ip, port)
def start_udp_stream(app, ip="127.0.0.1", port=12345):
"""
Start receiving video stream over UDP.
"""
try:
stop_udp_stream(app) # Ensure any existing UDP stream is stopped
if hasattr(app, 'udp_client') and app.udp_client:
app.udp_client.reset(ip, port)
else:
app.udp_client = UdpClient(ip, port)
app.udp_client.change_pixmap_signal.connect(lambda frame: update_frame(app, frame))
app.udp_client.error_signal.connect(lambda error: show_error(app, error))
app.udp_client.start()
print(f"Started UDP stream on {ip}:{port}")
except Exception as e:
print(f"Error while starting UDP stream: {e}")
def update_frame(app, frame):
"""
Update the video frame from the UDP stream.
"""
try:
if frame is not None:
print("Updating frame in GUI")
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
h, w, ch = frame.shape
bytes_per_line = ch * w
qt_image = QImage(frame.data, w, h, bytes_per_line, QImage.Format_RGB888)
qt_pixmap = QPixmap.fromImage(qt_image).scaled(app.live_video_widget.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
app.live_video_widget.setPixmap(qt_pixmap)
QApplication.processEvents() # Refresh the GUI
else:
print("Received empty frame")
except Exception as e:
print(f"Error while updating frame: {e}")
def show_error(app, error):
"""
Show error message in the GUI.
"""
QMessageBox.critical(app, "Error", error)
def close_event(app):
"""
Handle the close event to release the video capture.
"""
try:
if hasattr(app, 'cap') and app.cap:
app.cap.release()
print("Video capture released.")
if hasattr(app, 'udp_client') and app.udp_client:
app.udp_client.stop()
print("UDP client stopped.")
except Exception as e:
print(f"Error while closing: {e}")
I hope that these are enough.will share more if required.
inam_1611 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
Try this
import sys
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
import socket
class UdpWorker(QThread):
data_received = pyqtSignal(str)
def __init__(self):
super().__init__()
self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.udp_socket.bind(('0.0.0.0', 12345)) # Bind to any address and port 12345
self.running = True
def run(self):
while self.running:
try:
data, addr = self.udp_socket.recvfrom(1024) # Buffer size is 1024 bytes
self.data_received.emit(data.decode('utf-8'))
except socket.error as e:
print(f"Socket error: {e}")
self.running = False
def stop(self):
self.running = False
self.udp_socket.close()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.label = QLabel("Listening for UDP packets...", self)
self.setCentralWidget(self.label)
self.udp_worker = UdpWorker()
self.udp_worker.data_received.connect(self.update_label)
self.udp_worker.start()
def update_label(self, data):
self.label.setText(f"Received: {data}")
def closeEvent(self, event):
self.udp_worker.stop()
self.udp_worker.wait()
super().closeEvent(event)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())