summaryrefslogtreecommitdiff
path: root/localvideowebencode
blob: 76345257c162c94a09a964c4afb5aa6041603f64 (plain)
  1. #!/bin/sh
  2. # Origins:
  3. # http://diveintohtml5.org/video.html
  4. # http://camendesign.com/code/video_for_everybody
  5. # http://www.streaminglearningcenter.com/articles/so-you-want-to-get-to-know-h264.html
  6. # Possible flashplayers:
  7. # http://www.internetmarketingnotes.com/2010/07/free-embeddable-flash-video-flv-players-for-commercial-use/
  8. # TODO: offer to skip rendering again if an output file exist already
  9. # TODO: support --width and --height (resolving the other part from input/forced aspect ratio)
  10. # TODO: support --formats (comma-separated, to allow e.g. excluding webm even if supported)
  11. # TODO: add --speech option, using mono, lower audio rate, and (when solved how) speex
  12. set -e
  13. PRG=$(basename "$0")
  14. showhelp() {
  15. cat <<EOF
  16. Usage: $PRG [OPTION...] [--] [ARG=VALUE...] INPUTFILE... [ARG=VALUE...]
  17. Encode video file in multiple web-optimized formats, and provide sample
  18. html favoring open formats with optional non-JavaScript Flash fallback.
  19. -s, --size Output size (ffmpeg): WIDTHxHEIGHT vga qcif etc.
  20. (default: use input size)
  21. -a, --aspect Display Aspect Ratio in melt format e.g. @16/9
  22. (default: no aspect hinting)
  23. -b, --bitrate Video bitrate in bytes, with optional ISO suffix
  24. (default: none)
  25. -p, --profile Video format (melt): square_ntsc qcif_15 etc.
  26. (default: none - reuse input format)
  27. --h264profile MPEG-4 AVC target profile (baseline medium)
  28. (default: baseline)
  29. --stem Stem of output filenames, optionally with path
  30. (default: basename of last input file)
  31. -t, --title Title used in html fallback graphics
  32. (default: stem)
  33. --filter Add melt filter (applied to all input files)
  34. --sample[=frame] Limit output to a 150 frames sample from
  35. beginning or optionally a later start frame
  36. -h, --help This help text
  37. Examples:
  38. $PRG -s qvga -t "Funny guy" intro.dv myvideo.dv
  39. $PRG -p sdi_486i_5994 --stem funny -t "Funny guy" myvideo.dv
  40. Options before input files are passed to melt producer, and after to
  41. melt avformat consumer.
  42. When video bitrate is set, 2-pass encoding is used for MPEG-4 output.
  43. Hints:
  44. * Use max. 640x480 pixel size for widest compatibility
  45. (ie. square-pixel 640x360 or anamorphic svcd_ntsc_wide for 16:9)
  46. * Append these for single-mic speech: ac=1 ar=32000 ab=64k
  47. * Set bitrate for optimal MPEG-4/WebM bits-per-pixel ratio:
  48. + talking head: 0.1
  49. + high-motion or detailed content: 0.15
  50. (inspect result with mediainfo)
  51. More info: <http://camendesign.com/code/video_for_everybody>
  52. <http://www.streaminglearningcenter.com/>
  53. <http://en.wikipedia.org/wiki/HTML5_video>
  54. EOF
  55. }
  56. exit1() {
  57. response="${1:+Error: }${1:-Internal error!}"
  58. echo >&2 "$response"
  59. exit 1
  60. }
  61. # defaults
  62. h264profile=baseline
  63. # parse cmdline options
  64. 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."
  65. eval set -- "$TEMP"
  66. while true ; do
  67. case "$1" in
  68. -h|--help) showhelp; exit;;
  69. -s|--size) size="$2"; shift 2;;
  70. -a|--aspect) aspect="$2"; shift 2;;
  71. -b|--bitrate) bitrate="$2"; shift 2;;
  72. -p|--profile) profile="$2"; shift 2;;
  73. --h264profile) h264profile="$2"; shift 2;;
  74. --stem) stem="$2"; shift 2;;
  75. -t|--title) title="$2"; shift 2;;
  76. --filter) filters="${filters:+$filters }-filter $2"; shift 2
  77. while [ $# -gt 0 ] ; do
  78. case "$1" in
  79. *=*) filters="${filters:+$filters }$1"; shift;;
  80. *) break;;
  81. esac
  82. done
  83. ;;
  84. --sample) sample="in=${2:-0} out=$((${2:-0} + 150))"; shift 2;;
  85. --) shift; break;;
  86. *) exit1 "Internal error resolving options.";;
  87. esac
  88. done
  89. while [ $# -gt 0 ] ; do
  90. case "$1" in
  91. *=*) args_in="${args_in:+$args_in }$1"; shift;;
  92. *) break;;
  93. esac
  94. done
  95. while [ $# -gt 0 ] ; do
  96. case "$1" in
  97. *=*) args_out="${args_out:+$args_out }$1"; shift;;
  98. *) infiles="${infiles:+$infiles }$1"; shift;;
  99. esac
  100. done
  101. if [ -z "$infiles" ]; then
  102. showhelp
  103. exit1 "Too few parameters!"
  104. fi
  105. # input filename (mandatory)
  106. infile=$(perl -e 'print pop @ARGV' $infiles)
  107. [ -e "$infile" ] || exit1 "Input file missing!"
  108. # resolve stem and title (if not explicitly set)
  109. stem=${stem:-$(basename "$infile" | perl -pe 's/\.[^.]*//')}
  110. title=${title:-$stem}
  111. # TODO: Check and fail if all needed tools are not available
  112. # TODO: When verified beneficial, add option real_time=-2
  113. args_in="-progress $sample ${profile:+-profile $profile}${args_in:+ $args_in}"
  114. args=" ${bitrate:+vb=${bitrate}} ${size:+s=$size} ${aspect:+aspect=$aspect}"
  115. args_audio="ab=96k"
  116. ## Theora/Vorbis/Ogg
  117. melt -group $args_in $infiles -group $filters -consumer avformat:"$stem.ogg" f=ogg vcodec=libtheora $args acodec=libvorbis $args_audio $args_out
  118. ## H.264/AAC/MP4
  119. [ -z "$bitrate" ] || melt -group $args_in $infiles -group $filters -consumer avformat:/dev/null properties=x264-medium-pass1 properties=x264-medium-$h264profile $args $args_out
  120. 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
  121. mv "$stem.mp4" "$stem.mp4"~
  122. qt-faststart "$stem.mp4"~ "$stem.mp4"
  123. [ -f "$stem.mp4" ] && rm "$stem.mp4"~ || exit1 "failed to optimize with qt-faststart."
  124. ## VP8/Vorbis/WebM
  125. # TODO: use two-pass when supported by melt
  126. melt -group $args_in $infiles -group $filters -consumer avformat:"$stem.webm" properties=webm $args $args_audio $args_out
  127. ## JPEG preview
  128. ffmpegthumbnailer -s0 -i "$stem.mp4" -o "$stem.jpg"
  129. # resolve width and height from preview image
  130. size=$(jpeginfo "$stem.jpg" | perl -ane 'print "$F[1]x$F[3]"')
  131. width=$(echo "$size" | perl -Fx -ane 'print $F[0]')
  132. height=$(echo "$size" | perl -Fx -ane 'print $F[1]')
  133. heightplus=${height:+$(($height+4))}
  134. # TODO: resolve flash player to use
  135. [ -z "$flashplayer" ] || flash=yes
  136. cat >"$stem.html" <<EOF
  137. <!-- Video for Everybody, Kroc Camen of Camen Design -->
  138. <video width="$width" height="$height" preload controls>
  139. <source src="$stem.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"' />
  140. <source src="$stem.ogg" type='video/ogg; codecs="theora, vorbis"' />
  141. <source src="$stem.webm" type='video/webm; codecs="vp8, vorbis"' />
  142. ${flash:+<object width="$width" height="$heightplus" type="application/x-shockwave-flash" data="$flashplayer.swf">
  143. <param name="movie" value="$flashplayer.swf" />
  144. <param name="flashvars" value="image=$stem.jpg&amp;file=$stem.mp4" />
  145. }<img src="$stem.jpg" width="$width" height="$height" alt="$title"
  146. title="No video playback capabilities, please download the video below" />
  147. ${flash:+</object>
  148. }</video>
  149. <p><strong>Download Video:</strong>
  150. open format <a href="$stem.ogg">Ogg</a>,
  151. open format <a href="$stem.webm">WebM</a>,
  152. closed Format <a href="$stem.mp4">MP4</a>.
  153. </p>
  154. EOF