Skip to content

Instantly share code, notes, and snippets.

@victorcastelan
Forked from fitz123/job_gen.sh
Created May 24, 2019 19:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save victorcastelan/e277275cf606d21b15e5ff7592c2b5c3 to your computer and use it in GitHub Desktop.
Save victorcastelan/e277275cf606d21b15e5ff7592c2b5c3 to your computer and use it in GitHub Desktop.
Supervisor ffmpeg transcoding job and HLS playlist generator
#!/bin/bash
###############################################################################
#
# Description:
# Script generates Nimble session-friendly playlists
# (parent playlist with sub-playlists inside) and supervisor program/job
# of ffmpeg process which pulls from provided source address $ch_source and
# pushes to localhost nibmle-origin server as a name $ch_res for later HLS transmuxing
#
# To generate playlists and jobs - templates are used (playlist.template,*-job.template)
#
# As a result followed files will be generated:
# * $supervisor_confd/ffmpeg-$ch_name - supervisor job
# * $playlist_root/$ch_name-$ch_res.m3u8 - "parent" playlist for stream
# (if 3rd arg is 'abr' also playlist for each resolution will be created)
# * $playlist_root/$ch_name.m3u8 - symlink to parent playlist
#
# No output and 0 exit status means everything good, job is started!
#
# Usage example:
# sudo ./job_gen.sh rtmp://27.131.165.98:1935/dvrorigin1/hd-foxpremiumeng_1080 fox abr
#
# Parameters:
# $1) source to grab stream from
# $2) name to publish stream as. Also creates supervisor "program" with the same name
# $3) template to apply for job and playlist generation.
# Possibly values are:
# * 240p, 360p, 480p, 720p - each value generates single transcoding job and playlist
# * copy - re-publishes stream without transcoding and creates playlist
# * abr - generates transcoding job for multiple resolutions,
# creates combined playlist with all resolutions for ABR streaming and
# playlist for each resolution separatelly
#
# script: job_gen.sh
# ver: 0.1
# author: anton.lugovoi@yandex.ru
#
###############################################################################
playlist_root='/srv/media-server/live'
supervisor_confd='/etc/supervisor/conf.d'
resolutions='720p 480p 360p 240p copy'
templates='240p-job.template 480p-job.template abr-job.template copy-job.template 360p-job.template 720p-job.template abr-playlist.template playlist.template'
bw_240p='500000'
bw_360p='1000000'
bw_480p='1500000'
bw_720p='3000000'
bw_copy='9999999'
ch_source="$1"
ch_name="$2"
ch_res="$3"
# fix resolution parameter if passed without trailing p
[ ! 'copy' == "$ch_res" -a ! 'abr' == "$ch_res" -a ! 'p' == "${ch_res:(-1)}" ] && ch_res=$3p
##
# checks
##
print_readme() {
printf '
Usage example:
sudo ./job_gen.sh rtmp://27.131.165.98:1935/dvrorigin1/hd-foxpremiumeng_1080 fox abr
Parameters:
$1) source to grab stream from
$2) name to publish stream as. Also creates supervisor "program" with a such name
$3) template to apply for job and playlist generation.
Possibly values are:
* 240p, 360p, 480p, 720p - each value generates single transcoding job and playlist
* copy - generates "copy" and playlist
* abr - generates transcoding job for multiple resolutions,
creates combined playlist with all resolutions for ABR streaming and
playlist for each resolution separatelly
'
}
# check if run not as root
if [ "$EUID" -ne 0 ]
then echo "Please run as root"
exit 1
fi
# check arguments number
if [ "$#" -ne 3 ]; then
echo "Error: Illegal number of parameters"
print_readme
exit 1
fi
# check resolution
if [[ ! "$resolutions" =~ "$ch_res" ]]; then
if [ ! 'abr' == "$ch_res" ]; then
echo "Error: Illegal resolution $ch_res"
print_readme
exit 1
fi
fi
# check supervisor config directory
[ -d "$supervisor_confd" ] || { echo Error: directory "$supervisor_confd" directory does not exist ; exit 1 ;}
# check playlist root
[ -d "$playlist_root" ] || { echo Error: directory "$playlist_root" directory does not exist ; exit 1 ;}
# check stream directories
for dir in $resolutions; do [ -d "$playlist_root/$dir" ] || { echo Error: directory "$playlist_root/$dir" directory does not exist ; exit 1 ;}; done
# check templates required for jobs and playlists generation
for tpl in $templates; do
if [ ! -e "$tpl" -o ! -f "$tpl" -o ! -s "$tpl" -o ! -r "$tpl" ]; then
echo Error: template "$tpl" does not exist, not a file, zero size or not readable
exit 1
fi
done
# check ffmpeg/ffprobe installed
command -v ffmpeg >/dev/null 2>&1 || { echo >&2 "I require ffmpeg but it's not installed. Aborting."; exit 1; }
command -v ffprobe >/dev/null 2>&1 || { echo >&2 "I require ffprobe but it's not installed. Aborting."; exit 1; }
# check source
ffprobe "$ch_source" 2>&1 | egrep "^\s+Stream.+Video." >/dev/null 2>&1 || { echo Error: stream source $ch_source has no video or invalid ; exit 1 ;}
##
# generate playlists
##
if [ $ch_res == 'abr' ]; then
# playlist with all resolutions
sed -e "s;%channel_name%;$ch_name;g" $ch_res-playlist.template > $playlist_root/$ch_name-$ch_res.m3u8
ln -f -s $playlist_root/$ch_name-$ch_res.m3u8 $playlist_root/$ch_name.m3u8
for res in $resolutions; do
# playlist for nimble sessions compatibility for each resolution inside abr group
bw=bw_$res
sed -e "s;%channel_name%;$ch_name;g" -e "s;%resolution%;$res;g" -e "s;%bandwidth%;${!bw};g" playlist.template > $playlist_root/$ch_name-$res.m3u8
done
else
# playlist for nimble sessions compatibility
bw=bw_$ch_res
sed -e "s;%channel_name%;$ch_name;g" -e "s;%resolution%;$ch_res;g" -e "s;%bandwidth%;${!bw};g" playlist.template > $playlist_root/$ch_name-$ch_res.m3u8
ln -f -s $playlist_root/$ch_name-$ch_res.m3u8 $playlist_root/$ch_name.m3u8
fi
##
# generate supervisor job
##
# detect if stream is http then apply additional parameters for input robustness
input_proto=$(echo "$ch_source" | cut -d: -f1)
if [ "$input_proto" == 'http' ]; then
stream_input_parameters='-reconnect_at_eof 1 -reconnect_streamed 1'
elif [ "$input_proto" == "$ch_source" ]; then
stream_input_parameters='-re'
else
stream_input_parameters=''
fi
sed -e "s;%channel_source%;$ch_source;g" -e "s;%channel_name%;$ch_name;g" -e "s;%stream_input_parameters%;$stream_input_parameters;g" $ch_res-job.template > $supervisor_confd/ffmpeg-$ch_name.conf
supervisorctl update && sleep 3 && \
job_status=$(supervisorctl status $ch_name | awk '{print $2}') && \
[ ! $job_status == 'RUNNING' ] && echo Job has been started but something went wrong. Job status is $job_status && exit 1
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment