Overview
After computing synchronization offsets, the system applies them to video files using FFmpeg. Understanding the sign convention is critical for interpreting results and debugging issues.Key Principle: Offsets represent how much to shift each video’s timeline to align all videos to a common reference time.
Sign Convention
The system uses Option C semantics from the source code:Positive Offset (+)
Delay the entire fileVideo and audio start later in the synchronized timeline. Black frames and silence are added at the beginning.
Negative Offset (-)
Trim from the startThe first
|offset| seconds are removed. The file starts later in its own content.Visual Example
- Positive Offset (+2.5s)
- Negative Offset (-1.8s)
- Zero Offset (0.0s)
Implementation Details
The offset application logic is insrc/video_sync.py:
Positive Offset: Delay
Why re-encode for delays?
Why re-encode for delays?
FFmpeg’s
-itsoffset flag can delay streams without re-encoding, but it has compatibility issues:- Some players ignore PTS (presentation timestamp) shifts
- OpenCV’s
cv2.VideoCapturedoesn’t respect-itsoffset - Frame-accurate seeking may fail
tpad to insert actual black frames at the beginning. This ensures all players and tools see the delay.Negative Offset: Trim
Fast Trim: Using
-ss before -i enables fast seeking. FFmpeg jumps to the nearest keyframe and stream-copies from there. No re-encoding needed.Duration Equalization
After applying offsets, videos may have different final durations:End Padding Example
End Padding Implementation
Sign Derivation from Sync Methods
Both sync methods return offsets with specific sign conventions:Audio Sync (GCC-PHAT)
Why the negative sign in GCC-PHAT?
Why the negative sign in GCC-PHAT?
The raw correlation lag represents:But we want offsets to apply to sig_b’s timeline:This ensures:
- If sig_b is delayed (lag > 0), we need to add delay → positive offset
- If sig_b is ahead (lag < 0), we need to trim → negative offset
offset > 0→ sig_b started late → add delayoffset < 0→ sig_b started early → trim
Visual Sync (Motion)
Verification
After synchronization, verify offsets were applied correctly:Visual Inspection
Use the built-in multi-video player:
- All videos should start simultaneously
- Shared events (clap, speech) should align across views
- No drift over time (constant offset)
Common Misunderstandings
Example Scenario
Three cameras recording a presentation:Log Output
FFmpeg Command Examples
Silent Videos
Videos without audio tracks are handled differently:- Positive offset: Only
tpadapplied (noadelay) - Negative offset: Trim works normally
- No audio mapping in FFmpeg commands
Troubleshooting
Videos not aligned after sync
Videos not aligned after sync
Check:
- Verify offsets in logs:
INFO: Processing X with offset Y - Ensure all
_synced.mp4files have same duration - Check first frame of positive-offset videos (should be black)
- Use
ffprobeto verify PTS start times
Black frames at wrong position
Black frames at wrong position
Symptom: Black frames in middle or end instead of startCause: FFmpeg command error or codec issueSolution: Check logs for FFmpeg errors, try re-running sync
Audio/video desync within a file
Audio/video desync within a file
Symptom: Video and audio drift apart in synced fileCause:
- Original file had A/V sync issues
- Variable framerate (VFR) video
- Fix original video first:
ffmpeg -i input.mp4 -c:v libx264 -r 30 -c:a aac fixed.mp4 - Use constant framerate (CFR) recordings
Source Code Reference
Offset application logic insrc/video_sync.py:
- Line 1-12: Offset semantics documentation
- Line 77-96:
_delay_stream_copy()- Delay using -itsoffset (stream copy) - Line 99-107:
_trim_stream_copy()- Trim using -ss (stream copy) - Line 110-173:
_reencode_delay()- Delay using tpad/adelay (re-encode) - Line 176-189:
_reencode_trim()- Trim with re-encode (fallback) - Line 192-363:
apply_video_offsets()- Main offset application function
Next Steps
Audio Sync
How offsets are computed from audio
Visual Sync
How offsets are computed from motion