Advanced Features¶
This guide covers VBC's advanced features: dynamic quality, auto-rotation, camera filtering, and more.
Dynamic Quality (Camera-Specific Quality)¶
Different cameras produce different quality levels. VBC can apply per-camera rules with explicit cq and optional rate.
Configuration¶
# conf/vbc.yaml
gpu_encoder:
common_args:
- "-cq 45" # Default for unknown cameras
general:
dynamic_quality:
"ILCE-7RM5":
cq: 38
rate:
bps: "0.8"
minrate: "0.7"
maxrate: "0.9"
"DC-GH7":
cq: 40
"DJI OsmoPocket3":
cq: 48
rate:
bps: "180M"
How It Works¶
- ExifTool analysis: VBC extracts full EXIF metadata
- Pattern matching: Searches all metadata for camera model strings
- Mode-aware override:
quality_mode=cqusesdynamic_quality.<pattern>.cqquality_mode=rateusesdynamic_quality.<pattern>.rate(if provided)- First match wins: Patterns are checked in config file order
Example¶
File: IMG_1234.MOV
EXIF: EXIF:Model = "ILCE-7RM5"
Result: CQ = 38 (specific match beats generic)
Schema note: legacy scalar format is rejected, e.g. "Sony": 40 is invalid.
CLI Override¶
# Override baseline CQ/CRF in encoder args
uv run vbc /videos --quality 40
# Dynamic Quality still active (from config)
uv run vbc /videos --config conf/vbc.yaml
Note: --quality overrides the base CQ/CRF value but does not disable dynamic_quality.
To disable dynamic quality, set general.dynamic_quality: {} or general.use_exif: false.
Debugging¶
Enable debug logging to see CQ decisions:
Look for:
Auto-Rotation¶
Automatically rotate videos based on filename patterns (useful for GoPro, drone footage).
Configuration¶
# conf/vbc.yaml
autorotate:
sidecar: false
patterns:
"DJI_.*\\.MP4": 0 # DJI drones - no rotation
"GOPR\\d+\\.MP4": 180 # GoPro pattern - flip 180°
"IMG_\\d{4}\\.MOV": 90 # iPhone - rotate 90°
Regex syntax: Python re module (backslashes must be escaped).
How It Works¶
- Manual override: A CLI rotation has highest priority
- Sidecar check: With
sidecar: true,video.mp4readsvideo.rot - Filename check: If no sidecar exists, VBC checks filename patterns
- Rotation filter: Applies FFmpeg transpose/hflip+vflip filters
A sidecar contains one directive, for example:
The accepted values are -1, 0, 90, 180, and 270. A value of -1
means that rotation could not be determined; VBC applies no custom rotation
and does not check filename patterns for that video. Sidecars are ignored
unless autorotate.sidecar is enabled globally or in the applicable
VBC.YAML. An explicit rotation from a sidecar, filename pattern, or CLI
override ignores embedded input rotation metadata.
Rotation Angles¶
| Angle | FFmpeg Filter |
|---|---|
| 0 | None (no rotation) |
| 90 | transpose=1 (clockwise) |
| 180 | hflip,vflip (upside down) |
| 270 | transpose=2 (counter-clockwise) |
Manual Override¶
Camera Filtering¶
Process only files from specific camera models.
Configuration¶
Or via CLI:
How It Works¶
- EXIF extraction: Uses ExifTool to get camera model
- Substring match: Checks if any filter string is in camera model
- Skip non-matches: Files from other cameras are skipped
Example:
Filter: ["ILCE-7RM5", "DJI"]
File: IMG_1234.MOV
Camera: ILCE-7RM5 (Sony A7R V)
Match: "ILCE-7RM5" in "ILCE-7RM5" → Process ✓
File: VIDEO_5678.MP4
Camera: Canon EOS R5
Match: None → Skip ✗
Minimum Compression Ratio¶
Keep original file if compression savings are below threshold.
Configuration¶
Or via CLI:
How It Works¶
- Compress normally: FFmpeg creates compressed file
- Check ratio: Calculate
(1 - output_size/input_size) - Compare threshold: If savings <
min_compression_ratio: - Delete compressed file
- Copy original to output directory
- Write metadata/tags only when accepted: Deep metadata copy and VBC tags run only if ratio passes.
- Log decision: "MinRatio: kept original (X% < Y% minimum)"
Example:
Input: 100 MB
Output: 92 MB
Savings: 8% (1 - 92/100 = 0.08)
min_compression_ratio: 0.1 (10%)
Result: 8% < 10% → Keep original (copy 100 MB file)
Use Cases¶
- Already compressed: Files from efficient cameras (e.g., DJI with H.265)
- Tiny files: Small clips where AV1 overhead > savings
- Quality priority: Never accept worse compression
Skip AV1 Files¶
Avoid re-compressing files already in AV1 codec.
Configuration¶
Or via CLI:
How It Works¶
- FFprobe check: Extract codec from stream info
- AV1 detection: Check if
codec == "av1" - Skip: Don't queue for compression
Use case: Mixed library with some files already compressed to AV1.
Skip Already Encoded Files¶
VBC automatically detects files it has already encoded to prevent accidental re-compression (e.g., if output is used as input).
How It Works¶
- Tag Detection: VBC writes the XMP tag as
VBCEncoder. Detection also accepts displayed or legacy metadata keys such asVBC Encoder(via FFprobe or ExifTool). - Auto-Move: If found, the file is moved to the output directory and published as
JobCompleted. - Warning: At the end of processing, a yellow warning is displayed if any files were moved for this reason.
Note: This feature is always active and cannot be disabled.
Audio Consistency Check¶
Verify that audio handling in the output matches VBC's rules.
Behavior summary:
- Lossless (pcm_*, flac, alac, truehd, mlp, wavpack, ape, tta) → AAC 256 kbps
- AAC/MP3 → stream copy
- Other/unknown → AAC 192 kbps
- No audio → no audio
Usage¶
# Default output dir: <input_dir>_out
python vbc/utils/check_audio_consistency.py /path/to/videos
# Custom output dir
python vbc/utils/check_audio_consistency.py /path/to/videos --output-dir /path/to/videos_out
Output¶
The script prints summary counts (including how many input files had no audio), lists missing outputs, and reports any codec/bitrate mismatches.
Prefetch Factor¶
Controls submit-on-demand queue size.
Configuration¶
Formula:
Examples:
- prefetch_factor=1, threads=4 → 4 jobs queued
- prefetch_factor=2, threads=4 → 8 jobs queued
- User presses > (threads 4→5) → queue expands to 10 jobs
Trade-offs¶
| Factor | Pros | Cons |
|---|---|---|
| 1 (default) | Minimal memory, responsive to thread changes | Less parallelism |
| 2-3 | Better parallelism, smoother queue | Higher memory usage |
| 4+ | Maximum parallelism | Memory intensive, slow thread response |
Recommendation: Keep at 1 unless you need more parallelism and your system can sustain up to 8 threads.
Deep Metadata Copy¶
VBC uses ExifTool to preserve all metadata including GPS, camera settings, and custom tags.
Configuration¶
What's Copied¶
- GPS: Latitude, longitude, altitude
- Camera: Model, lens, focal length, ISO, aperture
- XMP: All XMP tags (Adobe, vendor-specific)
- QuickTime: All QuickTime metadata
- Custom VBC tags: Original filename, size, original bitrate, quality target, encoder, timestamp, and source part numbers used by the output
ExifTool Config¶
VBC uses conf/exiftool.conf to define custom VBC tags:
# conf/exiftool.conf
%Image::ExifTool::UserDefined = (
'Image::ExifTool::XMP::Main' => {
VBC => {
SubDirectory => {
TagTable => 'Image::ExifTool::UserDefined::VBC',
},
},
},
);
%Image::ExifTool::UserDefined::VBC = (
GROUPS => { 0 => 'XMP', 1 => 'XMP-vbc', 2 => 'Image' },
NAMESPACE => { 'VBC' => 'http://ns.example.com/vbc/1.0/' },
WRITABLE => 'string',
VBCOriginalName => { },
VBCOriginalSize => { },
VBCQuality => { },
VBCOriginalBitrate => { },
VBCJsonNotes => { },
VBCEncoder => { },
VBCFinishedAt => { },
VBCSourceParts => { },
);
View VBC Tags¶
Output:
VBC Original Name : original_video.mp4
VBC Original Size : 125829120
VBC Original Bitrate : 35.9 Mbps
VBC Quality : 0.2
VBC Json Notes : {"rate_control":{"mode":"rate","target_expr":"0.2"}}
VBC Encoder : NVENC AV1 (GPU)
VBC Finished At : 2025-12-21T15:30:45+01:00
VBC Quality stores the configured compression target:
- cq mode: quality parameter label (e.g. CQ45)
- rate mode: configured bps expression, either an absolute bitrate (e.g. 20M, 200Mbps) or a source-bitrate ratio (e.g. 0.2)
Hardware Capability Detection¶
VBC automatically detects GPU limitations including: - 10-bit AV1 encoding not supported (older GPUs) - NVENC session limits exceeded (too many concurrent encodes)
Common HW_CAP Causes¶
Session Limits Exceeded:
- RTX 30-series: Max ~5 concurrent sessions
- RTX 40-series (e.g., 4090): Max 10-12 concurrent sessions
- VBC keyboard runtime controls (</>) clamp to 1-8 threads
- Startup --threads / general.threads accepts values >0 (practical upper bound is ThreadPoolExecutor(max_workers=16))
10-bit Encoding: - Older GPUs don't support 10-bit AV1 - RTX 40-series has full 10-bit support
Error Detection¶
FFmpeg outputs:
VBC:
1. Detects error string or exit code 187
2. Sets job status to HW_CAP_LIMIT
3. Creates .err marker
4. Increments hw_cap counter in UI
UI Display¶
┌─ COMPRESSION STATUS ───────────────────────────┐
│ Ignored: size:5 | err:2 | hw_cap:3 | av1:0 │
└────────────────────────────────────────────────┘
┌─ SUMMARY ──────────────────────────────────────┐
│ ✓ 42 success ✗ 2 errors ⚠ 3 hw_cap ⊘ 0 skip│
└────────────────────────────────────────────────┘
Workarounds¶
Option 1: Reduce thread count to GPU session limit
Option 2: Use CPU mode (no hardware limitations)
Option 3: Reduce quality for 10-bit issues
Option 4: Upgrade GPU (RTX 40-series has full 10-bit AV1 support and higher session limits)
Color Space Fix (FFmpeg 7.x)¶
FFmpeg 7.x has issues with "reserved" color space. VBC automatically fixes this.
Detection¶
FFprobe shows:
Fix Process¶
-
Remux: Use bitstream filter to set valid color space
-
Compress: Use fixed file as input
-
Cleanup: Delete temp file
Codecs Supported¶
- HEVC (h265):
hevc_metadatafilter - H.264:
h264_metadatafilter - Others: Proceed without fix (warning logged)
Debug Logging¶
Look for:
Detected reserved color space in video.mp4, applying fix...
Successfully fixed color space for video.mp4
Unicode Handling¶
Filenames with emoji or special Unicode can break table alignment.
Configuration¶
Effect:
- Filesystem: Filenames unchanged
- UI display: Non-ASCII replaced with ?
Example:
Disable:
Warning: May cause table misalignment in UI.
Next Steps¶
- CLI Reference - All command-line options
- Runtime Controls - Keyboard shortcuts
- Architecture - How features work internally