#!/bin/bash # Function to print usage instructions usage() { echo "Usage: $0 input_file HH:MM:SS_1 HH:MM:SS_2 ... HH:MM:SS_N" exit 1 } # Check if there are at least two arguments (input file and one time code) if [ "$#" -lt 2 ]; then usage fi # Get the input file and validate its existence input_file="$1" if [ ! -f "$input_file" ]; then echo "Error: File '$input_file' does not exist." exit 1 fi # Extract file extension and base name extension="${input_file##*.}" base_name="${input_file%.*}" # Get the duration of the input file using ffprobe duration=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$input_file") if [ -z "$duration" ]; then echo "Error: Unable to determine the duration of the file." exit 1 fi duration=${duration%.*} # Convert to integer seconds # Get the list of time codes time_codes=("${@:2}") # Add the end of the video to the list of time codes time_codes+=("$(printf '%02d:%02d:%02d\n' $((duration/3600)) $((duration%3600/60)) $((duration%60)))") # Function to convert HH:MM:SS to seconds time_to_seconds() { local time="$1" IFS=: read -r hh mm ss <<< "$time" echo $((10#$hh * 3600 + 10#$mm * 60 + 10#$ss)) } # Validate each time code for time in "${time_codes[@]}"; do total_seconds=$(time_to_seconds "$time") if [ "$total_seconds" -gt "$duration" ]; then echo "Error: Time code $time exceeds video duration." exit 1 fi done # Process each segment previous_time="00:00:00" for i in "${!time_codes[@]}"; do current_time="${time_codes[i]}" if [ "$i" -eq $((${#time_codes[@]} - 1)) ]; then # If this is the last time code, process until the end of the video current_time=$(printf '%02d:%02d:%02d\n' $((duration/3600)) $((duration%3600/60)) $((duration%60))) fi current_seconds=$(time_to_seconds "$current_time") previous_seconds=$(time_to_seconds "$previous_time") segment_duration=$((current_seconds - previous_seconds)) if [ "$segment_duration" -le 0 ]; then echo "Error: Invalid time range $previous_time to $current_time." exit 1 fi # Generate output file name output_file="${base_name}_${previous_time}-${current_time}.${extension}" echo "Creating segment: $output_file" if [ "$previous_time" == "00:00:00" ]; then # For the first segment, ensure that it starts from the very first frame (avoiding keyframe issues) ffmpeg -y -i "$input_file" -ss "$previous_time" -to "$current_time" -c:v copy -c:a copy -c:s copy -map 0 -copyts -vsync 1 "$output_file" else # For subsequent segments, simply seek and copy streams ffmpeg -y -i "$input_file" -ss "$previous_time" -to "$current_time" -c:v copy -c:a copy -c:s copy -map 0 -copyts "$output_file" fi previous_time="$current_time" done echo "Splitting completed successfully."