How to Start and Stop Individual Cameras in the Multi-Cam Face Tracker
Call CameraManager.start_camera(cam_id) and CameraManager.stop_camera(cam_id) from core/camera_manager.py to control specific camera threads independently.
The aarambhdevhub/multi-cam-face-tracker repository implements a thread-per-camera architecture that allows dynamic lifecycle management of video capture devices. Understanding how to start and stop individual cameras programmatically enables selective processing workflows and precise resource control without restarting the entire application.
Camera Management Architecture
The CameraManager class in core/camera_manager.py serves as the central authority for camera lifecycle operations. It reads the YAML configuration from config/config.yaml, instantiates a CameraConfig for each entry, and maintains dedicated daemon threads for every enabled camera. Each running camera receives its own queue.Queue (maxsize = 1) to hold the latest frame, ensuring thread-safe communication between capture threads and the main application loop.
The manager uses a single threading.Event (self.stop_event) to signal graceful shutdown to individual threads. When you start and stop individual cameras, the manager handles thread cleanup automatically to prevent resource leaks.
Starting Individual Cameras
Programmatic Control via start_camera()
To activate a specific camera, invoke CameraManager.start_camera(cam_id: int) -> bool. This method performs validation checks to ensure the camera ID exists and is marked enabled in the configuration, then spawns a capture thread running the internal _capture_frames(cam_id) method.
from core.camera_manager import CameraManager
# Initialise the manager with the YAML config
cam_mgr = CameraManager(config_path="config/config.yaml")
# Start camera with ID 2 (must exist and be enabled)
if cam_mgr.start_camera(2):
print("Camera 2 started")
else:
print("Failed to start Camera 2")
As implemented in lines 98-124 of core/camera_manager.py, the method cleans up any existing thread for that camera ID, creates a fresh frame queue, and starts the daemon thread before returning True on success.
Stopping Individual Cameras
Graceful Thread Termination
To stop a specific camera without affecting others, call CameraManager.stop_camera(cam_id: int) -> bool. This method looks up the thread associated with the camera ID, signals it to exit via the stop event, and joins the thread to ensure complete termination.
# Stop camera with ID 2
if cam_mgr.stop_camera(2):
print("Camera 2 stopped")
else:
print("Camera 2 was not running")
The implementation in lines 126-132 of core/camera_manager.py delegates to _cleanup_camera_thread(cam_id), which clears the associated frame queue and removes the thread reference from internal dictionaries. This prevents memory leaks and ensures the camera can be restarted cleanly later.
Qt UI Integration
MainWindow Action Slots
The graphical interface in ui/main_window.py provides convenience wrappers that forward user selections to the manager. The start_selected_camera() and stop_selected_camera() methods retrieve the current camera ID from a combo box and invoke the corresponding manager methods.
# Inside the Qt UI class (MainWindow)
self.camera_combo.setCurrentIndex(0) # selects the first entry (e.g., ID 1)
self.start_selected_camera() # triggers start_camera(1)
# … later …
self.stop_selected_camera() # triggers stop_camera(1)
These slots automatically update the status label based on the boolean return value, as shown in lines 63-79 of ui/main_window.py.
Configuration Prerequisites
Cameras must be explicitly enabled in config/config.yaml (enabled: true) before they can be started. Attempting to start a disabled camera returns False and generates a warning log. The manager validates this flag during the start_camera() call to prevent initialization of unavailable hardware.
Summary
start_camera(cam_id)validates the camera configuration, creates a frame queue, and spawns a daemon thread executing_capture_frames().stop_camera(cam_id)signals thread termination via the internal stop event, joins the thread, and cleans up the frame queue through_cleanup_camera_thread().- Configuration requirement: The target camera must have
enabled: trueinconfig/config.yaml. - UI convenience:
ui/main_window.pyexposesstart_selected_camera()andstop_selected_camera()for integration with Qt combo box selections. - Thread safety: Each camera operates with isolated
queue.Queueinstances and sharedthreading.Eventsignaling for graceful shutdown.
Frequently Asked Questions
What happens if I try to start a disabled camera?
The start_camera() method checks the enabled flag in the camera configuration and returns False immediately if the camera is disabled, logging a warning to indicate the rejection. No thread is spawned for disabled cameras.
Can I start or stop all cameras simultaneously?
Yes. The CameraManager provides start_all_cameras() to iterate over the configuration and start every enabled camera, and stop_all_cameras() to set the global stop event, join all threads, and clear internal dictionaries simultaneously.
Is the frame queue cleared when stopping a camera?
Yes. The _cleanup_camera_thread() method called by stop_camera() explicitly clears the frame queue associated with the camera ID, ensuring no stale frames persist between restart cycles and preventing memory leaks.
How does the UI know which camera to start or stop?
The MainWindow class maintains a combo box populated with camera IDs. The start_selected_camera() and stop_selected_camera() slots extract the current ID from this widget (lines 63-79 of ui/main_window.py) and pass it directly to the corresponding CameraManager methods.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →