I have 32 of ip cameras with 5 mp and high resolution and I send frames with this code over network but this code get many cpu usage and when frames receive to client loss some of frames , please give me solved this problems
when increase my cameras use full of cpu and do not work well
I wrote Client code and check this code work well with cameras
import cv2
import zmq
import threading
import os
import subprocess
import base64
import datetime
import asyncio
import zmq.asyncio
class VideoStreamer:
def __init__(self, video_files, port=5555, server_ip="10.129.163.200", store=False):
self.video_files = video_files
self.context = zmq.asyncio.Context()
self.sockets = []
self.server_ip = server_ip
self.port = port
self.sockets_open = False
self.video_captures = []
self.store = store
cv2.cuda.setDevice(0)
def toggle_sockets(self):
if self.sockets_open:
self.close_sockets()
else:
self.open_sockets()
def open_sockets(self):
self.sockets = [self.context.socket(zmq.PUB) for _ in range(len(self.video_files))]
for i, socket in enumerate(self.sockets):
socket.bind(f"tcp://{self.server_ip}:{self.port + i}")
self.sockets_open = True
self.stopped = False
def close_sockets(self):
for socket in self.sockets:
socket.close()
self.sockets_open = False
self.stopped = True
self.video_threads.clear()
self.sockets.clear()
self.stopped = False
def start(self):
self.video_thread_captures = [threading.Thread(target=self.send_video, args=(video_stream, i))
for i, video_stream in enumerate(self.video_files)]
for thread in self.video_thread_captures:
thread.start()
def send_video(self, video_file, client_index):
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(self.send_video_async(video_file, client_index))
loop.close()
async def send_video_async(self, video_file, client_index):
cap = cv2.VideoCapture(video_file['url'])
cap.set(cv2.CAP_PROP_BUFFERSIZE, 3)
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
fps = cap.get(cv2.CAP_PROP_FPS)
while not self.stopped:
ret, frame = cap.read()
if ret:
# frame_cuda = cv2.cuda_GpuMat()
# frame_cuda.upload(frame)
# frame_cuda_resized = cv2.cuda.resize(frame_cuda, (100, 75))
# cv_rgb_image_cuda = cv2.cuda.cvtColor(frame_cuda_resized, cv2.COLOR_BGR2RGB)
#
# frame_resized = cv_rgb_image_cuda.download()
_, video_frame = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 90])
# _, video_frame = cv2.imencode('.h264', frame)
jpg_bytes = video_frame.tobytes()
jpg_base64 = base64.b64encode(jpg_bytes).decode('utf-8')
frame_with_ip = {"IP":video_file['ip'], "Frame":jpg_base64}
if self.store:
video_file['buffer'].append(frame)
if len(video_file['buffer']) > 100:
now = datetime.now()
dt_string = now.strftime("%d-%m-%Y_%H-%M-%S")
ffmpeg_d = self.export_video(video_file['root'] + dt_string, video_file['root'], width, height, fps)
for cached_frame in video_file['buffer']:
ffmpeg_d.stdin.write(cached_frame.tobytes())
# ffmpeg_d.stdin.close()
# ffmpeg_d.wait()
video_file['buffer'] = []
#
# Send the frame to the specific client
if self.sockets_open:
await self.sockets[client_index].send_json(frame_with_ip)
await asyncio.sleep(0.3) # Adjust the delay as needed
# self.sockets[client_index].send(jpg_bytes)
# cv2.waitKey(delay)
# time.sleep(0.03) # Adjust the delay based on your frame rate
def export_video(self, name, directory, width, height, fps):
file_name = f"{name}.mp4"
if not os.path.exists(directory):
os.makedirs(directory)
output_file = os.path.join(directory, file_name)
ffmpeg_cmd = [
'ffmpeg',
'-y', # Overwrite output file if it exists
'-f', 'rawvideo',
'-vcodec', 'rawvideo',
'-s', f'{int(width)}x{int(height)}',
'-pix_fmt', 'bgr24',
'-r', str(fps),
'-i', '-',
'-c:v', 'h264_nvenc',
# '-c:v' , 'h264',
'-pix_fmt', 'yuv420p',
output_file
]
# Open subprocess for ffmpeg
ffmpeg_process = subprocess.Popen(ffmpeg_cmd, stdin=subprocess.PIPE)
return ffmpeg_process