Worked with same IP cameras for some time, and noticed that camera use much processing power because of multiple connections. Writing streaming server looked as nice solution so I decided to write my own. This code is posted to my github page
Main.py
import sys
import socket
import _thread
import time
import signal
from Libs import Connection
# Create socket and listen on port 5005
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(("", 5005))
server_socket.listen(5)
connections = []
opened_cameras = {}
def signal_handler(signal=None, frame=None):
exit(0)
# Loop and check for new connections
while 1:
try:
client_socket, address = server_socket.accept()
print
"Conencted to - ", address, "\n"
cam_url = client_socket.recv(1024)
# if camera url does not exsists in oppened camera, open new connection,
# or else just append client params and pass to Connection thread
if cam_url not in opened_cameras:
# opened_cameras.append(cam_url)
client = Connection.Connection([client_socket, cam_url])
opened_cameras[cam_url] = client
_thread.start_new_thread(client.capture, (opened_cameras,))
else:
opened_cameras[cam_url].addConnection(client_socket)
connections.append([client_socket, cam_url])
except socket.timeout:
continue
except KeyboardInterrupt:
server_socket.close()
del connections
exit(0)
Libs/Connection.py
import cv2
import socket
import signal
class Connection(object):
def __init__(self, connections):
print(connections)
self.url = connections[1].decode("utf-8")
print(self.url)
self.socket = []
self.socket.append(connections[0])
self.connections = connections
# signal.signal(signal.SIGINT, signal_handler)
self.connect()
pass
def connect(self):
self.connection = cv2.VideoCapture(self.url)
return self.connection
def addConnection(self, client):
self.socket.append(client)
def capture(self, opened_cameras):
self.opened_cameras = opened_cameras
while 1:
try:
ret, frame = self.connection.read()
data = cv2.imencode('.jpg', frame)[1].tostring()
if len(self.socket):
for c in self.socket:
self.send(c,data)
else:
self.connection.release()
del self.opened_cameras[self.connections[1]]
exit(0)
# self.connections[1].close()
except KeyboardInterrupt:
self.signal_handler()
def send(self,c, data):
try:
c.send(data)
c.send(b"END!") # send param to end loop in client
except socket.error:
self.socket.remove(c)
This will check for user to connect and if same camera url is passed as parameter, Connection
class will handle passing captured images to users that request from that camera.
client/recv.py
#!/usr/bin/python
import socket
import cv2
import numpy
import random
import sys
host = sys.argv[1] # e.g. localhost, 192.168.1.123
cam_url = sys.argv[2] # rtsp://user:pass@url/live.sdp , http://url/video.mjpg ...
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
client_socket.connect((host, 5005))
name = str(random.random()) # gives random name to create window
client_socket.send(str.encode(cam_url))
def rcv():
data = b''
while 1:
try:
r = client_socket.recv(90456)
if len(r) == 0:
exit(0)
a = r.find(b'END!')
if a != -1:
data += r[:a]
break
data += r
except Exception as e:
print(e)
continue
nparr = numpy.fromstring(data, numpy.uint8)
frame = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
if type(frame) is type(None):
pass
else:
try:
cv2.imshow(name,frame)
if cv2.waitKey(10) == ord('q'):
client_socket.close()
sys.exit()
except:
client_socket.close()
exit(0)
while 1:
rcv()
Unique window name is required because there will no be two windows if two clients are opened from the same PC. CPU usage is very low, on my PC cpu usage is 4% when server have connection, and on every other connection which uses the same params, there is no update in cpu usage.
Basic server usage:
python3 Main.py
Client usage:
cd client
python3 recv.py localhost rtsp://192.168.1.123/live2.sdp
Params for recv.py are
- host where server is running
- Camera video address
export DISPLAY=:0
(or what your display is) before running. And I dont understand last part, no matches found? Did you mean no found for host info? Just provide right host address. \$\endgroup\$