Skip to main content
The video_sync module applies computed time offsets to entire video files (both audio and video streams) using ffmpeg. It supports both stream copying (fast, lossless) and re-encoding when necessary.

apply_video_offsets

Apply time offsets to video files based on computed synchronization offsets.
from src.video_sync import apply_video_offsets

# Offsets from audio_sync or visual_sync
offsets = {
    'camera1.mp4': 0.0,      # Reference (no offset)
    'camera2.mp4': 1.5,      # Delay by 1.5s
    'camera3.mp4': -0.8      # Trim first 0.8s
}

apply_video_offsets(
    video_dir="./videos",
    offsets=offsets,
    output_dir="./synced_videos",
    verbose=True
)

Parameters

video_dir
str
required
Directory containing original video files
offsets
Dict[str, float]
required
Dictionary mapping filename to offset in seconds:
  • Positive offset (>0): Delay the entire file (video+audio start later with black frames/silence)
  • Negative offset (<0): Trim the first |offset| seconds from the file
output_dir
str
required
Directory where synchronized videos will be saved. Created if it doesn’t exist.
verbose
bool
default:"True"
Show tqdm progress bar during processing

Returns

success
bool
Returns True when all videos have been processed successfully

Output Files

Synchronized videos are saved with _synced suffix:
  • Input: camera1.mp4 → Output: camera1_synced.mp4
  • Input: camera2.mp4 → Output: camera2_synced.mp4

Offset Semantics

The function uses “Option C” semantics for offset application:
  • Positive offset (+2.0s): Adds 2 seconds of black frames at the start
  • Negative offset (-1.5s): Removes the first 1.5 seconds of content
  • Zero offset (0.0s): Simple copy with duration padding if needed

Processing Strategy

The function intelligently chooses between stream copying and re-encoding:
  1. Stream Copy (fast, lossless):
    • Used for simple trim operations when no end padding is needed
    • Preserves original video/audio quality
    • Completes in seconds
  2. Re-encode (slower, with quality settings):
    • Required for delays (adding black frames/silence at start)
    • Required for end padding to match all videos to same duration
    • Uses ultrafast preset with CRF 23 for good quality/speed balance
    • Audio encoded as AAC 128k

Duration Normalization

All output videos are automatically padded to the same duration:
max_duration = max(original_duration + offset for all videos)
This ensures all synchronized videos have identical lengths, which is important for:
  • Side-by-side playback comparison
  • Creating synchronized multi-view exports
  • Frame-accurate alignment

Silent Video Handling

The function automatically detects videos without audio streams and processes them correctly:
  • No audio delay/padding filters applied
  • Only video stream is processed
  • Prevents ffmpeg errors from missing audio

Example Workflow

from src.audio_sync import estimate_offsets_robust
from src.video_sync import apply_video_offsets

# Step 1: Extract audio from videos (using ffmpeg externally)
# ffmpeg -i camera1.mp4 -vn -acodec pcm_s16le audio/camera1.wav

# Step 2: Compute audio-based offsets
offsets = estimate_offsets_robust(
    audio_dir="./audio",
    max_offset_sec=10.0,
    window_sec=30.0
)

# Step 3: Apply offsets to original videos
apply_video_offsets(
    video_dir="./videos",
    offsets=offsets,
    output_dir="./synced"
)

print("Synchronization complete! Check ./synced/ for results")

Error Handling

The function includes robust error handling:
  • Missing files: Logged as warnings, processing continues with remaining files
  • Stream copy failures: Automatically falls back to re-encode
  • ffmpeg errors: Logged with full error messages for debugging
  • Duration detection failures: Skips problematic files with error logs

Performance Considerations

  • Stream copy operations: Near-instant (seconds for large files)
  • Re-encoding: Depends on video length and system performance
    • 1080p 60fps: ~0.5-2x realtime with ultrafast preset
    • 4K 30fps: ~0.3-1x realtime with ultrafast preset
  • Memory usage: Minimal (ffmpeg streams data)
  • Disk usage: Roughly same as original files (CRF 23 is visually lossless)

Logging

The function provides detailed logging:
INFO: Calculating video durations...
DEBUG:   camera1.mp4: 60.00s -> 60.00s
DEBUG:   camera2.mp4: 58.50s -> 60.00s  
INFO: Max final duration: 60.00s
INFO: Synchronizing videos...
INFO: Processing camera1.mp4 with offset +0.000s
INFO: Processing camera2.mp4 with offset +1.500s
Use logging.DEBUG level for detailed ffmpeg command inspection.

Build docs developers (and LLMs) love