split_video_for_youtube.sh 1.8 KB

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