Skip to content

Instantly share code, notes, and snippets.

@liveinstantly
Last active March 29, 2023 09:12
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 liveinstantly/7969cc44d14e96c98434cf4e8744a15f to your computer and use it in GitHub Desktop.
Save liveinstantly/7969cc44d14e96c98434cf4e8744a15f to your computer and use it in GitHub Desktop.
FFmpeg scripts: Multiple-bitrate live transcoding for adaptive live streaming with FFmpeg.
#!/bin/bash
#
# ffmpeg_filelive_abr_transcode.sh
# FFmpeg scripts: Multiple-bitrate live transcoding for adaptive live streaming with FFmpeg.
#
# (c) 2023 LiveInstantly, LLC. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# NOTE:
# - This script is fixed for 30fps input video.
# - 'High' profile video encoding is with 128kbps audio and other profiles are with 64kbps audio.
# - The encode spec file is as follows:
#
# The encoding spec file is a text file with multiple lines, and each line must have 3 elements with comma-separated:
# stream-name,video-width,video-hight,video-bitrate,vieo-profile
#
# A sample encoding spec file is as follows:
# livestream1,1280,720,1500,high
# livestream2,960,540,800,baseline
# livestream3,640,360,500,baseline
#
print_usage() {
echo ""
echo "`basename $0`: ffmpeg GOP aligned encoding for Live Streaming."
echo ""
echo "Usage: `basename $0` [-f filename] [-s encoding_spec_file]"
echo " [-h host] [-p port] [-a app] [-u username] [-p password]"
echo ""
echo " [filename] An input video file path and name for generating live streams."
echo " [encoding_spec_file] An encoding spec file name."
echo " [host] A host name for ingesting live streams."
echo " [port] A port number for ingesting live streams"
echo " [app] An app name for ingesting live streams."
echo " [username] An username for source authentication."
echo " [password] A password for source authentication."
echo ""
exit 1
}
# Initial values
dryrun=0
app_path=live
host=yourhost
port=1935
# Get options
OPTIONS=`getopt -n $(basename $0) -o a:df:h:n:p:u:s: -- "$@"`
[ "x$?" != "x0" ] && print_usage
eval set -- "$OPTIONS"
#echo $OPTIONS
while [ $# -gt 0 ]
do
case $1 in
-a) app_path=$2; shift ;;
-d) dryrun=1; ;;
-f) file=$(realpath $2); [ ! -f ${file} ] && echo "`basename $0`: invalid argument -- 'f': file not found: $file" && print_usage; shift ;;
-h) host=$2; shift ;;
-n) port=$2; shift ;;
-p) password=$2; shift ;;
-s) spec=$(realpath $2); [ ! -f ${spec} ] && echo "`basename $0`: invalid argument -- 's': file not found: $spec" && print_usage; shift ;;
-u) username=$2; shift ;;
--) shift; break ;;
*) print_usage ;;
esac
shift
done
url_prefix=
if [ "x${username}" != "x" -a "x${password}" != "x" ]; then
url_prefix="${username}:${password}@"
fi
videofps=30
goplength=2
gopsize=`expr ${videofps} \* ${goplength}`
options="ffmpeg -threads 4"
options="${options} -re -stream_loop -1"
options="${options} -i ${file}"
options="${options} -rtmp_live live"
options="${options} -pix_fmt yuv420p"
options="${options} -r ${videofps}"
while read line
do
stream=`echo ${line} | sed 's/^\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\)$/\1/'`
width=`echo ${line} | sed 's/^\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\)$/\2/'`
height=`echo ${line} | sed 's/^\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\)$/\3/'`
bitrate=`echo ${line} | sed 's/^\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\)$/\4/'`
profile=`echo ${line} | sed 's/^\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\)$/\5/'`
bufsize=`expr ${bitrate} \* 2`
bitrate_str=`printf "%04d" ${bitrate}`
bufsize=`expr ${bitrate} \* 2`
# Map for Video Encoding
options="${options} -map 0:v:0 -c:v libx264"
options="${options} -preset veryfast -tune animation"
options="${options} -b:v ${bitrate}k -profile:v ${profile}"
options="${options} -s:v ${width}x${height}"
#options="${options} -vf:v scale=${width}:${height}"
options="${options} -minrate:v ${bitrate}k"
options="${options} -maxrate:v ${bitrate}k"
options="${options} -bufsize:v ${bufsize}k"
options="${options} -flags:v +cgop"
options="${options} -g ${gopsize} -x264opts keyint=${gopsize}:keyint_min=${gopsize}:no-scenecut"
options="${options} -sc_threshold 0 -crf 23 -vsync 1"
options="${options} -filter:v drawtext=:text=(bitrate=${bitrate}K):fontsize=32:x=32:y=32:box=1:boxcolor=white:fontcolor=black,drawtext=:text=%{localtime}:x=32:y=64:fontsize=32:box=1:boxcolor=white:fontcolor=black,drawtext=:text=%{pts\\\:hms}:x=32:y=96:fontsize=32:box=1:boxcolor=white:fontcolor=black"
# Map for Audio Encoding
options="${options} -map 0:a:0 -c:a aac"
if [ "x${profile}" = "xhigh" ]; then
options="${options} -b:a 128k -ac:a 2 -ar:a 48000"
else
options="${options} -b:a 64k -ac:a 2 -ar:a 48000"
fi
options="${options} -af:a aresample=async=1:min_hard_comp=0.100000:first_pts=0"
# Output RTMP
options="${options} -f flv"
options="${options} rtmp://${url_prefix}${host}:${port}/${app_path}/${stream}"
done < ${spec}
if [ ${dryrun} == 1 ]; then
echo ${options}
else
exec ${options}
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment