About multi camera svo recording

Good afternoon sir,
I have a question about multi camera svo recording using zed2i camera.
My final goal is record svo file with 2 camera at the same time.

My code consists of three modules.

  • main.py
  • camera_logging.py
  • utils.py

When I run the main code,

[ZED][ERROR] [ZED] Cannot start camera stream. Make sure your camera is not already used by another process or blocked by firewall.

The above error occurs.

Can you tell me what is wrong with my code?

main.py

'''
main module
'''

from loguru import logger
from camera_logging import CamRecorder
import multiprocessing


def create_process():
    cam1 = CamRecorder(cam_serial_nr="36824395", output_folder= "C:/Users/MSDL-DESK-02/Desktop/camera1", file_prefix = "cam1")
    cam2 = CamRecorder(cam_serial_nr="36568851", output_folder= "C:/Users/MSDL-DESK-02/Desktop/camera2", file_prefix = "cam2")
    logger.debug("Start recording")
    cam1.start_recording()
    cam2.start_recording()
    

@logger.catch
def main():
    p1 = multiprocessing.Process(target=create_process)
    p1.start()
    p1.join()
    

if __name__ == "__main__":
    logger.add("logs/{time}.log", rotation="100 MB",level="INFO")
    # logger.add(sys.stdout, level="INFO")
    main()

camera_logging.py

'''
camera_logging.py module
'''

import pyzed.sl as sl
from signal import signal, SIGINT
from loguru import logger
from pathlib import Path
from utils import check_path,svo_path
from time import sleep


class CamRecorder:
    def __init__(self,cam_serial_nr:str = "",rec_duration_s:int=60,output_folder:Path = "C:/Users/MSDL-DESK-02/Desktop",file_prefix:str = "cam1") -> None:
        if cam_serial_nr:
            self.cam_serial_nr = cam_serial_nr
            print("serial_num:",self.cam_serial_nr)
            self.cam = sl.Camera(self.cam_serial_nr)
        else:
            logger.info("No camera serial number provided, using first camera found")
            self.cam = sl.Camera()
            print(self.cam)
            pass

        self.output_path =  check_path(output_folder)
        self.file_prefix = file_prefix
        self.rec_duration_s = rec_duration_s 
        self.signal = signal(SIGINT, self.handler) # signal handler for ctrl-c
        self.init = sl.InitParameters()
        self.init.camera_resolution = sl.RESOLUTION.HD2K
        self.init.depth_mode = sl.DEPTH_MODE.NEURAL
        self.init.camera_fps = 15
        self.init.coordinate_units = sl.UNIT.MILLIMETER
        self.init.camera_disable_self_calib = True
        self.init.sdk_verbose = True
        self.status = self.cam.open(self.init)
        self.run = 0
        if self.status != sl.ERROR_CODE.SUCCESS:
            logger.error(repr(self.status))
            exit(1)
        
        logger.debug("Camera opened")

    def handler(self,signal_received, frame):
        """handler for ctrl-c to stop recording"""
        logger.info("SIGINT or CTRL-C detected. Exiting gracefully")
        self.cam.disable_recording()
        self.cam.close()
        self.run = 0
        
    def start_recording(self):
        """Start recording SVO file"""
        logger.info("SVO is Recording, use Ctrl-C to stop.")
        path = str(svo_path(self.output_path,self.file_prefix))
        recording_param = sl.RecordingParameters(path, sl.SVO_COMPRESSION_MODE.H265)
        logger.debug(f"{recording_param.video_filename}")
        try:
            err = self.cam.enable_recording(recording_param)
        except:
            logger.error("Error in enable_recording")

        if err != sl.ERROR_CODE.SUCCESS:
            logger.error("Failed to start recording")
            exit(1)
            
        
        logger.debug(f"Recording duration is {self.rec_duration_s} seconds")
        runtime = sl.RuntimeParameters()
        frames_recorded = 0
        self.run = 1
        fps = self.cam.get_camera_information().camera_fps   
        # run until ctrl-c or stop_recording is called
        while self.run:
            if self.cam.grab(runtime) == sl.ERROR_CODE.SUCCESS :
                frames_recorded += 1
                duration = frames_recorded / fps
                if duration > self.rec_duration_s:
                    logger.debug(f"Recording duration reached, save current recording to {recording_param.video_filename}")
                    self.cam.disable_recording()#stop recording
                    sleep(0.1) #give camera time to close recording
                    recording_param.video_filename = svo_path(self.output_path,self.file_prefix)
                    self.cam.enable_recording(recording_param) #restart recording
                    frames_recorded = 0 #reset counter
                    
        #done recording
        self.cam.disable_recording()    
        self.cam.close()
        
        
    def stop_recording(self):
        self.cam.disable_recording()
        self.run = 0
        return True
    
    def reconnect_cam(self):
        try:
            self.cam.close()
            sleep(0.1)
            self.cam.open(self.init)
            return True
        except:
            return False
        
    def is_recording(self):
        return self.cam.is_recording_enabled()

utils.py

'''
utils module
'''

from pathlib import Path
from datetime import datetime
import os
from loguru import logger as lo

def check_path(path:str= "")-> Path:
    """Check if path exists, if not raise FileNotFoundError"""
    lo.debug(f"Checking path {path}")
    if path:
        path = Path(path)
        if path.exists():
            return Path(path)
        else:
            raise FileNotFoundError(f"Path {path} does not exist.")
    else:
        raise ValueError("Path cannot be empty.")

def dateandtime()-> str:
    """Return current date and time as string"""
    return datetime.now().strftime("%Y-%m-%d_%H-%M-%S")

def svo_path(folder:str , prefix:str)-> str:
    """Return path to SVO file"""
    return str(os.path.join(folder,f"{prefix}_{dateandtime()}.svo"))

best regards,

Yoon