Video Streamer Filter
The Video Streamer filter is an output filter for OpenFilter that writes incoming Frame images to video files or RTSP streams. It supports segmented file output by time, adaptive FPS control, and various video encoding parameters through the params dictionary. The filter uses the vidgear library for robust video writing and streaming capabilities.
Note: THIS IS NOT A RTSP SERVER. Keep in mind that when using RTSP stream as an output you will still need to use a RTSP server such as
mediamtx.
OverviewDirect link to Overview
The Video Streamer filter is designed to handle video output scenarios where you need to:
- Write processed images to video files in various formats
- Stream video to RTSP endpoints for live viewing
- Create segmented video files based on time duration
- Control video encoding parameters via the
paramsdictionary - Handle adaptive frame rate based on input
- Support multiple output formats (MP4, AVI, MOV, etc.)
- Stream to multiple RTSP clients simultaneously
Key FeaturesDirect link to Key Features
- Multiple Output Formats: MP4, AVI, MOV, MKV, WebM
- RTSP Streaming: Live video streaming to RTSP endpoints
- Time-based Segmentation: Automatic video file segmentation by time (in minutes)
- Adaptive FPS: Dynamic frame rate adjustment based on input
- Video Encoding: Configurable encoding parameters via
paramsdictionary - Multi-Stream Support: Stream to multiple RTSP clients
- Error Recovery: Robust error handling and recovery
ConfigurationDirect link to Configuration
Basic ConfigurationDirect link to Basic Configuration
from openfilter.filter_runtime.filter import Filter
from openfilter.filter_runtime.filters.video_out import VideoOut
# Simple video file output
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///path/to/output.mp4',
)),
])
Advanced Configuration with Multiple OptionsDirect link to Advanced Configuration with Multiple Options
# Video output with comprehensive options
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///path/to/output.mp4!segtime=1', # 1-minute segments
fps=30, # Output 30 FPS
params={
'crf': 23, # Constant Rate Factor (quality)
'preset': 'medium', # Encoding preset
'bitrate': '2M', # 2 Mbps bitrate
}
)),
])
Environment VariablesDirect link to Environment Variables
You can configure via environment variables:
export VIDEO_OUT_BGR="true" # BGR format (default: true)
export VIDEO_OUT_FPS="30" # Default FPS (default: 15)
export VIDEO_OUT_SEGTIME="1" # Default segment time in minutes
export VIDEO_OUT_PARAMS='{"crf": 23}' # Default encoding parameters
Output DestinationsDirect link to Output Destinations
1. Local Video FilesDirect link to 1. Local Video Files
File Path FormatDirect link to File Path Format
outputs='file:///path/to/output.mp4'
outputs='file:///path/to/output.avi'
outputs='file:///path/to/output.mov'
Supported FormatsDirect link to Supported Formats
- MP4: H.264, H.265, MPEG-4
- AVI: Various codecs
- MOV: QuickTime format
- MKV: Matroska format
- WebM: WebM format
File ExamplesDirect link to File Examples
# Local file output
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///home/user/videos/output.mp4',
fps=30,
)),
])
2. RTSP StreamingDirect link to 2. RTSP Streaming
RTSP URL FormatDirect link to RTSP URL Format
outputs='rtsp://server:port/stream'
outputs='rtsp://192.168.1.100:554/live'
RTSP ExamplesDirect link to RTSP Examples
# RTSP streaming
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='rtsp://192.168.1.100:554/live',
fps=30,
codec='libx264',
)),
])
3. Segmented OutputDirect link to 3. Segmented Output
Segment ConfigurationDirect link to Segment Configuration
# Using segtime in output string (in minutes)
outputs='file:///output.mp4!segtime=1' # 1-minute segments
outputs='file:///output.mp4!segtime=5' # 5-minute segments
outputs='file:///output.mp4' # No segmentation
# Or using segtime parameter
segtime=1 # 1-minute segments
segtime=5 # 5-minute segments
segtime=None # No segmentation
Segment ExamplesDirect link to Segment Examples
# Segmented video output
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///videos/recording_%Y%m%d_%H%M%S.mp4!segtime=1', # 1-minute segments
fps=30,
)),
])
Video Encoding OptionsDirect link to Video Encoding Options
Encoding Parameters (params)Direct link to encoding-parameters-params
All video encoding parameters are controlled through the params dictionary:
params={
'crf': 23, # Constant Rate Factor (0=best quality, 51=worst)
'preset': 'medium', # Encoding preset (ultrafast, fast, medium, slow, veryslow)
'bitrate': '2M', # Target bitrate
'pix_fmt': 'yuv420p', # Pixel format
'g': 50, # Group of pictures (GOP) size
'vf': 'scale=1280:720' # Video filters
}
Codec ExamplesDirect link to Codec Examples
# H.264 encoding
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///output.mp4',
params={'crf': 23, 'preset': 'medium'},
)),
])
# H.265 encoding for better compression
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///output.mp4',
params={'crf': 28, 'preset': 'slow'},
)),
])
Quality ControlDirect link to Quality Control
Constant Rate Factor (crf)Direct link to constant-rate-factor-crf
Controls video quality and file size:
params={'crf': 18} # High quality, large file
params={'crf': 23} # Good quality, balanced
params={'crf': 28} # Lower quality, smaller file
Bitrate Control (bitrate)Direct link to bitrate-control-bitrate
Controls target bitrate:
params={'bitrate': '1M'} # 1 Mbps
params={'bitrate': '2M'} # 2 Mbps
params={'bitrate': '5M'} # 5 Mbps
Quality ExamplesDirect link to Quality Examples
# High quality output
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///high_quality.mp4',
params={'crf': 18, 'preset': 'slow'}, # Slower encoding for better quality
)),
])
# Balanced quality and size
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///balanced.mp4',
params={'crf': 23, 'preset': 'medium'},
)),
])
# Small file size
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///small.mp4',
params={'crf': 28, 'bitrate': '500k'},
)),
])
Encoding Presets (preset)Direct link to encoding-presets-preset
Controls encoding speed vs. quality trade-off:
params={'preset': 'ultrafast'} # Fastest encoding, lower quality
params={'preset': 'fast'} # Fast encoding
params={'preset': 'medium'} # Balanced (default)
params={'preset': 'slow'} # Slower encoding, better quality
params={'preset': 'veryslow'} # Slowest encoding, best quality
Preset ExamplesDirect link to Preset Examples
# Fast encoding for real-time processing
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///fast.mp4',
params={'preset': 'fast', 'crf': 25},
)),
])
# High quality encoding
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///quality.mp4',
params={'preset': 'slow', 'crf': 18},
)),
])
Frame Rate ControlDirect link to Frame Rate Control
Output Frame Rate (fps)Direct link to output-frame-rate-fps
Controls the output video frame rate:
fps=30 # 30 FPS output
fps=60 # 60 FPS output
fps=15 # 15 FPS output
fps=True # Adaptive FPS (recommended)
fps=None # Uses environment variable default (15)
FPS ExamplesDirect link to FPS Examples
# Fixed 30 FPS output
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///output.mp4',
fps=30,
)),
])
# Adaptive FPS based on input (recommended)
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///adaptive.mp4',
fps=True, # Adaptive FPS
)),
])
Adaptive FPSDirect link to Adaptive FPS
When fps=True, the filter adapts to input frame rate by tracking the rate at which frames are written and setting this rate for each new file segment or restarting the RTSP stream if the rate strays too far from what the stream is set to.
# Adaptive FPS examples
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///adaptive.mp4!segtime=1', # Requires segmentation for adaptive FPS
fps=True, # Will match input FPS
)),
])
Note: Adaptive FPS only works for files if they are output in segments (segtime specified), otherwise there will never be an opportunity to set a more correct framerate than the initial guess.
File ManagementDirect link to File Management
Segment ManagementDirect link to Segment Management
Segment Duration (segtime)Direct link to segment-duration-segtime
Controls how long each video segment should be (in minutes):
segtime=1 # 1-minute segments
segtime=5 # 5-minute segments
segtime=60 # 1-hour segments
segtime=None # No segmentation
Segment ExamplesDirect link to Segment Examples
# 1-minute segments
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///segments/recording_%Y%m%d_%H%M%S.mp4!segtime=1',
fps=30,
)),
])
# 5-minute segments
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///segments/recording_%Y%m%d_%H%M%S.mp4!segtime=5',
fps=30,
)),
])
Note: The VideoOut filter does not provide automatic file rotation or max_files functionality. You would need to implement this separately if needed.
File RotationDirect link to File Rotation
The VideoOut filter creates new files based on the segtime parameter and filename templating:
# Automatic file rotation with timestamped filenames
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///videos/recording_%Y%m%d_%H%M%S.mp4!segtime=60', # 1-hour segments
fps=30,
)),
])
Filename templating: You can use strftime formatting in the output filename. The filter will also append a segment index (e.g., _000001, _000002) to distinguish segments.
Usage ExamplesDirect link to Usage Examples
Example 1: Basic Video RecordingDirect link to Example 1: Basic Video Recording
Filter.run_multi([
# ... other filters above
(VideoIn, dict(
sources='file:///input.mp4',
outputs='tcp://*:5550',
)),
(ObjectDetection, dict(
sources='tcp://localhost:5550',
outputs='tcp://*:5552',
)),
(VideoOut, dict(
sources='tcp://localhost:5552',
outputs='file:///output/detected.mp4',
fps=30,
)),
])
Behavior: Records processed video with object detection results.
Example 2: RTSP Live StreamingDirect link to Example 2: RTSP Live Streaming
Filter.run_multi([
# ... other filters above
(VideoIn, dict(
sources='0', # Webcam
outputs='tcp://*:5550',
)),
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='rtsp://192.168.1.100:554/live',
fps=30,
params={'bitrate': '2M'},
)),
])
Behavior: Streams webcam feed to RTSP endpoint.
Example 3: Segmented RecordingDirect link to Example 3: Segmented Recording
Filter.run_multi([
# ... other filters above
(VideoIn, dict(
sources='rtsp://camera.local/stream',
outputs='tcp://*:5550',
)),
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///recordings/recording_%Y%m%d_%H%M%S.mp4!segtime=5', # 5-minute segments
fps=15,
)),
])
Behavior: Records camera stream in 5-minute segments with timestamped filenames.
Example 4: High Quality RecordingDirect link to Example 4: High Quality Recording
Filter.run_multi([
# ... other filters above
(VideoIn, dict(
sources='file:///input.mp4',
outputs='tcp://*:5550',
)),
(VideoProcessor, dict(
sources='tcp://localhost:5550',
outputs='tcp://*:5552',
)),
(VideoOut, dict(
sources='tcp://localhost:5552',
outputs='file:///high_quality.mp4',
fps=30,
params={
'crf': 18, # High quality
'preset': 'slow', # Slow encoding for best quality
}
)),
])
Behavior: Creates high-quality encoded video with slow preset for best quality.
Example 5: Multi-Stream OutputDirect link to Example 5: Multi-Stream Output
Filter.run_multi([
# ... other filters above
(VideoIn, dict(
sources='0', # Webcam
outputs='tcp://*:5550',
)),
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///local_recording.mp4',
fps=30,
)),
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='rtsp://192.168.1.100:554/live',
fps=15, # Lower FPS for streaming
params={'bitrate': '1M'},
)),
])
Behavior: Records locally and streams simultaneously.
Example 6: Surveillance SystemDirect link to Example 6: Surveillance System
Filter.run_multi([
# ... other filters above
(VideoIn, dict(
sources='rtsp://camera.local/stream',
outputs='tcp://*:5550',
)),
(MotionDetection, dict(
sources='tcp://localhost:5550',
outputs='tcp://*:5552',
)),
(VideoOut, dict(
sources='tcp://localhost:5552',
outputs='file:///surveillance/motion_%Y%m%d_%H%M%S.mp4!segtime=1', # 1-minute segments
fps=15,
params={'crf': 25},
)),
])
Behavior: Records motion-detected video in 1-minute segments with timestamped filenames.
Performance ConsiderationsDirect link to Performance Considerations
Video Encoding PerformanceDirect link to Video Encoding Performance
- Codec Choice: H.264 is faster than H.265
- Preset Selection: Faster presets reduce CPU usage
- Resolution Impact: Higher resolution requires more processing
- Frame Rate: Higher FPS increases encoding load
File I/O PerformanceDirect link to File I/O Performance
- Disk Speed: SSD vs. HDD affects write performance
- Network Bandwidth: RTSP streaming limited by network
- File Size: Larger files require more disk space
- Segment Management: Frequent segmentation can impact performance
Memory UsageDirect link to Memory Usage
- Frame Buffering: Video frames consume memory
- Encoding Buffers: Codec buffers add memory overhead
- Multiple Streams: Each stream consumes memory independently
- Segment Management: Segment metadata consumes memory
Optimization StrategiesDirect link to Optimization Strategies
# Optimize for performance
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///output.mp4',
fps=15, # Lower frame rate
params={
'preset': 'fast', # Faster preset
'crf': 25, # Balanced quality
}
)),
])
Error HandlingDirect link to Error Handling
Common Error ScenariosDirect link to Common Error Scenarios
- Disk Space: Insufficient disk space for recording
- Permission Errors: File write permission issues
- Codec Issues: Unsupported codec or parameters
- Network Issues: RTSP connection failures
- File System: File system errors or corruption
- Memory Issues: Insufficient memory for encoding
Error RecoveryDirect link to Error Recovery
- Automatic Retry: Retries failed operations
- Graceful Degradation: Continues with available outputs
- Error Logging: Logs errors for debugging
- Resource Cleanup: Proper cleanup on failures
Error ExamplesDirect link to Error Examples
# Invalid parameters
params={'invalid_param': 'value'} # Error: Unknown parameter
# Invalid bitrate format
params={'bitrate': 'invalid'} # Error: Invalid bitrate format
# Permission denied
outputs='file:///root/output.mp4' # Error: Permission denied
Debugging and MonitoringDirect link to Debugging and Monitoring
Debug ConfigurationDirect link to Debug Configuration
import logging
logging.basicConfig(level=logging.DEBUG)
# Enable video output debugging
export LOG_LEVEL=DEBUG
Debug InformationDirect link to Debug Information
- Output Status: Shows output connection status
- Encoding Information: Logs encoding parameters and progress
- File Operations: Logs file write operations
- Error Details: Detailed error information
MonitoringDirect link to Monitoring
- Encoding Performance: Track encoding speed and quality
- File Sizes: Monitor output file sizes
- Error Rates: Track encoding and file errors
- Resource Usage: Monitor CPU and memory usage
TroubleshootingDirect link to Troubleshooting
Common IssuesDirect link to Common Issues
Encoding ProblemsDirect link to Encoding Problems
- Check codec availability
- Verify encoding parameters
- Monitor system resources
- Test with different presets
File Output IssuesDirect link to File Output Issues
- Check disk space and permissions
- Verify file path format
- Monitor file system performance
- Check for file locks
RTSP Streaming IssuesDirect link to RTSP Streaming Issues
- Verify network connectivity
- Check RTSP server configuration
- Monitor network bandwidth
- Test with different clients
Performance IssuesDirect link to Performance Issues
- Optimize encoding parameters
- Check system resources
- Consider hardware acceleration
- Monitor disk I/O performance
Debug ConfigurationDirect link to Debug Configuration
# Enable comprehensive debugging
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///output.mp4',
fps=15, # Lower FPS for debugging
params={
'crf': 25, # Balanced quality
'preset': 'fast', # Faster encoding
}
)),
])
Advanced UsageDirect link to Advanced Usage
Custom Video ProcessingDirect link to Custom Video Processing
# Custom video processing with output
Filter.run_multi([
# ... other filters above
(VideoIn, dict(
sources='file:///input.mp4',
outputs='tcp://*:5550',
)),
(CustomProcessor, dict(
sources='tcp://localhost:5550',
outputs='tcp://*:5552',
)),
(VideoOut, dict(
sources='tcp://localhost:5552',
outputs='file:///processed.mp4',
params={'crf': 20},
)),
])
Dynamic ConfigurationDirect link to Dynamic Configuration
# Dynamic configuration based on input
def get_output_config(input_source):
if 'camera' in input_source:
return {'fps': 30, 'params': {'bitrate': '2M'}}
elif 'file' in input_source:
return {'fps': True, 'params': {'crf': 23}}
else:
return {'fps': 15, 'params': {'crf': 25}}
# Apply configuration
config = get_output_config('camera')
Filter.run_multi([
# ... other filters above
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///output.mp4',
**config
)),
])
Multi-Format OutputDirect link to Multi-Format Output
# Output in multiple formats
Filter.run_multi([
# ... other filters above
(VideoIn, dict(
sources='file:///input.mp4',
outputs='tcp://*:5550',
)),
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///output_h264.mp4',
params={'crf': 23},
)),
(VideoOut, dict(
sources='tcp://localhost:5550',
outputs='file:///output_h265.mp4',
params={'crf': 28},
)),
])
API ReferenceDirect link to API Reference
VideoOutConfigDirect link to VideoOutConfig
class VideoOutConfig(FilterConfig):
sources: str | list[str]
outputs: str | list[str | Output]
bgr: bool | None # BGR vs RGB format
fps: float | Literal[True] | None # Frame rate (True = adaptive)
segtime: float | None # Segment time in minutes
params: dict[str, Any] | None # Video encoding parameters
VideoOutDirect link to VideoOut
class VideoOut(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 process_src_fps(self, frames) # For adaptive FPS
def process_check_rtsp_fps(self, frames)
Environment VariablesDirect link to Environment Variables
VIDEO_OUT_BGR: BGR format (default: true)VIDEO_OUT_FPS: Default FPS (default: 15)VIDEO_OUT_SEGTIME: Default segment time in minutesVIDEO_OUT_PARAMS: Default encoding parameters as JSON string