transcode-video.sh 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. #!/usr/bin/env bash
  2. # https://gist.github.com/mrbar42/ae111731906f958b396f30906004b3fa
  3. set -e
  4. # Usage create-vod-hls.sh SOURCE_FILE [OUTPUT_NAME]
  5. [[ ! "${1}" ]] && echo "Usage: create-vod-hls.sh SOURCE_FILE [OUTPUT_NAME]" && exit 1
  6. FFMPEG=ffmpeg
  7. # comment/add lines here to control which renditions would be created
  8. renditions=(
  9. # resolution bitrate audio-rate
  10. # "426x240 400k 64k"
  11. "640x360 800k 96k"
  12. # "842x480 1400k 128k"
  13. # "1280x720 2800k 128k"
  14. # "1920x1080 5000k 192k"
  15. )
  16. segment_target_duration=2 # try to create a new segment every X seconds
  17. max_bitrate_ratio=1.07 # maximum accepted bitrate fluctuations
  18. rate_monitor_buffer_ratio=1.5 # maximum buffer size between bitrate conformance checks
  19. #########################################################################
  20. source="${1}"
  21. target="${2}"
  22. if [[ ! "${target}" ]]; then
  23. target="${source##*/}" # leave only last component of path
  24. target="${target%.*}" # strip extension
  25. fi
  26. mkdir -p ${target}
  27. key_frames_interval="$(echo `ffprobe ${source} 2>&1 | grep -oE '[[:digit:]]+(.[[:digit:]]+)? fps' | grep -oE '[[:digit:]]+(.[[:digit:]]+)?'`*2 | bc || echo '')"
  28. key_frames_interval=${key_frames_interval:-50}
  29. key_frames_interval=$(echo `printf "%.1f\n" $(bc -l <<<"$key_frames_interval/10")`*10 | bc) # round
  30. key_frames_interval=${key_frames_interval%.*} # truncate to integer
  31. # static parameters that are similar for all renditions
  32. static_params="-c:a aac -ar 48000 -c:v h264 -profile:v main -crf 20 -sc_threshold 0 -strict -2"
  33. static_params+=" -g ${key_frames_interval} -keyint_min ${key_frames_interval} -force_key_frames expr:gte(t,n_forced*2) -hls_time ${segment_target_duration}"
  34. # not working w current
  35. #static_params+=" -hls_playlist_type vod"
  36. static_params+=" -hls_list_size 0"
  37. # misc params
  38. misc_params="-hide_banner -y"
  39. master_playlist="#EXTM3U
  40. #EXT-X-VERSION:3
  41. "
  42. cmd=""
  43. for rendition in "${renditions[@]}"; do
  44. # drop extraneous spaces
  45. rendition="${rendition/[[:space:]]+/ }"
  46. # rendition fields
  47. resolution="$(echo ${rendition} | cut -d ' ' -f 1)"
  48. bitrate="$(echo ${rendition} | cut -d ' ' -f 2)"
  49. audiorate="$(echo ${rendition} | cut -d ' ' -f 3)"
  50. # calculated fields
  51. width="$(echo ${resolution} | grep -oE '^[[:digit:]]+')"
  52. height="$(echo ${resolution} | grep -oE '[[:digit:]]+$')"
  53. maxrate="$(echo "`echo ${bitrate} | grep -oE '[[:digit:]]+'`*${max_bitrate_ratio}" | bc)"
  54. bufsize="$(echo "`echo ${bitrate} | grep -oE '[[:digit:]]+'`*${rate_monitor_buffer_ratio}" | bc)"
  55. bandwidth="$(echo ${bitrate} | grep -oE '[[:digit:]]+')000"
  56. name="${height}p"
  57. cmd+=" ${static_params} -vf scale=w=${width}:h=${height}" # :force_original_aspect_ratio=decrease
  58. cmd+=" -b:v ${bitrate} -maxrate ${maxrate%.*}k -bufsize ${bufsize%.*}k -b:a ${audiorate}"
  59. cmd+=" -hls_segment_filename ${target}/${name}_%03d.ts ${target}/${name}.m3u8"
  60. # add rendition entry in the master playlist
  61. master_playlist+="#EXT-X-STREAM-INF:BANDWIDTH=${bandwidth},RESOLUTION=${resolution}\n${name}.m3u8\n"
  62. done
  63. # start conversion
  64. echo -e "Executing command:\n${FFMPEG} ${misc_params} -i ${source} ${cmd}"
  65. $FFMPEG ${misc_params} -i ${source} ${cmd}
  66. # create master playlist file
  67. echo -e "${master_playlist}" > ${target}/playlist.m3u8
  68. echo "Done - encoded HLS is at ${target}/"