summaryrefslogtreecommitdiff
path: root/localvideowebencode
diff options
context:
space:
mode:
authorJonas Smedegaard <dr@jones.dk>2014-10-03 02:37:41 +0200
committerJonas Smedegaard <dr@jones.dk>2014-10-03 14:42:59 +0200
commitb5fd27d2ca5bdd4074bfaabdd44cdad74753edde (patch)
tree21c3fed05955797b54d46d592db467ba37c95caf /localvideowebencode
parent992bc13338f8355f8afedc994acbc0ff7f077082 (diff)
Refactor to use vpxenc: Use of libvpx via libav apparently broken wrt. CRF option.
Diffstat (limited to 'localvideowebencode')
-rwxr-xr-xlocalvideowebencode155
1 files changed, 121 insertions, 34 deletions
diff --git a/localvideowebencode b/localvideowebencode
index eeac39c..7ff187c 100755
--- a/localvideowebencode
+++ b/localvideowebencode
@@ -16,6 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Depends: libav-tools melt mediainfo
+# Recommends: moreutils vpx-tools vorbis-tools opus-tools
#
# TODO:
# * Offer to skip rendering again if an output file exist already.
@@ -28,6 +29,8 @@
# Maybe as workaround re-feed audio separately from xml, as done at
# <http://bernaerts.dyndns.org/linux/74-ubuntu/214-ubuntu-stabilize-video-melt>.
# * Resolve flash player to use.
+# * Make choice of encoders configurable.
+# * Figure out how to apply application option when using opusenc.
set -e
@@ -160,6 +163,10 @@ while true ; do
esac
done
+# Resolve if system has many CPU cores
+processors=$(nproc)
+[ $processors -gt 2 ] || processors=
+
# Resolve if melt is version 0.9.2 or newer
melt_recent=$(melt -query filter=loudness | grep -qi R128 && echo yes)
@@ -172,36 +179,40 @@ infile_first=$(perl -e 'print shift @ARGV' $infiles)
stem=${stem:-$(basename "$infile_first" | perl -pe 's/\.[^.]*//')}
title=${title:-$stem}
+# Use vpxenc for VP8 and VP9: CRF is apparently broken with libav
+use_vpxenc=yes
+#use_oggenc=yes
+#use_opusenc=yes
+
# resolve quality/speed hints
multipass=yes
-speedpreset_h264=medium
-crf_vp8=10
-crf_vp9=10
-crf_h264=23
qscale_theora=5
-cpu_vp8=3
+crf_vp8=55
+cpu_vp8=0
+crf_vp9=35
cpu_vp9=5
+crf_h264=23
+speedpreset_h264=medium
case "$compression" in
normal) :;;
dirty)
- multipass=
- speedpreset_h264=veryfast
- crf_vp8=0
- crf_vp9=0
- qscale_theora=3
+ qscale_theora=1
+ crf_vp8=63
cpu_vp8=5
+ crf_vp9=63
+ crf_h264=51
;;
hq)
- speedpreset_h264=veryslow
- crf_vp8=10
- crf_vp9=10
qscale_theora=6
+ crf_vp8=40
cpu_vp8=0
+ crf_vp9=40
cpu_vp9=1
+ speedpreset_h264=veryslow
;;
*) exit1 "Unknown compression mode \"$compression\".";;
esac
-
+[ -n "$multipass" ] || singlepass=yes
# parse/resolve size and framerate
case "$profile" in
@@ -266,13 +277,15 @@ EOF
esac
# resolve input size and framerate (needed for computing bitrate)
-while read w h r foo; do
+while read w h r s foo; do
width_in="${width_in:-$w}"
height_in="${height_in:-$h}"
framerate_in="${framerate_in:-$r}"
+ scantype_in="${scantype_in:-$s}"
done << EOF
-$(mediainfo --Inform="Video;%Width% %Height% %FrameRate%" "$infile_first")
+$(mediainfo --Inform="Video;%Width% %Height% %FrameRate% %ScanType%" "$infile_first")
EOF
+[ Progressive = "$scantype_in" ] || do_deinterlace=yes
case "$video" in
talkinghead)
@@ -308,10 +321,18 @@ fi
_frames="${framerate:-$framerate_in}"
sizepreset_vpx=libvpx-360p
+webm_qmin=0
+webm_qmax=63
+webm_lag=16
+webm_tokenparts_log2=0
if [ -n "$_pixels" ] && [ $_pixels -ge $((1024*768)) ]; then
sizepreset_vpx=libvpx-720p
+ webm_qmin=11
+ web_qmax=51
+ webm_tokenparts_log2=2
if [ -n "$_frames" ] && [ $_frames -gt 40 ]; then
sizepreset_vpx=libvpx-720p50_60
+ webm_lag=25
fi
fi
@@ -366,9 +387,14 @@ esac
# generic options
melt="melt -progress"
avconv="avconv -threads auto -y -v warning"
+vpxenc="vpxenc --quiet ${processors:+-t $((processors-1))}"
+oggenc="oggenc --quiet"
+opusenc="opusenc --quiet"
_melt_sample="$infile_first ${sample:+in=${samplestart:-0} out=$((${samplestart:-0} + samplelength))}"
_melt_video="progressive=1${framerate:+ frame_rate_num="$framerate_num" frame_rate_den="$framerate_den"}${size:+ s=${width:+$width}x${height:+$height}}${aspect:+ aspect=$aspect}"
+_avconv_video="${do_deinterlace:+-filter:v yadif}${framerate:+ -r $framerate_num/$framerate_den}${size:+ -s ${width:+$width}x${height:+$height}}${aspect:+ -aspect $aspect}"
_melt_audio="${channels:+ac=$channels}"
+_avconv_audio="${channels:+-ac $channels}"
# filter options
# limit (i.e. avoid peaks "clipping")
@@ -378,18 +404,39 @@ _melt_postfilters_audio="${limit:+-filter ladspa.1077}"
_melt_theora="vcodec=libtheora${bitrate:+ vb=$bitrate} qscale=$qscale_theora"
_melt_vp8="vcodec=libvpx vpreset=$sizepreset_vpx${bitrate_vp8:+ vb=$bitrate_vp8 minrate=$((bitrate_vp8/20)) maxrate=$((bitrate_vp8*12))} crf=$crf_vp8 cpu-used=$cpu_vp8"
_avconv_vp8="-c:v libvpx -pre:v $sizepreset_vpx${bitrate_vp8:+ -b:v $bitrate_vp8 -minrate $((bitrate_vp8/20)) -maxrate $((bitrate_vp8*12))} -crf $crf_vp8 -cpu-used $cpu_vp8"
-# CRF ignored with libvpx 1.3
+_vpxenc_vpx="--min-q=$webm_qmin --max-q=$webm_qmax${multipass:+ --minsection-pct=5 --maxsection-pct=1200} --kf-max-dist=120 --auto-alt-ref=1 --lag-in-frames=$webm_lag --arnr-maxframes=7 --arnr-strength=5 --arnr-type=3"
+_vpxenc_vp8="--codec=vp8${bitrate_vp8:+ --target-bitrate=$bitrate_vp8} --good --end-usage=cq --cq-level=$crf_vp8 --cpu-used=$cpu_vp8 $_vpxenc_vpx --token-parts=$webm_tokenparts_log2"
_melt_vp9="vcodec=libvpx-vp9 vpreset=$sizepreset_vpx${bitrate_vp9:+ vb=$bitrate_vp9 minrate=$((bitrate_vp9/20)) maxrate=$((bitrate_vp9*12))} crf=$crf_vp9 cpu-used=$cpu_vp9"
_avconv_vp9="-c:v libvpx-vp9 -pre:v $sizepreset_vpx${bitrate_vp9:+ -b:v $bitrate_vp9 -minrate $((bitrate_vp9/20)) -maxrate $((bitrate_vp9*12))} -crf $crf_vp9 -cpu-used $cpu_vp9"
+_vpxenc_vp9="--codec=vp9${bitrate_vp9:+ --target-bitrate=$bitrate_vp9} --good --end-usage=cq --cq-level=$crf_vp9 --cpu-used=$cpu_vp9 $_vpxenc_vpx --tile-columns=$webm_tokenparts_log2 --tile-rows=$webm_tokenparts_log2"
_melt_h264="vcodec=libx264 vpreset=$speedpreset_h264 vprofile=baseline${x264tune:+ tune=$x264tune} threads=0 movflags=+faststart crf=$crf_h264"
_melt_vorbis="$_melt_audio acodec=libvorbis aq=$quality_vorbis"
+_avconv_vorbis="-c:a libvorbis -aq $quality_vorbis"
+_oggenc_vorbis="-q $quality_vorbis"
_melt_opus="$_melt_audio acodec=libopus${channels:+ ab=$(($channels*$bitrate_opus))k}${opusapp:+ application=$opusapp}"
+_avconv_opus="-c:a libopus${channels:+ -b:a $(($channels*$bitrate_opus))k}${opusapp:+ -application $opusapp}"
+_opusenc_opus="${channels:+--bitrate $((channels*bitrate_opus))}"
_melt_aac="$_melt_audio acodec=aac${channels:+ ab=$(($channels*$bitrate_aac))k}"
# container options
+_melt_yuv4mpeg2="f=yuv4mpegpipe $_melt_video pix_fmt=yuv420p an=1 audio_off=1"
+_avconv_yuv4mpeg2_in="-f yuv4mpegpipe"
+_avconv_rawvideo="-f rawvideo"
+_melt_wav="f=wav $_melt_audio vn=1 video_off=1"
+_avconv_wav_in="-f wav $_avconv_audio"
+_oggenc_wav_in=
+_opusenc_wav_in=
_melt_ogg="f=ogg $_melt_video $_melt_theora $_melt_vorbis"
+_avconv_ogg_in="-f ogg"
+_avconv_ogg_vorbis="-f ogg -vn $_avconv_vorbis"
+_avconv_ogg_opus="-f ogg -vn $_avconv_opus"
_melt_webm="f=webm $_melt_video $_melt_vp8 $_melt_vorbis"
+_avconv_webm="-f webm $_avconv_video $_avconv_vp8 $_avconv_vorbis"
+_avconv_webm_in="-f webm"
+_avconv_webm_keepvideo="-f webm $_avconv_video -c:v copy $_avconv_vorbis"
+_avconv_webm_keepvideo_opus="-f webm $_avconv_video -c:v copy $_avconv_opus"
_melt_webm_vp9="f=webm $_melt_video $_melt_vp9 $_melt_opus"
+_avconv_webm_vp9="-f webm $_avconv_video $_avconv_vp9 $_avconv_opus"
_melt_mp4="f=mp4 $_melt_video $_melt_h264 $_melt_aac"
_melt_img="f=image2 $_melt_video"
@@ -403,23 +450,63 @@ fi
if [ -n "$multipass" ] && [ -n "$webm$vp9" ]; then
echo "Analyzing complexity for WebM..."
- $melt ${_melt_sample:-$infiles} $filters \
- -consumer avformat:pipe:1 $_melt_video f=yuv4mpegpipe pix_fmt=yuv420p an=1 audio_off=1 \
- | $avconv -i pipe:0 \
- ${webm:+-f rawvideo $_avconv_vp8 -an -pass 1 -passlogfile ${stem}_vp8 /dev/null} \
- ${vp9:+-f rawvideo $_avconv_vp9 -an -pass 1 -passlogfile ${stem}_vp9 /dev/null}
- [ -z "$webm" ] || mv -f ${stem}_vp8-*.log ${stem}_vp8_2pass.log
- [ -z "$vp9" ] || mv -f ${stem}_vp9-*.log ${stem}_vp9_2pass.log
+ if [ -n "$use_vpxenc" ]; then
+ $melt ${_melt_sample:-$infiles} $filters \
+ -consumer avformat:pipe:1 $_melt_yuv4mpeg2 \
+ | pee \
+ ${webm:+"$vpxenc - $_vpxenc_vp8 -p 2 --pass=1 --fpf=${stem}_vp8.log -o /dev/null"} \
+ ${vp9:+"$vpxenc - $_vpxenc_vp9 -p 2 --pass=1 --fpf=${stem}_vp9.log -o /dev/null"}
+ else
+ $melt ${_melt_sample:-$infiles} $filters \
+ -consumer avformat:pipe:1 $_melt_yuv4mpeg2 \
+ | $avconv $_avconv_yuv4mpeg2_in -i pipe:0 \
+ ${webm:+$_avconv_rawvideo $_avconv_vp8 -an -pass 1 -passlogfile ${stem}_vp8 /dev/null} \
+ ${vp9:+$_avconv_rawvideo $_avconv_vp9 -an -pass 1 -passlogfile ${stem}_vp9 /dev/null}
+ [ -z "$webm" ] || mv -f ${stem}_vp8-*.log ${stem}_vp8_2pass.log
+ [ -z "$vp9" ] || mv -f ${stem}_vp9-*.log ${stem}_vp9_2pass.log
+ fi
fi
-echo "Encoding video..."
-$melt ${_melt_sample:-$infiles} \
- ${channels:+$audioprefilters${_melt_loudness:+ -filter loudness results="$_melt_loudness"}} \
- $filters${channels:+ $_melt_postfilters_audio} \
- ${ogg:+-consumer avformat:$stem.ogv $_melt_ogg} \
- ${webm:+-consumer avformat:$stem.webm $_melt_webm${multipass:+ pass=2 passlogfile=${stem}_vp8}} \
- ${vp9:+-consumer avformat:${stem}_vp9.webm $_melt_webm_vp9${multipass:+ pass=2 passlogfile=${stem}_vp9}} \
- ${mp4:+-consumer avformat:$stem.mp4 $_melt_mp4}
+if [ -n "$use_oggenc$use_opusenc$use_vpxenc" ] && [ -n "$webm$vp9" ]; then
+ echo "Encoding raw video and extracting audio..."
+ $melt ${_melt_sample:-$infiles} \
+ ${channels:+$audioprefilters${_melt_loudness:+ -filter loudness results="$_melt_loudness"}} \
+ $filters${channels:+ $_melt_postfilters_audio} \
+ ${ogg:+-consumer avformat:$stem.ogv $_melt_ogg} \
+ ${mp4:+-consumer avformat:$stem.mp4 $_melt_mp4} \
+ ${channels:+-consumer avformat:$stem.wav $_melt_wav} \
+ -consumer avformat:pipe:1 $_melt_yuv4mpeg2 \
+ | pee \
+ ${webm:+"$vpxenc - $_vpxenc_vp8${singlepass:+ -p 1}${multipass:+ -p 2 --pass=2 --fpf=${stem}_vp8.log} -o ${stem}_silent.webm"} \
+ ${vp9:+"$vpxenc - $_vpxenc_vp9${singlepass:+ -p 1}${multipass:+ -p 2 --pass=2 --fpf=${stem}_vp9.log} -o ${stem}_vp9_silent.webm"}
+ if [ -n "$webm" ]; then
+ echo "Encoding Vorbis audio and muxing with VP8 video..."
+ if [ -n "$use_oggenc" ]; then
+ $oggenc $_oggenc_wav_in $_oggenc_vorbis -o - $stem.wav \
+ | $avconv $_avconv_webm_in -i ${stem}_silent.webm $_avconv_ogg_in -i pipe:0 $_avconv_webm_keepvideo $stem.webm
+ else
+ $avconv $_avconv_webm_in -i ${stem}_silent.webm $_avconv_wav_in -i $stem.wav $_avconv_webm_keepvideo ${stem}.webm
+ fi
+ fi
+ if [ -n "$vp9" ]; then
+ echo "Encoding Opus audio and muxing with WebM/VP9 video..."
+ if [ -n "$use_opusenc" ]; then
+ $opusenc $_opusenc_wav_in $_opusenc_opus -o - $stem.wav \
+ | $avconv $_avconv_webm_in -i ${stem}_vp9_silent.webm $_avconv_ogg_in -i pipe:0 $_avconv_webm_keepvideo_opus ${stem}_vp9.webm
+ else
+ $avconv $_avconv_webm_in -i ${stem}_vp9_silent.webm $_avconv_wav_in -i $stem.wav $_avconv_webm_keepvideo_opus ${stem}_vp9.webm
+ fi
+ fi
+else
+ echo "Encoding video..."
+ $melt ${_melt_sample:-$infiles} \
+ ${channels:+$audioprefilters${_melt_loudness:+ -filter loudness results="$_melt_loudness"}} \
+ $filters${channels:+ $_melt_postfilters_audio} \
+ ${ogg:+-consumer avformat:$stem.ogv $_melt_ogg} \
+ ${webm:+-consumer avformat:$stem.webm $_melt_webm${multipass:+ pass=2 passlogfile=${stem}_vp8}} \
+ ${vp9:+-consumer avformat:${stem}_vp9.webm $_melt_webm_vp9${multipass:+ pass=2 passlogfile=${stem}_vp9}} \
+ ${mp4:+-consumer avformat:$stem.mp4 $_melt_mp4}
+fi
if [ -n "$mp4" ] && [ -z "$melt_recent" ]; then
mv "$stem.mp4" "$stem.mp4"~
@@ -427,8 +514,8 @@ if [ -n "$mp4" ] && [ -z "$melt_recent" ]; then
[ -f "$stem.mp4" ] && rm "$stem.mp4"~ || mv -f "$stem.mp4"~ "$stem.mp4"
fi
-# cleanup audio normalize hinting
-rm -f $stem.xml
+# cleanup encoding cruft
+rm -f $stem.xml $stem.wav ${stem}_vp8.log ${stem}_vp9.log ${stem}_silent.webm ${stem}_vp9_silent.webm
# JPEG preview
$melt $infile_first in=0 out=0 \