raspberrypi / picamera2

New libcamera based python library
BSD 2-Clause "Simplified" License
891 stars 188 forks source link

[HOW-TO] Cleanly Close and Configure Cameras with Arducam Multicam v2.2 #1008

Open carlyjb opened 7 months ago

carlyjb commented 7 months ago

Describe what it is that you want to accomplish I have (2) OV5647 cameras that are attached to an Arducam Multi Camera Adapter Module V2.2. I wish to preview from Camera 0 and capture an image and then switch to showing a preview and capture an image from Camera 1.

However, whenever I try to start Camera 1 after stopping Camera 0, I get a V4L2 device or resource is busy error. ERROR V4L2 v4l2_videodevice.cpp:1047 /dev/video0[26:cap]: Unable to set format: Device or resource busy

Describe alternatives you've considered If I close() camera 0 instead of stopping, I am able to switch to camera 1 without issue. But that requires me to reinitialize/reallocate the Picamera2(0) the next time I want to switch back which is slow.

Additional context I am using a Raspi 4b running 64-bit Bullseye and a Waveshare 2.8 HDMI display. In my config.txt I am using dtoverlay=camera-mux-4port,cam0-ov5647,cam1-ov5647 and camera_auto_detect=0 to enable the multi camera adapter. libcamera-hello -t 0 --camera 0 and libcamera-hello -t 0 --camera 1 both work successfully from the terminal.

print(Picamera2.global_camera_info()) produces [{'Model': 'ov5647', 'Location': 2, 'Rotation': 0, 'Id': '/base/soc/i2c0mux/i2c@1/pca@70/i2c@0/ov5647@36'}, {'Model': 'ov5647', 'Location': 2, 'Rotation': 0, 'Id': '/base/soc/i2c0mux/i2c@1/pca@70/i2c@1/ov5647@36'}]

This is a minimal code example that reproduces the error. It occurs even with just trying to capture images without displaying the preview.

from picamera2 import Picamera2
import time

cam0 = Picamera2(0)
cam1 = Picamera2(1)

cam0.start()
cam0.capture_file("cam0.jpg")
cam0.stop()  
#code succeeds if this is cam0.close()

time.sleep(5)

cam1.start()
cam1.capture_file("cam1.jpg")
cam1.stop()
Traceback (most recent call last):
  File "/home/me/tests/test.py", line 15, in <module>
    cam1.start()
  File "/usr/lib/python3/dist-packages/picamera2/picamera2.py", line 1049, in start
    self.configure(config)
  File "/usr/lib/python3/dist-packages/picamera2/picamera2.py", line 1004, in configure
    self.configure_(camera_config)
  File "/usr/lib/python3/dist-packages/picamera2/picamera2.py", line 943, in configure_
    if self.camera.configure(libcamera_config):
RuntimeError: Failed to configure camera: Device or resource busy

How do I cleanly stop() camera 0 or force a reconfigure so that I can use camera 1 without deallocating camera 0 entirely?

davidplowman commented 7 months ago

Hi, and thanks for the question.

I think basically I have only bad news for you here. Two cameras show up because you've put them in your device tree, but unfortunately, to the Linux kernel these are the same device - that fact that there's some "magic" on the adpater board is completely unknown to it. There's no way you can have one device "left open" but use what you think is a second device but which to the kernel, is the same device - all those /dev/video<N> nodes are the same in both cases, so they all have to be closed and re-opened.

libcamera-hello works as you describe because it does a complete shutdown when the process quits, just like quitting your Python process and starting over. So far as I know, there is no difference in this respect between using libcamera directly or Picamera2.

I think these are just the limits of adapter boards like this. You could get round this using a Pi with two physically distinct camera connectors, such as a Compute Module (or Pi 5). Beyond that, I guess if there's something particularly slow about closing one camera and opening another, then maybe there's something there that can be investigated. Do you have any further data on this?