This file is indexed.

/usr/bin/lavtc.sh is in mjpegtools 1:1.9.0-0.5ubuntu7.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
#!/bin/sh
#
# lav2tc.bash - use transcode to convert MJPEG avi files to another 
#               video/audio format.
#
# copyright 2003 Shawn Sulma <mjpeg@athos.cx>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# Description:
#
# This is intended to be a fairly intelligent wrapper for the transcode
# utility when working with mjpeg files and the lav tools.  It assumes
# that you have transcode and the lavtools installed and available in the
# $PATH.
#
# Transcode can be found at:
# http://www.theorie.physik.uni-goettingen.de/~ostreich/transcode/
#
# It is written for bash specifically.  It _should_ be fairly portable with
# only minor changes to other important shells such as zsh and ksh.  It is
# not particularly compatible with the rather minimal sh implementation
# found in some Linux distros.  I don't know much about [t]csh, but doubt
# it's easily portable to that.
#
# I'm sure there are a few naive things left in this script. Constructive
# feedback is welcome.
#
# It doesn't do much checking for existence of codecs, or allow passing of
# arbitrary parameters to transcode (including codec-specific ones). 
# However I think it does manage to cover most of the common ground.  It
# does some simple range checking on many of the parameters.
#
# A useful feature is the ability to specify "--two-pass".  For most DIVX
# codecs (and some others), two pass encoding gives better overall results.
# This script manages the two pass process.  It generates a log file name
# for the first pass based on the output name.  When the first pass is done,
# it generates an md5sum of the log.  This allows the second pass to be
# interrupted.  When the script is run on the same output file again, it
# checks the md5sum of the log.  If it's valid, it assumes that the first
# pass is already successfully done and restarts only the second pass.  Yes,
# this can still break, but it's saved me much effort in converting.
#
# Transcode comes bundled with some plugins that are useful.  In particular,
# ivtc and smartdeinter.  These do inverse telecine and deinterlacing (based
# on SmartDub's deinterlacer which is rather nice).  However, I've found
# that yuvkineco and yuvdenoise sometimes (often) do a better job of inverse
# telecine or deinterlacing.  While there is support for some of the
# yuv4mpeg utilities in transcode as plugin filters, I've added here some
# additional capabilities that basically use yuvdenoise, yuvcorrect or
# yuvkineco as "pre-processors" for transcode.  Hiding the ugliness of this
# from someone who just wants a nice conversion is a good thing.  Of course,
# if you want to do something more complicated, please do, but this is
# intended to handle only modestly complex usage.
#
# As an additional "feature", this script automates the creation of an ogg
# media file from the transcoded file.  Ogg is a media container format,
# much like AVI.  Most people know ogg from Ogg Vorbis, which is a very good
# lossy audio codec.  The container format, though also accepts video
# streams.  Specifying "--ogg" on the command line will generate a separate
# ogg audio file (since most avi-aware codecs in transcode cannot handle ogg
# Vorbis).  After processing is complete, the script uses the 'ogmmerge'
# utility to combine the video and audio streams together into a single ogg
# file.  ogmmerge is not part of the ogg development download.  You can get
# it here: http://www.bunkus.org/videotools/ogmtools/
#
# Determining the correct video and audio bandwith to use is a bit annoying
# at times.  This script attempts to help with this by having some bandwidth
# estimation capabilities.  "--max-length" allows you to specify the maximum
# MiB to be used by the final output file.  The script will figure out the
# appropriate video bandwidth.  It also does some automatic calculation of
# audio bandwidths (essentially for mp3 56kbps for mono and 128kbps for
# stereo, and for vorbis/ogg, 48 and 96 respectively (Vorbis gives similar
# quality at those rates)).  If you specify the video and/or audio bitrates
# with -b and -a, those values are used, and not any calculated ones.  Smart
# users can do better than the calculation, but not too often.
#
# The default output codec is "xvidcvs".  This is the most up-to-date
# xvid/divx encoder.  If you do not have the necessary xvid libs around, you
# can specify another video code with "--videocodec".  Other typical values
# might be "odivx", "ffmpeg" or "xvid".
#
# I am partial to xvid.  You can find it here: http://www.xvid.org/
#
# Currently the script will process only one input file.  If you have
# multiple, you should create a edit list for them, and provide that edit
# list to the script as the input file.
#
# Most of the script is sanity-checking.  Or comments.  Or logging.
#
# Example usage:
#
# simple case:
#   lav2tc.bash -o out.avi -b 1000 -a 128 in.eli
#     use lots of defaults, no clipping, or resize or deinterlace, just use
#     1000kbps for video and 128kbps for audio)
#
# something more complicated:
#   lav2tc.bash -o out.avi --two-pass --max-length 700 in.eli
#     mostly use defaults, but do two-pass encoding, and determine the bitrates
#     necessary to fit the resulting output.avi onto an 80 min CDR )
#
#   lav2tc.bash --clip 20,20,10,10 --scale 0.75 -o out.avi -b 1000 in.eli
#     clip 20 pixels from the top and left and 10 from the bottom and right,
#     then scale the result by 75%.
#
#   lav2tc.bash --pulldown=kineco -o out.avi --ogg --luma 75 --chroma 75 in.eli
#     uses yuvkineco to perform inverse telecine, adjusts the luma and chroma
#     contrasts, and creates an ogg media file as output.  The final output is
#     written to "out.ogm".
# 
# Dependencies (script checks the availability of each as needed):
#	(always) getopt, which, dc, cut, tr, expr, lavinfo, transcode
#	(for two-pass automation) md5sum
# 	(for yuvdenoise deinterlace) yuvdenoise, yuvcorrect
#	(for yuvkineco inverse telecine) yuvkineco, yuvcorrect
#	(for "--ogg") ogmmerge
#
# History:
#	This script replaces the lav2divx utility
#	2003-06-01: Initial version (Shawn Sulma)
#

appName=`basename ${0}`
appVersion="0.1"

#
# Helpers.  These might some day belong in an include script file themself.
#
assertExists ()
{
	[ -x `which ${1}` ] || log_fail ${1} not found. ${2}${2+ requires this.}
}

assertNumber ()
{
	if [[ `expr "${1}" : "[0-9${3}]*" 2> /dev/null` -ne ${#1} ]] ; then
		log_error "${2}${2+:} \"${1}\" is not a valid value"
		exit 1;
	fi
}

assertRange ()
{
	assertNumber ${1} ${3}
	if [[ ${1} -lt 0 || ${1} -gt ${2} ]] ; then
		log_error "${3}${3+:} \"${1}\" outside allowed range 0-${2}"
		exit 1 ;
	fi
}

#
# parse a string into multiple parts separated by any of "xX,._+:-".  This is useful
# for geometry strings: "000x000+000+000".  It ignores the separators.  The result is
# stored in the array ${geometry}
#
parseGeometry ()
{
	geometry=(`echo "${1}" | tr ' xX,._+:-' '         '`)
}

#
# logging mechanism.  It handles different levels of output.  Yes, it's not
# too efficient, but this is a wrapper script, and performance of this script
# is not required to be stellar.
#
debug=3
info=2
warn=1
error=0
logLevelText=( "**ERROR" "## WARN" "== INFO" "--DEBUG" )

log_debug () { __log ${debug} $* ; }
log_info () { __log ${info} $* ; }
log_warn () { __log ${warn} $* ; }
log_error () { __log ${error} $* ; }
log_fail () { __log ${error} $* ; exit 1 ; }
__log ()
{
	if [[ ${logLevel=2} -ge ${1} ]] ; then
		level=${1}
		shift
		echo "${logLevelText[${level}]}: [${appName}] $*" >&2
	fi
}

#
# Usage and Help display
#
usage ()
{
	cat << EOF
${appName} ${appVersion} - a transcode wrapper script for lavtools

Usage:    ${appName} -o <output file> [options] <input file>
For help: ${appName} -h

EOF
}

helptext ()
{
	usage
	cat << EOF
Options:
  -h | --help		  this help output
  -o | --output=<file>	  output to <file>
  -b | --videorate=<n>	  use <n> kilobits/second as the video bitrate
  -a | --audiorate=<n>	  use <n> kilobits/second as the audio bitrate
  -m | --mono		  convert the audio to mono before encoding
  -v | --verbose=<n>	  select verbosity level (0-3, higher outputs more)
  --maxlength=<n>	  calculate video bandwidth for output size <n> MiB
  --two-pass		  perform two-pass encoding where possible
  --clip=<t>,<l>,<b>,<r>  clip number of pixels from top, left, bottom, right
  --frame=<w>x<h>+<x>+<y> use the specified frame geometry (clip to)
  --resize=<w>,<h>	  resize to specified width and height
  --scale=<scale>	  scale by the factor <scale> (1.00 = 100%)
  --deinterlace[=<type>]  set deinterlace/inverse telecine type
 			  (type is "smart", "denoise", "kineco" or "ivtc")
  --line-switch		  swap lines prior to processing
  --luma=<contrast>	  set luma contrast
  --chroma=<contrast>	  set chroma contrast (saturation)
  --frames=<from>-<to>	  only process frames <from> through <to>
  --frames=<number>	  only process first <number> frames
  --status-delay=<frames> update status line every <frames> frames
  --videocodec=<codec>	  use the specified codec (xvid, ffmpeg, etc)
  --grayscale		  convert to black and white
  --quality=<n>		  use quality level <n> (1-5, default 5)
  --crispness=<n>	  use crispness <n> (default 100)
  --ogg			  generate an ogg media file (use Vorbis not MP3)
  --norm={n,p}		  declare norm to be "n" or "p" (passed to preprocess)

EOF
}

parseParams ()
{
args=`getopt -n ${appName} -o o:b:a:mv:hV -l  output:,videorate:,audiorate:,mono,verbose:,max-length:,two-pass,ogg,clip:,frame:,scale:,deinterlacer::,pulldown::,deinterlace::,line-switch,luma:,chroma:,frames:,status-delay:,grayscale,videocodec:,crispness:,quality:,resize:,scale:,help,norm:,greyscale,version,norm: -- "$@"`

	if [ $? != 0 ] ; then
		log_fail "Cannot continue."
	fi
	eval set -- "$args"
	while true ; do
		case "${1}" in
			-h|--help) helptext >&2 ; exit 0;;
			-o|--output) output="${2}" ; shift 2 ;;
			-b|--video-rate) 
				assertNumber ${2} "video bandwidth"
				videoBW="${2}" ; 
				shift 2 ;;
			-a|--audio-rate) 
				assertNumber ${2} "audio bandwidth" ; 
				audioBW="${2}" ;
				shift 2 ;;
			-m|--mono) audioOutChannels=1 ; shift ;;
			-v|--verbose) 
				assertRange ${2} 3 "verbosity level" ;
				logLevel=${2} ; 
				shift 2 ;;
			--max-length) 
				assertNumber ${2} "maximum output size"  ; 
				maxlength="${2}" ; 
				shift 2 ;;
			--two-pass) 
				assertExists md5sum "${1}" ;
				twopass=1 ; 
				shift ;;
			--ogg) 
				assertExists ogmmerge "${1}" ;
				ogg=1 ; 
				shift ;;
			--clip) clip="${2}" ; shift 2 ;;
			--frame) frame="${2}" ; shift 2 ;;
			--line-switch) flip=1 ; shift ;;
			--resize) resize="${2}" ; shift 2 ;;
			--scale) 
				videoScale="${2}" ; 
				assertNumber ${2} "video scaling factor" . ; 
				shift 2 ;;
			--deinterlace*|--pulldown)
				case "${2}" in
					denoise|kineco)
						assertExists yuv${2} "${1} ${2}"
						deinterlacer="${2}" ;;
					smart|ivtc)
						deinterlacer="${2}" ;;
					"") deinterlacer="smart" ;;
					*) log_fail "Unknown deinterlacer type: ${2}" ;;
				esac ; shift 2 ;;
			--luma) 
				assertNumber ${2} "luma contrast" ; 
				assertExists yuvdenoise "${1}"
				lumaContrast="${2}" ; 
				shift 2 ;;
			--chroma) 
				assertNumber ${2} "chroma contrast" ;
				assertExists yuvdenoise "${1}"
				chromaContrast="${2}" ; 
				shift 2 ;;
			--frames) frameRange="${2}" ; shift 2 ;;
			--status-delay) 
				assertNumber ${2} "status display delay" ;
				delay="${2}" ;
				shift 2 ;;
			--grayscale|--greyscale) grayscale="1" ; shift ;;
			--videocodec) videoOutCodec="${2}" ; shift 2 ;;
			--quality) 
				assertNumber ${2} "quality" ;
				quality="${2}" ; 
				shift 2 ;;
			--crispness) 
				assertNumber ${2} "crispness" ; 
				crispness="${2}" ; 
				shift 2 ;;
			--norm) norm="${2}" ; shift 2 ;;
			-V|--version) usage ; exit 0 ;;
			--) shift ; break ;;
			*) log_fail "Internal error at ${1}" ;;
		esac
	done
	# transcode can only handle one file input.  This script will eventually 
	# handle more, but for now...
	inFile="${1}"
	if [[ -z ${output} ]] ; then
		log_error "output file required"
		usage
		exit 1;
	elif [[ -z ${inFile} ]] ; then
		log_error "one input file required"
		usage
		exit 1;
	elif [ ! -e ${inFile} ] ; then
		log_fail "input file ${inFile} does not exist"
	fi
}

#
# read information about the input file.  There's probably a better way to
# do this, but this works well enough.
#
readHeader ()
{
	header="`lavinfo ${norm++}${norm} ${inFile}`"
	for line in ${header} ; do
		value=`echo ${line} | cut -d '=' -f2`
		case "${line}" in
			video_width*) videoWidth=${value} ;;
			video_height*) videoHeight=${value} ;;
			video_fps*) videoFrameRate=${value} ;;
			video_inter*) videoIsInterlaced=${value} ;;
			video_frames*) totalFrames=${value} ;;
			audio_bits*) audioInBits=${value} ;;
			audio_chans*) audioInChannels=${value} ;;
			audio_rate*) audioInRate=${value} ;;
			num_video_files*) numVideoFiles=${value} ;;
		esac
	done
	videoSeconds=`dc -e "0 k ${totalFrames} ${videoFrameRate} / p"`
}

#
# For kineco and yuvdenoise deinterlace, a fifo is required.  Ensure one
# exists, and clean up when we're done with it.
#
ensureFifo ()
{
	fifo="${outputBaseName}.fifo"
	if [ -p ${fifo} ] ; then
		log_debug "Fifo already established"
	elif [ -e ${fifo} ] ; then
		log_fail "${fifo} is not a FIFO.  Cannot continue." ;
	else
		log_debug "Creating fifo ${fifo}"
		log_debug mkfifo ${fifo}
		mkfifo ${fifo}
		needToCleanupFifo=1
	fi
}
cleanupFifo ()
{
	if [ -p ${fifo} ] ; then
		log_debug "removing fifo ${fifo}"
		log_debug rm ${fifo}
		rm ${fifo}
	fi
}

#
# If we're not using a pre-processing pipe, we can perform line switching
# through a filter plugin.
#
setFlipArgs ()
{
	if [[ ${flip=0} = 1 && ${videoIsInterlaced} = 1 ]] ; then 
		flipArgs="-J fields=flip"
	fi
}

#
# Set up for handling the different types of deinterlacers and inverse telecine
# filters.  Some require separate filter entries, while others need pre-
# processing pipelines.  The latte introduces complications because now the
# audio has to be passed to transcode separately.
#
setDeinterlaceArgs ()
{
	# set up for deinterlacing.  In some cases, the actual deinterlacing 
	# is finally triggered elsewhere.
	#
	# get the audio and video from the input file (default case)
	#
	inputFile="${inFile}"
	inputVideoCodec="lav"
	if [[ ${videoIsInterlaced} == 0 || ${deinterlacer=none} == "none" ]] ; then
		deinterlacerText="No deinterlacing"
		setFlipArgs
	elif [ ${deinterlacer} = "smart" ] ; then
		deinterlacerText="SmartDub deinterlacer"
		deinterlaceArgs="-J smartdeinter=cubic=1:diffmode=2:highq=1"
		setFlipArgs
	elif [ ${deinterlacer} = "ivtc" ] ; then
		deinterlacerText="Transcode ivtc inverse telecine"
		deinterlaceArgs="-J ivtc,32detect=force_mode=5,decimate"
		setFlipArgs
	else
		ensureFifo
		#
		# We have to turn off auto-probing.  Thus we have to provide
		# information about the video and audio input ourselves.
		#
		cineRate=`dc -e "6 k 24000 1001 / p"`
		deinterlaceArgs="-H 0 -f ${cineRate},1 -M 0 -g ${videoWidth}x${videoHeight} -e ${audioInRate},${audioInBits},${audioInChannels}"
		#
		# get the video from the fifo and the audio from the input
		#
		inputFile="${fifo} -p ${inFile}"
		inputVideoCodec="yuv4mpeg"
		inputAudioCodec=",lav"
		if [ ${deinterlacer} = "denoise" ] ; then
			# in theory, the builtin yuvdenoise filter plugin should
			# be able to do this.  In practise, I could not find a 
			# practical way to tell it to _only_ deinterlace.
			deinterlacerText="yuvdenoise deinterlacer"
		elif [ ${deinterlacer} = "kineco" ] ; then
			#
			# yuvkineco 1 pass inverse telecine
			#
			deinterlacerText="yuvkineco inverse telecine"
			# since the incoming stream is now at a different frame rate, we need
			# to recalculate the number of frames that can be seen and used by transcode
			totalFrames=`dc -e "8 k ${cineRate} ${videoFramesRate} / ${totalFrames} * 0 k 1 + 1 / p"`
		else
			log_fail "Unknown deinterlacer/pulldown: ${deinterlacer}"
		fi
	fi
}

setAudioArgs ()
{
	#
	# if there's no audio, don't bother with it.
	#
	if [[ ${audioInChannels} -gt 0 ]] ; then
		#
		# keep the same bitrate and sample size
		#
		audioOutBits=${audioInBits}
		audioOutRate=${audioInRate}
		if [[ -z ${audioOutChannels} ]] ; then
			audioOutChannels=${audioInChannels}
		fi
		#
		# If the output bitrate isn't set, determine it.
		#
		if [[ -z ${audioBW} ]] ; then
			if [[ -n ${ogg} ]] ; then
				# Ogg Vorbis compresses better
				let audioBW="48*${audioOutChannels}"
			else
				if [ ${audioOutChannels} = 1 ] ; then
					audioBW=56
				else
					let audioBW="64*${audioOutChannels}"
				fi
			fi
		fi
		audioArgs="-E ${audioOutRate},${audioOutBits},${audioOutChannels} -b ${audioBW}"
		if [[ -n ${ogg} ]] ; then
			oggName="${outputBaseName}.audio.ogg"
		fi
	fi
}

setVideoBW ()
{
	if [[ -n ${maxlength} ]] ; then
		#
		# if not set, guess an appropriate bandwidth.
		# This is, in some ways, a voodoo calculation.  Well, to be
		# precise, I'm guessing at the additional 6 bytes of overhead
		# per frame.  In practise, I've found this calculation is
		# actually quite useful; conservative without being too much so.
		#
		let availableBytes="${maxlength}*1024*1024"
		# bandwidth calculation
		let bytesIndex="${totalFrames}*8"
		let bytesAudio="${videoSeconds}*${audioBW-0}*128"
		let bytesOverhead="${totalFrames}*6"
		let remainder="${availableBytes}-${bytesAudio}-${bytesIndex}-${bytesOverhead}"
		bandwidth=`dc -e "${remainder} ${videoSeconds} / 128 / p"`
	fi
	videoBW=${videoBW-${bandwidth-1000}}
}

setClipArgs ()
{
	if [[ -n ${clip} ]] ; then
		parseGeometry ${clip}
		clipTop=${geometry[0]}
		clipLeft=${geometry[1]}
		clipBottom=${geometry[2]}
		clipRight=${geometry[3]}
	elif [[ -n ${frame} ]] ; then
		parseGeometry ${frame}
		assertRange ${geometry[0]} ${videoWidth} "frame width"
		assertRange ${geometry[1]} ${videoHeight} "frame height"
		assertRange ${geometry[2]} ${videoWidth} "frame x offset"
		assertRange ${geometry[3]} ${videoHeight} "frame y offset"
		#
		# convert the geometry string to clipping pixels.
		#
		let clipBottom=${videoHeight}-${geometry[1]}-${geometry[3]}
		let clipTop=${geometry[3]}
		let clipRight=${videoWidth}-${geometry[0]}-${geometry[2]}
		let clipLeft=${geometry[2]}
	fi
	assertRange ${clipTop=0} ${videoHeight} "top clipping parameter"
	assertRange ${clipBottom=0} ${videoHeight} "bottom clipping parameter"
	assertRange ${clipLeft=0} ${videoWidth} "left clipping parameter"
	assertRange ${clipRight=0} ${videoWidth} "right clipping paramter"
	let totalClipped="${clipTop}+${clipBottom}+${clipRight}+${clipLeft}"
	if [ ${totalClipped} != 0 ] ; then
		clippingArgs="-j ${clipTop},${clipLeft},${clipBottom},${clipRight}"
	fi
}

setResizeArgs ()
{
	let clippedHeight="${videoHeight}-${clipTop}-${clipBottom}"
	let clippedWidth="${videoWidth}-${clipLeft}-${clipRight}"
	if [[ -n ${resize} ]] ; then
		videoOutWidth=${resize%%[x./-, ]*}
		videoOutHeight=${resize##*[x./-, ]}
		assertNumber ${videoOutWidth} "target width"
		assertNumber ${videoOutHeight} "target height"
	else
		assertNumber ${videoScale} "output scaling factor" .
		videoScale=${videoScale-1.00}
		videoOutWidth=`dc -e "0 k ${clippedWidth} ${videoScale} * 1 / p"`
		videoOutHeight=`dc -e "0 k ${clippedHeight} ${videoScale} * 1 / p"`
	fi
	if [[ ${videoOutHeight} != ${clippedHeight} || ${videoOutWidth} != ${clippedWidth} ]] ; then
		resizeArgs="-Z ${videoOutWidth}x${videoOutHeight}"
	fi
}

setEnhanceArgs ()
{
	[[ -n "${lumaContrast}" || -n "${chromaContrast}" ]] && enhanceArgs="-J yuvdenoise=mode=2"
	[[ -n ${lumaContrast} ]] && enhanceArgs="${enhanceArgs}:luma_contrast=${lumaContrast}"
	[[ -n ${chromaContrast} ]] && enhanceArgs="${enhanceArgs}:chroma_contrast=${chromaContrast}"
	[[ -n ${grayscale} ]] && enhanceArgs="-K ${enhanceArgs}"
}

setFramesRangeArgs ()
{
	if [[ `expr "${frameRange=0}" : "[0-9]*[^0-9][0-9]*" 2> /dev/null` -eq ${#frameRange} ]] ; then 
		firstFrame="${frameRange%%[.,-]**}"
		lastFrame="${frameRange##*[.,-]}"
	else
		firstFrame=1
		lastFrame=${frameRange}
		assertNumber ${lastFrame} "frames to encode"
	fi
	if [[ -z $firstFrame ]] ; then 
		firstFrame=0 ;
	fi
	if [[ -z $lastFrame ]] ; then 
		lastFrame=0 ; 
	fi
	# normalise negatives
	if [ ${firstFrame} -lt 0 ] ; then
		let firstFrame=${totalFrames}${firstFrame}
	fi
	if [ ${lastFrame} -lt 0 ] ; then
		let lastFrame=${totalFrames}${lastFrame}
	fi
	# now check for valid ranges.
	if [ ${firstFrame} = 0 -a ${lastFrame} = 0 ] ; then
		firstFrame=1
		lastFrame=${totalFrames}
	elif [ ${lastFrame} = 0 ] ; then
		lastFrame=${firstFrame}
		firstFrame=1
	elif [ ${firstFrame} = 0 ] ; then
		firstFrame=1
	fi
	# upper bounds
	if [ ${lastFrame} -gt ${totalFrames} ] ; then
		lastFrame=${totalFrames}
	fi
	if [ ${firstFrame} -gt ${lastFrame} ] ; then
		firstFrame=${lastFrame}
	fi
	# generate arg
	framesRangeArgs="-c ${firstFrame}-${lastFrame}"
}

setStatusArgs ()
{
	if [[ ${logLevel} -lt 2 ]] ; then
		statusArgs="-q 0" ;
	elif [[ ${logLevel} -eq 2 ]] ; then
		statusArgs="-q 1" ;
		statusOnly="1" ;
	else
		statusArgs="-q 1" ;
	fi
	if [[ ${logLevel} -gt 0 ]] ; then
		delayArgs=" --print_status ${delay=1} "
	fi
}

initialize ()
{
outputBaseName="${output%.*}"
readHeader
setDeinterlaceArgs
setAudioArgs
setClipArgs
setResizeArgs
setEnhanceArgs
setFramesRangeArgs
setStatusArgs
setVideoBW

	videoOutCodec="${videoOutCodec-xvidcvs}"
	quality="${quality-5}"
	crispness="${crispness-144}"
	log_info "encoding ${inFile}"
	log_info "input video: ${videoWidth}x${videoHeight}"
	log_info "input total length: ${totalFrames} frames (${videoSeconds} seconds)"
	log_info "deinterlace type: ${deinterlacer} (input is " `if [[ ${videoIsInterlaced} == 0 ]] ; then echo -n "not " ; fi ` " interlaced)"
	if [[ ${audioInChannels} == 0 ]] ; then
		log_info "no audio on input"
	else
		log_info "input audio: ${audioInRate},${audioInBits},${audioInChannels}"
		log_info "output audio: ${audioOutRate},${audioOutBits},${audioOutChannels}"
		log_info "output audio bandwidth: ${audioBW}"
		if [[ -n ${ogg} ]] ; then
			log_info "using ogg vorbis for audio "
		fi
	fi
	log_info "clipping: left ${clipLeft-0}, top ${clipTop-0}, right ${clipRight-0}, bottom ${clipBottom-0}"
	log_info "resize scale: ${videoScale-n/a}, result ${videoOutWidth}x${videoOutHeight}"
	log_info "contrast: ${lumaContrast-n/a}, saturation: ${chromaContrast-n/a}"
	log_info "encoding frames: ${firstFrame} to ${lastFrame}"
	log_info "video bandwidth: estimated ${bandwidth-n/a}, used ${videoBW}"
	log_info "transcode video out codec: ${videoOutCodec}"

transcodeArgs="\
-i ${inputFile} \
${clippingArgs} \
${resizeArgs} \
${flipArgs} \
${deinterlaceArgs} \
${enhanceArgs}
${audioArgs} \
-Q ${quality} \
-o ${output} \
-w ${videoBW},,${crispness} \
-V -k ${framesRangeArgs} ${statusArgs} ${delayArgs}"

}

#
#
# Main section of the script. It handles the creation of the pipeline 
# (if necessary) as well as the management of two pass encodings (i.e. the log
# file and running the separate passes).
#
#
for required in expr transcode dc getopt cut tr lavinfo ; do
	[ -x `which ${required}` ] || log_fail "${required} not found.  Cannot continue."
done
parseParams "$@"
initialize
pass=1
while [ ${pass} != 2 ] ;
do
	if [[ -n ${twopass} ]] ; then
		passArgs=""
		if ( md5sum -c ${outputBaseName}.pass1.md5sum &> /dev/null ) then
			# if [[ ${pass} = 3 ]] ; then
			pass=2
			inputAudioCodec=""
			if [[ -n ${ogg} ]] ; then
				passArgs="-m ${oggName}"
				outputAudioCodec=",ogg"
			else
				outputAudioCodec=""
			fi
			log_info "Valid first pass log_file found"
		else
			pass=1
			log_warn "First pass log_file not found or not valid"
			log_debug "removing spurious first pass log_file."
			log_debug "rm ${outputBaseName}.pass1.log &> /dev/null"
			rm ${outputBaseName}.pass1.log &> /dev/null
			passArgs=""
			outputAudioCodec=",null"
			inputAudioCodec=",null"
		fi
		passArgs="-R ${pass},${outputBaseName}.pass1.log ${passArgs}"
	else
		# single pass.
		log_info "single pass encoding only." >&2
	fi

	log_info "beginning pass ${pass}" >&2
	# set up pipeline if needed (using kineco or yuvdenoise deinterlacer)
	if [[ ${videoIsInterlaced} = 1 && ( "${deinterlacer}" = "kineco" || "${deinterlacer}" = "denoise" ) ]] ; then 
		if [[ -n ${flip} ]] ; then
			corrector="yuvcorrect -v 0 -T LINE_SWITCH"
		else
			corrector="cat"
		fi
		if [ ${deinterlacer} == "kineco" ] ; then
			deinterlaceCmd="yuvkineco -F 1 "
		else
			deinterlaceCmd="yuvdenoise -I -v 0 "
		fi
		log_info "invoking deinterlacer/pulldown thread"
		log_debug "lav2yuv ${inFile} | ${corrector} | ${deinterlaceCmd} > ${fifo} &"
		lav2yuv ${inFile} | ${corrector} | ${deinterlaceCmd} > ${fifo} &
	fi
	if [[ "${audioInChannels}" == 0 ]] ; then
		inputAudioCodec=",null"
		outputAudioCodec=",null"
	elif [[ ${pass} == 2 ]] ; then
		inputAudioCodec=",lav"
	fi
	inputCodecArgs="-x ${inputVideoCodec}${inputAudioCodec}"
	outputCodecArgs="-y ${videoOutCodec}${outputAudioCodec}"
	#
	# this is the big call
	#
	log_debug `for arg in /usr/local/bin/transcode ${passArgs} ${transcodeArgs} ${inputCodecArgs} ${outputCodecArgs} ; do echo -n "${arg} " ; done` " <EOL>"
	/usr/local/bin/transcode \
		${passArgs} \
		${transcodeArgs} \
		${inputCodecArgs} \
		${outputCodecArgs} 
	errcode=$?
	# errcode=0
	if [ ${errcode} != 0 ] ; then
		exit ${errcode}
	fi
	if [[ -n ${twopass} ]] ; then
		if [ ${pass} = 1 ] ; then
			log_debug "md5sum ${outputBaseName}.pass1.log >  ${outputBaseName}.pass1.md5sum"
			md5sum ${outputBaseName}.pass1.log > ${outputBaseName}.pass1.md5sum
		else
			log_debug "mv ${outputBaseName}.pass1.log ${outputBaseName}.pass1.log.old"
			mv ${outputBaseName}.pass1.log ${outputBaseName}.pass1.log.old
		fi
	else
		break;
	fi
done
if [[ -n ${needToCleanupFifo} ]]; then
	cleanupFifo ;
fi
log_debug "chmod -x ${output}"
chmod -x ${output}
if [[ -n ${ogg} && ${audioInChannels} -gt 0 ]] ; then
	# need to merge the two together.
	log_debug "using ogmmerge to generate ogg media file"
	log_debug "ogmmerge -o ${outputBaseName}.ogm -D ${output} -A ${oggName}"
	ogmmerge -o ${outputBaseName}.ogm -A ${output} -D ${oggName}
fi