A Python-based system that captures video from a webcam and streams it simultaneously to multiple independent consumer processes. This allows parallel processing of the same video feed without interference—perfect for object detection, computer vision analysis, and real-time video processing tasks.
This project demonstrates how to:
- Capture webcam video on macOS
- Serve the stream to multiple independent Python processes via TCP
- Process the same video feed in parallel with different algorithms
- Monitor all streams in real-time with a Streamlit dashboard
┌─────────────┐
│ Webcam │
└──────┬──────┘
│
┌──────▼───────────────────┐
│ producer.py (TCP Server) │ Captures frames and serves on 3 ports
├──────┬────────┬──────────┤
│ :9999│ :10000 │ :10001 │
└──┬───┴─┬──────┴────┬─────┘
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌─────────────┐
│consumer1 │ │consumer2 │ │app.py │
│(port10k) │ │(port10k) │ │(Streamlit) │
│Object │ │Other │ │Dashboard │
│Detection │ │Processing│ │Monitor │
└──────────┘ └──────────┘ └─────────────┘
- producer.py - Captures webcam frames and broadcasts to three TCP ports (9999, 10000, 10001)
- consumer1.py - Example consumer process receiving on port 10000
- consumer2.py - Example consumer process receiving on port 10001
- app.py - Streamlit dashboard for real-time visualization of all three streams
- README.md - This file
- macOS (or Linux with OpenCV support)
- Python 3.7+
- A connected webcam
- Clone or download this project
cd /path/to/project- Install required packages
pip install opencv-python numpy streamlitOpen 4 terminal windows and run:
Terminal 1 - Start the producer
python producer.pyExpected output:
Webcam opened. Capturing at 30 FPS
[producer] Server listening on localhost:9999
[consumer1] Server listening on localhost:10000
[consumer2] Server listening on localhost:10001
Terminal 2 - Start consumer 1
python consumer1.pyExpected output:
[Consumer-1] Attempting to connect to localhost:10000
[Consumer-1] Connected successfully!
[Consumer-1] Received frame 1, Shape: (480, 640, 3), FPS: 30.00
[Consumer-1] Received frame 2, Shape: (480, 640, 3), FPS: 30.00
...
Terminal 3 - Start consumer 2
python consumer2.pyTerminal 4 - Start the Streamlit dashboard
streamlit run app.pyThis will open your browser to http://localhost:8501 with a dashboard showing:
- Producer stream (raw webcam feed)
- Consumer 1 stream (port 10000)
- Consumer 2 stream (port 10001)
Click "Connect All" in the sidebar to begin streaming.
The producer:
- Captures frames from the default webcam at 30 FPS
- Encodes frames as JPEG
- Broadcasts to three independent TCP servers
- Each client receives the same frame stream
Key features:
- Thread-safe frame buffering
- Non-blocking client handling
- Automatic client cleanup on disconnect
- 30 FPS capture rate (configurable)
Each consumer:
- Connects to a specific TCP port
- Receives frames one at a time
- Decodes and processes frames
- Tracks FPS and frame count
Customization:
Replace the processing loop in the run() method with your own logic:
while True:
frame = self.receive_frame()
if frame is None:
break
# Your processing here
# e.g., object detection, filtering, edge detection, etc.
print(f"[{self.name}] Processing frame {frame_count}")The Streamlit dashboard:
- Connects to all three TCP servers
- Displays three video feeds side-by-side
- Shows real-time FPS and frame counts
- Status indicators for each stream
Features:
- Live video visualization
- Connect/Disconnect buttons
- Frame statistics
- Connection status monitoring
In producer.py, change the FRAME_RATE variable:
FRAME_RATE = 30 # Change to desired FPSModify the PORTS dictionary in producer.py:
PORTS = {
'producer': 9999,
'consumer1': 10000,
'consumer2': 10001
}And update the corresponding PORT in consumer files.
In producer.py, change the camera index:
cap = cv2.VideoCapture(0) # 0 = default, 1 = external USB, etc.Here's how to add object detection to consumer1:
# In consumer1.py, after receiving a frame:
import cv2
import numpy as np
# Load a pre-trained model (example: YOLO or OpenCV DNN)
# net = cv2.dnn.readNet("yolov3.weights", "yolov3.cfg")
while True:
frame = self.receive_frame()
if frame is None:
break
# Run object detection
# results = net.forward(...)
# Draw bounding boxes
# for detection in results:
# x, y, w, h = detection
# cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
# Optional: Save or display processed frame
cv2.imshow('Object Detection', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
breakIn consumer2, add other processing:
# Face detection
face_cascade = cv2.CascadeClassifier(
cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
)
while True:
frame = self.receive_frame()
if frame is None:
break
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.1, 4)
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
cv2.imshow('Face Detection', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break- Each consumer receives the entire frame stream independently
- No frame dropping between producer and consumers
- Processing speed in one consumer does not affect others
- Network overhead is minimal (all connections are local)
- Frame rate is limited by producer capture rate (default: 30 FPS)
Memory Usage:
- Producer: ~50-100 MB (depending on resolution)
- Each Consumer: ~50-100 MB (independent)
- Streamlit App: ~100-150 MB
- Ensure your webcam is connected and not in use by another application
- On macOS, grant permission: System Preferences → Security & Privacy → Camera
- Try changing the camera index:
cv2.VideoCapture(1)orcv2.VideoCapture(2)
- Make sure
producer.pyis running first - Check that the correct ports are being used
- Verify localhost is not blocked by firewall
- Network might be unstable; try increasing buffer sizes
- Check system resources (CPU/memory)
- Reduce frame rate:
FRAME_RATE = 15
- Reduce image resolution in producer
- Close other applications
- Use hardware acceleration if available
To stream across a network:
In producer.py:
HOST = '192.168.1.100' # Your machine's IPIn consumer files:
HOST = '192.168.1.100' # Server's IPAdd more ports in producer.py:
PORTS = {
'producer': 9999,
'consumer1': 10000,
'consumer2': 10001,
'consumer3': 10002,
'consumer4': 10003,
}Then create consumer3.py, consumer4.py, etc., using the corresponding ports.
Add recording functionality to any consumer:
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter('output.mp4', fourcc, 30.0, (640, 480))
while True:
frame = self.receive_frame()
if frame is None:
break
out.write(frame)
out.release()- All connections are local (localhost) by default
- Frame rate capped at capture rate
- No buffering between producer and consumer (dropped frames on slow consumers)
- JPEG compression may introduce artifacts; use lossless codecs for critical applications
- Add UDP streaming for lower latency
- Implement frame dropping/skipping for slow consumers
- Support for multiple cameras
- Frame compression options (H.264, VP9)
- Distributed processing across multiple machines
- WebRTC support for browser-based streaming
This project is provided as-is for educational and research purposes.
For issues or questions:
- Check the Troubleshooting section
- Review terminal output for error messages
- Ensure all dependencies are installed correctly
- Verify webcam permissions on macOS
Feel free to modify and extend this system for your needs!