Skip to content

Instantly share code, notes, and snippets.

@krasi-georgiev
Last active April 13, 2025 05:50
Show Gist options
  • Save krasi-georgiev/1f167a2136bbce5824c6516d2777ef79 to your computer and use it in GitHub Desktop.
Save krasi-georgiev/1f167a2136bbce5824c6516d2777ef79 to your computer and use it in GitHub Desktop.
Cut a video file from frame.io comments.
#!/bin/bash
# Run with:
# bash <(curl -sL "https://gist.githubusercontent.com/krasi-georgiev/1f167a2136bbce5824c6516d2777ef79/raw/cut_segments.sh")
shopt -s nullglob
### STEP 1: Select CSV file
csv_files=( *.csv )
if [ ${#csv_files[@]} -eq 0 ]; then
echo "❌ No CSV files found."
exit 1
fi
if [ -t 0 ]; then
echo "Available CSV files:"
select csv_file in "${csv_files[@]}"; do
[[ -n "$csv_file" ]] && break
echo "❌ Invalid selection. Try again."
done
else
csv_file="${csv_files[0]}"
echo "ℹ️ Auto-selected CSV: $csv_file"
fi
### STEP 2: Select MP4 file
mp4_files=( *.mp4 )
if [ ${#mp4_files[@]} -eq 0 ]; then
echo "❌ No MP4 files found."
exit 1
fi
IFS=$'\n' mp4_files=( $(ls -S *.mp4) )
if [ -t 0 ]; then
echo "Available MP4 files (sorted by size):"
select video_file in "${mp4_files[@]}"; do
[[ -n "$video_file" ]] && break
echo "❌ Invalid selection. Try again."
done
else
video_file="${mp4_files[0]}"
echo "ℹ️ Auto-selected MP4: $video_file"
fi
### STEP 3: Detect FPS
FPS=$(ffprobe -v 0 -of csv=p=0 -select_streams v:0 -show_entries stream=r_frame_rate "$video_file" | bc -l)
if [[ -z "$FPS" || "$FPS" == "0" ]]; then
echo "❌ Could not detect FPS from video."
exit 1
fi
echo "🎞 Detected FPS: $FPS"
### STEP 4: Extract Frame column (14)
echo "📋 Parsing frames from column 14..."
mapfile -t frames < <(
tail -n +2 "$csv_file" | awk -F',' '
{
gsub(/^"|"$/, "", $14)
if ($14 ~ /^[0-9]+$/) print $14
}
'
)
### STEP 5: Process in pairs
total_pairs=$(( ${#frames[@]} / 2 ))
echo "🎬 Cutting $total_pairs segments from ${#frames[@]} frame entries..."
for (( i=0; i<${#frames[@]}-1; i+=2 )); do
start_frame="${frames[$i]}"
end_frame="${frames[$((i+1))]}"
if (( end_frame <= start_frame )); then
echo "❌ Error: Invalid segment. End frame ($end_frame) <= Start frame ($start_frame)"
exit 1
fi
start_sec=$(bc <<< "scale=6; $start_frame / $FPS")
end_sec=$(bc <<< "scale=6; $end_frame / $FPS")
output_file="segment_${start_frame}_to_${end_frame}.mp4"
echo "⏱ Cutting: frame $start_frame ($start_sec s) → $end_frame ($end_sec s)"
echo "📁 Output: $output_file"
ffmpeg -hide_banner -loglevel error -y \
-ss "$start_sec" -to "$end_sec" \
-i "$video_file" -c copy "$output_file"
if [ $? -eq 0 ]; then
echo "✅ Created: $output_file"
else
echo "❌ Failed: $output_file"
fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment