#!/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&amp;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