Ooops. Bugfix for HLS-16
Ooops. Bugfix for HLS-16

#!/bin/bash #!/bin/bash
# #
# A very simple BASH script to take an input video and split it down into Segments # A very simple BASH script to take an input video and split it down into Segments
# before creating an M3U8 Playlist, allowing the file to be served using HLS # before creating an M3U8 Playlist, allowing the file to be served using HLS
# #
# #
   
###################################################################################### ######################################################################################
# #
# Copyright (c) 2013, Ben Tasker # Copyright (c) 2013, Ben Tasker
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met: # are permitted provided that the following conditions are met:
# #
# Redistributions of source code must retain the above copyright notice, this # Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer. # list of conditions and the following disclaimer.
# #
# Redistributions in binary form must reproduce the above copyright notice, this # Redistributions in binary form must reproduce the above copyright notice, this
# list of conditions and the following disclaimer in the documentation and/or # list of conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution. # other materials provided with the distribution.
# #
# Neither the name of Ben Tasker nor the names of his # Neither the name of Ben Tasker nor the names of his
# contributors may be used to endorse or promote products derived from # contributors may be used to endorse or promote products derived from
# this software without specific prior written permission. # this software without specific prior written permission.
# #
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# #
###################################################################################### ######################################################################################
   
# Basic config # Basic config
OUTPUT_DIRECTORY=${OUTPUT_DIRECTORY:-'./output'} OUTPUT_DIRECTORY=${OUTPUT_DIRECTORY:-'./output'}
   
# Change this if you want to specify a path to use a specific version of FFMPeg # Change this if you want to specify a path to use a specific version of FFMPeg
FFMPEG=${FFMPEG:-'ffmpeg'} FFMPEG=${FFMPEG:-'ffmpeg'}
   
# Number of threads which will be used for transcoding. With newer FFMPEGs and x264 # Number of threads which will be used for transcoding. With newer FFMPEGs and x264
# encoders "0" means "optimal". This is normally the number of CPU cores. # encoders "0" means "optimal". This is normally the number of CPU cores.
NUMTHREADS=${NUMTHREADS:-"0"} NUMTHREADS=${NUMTHREADS:-"0"}
   
# Video codec for the output video. Will be used as an value for the -vcodec argument # Video codec for the output video. Will be used as an value for the -vcodec argument
VIDEO_CODEC=${VIDEO_CODEC:-"libx264"} VIDEO_CODEC=${VIDEO_CODEC:-"libx264"}
   
# Video codec for the output video. Will be used as an value for the -acodec argument # Video codec for the output video. Will be used as an value for the -acodec argument
AUDIO_CODEC=${AUDIO_CODEC:-"libfdk_aac"} AUDIO_CODEC=${AUDIO_CODEC:-"libfdk_aac"}
   
# Additional flags for ffmpeg # Additional flags for ffmpeg
FFMPEG_FLAGS=${FFMPEG_FLAGS:-""} FFMPEG_FLAGS=${FFMPEG_FLAGS:-""}
   
# If the input is a live stream (i.e. linear video) this should be 1 # If the input is a live stream (i.e. linear video) this should be 1
LIVE_STREAM=${LIVE_STREAM:-0} LIVE_STREAM=${LIVE_STREAM:-0}
   
# Video bitrates to use in output (comma seperated list if you want to create an adaptive stream.) # Video bitrates to use in output (comma seperated list if you want to create an adaptive stream.)
# leave null to use the input bitrate # leave null to use the input bitrate
OP_BITRATES=${OP_BITRATES:-''} OP_BITRATES=${OP_BITRATES:-''}
   
# Determines whether the processing for adaptive streams should run sequentially or not # Determines whether the processing for adaptive streams should run sequentially or not
NO_FORK=${NO_FORK:-0} NO_FORK=${NO_FORK:-0}
   
# Lets put our functions here # Lets put our functions here
   
   
## Output the script's CLI Usage ## Output the script's CLI Usage
# #
# #
function print_usage(){ function print_usage(){
   
cat << EOM cat << EOM
HTTP Live Stream Creator HTTP Live Stream Creator
Version 1 Version 1
   
Copyright (C) 2013 B Tasker, D Atanasov Copyright (C) 2013 B Tasker, D Atanasov
Released under BSD 3 Clause License Released under BSD 3 Clause License
See LICENSE See LICENSE
   
   
Usage: HLS-Stream-Creator.sh -[lf] [-c segmentcount] -i [inputfile] -s [segmentlength(seconds)] -o [outputdir] -b [bitrates] [-p filename] Usage: HLS-Stream-Creator.sh -[lf] [-c segmentcount] -i [inputfile] -s [segmentlength(seconds)] -o [outputdir] -b [bitrates] [-p filename]
   
-i Input file -i Input file
-s Segment length (seconds) -s Segment length (seconds)
-o Output directory (default: ./output) -o Output directory (default: ./output)
-l Input is a live stream -l Input is a live stream
-c Number of segments to include in playlist (live streams only) - 0 is no limit -c Number of segments to include in playlist (live streams only) - 0 is no limit
-b Output video Bitrates (comma seperated list for adaptive streams) -b Output video Bitrates (comma seperated list for adaptive streams)
-f Foreground encoding only (don't fork the encoding processes into the background - adaptive non-live streams only) -f Foreground encoding only (don't fork the encoding processes into the background - adaptive non-live streams only)
-p Playlist filename -p Playlist filename
-t Segment filename prefix -t Segment filename prefix
-S Segment directory name (default none) -S Segment directory name (default none)
   
Deprecated Legacy usage: Deprecated Legacy usage:
HLS-Stream-Creator.sh inputfile segmentlength(seconds) [outputdir='./output'] HLS-Stream-Creator.sh inputfile segmentlength(seconds) [outputdir='./output']
   
EOM EOM
   
exit exit
   
} }
   
   
function createStream(){ function createStream(){
# For VoD and single bitrate streams the variables we need will exist in Global scope. # For VoD and single bitrate streams the variables we need will exist in Global scope.
# for live adaptive streams though, that won't be the case, so we need to take them as arguments # for live adaptive streams though, that won't be the case, so we need to take them as arguments
# Some are global though, so we'll leave those as is # Some are global though, so we'll leave those as is
   
playlist_name="$1" playlist_name="$1"
output_name="$2" output_name="$2"
bitrate="$3" bitrate="$3"
infile="$4" infile="$4"
   
$FFMPEG -i "$infile" \ $FFMPEG -i "$infile" \
-loglevel error -y \ -loglevel error -y \
-vcodec "$VIDEO_CODEC" \ -vcodec "$VIDEO_CODEC" \
-acodec "$AUDIO_CODEC" \ -acodec "$AUDIO_CODEC" \
-threads "$NUMTHREADS" \ -threads "$NUMTHREADS" \
-map 0 \ -map 0 \
-flags \ -flags \
-global_header \ -global_header \
-f segment \ -f segment \
-segment_list "$playlist_name" \ -segment_list "$playlist_name" \
-segment_time "$SEGLENGTH" \ -segment_time "$SEGLENGTH" \
-segment_format mpeg_ts \ -segment_format mpeg_ts \
$bitrate \ $bitrate \
$FFMPEG_ADDITIONAL \ $FFMPEG_ADDITIONAL \
$FFMPEG_FLAGS \ $FFMPEG_FLAGS \
"$OUTPUT_DIRECTORY/$output_name" "$OUTPUT_DIRECTORY/$output_name"
} }
   
   
function createVariantPlaylist(){ function createVariantPlaylist(){
playlist_name="$1" playlist_name="$1"
echo "#EXTM3U" > "$playlist_name" echo "#EXTM3U" > "$playlist_name"
} }
   
   
function appendVariantPlaylistentry(){ function appendVariantPlaylistentry(){
playlist_name=$1 playlist_name=$1
playlist_path=$2 playlist_path=$2
playlist_bw=$(( $3 * 1000 )) # bits not bytes :) playlist_bw=$(( $3 * 1000 )) # bits not bytes :)
   
cat << EOM >> "$playlist_name" cat << EOM >> "$playlist_name"
#EXT-X-STREAM-INF:BANDWIDTH=$playlist_bw #EXT-X-STREAM-INF:BANDWIDTH=$playlist_bw
$playlist_path $playlist_path
EOM EOM
   
} }
   
   
function awaitCompletion(){ function awaitCompletion(){
# Monitor the encoding pids for their completion status # Monitor the encoding pids for their completion status
while [ ${#PIDS[@]} -ne 0 ]; do while [ ${#PIDS[@]} -ne 0 ]; do
# Calculate the length of the array # Calculate the length of the array
pid_length=$((${#PIDS[@]} - 1)) pid_length=$((${#PIDS[@]} - 1))
   
# Check each PID in the array # Check each PID in the array
for i in `seq 0 $pid_length` for i in `seq 0 $pid_length`
do do
# Test whether the pid is still active # Test whether the pid is still active
if ! kill -0 ${PIDS[$i]} 2> /dev/null if ! kill -0 ${PIDS[$i]} 2> /dev/null
then then
echo "Encoding for bitrate ${BITRATE_PROCESSES[$i]}k completed" echo "Encoding for bitrate ${BITRATE_PROCESSES[$i]}k completed"
unset BITRATE_PROCESSES[$i] unset BITRATE_PROCESSES[$i]
unset PIDS[$i] unset PIDS[$i]
fi fi
done done
PIDS=("${PIDS[@]}") # remove any nulls PIDS=("${PIDS[@]}") # remove any nulls
sleep 1 sleep 1
done done
} }
   
   
# This is used internally, if the user wants to specify their own flags they should be # This is used internally, if the user wants to specify their own flags they should be
# setting FFMPEG_FLAGS # setting FFMPEG_FLAGS
FFMPEG_ADDITIONAL='' FFMPEG_ADDITIONAL=''
LIVE_SEGMENT_COUNT=0 LIVE_SEGMENT_COUNT=0
IS_FIFO=0 IS_FIFO=0
TMPDIR=${TMPDIR:-"/tmp"} TMPDIR=${TMPDIR:-"/tmp"}
MYPID=$$ MYPID=$$
# Get the input data # Get the input data
   
# This exists to maintain b/c # This exists to maintain b/c
LEGACY_ARGS=1 LEGACY_ARGS=1
   
# If even one argument is supplied, switch off legacy argument style # If even one argument is supplied, switch off legacy argument style
while getopts "i:o:s:c:b:p:t:S:lf" flag while getopts "i:o:s:c:b:p:t:S:lf" flag
do do
LEGACY_ARGS=0 LEGACY_ARGS=0
case "$flag" in case "$flag" in
i) INPUTFILE="$OPTARG";; i) INPUTFILE="$OPTARG";;
o) OUTPUT_DIRECTORY="$OPTARG";; o) OUTPUT_DIRECTORY="$OPTARG";;
s) SEGLENGTH="$OPTARG";; s) SEGLENGTH="$OPTARG";;
l) LIVE_STREAM=1;; l) LIVE_STREAM=1;;
c) LIVE_SEGMENT_COUNT="$OPTARG";; c) LIVE_SEGMENT_COUNT="$OPTARG";;
b) OP_BITRATES="$OPTARG";; b) OP_BITRATES="$OPTARG";;
f) NO_FORK=1;; f) NO_FORK=1;;
p) PLAYLIST_PREFIX="$OPTARG";; p) PLAYLIST_PREFIX="$OPTARG";;
t) SEGMENT_PREFIX="$OPTARG";; t) SEGMENT_PREFIX="$OPTARG";;
S) SEGMENT_DIRECTORY="$OPTARG";; S) SEGMENT_DIRECTORY="$OPTARG";;
esac esac
done done
   
   
if [ "$LEGACY_ARGS" == "1" ] if [ "$LEGACY_ARGS" == "1" ]
then then
# Old Basic Usage is # Old Basic Usage is
# cmd.sh inputfile segmentlength # cmd.sh inputfile segmentlength
   
INPUTFILE=${INPUTFILE:-$1} INPUTFILE=${INPUTFILE:-$1}
SEGLENGTH=${SEGLENGTH:-$2} SEGLENGTH=${SEGLENGTH:-$2}
if ! [ -z "$3" ] if ! [ -z "$3" ]
then then
OUTPUT_DIRECTORY=$3 OUTPUT_DIRECTORY=$3
fi fi
fi fi
   
   
# Check we've got the arguments we need # Check we've got the arguments we need
if [ "$INPUTFILE" == "" ] || [ "$SEGLENGTH" == "" ] if [ "$INPUTFILE" == "" ] || [ "$SEGLENGTH" == "" ]
then then
print_usage print_usage
fi fi
   
# FFMpeg is a pre-requisite, so let check for it # FFMpeg is a pre-requisite, so let check for it
if hash $FFMPEG 2> /dev/null if hash $FFMPEG 2> /dev/null
then then
# FFMpeg exists # FFMpeg exists
echo "ffmpeg command found.... continuing" echo "ffmpeg command found.... continuing"
else else
# FFMPeg doesn't exist, uh-oh! # FFMPeg doesn't exist, uh-oh!
echo "Error: FFmpeg doesn't appear to exist in your PATH. Please addresss and try again" echo "Error: FFmpeg doesn't appear to exist in your PATH. Please addresss and try again"
exit 1 exit 1
fi fi
   
# Check whether the input is a named pipe # Check whether the input is a named pipe
if [ -p "$INPUTFILE" ] if [ -p "$INPUTFILE" ]
then then
echo "Warning: Input is FIFO - EXPERIMENTAL" echo "Warning: Input is FIFO - EXPERIMENTAL"
IS_FIFO=1 IS_FIFO=1
   
fi fi
   
# Check output directory exists otherwise create it # Check output directory exists otherwise create it
if [ ! -w $OUTPUT_DIRECTORY ] if [ ! -w $OUTPUT_DIRECTORY ]
then then
echo "Creating $OUTPUT_DIRECTORY" echo "Creating $OUTPUT_DIRECTORY"
mkdir -p $OUTPUT_DIRECTORY mkdir -p $OUTPUT_DIRECTORY
fi fi
   
if [ "$LIVE_STREAM" == "1" ] if [ "$LIVE_STREAM" == "1" ]
then then
FFMPEG_ADDITIONAL+="-segment_list_flags +live" FFMPEG_ADDITIONAL+="-segment_list_flags +live"
   
if [ "$LIVE_SEGMENT_COUNT" -gt 0 ] if [ "$LIVE_SEGMENT_COUNT" -gt 0 ]
then then
FFMPEG_ADDITIONAL+=" -segment_list_size $LIVE_SEGMENT_COUNT" FFMPEG_ADDITIONAL+=" -segment_list_size $LIVE_SEGMENT_COUNT"
fi fi
fi fi
   
   
# Pulls file name from INPUTFILE which may be an absolute or relative path. # Pulls file name from INPUTFILE which may be an absolute or relative path.
INPUTFILENAME=${INPUTFILE##*/} INPUTFILENAME=${INPUTFILE##*/}
   
# If a prefix hasn't been specified, use the input filename # If a prefix hasn't been specified, use the input filename
PLAYLIST_PREFIX=${PLAYLIST_PREFIX:-$INPUTFILENAME} PLAYLIST_PREFIX=${PLAYLIST_PREFIX:-$INPUTFILENAME}
SEGMENT_PREFIX=${SEGMENT_PREFIX:-$PLAYLIST_PREFIX} SEGMENT_PREFIX=${SEGMENT_PREFIX:-$PLAYLIST_PREFIX}
   
# The 'S' option allows segments and bitrate specific manifests to be placed in a subdir # The 'S' option allows segments and bitrate specific manifests to be placed in a subdir
SEGMENT_DIRECTORY=${SEGMENT_DIRECTORY:-''} SEGMENT_DIRECTORY=${SEGMENT_DIRECTORY:-''}
   
if [ ! "$SEGMENT_DIRECTORY" == "" ] if [ ! "$SEGMENT_DIRECTORY" == "" ]
then then
   
if [ ! -d "${OUTPUT_DIRECTORY}/${SEGMENT_DIRECTORY}" ] if [ ! -d "${OUTPUT_DIRECTORY}/${SEGMENT_DIRECTORY}" ]
then then
mkdir "${OUTPUT_DIRECTORY}/${SEGMENT_DIRECTORY}" mkdir "${OUTPUT_DIRECTORY}/${SEGMENT_DIRECTORY}"
fi fi
   
SEGMENT_DIRECTORY+="/" SEGMENT_DIRECTORY+="/"
fi fi
   
# Set the bitrate # Set the bitrate
if [ ! "$OP_BITRATES" == "" ] if [ ! "$OP_BITRATES" == "" ]
then then
# Make the bitrate list easier to parse # Make the bitrate list easier to parse
OP_BITRATES=${OP_BITRATES//,/$'\n'} OP_BITRATES=${OP_BITRATES//,/$'\n'}
   
# Create an array to house the pids for backgrounded tasks # Create an array to house the pids for backgrounded tasks
declare -a PIDS declare -a PIDS
declare -a BITRATE_PROCESSES declare -a BITRATE_PROCESSES
   
# Get the variant playlist created # Get the variant playlist created
createVariantPlaylist "$OUTPUT_DIRECTORY/${PLAYLIST_PREFIX}_master.m3u8" createVariantPlaylist "$OUTPUT_DIRECTORY/${PLAYLIST_PREFIX}_master.m3u8"
for br in $OP_BITRATES for br in $OP_BITRATES
do do
appendVariantPlaylistentry "$OUTPUT_DIRECTORY/${SEGMENT_DIRECTORY}${PLAYLIST_PREFIX}_master.m3u8" "${PLAYLIST_PREFIX}_${br}.m3u8" "$br" appendVariantPlaylistentry "$OUTPUT_DIRECTORY/${PLAYLIST_PREFIX}_master.m3u8" "${SEGMENT_DIRECTORY}${PLAYLIST_PREFIX}_${br}.m3u8" "$br"
done done
   
OUTPUT_DIRECTORY+=$SEGMENT_DIRECTORY OUTPUT_DIRECTORY+=$SEGMENT_DIRECTORY
   
# Now for the longer running bit, transcode the video # Now for the longer running bit, transcode the video
for br in $OP_BITRATES for br in $OP_BITRATES
do do
BITRATE="-b:v ${br}k -bufsize ${br}k" BITRATE="-b:v ${br}k -bufsize ${br}k"
# Finally, lets build the output filename format # Finally, lets build the output filename format
OUT_NAME="${SEGMENT_PREFIX}_${br}_%05d.ts" OUT_NAME="${SEGMENT_PREFIX}_${br}_%05d.ts"
PLAYLIST_NAME="$OUTPUT_DIRECTORY/${PLAYLIST_PREFIX}_${br}.m3u8" PLAYLIST_NAME="$OUTPUT_DIRECTORY/${PLAYLIST_PREFIX}_${br}.m3u8"
SOURCE_FILE="$INPUTFILE" SOURCE_FILE="$INPUTFILE"
echo "Generating HLS segments for bitrate ${br}k - this may take some time" echo "Generating HLS segments for bitrate ${br}k - this may take some time"
   
if [ "$NO_FORK" == "0" ] || [ "$LIVE_STREAM" == "1" ] if [ "$NO_FORK" == "0" ] || [ "$LIVE_STREAM" == "1" ]
then then
# Processing Starts # Processing Starts
if [ "$IS_FIFO" == "1" ] if [ "$IS_FIFO" == "1" ]
then then
# Create a FIFO specially for this bitrate # Create a FIFO specially for this bitrate
SOURCE_FILE="$TMPDIR/hlsc.encode.$MYPID.$br" SOURCE_FILE="$TMPDIR/hlsc.encode.$MYPID.$br"
mknod "$SOURCE_FILE" p mknod "$SOURCE_FILE" p
fi fi
   
# Schedule the encode # Schedule the encode
createStream "$PLAYLIST_NAME" "$OUT_NAME" "$BITRATE" "$SOURCE_FILE" & createStream "$PLAYLIST_NAME" "$OUT_NAME" "$BITRATE" "$SOURCE_FILE" &
PID=$! PID=$!
PIDS=(${PIDS[@]} $PID) PIDS=(${PIDS[@]} $PID)
BITRATE_PROCESSES=(${BITRATE_PROCESSES[@]} $br) BITRATE_PROCESSES=(${BITRATE_PROCESSES[@]} $br)
else else
createStream "$PLAYLIST_NAME" "$OUT_NAME" "$BITRATE" "$SOURCE_FILE" createStream "$PLAYLIST_NAME" "$OUT_NAME" "$BITRATE" "$SOURCE_FILE"
fi fi
   
done done
   
if [ "$IS_FIFO" == "1" ] if [ "$IS_FIFO" == "1" ]
then then
# If the input was a FIFO we need to read from it and push into the new FIFOs # If the input was a FIFO we need to read from it and push into the new FIFOs
cat "$INPUTFILE" | tee $(for br in $OP_BITRATES; do echo "$TMPDIR/hlsc.encode.$MYPID.$br"; done) > /dev/null & cat "$INPUTFILE" | tee $(for br in $OP_BITRATES; do echo "$TMPDIR/hlsc.encode.$MYPID.$br"; done) > /dev/null &
TEE_PID=$! TEE_PID=$!
fi fi
   
if [ "$NO_FORK" == "0" ] || [ "$LIVE_STREAM" == "1" ] if [ "$NO_FORK" == "0" ] || [ "$LIVE_STREAM" == "1" ]
then then
# Monitor the background tasks for completion # Monitor the background tasks for completion
echo "All transcoding processes started, awaiting completion" echo "All transcoding processes started, awaiting completion"
awaitCompletion awaitCompletion
fi fi
   
if [ "$IS_FIFO" == "1" ] if [ "$IS_FIFO" == "1" ]
then then
for br in $OP_BITRATES for br in $OP_BITRATES
do do
rm -f "$TMPDIR/hlsc.encode.$MYPID.$br"; rm -f "$TMPDIR/hlsc.encode.$MYPID.$br";
done done
# If we were interrupted, tee may still be running # If we were interrupted, tee may still be running
kill $TEE_PID 2> /dev/null kill $TEE_PID 2> /dev/null
fi fi
   
else else
   
OUTPUT_DIRECTORY+=$SEGMENT_DIRECTORY OUTPUT_DIRECTORY+=$SEGMENT_DIRECTORY
# No bitrate specified # No bitrate specified
   
# Finally, lets build the output filename format # Finally, lets build the output filename format
OUT_NAME="${SEGMENT_PREFIX}_%05d.ts" OUT_NAME="${SEGMENT_PREFIX}_%05d.ts"
PLAYLIST_NAME="$OUTPUT_DIRECTORY/${PLAYLIST_PREFIX}.m3u8" PLAYLIST_NAME="$OUTPUT_DIRECTORY/${PLAYLIST_PREFIX}.m3u8"
   
echo "Generating HLS segments - this may take some time" echo "Generating HLS segments - this may take some time"
   
# Processing Starts # Processing Starts
   
createStream "$PLAYLIST_NAME" "$OUT_NAME" "$BITRATE" "$INPUTFILE" createStream "$PLAYLIST_NAME" "$OUT_NAME" "$BITRATE" "$INPUTFILE"
   
   
fi fi