From b5fd27d2ca5bdd4074bfaabdd44cdad74753edde Mon Sep 17 00:00:00 2001 From: Jonas Smedegaard Date: Fri, 3 Oct 2014 02:37:41 +0200 Subject: Refactor to use vpxenc: Use of libvpx via libav apparently broken wrt. CRF option. --- localvideowebencode | 155 ++++++++++++++++++++++++++++++++++++++++------------ 1 file 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 . # # 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 # . # * 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 \ -- cgit v1.2.3