1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
|
#!/bin/bash
#
# externremux.sh - sample remux script using mencoder for remuxing.
#
# Install this script as VDRCONFDIR/plugins/streamdev-server/externremux.sh
#
# The parameter QUALITY selects the default remux parameters. Adjust
# to your needs and point your web browser to http://servername:3000/ext/
# To select different remux parameters on the fly, insert a semicolon
# followed by the name and value of the requested parameter, e.g:
# e.g. http://servername:3000/ext;QUALITY=WLAN11;VBR=512/
# The following parameters are recognized:
#
# PROG actual remux program
# VC video codec
# VBR video bitrate (kbit)
# VOPTS custom video options
# WIDTH scale video to width
# HEIGHT scale video to height
# FPS output frames per second
# AC audio codec
# ABR audio bitrate (kbit)
# AOPTS custom audio options
#
##########################################################################
### GENERAL CONFIG START
###
# Pick one of DSL1000/DSL2000/DSL3000/DSL6000/DSL16000/LAN10/WLAN11/WLAN54
QUALITY='DSL1000'
# Program used for logging (logging disabled if empty)
LOGGER=logger
# Path and name of FIFO
FIFO=/tmp/externremux-${RANDOM:-$$}
# Default remux program (cat/mencoder/ogg)
PROG=mencoder
# Use mono if $ABR is lower than this value
ABR_MONO=64
###
### GENERAL CONFIG END
### MENCODER CONFIG START
###
# mencoder binary
MENCODER=mencoder
# verbosity from all=-1 to all=9 (-msglevel ...)
MENCODER_MSGLEVEL=all=1
### video part
# Default video codec (e.g. lavc/x264/copy)
MENCODER_VC=lavc
# Default video options if lavc is used (-ovc lavc -lavcopts ...)
MENCODER_LAVC_VOPTS=vcodec=mpeg4
# Default video options if x264 is used (-ovc x264 -x264encopts ...)
MENCODER_X264_VOPTS=threads=auto
### audio part
# Audio language to use if several audio PIDs are available (-alang ...)
MENCODER_ALANG=eng
# Default audio codec (e.g. lavc/mp3lame/faac/copy)
MENCODER_AC=mp3lame
# Default audio options if lavc is used (-oac lavc -lavcopts ...)
MENCODER_LAVC_AOPTS=acodec=mp2
# Default audio options if mp3lame is used (-oac mp3lame -lameopts ...)
MENCODER_LAME_AOPTS=
# Default audio options if faac is used (-oac faac -faacopts ...)
MENCODER_FAAC_AOPTS=
###
### MENCODER CONFIG END
### OGG CONFIG START
###
# ffmpeg2theora binary
OGG=ffmpeg2theora
# speedlevel - lower value gives better quality but is slower (0..2)
OGG_SPEED=1
# videoquality - higher value gives better quality but is slower (0..10)
OGG_VQUALITY=0
# audioquality - higher value gives better quality but is slower (0..10)
OGG_AQUALITY=0
# aspect ratio used for scaling if only one of HEIGHT/WIDTH given (16/9 or 4/3)
OGG_ASPECT='4 / 3'
###
### OGG CONFIG END
##########################################################################
function hasOpt { echo "$1" | grep -q "\b${2}\b"; }
# $1: concatenation of already set option=value pairs
# $2-$n: option=value pairs to be echod if the option is not present in $1
function addOpts
{
local opts="$1"
shift
while [ $# -gt 0 ]; do
hasOpt "$opts" ${1%%=*}= || echo $1
shift
done
}
function isNumeric() { echo "$@" | grep -q '^-\?[0-9]\{1,\}$'; }
function remux_cat
{
startReply
exec 3<&0
cat 0<&3 >"$FIFO" &
}
function remux_mencoder
{
# lavc may be used for video and audio
LAVCOPTS=()
# Assemble video options
VC=${REMUX_PARAM_VC:-$MENCODER_VC}
VOPTS=${REMUX_PARAM_VOPTS}
FPS=${REMUX_PARAM_FPS:-$FPS}
# if only one of HEIGHT/WIDTH given:
# have mencoder calculate other value depending on actual aspect ratio
if [ "$HEIGHT" -a -z "$WIDTH" ]; then
WIDTH=-3
elif [ "$WIDTH" -a -z "$HEIGHT" ]; then
HEIGHT=-3
fi
case "$VC" in
lavc)
LAVCOPTS=(
${VOPTS}
$(IFS=$IFS:; addOpts "$VOPTS" $MENCODER_LAVC_VOPTS)
${VBR:+vbitrate=$VBR}
)
[ ${#LAVCOPTS[*]} -gt 0 ] && VOPTS=$(IFS=:; echo -lavcopts "${LAVCOPTS[*]}")
;;
x264)
isNumeric "$HEIGHT" && [ $HEIGHT -lt 0 -a $HEIGHT -gt -8 ] && ((HEIGHT-=8))
isNumeric "$WIDTH" && [ $WIDTH -lt 0 -a $WIDTH -gt -8 ] && ((WIDTH-=8))
X264OPTS=(
${VOPTS}
$(IFS=$IFS:; addOpts "$VOPTS" $MENCODER_X264_VOPTS)
${VBR:+bitrate=$VBR}
)
[ ${#X264OPTS[*]} -gt 0 ] && VOPTS=$(IFS=:; echo -x264encopts "${X264OPTS[*]}")
;;
copy)
VOPTS=
;;
*)
error "Unknown video codec '$VC'"
;;
esac
# Assemble audio options
AC=${REMUX_PARAM_AC:-$MENCODER_AC}
AOPTS=${REMUX_PARAM_AOPTS}
case "$AC" in
lavc)
LAVCOPTS=(
${LAVCOPTS[*]}
${AOPTS}
$(IFS=$IFS:; addOpts "$AOPTS" $MENCODER_LAVC_AOPTS)
${ABR:+abitrate=$ABR}
)
[ ${#LAVCOPTS[*]} -gt 0 ] && AOPTS=$(IFS=:; echo -lavcopts "${LAVCOPTS[*]}")
# lavc used for video and audio decoding - wipe out VOPTS as video options became part of AOPTS
[ "$VC" = lavc ] && VOPTS=
;;
mp3lame)
LAMEOPTS=(
${AOPTS}
$(isNumeric "${ABR}" && [ "${ABR}" -lt "$ABR_MONO" ] && ! hasOpt "${AOPTS}" mode ] && echo 'mode=3')
$(IFS=$IFS:; addOpts "$AOPTS" $MENCODER_LAME_AOPTS)
${ABR:+preset=$ABR}
)
[ ${#LAMEOPTS[*]} -gt 0 ] && AOPTS=$(IFS=:; echo -lameopts "${LAMEOPTS[*]}")
;;
faac)
FAACOPTS=(
${AOPTS}
$(IFS=$IFS:; addOpts "$AOPTS" $MENCODER_FAAC_AOPTS)
${ABR:+br=$ABR}
)
[ ${#FAACOPTS[*]} -gt 0 ] && AOPTS=$(IFS=:; echo -faacopts "${FAACOPTS[*]}")
;;
copy)
AOPTS=
;;
*)
error "Unknown audio codec '$AC'"
;;
esac
startReply
exec 3<&0
echo $MENCODER \
${MENCODER_MSGLEVEL:+-msglevel $MENCODER_MSGLEVEL} \
-ovc $VC $VOPTS \
-oac $AC $AOPTS \
${MENCODER_ALANG:+-alang $MENCODER_ALANG} \
${WIDTH:+-vf scale=$WIDTH:$HEIGHT -zoom} \
${FPS:+-ofps $FPS} \
-o "$FIFO" -- - >&2
$MENCODER \
${MENCODER_MSGLEVEL:+-msglevel $MENCODER_MSGLEVEL} \
-ovc $VC $VOPTS \
-oac $AC $AOPTS \
${MENCODER_ALANG:+-alang $MENCODER_ALANG} \
${WIDTH:+-vf scale=$WIDTH:$HEIGHT -zoom} \
${FPS:+-ofps $FPS} \
-o "$FIFO" -- - 0<&3 >/dev/null &
}
function remux_ogg
{
VOPTS=${REMUX_PARAM_VOPTS//[:=]/ }
AOPTS=${REMUX_PARAM_AOPTS//[:=]/ }
# if only one of HEIGHT/WIDTH given:
# calculate other value depending on configured aspect ratio
# trim to multiple of 8
if [ "$HEIGHT" -a -z "$WIDTH" ]; then
WIDTH=$((HEIGHT * $OGG_ASPECT / 8 * 8))
elif [ "$WIDTH" -a -z "$HEIGHT" ]; then
HEIGHT=$(($WIDTH * $( echo $OGG_ASPECT | sed 's#^\([0-9]\+\) */ *\([0-9]\+\)$#\2 / \1#') / 8 * 8))
fi
OGGOPTS=(
${VOPTS}
${VBR:+--videobitrate $VBR}
$(hasOpt "${VOPTS}" videoquality || echo "--videoquality $OGG_VQUALITY")
$(hasOpt "${VOPTS}" speedlevel || echo "--speedlevel $OGG_SPEED")
${AOPTS}
${ABR:+--audiobitrate $ABR}
$(isNumeric "${ABR}" && [ "${ABR}" -lt "$ABR_MONO" ] && ! hasOpt "${AOPTS}" channels ] && echo '--channels 1')
$(hasOpt "${AOPTS}" audioquality || echo "--audioquality $OGG_AQUALITY")
$(hasOpt "${AOPTS}" audiostream || echo '--audiostream 1')
)
startReply
exec 3<&0
echo $OGG --format ts \
${OGGOPTS[*]} \
${WIDTH:+--width $WIDTH --height $HEIGHT} \
--title "VDR Streamdev: ${REMUX_CHANNEL_NAME}" \
--output "$FIFO" -- - 0<&3 >&2
$OGG --format ts \
${OGGOPTS[*]} \
${WIDTH:+--width $WIDTH --height $HEIGHT} \
--title "VDR Streamdev: ${REMUX_CHANNEL_NAME}" \
--output "$FIFO" -- - 0<&3 >/dev/null &
}
function error
{
if [ "$SERVER_PROTOCOL" = HTTP ]; then
echo -ne "Content-type: text/plain\r\n"
echo -ne '\r\n'
echo "$*"
fi
echo "$*" >&2
exit 1
}
function startReply
{
if [ "$SERVER_PROTOCOL" = HTTP ]; then
# send content-type and custom headers
echo -ne "Content-type: ${CONTENTTYPE}\r\n"
for header in "${HEADER[@]}"; do echo -ne "$header\r\n"; done
echo -ne '\r\n'
# abort after headers
[ "$REQUEST_METHOD" = HEAD ] && exit 0
fi
# create FIFO and read from it in the background
mkfifo "$FIFO"
trap "trap '' EXIT HUP INT TERM ABRT PIPE CHLD; kill -INT 0; sleep 1; fuser -k '$FIFO'; rm '$FIFO'" EXIT HUP INT TERM ABRT PIPE CHLD
cat "$FIFO" <&- &
}
HEADER=()
[ "$LOGGER" ] && exec 2> >($LOGGER -t "vdr: [$$] ${0##*/}" 2>&-)
# set default content-types
case "$REMUX_VPID" in
''|0|1) CONTENTTYPE='audio/mpeg';;
*) CONTENTTYPE='video/mpeg';;
esac
QUALITY=${REMUX_PARAM_QUALITY:-$QUALITY}
case "$QUALITY" in
DSL1000|dsl1000) VBR=96; ABR=16; WIDTH=160;;
DSL2000|dsl2000) VBR=128; ABR=16; WIDTH=160;;
DSL3000|dsl3000) VBR=256; ABR=16; WIDTH=320;;
DSL6000|dsl6000) VBR=378; ABR=32; WIDTH=320;;
DSL16000|dsl16000) VBR=512; ABR=32; WIDTH=480;;
WLAN11|wlan11) VBR=768; ABR=64; WIDTH=640;;
WLAN54|wlan54) VBR=2048; ABR=128; WIDTH=;;
LAN10|lan10) VBR=4096; ABR=; WIDTH=;;
*) error "Unknown quality '$QUALITY'";;
esac
ABR=${REMUX_PARAM_ABR:-$ABR}
VBR=${REMUX_PARAM_VBR:-$VBR}
WIDTH=${REMUX_PARAM_WIDTH:-$WIDTH}
HEIGHT=${REMUX_PARAM_HEIGHT:-$HEIGHT}
PROG=${REMUX_PARAM_PROG:-$PROG}
case "$PROG" in
cat) remux_cat;;
mencoder) remux_mencoder;;
ogg) remux_ogg;;
*) error "Unknown remuxer '$PROG'";;
esac
set -o monitor
wait
|