Externremux.sh

Aus VDR Wiki
(Unterschied zwischen Versionen)
Wechseln zu: Navigation, Suche
K (neues extremux script hinzugefügt)
 
(Eine dazwischenliegende Version von einem Benutzer wird nicht angezeigt)
Zeile 8: Zeile 8:
 
Die Übergabe von Parametern zur Qualitätssteuerung ist in der URL möglich (bei Verwendung untenstehender externremux.sh (2):
 
Die Übergabe von Parametern zur Qualitätssteuerung ist in der URL möglich (bei Verwendung untenstehender externremux.sh (2):
  
<nowiki>http://vdr-ip-or-host:3000/EXTERN;DSL3500/1</nowiki>
+
<nowiki>http://vdr-ip-or-host:3000/EXT;DSL3500/1</nowiki>
  
 
Das [[streamdev-plugin]] ruft dann das Skript [[externremux.sh]]. Der Datenstrom des gewählten Senders steht dem Skript über Standard-Eingabe (stdin) zur Verfügung. Der manipulierte Datenstrom muss über Standard-Ausgabe (stdout) an das Plugin zurückgegeben werden.
 
Das [[streamdev-plugin]] ruft dann das Skript [[externremux.sh]]. Der Datenstrom des gewählten Senders steht dem Skript über Standard-Eingabe (stdin) zur Verfügung. Der manipulierte Datenstrom muss über Standard-Ausgabe (stdout) an das Plugin zurückgegeben werden.
Zeile 409: Zeile 409:
 
</pre>
 
</pre>
 
}}
 
}}
 +
 +
=== externremux.sh mit ffmpeg / vlc / mencoder /ogg ===
  
 
[[Kategorie:Skripte]][[Kategorie:Streaming]]
 
[[Kategorie:Skripte]][[Kategorie:Streaming]]
 +
 +
Mit dieser Weiterentwicklung (Quelle: [http://www.vdr-portal.de/board16-video-disk-recorder/board55-vdr-plugins/125735-neue-version-externremux-sh-vlc-ffmpeg vdr-portal]) kann ffmpeg, vlc, ogg oder mencoder für das Traskodieren verwendet werden.
 +
{{Box Datei|$PATH/externremux.sh|
 +
<pre>
 +
#!/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='WLAN11'
 +
# 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/ffmpeg)
 +
PROG=vlc
 +
# Use mono if $ABR is lower than this value
 +
ABR_MONO=64
 +
###
 +
### GENERAL CONFIG END
 +
 +
### VLC CONFIG START
 +
###
 +
VLC=vlc
 +
### video part
 +
# Default video codec (e.g. mp4v/x264/theo)
 +
VLC_VC=x264
 +
# Default Encoder Options for x264 encoder
 +
VLC_X264_VOPTS=me=dia,subme=1,analyse=none,bframes=1,b-adapt=none,chroma-me=none,merange=12,cabac=none
 +
#VLC_X264_VOPTS=vbv-maxrate=512,vbv-minrate=512,qcomp=0,ratetol=0,keyint=20
 +
# Default Encoder Options for theora encoder
 +
VLC_THEO_VOPTS=quality=5
 +
# Default ffmpeg Encoder Options for VP80 encoder
 +
VLC_VP80_VOPTS=crf=25,qmin=4,qmax=43,passes=1
 +
#VLC_VP80_VOPTS=minrate=500K,maxrate=500K,passes=1
 +
#VLC_VP80_VOPTS=hurry-up
 +
### audio part
 +
# Default audio codec (e.g. mp4a/mpga/mp3/vorb)
 +
VLC_AC=mpga
 +
# Default Encoder Options for vorbis encoder
 +
#VLC_VORB_AOPTS=quality=1
 +
 +
###
 +
### VLC CONFIG END
 +
 +
### FFMPEG CONFIG START
 +
###
 +
# ffmpeg binary (ffmpeg/avconv)
 +
#FFMPEG=/opt/ffmpeg-git-20150115-64bit-static/ffmpeg
 +
FFMPEG=ffmpeg
 +
#FFMPEG=avconv
 +
# Default number of threads
 +
FFMPEG_THREADS=2
 +
### video part
 +
# Default video codec (e.g. lavc/x264/copy)
 +
FFMPEG_VC=x264
 +
# Default video options if libx264 is used
 +
FFMPEG_X264_VOPTS='-bufsize 1024k -q:v 20'
 +
# Default video options if libtheora is used
 +
FFMPEG_THEORA_VOPTS=''
 +
### audio part
 +
# Default audio codec (e.g. lavc/mp3lame/faac/copy)
 +
FFMPEG_AC=libvorbis
 +
# Default audio options if libmp3lame is used
 +
FFMPEG_LAME_AOPTS='-ar 44100 -ac 2 -async 50'
 +
FFMPEG_FLAC_AOPTS=''
 +
###
 +
### FFMPEG CONFIG END
 +
 +
### MENCODER CONFIG START
 +
###
 +
# mencoder binary
 +
MENCODER=mencoder
 +
# verbosity from all=-1 to all=9 (-msglevel ...)
 +
MENCODER_MSGLEVEL=all=3
 +
### video part
 +
# Default video codec (e.g. lavc/x264/copy)
 +
MENCODER_VC=x264
 +
# 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=subq=4:bframes=2:b_pyramid=normal:weight_b:vbv_bufsize=600
 +
### audio part
 +
# Audio language to use if several audio PIDs are available (-alang ...)
 +
MENCODER_ALANG=ger
 +
# 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 ...) - cbr
 +
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='16 / 9'
 +
###
 +
### 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 check_muxer
 +
{
 +
local mux = $1
 +
local vc=$2
 +
local ac=$3
 +
local err=false
 +
case "$mux"
 +
in
 +
mp4|mov|3gp)
 +
case "$vc"
 +
in
 +
mp4v|m4v|DIV1|div1|DIVX|divx|DX50|dx50|XVID|XviD|xvid|FMP4|fmp4|3IV2|3iv2|BLZ0)
 +
# vc looks ok
 +
;;
 +
 +
*)
 +
# unsuppored vc for this muxer
 +
err=true
 +
;;
 +
esac
 +
;;
 +
 +
*)
 +
err=true;
 +
;;
 +
esac
 +
}
 +
 +
function remux_vlc
 +
{
 +
# if only one of HEIGHT/WIDTH given:
 +
# have mencoder calculate other value depending on actual aspect ratio
 +
if [ "$HEIGHT" -a -z "$WIDTH" ]; then
 +
  WIDTH=0
 +
elif [ "$WIDTH" -a -z "$HEIGHT" ]; then
 +
  HEIGHT=0
 +
fi
 +
 +
        # Assemble video options
 +
        VC=${REMUX_PARAM_VC:-$VLC_VC}
 +
        VOPTS=${REMUX_PARAM_VOPTS}
 +
        FPS=${REMUX_PARAM_FPS:-$FPS}
 +
 +
case "$REMUX_VPID" in
 +
        ''|0|1) VC=none; VBR='';;
 +
esac
 +
 +
case "$VC" in
 +
none)
 +
VOPTS=""
 +
MUXER=raw
 +
;;
 +
mpgv|mp1v|mp2v)
 +
VOPTS=""
 +
MUXER=ts
 +
;;
 +
mp4v|m4v|DIVX|divx|DX50|dx50|XVID|XviD|xvid|FMP4|fmp4|3IV2|3iv2|BLZ0|DXGM|HDX4|hdx4|M4S2|m4s2|MP4S|mp4s|RMP4|SEDG|SMP4|UMP4|WV1F|XVIX)
 +
VOPTS=""
 +
MUXER=ts
 +
;;
 +
DIV1|div1|DIV2|div2|DIV3|div3)
 +
VOPTS=""
 +
MUXER=ts
 +
;;
 +
                x264)
 +
X264EOPTS=(
 +
${VOPTS}
 +
$(IFS=$IFS:; addOpts "$VOPTS" $VLC_X264_VOPTS)
 +
)
 +
[ ${#X264EOPTS[*]} -gt 0 ] && VOPTS=$(IFS=,; echo x264{"${X264EOPTS[*]}"})
 +
MUXER=ts
 +
;;
 +
theo)
 +
THEORAEOPTS=(
 +
${VOPTS}
 +
$(IFS=$IFS:; addOpts "$VOPTS" $VLC_THEO_VOPTS)
 +
)
 +
[ ${#THEORAEOPTS[*]} -gt 0 ] && VOPTS=$(IFS=,; echo theora{"${THEORAEOPTS[*]}"})
 +
MUXER=ogg
 +
CONTENTTYPE='video/ogg'
 +
;;
 +
drac)
 +
VOPTS=""
 +
MUXER=ts
 +
;;
 +
VP80)
 +
VP80EOPTS=(
 +
${VOPTS}
 +
"codec=libvpx"
 +
$(IFS=$IFS:; addOpts "$VOPTS" $VLC_VP80_VOPTS)
 +
)
 +
[ ${#VP80EOPTS[*]} -gt 0 ] && VOPTS=$(IFS=,; echo ffmpeg{"${VP80EOPTS[*]}"})
 +
MUXER=webm
 +
;;
 +
*)
 +
                        error "Unknown video codec '$VC'"
 +
                        ;;
 +
esac
 +
 +
# Assemble audio options
 +
AC=${REMUX_PARAM_AC:-$VLC_AC}
 +
AOPTS=${REMUX_PARAM_AOPTS}
 +
ACH=2
 +
isNumeric "${ABR}" && [ "${ABR}" -lt "$ABR_MONO" ] && ! hasOpt "${AOPTS}" channels ] && ACH=1
 +
 +
case "$AC" in
 +
mp4a|aac)
 +
AOPTS="avcodec{codec=libfdk_aac}"
 +
[ "$VC" == "none" ] && MUXER=m4a && CONTENTTYPE='audio/mp4'
 +
;;
 +
mpga)
 +
AOPTS=""
 +
;;
 +
mp3)
 +
AOPTS=""
 +
[ "$VC" == "none" ] && MUXER=dummy
 +
;;
 +
vorb)
 +
VORBISEOPTS=(
 +
${AOPTS}
 +
"codec=libvorbis"
 +
$(IFS=$IFS:; addOpts "$AOPTS" $VLC_VORB_AOPTS)
 +
)
 +
#[ ${#VORBISEOPTS[*]} -gt 0 ] && AOPTS=$(IFS=,; echo vorbis{"${VORBISEOPTS[*]}"})
 +
[ ${#VORBISEOPTS[*]} -gt 0 ] && AOPTS=$(IFS=,; echo avcodec{"${VORBISEOPTS[*]}"})
 +
[ "$VC" == "none" ] && MUXER=ogg && CONTENTTYPE='audio/ogg'
 +
;;
 +
*)
 +
error "Unknown audio codec '$AC'"
 +
;;
 +
        esac
 +
 +
#[ -z "$MUXER" ] && MUXER=raw
 +
[ "$MUXER" = "webm" ] && MUXER=ffmpeg{mux=webm}
 +
# set APID when needed
 +
read -a APID_ARRAY <<< "$REMUX_APID"
 +
[ ${#APID_ARRAY[*]} -eq 1 ] && APID=${APID_ARRAY[0]}
 +
 +
startReply
 +
        exec 3<&0
 +
 +
echo $VLC -I dummy -v --no-interact --ignore-config --no-fb-tty --no-sout-display --no-sout-display-audio ${APID:+--audio-track-id $APID} \
 +
--sout "#transcode{vcodec=$VC,${VOPTS:+venc=$VOPTS,}${VBR:+vb=$VBR,}${WIDTH:+scale=1,width=$WIDTH,height=$HEIGHT,}${FPS:+fps=$FPS,}deinterlace,hurry-up, \
 +
acodec=$AC,${AOPTS:+aenc=$AOPTS,}ab=$ABR,channels=$ACH}:std{access=file,mux=$MUXER,name=\"${REMUX_CHANNEL_NAME}\",description=\"Powered by VDR streamdev $SERVER_SOFTWARE\",dst=$FIFO}" fd://0 vlc://quit >&2
 +
 +
$VLC -I dummy -vv --no-interact --ignore-config --no-fb-tty --no-sout-display --no-sout-display-audio ${APID:+--audio-track-id $APID} \
 +
--sout "#transcode{vcodec=$VC,${VOPTS:+venc=$VOPTS,}${VBR:+vb=$VBR,}${WIDTH:+scale=1,width=$WIDTH,height=$HEIGHT,}${FPS:+fps=$FPS,}deinterlace,hurry-up, \
 +
acodec=$AC,${AOPTS:+aenc=$AOPTS,}ab=$ABR,channels=$ACH}:std{access=file,mux=$MUXER,name=\"${REMUX_CHANNEL_NAME}\",description=\"Powered by VDR streamdev $SERVER_SOFTWARE\",dst=$FIFO}" fd://0 vlc://quit 0<&3 >/dev/null &
 +
 +
# echo $VLC --intf=dummy -v --no-interact \
 +
# --sout-transcode-vcodec=$VC \
 +
# ${VOPTS:+--sout-transcode-venc=$VOPTS} \
 +
# ${VBR:+--sout-transcode-vb=$VBR} \
 +
# ${WIDTH:+--sout-transcode-scale=1 --sout-transcode-width=$WIDTH --sout-transcode-height=$HEIGHT} \
 +
# ${FPS:+--sout-transcode-fps=$FPS} \
 +
# --sout-transcode-deinterlace \
 +
# --sout-transcode-hurry-up \
 +
# --sout-transcode-acodec=$AC \
 +
# ${AOPTS:+--sout-transcode-aenc=$AOPTS} \
 +
# --sout-transcode-ab=$ABR \
 +
# --sout-transcode-channels=$ACHAN \
 +
# --sout-standard-access=file \
 +
# --sout-standard-mux=$MUXER \
 +
# --sout-standard-dst=$FIFO \
 +
# fd://0 vlc://quit >&2
 +
 +
# $VLC --intf=dummy -v --no-interact \
 +
# --sout-transcode-vcodec=$VC \
 +
# ${VOPTS:+--sout-transcode-venc=$VOPTS} \
 +
# ${VBR:+--sout-transcode-vb=$VBR} \
 +
# ${WIDTH:+--sout-transcode-scale=1 --sout-transcode-width=$WIDTH --sout-transcode-height=$HEIGHT} \
 +
# ${FPS:+--sout-transcode-fps=$FPS} \
 +
# --sout-transcode-deinterlace \
 +
# --sout-transcode-hurry-up \
 +
# --sout-transcode-acodec=$AC \
 +
# ${AOPTS:+--sout-transcode-aenc=$AOPTS} \
 +
# --sout-transcode-ab=$ABR \
 +
# --sout-transcode-channels=$ACHAN \
 +
# --sout-standard-access=file \
 +
# --sout-standard-mux=$MUXER \
 +
# --sout-standard-dst=$FIFO \
 +
# fd://0 vlc://quit 0<&3 >/dev/null &
 +
 +
}
 +
 +
function remux_ffmpeg
 +
{
 +
# lavc may be used for video and audio
 +
LAVCOPTS=()
 +
FFMPEG_THREADS=${REMUX_PARAM_THREADS:-$FFMPEG_THREADS}
 +
 +
# Assemble video options
 +
VC=${REMUX_PARAM_VC:-$FFMPEG_VC}
 +
VOPTS=${REMUX_PARAM_VOPTS}
 +
FPS=${REMUX_PARAM_FPS:-$FPS}
 +
 +
# 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
 +
 +
VSIZE="scale=iw*min($WIDTH/iw\,$HEIGHT/ih):ih*min($WIDTH/iw\,$HEIGHT/ih), pad=$WIDTH:$HEIGHT:($WIDTH-iw*min($WIDTH/iw\,$HEIGHT/ih))/2:($HEIGHT-ih*min($WIDTH/iw\,$HEIGHT/ih))/2"
 +
 +
case "$VC" in
 +
libx264)
 +
VOPTS="${VOPTS:-$FFMPEG_X264_VOPTS}"
 +
VOPTS="-maxrate ${VBR}k ${VOPTS}"
 +
;;
 +
libtheora)
 +
VOPTS="${VOPTS:-$FFMPEG_THEORA_VOPTS}"
 +
VOPTS="-qscale:v 3"
 +
;;
 +
*)
 +
error "Unknown video codec '$VC'"
 +
;;
 +
esac
 +
 +
# Assemble audio options
 +
AC=${REMUX_PARAM_AC:-$FFMPEG_AC}
 +
AOPTS=${REMUX_PARAM_AOPTS}
 +
case "$AC" in
 +
libmp3lame)
 +
AOPTS="${AOPTS:-$FFMPEG_LAME_AOPTS}"
 +
AOPTS="-b:a ${ABR}k ${AOPTS}"
 +
;;
 +
libvorbis)
 +
AOPTS="-qscale:a 3"
 +
;;
 +
*)
 +
error "Unknown audio codec '$AC'"
 +
;;
 +
esac
 +
 +
 +
startReply "NOFIFO"
 +
exec 3<&0
 +
echo $FFMPEG \
 +
-v 9 -loglevel 99 \
 +
-i - \
 +
-threads $FFMPEG_THREADS \
 +
-filter:v \"${VSIZE}, yadif\" \
 +
-codec:v $VC $VOPTS \
 +
${FPS:+-framerate $FPS} \
 +
-codec:a $AC $AOPTS \
 +
-f ogg pipe:1 >&2
 +
$FFMPEG \
 +
-v 9 -loglevel 99 \
 +
-i - \
 +
-threads $FFMPEG_THREADS \
 +
-filter:v "${VSIZE}, yadif" \
 +
-codec:v $VC $VOPTS \
 +
${FPS:+-framerate $FPS} \
 +
-codec:a $AC $AOPTS \
 +
-f ogg pipe:1 0<&3 >/dev/null &
 +
}
 +
 +
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:vbv_maxrate=$((VBR+50))}
 +
)
 +
[ ${#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 \
 +
-v -v -v \
 +
${MENCODER_MSGLEVEL:+-msglevel $MENCODER_MSGLEVEL} \
 +
-ovc $VC $VOPTS \
 +
-oac $AC $AOPTS \
 +
${MENCODER_ALANG:+-alang $MENCODER_ALANG} \
 +
${WIDTH:+-vf scale=$WIDTH:$HEIGHT} \
 +
${FPS:+-ofps $FPS} \
 +
-o "$FIFO" -- - >&2
 +
$MENCODER \
 +
-v -v -v \
 +
${MENCODER_MSGLEVEL:+-msglevel $MENCODER_MSGLEVEL} \
 +
-ovc $VC $VOPTS \
 +
-oac $AC $AOPTS \
 +
${MENCODER_ALANG:+-alang $MENCODER_ALANG} \
 +
${WIDTH:+-vf scale=$WIDTH:$HEIGHT} \
 +
${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
 +
if [ "$1" != "NOFIFO" ];
 +
then
 +
# 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" <&- &
 +
else
 +
trap "trap '' EXIT HUP INT TERM ABRT PIPE CHLD; kill -INT 0" EXIT HUP INT TERM ABRT PIPE CHLD
 +
fi
 +
}
 +
 +
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=;;
 +
WLAN54|wlan54)          VBR=2048; ABR=128; WIDTH=;;
 +
LAN10|lan10)            VBR=4096; ABR=;    WIDTH=;;
 +
PHONE|HANDY|phone|handy) VBR=768; ABR=96; WIDTH=640; PROG=vlc; VLC_VC=mp4v; VLC_AC=mp3;;
 +
UMTS|umts)              VBR=150; ABR=16; WIDTH=320;;
 +
BEST|best)              PROG=ogg; OGG_VQUALITY=2; VBR=1000; ABR=100; WIDTH=520;;
 +
#  WIDTH=576
 +
*)                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;;
 +
ffmpeg)  remux_ffmpeg;;
 +
vlc)      remux_vlc;;
 +
*)        error "Unknown remuxer '$PROG'";;
 +
esac
 +
 +
set -o monitor
 +
wait
 +
</pre>
 +
}}

Aktuelle Version vom 15. Februar 2015, 18:01 Uhr

Inhaltsverzeichnis

[Bearbeiten] Beschreibung

Der HTTP-Server des streamdev-plugins erlaubt es den Datenstrom eines Senders vor dem Versenden zu manipulieren. Um von dieser Möglichkeit Gebrauch zu machen, muss der Stream über folgende Adresse abgerufen werden:

http://vdr-ip-or-host:3000/EXT/1

Die 3000 steht für den im streamdev-plugin Setup eingestellten Port des HTTP-Servers. Die 1 steht für Kanal 1 gemäß der channels.conf. Die Übergabe von Parametern zur Qualitätssteuerung ist in der URL möglich (bei Verwendung untenstehender externremux.sh (2):

http://vdr-ip-or-host:3000/EXT;DSL3500/1

Das streamdev-plugin ruft dann das Skript externremux.sh. Der Datenstrom des gewählten Senders steht dem Skript über Standard-Eingabe (stdin) zur Verfügung. Der manipulierte Datenstrom muss über Standard-Ausgabe (stdout) an das Plugin zurückgegeben werden.

U.a. kann man MPlayer / VLC media player als Client benutzen.

[Bearbeiten] Konfiguration

Das streamdev-plugin muss installiert und der HTTP-Server des Plugins aktiviert sein.

Um viele Fehler bei der externremux.sh zu umgehen (da untenstehende Beispiele bei der aktuellen vdr-Version (1.7.18), bzw. streamdev-Server (0.5.1) nicht funktionieren), sollte die Beispiel-Config aus /usr/share/doc/vdr-plugin-streamdev-server/examples/externremux.sh.gz kopiert werden, zB: in den vdr-Plugins-Ordner:

gunzip /usr/share/doc/vdr-plugin-streamdev-server/examples/externremux.sh.gz -c > /etc/vdr/plugins/externremux.sh

Die externremux.sh muss für den vdr-user les- und ausführbar sein:

chown vdruser:vdrgroup externremux.sh
chmod 755 externremux.sh

Auch das Verzeichnis in dem die externremux.sh liegt muss den Zugriff für den VDR-Benutzer zulassen, das Verzeichnis /etc/vdr/plugins/ ist es im Normalfall.

Anschließend externremux.sh nun in den streamdev-server Aufruf einzubinden.


[Bearbeiten] Distributions-spezifisch

Je nach Distribution wird die Übergabe, an das Plugin unterschiedlich erfolgen.

[Bearbeiten] Gentoo

Bei gentoo ist es folgende Konfigurations-Datei.

Datei
/etc/conf.d/vdr.streamdev-server
_EXTRAOPTS="--remux=/home/vdr/externremux.sh"


zumindest bei Gen2VDR beta3 muß es PLUGIN_PARAMETERS="--remux=/home/vdr/externremux.sh" heißen


Für streamdev 0.5.x

STREAMDEV_REMUX_SCRIPT="/home/vdr/externremux.sh"

Außerdem müssen alte Skripte so beginnen:

echo -ne 'Content-type: video/mpeg\r\n'
echo -ne '\r\n'

[Bearbeiten] Debian / C't-VDR

Im StartUp-Skript von Debian/ctvdr werden die Plugin-Parameter über eine Datei namens plugin.<pluginname>.conf bestimmt. Diese Datei befindet sich unter /etc/vdr/plugins/. Folglich muss eine Datei in etwa so angelegt werden:

Datei
/etc/vdr/plugins/plugin.streamdev-server.conf
#
# Kommandozeilenparameter für das Streamdev-Plugin
#
# Mit dem Parameter -r oder --remux kann ein externer Remuxer aufgerufen werden.
# Die Streams können dann wie folgt den Remuxer inkludieren:
#    http://vdr-ip-or-host:3000/Extern/1
# Dabei ist IP und Port auf dem Client der Serveradresse anzupassen.
# Die letzte Zahl entspricht dem Kanal wie sie in der channels.conf aufgeführt werden.
#
-r /var/lib/vdr/plugins/streamdev/externremux.sh


Beim Debian-Paketen wird dies im vdr-Plugins Directory (zB: /etc/vdr/plugins/ ) das File plugin.streamdev-server.conf erstellt und darin die externremux.sh beim Start des streamdev-servers aufgerufen.

echo "-r /etc/vdr/plugins/externremux.sh" > /etc/vdr/plugins/plugin.streamdev-server.conf

oder auch

echo "-r=/etc/vdr/plugins/externremux.sh -a user:password" > /etc/vdr/plugins/plugin.streamdev-server.conf

Hier wird dann bei allen Zugriffen auf einen Channel Username und Password abgefragt die nicht in der streamdevhosts.conf Datei eingetragen sind.


Nun muss noch vdr neu gestartet werden, und fertig:

/etc/init.d/vdr restart

Natürlich sollte sich unter /var/lib/vdr/plugins/streamdev/ auch das Skript externremux.sh befinden. Man kann es aus den Beispielen kopieren (/usr/share/doc/vdr-plugin-streamdev-server/examples/externremux.sh) und den Pfad wie oben beschrieben ggf. anpassen.


[Bearbeiten] Ubuntu

Bei Ubuntu muss im externremux.sh #!/bin/sh durch #!/bin/bash ersetzt werden.

[Bearbeiten] Fedora

Bei Fedora werden die Plugin-Parameter für den streamdev-server in der Datei streamdev-server.conf im Ordner /etc/sysconfig/vdr-plugins.d/ festgelegt. Das Skript externremux.sh befindet sich schon mit im Paket vdr-streamdev-server und braucht nur noch angegeben werden. Dabei ist darauf zu achten, dass der Pfad je nach Architektur (lib/lib64) angepasst wird. Das folgende Beispiel ist für 64Bit:

Datei
/etc/sysconfig/vdr-plugins.d/streamdev-server.conf
# Configuration snippet for vdr-streamdev-server                          -*- sh -*-
#
# Add command line options to pass to the streamdev-server plugin to PLUGIN_OPTIONS.

PLUGIN_OPTIONS="--remux=/usr/lib64/vdr/bin/externremux.sh"


[Bearbeiten] Anwendungsbeispiele

[Bearbeiten] Streamen über schmalbandige Verbindungen

Mit Hilfe des streamdev-plugins und MEncoder kann man das laufende Fernsehprogramm auch über schmalbandige Verbindungen (z. B. DSL-Upload) streamen.

Dazu dient folgender MEncoder-Aufruf (im obigen Beispiel ergänzen):

 mencoder -ovc lavc -ffourcc XVID -oac lavc \
  -lavcopts  acodec=mp3:abitrate=32:vcodec=mpeg4:vbitrate=100 \
  -vf scale -zoom -xy 288 -channels 1 -o $FIFO - &>$OUTLOG

Bei Verwendung eines Routers zum Internet muss der Port 3000 auf den VDR-Server weitergeleitet werden. Zum Testen empfiehlt es sich, erst einmal im lokalen Netz die Funktionsfähigkeit zu überprüfen.

Der Clientrechner muss zudem die Erlaubnis haben, auf den Stream zugreifen zu dürfen. Dies wird in der Datei streamdevhosts.conf eingestellt. Die Zeile

0.0.0.0/0

gibt allen Rechnern im Internet die Erlaubnis, den Stream zu sehen. Diese Einstellung sollte nur in Verbindung mit einer Passwortabfrage im streamdev-plugin verwendet werden!

[Bearbeiten] externremux.sh (1)

In der Praxis kommt häufig das Programm MEncoder (Bestandteil von MPlayer) zum Einsatz. Dazu empfiehlt sich eines der folgenden Beispiele:

Datei
$PATH/externremux.sh
#!/bin/sh
umask 077
tmpdir=${TMPDIR-/tmp}/externremux-${RANDOM:-$$}
FIFO=$tmpdir/out.avi
OUTLOG=$tmpdir/out.log
mkdir -p $tmpdir || exit 1
mkfifo $FIFO
(cat $FIFO; rm -rf $tmpdir) &
mencoder <OPTIONEN> -o $FIFO -- - &>$OUTLOG


In die Datei out.log kann man bei Problemen rein schauen. Allerdings wird diese Datei beim Beenden von externremux.sh gelöscht. Um dies zu verhindern, bitte die Zeile "OUTLOG=" folgendermaßen ändern:

OUTLOG=/tmp/out.log

[Bearbeiten] externremux.sh (2)

Datei
$PATH/externremux.sh
#!/bin/sh
#
# externremux.sh

# CONFIG START
  TMP=/tmp/externremux-${RANDOM:-$$}
  STREAMQUALITY="DSL6000"
# CONFIG END

mkdir -p $TMP
mkfifo $TMP/out.avi
(trap "rm -rf $TMP" EXIT HUP INT TERM ABRT; cat $TMP/out.avi) &

case ${1:-$STREAMQUALITY} in
     "DSL1000") exec mencoder -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=100 \
		-oac mp3lame -lameopts preset=15:mode=3 -vf scale -zoom -xy 160 \
		-o $TMP/out.avi -- - &>$TMP/out.log ;;
     "DSL2000") exec mencoder -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=128 \
		-oac mp3lame -lameopts preset=15:mode=3 -vf scale -zoom -xy 160 \
		-o $TMP/out.avi -- - &>$TMP/out.log ;;
     "DSL3000") exec mencoder -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=250 \
		-oac mp3lame -lameopts preset=15:mode=3 -vf scale -zoom -xy 320 \
		-o $TMP/out.avi -- - &>$TMP/out.log ;;
     "DSL3500") exec mencoder -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=300 \
                -oac mp3lame -lameopts preset=15:mode=3 -vf scale -zoom -xy 320 \
                -o $TMP/out.avi -- - &>$TMP/out.log ;;
     "DSL6000") exec mencoder -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=350 \
		-oac mp3lame -lameopts preset=15:mode=3 -vf scale -zoom -xy 320 \
		-o $TMP/out.avi -- - &>$TMP/out.log ;;
     "DSL16000") exec mencoder -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=500 \
		-oac mp3lame -lameopts preset=15:mode=3 -vf scale -zoom -xy 480 \
		-o $TMP/out.avi -- - &>$TMP/out.log ;;
       "LAN10") exec mencoder -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=4096 \
		-oac mp3lame -lameopts preset=standard \
		-o $TMP/out.avi -- - &>$TMP/out.log ;;
      "WLAN11") exec mencoder -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=768 \
		-oac mp3lame -lameopts preset=standard -vf scale -zoom -xy 640 \
		-o $TMP/out.avi -- - &>$TMP/out.log ;;
      "WLAN54") exec mencoder -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=2048 \
		-oac mp3lame -lameopts preset=standard \
		-o $TMP/out.avi -- - &>$TMP/out.log ;;
	"IPAQ") exec mencoder -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=350 \
		-oac mp3lame -lameopts preset=15:mode=3 -vf scale -zoom -xy 320 \
		-o $TMP/out.avi -- - &>$TMP/out.log ;;
	"OGG") exec ffmpeg2theora --format ts \
		--videoquality 0 --videobitrate 300 --width 360 --height 360 --speedlevel 1 \
		--audioquality 0 --audiobitrate 37 --channels 1 --audiostream 0 \
		--title "VDR Live Stream" \
		--output $TMP/out.avi -- - &>$TMP/out.log ;;
        "COPY") exec mencoder -of mpeg -ovc copy -oac copy -mpegopts format=mpeg \
                -o $TMP/out.avi -- - &>$TMP/out.log ;;
	   *) touch $TMP/out.avi ;;
esac


Der Aufruf des Streams erfolgt hierbei für das Beispiel "DSL1000" über folgende Adresse:

http://vdr-ip-or-host:3000/Extern;DSL1000/1

[Bearbeiten] externremux.sh (3)

Datei
$PATH/externremux.sh
#!/bin/sh
#
# externremux.sh

# CONFIG START
  STREAMQUALITY="UMTS" # COPY, UMTS, DSL{1,2,3,6}000, DSL3500, LAN10, WLAN{11,54}, IPAQ
  RECDIR=/video0/
  TMP=/tmp/externremux-${RANDOM:-$$}
# CONFIG END

# DVD abspielen:
# /Extern;STREAMQUALITY:dvd:dvdfile

# Aufzeichnungen abspielen
# /Extern;STREAMQUALITY:rec:dirname to search
# /Extern;STREAMQUALITY:file:filename to search

mkdir -p $TMP
mkfifo $TMP/out.avi
(trap "rm -rf $TMP" EXIT HUP INT TERM ABRT; cat $TMP/out.avi) &

case ${1:0:1} in
     [A-Z]) IFS=: CMD=($1) IFS= ;;
         *) IFS=: CMD=("$STREAMQUALITY" $1) IFS= ;;
esac

case ${CMD[1]} in
     d*) RECORDING="dvd://${CMD[2]}"
         ;;
     r*) REC=$(eval find $RECDIR -name 20*.rec | grep -m 1 -i "${CMD[2]}")
         if [ -d "$REC" ] ; then
             RECORDING="$REC/[0-9][0-9][0-9].vdr"
         fi
         ;;
     f*) REC=$(eval find $RECDIR | grep -m 1 -i "${CMD[2]}")
         if [ -f "$REC" ] ; then
             RECORDING="$REC"
         fi
         ;;
esac

case $CMD in
	H265) exec mencoder $RECORDING -ovc x264  \
		-x264encopts bitrate=200:vbv_maxrate=250:vbv_bufsize=300:ratetol=0.1:threads=3 \
		-oac faac -faacopts br=32 -vf pp=ci,scale -zoom -xy 320 \
		-o $TMP/out.avi -- - &>$TMP/out.log ;;

    H264_150) exec mencoder $RECORDING -ovc x264 -srate 22050 \
		-x264encopts bitrate=150:vbv_maxrate=180:vbv_bufsize=300:ratetol=0.1:threads=3 \
		-oac mp3lame -lameopts cbr:br=16:q=2:mode=3 -vf pp=ci,scale -zoom -xy 320 \
		-o $TMP/out.avi -- - &>$TMP/out.log ;;

 H264_200_15) exec mencoder $RECORDING -ovc x264 -srate 22050 -ofps 15 \
		-x264encopts bitrate=200:vbv_maxrate=250:vbv_bufsize=300:ratetol=0.1:threads=3 \
		-oac mp3lame -lameopts cbr:br=16:q=2:mode=3 -vf pp=ci,scale -zoom -xy 320 \
		-o $TMP/out.avi -- - &>$TMP/out.log ;;

    H264_200) exec mencoder $RECORDING -ovc x264 -srate 22050 \
		-x264encopts bitrate=200:vbv_maxrate=250:vbv_bufsize=300:ratetol=0.1:threads=3 \
		-oac mp3lame -lameopts cbr:br=16:q=2:mode=3 -vf pp=ci,scale -zoom -xy 320 \
		-o $TMP/out.avi -- - &>$TMP/out.log ;;

    H264_250) exec mencoder $RECORDING -ovc x264 -srate 22050 \
		-x264encopts bitrate=250:vbv_maxrate=280:vbv_bufsize=300:ratetol=0.1:threads=3 \
		-oac mp3lame -lameopts cbr:br=16:q=2:mode=3 -vf pp=ci,scale -zoom -xy 320 \
		-o $TMP/out.avi -- - &>$TMP/out.log ;;
		
    H264_400) exec mencoder $RECORDING -ovc x264 -srate 22050 \
		-x264encopts bitrate=400:vbv_maxrate=450:vbv_bufsize=300:ratetol=0.1:threads=3 \
		-oac mp3lame -lameopts cbr:br=16:q=2:mode=3 -vf pp=ci,scale -zoom -xy 320 \
		-o $TMP/out.avi -- - &>$TMP/out.log ;;

    H264_500) exec mencoder $RECORDING -ovc x264 -srate 44100 \
		-x264encopts bitrate=500:vbv_maxrate=550:vbv_bufsize=600:ratetol=0.1:threads=3 \
		-oac mp3lame -lameopts cbr:br=16:q=2:mode=3 -vf pp=ci,scale -zoom -xy 480 \
		-o $TMP/out.avi -- - &>$TMP/out.log ;;

    H264_600) exec mencoder $RECORDING -ovc x264 -srate 44100 \
		-x264encopts bitrate=600:vbv_maxrate=650:vbv_bufsize=600:ratetol=0.1:threads=3 \
		-oac mp3lame -lameopts cbr:br=16:q=2:mode=3 -vf pp=ci,scale -zoom -xy 480 \
		-o $TMP/out.avi -- - &>$TMP/out.log ;;

    H264_800) exec mencoder $RECORDING -ovc x264 -srate 22050 \
		-x264encopts bitrate=800:vbv_maxrate=850:vbv_bufsize=300:ratetol=0.1:threads=3 \
		-oac mp3lame -lameopts cbr:br=16:q=2:mode=3 -vf pp=ci,scale -zoom -xy 320 \
		-o $TMP/out.avi -- - &>$TMP/out.log ;;

        UMTS) exec mencoder $RECORDING -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=150 \
                -oac mp3lame -lameopts preset=15:mode=3 -vf scale=320:240 \
                -o $TMP/out.avi -- - &>$TMP/out.log ;;

       HANDY) exec mencoder $RECORDING -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=350 \
                -oac mp3lame -lameopts preset=15:mode=3 -vf scale=320:240 \
                -o $TMP/out.avi -- - &>$TMP/out.log ;;

     DSL1000) exec mencoder $RECORDING -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=100 \
                -oac mp3lame -lameopts preset=15:mode=3 -vf scale=160:104 \
                -o $TMP/out.avi -- - &>$TMP/out.log ;;

     DSL2000) exec mencoder $RECORDING -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=128 \
                -oac mp3lame -lameopts preset=15:mode=3 -vf scale=160:104 \
                -o $TMP/out.avi -- - &>$TMP/out.log ;;

     DSL3000) exec mencoder $RECORDING -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=250 \
                -oac mp3lame -lameopts preset=15:mode=3 -vf scale=320:208 \
                -o $TMP/out.avi -- - &>$TMP/out.log ;;

     DSL3500) exec mencoder $RECORDING -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=300 \
                -oac mp3lame -lameopts preset=15:mode=3 -vf scale=320:208 \
                -o $TMP/out.avi -- - &>$TMP/out.log ;;

     DSL6000) exec mencoder $RECORDING -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=350 \
                -oac mp3lame -lameopts preset=15:mode=3 -vf scale=320:208 \
                -o $TMP/out.avi -- - &>$TMP/out.log ;;

    DSL16000) exec mencoder $RECORDING [21~-ovc lavc -lavcopts vcodec=mpeg4:vbitrate=500 \
		-oac mp3lame -lameopts preset=15:mode=3 -vf scale -zoom -xy 480 \
		-o $TMP/out.avi -- - &>$TMP/out.log ;;

       LAN10) exec mencoder $RECORDING -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=4096 \
                -oac mp3lame -lameopts preset=standard \
                -o $TMP/out.avi -- - &>$TMP/out.log ;;

      WLAN11) exec mencoder $RECORDING -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=768 \
                -oac mp3lame -lameopts preset=standard -vf scale=640:408 \
                -o $TMP/out.avi -- - &>$TMP/out.log ;;

      WLAN54) exec mencoder $RECORDING -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=2048 \
                -oac mp3lame -lameopts preset=standard \
                -o $TMP/out.avi -- - &>$TMP/out.log ;;

        IPAQ) exec mencoder $RECORDING -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=350 \
                -oac mp3lame -lameopts preset=15:mode=3 -vf scale=320:208 \
                -o $TMP/out.avi -- - &>$TMP/out.log ;;

        COPY) exec mencoder $RECORDING -of mpeg -ovc copy -oac copy -mpegopts format=mpeg \
                -o $TMP/out.avi -- - &>$TMP/out.log ;;
           *) touch $TMP/out.avi ;;
esac


[Bearbeiten] externremux.sh via ffmpeg in flv Container

Diese Version der externremux.sh (Quelle: vdr-portal) verwendet ffmpeg direkt und muxt den h264 Video- und MP3 Audiostream in einen FLV Container (abspielbar mit den meisten gängigen Software Playern und auch embedded Flash Player in Websites wie z.B dem JW-Player)

Datei
$PATH/externremux.sh
#!/bin/sh
#
# externremux.sh

### GENERAL CONFIG START
###
# Pick one of DSL/WLAN
QUALITY="DSL"
###
### GENERAL CONFIG END

case "$REMUX_VPID" in
''|0|1) CONTENTTYPE='audio/mpeg';;
*) CONTENTTYPE='video/mpeg';;
esac

QUALITY=${REMUX_PARAM_QUALITY:-$QUALITY}
case "$QUALITY" in
DSL|dsl) VBR=640K; ABR=64K; VSIZE=hd480;;
WLAN|wlan) VBR=3072K; ABR=128K; VSIZE=hd720;;
*) error "Unknown quality '$QUALITY'";;
esac
ABR=${REMUX_PARAM_ABR:-$ABR}
VBR=${REMUX_PARAM_VBR:-$VBR}
VSIZE=${REMUX_PARAM_VSIZE:-$VSIZE}

FPS=${REMUX_PARAM_FPS:-$FPS}

if [ "$SERVER_PROTOCOL" = HTTP ]; then
echo -ne "Content-type: ${CONTENTTYPE}\r\n"
echo -ne '\r\n'
# abort after headers
[ "$REQUEST_METHOD" = HEAD ] && exit 0
fi

ffmpeg -f mpegts -i - \
-filter:v yadif -filter:v scale=${VSIZE} \
-c:v libx264 -maxrate ${VBR} -bufsize 1024K \
-c:a libmp3lame -b:a ${ABR} -ar 44100 -ac 2 -async 50 \
${FPS:+-r $FPS} \
-f flv pipe:1


[Bearbeiten] externremux.sh mit ffmpeg / vlc / mencoder /ogg

Mit dieser Weiterentwicklung (Quelle: vdr-portal) kann ffmpeg, vlc, ogg oder mencoder für das Traskodieren verwendet werden.

Datei
$PATH/externremux.sh
#!/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='WLAN11'
# 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/ffmpeg)
PROG=vlc
# Use mono if $ABR is lower than this value
ABR_MONO=64
###
### GENERAL CONFIG END

### VLC CONFIG START
###
VLC=vlc
### video part
# Default video codec (e.g. mp4v/x264/theo)
VLC_VC=x264
# Default Encoder Options for x264 encoder
VLC_X264_VOPTS=me=dia,subme=1,analyse=none,bframes=1,b-adapt=none,chroma-me=none,merange=12,cabac=none
#VLC_X264_VOPTS=vbv-maxrate=512,vbv-minrate=512,qcomp=0,ratetol=0,keyint=20
# Default Encoder Options for theora encoder
VLC_THEO_VOPTS=quality=5
# Default ffmpeg Encoder Options for VP80 encoder
VLC_VP80_VOPTS=crf=25,qmin=4,qmax=43,passes=1
#VLC_VP80_VOPTS=minrate=500K,maxrate=500K,passes=1
#VLC_VP80_VOPTS=hurry-up
### audio part
# Default audio codec (e.g. mp4a/mpga/mp3/vorb)
VLC_AC=mpga
# Default Encoder Options for vorbis encoder
#VLC_VORB_AOPTS=quality=1

###
### VLC CONFIG END

### FFMPEG CONFIG START
###
# ffmpeg binary (ffmpeg/avconv)
#FFMPEG=/opt/ffmpeg-git-20150115-64bit-static/ffmpeg
FFMPEG=ffmpeg
#FFMPEG=avconv
# Default number of threads
FFMPEG_THREADS=2
### video part
# Default video codec (e.g. lavc/x264/copy)
FFMPEG_VC=x264
# Default video options if libx264 is used
FFMPEG_X264_VOPTS='-bufsize 1024k -q:v 20'
# Default video options if libtheora is used
FFMPEG_THEORA_VOPTS=''
### audio part
# Default audio codec (e.g. lavc/mp3lame/faac/copy)
FFMPEG_AC=libvorbis
# Default audio options if libmp3lame is used
FFMPEG_LAME_AOPTS='-ar 44100 -ac 2 -async 50'
FFMPEG_FLAC_AOPTS=''
###
### FFMPEG CONFIG END

### MENCODER CONFIG START
###
# mencoder binary
MENCODER=mencoder
# verbosity from all=-1 to all=9 (-msglevel ...)
MENCODER_MSGLEVEL=all=3
### video part
# Default video codec (e.g. lavc/x264/copy)
MENCODER_VC=x264
# 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=subq=4:bframes=2:b_pyramid=normal:weight_b:vbv_bufsize=600
### audio part
# Audio language to use if several audio PIDs are available (-alang ...)
MENCODER_ALANG=ger
# 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 ...) - cbr
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='16 / 9'
###
### 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 check_muxer
{
	local mux = $1
	local vc=$2
	local ac=$3
	local err=false
	case "$mux"
	in
		mp4|mov|3gp)
			case "$vc"
			in
				mp4v|m4v|DIV1|div1|DIVX|divx|DX50|dx50|XVID|XviD|xvid|FMP4|fmp4|3IV2|3iv2|BLZ0)
					# vc looks ok
					;;

				*)
					# unsuppored vc for this muxer
					err=true
					;;
			esac
			;;

		*)
			err=true;
			;;
	esac
}

function remux_vlc
{
	# if only one of HEIGHT/WIDTH given:
	# have mencoder calculate other value depending on actual aspect ratio
	if [ "$HEIGHT" -a -z "$WIDTH" ]; then
	  WIDTH=0
	elif [ "$WIDTH" -a -z "$HEIGHT" ]; then
	  HEIGHT=0
	fi

        # Assemble video options
        VC=${REMUX_PARAM_VC:-$VLC_VC}
        VOPTS=${REMUX_PARAM_VOPTS}
        FPS=${REMUX_PARAM_FPS:-$FPS}

	case "$REMUX_VPID" in
        	''|0|1) VC=none; VBR='';;
	esac

	case "$VC" in
		none)
			VOPTS=""
			MUXER=raw
			;;
		mpgv|mp1v|mp2v)
			VOPTS=""
			MUXER=ts
			;;
		mp4v|m4v|DIVX|divx|DX50|dx50|XVID|XviD|xvid|FMP4|fmp4|3IV2|3iv2|BLZ0|DXGM|HDX4|hdx4|M4S2|m4s2|MP4S|mp4s|RMP4|SEDG|SMP4|UMP4|WV1F|XVIX)
			VOPTS=""
			MUXER=ts
			;;
		DIV1|div1|DIV2|div2|DIV3|div3)
			VOPTS=""
			MUXER=ts
			;;
                x264)
			X264EOPTS=(
				${VOPTS}
				$(IFS=$IFS:; addOpts "$VOPTS" $VLC_X264_VOPTS)
			)
			[ ${#X264EOPTS[*]} -gt 0 ] && VOPTS=$(IFS=,; echo x264{"${X264EOPTS[*]}"})
			MUXER=ts
			;;
		theo)
			THEORAEOPTS=(
				${VOPTS}
				$(IFS=$IFS:; addOpts "$VOPTS" $VLC_THEO_VOPTS)
			)
			[ ${#THEORAEOPTS[*]} -gt 0 ] && VOPTS=$(IFS=,; echo theora{"${THEORAEOPTS[*]}"})
			MUXER=ogg
			CONTENTTYPE='video/ogg'
			;;
		drac)
			VOPTS=""
			MUXER=ts
			;;
		VP80)
			VP80EOPTS=(
				${VOPTS}
				"codec=libvpx"
				$(IFS=$IFS:; addOpts "$VOPTS" $VLC_VP80_VOPTS)
			)
			[ ${#VP80EOPTS[*]} -gt 0 ] && VOPTS=$(IFS=,; echo ffmpeg{"${VP80EOPTS[*]}"})
			MUXER=webm
			;;
		*)
                        error "Unknown video codec '$VC'"
                        ;;
	esac

	# Assemble audio options
	AC=${REMUX_PARAM_AC:-$VLC_AC}
	AOPTS=${REMUX_PARAM_AOPTS}
	ACH=2
	isNumeric "${ABR}" && [ "${ABR}" -lt "$ABR_MONO" ] && ! hasOpt "${AOPTS}" channels ] && ACH=1

	case "$AC" in
		mp4a|aac)
			AOPTS="avcodec{codec=libfdk_aac}"
			[ "$VC" == "none" ] && MUXER=m4a && CONTENTTYPE='audio/mp4'
			;;
		mpga)
			AOPTS=""
			;;
		mp3)
			AOPTS=""
			[ "$VC" == "none" ] && MUXER=dummy
			;;
		vorb)
			VORBISEOPTS=(
				${AOPTS}
				"codec=libvorbis"
				$(IFS=$IFS:; addOpts "$AOPTS" $VLC_VORB_AOPTS)
			)
			#[ ${#VORBISEOPTS[*]} -gt 0 ] && AOPTS=$(IFS=,; echo vorbis{"${VORBISEOPTS[*]}"})
			[ ${#VORBISEOPTS[*]} -gt 0 ] && AOPTS=$(IFS=,; echo avcodec{"${VORBISEOPTS[*]}"})
			[ "$VC" == "none" ] && MUXER=ogg && CONTENTTYPE='audio/ogg'
			;;
		*)
			error "Unknown audio codec '$AC'"
			;;
        esac

	#[ -z "$MUXER" ] && MUXER=raw
	[ "$MUXER" = "webm" ] && MUXER=ffmpeg{mux=webm}
	# set APID when needed
	read -a APID_ARRAY <<< "$REMUX_APID"
	[ ${#APID_ARRAY[*]} -eq 1 ] && APID=${APID_ARRAY[0]}

	startReply
        exec 3<&0

	echo $VLC -I dummy -v --no-interact --ignore-config --no-fb-tty --no-sout-display --no-sout-display-audio ${APID:+--audio-track-id $APID} \
		--sout "#transcode{vcodec=$VC,${VOPTS:+venc=$VOPTS,}${VBR:+vb=$VBR,}${WIDTH:+scale=1,width=$WIDTH,height=$HEIGHT,}${FPS:+fps=$FPS,}deinterlace,hurry-up, \
acodec=$AC,${AOPTS:+aenc=$AOPTS,}ab=$ABR,channels=$ACH}:std{access=file,mux=$MUXER,name=\"${REMUX_CHANNEL_NAME}\",description=\"Powered by VDR streamdev $SERVER_SOFTWARE\",dst=$FIFO}" fd://0 vlc://quit >&2

	$VLC -I dummy -vv --no-interact --ignore-config --no-fb-tty --no-sout-display --no-sout-display-audio ${APID:+--audio-track-id $APID} \
		--sout "#transcode{vcodec=$VC,${VOPTS:+venc=$VOPTS,}${VBR:+vb=$VBR,}${WIDTH:+scale=1,width=$WIDTH,height=$HEIGHT,}${FPS:+fps=$FPS,}deinterlace,hurry-up, \
acodec=$AC,${AOPTS:+aenc=$AOPTS,}ab=$ABR,channels=$ACH}:std{access=file,mux=$MUXER,name=\"${REMUX_CHANNEL_NAME}\",description=\"Powered by VDR streamdev $SERVER_SOFTWARE\",dst=$FIFO}" fd://0 vlc://quit 0<&3 >/dev/null &

#	echo $VLC --intf=dummy -v --no-interact \
#		--sout-transcode-vcodec=$VC \
#		${VOPTS:+--sout-transcode-venc=$VOPTS} \
#		${VBR:+--sout-transcode-vb=$VBR} \
#		${WIDTH:+--sout-transcode-scale=1 --sout-transcode-width=$WIDTH --sout-transcode-height=$HEIGHT} \
#		${FPS:+--sout-transcode-fps=$FPS} \
#		--sout-transcode-deinterlace \
#		--sout-transcode-hurry-up \
#		--sout-transcode-acodec=$AC \
#		${AOPTS:+--sout-transcode-aenc=$AOPTS} \
#		--sout-transcode-ab=$ABR \
#		--sout-transcode-channels=$ACHAN \
#		--sout-standard-access=file \
#		--sout-standard-mux=$MUXER \
#		--sout-standard-dst=$FIFO \
#		fd://0 vlc://quit >&2

#	$VLC --intf=dummy -v --no-interact \
#		--sout-transcode-vcodec=$VC \
#		${VOPTS:+--sout-transcode-venc=$VOPTS} \
#		${VBR:+--sout-transcode-vb=$VBR} \
#		${WIDTH:+--sout-transcode-scale=1 --sout-transcode-width=$WIDTH --sout-transcode-height=$HEIGHT} \
#		${FPS:+--sout-transcode-fps=$FPS} \
#		--sout-transcode-deinterlace \
#		--sout-transcode-hurry-up \
#		--sout-transcode-acodec=$AC \
#		${AOPTS:+--sout-transcode-aenc=$AOPTS} \
#		--sout-transcode-ab=$ABR \
#		--sout-transcode-channels=$ACHAN \
#		--sout-standard-access=file \
#		--sout-standard-mux=$MUXER \
#		--sout-standard-dst=$FIFO \
#		fd://0 vlc://quit 0<&3 >/dev/null &

}

function remux_ffmpeg
{
	# lavc may be used for video and audio
	LAVCOPTS=()
	FFMPEG_THREADS=${REMUX_PARAM_THREADS:-$FFMPEG_THREADS}

	# Assemble video options
	VC=${REMUX_PARAM_VC:-$FFMPEG_VC}
	VOPTS=${REMUX_PARAM_VOPTS}
	FPS=${REMUX_PARAM_FPS:-$FPS}

	# 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

	VSIZE="scale=iw*min($WIDTH/iw\,$HEIGHT/ih):ih*min($WIDTH/iw\,$HEIGHT/ih), pad=$WIDTH:$HEIGHT:($WIDTH-iw*min($WIDTH/iw\,$HEIGHT/ih))/2:($HEIGHT-ih*min($WIDTH/iw\,$HEIGHT/ih))/2"

	case "$VC" in
		libx264)
			VOPTS="${VOPTS:-$FFMPEG_X264_VOPTS}"
			VOPTS="-maxrate ${VBR}k ${VOPTS}"
			;;
		libtheora)
			VOPTS="${VOPTS:-$FFMPEG_THEORA_VOPTS}"
			VOPTS="-qscale:v 3"
			;;
		*)
			error "Unknown video codec '$VC'"
			;;
	esac

	# Assemble audio options 
	AC=${REMUX_PARAM_AC:-$FFMPEG_AC}
	AOPTS=${REMUX_PARAM_AOPTS}
	case "$AC" in
		libmp3lame)
			AOPTS="${AOPTS:-$FFMPEG_LAME_AOPTS}"
			AOPTS="-b:a ${ABR}k ${AOPTS}"
			;;
		libvorbis)
			AOPTS="-qscale:a 3"
			;;
		*)
			error "Unknown audio codec '$AC'"
			;;
	esac


	startReply "NOFIFO"
	exec 3<&0
	echo $FFMPEG \
		-v 9 -loglevel 99 \
		-i - \
		-threads $FFMPEG_THREADS \
		-filter:v \"${VSIZE}, yadif\" \
		-codec:v $VC $VOPTS \
		${FPS:+-framerate $FPS} \
		-codec:a $AC $AOPTS \
		-f ogg pipe:1 >&2
	$FFMPEG \
		-v 9 -loglevel 99 \
		-i - \
		-threads $FFMPEG_THREADS \
		-filter:v "${VSIZE}, yadif" \
		-codec:v $VC $VOPTS \
		${FPS:+-framerate $FPS} \
		-codec:a $AC $AOPTS \
		-f ogg pipe:1 0<&3 >/dev/null &
}

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:vbv_maxrate=$((VBR+50))}
			)
			[ ${#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 \
		-v -v -v \
		${MENCODER_MSGLEVEL:+-msglevel $MENCODER_MSGLEVEL} \
		-ovc $VC $VOPTS \
		-oac $AC $AOPTS \
		${MENCODER_ALANG:+-alang $MENCODER_ALANG} \
		${WIDTH:+-vf scale=$WIDTH:$HEIGHT} \
		${FPS:+-ofps $FPS} \
		-o "$FIFO" -- - >&2
	$MENCODER \
		-v -v -v \
		${MENCODER_MSGLEVEL:+-msglevel $MENCODER_MSGLEVEL} \
		-ovc $VC $VOPTS \
		-oac $AC $AOPTS \
		${MENCODER_ALANG:+-alang $MENCODER_ALANG} \
		${WIDTH:+-vf scale=$WIDTH:$HEIGHT} \
		${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
	if [ "$1" != "NOFIFO" ];
	then
		# 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" <&- &
	else
		trap "trap '' EXIT HUP INT TERM ABRT PIPE CHLD; kill -INT 0" EXIT HUP INT TERM ABRT PIPE CHLD
	fi
}

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=;;
	WLAN54|wlan54)           VBR=2048; ABR=128; WIDTH=;;
	LAN10|lan10)             VBR=4096; ABR=;    WIDTH=;;
	PHONE|HANDY|phone|handy) VBR=768; ABR=96; WIDTH=640; PROG=vlc; VLC_VC=mp4v; VLC_AC=mp3;;
	UMTS|umts)               VBR=150; ABR=16; WIDTH=320;;
	BEST|best)               PROG=ogg; OGG_VQUALITY=2; VBR=1000; ABR=100; WIDTH=520;;
	#  WIDTH=576
	*)                 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;;
	ffmpeg)   remux_ffmpeg;;
	vlc)      remux_vlc;;
	*)        error "Unknown remuxer '$PROG'";;
esac

set -o monitor
wait