#!/usr/bin/env bash # https://gist.github.com/mrbar42/ae111731906f958b396f30906004b3fa set -e # Usage create-vod-hls.sh SOURCE_FILE [OUTPUT_NAME] [[ ! "${1}" ]] && echo "Usage: create-vod-hls.sh SOURCE_FILE [OUTPUT_NAME]" && exit 1 FFMPEG=ffmpeg # comment/add lines here to control which renditions would be created renditions=( # resolution bitrate audio-rate # "426x240 400k 64k" "640x360 800k 96k" # "842x480 1400k 128k" # "1280x720 2800k 128k" # "1920x1080 5000k 192k" ) segment_target_duration=2 # try to create a new segment every X seconds max_bitrate_ratio=1.07 # maximum accepted bitrate fluctuations rate_monitor_buffer_ratio=1.5 # maximum buffer size between bitrate conformance checks ######################################################################### source="${1}" target="${2}" if [[ ! "${target}" ]]; then target="${source##*/}" # leave only last component of path target="${target%.*}" # strip extension fi mkdir -p ${target} key_frames_interval="$(echo `ffprobe ${source} 2>&1 | grep -oE '[[:digit:]]+(.[[:digit:]]+)? fps' | grep -oE '[[:digit:]]+(.[[:digit:]]+)?'`*2 | bc || echo '')" key_frames_interval=${key_frames_interval:-50} key_frames_interval=$(echo `printf "%.1f\n" $(bc -l <<<"$key_frames_interval/10")`*10 | bc) # round key_frames_interval=${key_frames_interval%.*} # truncate to integer # static parameters that are similar for all renditions static_params="-c:a aac -ar 48000 -c:v h264 -profile:v main -crf 20 -sc_threshold 0 -strict -2" 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}" # not working w current #static_params+=" -hls_playlist_type vod" static_params+=" -hls_list_size 0" # misc params misc_params="-hide_banner -y" master_playlist="#EXTM3U #EXT-X-VERSION:3 " cmd="" for rendition in "${renditions[@]}"; do # drop extraneous spaces rendition="${rendition/[[:space:]]+/ }" # rendition fields resolution="$(echo ${rendition} | cut -d ' ' -f 1)" bitrate="$(echo ${rendition} | cut -d ' ' -f 2)" audiorate="$(echo ${rendition} | cut -d ' ' -f 3)" # calculated fields width="$(echo ${resolution} | grep -oE '^[[:digit:]]+')" height="$(echo ${resolution} | grep -oE '[[:digit:]]+$')" maxrate="$(echo "`echo ${bitrate} | grep -oE '[[:digit:]]+'`*${max_bitrate_ratio}" | bc)" bufsize="$(echo "`echo ${bitrate} | grep -oE '[[:digit:]]+'`*${rate_monitor_buffer_ratio}" | bc)" bandwidth="$(echo ${bitrate} | grep -oE '[[:digit:]]+')000" name="${height}p" cmd+=" ${static_params} -vf scale=w=${width}:h=${height}" # :force_original_aspect_ratio=decrease cmd+=" -b:v ${bitrate} -maxrate ${maxrate%.*}k -bufsize ${bufsize%.*}k -b:a ${audiorate}" cmd+=" -hls_segment_filename ${target}/${name}_%03d.ts ${target}/${name}.m3u8" # add rendition entry in the master playlist master_playlist+="#EXT-X-STREAM-INF:BANDWIDTH=${bandwidth},RESOLUTION=${resolution}\n${name}.m3u8\n" done # start conversion echo -e "Executing command:\n${FFMPEG} ${misc_params} -i ${source} ${cmd}" $FFMPEG ${misc_params} -i ${source} ${cmd} # create master playlist file echo -e "${master_playlist}" > ${target}/playlist.m3u8 echo "Done - encoded HLS is at ${target}/"