Skip to content

Instantly share code, notes, and snippets.

@baso53
Created July 18, 2025 14:28
Show Gist options
  • Select an option

  • Save baso53/d6ebe379c7f0aae0eee5343de11bb53e to your computer and use it in GitHub Desktop.

Select an option

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 …
#!/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