1#!/bin/sh 2# 3# A convenient front-end for the various mpeg encoding tools. 4# Allows "1 command" production of a video stream... 5# 6 7# Licensed under GPL (see http://www.fsf.org/licenses/gpl.html or contact 8# the Free Software Foundation for a copy) 9# Copyright Scott Moser 10 11 12# these can be changed with env variables, just set and export to override 13NICEVAL=${NICEVAL:-19} 14 15LAV2YUV=${LAV2YUV:-"lav2yuv"} 16YUVSCALER=${YUVSCALER:-"yuvscaler"} 17MPEG2ENC=${MPEG2ENC:-"mpeg2enc"} 18LAV2WAV=${LAV2WAV:-"lav2wav"} 19AUDIOENC=${AUDIOENC:-"mp2enc"} # can be "toolame" or "mp2enc" 20MPLEX=${MPLEX:-"mplex"} 21YUVDENOISE=${YUVDENOISE:-"yuvdenoise"} 22LAVINFO=${LAVINFO:-"lavinfo"} 23 24NOISYLOGFILE="" # if not set, will be outputfilename.log -- only used if -L flag sent 25QUIETLOG=${QUIETLOG:-"lav2mpeg.log"} # if set to not "" will log all normal messages to this file as well as stdout 26LOGDATE=${LOGDATE:-1} # whether or not to output the date in log messages 27LOGDATESTR=${LOGDATESTR:-"+%H:%M:%S"} # format for the date - only used if logdate!=0 28LOGCOMMANDS=${LOGCOMMANDS:-0}; # if non-zero, will output the commands it runs. commands are always logged to NOISYLOGFILE if used 29LOGONLY=${LOGONLY:-""} # will only log the commands it would use if set (for example useage/testing) 30LAV2MPEGRC=${LAV2MPEGRC:-"$HOME/.lav2mpegrc"} # set this to contain your lav2mpeg rc file -- in bash sourceable syntax. 31 # it can modify any ENV vars in this script 32 # or set a "LAV2MPEG_OPTIONS" ENV to prepend default options that will be overridden by explicit command line options. 33if [ "$LOGONLY" != "" ]; then 34 LOGCOMMANDS=1 35fi 36VCD_MEDIUM_BR=${VCD_MEDIUM_BR:-1550} 37VCD_HIGH_BR=${VCD_HIGH_BR:-1800} 38SVCD_HIGH_BR=${SVCD_HIGH_BR:-3000} 39SVCD_HIGH_QUAL=${SVCD_HIGH_QUAL:-5} 40SVCD_HIGH_BUFFSIZE=${SVCD_HIGH_BUFFSIZE:-100} 41 42# extra flags for the encoders (will be the last thing on the line before file names) 43EXTRA_LAV2YUV=${EXTRA_LAV2YUV:-""} 44EXTRA_YUVSCALER=${EXTRA_YUVSCALER:-""} 45EXTRA_MPEG2ENC=${EXTRA_MPEG2ENC:-""} 46EXTRA_LAV2WAV=${EXTRA_LAV2WAV:-""} 47EXTRA_AUDIOENC=${EXTRA_AUDIOENC:-""} 48EXTRA_MPLEX=${EXTRA_MPLEX:-""} 49EXTRA_YUVDENOISE=${EXTRA_YUVDENOISE:-""} 50 51# things that can be changed with arguments 52# don't let an env override, to avoid confusion 53bitrate=1152 54quality=12 55saveraw=0 56mode="vcd" 57outputres="" 58encode_quality=2 59outfile="" 60stereo=1 61noisy=0 62logall=0 63aencbpr_stereo=224 64aencbpr_mono=112 65use_fifo=0 66 67# -- shouldn't have to change below here 68NICE="nice -n $NICEVAL" 69 70 71# functions 72logIt() { 73 if [ $LOGDATE -ne 0 ]; then 74 NOW=$(date $LOGDATESTR) 75 NOW="$NOW - " 76 fi 77 if [ "$logfile" = "" ]; then 78 echo "${NOW}$@" 79 else 80 echo "${NOW}$@" | tee -a $logfile 81 fi 82 if [ "$output_noisy" != "" ]; then 83 echo "${NOW}$@" >> $noisylog 84 fi 85} 86 87cleanExit() { 88 # delete raw files if sawraw is 0 or exiting with non-zero 89 if [ $saveraw -eq 0 -a "$1" = "0" ]; then 90 rm -f $audio $video 91 fi 92 exit $1 93} 94 95getTimeDiff() { 96 if [ $# -lt 2 ]; then 97 return 98 fi 99 diff=$(expr $2 - $1) 100 hours=$(expr $diff / 3600) 101 temp=$(expr $hours \* 3600 ) 102 diff=$(expr $diff - $temp ) 103 minutes=$(expr $diff / 60) 104 sec=$(expr $diff % 60) 105 printf "%i:%02d:%02d\n" "$hours" "$minutes" "$sec" 106} 107 108doStep() { 109 if [ "$LOGCOMMANDS" = "0" ]; then 110 echo "COMMAND=${step[$count]}" 111 fi 112 if [ "$LOGONLY" = "" ]; then 113 eval ${step[$count]} 114 fi 115} 116 117 118usage() 119{ 120 name=`basename $0` 121 cat << END 122Usage: $name [ -s/S -k/K -f/F -l/L -n/N -y/Y ] [ -m mode ] [ -e 0|1|2 ] [ -o outputFile ] [ -b vidbitrate ] [ -a audbitrate ] [ -q 0-30 ] [ -d XxY ] srcfile... 123 s/S - stereo : -s=off -S=on (default auto) 124 k/K - keep raw output files (.m1v, .m2v, .mp2) : -k=no -K=yes (default no) 125 f/F - use fifos : -f=no -F=yes (default no) 126 l/L - log all encoding : -l=no -L=yes (default no) 127 n/N - be noisy (don't hide output of tools) : -n=no -N=yes (default no) 128 y/Y - yuvdenoise : -y=don't use -Y=use (default e=1|2 use e=0 dont) 129 m - one of MODES (see below) (default $mode) 130 e - encoding quality : 0, 1, or 2 (default $encode_quality) 131 o - output file ( defaults to firstInputFileName.mpg ) 132 b - video bitrate in kbps ( only used when -o is "mpeg1" or "mpeg2" ) 133 a - audio bitrate in kpbs ( only used when -o is not "vcd*" ) 134 q - quality for mpeg2enc ( only used when -o is "mpeg1" or "mpeg2" ) 135 d - dimensions XxY ( only used when -o is "mpeg1" or "mpeg2" ) 136 defaults to same as input 137 138 MODES: 139 vcd -- standard VCD (352x240 or 352x288) 140 vcd_medium -- ${VCD_MEDIUM_BR}kbps video VCD (352x240 or 352x288) 141 vcd_high -- ${VCD_HIGH_BR}kbps video VCD (352x240 or 352x288) 142 svcd -- standard SVCD (480x480 or 480x576) 143 svcd_high -- ${SVCD_HIGH_BR}kbps(max) vbr @qual=${SVCD_HIGH_QUAL} (480x480 or 480x576) 144 mpeg1 -- honor -a -b -q -d flags default resolution same as input 145 mpeg2 -- honor -a -b -q -d flags default resolution same as input 146 147 EXAMPLE: 148 VCD: $name file.avi 149 - will create a VCD compatible mpeg named file.mpg 150 mpeg2: $name -m mpeg2 -o output.mpg file.edl 151 - will create a mpeg2 with default bitrate in same res as input 152 mpeg1: $name -a 160 -b 2110 -d 320x240 -m mpeg1 -o output.mpg file.edl 153 - will create a mpeg2 with videobitrate=2110 and audio=160 154 - and resolution 320x240 155 debug: export LOGONLY=1; $name -m mpeg2 -o output.mpg file.edl 156 - will print out the commands it would use to do this, but 157 - not do anything 158 159 please see the script for more info and environment variables set/used 160END 161exit 1 162} 163 164printDebugInfo() { 165 logIt "going from ${video_width}x${video_height} ($video_norm) to ${output_width}x${output_height} in $mode with quality=$quality, bitrate=$bitrate and encodequal=${encode_quality}" 166 logIt "outfile=$outfile audio=$audio video=$video" 167 logIt "lav2yuv_flags=$lav2yuv_flags" 168 logIt "yuscaler_flags=$yuvscaler_flags" 169 logIt "mpeg2enc_flags=$mpeg2enc_flags" 170 logIt "lav2wav_flags=$lav2wav_flags" 171 logIt "audioenc_flags=$audioenc_flags" 172 logIt "mplex_flags=$mplex_flags" 173 logIt "need_scale=$needscale" 174 logIt "downscale=$downscaling" 175} 176 177if [ $# -eq 0 -o "$1" = "--help" -o "$1" = "-h" ]; then 178 usage; 179 exit 1 180fi 181 182LAVRC_COUNT=0 183if [ -e $LAV2MPEGRC ]; then 184 logIt "Sourcing lav2mpgrc file $LAV2MPEGRC (this can change defaults!)" 185 . $LAV2MPEGRC 186 LAVRC_COUNT=$(echo $LAV2MPEG_OPTIONS | wc -w ) 187fi 188 189infostr="" 190while getopts "sSkKfFlLnNyYb:a:q:d:m:e:o:" opt $LAV2MPEG_OPTIONS $@ 191do 192 case $opt in 193 s) userstereo=0 194 infostr="${infostr} using mono -" 195 ;; 196 S) userstereo=1 197 infostr="${infostr} using stereo -" 198 ;; 199 k) saveraw=0 200 infostr="${infostr} not saving raw files -" 201 ;; 202 K) saveraw=1 203 infostr="${infostr} saving raw files -" 204 ;; 205 f) use_fifo=0 206 infostr="${infostr} not using fifos-" 207 ;; 208 F) use_fifo=1 209 infostr="${infostr} using fifos-" 210 ;; 211 l) logall=0 212 infostr="${infostr} not logging all -" 213 ;; 214 L) logall=1 215 infostr="${infostr} logging all -" 216 ;; 217 n) noisy=0 218 infostr="${infostr} not being noisy -" 219 ;; 220 N) noisy=1 221 infostr="${infostr} being noisy -" 222 ;; 223 y) userdenoise=0 224 infostr="${infostr} not using yuvdenoise -" 225 ;; 226 Y) userdenoise=1 227 infostr="${infostr} using yuvdenoise -" 228 ;; 229 b) bitrate=$OPTARG 230 infostr="${infostr} using video bitrate=$bitrate -" 231 ;; 232 a) useraencbpr=$OPTARG 233 infostr="${infostr} using audio bitrate=$useraencbpr" 234 ;; 235 q) quality=$OPTARG 236 infostr="${infostr} using quality=$quality -" 237 ;; 238 d) outputres=$OPTARG 239 infostr="${infostr} using outputres=$outputres -" 240 ;; 241 m) mode=$OPTARG 242 infostr="${infostr} mode=$mode -" 243 ;; 244 e) encode_quality=$OPTARG 245 infostr="${infostr} encode_quality=$encode_quality -" 246 ;; 247 o) outfile=$OPTARG 248 infostr="${infostr} outfile=$outfile -" 249 ;; 250 ?) 251 usage 252 ;; 253 esac 254done 255let MOPTIND=OPTIND-LAVRC_COUNT 256shift `expr $MOPTIND - 1` 257 258if [ "${QUIETLOG}" != "" ]; then 259 logfile=${QUIETLOG} 260else 261 logfile="/dev/null" 262fi 263#uncomment to blank logfile 264#echo "" > $logfile 265 266logIt "$infostr" 267 268# lavinfo should set up video_frames, video_width 269# video_height, video_inter, video_norm, audio_chans 270eval $($LAVINFO $@ | grep "=") # grep for = to remove Warnings 271if [ "$video_frames" = "" ]; then 272 logIt "'lavinfo $@' died! exiting" 273 logIt " maybe you don't have lavinfo. or your input flags were wrong" 274 logIt " input files must be the last input on the command line" 275 exit 1 276fi 277 278case $mode in 279 vcd*) 280 case $video_norm in 281 NTSC) output_width=352; output_height=240 ;; 282 PAL) output_width=352; output_height=288 ;; 283 SECAM) output_width="SECAM_VCD_WIDTH???"; output_height="SECAM_VCD_HEIGHT";; 284 esac 285 ;; 286 svcd*) 287 case $video_norm in 288 NTSC) output_width=480; output_height=480 ;; 289 PAL) output_width=480; output_height=576;; 290 SECAM) output_width="SECAM_SVCD_WIDTH???"; output_height="SECAM_SVCD_HEIGHT" ;; 291 esac 292 ;; 293 mpeg*) 294 if [ "$outputres" != "" ]; then 295 temp=$outputres 296 temp=${outputres%%[+-]*} 297 output_width=${temp%x*} 298 output_height=${temp#*x} 299 logIt "using output_width=$output_width, output_height=$output_height" 300 # these don't work yet, negative values would mess them up 301 temp=${outputres#*+} 302 output_xoff=${temp%%[+-]*} 303 output_yoff=${temp##*[+-]} 304 else 305 output_width=$video_width 306 output_height=$video_height 307 fi 308 ;; 309esac 310 311 312# hopefully sane input has been checked, lets start setting things up 313 314# simple check for logonly mode 315if [ "$LOGONLY" != "" -a "$LOGONLY" != "0" -a $use_fifo -eq 1 ]; then 316 use_fifo=0 317 logIt "can't do logonly with fifos, turning fifos off" 318fi 319 320# set up extra flags as possibly given by user 321lav2yuv_flags=$EXTRA_LAV2YUV 322yuvscaler_flags=$EXTRA_YUVSCALER 323mpeg2enc_flags=$EXTRA_MPEG2ENC 324lav2wav_flags=$EXTRA_LAV2WAV 325audioenc_flags=$EXTRA_AUDIOENC 326mplex_flags=$EXTRA_MPLEX 327yuvdenoise_flags=$EXTRA_YUVDENOISE 328 329# get output mpeg version and output file names 330case $mode in 331 vcd|vcd_medium|vcd_high|mpeg1) mpegver=1 ;; 332 svcd|svcd_high|mpeg2) mpegver=2 ;; 333esac 334 335if [ "$outfile" != "" ]; then 336 basename=${outfile%.*} 337else 338 basename=${1%.*} 339 outfile=${basename}.mpg 340fi 341video=${basename}.m${mpegver}v 342audio=${basename}.mp2 343 344if [ "$NOISYLOGFILE" = "" ]; then 345 noisylog=${basename}.log 346else 347 noisylog=$NOISYLOGFILE 348fi 349 350# set up the audio 351if [ "$userstereo" = "" ]; then 352 stereo=${audio_chans:-0} 353else 354 stereo=$userstereo 355fi 356 357if [ $AUDIOENC = "mp2enc" ]; then 358 nostereo_flag="-m" 359else 360 nostereo_flag="-a" 361fi 362 363if [ "$stereo" != "0" ]; then 364 aencbpr=$aencbpr_stereo 365else 366 aencbpr=$aencbpr_mono 367 mono_flag=$nostereo_flag 368fi 369# set useraencbpr to aencbpr unless set 370useraencbpr=${useraencbpr:-$aencbpr} 371 372# set up always-on flags 373lav2yuv_flags="$lav2yuv_flags $@" 374case $video_norm in 375 PAL) ysnorm="p";; 376 SECAM) ysnorm="s";; 377 NTSC|*) ysnorm="n";; 378esac 379yuvscaler_flags="-n $ysnorm $yuvscaler_flags" 380mpeg2enc_flags="-o $video $mpeg2enc_flags" 381lav2wav_flags="$lav2wav_flags $@" 382if [ $AUDIOENC = "mp2enc" ]; then 383 audioenc_flags="$mono_flag -r 44100 ${audioenc_flags} -o $audio" 384else 385 # assume toolame 386 audioenc_flags="$mono_flag -s 44.1 /dev/stdin ${audioenc_flags} $audio" 387fi 388mplex_flags=" -o $outfile $mplex_flags $audio $video" 389 390# input/output dependent 391if [ $video_width -eq $output_width -a $video_height -eq $output_height ]; then 392 needscale=0; 393else 394 needscale=1 395fi 396downscaling=0 397if [ $video_width -gt $output_width -o $video_width -eq $output_width ]; then 398 if [ $video_height -gt $output_height -o $video_height -eq $output_height ]; 399 then 400 downscaling=1 401 fi 402fi 403 404if [ "$video_inter" = "1" ]; then 405 yuvdenoise_flags="$yuvdenoise_flags -F" 406fi 407 408#encoder quality dependent 409case ${encode_quality} in 410 0) 411 mpeg2enc_flags="-4 4 -2 4 ${mpeg2enc_flags}" 412 if [ $downscaling -ne 0 ]; then 413 yuvscaler_flags="-M RESAMPLE ${yuvscaler_flags}" 414 fi 415 dodenoise=0 416 if [ "$userdenoise" != "" -a "$userdenoise" != "0" ]; then 417 logIt "set dodenoise to on at users request" 418 dodenoise=1 419 fi 420 ;; 421 2) 422 mpeg2enc_flags="-4 1 -2 1 ${mpeg2enc_flags}" # -N here? 423 dodenoise=1 424 if [ "$userdenoise" != "" -a "$userdenoise" = "0" ]; then 425 dodenoise=0 426 fi 427 ;; 428 1|*) 429 dodenoise=1 430 if [ "$userdenoise" != "" -a "$userdenoise" = "0" ]; then 431 dodenoise=0 432 fi 433 ;; 434esac 435 436# output(mode) dependent 437case ${mode} in 438 vcd) 439 yuvscaler_flags="-O VCD ${yuvscaler_flags}" 440 mpeg2enc_flags="-a 2 -f 1 ${mpeg2enc_flags}" 441 mplex_flags="-f 1 ${mplex_flags}" 442 ;; 443 vcd_medium) 444 yuvscaler_flags="-O VCD ${yuvscaler_flags}" 445 mpeg2enc_flags="-a 2 -f 2 -b ${VCD_MEDIUM_BR} ${mpeg2enc_flags}" 446 mplex_flags="-f 2 ${mplex_flags}" 447 ;; 448 vcd_high) 449 yuvscaler_flags="-O VCD ${yuvscaler_flags}" 450 mpeg2enc_flags="-a 2 -f 2 -b ${VCD_HIGH_BR} ${mpeg2enc_flags}" 451 mplex_flags="-f 2 ${mplex_flags}" 452 ;; 453 mpeg1) 454 yuvscaler_flags="-O SIZE_${output_width}x${output_height} ${yuvscaler_flags}" 455 mpeg2enc_flags="-f 0 -b ${bitrate} ${mpeg2enc_flags}" 456 mplex_flags="-f 0 ${mplex_flags}" 457 aencbpr=$useraencbpr 458 ;; 459 svcd) 460 yuvscaler_flags="-O SVCD ${yuvscaler_flags}" 461 mpeg2enc_flags="-a 2 -f 4 ${mpeg2enc_flags}" 462 mplex_flags="-f 4 ${mplex_flags}" 463 aencbpr=$useraencbpr 464 audioenc_flags="-e $audioenc_flags" 465 ;; 466 svcd_high) 467 yuvscaler_flags="-O SVCD ${yuvscaler_flags}" 468 mpeg2enc_flags="-a 2 -f 5 -b ${SVCD_HIGH_BR} -V ${SVCD_HIGH_BUFFSIZE} -q ${SVCD_HIGH_QUAL} ${mpeg2enc_flags}" 469 mplex_flags="-f 5 ${mplex_flags}" 470 aencbpr=$useraencbpr 471 audioenc_flags="-e $audioenc_flags" 472 ;; 473 mpeg2) 474 yuvscaler_flags="-O SIZE_${output_width}x${output_height} ${yuvscaler_flags}" 475 mpeg2enc_flags="-f 3 -b ${bitrate} -q $quality ${mpeg2enc_flags}" 476 mplex_flags="-V -f 3 ${mplex_flags}" 477 aencbpr=$useraencbpr 478 ;; 479esac 480 481if [ $dodenoise -ne 0 ]; then 482 yuvdenoise_str="| $NICE $YUVDENOISE $yuvdenoise_flags" 483else 484 yuvdenoise_str="" 485 logIt "not using yuvdenoiser, dodenoise=$dodenoise" 486fi 487 488if [ $needscale -ne 0 ]; then 489 yuvscale_str="| $NICE $YUVSCALER $yuvscaler_flags" 490else 491 yuvscale_str="" 492fi 493 494#final flags -- bitrate flag is -b for both mp2enc and toolame 495audioenc_flags="-b $aencbpr $audioenc_flags" 496 497 498# this is kinda nasty, but it ends up giving a somewhat clean loop at the 499# bottom without a whole lot of if's and such 500count=1; 501stepdesc[$count]="video encoding" 502step[$count]="$NICE $LAV2YUV $lav2yuv_flags $yuvdenoise_str $yuvscale_str | $NICE $MPEG2ENC $mpeg2enc_flags" 503 504count=2; 505stepdesc[$count]="audio encoding" 506step[$count]="$NICE $LAV2WAV $lav2wav_flags | $NICE $AUDIOENC $audioenc_flags" 507 508count=3; 509if [ $use_fifo -eq 1 ]; then 510 stepdesc[$count]="encoding with fifos" 511else 512 stepdesc[$count]="multiplexing" 513fi 514step[$count]="$NICE $MPLEX $mplex_flags" 515 516output_noisy="" 517if [ $noisy -ne 0 -a $logall -ne 0 ]; then 518 output_noisy="2>&1 | tee -a $noisylog" 519 echo "" > $noisylog 520fi 521if [ $noisy -eq 0 ]; then 522 if [ $logall -eq 0 ]; then 523 noisylog="/dev/null" 524 fi 525 echo "" > $noisylog 526 output_noisy=">>$noisylog 2>&1" 527fi 528 529detach="" 530if [ $use_fifo -ne 0 ]; then 531 detach="&"; 532 saveraw=0 533 rm -f $video $audio 534 mkfifo $video 535 mkfifo $audio 536fi 537 538logIt "using mode=$mode, stereo=$stereo audio bpr=$aencbpr" 539if [ $logall -ne 0 ]; then 540 logIt "logging everything to $noisylog" 541fi 542logIt "beginning conversion of $@ to $outfile" 543logIt "had $video_frames to encode" 544 545STARTALL=$SECONDS 546for stepnum in 1 2 3 547do 548 count=$stepnum 549 START=$SECONDS 550 if [ $stepnum -eq 3 -o $use_fifo -ne 1 ]; then 551 logIt "beginning ${stepdesc[$count]}" 552 if [ $LOGCOMMANDS != "0" ]; then 553 logIt "COMMAND=${step[$count]}" 554 fi 555 fi 556 if [ $stepnum -eq 3 ]; then 557 detach="" # don't detach the last stem (mplex) 558 fi 559 eval doStep $output_noisy $detach 560 RET=$? 561 if [ $RET -ne 0 ]; then 562 logIt "ugh! ${stepdesc[$count]} failed, bailing. used command:" 563 logIt "${step[$count]}" 564 cleanExit $RET 565 fi 566 if [ $stepnum -eq 3 -o $use_fifo -ne 1 ]; then 567 diff=$(getTimeDiff $START $SECONDS) 568 elapsed=$(expr $SECONDS - $START) 569 if [ "$elapsed" != "0" ]; then 570 fps=$(echo "scale=3; $video_frames / $elapsed " | bc) 571 logIt "finished ${stepdesc[$count]} ( took $diff - $fps fps)" 572 else 573 logIt "finished ${stepdesc[$count]} ( took $diff )" 574 fi 575 fi 576done 577 578END=$SECONDS 579diff=$(getTimeDiff $STARTALL $SECONDS) 580temp=$(expr $SECONDS - $STARTALL) 581if [ "$temp" != "0" ]; then # avoid divide by zero possibility 582 fps=$(echo "scale=3; $video_frames / $temp" | bc) 583 logIt "finished encoding (took $diff - $fps fps)" 584else 585 logIt "finished encoding (took $diff)" 586fi 587cleanExit 0 588