effeffmpeg - cleverdevil/squishy GitHub Wiki
effeffmpeg Documentation
FFmpeg Hardware-Aware Transcoder is a Python wrapper around FFmpeg that powers Squishy's transcoding functionality. It simplifies video transcoding with hardware acceleration, automatically detecting hardware capabilities and falling back to software encoding when needed.
Features
- Automatic hardware acceleration detection (currently supports VAAPI)
- Smart fallback to software encoding when hardware acceleration isn't available
- Resolution scaling with common presets (360p, 480p, 720p, 1080p, 2160p)
- Support for various video and audio codecs with container compatibility validation
- Quality control using CRF or bitrate settings
- Preset system for common encoding configurations
- Command-line interface
- Python API for integration into other applications
- Non-blocking operation with live progress tracking
- Real-time progress reporting callback function
Installation
No special installation is required as effeffmpeg is embedded within Squishy. The module consists of a single Python file: effeffmpeg.py
.
Requirements:
- Python 3.6 or later
- FFmpeg installed on your system
ffprobe
command (usually installed alongside FFmpeg)
Command-line Usage
Detect hardware capabilities
python3 effeffmpeg.py detect capabilities.json
List available presets
python3 effeffmpeg.py presets --file presets.json
Transcode a video using command-line options
python3 effeffmpeg.py transcode --to h264 --scale 720p --audio aac --run input.mp4 output.mp4
Transcode using a preset
python3 effeffmpeg.py transcode --preset 720p-high --run input.mp4 output.mp4
Preset System
effeffmpeg uses a flexible preset system for defining common encoding configurations:
- JSON files: Store presets in JSON files and load them at runtime
- Python dictionaries: Define presets directly in your Python code
Preset Format
Each preset is a dictionary with the following keys:
container
: The container format (e.g., ".mp4", ".mkv", ".webm")codec
: The video codec to use (e.g., "h264", "hevc", "vp9")scale
: The target resolution (e.g., "360p", "720p", "1080p")audio_codec
: The audio codec to use (e.g., "aac", "opus", "flac")audio_bitrate
: The audio bitrate (e.g., "128k", "192k")bitrate
orcrf
: The video quality setting (bitrate-based or quality-based)allow_fallback
: Whether to allow fallback to software encoding
Preset Collections
effeffmpeg comes with two preset collections:
Compatible Presets (presets-compatible.json)
These presets focus on compatibility using H.264/MP4 with different bitrates:
{
"presets": {
"360p-low": {
"container": ".mp4",
"codec": "h264",
"scale": "360p",
"audio_codec": "aac",
"audio_bitrate": "64k",
"bitrate": "500k",
"allow_fallback": true
},
"720p-medium": {
"container": ".mp4",
"codec": "h264",
"scale": "720p",
"audio_codec": "aac",
"audio_bitrate": "128k",
"bitrate": "2.5M",
"allow_fallback": true
},
"1080p-high": {
"container": ".mp4",
"codec": "h264",
"scale": "1080p",
"audio_codec": "aac",
"audio_bitrate": "192k",
"bitrate": "8M",
"allow_fallback": true
}
}
}
Quality Presets (presets-quality.json)
These presets focus on quality using HEVC/MKV with CRF-based encoding:
{
"presets": {
"360p-low": {
"container": ".mkv",
"codec": "hevc",
"scale": "360p",
"audio_codec": "aac",
"audio_bitrate": "64k",
"crf": 28,
"allow_fallback": true
},
"720p-medium": {
"container": ".mkv",
"codec": "hevc",
"scale": "720p",
"audio_codec": "aac",
"audio_bitrate": "128k",
"crf": 24,
"allow_fallback": true
},
"1080p-high": {
"container": ".mkv",
"codec": "hevc",
"scale": "1080p",
"audio_codec": "aac",
"audio_bitrate": "192k",
"crf": 20,
"allow_fallback": true
}
}
}
Python API Usage
Basic Transcoding
import effeffmpeg
# Transcode a video with hardware acceleration if available
effeffmpeg.transcode(
input_file="input.mp4",
output_file="output.mp4",
codec="h264",
scale="720p",
audio_codec="aac",
audio_bitrate="128k",
allow_fallback=True, # Allow fallback to software encoding if needed
overwrite=True # Overwrite output file if it exists
)
Quality-Based Encoding
import effeffmpeg
# Use CRF for quality-based encoding (software encoding only)
effeffmpeg.transcode(
input_file="input.mp4",
output_file="output.mkv",
codec="hevc",
scale="1080p",
audio_codec="libopus",
audio_bitrate="192k",
crf=22, # Lower CRF = higher quality
force_software=True, # Force software encoding
overwrite=True
)
Using Presets
import effeffmpeg
# Using a preset from a JSON file
effeffmpeg.transcode(
input_file="input.mp4",
output_file="output.mp4",
preset_name="720p-high",
presets_file="presets/presets-compatible.json",
overwrite=True
)
# Using a quality-focused preset
effeffmpeg.transcode(
input_file="input.mp4",
output_file="output.mkv",
preset_name="1080p-high",
presets_file="presets/presets-quality.json",
overwrite=True
)
Non-Blocking Transcoding with Progress Tracking
import effeffmpeg
import time
# Define a progress callback function
def progress_handler(line, progress):
if progress is not None:
print(f"Progress: {progress*100:.1f}% - {line}")
# Start a non-blocking transcode
process = effeffmpeg.transcode(
input_file="input.mp4",
output_file="output.mkv",
codec="hevc",
scale="1080p",
audio_codec="libopus",
audio_bitrate="192k",
overwrite=True,
non_blocking=True, # Enable non-blocking mode
progress_callback=progress_handler # Register progress callback
)
# Do other work while transcoding is in progress
while not process.finished:
print(f"Elapsed time: {process.get_elapsed_time():.1f} seconds")
time.sleep(1)
# Check if the process has completed
if process.process.poll() is not None:
process.finished = True
process.returncode = process.process.returncode
# Get the result when done
print(f"Transcoding completed with return code: {process.returncode}")
Hardware Capability Detection
import effeffmpeg
import json
# Detect hardware acceleration capabilities
capabilities = effeffmpeg.detect_capabilities()
# Print available hardware encoders
if capabilities["hwaccel"]:
print(f"Hardware acceleration available: {capabilities['hwaccel']}")
print(f"Available encoders: {list(capabilities['encoders'].keys())}")
else:
print("No hardware acceleration detected, using software encoding")
# Save capabilities to a file for future use
with open("capabilities.json", "w") as f:
json.dump(capabilities, f, indent=2)
API Reference
transcode()
def transcode(
input_file, # Path to input video file
output_file, # Path to output video file
codec=None, # Target video codec (h264, hevc, vp9, av1)
scale=None, # Target resolution (360p, 480p, 720p, 1080p, 2160p)
audio_codec=None, # Target audio codec (copy, aac, flac, opus, libopus)
allow_fallback=True, # Allow software fallback if hardware encoding fails
force_software=False, # Force software encoding
crf=None, # Constant Rate Factor (0-51, lower is better)
bitrate=None, # Target video bitrate (e.g. "2M")
audio_bitrate=None, # Target audio bitrate (e.g. "128k")
flac_compression=None, # FLAC compression level (0-8)
capabilities_file=None, # Path to capabilities JSON file
dry_run=False, # Return command without executing
overwrite=False, # Force overwrite of output file
quiet=False, # Suppress informational output
non_blocking=False, # Enable non-blocking operation
progress_callback=None, # Function to call with progress updates
preset_name=None, # Name of the preset to use
presets_data=None, # Python dictionary containing preset configurations
presets_file=None # Path to JSON file containing preset configurations
)
Returns:
- If
dry_run=True
: Returns the FFmpeg command as a list of strings - If
non_blocking=True
: Returns aTranscodeProcess
object to manage the process - Otherwise: Returns a
subprocess.CompletedProcess
object with the result
Integration with Squishy
In Squishy, effeffmpeg is used to power the transcoding functionality:
- Squishy detects hardware capabilities during startup
- The onboarding wizard helps configure hardware acceleration
- Transcoding jobs are managed through a queue system
- Each job uses effeffmpeg to perform the actual transcoding
- Progress is tracked in real-time and displayed in the web interface
The integration can be seen in the transcoder.py
file, where Squishy creates a custom progress callback function to update the job status and emits events to the web interface.