Skip to content

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

  1. ExifTool analysis: VBC extracts full EXIF metadata
  2. Pattern matching: Searches all metadata for camera model strings
  3. Mode-aware override:
  4. quality_mode=cq uses dynamic_quality.<pattern>.cq
  5. quality_mode=rate uses dynamic_quality.<pattern>.rate (if provided)
  6. First match wins: Patterns are checked in config file order

Example

dynamic_quality:
  "Sony":
    cq: 40
  "ILCE-7RM5":
    cq: 38

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:

uv run vbc /videos --debug

Look for:

Detected camera: ILCE-7RM5 - using custom CQ: 38

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

  1. Manual override: A CLI rotation has highest priority
  2. Sidecar check: With sidecar: true, video.mp4 reads video.rot
  3. Filename check: If no sidecar exists, VBC checks filename patterns
  4. Rotation filter: Applies FFmpeg transpose/hflip+vflip filters

A sidecar contains one directive, for example:

--video-rotate=90

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

# Rotate all videos 180° (overrides config patterns)
uv run vbc /videos --rotate-180

Camera Filtering

Process only files from specific camera models.

Configuration

# conf/vbc.yaml
general:
  filter_cameras:
    - "ILCE-7RM5"
    - "DJI OsmoPocket3"
    - "Canon EOS R5"

Or via CLI:

uv run vbc /videos --camera "ILCE-7RM5,DJI"

How It Works

  1. EXIF extraction: Uses ExifTool to get camera model
  2. Substring match: Checks if any filter string is in camera model
  3. 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

# conf/vbc.yaml
general:
  min_compression_ratio: 0.1  # Require 10% savings

Or via CLI:

uv run vbc /videos --min-ratio 0.2  # 20% minimum

How It Works

  1. Compress normally: FFmpeg creates compressed file
  2. Check ratio: Calculate (1 - output_size/input_size)
  3. Compare threshold: If savings < min_compression_ratio:
  4. Delete compressed file
  5. Copy original to output directory
  6. Write metadata/tags only when accepted: Deep metadata copy and VBC tags run only if ratio passes.
  7. 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

# conf/vbc.yaml
general:
  skip_av1: true

Or via CLI:

uv run vbc /videos --skip-av1

How It Works

  1. FFprobe check: Extract codec from stream info
  2. AV1 detection: Check if codec == "av1"
  3. 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

  1. Tag Detection: VBC writes the XMP tag as VBCEncoder. Detection also accepts displayed or legacy metadata keys such as VBC Encoder (via FFprobe or ExifTool).
  2. Auto-Move: If found, the file is moved to the output directory and published as JobCompleted.
  3. 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

# conf/vbc.yaml
general:
  prefetch_factor: 2  # Queue 2x threads

Formula:

max_queued_jobs = prefetch_factor × current_threads

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

# conf/vbc.yaml
general:
  copy_metadata: true  # Default
  use_exif: true       # Required for deep copy

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

exiftool -XMP-vbc:all compressed.mp4

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:

Hardware is lacking required capabilities

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

# RTX 30-series
uv run vbc /videos --threads 5

# RTX 4090
uv run vbc /videos --threads 8

Option 2: Use CPU mode (no hardware limitations)

uv run vbc /videos --cpu

Option 3: Reduce quality for 10-bit issues

uv run vbc /videos --quality 38

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:

color_space=reserved

Fix Process

  1. Remux: Use bitstream filter to set valid color space

    ffmpeg -i input.mp4 -c copy \
      -bsf:v hevc_metadata=colour_primaries=1:transfer_characteristics=1:matrix_coefficients=1 \
      temp_colorfix.mp4
    

  2. Compress: Use fixed file as input

  3. Cleanup: Delete temp file

Codecs Supported

  • HEVC (h265): hevc_metadata filter
  • H.264: h264_metadata filter
  • Others: Proceed without fix (warning logged)

Debug Logging

uv run vbc /videos --debug

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

# conf/vbc.yaml
general:
  strip_unicode_display: true  # Default

Effect: - Filesystem: Filenames unchanged - UI display: Non-ASCII replaced with ?

Example:

File on disk: video_🎬_final.mp4
UI display:   video_?_final.mp4

Disable:

strip_unicode_display: false

Warning: May cause table misalignment in UI.

Next Steps