# How to Start and Stop Individual Cameras in the Multi-Cam Face Tracker

> Learn to start and stop individual cameras in the Multi-Cam Face Tracker. Use CameraManager start_camera and stop_camera functions for precise control over camera threads.

- Repository: [AarambhDevHub/multi-cam-face-tracker](https://github.com/aarambhdevhub/multi-cam-face-tracker)
- Tags: how-to-guide
- Published: 2026-02-23

---

**Call `CameraManager.start_camera(cam_id)` and `CameraManager.stop_camera(cam_id)` from [`core/camera_manager.py`](https://github.com/aarambhdevhub/multi-cam-face-tracker/blob/main/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`](https://github.com/aarambhdevhub/multi-cam-face-tracker/blob/main/core/camera_manager.py) serves as the central authority for camera lifecycle operations. It reads the YAML configuration from [`config/config.yaml`](https://github.com/aarambhdevhub/multi-cam-face-tracker/blob/main/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.

```python
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`](https://github.com/aarambhdevhub/multi-cam-face-tracker/blob/main/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.

```python

# 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`](https://github.com/aarambhdevhub/multi-cam-face-tracker/blob/main/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`](https://github.com/aarambhdevhub/multi-cam-face-tracker/blob/main/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.

```python

# 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`](https://github.com/aarambhdevhub/multi-cam-face-tracker/blob/main/ui/main_window.py).

## Configuration Prerequisites

Cameras must be explicitly enabled in [`config/config.yaml`](https://github.com/aarambhdevhub/multi-cam-face-tracker/blob/main/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: true` in [`config/config.yaml`](https://github.com/aarambhdevhub/multi-cam-face-tracker/blob/main/config/config.yaml).
- **UI convenience**: [`ui/main_window.py`](https://github.com/aarambhdevhub/multi-cam-face-tracker/blob/main/ui/main_window.py) exposes `start_selected_camera()` and `stop_selected_camera()` for integration with Qt combo box selections.
- **Thread safety**: Each camera operates with isolated `queue.Queue` instances and shared `threading.Event` signaling 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`](https://github.com/aarambhdevhub/multi-cam-face-tracker/blob/main/ui/main_window.py)) and pass it directly to the corresponding `CameraManager` methods.