#!/bin/sh # Origins: # http://diveintohtml5.org/video.html # http://camendesign.com/code/video_for_everybody # http://www.streaminglearningcenter.com/articles/so-you-want-to-get-to-know-h264.html # Possible flashplayers: # http://www.internetmarketingnotes.com/2010/07/free-embeddable-flash-video-flv-players-for-commercial-use/ # TODO: offer to skip rendering again if an output file exist already # TODO: support --width and --height (resolving the other part from input/forced aspect ratio) # TODO: support --formats (comma-separated, to allow e.g. excluding webm even if supported) # TODO: add --speech option, using mono, lower audio rate, and (when solved how) speex set -e PRG=$(basename "$0") showhelp() { cat <<EOF Usage: $PRG [OPTION...] [--] [ARG=VALUE...] INPUTFILE... [ARG=VALUE...] Encode video file in multiple web-optimized formats, and provide sample html favoring open formats with optional non-JavaScript Flash fallback. -s, --size Output size (ffmpeg): WIDTHxHEIGHT vga qcif etc. (default: use input size) -a, --aspect Display Aspect Ratio in melt format e.g. @16/9 (default: no aspect hinting) -b, --bitrate Video bitrate in bytes, with optional ISO suffix (default: none) -p, --profile Video format (melt): square_ntsc qcif_15 etc. (default: none - reuse input format) --h264profile MPEG-4 AVC target profile (baseline medium) (default: baseline) --stem Stem of output filenames, optionally with path (default: basename of last input file) -t, --title Title used in html fallback graphics (default: stem) --filter Add melt filter (applied to all input files) --sample[=frame] Limit output to a 150 frames sample from beginning or optionally a later start frame -h, --help This help text Examples: $PRG -s qvga -t "Funny guy" intro.dv myvideo.dv $PRG -p sdi_486i_5994 --stem funny -t "Funny guy" myvideo.dv Options before input files are passed to melt producer, and after to melt avformat consumer. When video bitrate is set, 2-pass encoding is used for MPEG-4 output. Hints: * Use max. 640x480 pixel size for widest compatibility (ie. square-pixel 640x360 or anamorphic svcd_ntsc_wide for 16:9) * Append these for single-mic speech: ac=1 ar=32000 ab=64k * Set bitrate for optimal MPEG-4/WebM bits-per-pixel ratio: + talking head: 0.1 + high-motion or detailed content: 0.15 (inspect result with mediainfo) More info: <http://camendesign.com/code/video_for_everybody> <http://www.streaminglearningcenter.com/> <http://en.wikipedia.org/wiki/HTML5_video> EOF } exit1() { response="${1:+Error: }${1:-Internal error!}" echo >&2 "$response" exit 1 } # defaults h264profile=baseline # parse cmdline options TEMP="`getopt -s sh -o hs:a:b:p:t: -l help,size:,aspect:,bitrate:,profile:,h264profile:,stem:,title:,filter:,sample:: -n "$PRG" -- "$@"`" || exit1 "Internal getopt error." eval set -- "$TEMP" while true ; do case "$1" in -h|--help) showhelp; exit;; -s|--size) size="$2"; shift 2;; -a|--aspect) aspect="$2"; shift 2;; -b|--bitrate) bitrate="$2"; shift 2;; -p|--profile) profile="$2"; shift 2;; --h264profile) h264profile="$2"; shift 2;; --stem) stem="$2"; shift 2;; -t|--title) title="$2"; shift 2;; --filter) filters="${filters:+$filters }-filter $2"; shift 2 while [ $# -gt 0 ] ; do case "$1" in *=*) filters="${filters:+$filters }$1"; shift;; *) break;; esac done ;; --sample) sample="in=${2:-0} out=$((${2:-0} + 150))"; shift 2;; --) shift; break;; *) exit1 "Internal error resolving options.";; esac done while [ $# -gt 0 ] ; do case "$1" in *=*) args_in="${args_in:+$args_in }$1"; shift;; *) break;; esac done while [ $# -gt 0 ] ; do case "$1" in *=*) args_out="${args_out:+$args_out }$1"; shift;; *) infiles="${infiles:+$infiles }$1"; shift;; esac done if [ -z "$infiles" ]; then showhelp exit1 "Too few parameters!" fi # input filename (mandatory) infile=$(perl -e 'print pop @ARGV' $infiles) [ -e "$infile" ] || exit1 "Input file missing!" # resolve stem and title (if not explicitly set) stem=${stem:-$(basename "$infile" | perl -pe 's/\.[^.]*//')} title=${title:-$stem} # TODO: Check and fail if all needed tools are not available # TODO: When verified beneficial, add option real_time=-2 args_in="-progress $sample ${profile:+-profile $profile}${args_in:+ $args_in}" args=" ${bitrate:+vb=${bitrate}} ${size:+s=$size} ${aspect:+aspect=$aspect}" args_audio="ab=96k" ## Theora/Vorbis/Ogg melt -group $args_in $infiles -group $filters -consumer avformat:"$stem.ogg" f=ogg vcodec=libtheora $args acodec=libvorbis $args_audio $args_out ## H.264/AAC/MP4 [ -z "$bitrate" ] || melt -group $args_in $infiles -group $filters -consumer avformat:/dev/null properties=x264-medium-pass1 properties=x264-medium-$h264profile $args $args_out melt -group $args_in $infiles -group $filters -consumer avformat:"$stem.mp4" ${bitrate:+pass=2} properties=x264-medium-$h264profile $args acodec=aac $args_audio $args_out mv "$stem.mp4" "$stem.mp4"~ qt-faststart "$stem.mp4"~ "$stem.mp4" [ -f "$stem.mp4" ] && rm "$stem.mp4"~ || exit1 "failed to optimize with qt-faststart." ## VP8/Vorbis/WebM # TODO: use two-pass when supported by melt melt -group $args_in $infiles -group $filters -consumer avformat:"$stem.webm" properties=webm $args $args_audio $args_out ## JPEG preview ffmpegthumbnailer -s0 -i "$stem.mp4" -o "$stem.jpg" # resolve width and height from preview image size=$(jpeginfo "$stem.jpg" | perl -ane 'print "$F[1]x$F[3]"') width=$(echo "$size" | perl -Fx -ane 'print $F[0]') height=$(echo "$size" | perl -Fx -ane 'print $F[1]') heightplus=${height:+$(($height+4))} # TODO: resolve flash player to use [ -z "$flashplayer" ] || flash=yes cat >"$stem.html" <<EOF <!-- Video for Everybody, Kroc Camen of Camen Design --> <video width="$width" height="$height" preload controls> <source src="$stem.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"' /> <source src="$stem.ogg" type='video/ogg; codecs="theora, vorbis"' /> <source src="$stem.webm" type='video/webm; codecs="vp8, vorbis"' /> ${flash:+<object width="$width" height="$heightplus" type="application/x-shockwave-flash" data="$flashplayer.swf"> <param name="movie" value="$flashplayer.swf" /> <param name="flashvars" value="image=$stem.jpg&file=$stem.mp4" /> }<img src="$stem.jpg" width="$width" height="$height" alt="$title" title="No video playback capabilities, please download the video below" /> ${flash:+</object> }</video> <p><strong>Download Video:</strong> open format <a href="$stem.ogg">Ogg</a>, open format <a href="$stem.webm">WebM</a>, closed Format <a href="$stem.mp4">MP4</a>. </p> EOF