split_video_for_youtube.sh (1825B)
1 #!/bin/bash 2 # 3 # Split a video file (to MKV format) suitable for standard users in Youtube (<15') 4 # 5 # $ bash split_video_for_youtube.sh video.avi 6 # video.part1.mkv 7 # video.part2.mkv 8 # 9 # $ youtube-upload [OPTIONS] video.part*.mkv 10 # 11 12 # Echo to standard error 13 debug() { 14 echo "$@" >&2 15 } 16 17 # Returns duration (in seconds) of a video $1 (uses ffmpeg). 18 get_video_duration() { 19 OUTPUT=$(ffmpeg -i "$1" -vframes 1 -f rawvideo -y /dev/null 2>&1) || 20 { debug -e "get_video_duration: error running ffmpeg:\n$OUTPUT"; return 1; } 21 DURATION=$(echo "$OUTPUT" | grep -m1 "^[[:space:]]*Duration:" | 22 cut -d":" -f2- | cut -d"," -f1 | sed "s/[:\.]/ /g") || 23 { debug -e "get_video_duration: error parsing duration:\n$OUTPUT"; return 1; } 24 read HOURS MINUTES SECONDS DECISECONDS <<< "$DURATION" 25 echo $((10#$HOURS * 3600 + 10#$MINUTES * 60 + 10#$SECONDS)) 26 } 27 28 main() { 29 set -e -u -o pipefail 30 if test $# -eq 0; then 31 debug "Usage: $(basename $0) VIDEO [EXTRA_OPTIONS_FOR_FFMPEG]" 32 exit 1 33 fi 34 CHUNK_DURATION=$((60*15)) 35 VIDEO=$1 36 shift 1 37 38 DURATION=$(get_video_duration "$VIDEO") 39 if test $DURATION -le $CHUNK_DURATION; then 40 debug "no need to split, duration of video: $DURATION <= $CHUNK_DURATION" 41 echo "$VIDEO" 42 exit 0 43 fi 44 45 EXTENSION=${VIDEO##*.} 46 BASENAME=$(basename "$VIDEO" ".$EXTENSION") 47 debug "start split: $VIDEO ($DURATION seconds)" 48 seq 0 $CHUNK_DURATION $DURATION | cat -n | while read INDEX OFFSET; do 49 debug "$VIDEO: from position $OFFSET take $CHUNK_DURATION seconds" 50 PADDED_INDEX=$(printf '%03d' $INDEX) 51 OUTPUT_FILE="${BASENAME}.part${PADDED_INDEX}.mkv" 52 ffmpeg -i "$VIDEO" -vcodec copy -acodec copy "$@" \ 53 -ss $OFFSET -t $CHUNK_DURATION -y "$OUTPUT_FILE" </dev/null 54 echo "$OUTPUT_FILE" 55 done 56 } 57 58 test "$NOEXEC" = 1 || main "$@"