Created
July 18, 2025 14:28
-
-
Save baso53/d6ebe379c7f0aae0eee5343de11bb53e to your computer and use it in GitHub Desktop.
This script modifies the timecode of videos filmed with Sony cameras (it may work on others), so that the time between the clips is accurately represented. It only has 2-second accuracy (since it's based on the time of start of recording, which only has a second accuracy), but this is enough to make a rough sync for clips. It was only tested on …
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # --------------------------------------------------------------------------- | |
| # modify-timecode.sh | |
| # --------------------------------------------------------------------------- | |
| # • First clip -> 00:00:00:00 | |
| # • Others -> offset from first clip’s “Encoded date” | |
| # • Frames part -> always 00 | |
| # • Streams are copied, NO re-encoding | |
| # | |
| # Needs: mediainfo, ffmpeg (brew install mediainfo ffmpeg) | |
| # --------------------------------------------------------------------------- | |
| set -euo pipefail | |
| IFS=$'\n' # keep filenames with blanks intact | |
| # --------------------------------------------------------------------------- | |
| # 1. Collect *.mp4 (case-insensitive) in the current directory | |
| # --------------------------------------------------------------------------- | |
| shopt -s nocaseglob nullglob | |
| files=( *.mp4 ) | |
| shopt -u nocaseglob | |
| if [ ${#files[@]} -eq 0 ]; then | |
| echo "No MP4 files found – aborting." >&2 | |
| exit 1 | |
| fi | |
| # --------------------------------------------------------------------------- | |
| # 2. First pass – find the earliest Encoded_Date (=> reference 0 s) | |
| # --------------------------------------------------------------------------- | |
| first_epoch='' | |
| for f in "${files[@]}"; do | |
| enc_date=$(mediainfo --Output='General;%Encoded_Date%' -- "$f") || { | |
| echo "Cannot read Encoded_Date from '$f' – skipping." >&2 | |
| continue | |
| } | |
| # expected format: “UTC 2024-06-19 13:59:57” | |
| enc_date=${enc_date#UTC } # strip leading “UTC ” | |
| if ep=$(date -u -j -f "%Y-%m-%d %H:%M:%S" "$enc_date" "+%s" 2>/dev/null) | |
| then | |
| if [ -z "$first_epoch" ] || [ "$ep" -lt "$first_epoch" ]; then | |
| first_epoch=$ep | |
| fi | |
| else | |
| echo "Cannot parse date '$enc_date' in '$f' – skipping." >&2 | |
| fi | |
| done | |
| if [ -z "$first_epoch" ]; then | |
| echo "No usable Encoded_Date values – aborting." >&2 | |
| exit 1 | |
| fi | |
| echo "Earliest clip time: $(date -u -r "$first_epoch" "+%Y-%m-%d %H:%M:%S") (t = 0)" | |
| # --------------------------------------------------------------------------- | |
| # 3. Second pass – compute offset for every file and inject time-code | |
| # --------------------------------------------------------------------------- | |
| for f in "${files[@]}"; do | |
| enc_date=$(mediainfo --Output='General;%Encoded_Date%' -- "$f") || continue | |
| enc_date=${enc_date#UTC } | |
| ep=$(date -u -j -f "%Y-%m-%d %H:%M:%S" "$enc_date" "+%s" 2>/dev/null) || continue | |
| offset=$(( ep - first_epoch )) | |
| [ $offset -lt 0 ] && offset=0 # shouldn’t happen, but be safe | |
| hh=$(( offset / 3600 )) | |
| mm=$(( (offset % 3600) / 60 )) | |
| ss=$(( offset % 60 )) | |
| tc=$(printf "%02d:%02d:%02d:00" "$hh" "$mm" "$ss") | |
| echo "[$f] offset=${offset}s => time-code $tc" | |
| tmp="${f%.*}.__tc__.mp4" | |
| ffmpeg -loglevel error -y -i "$f" \ | |
| -codec copy \ | |
| -timecode "$tc" \ | |
| "$tmp" | |
| mv -f "$tmp" "$f" | |
| done | |
| echo "All done." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment