89 lines
2.7 KiB
Bash
Executable File
89 lines
2.7 KiB
Bash
Executable File
#!/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."
|