How Deep-Live-Cam Optimizes Face Detection on Apple Silicon (M1-M5) with Adaptive Detection Rates
Deep-Live-Cam limits face detection to 30 FPS on Apple Silicon Macs by using platform-specific detection and time-based caching, significantly reducing CPU/GPU load while maintaining smooth real-time face swapping.
Deep-Live-Cam implements a dedicated Apple-Silicon-aware pipeline to optimize face detection on M-series Macs. The optimization centers on adaptive frame-skipping and result caching, ensuring that the computationally expensive detection model runs at most once every 33 milliseconds regardless of the camera's actual frame rate.
Platform Detection and Adaptive Interval Setup
The optimization begins at module import time, where the code determines whether it is running on Apple Silicon and configures the throttling parameters.
Detecting Apple Silicon Architecture
In modules/processors/frame/face_swapper.py, the code checks the platform and machine architecture to set a global flag:
IS_APPLE_SILICON = platform.system() == 'Darwin' and platform.machine() == 'arm64'
This boolean determines whether the adaptive caching logic activates. On non-Apple-Silicon systems, the pipeline falls back to standard detection on every frame.
Configuring the Detection Interval
The module defines a constant that governs the minimum time between fresh detection passes:
DETECTION_INTERVAL = 0.033 # approximately 30 FPS
This value ensures that even if the camera delivers 60 or 120 FPS, the face detection model only executes at most 30 times per second.
The get_faces_optimized Function
The core optimization lives in the get_faces_optimized function, which wraps the standard detection calls with a caching layer.
Cache-Based Fast Path
The function maintains two global state variables to track recent results:
LAST_DETECTION_TIME = 0
FACE_DETECTION_CACHE = {}
When get_faces_optimized(frame, use_cache=True) is called on Apple Silicon, it first calculates the elapsed time since the last detection:
current_time = time.time()
time_since_last = current_time - LAST_DETECTION_TIME
if time_since_last < DETECTION_INTERVAL and FACE_DETECTION_CACHE:
return FACE_DETECTION_CACHE.get('faces')
If the interval has not elapsed and cached faces exist, the function returns the cached result immediately, bypassing the model entirely.
Fresh Detection and Cache Update
When the interval expires or the cache is empty, the function executes a fresh detection using the underlying analyzers:
LAST_DETECTION_TIME = current_time
if modules.globals.many_faces:
faces = get_many_faces(frame)
else:
faces = get_one_face(frame)
FACE_DETECTION_CACHE['faces'] = faces
FACE_DETECTION_CACHE['timestamp'] = current_time
return faces
This updates the global timestamp and stores the new results for subsequent frames.
Integration with the Processing Pipeline
The optimized detection integrates into the live processing loop via modules/ui.py. The _detection_thread_func runs continuously, filling a shared detection_result dictionary. While the standard implementation calls get_many_faces or get_one_face directly, builds targeting Apple Silicon can substitute get_faces_optimized to leverage the adaptive rate limiting:
# In modules/ui.py, _detection_thread_func
if modules.globals.many_faces:
many = get_faces_optimized(frame) # Adaptive path for Apple Silicon
detection_result['many_faces'] = many
else:
face = get_faces_optimized(frame)
detection_result['target_face'] = face[0] if face else None
This ensures that the UI thread receives face coordinates at the camera frame rate, but the underlying model only executes at the throttled 30 FPS rate.
Code Examples
Basic Usage on Apple Silicon
To use the optimized detection in a custom processor:
from modules.processors.frame.face_swapper import get_faces_optimized
from modules.typing import Frame
def process_frame(frame: Frame):
# Automatically uses caching on M1-M5 Macs
faces = get_faces_optimized(frame, use_cache=True)
if faces:
# Proceed with face swapping or enhancement
pass
Patching the UI Thread
To enable adaptive detection in the live camera view:
# Inside modules/ui.py, within _detection_thread_func:
if modules.globals.many_faces:
many = get_faces_optimized(frame) # Replaces get_many_faces
detection_result['many_faces'] = many
else:
face = get_faces_optimized(frame) # Replaces get_one_face
detection_result['target_face'] = face[0] if face else None
Inspecting Cache State
For debugging performance on Apple Silicon:
from modules.processors.frame.face_swapper import (
FACE_DETECTION_CACHE,
LAST_DETECTION_TIME
)
print(f"Cached faces: {FACE_DETECTION_CACHE.get('faces')}")
print(f"Last detection: {LAST_DETECTION_TIME}")
Summary
- Platform-aware activation: Deep-Live-Cam detects Apple Silicon via
platform.system() == 'Darwin'andplatform.machine() == 'arm64'inmodules/processors/frame/face_swapper.py. - Adaptive throttling: A
DETECTION_INTERVALof 0.033 seconds (30 FPS) limits how often the face detection model runs, regardless of camera frame rate. - Result caching: The
FACE_DETECTION_CACHEdictionary stores recent detection results, allowing instantaneous retrieval for frames arriving within the throttle window. - Performance impact: By skipping redundant inference on M1-M5 Macs, the pipeline reduces CPU/GPU utilization and maintains smoother real-time face swapping.
Frequently Asked Questions
What is the detection interval used in Deep-Live-Cam?
The detection interval is set to 0.033 seconds (approximately 30 FPS) via the DETECTION_INTERVAL constant in modules/processors/frame/face_swapper.py. This value ensures that the face detection model executes at most 30 times per second, even if the camera captures video at 60 FPS or higher.
How does the cache improve performance on Apple Silicon?
The FACE_DETECTION_CACHE dictionary stores the most recent detection results and timestamp. When subsequent frames arrive within the 33-millisecond window, get_faces_optimized returns the cached face coordinates instantly without invoking the neural network. This adaptive frame-skipping dramatically reduces compute load on M-series chips while maintaining visual continuity.
Can I disable the adaptive detection on Apple Silicon?
Yes. The get_faces_optimized function accepts a use_cache parameter that defaults to True. Passing use_cache=False bypasses the Apple-Silicon-specific logic and forces a fresh detection call to get_one_face or get_many_faces on every frame, effectively disabling the adaptive rate limiting.
Where is the face detection logic implemented?
The core optimization resides in modules/processors/frame/face_swapper.py, specifically within the get_faces_optimized function (lines 54–87). The underlying face analysis utilities (get_one_face, get_many_faces) are defined in modules/face_analyser.py, and the UI integration occurs in modules/ui.py within the _detection_thread_func function.
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 →