When trying to stream 4k video from the color camera, I noticed a much lower bandwidth than I was setting. I wrote the following python program to test and investigate by measuring system resources and fps received.
When I stream 4k resolution with an mjpeg video encoder (ENCODE_VIDEO = True
), I am able to get 42 fps (max from ColorCamera Node), but if I remove the video encoder node(ENCODE_VIDEO=False
), I can only get 12-15 fps. When I use usbtop
to monitor USB bandwidth, I still only see 170 Mbps, and that is with a thunberbolt 3 cable on a thunderbolt 3 USB-C port, so I would expect the speeds to be higher.
Screenshots of the program's output along with usbtop
measurements are shown below for both cases (encoding and no encoding). Is this expected behavior?
No encoding:
With MJPEG encoding:
import cv2
import depthai as dai
import time
import curses
ENCODE_VIDEO = True
def printSystemInformation(info, fps):
m = 1024 * 1024 # MiB
stdscr.addstr(0, 0, f"Ddr used / total - {info.ddrMemoryUsage.used / m:.2f} / {info.ddrMemoryUsage.total / m:.2f} MiB")
stdscr.addstr(1, 0, f"Cmx used / total - {info.cmxMemoryUsage.used / m:.2f} / {info.cmxMemoryUsage.total / m:.2f} MiB")
stdscr.addstr(2, 0, f"LeonCss heap used / total - {info.leonCssMemoryUsage.used / m:.2f} / {info.leonCssMemoryUsage.total / m:.2f} MiB")
stdscr.addstr(3, 0, f"LeonMss heap used / total - {info.leonMssMemoryUsage.used / m:.2f} / {info.leonMssMemoryUsage.total / m:.2f} MiB")
t = info.chipTemperature
stdscr.addstr(4, 0, f"Chip temperature - average: {t.average:.2f}, css: {t.css:.2f}, mss: {t.mss:.2f}, upa: {t.upa:.2f}, dss: {t.dss:.2f}")
stdscr.addstr(5, 0, f"Cpu usage - Leon CSS: {info.leonCssCpuUsage.average * 100:.2f}%, Leon MSS: {info.leonMssCpuUsage.average * 100:.2f} %")
stdscr.addstr(6, 0, "----------------------------------------")
stdscr.addstr(7, 0, f"Speed: {fps:.1f} fps")
stdscr.addstr(8, 0, "----------------------------------------")
stdscr.refresh()
# Create pipeline
pipeline = dai.Pipeline()
# Define source and output
camRgb = pipeline.createColorCamera()
if ENCODE_VIDEO:
videoEncoder = pipeline.createVideoEncoder()
xoutVideo = pipeline.createXLinkOut()
xoutVideo.setStreamName("video")
# Properties
camRgb.setBoardSocket(dai.CameraBoardSocket.RGB)
camRgb.setResolution(dai.ColorCameraProperties.SensorResolution.THE_4_K)
camRgb.setVideoSize(3840, 2160)
camRgb.setFps(42)
camRgb.setInterleaved(False)
if ENCODE_VIDEO:
videoEncoder.setDefaultProfilePreset(camRgb.getVideoSize(), camRgb.getFps(), dai.VideoEncoderProperties.Profile.MJPEG)
xoutVideo.input.setBlocking(False)
xoutVideo.input.setQueueSize(1)
# Linking
if ENCODE_VIDEO:
camRgb.video.link(videoEncoder.input)
videoEncoder.bitstream.link(xoutVideo.input)
else:
camRgb.video.link(xoutVideo.input)
#-------------------- System Log pipeline -------------------------#
sysLog = pipeline.createSystemLogger()
linkOut = pipeline.createXLinkOut()
linkOut.setStreamName("sysinfo")
sysLog.setRate(1) # 1 Hz
sysLog.out.link(linkOut.input)
#------------------------------------------------------------------#
# Connect to device and start pipeline
with dai.Device(pipeline) as device:
video = device.getOutputQueue(name="video", maxSize=1, blocking=False)
qSysInfo = device.getOutputQueue(name="sysinfo", maxSize=1, blocking=False)
# for updating sysinfo numbers in terminal
stdscr = curses.initscr()
curses.noecho()
curses.cbreak()
timeLast = time.time()
pktCntr = 0
fps = 0
while True:
videoIn = video.get()
pktCntr = pktCntr + 1
# if ENCODE_VIDEO:
# frame = cv2.imdecode(videoIn.getData(), cv2.IMREAD_UNCHANGED)
# else:
# frame = videoIn.getCvFrame()
# # Display
# cv2.imshow('video', frame)
# System Log
sysInfo = qSysInfo.tryGet()
if sysInfo is not None:
fps = pktCntr/(time.time() - timeLast)
timeLast = time.time()
pktCntr = 0
printSystemInformation(sysInfo, fps)
if cv2.waitKey(1) == ord('q'):
break