I'm currently writing a python application that sends UVC streams from two cameras to a v4l2 loopback device. Upon receiving a switching command, the application shuts down one stream and starts the other. One of the cameras is an Oak-D Pro, the other is a regular UVC-Cam which streams via ffmpeg to the loopback device.
Now when I continuously switch the cameras in intervals of 10 seconds, I noticed that the Oak-D sometimes shows a stream and sometimes would just do nothing until the other webcam (which always works) is switched on again.
The following code is used to run the stream from the Oak-D to the loopback device
import depthai as dai
import pyvirtualcam
import asyncio
import time
from concurrent.futures.thread import ThreadPoolExecutor
import logging
from asyncio.locks import Event
class
OakD
(object):
'''
classdocs
'''
def
__init__
(
self
):
'''
Constructor
'''
self
.name =
"monocam"
self
.logger = logging.getLogger()
self
._executor = ThreadPoolExecutor(max_workers=1)
self
._evt_terminate = Event()
async def
run
(
self
):
self
.current_runner_future =
self
._executor.submit(
self
._cam_runner)
def
_cam_runner
(
self
):
self
._evt_terminate.clear()
pipeline = dai.Pipeline()
cam = pipeline.create(dai.node.ColorCamera)
cam.setColorOrder(dai.ColorCameraProperties.ColorOrder.RGB)
cam.setPreviewSize(640, 480)
xout = pipeline.create(dai.node.XLinkOut)
xout.setStreamName(
"rgb"
)
cam.preview.link(xout.input)
print(
"UVC initializing"
)
with dai.Device(pipeline) as device, pyvirtualcam.Camera(width=640, height=480, fps=30, device=
'/dev/video99'
) as uvc:
print(
"UVC starting"
)
if device.getDeviceInfo().protocol == dai.XLinkProtocol.X_LINK_USB_VSC and device.getUsbSpeed() not in (dai.UsbSpeed.SUPER, dai.UsbSpeed.SUPER_PLUS):
print(
"Warning: USB speed %s"
%str(device.getUsbSpeed()))
qRgb = device.getOutputQueue(name=
"rgb"
, maxSize=4, blocking=False)
print(
"UVC running"
)
while True:
if (
self
._evt_terminate.is_set()):
self
.logger.info(
"Oak D camera got signal to terminate current pipeline"
)
break
frame = qRgb.get().getFrame()
uvc.send(frame)
async def
terminate
(
self
):
if (
self
.current_runner_future is not None):
self
._evt_terminate.set()
while (
self
.current_runner_future.running()):
await asyncio.sleep(.05)
self
.current_runner_future = None
self
.logger.info(
"Oak D camera stream successfully terminated."
)
async def
main
():
cam = OakD()
await cam.run()
if __name__ ==
'__main__'
:
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
To illustrate the problem, I added a simple main method which just starts the stream to a loopback device previously created with sudo modprobe v4l2loopback video_nr=99
. If you start the script, kill it with ctrl-c and then restart it again, the behaviour often shows. The script runs, blocks on with dai.Device(pipeline) as deviceā¦
for a few seconds and then just exits.
Another important observation: I'm using an USB2-link. When using USB3 instead, the problem seems to disappear (at least, I couldn't reproduce it with an appropriate number of tries).
Btw: Is this the right/best way for UVC-streaming? This page mentions a file examples/rgb
*uvc.py
*in the depthai-python repo, which doesn't seem to exist. The closest I could find is apps/uvc/main.py in the depthai repo, which uses the apparently nonexisting method pipeline.createUVC()
.