Web Viewer Filter
The Web Viewer filter is an output filter for OpenFilter that provides a web-based visualization of incoming image streams. It hosts a FastAPI application that serves JPEG-encoded frames via a multipart/x-mixed-replace stream, accessible through a web browser. The filter also provides a /data
endpoint for streaming frame metadata, making it ideal for real-time monitoring and debugging of OpenFilter pipelines.
Overview
The Web Viewer filter is designed to handle web-based visualization scenarios where you need to:
- Display real-time image streams in a web browser
- Monitor OpenFilter pipeline output visually
- Debug image processing results
- Provide live visualization for multiple topics
- Stream frame metadata alongside images
- Host a web interface for pipeline monitoring
- Support multiple concurrent viewers
- Integrate with existing web applications
Key Features
- Web-based Visualization: Real-time image display in web browsers
- Multipart Streaming: Efficient JPEG streaming via multipart/x-mixed-replace
- Metadata Streaming: Frame data streaming via
/data
endpoint - Multi-topic Support: Display images from multiple topics
- Concurrent Viewers: Support multiple simultaneous viewers
- FastAPI Integration: Modern web framework with automatic API documentation
- CORS Support: Cross-origin resource sharing for web integration
- Responsive Design: Works on desktop and mobile browsers
Configuration
Basic Configuration
from openfilter.filter_runtime.filter import Filter
from openfilter.filter_runtime.filters.webvis import Webvis
# Simple web visualization
Filter.run_multi([
# ... other filters above
(Webvis, dict(
sources='tcp://localhost:5550',
outputs='tcp://*:5552',
port=8000,
)),
])
Advanced Configuration with Multiple Options
# Web visualization with available options
Filter.run_multi([
# ... other filters above
(Webvis, dict(
sources='tcp://localhost:5550',
outputs='tcp://*:5552',
port=8000,
host='0.0.0.0', # Listen on all interfaces
)),
])
Environment Variables
You can configure via environment variables:
export FILTER_SOURCES="tcp://localhost:5550"
export FILTER_OUTPUTS="tcp://*:5552"
export FILTER_PORT="8000"
export FILTER_HOST="0.0.0.0"
Web Interface
Main Visualization Page
The Web Viewer filter provides a web interface accessible at:
http://localhost:8000/
Page Features
- Real-time Image Display: Shows incoming images as they arrive
- Topic Selection: Dropdown to select different topics
- Metadata Display: Shows frame information and statistics
- Responsive Layout: Adapts to different screen sizes
- Auto-refresh: Automatically updates with new frames
Image Streaming Endpoint
Topic Endpoint (/{topic}
)
Provides real-time image streaming for specific topics:
GET /
GET /main
GET /camera1
Stream Features
- Multipart/x-mixed-replace: Standard MJPEG streaming format
- Topic-based URLs: Direct topic access via URL path
- JPEG Encoding: Efficient image compression
- Real-time Updates: Immediate frame updates
- Browser Compatibility: Works with all modern browsers
Stream Examples
# Stream main topic (default)
curl -N http://localhost:8000/
# Stream main topic explicitly
curl -N http://localhost:8000/main
# Stream camera1 topic
curl -N http://localhost:8000/camera1
Data Streaming Endpoint
Data Endpoint (/{topic}/data
)
Provides frame metadata streaming for specific topics:
GET /main/data
GET /camera1/data
Data Features
- Server-Sent Events: Real-time data streaming via text/event-stream
- JSON Data: Frame data dictionary as JSON string
- Topic-based URLs: Data from specific topics via URL path
- Event Stream: Real-time data updates every second
- API Integration: Easy integration with web applications
Data Format
The /data
endpoint streams Server-Sent Events with the following format:
data: {'meta': {'id': 231, 'ts': 1758745938.571617, 'src': 'file://./data/video-03.mp4', 'src_fps': 25.0, 'detections': [{'class': 'face', 'rois': [421, 133, 503, 236], 'confidence': 0.9186320304870605}, {'class': 'face', 'rois': [754, 8, 826, 132], 'confidence': 0.9028760194778442}]}, 'faces_detected': 2, 'face_coordinates': [{'bbox': [421, 133, 82, 103], 'confidence': 0.9186320304870605}, {'bbox': [754, 8, 72, 124], 'confidence': 0.9028760194778442}], 'face_details': [{'face_id': 0, 'bounding_box': {'x': 421, 'y': 133, 'width': 82, 'height': 103}, 'center': {'x': 462, 'y': 184}, 'confidence': 0.9186320304870605}, {'face_id': 1, 'bounding_box': {'x': 754, 'y': 8, 'width': 72, 'height': 124}, 'center': {'x': 790, 'y': 70}, 'confidence': 0.9028760194778442}]}
Data Examples
# Stream main topic data
curl -N http://localhost:8000/main/data
# Response: Server-Sent Events with JSON frame data
# Stream camera1 topic data
curl -N http://localhost:8000/camera1/data
# Response: Server-Sent Events with JSON frame data
Topic Management
The Web Viewer filter automatically creates endpoints for any topics that receive data. Topics are discovered dynamically from incoming frames - you cannot configure which topics to include or exclude.
Usage Examples
Example 1: Basic Web Visualization
Filter.run_multi([
# ... other filters above
(VideoIn, dict(
sources='file:///input.mp4',
outputs='tcp://*:5550',
)),
(ObjectDetection, dict(
sources='tcp://localhost:5550',
outputs='tcp://*:5552',
)),
(Webvis, dict(
sources='tcp://localhost:5552',
outputs='tcp://*:5554',
port=8000,
)),
])
Behavior: Displays object detection results in web browser at http://localhost:8000
.
Example 2: Multi-Camera Monitoring
Filter.run_multi([
# ... other filters above
(VideoIn, dict(
sources='0', # Camera 1
outputs='tcp://*:5550',
)),
(VideoIn, dict(
sources='1', # Camera 2
outputs='tcp://*:5552',
)),
(Webvis, dict(
sources=[
'tcp://localhost:5550',
# need to remap the topic, cause 1 main topic is accepted
'tcp://localhost:5552;>camera2'],
outputs='tcp://*:5554',
port=8000,
)),
])
Behavior: Monitors multiple cameras with topic selection in web interface.
Example 3: Real-time Processing Visualization
Filter.run_multi([
# ... other filters above
(VideoIn, dict(
sources='rtsp://camera.local/stream',
outputs='tcp://*:5550',
)),
(FaceDetection, dict(
sources='tcp://localhost:5550',
outputs='tcp://*:5552',
)),
(Webvis, dict(
sources='tcp://localhost:5552',
outputs='tcp://*:5554',
port=8000,
)),
])
Behavior: Shows face detection results with metadata streaming.
Example 4: Debugging and Development
Filter.run_multi([
# ... other filters above
(ImageIn, dict(
sources='file:///images/',
outputs='tcp://*:5550',
)),
(Util, dict(
sources='tcp://localhost:5550',
outputs='tcp://*:5552',
log=True, # Log frame data
)),
(Webvis, dict(
sources='tcp://localhost:5552',
outputs='tcp://*:5554',
port=8000,
)),
])
Behavior: Provides debugging interface with logged data visualization.
Example 5: Production Monitoring
Filter.run_multi([
# ... other filters above
(VideoIn, dict(
sources='rtsp://production-camera.local/stream',
outputs='tcp://*:5550',
)),
(ProductionProcessor, dict(
sources='tcp://localhost:5550',
outputs='tcp://*:5552',
)),
(Webvis, dict(
sources='tcp://localhost:5552',
outputs='tcp://*:5554',
port=8000,
host='0.0.0.0', # Listen on all interfaces
)),
])
Behavior: Production monitoring accessible from any network location.
Example 6: API Integration
Filter.run_multi([
# ... other filters above
(VideoIn, dict(
sources='0', # Webcam
outputs='tcp://*:5550',
)),
(Webvis, dict(
sources='tcp://localhost:5550',
outputs='tcp://*:5552',
port=8000,
)),
])
API Endpoints
Available Endpoints
1. Root Endpoint (/
)
- Method: GET
- Purpose: Main web interface
- Response: HTML page with visualization
2. Topic Stream Endpoint (/{topic}
)
- Method: GET
- Purpose: Image streaming for specific topic
- Parameters:
topic
in URL path - Response: multipart/x-mixed-replace JPEG stream
3. Topic Data Endpoint (/{topic}/data
)
- Method: GET
- Purpose: Frame metadata streaming for specific topic
- Parameters:
topic
in URL path - Response: text/event-stream data
API Examples
Stream Images
curl -N http://localhost:8000/main
# Response: multipart/x-mixed-replace JPEG stream
curl -N http://localhost:8000/camera1
# Response: multipart/x-mixed-replace JPEG stream
Stream Data
curl -N http://localhost:8000/main/data
# Response: text/event-stream data
curl -N http://localhost:8000/camera1/data
# Response: text/event-stream data
CORS Configuration
The Web Viewer filter has CORS (Cross-Origin Resource Sharing) hardcoded to allow all origins (*
). This cannot be configured - all web requests from any domain are allowed by default.
Performance Considerations
Web Server Performance
- Concurrent Connections: FastAPI handles multiple viewers
- Memory Usage: Image buffering for multiple viewers
- CPU Usage: JPEG encoding for each viewer
- Network Bandwidth: Multiple concurrent streams
Image Processing Performance
- JPEG Quality: Balance between quality and size
- Frame Rate: Limit frame rate for web display
- Resolution: Optimize resolution for web viewing
- Compression: Efficient JPEG compression
Optimization Strategies
# Optimize for web performance
Filter.run_multi([
# ... other filters above
(VideoIn, dict(
sources='file:///input.mp4',
outputs='tcp://*:5550',
)),
(Util, dict(
sources='tcp://localhost:5550',
outputs='tcp://*:5552',
resize='800x600', # Smaller images for web
maxfps=15, # Lower frame rate
)),
(Webvis, dict(
sources='tcp://localhost:5552',
outputs='tcp://*:5554',
port=8000,
)),
])
Error Handling
Common Error Scenarios
- Port Conflicts: Port already in use
- Image Processing Errors: Failed image encoding
- Network Issues: Connection failures
- Memory Issues: Insufficient memory for buffering
- Browser Compatibility: Unsupported browser features
Error Recovery
- Automatic Retry: Retries failed operations
- Graceful Degradation: Continues with available functionality
- Error Logging: Logs errors for debugging
- Resource Cleanup: Proper cleanup on failures
Error Examples
# Port already in use
port=8000 # Error: Port 8000 already in use
# Invalid host binding
host='invalid' # Error: Invalid host address
# CORS configuration error
# CORS cannot be configured - it's hardcoded
Debugging and Monitoring
Debug Configuration
import logging
logging.basicConfig(level=logging.DEBUG)
# Enable webvis debugging
export DEBUG_WEBVIS=true
export LOG_LEVEL=DEBUG
Debug Information
- Web Server Status: Shows server startup and status
- Connection Information: Logs client connections
- Image Processing: Logs image encoding operations
- Error Details: Detailed error information
Monitoring
- Active Connections: Track number of active viewers
- Frame Rates: Monitor actual vs. target frame rates
- Error Rates: Track connection and processing errors
- Resource Usage: Monitor memory and CPU usage
Troubleshooting
Common Issues
Web Server Issues
- Check port availability
- Verify host binding
- Check firewall settings
- Validate configuration parameters
Image Display Issues
- Check image format support
- Verify JPEG encoding
- Monitor frame rate
- Check browser compatibility
Network Issues
- Check network connectivity
- Verify CORS configuration
- Monitor bandwidth usage
- Test with different browsers
Performance Issues
- Optimize image resolution
- Reduce frame rate
- Monitor resource usage
- Check concurrent connections
Debug Configuration
# Enable comprehensive debugging
Filter.run_multi([
# ... other filters above
(Webvis, dict(
sources='tcp://localhost:5550',
outputs='tcp://*:5552',
port=8000,
)),
])
Advanced Usage
Custom Web Interface
# Custom web interface integration
Filter.run_multi([
# ... other filters above
(Webvis, dict(
sources='tcp://localhost:5550',
outputs='tcp://*:5552',
port=8000,
)),
])
Multi-Stream Integration
# Multiple web visualization instances
Filter.run_multi([
# ... other filters above
(VideoIn, dict(
sources='0', # Camera 1
outputs='tcp://*:5550',
)),
(VideoIn, dict(
sources='1', # Camera 2
outputs='tcp://*:5552',
)),
(Webvis, dict(
sources='tcp://localhost:5550',
outputs='tcp://*:5554',
port=8000,
)),
(Webvis, dict(
sources='tcp://localhost:5552',
outputs='tcp://*:5556',
port=8081,
)),
])
API Integration
# API integration with external systems
Filter.run_multi([
# ... other filters above
(Webvis, dict(
sources='tcp://localhost:5550',
outputs='tcp://*:5552',
port=8000,
)),
])
API Reference
WebvisConfig
class WebvisConfig(FilterConfig):
sources: str | list[str] | list[tuple[str, dict[str, Any]]]
outputs: str | list[str] | list[tuple[str, dict[str, Any]]]
port: int | None
host: str | None
Webvis
class Webvis(Filter):
FILTER_TYPE = 'Output'
@classmethod
def normalize_config(cls, config)
def init(self, config)
def setup(self, config)
def shutdown(self)
def process(self, frames)
def create_web_app(self)
def stream_images(self, topic)
def stream_data(self, topic)
def get_available_topics(self)
def encode_image(self, frame)
Environment Variables
FILTER_SOURCES
: Input sourcesFILTER_OUTPUTS
: Output destinationsFILTER_PORT
: Web server port (default: 8000)FILTER_HOST
: Web server host (default: '0.0.0.0')