|
#!/usr/bin/env bash |
|
|
|
set -e |
|
|
|
# Usage create-vod-hls.sh SOURCE_FILE [OUTPUT_NAME] |
|
[[ ! "${1}" ]] && echo "Usage: create-vod-hls.sh SOURCE_FILE [OUTPUT_NAME]" && exit 1 |
|
|
|
# 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=4 # 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" |
|
static_params+=" -g ${key_frames_interval} -keyint_min ${key_frames_interval} -hls_time ${segment_target_duration}" |
|
static_params+=" -hls_playlist_type vod" |
|
|
|
# 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:\nffmpeg ${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}/" |
This comment has been minimized.
is it possible to add "ffprobe source.mp4" and detect input height,
then create HLS resolution =< source ?
example :
source.mp4 is 720p ( 1280x720 )
then create HLS 720p, 480p, 360p, 240p
another thing is:
for example if source is between 1080p and 720p then again output will begin from 720p and so on
if source is between 2160p and 1080p then again output will begin from 1080p and so on