about summary refs log tree commit diff
path: root/converter/ppm/ppmtompeg
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2006-08-19 03:12:28 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2006-08-19 03:12:28 +0000
commit1fd361a1ea06e44286c213ca1f814f49306fdc43 (patch)
tree64c8c96cf54d8718847339a403e5e67b922e8c3f /converter/ppm/ppmtompeg
downloadnetpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.gz
netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.xz
netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.zip
Create Subversion repository
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'converter/ppm/ppmtompeg')
-rw-r--r--converter/ppm/ppmtompeg/BUGS43
-rw-r--r--converter/ppm/ppmtompeg/CHANGES180
-rw-r--r--converter/ppm/ppmtompeg/COPYRIGHT20
-rw-r--r--converter/ppm/ppmtompeg/HISTORY313
-rw-r--r--converter/ppm/ppmtompeg/LOGIC126
-rw-r--r--converter/ppm/ppmtompeg/Makefile140
-rw-r--r--converter/ppm/ppmtompeg/bframe.c1347
-rw-r--r--converter/ppm/ppmtompeg/bitio.c536
-rw-r--r--converter/ppm/ppmtompeg/block.c1045
-rw-r--r--converter/ppm/ppmtompeg/bsearch.c1088
-rw-r--r--converter/ppm/ppmtompeg/combine.c357
-rw-r--r--converter/ppm/ppmtompeg/docs/EXTENSIONS41
-rw-r--r--converter/ppm/ppmtompeg/docs/INPUT.FORMAT79
-rw-r--r--converter/ppm/ppmtompeg/docs/parallel.param142
-rw-r--r--converter/ppm/ppmtompeg/docs/param-summary14
-rw-r--r--converter/ppm/ppmtompeg/docs/template.param154
-rw-r--r--converter/ppm/ppmtompeg/docs/users-guide.ps3233
-rw-r--r--converter/ppm/ppmtompeg/examples/basicspeed.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/decoded.test81
-rw-r--r--converter/ppm/ppmtompeg/examples/decoded2.test81
-rw-r--r--converter/ppm/ppmtompeg/examples/decorig.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/default.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/fastspeed.param46
-rw-r--r--converter/ppm/ppmtompeg/examples/foobar.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/frame.test37
-rw-r--r--converter/ppm/ppmtompeg/examples/gop.combine11
-rw-r--r--converter/ppm/ppmtompeg/examples/gop.test43
-rw-r--r--converter/ppm/ppmtompeg/examples/gop1.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/hello.param60
-rw-r--r--converter/ppm/ppmtompeg/examples/i.test37
-rw-r--r--converter/ppm/ppmtompeg/examples/ispeed.jpeg.param48
-rw-r--r--converter/ppm/ppmtompeg/examples/ispeed.param45
-rw-r--r--converter/ppm/ppmtompeg/examples/jpeg.test66
-rw-r--r--converter/ppm/ppmtompeg/examples/jpeg19.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/jpegout19.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/localdisk.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/localremote.test80
-rw-r--r--converter/ppm/ppmtompeg/examples/luxo.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/luxo18.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/luxo19.5.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/luxo19.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/luxo2.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/luxo48.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/luxo49.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/luxo50.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/luxo52.5.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/luxo52.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/luxo53.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/luxobug.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/luxoskip.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/med.param36
-rw-r--r--converter/ppm/ppmtompeg/examples/med18.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/medspeed.param38
-rw-r--r--converter/ppm/ppmtompeg/examples/nametest.param60
-rw-r--r--converter/ppm/ppmtompeg/examples/nosearch.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/par3.param43
-rw-r--r--converter/ppm/ppmtompeg/examples/par4.param45
-rw-r--r--converter/ppm/ppmtompeg/examples/par5.param47
-rw-r--r--converter/ppm/ppmtompeg/examples/parallel.287
-rw-r--r--converter/ppm/ppmtompeg/examples/parallel.param141
-rw-r--r--converter/ppm/ppmtompeg/examples/parallel.test85
-rw-r--r--converter/ppm/ppmtompeg/examples/param.template107
-rw-r--r--converter/ppm/ppmtompeg/examples/payam.param37
-rw-r--r--converter/ppm/ppmtompeg/examples/payam18.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/pnm.param37
-rw-r--r--converter/ppm/ppmtompeg/examples/ppm.param37
-rw-r--r--converter/ppm/ppmtompeg/examples/prof.b.param48
-rw-r--r--converter/ppm/ppmtompeg/examples/prof.bhalf.param48
-rw-r--r--converter/ppm/ppmtompeg/examples/prof.param36
-rw-r--r--converter/ppm/ppmtompeg/examples/prof.ss.param48
-rw-r--r--converter/ppm/ppmtompeg/examples/prof2.param36
-rw-r--r--converter/ppm/ppmtompeg/examples/prof3.param36
-rw-r--r--converter/ppm/ppmtompeg/examples/prof4.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/remote.test85
-rw-r--r--converter/ppm/ppmtompeg/examples/search1.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search10.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search11.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search12.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search13.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search14.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search15.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search16.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search17.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search18.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search19.5.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/search19.param42
-rw-r--r--converter/ppm/ppmtompeg/examples/search2.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search20.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search21.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search22.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search23.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search24.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search25.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search26.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search27.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search28.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search29.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search3.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search30.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search31.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search32.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search33.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search34.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search35.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search36.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search37.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search38.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search39.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search4.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search40.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search41.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search42.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search43.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search44.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search45.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search46.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search47.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search48.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/search49.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/search5.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search50.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/search51.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search52.5.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/search52.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/search53.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/search6.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search7.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search8.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/search9.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/seq.param36
-rw-r--r--converter/ppm/ppmtompeg/examples/sequoia.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/sequoia19.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/sequoia2.param36
-rw-r--r--converter/ppm/ppmtompeg/examples/simple.param40
-rw-r--r--converter/ppm/ppmtompeg/examples/slice.param47
-rw-r--r--converter/ppm/ppmtompeg/examples/slimed.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/slowspeed.param38
-rw-r--r--converter/ppm/ppmtompeg/examples/stanford.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/subtest.param34
-rw-r--r--converter/ppm/ppmtompeg/examples/temp.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/template.param154
-rw-r--r--converter/ppm/ppmtompeg/examples/tennis.param37
-rw-r--r--converter/ppm/ppmtompeg/examples/tennis18.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/tennis19.5.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/tennis19.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/tennis48.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/tennis49.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/tennis50.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/tennis52.5.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/tennis52.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/tennis53.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/tennisbug.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/testp.param45
-rw-r--r--converter/ppm/ppmtompeg/examples/walk.param61
-rw-r--r--converter/ppm/ppmtompeg/examples/walk1.param61
-rw-r--r--converter/ppm/ppmtompeg/examples/walk18.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/walk19.5.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/walk19.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/walk2.param61
-rw-r--r--converter/ppm/ppmtompeg/examples/walk3.param61
-rw-r--r--converter/ppm/ppmtompeg/examples/walk4.param61
-rw-r--r--converter/ppm/ppmtompeg/examples/walk48.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/walk49.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/walk5.param62
-rw-r--r--converter/ppm/ppmtompeg/examples/walk50.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/walk52.5.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/walk52.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/walk53.param35
-rw-r--r--converter/ppm/ppmtompeg/examples/walk93.param62
-rw-r--r--converter/ppm/ppmtompeg/file.c322
-rw-r--r--converter/ppm/ppmtompeg/frame.c836
-rw-r--r--converter/ppm/ppmtompeg/frametype.c365
-rw-r--r--converter/ppm/ppmtompeg/fsize.c134
-rw-r--r--converter/ppm/ppmtompeg/gethostname.c26
-rw-r--r--converter/ppm/ppmtompeg/gethostname.h7
-rw-r--r--converter/ppm/ppmtompeg/headers/all.h95
-rw-r--r--converter/ppm/ppmtompeg/headers/ansi.h76
-rw-r--r--converter/ppm/ppmtompeg/headers/bitio.h140
-rw-r--r--converter/ppm/ppmtompeg/headers/block.h53
-rw-r--r--converter/ppm/ppmtompeg/headers/byteorder.h77
-rw-r--r--converter/ppm/ppmtompeg/headers/combine.h20
-rw-r--r--converter/ppm/ppmtompeg/headers/dct.h79
-rw-r--r--converter/ppm/ppmtompeg/headers/frame.h147
-rw-r--r--converter/ppm/ppmtompeg/headers/frames.h487
-rw-r--r--converter/ppm/ppmtompeg/headers/frametype.h17
-rw-r--r--converter/ppm/ppmtompeg/headers/fsize.h49
-rw-r--r--converter/ppm/ppmtompeg/headers/general.h174
-rw-r--r--converter/ppm/ppmtompeg/headers/huff.h34
-rw-r--r--converter/ppm/ppmtompeg/headers/input.h70
-rw-r--r--converter/ppm/ppmtompeg/headers/jpeg.h12
-rw-r--r--converter/ppm/ppmtompeg/headers/mheaders.h114
-rw-r--r--converter/ppm/ppmtompeg/headers/motion_search.h154
-rw-r--r--converter/ppm/ppmtompeg/headers/mpeg.h116
-rw-r--r--converter/ppm/ppmtompeg/headers/mproto.h132
-rw-r--r--converter/ppm/ppmtompeg/headers/mtypes.h109
-rw-r--r--converter/ppm/ppmtompeg/headers/opts.h125
-rw-r--r--converter/ppm/ppmtompeg/headers/parallel.h135
-rw-r--r--converter/ppm/ppmtompeg/headers/param.h87
-rw-r--r--converter/ppm/ppmtompeg/headers/postdct.h40
-rw-r--r--converter/ppm/ppmtompeg/headers/prototypes.h78
-rw-r--r--converter/ppm/ppmtompeg/headers/psocket.h41
-rw-r--r--converter/ppm/ppmtompeg/headers/rate.h204
-rw-r--r--converter/ppm/ppmtompeg/headers/readframe.h69
-rw-r--r--converter/ppm/ppmtompeg/headers/rgbtoycc.h39
-rw-r--r--converter/ppm/ppmtompeg/headers/specifics.h36
-rw-r--r--converter/ppm/ppmtompeg/huff.c131
-rw-r--r--converter/ppm/ppmtompeg/huff.h34
-rw-r--r--converter/ppm/ppmtompeg/huff.table172
-rw-r--r--converter/ppm/ppmtompeg/iframe.c1062
-rw-r--r--converter/ppm/ppmtompeg/input.c515
-rw-r--r--converter/ppm/ppmtompeg/jpeg.c634
-rw-r--r--converter/ppm/ppmtompeg/jrevdct.c1278
-rw-r--r--converter/ppm/ppmtompeg/memory.c71
-rw-r--r--converter/ppm/ppmtompeg/mfwddct.c393
-rw-r--r--converter/ppm/ppmtompeg/mheaders.c1192
-rw-r--r--converter/ppm/ppmtompeg/moutput.c442
-rw-r--r--converter/ppm/ppmtompeg/mpeg.c1717
-rw-r--r--converter/ppm/ppmtompeg/mquant.c44
-rw-r--r--converter/ppm/ppmtompeg/nojpeg.c61
-rw-r--r--converter/ppm/ppmtompeg/noparallel.c229
-rw-r--r--converter/ppm/ppmtompeg/opts.c536
-rw-r--r--converter/ppm/ppmtompeg/parallel.c2278
-rw-r--r--converter/ppm/ppmtompeg/param.c1077
-rw-r--r--converter/ppm/ppmtompeg/parse_huff.pl198
-rw-r--r--converter/ppm/ppmtompeg/pframe.c1072
-rw-r--r--converter/ppm/ppmtompeg/postdct.c626
-rw-r--r--converter/ppm/ppmtompeg/ppmtompeg.c722
-rw-r--r--converter/ppm/ppmtompeg/psearch.c989
-rw-r--r--converter/ppm/ppmtompeg/psocket.c452
-rw-r--r--converter/ppm/ppmtompeg/qtest.c63
-rw-r--r--converter/ppm/ppmtompeg/rate.c986
-rw-r--r--converter/ppm/ppmtompeg/readframe.c1016
-rw-r--r--converter/ppm/ppmtompeg/rgbtoycc.c204
-rw-r--r--converter/ppm/ppmtompeg/specifics.c688
-rw-r--r--converter/ppm/ppmtompeg/subsample.c280
-rw-r--r--converter/ppm/ppmtompeg/tst/README30
-rw-r--r--converter/ppm/ppmtompeg/tst/gop.param30
-rw-r--r--converter/ppm/ppmtompeg/tst/par3.param43
-rw-r--r--converter/ppm/ppmtompeg/tst/short.param31
-rwxr-xr-xconverter/ppm/ppmtompeg/tst/test_all19
-rw-r--r--converter/ppm/ppmtompeg/tst/ts.mpgbin0 -> 40978 bytes
-rw-r--r--converter/ppm/ppmtompeg/tst/ts.param29
-rw-r--r--converter/ppm/ppmtompeg/tst/ts.stat52
-rw-r--r--converter/ppm/ppmtompeg/tst/ts/stennis.30.jpgbin0 -> 19080 bytes
-rw-r--r--converter/ppm/ppmtompeg/tst/ts/stennis.31.jpgbin0 -> 18678 bytes
-rw-r--r--converter/ppm/ppmtompeg/tst/ts/stennis.32.jpgbin0 -> 18379 bytes
-rw-r--r--converter/ppm/ppmtompeg/tst/ts/stennis.33.jpgbin0 -> 18012 bytes
-rw-r--r--converter/ppm/ppmtompeg/tst/ts/stennis.34.jpgbin0 -> 17871 bytes
-rw-r--r--converter/ppm/ppmtompeg/tst/ts/stennis.35.jpgbin0 -> 17398 bytes
-rw-r--r--converter/ppm/ppmtompeg/tst/ts/stennis.36.jpgbin0 -> 17085 bytes
-rw-r--r--converter/ppm/ppmtompeg/tst/ts/stennis.37.jpgbin0 -> 16806 bytes
-rw-r--r--converter/ppm/ppmtompeg/tst/ts/stennis.38.jpgbin0 -> 16522 bytes
-rw-r--r--converter/ppm/ppmtompeg/tst/ts/stennis.39.jpgbin0 -> 16291 bytes
-rw-r--r--converter/ppm/ppmtompeg/tst/ts2.param33
-rw-r--r--converter/ppm/ppmtompeg/tst/ts2.stat52
-rw-r--r--converter/ppm/ppmtompeg/tst/ts3.param32
-rw-r--r--converter/ppm/ppmtompeg/tst/ts4.param56
-rw-r--r--converter/ppm/ppmtompeg/tst/tsd.param32
-rw-r--r--converter/ppm/ppmtompeg/tst/tsd.stat52
-rw-r--r--converter/ppm/ppmtompeg/tst/tstl.param31
260 files changed, 39497 insertions, 0 deletions
diff --git a/converter/ppm/ppmtompeg/BUGS b/converter/ppm/ppmtompeg/BUGS
new file mode 100644
index 00000000..64269dfb
--- /dev/null
+++ b/converter/ppm/ppmtompeg/BUGS
@@ -0,0 +1,43 @@
+Known BUGS:
+
+1. <fixed>
+
+2. rate control and specifics files interact badly
+
+3. using REMOTE parallel execution:
+   `command` to find INPUT files does not work
+   SPECIFICS_FILE (CDL_FILE)
+   USER_DATA 
+     dont work (should send the files over the socket, but do not
+
+4. using any sort of parallel code:
+     REFERENCE_FRAME	DECODED
+   does not work
+
+5. Cannot use both STDIN and CDL_FILEs (ok, since it doesnt make sense...)
+
+6. <fixed>
+
+7. Patterns of BBI...  seem to cause problems for parallel encoding.  
+   I believe the bugs are fixed for sequential, but if you hit one, let us
+   know!
+
+8. Sometimes parallel encoding results in a zero size being written into
+   the stream.  To fix, specify SIZE of the actual size.
+
+8.1 (related? minor, anyway) in parallel is also writes the Quant matrix
+   even when it is the default one
+
+9. It is unclear (to us anyway) if we should generate Y's from 0..255 or 16..224
+
+10. <fixed>
+
+11. <fixed>
+
+12. reading JPEG from stdin, the encoder will sometimes stop before the end
+of the stream (if the images are smaller than half the buffer size).
+
+13. Sometimes INPUT_CONVERT * is not good (requires "cat *"), in a parallel
+case reported by a user it was needed.
+
+14. Parallel encoding often generates improper temporal_ref's...
diff --git a/converter/ppm/ppmtompeg/CHANGES b/converter/ppm/ppmtompeg/CHANGES
new file mode 100644
index 00000000..fffa7a65
--- /dev/null
+++ b/converter/ppm/ppmtompeg/CHANGES
@@ -0,0 +1,180 @@
+Changes chronology
+------------------
+1.5b Release	August 1995
+	- added date to default USER_DATA string
+	- made prototypes happier
+	- renamed SPECIFICS_FILE to CDL_FILE
+	- fixed bit_rate param in constrained param setting (was too restrictive)
+	- fixed obscure P-block motion vector bug
+	- added a file name replication:
+	    foo.ppm  [1-10] will make 10 copies of foo.ppm
+	- generalized fopen calls to specify binary mode (MSDOG)
+	- generalized times calls into elapsed_time to handle different library routines
+	- fixed motion vector bug in bframes; skip block bug
+	- fixed minor bugs in parallel, mpeg, main, iframe, param, ....
+	- accepts extra whitespace at the end of lines in parameter files
+	- "PIXEL FULL" bug in B-frames fixed (caused ghosting)
+        - B-blocks "can I skip" rutine now looks at color too (more ghosting problems)
+        - switched from JPEG4 to JPEG5 (if they crash for you,
+                  do a -DJPEG4 for the encoder, and get jpeg4.tar.gz off our site)
+        - combine server (parallel) waits longer for files to exist (
+                         thanks to apian@ise.fhg.de)
+	- killing the parallel server kills the clients!!!! (apian@ise.fhg.de)
+
+1.5 Release	8 May 1995  Changes since version 1.3 release (to 1.5)
+= BUG FIXES
+	- removed SetBlocksPerSlice() from GOPStoMPEG
+	- don't access bb after freeing
+	- non-integer frame rates now work for all machines
+	- fixed parsing of -mv_histogram
+	- fixed numPadding bug (file name problem)
+	- fixed full pixel assertation bug
+        - corrected ASPECT_RATIO bug (was forced to 1)
+	- buffer size is now set correctly
+        - complains when file is too small
+	- fixed bug with non-ranged INPUT_FILE names
+	- forced MB at start/end of slice in P-frame bug fixed
+	- Actually evaluates the constrained parameter settings
+	- fixed a Cr/Cb mixup in bframe.c
+
+= NEW FEATURES
+	- rate control
+	- optional B search range different from P range
+	- can read images from stdin, allowing encoding on-the-fly
+        - Does Y files (no U or V)
+	- New way of specifying files `cmd`, like `ls jan-*-94`
+	- Can encode Abekas and Phillips style YUV formats
+	- gamma correction
+	- added -realquiet mode
+	- JMOVIE and JPEGv4 input format fully supported
+        - -float_dct uses the (slower) double precision floating point DCT 
+	- automatically identifies itself in (sequence header) userdata
+	- enforced [0][0] entry of Intra Q-table to be 8
+	- added Jim Boucher's resize code
+        - added -mse flag to print mean squared error on a per-block basis
+	- can specify Sequence header user data
+        - prints version number
+        - finds more skip blocks in GenBFrame
+	- can generate multiple sequence headers (every N GOPs)
+
+= SPEED IMPROVEMENTS
+
+
+= MAINTENANCE
+	- removed mpeg_jrevdct_sparse(), since it wasn't used
+	- added CompileTests();
+	- uses libpnmrw rather than entire pbmplus directory
+        - redid RCS
+        - reorganized [ipb]frame.c to make playing with rate controls easier
+
+= PORTABILITY
+	- added #ifdef's, #ifndef's LINUX'es to ease porting
+
+
+Changes from 1.2 to 1.3
+-----------------------
+= BUG FIXES
+	+ deletes frame files when done with them in parallel version
+	+ fixed bug in ComputeFrameTable
+	+ completion time estimation now is closer to actual time
+	+ modified ComputeSNR to avoid overflow of varOrig
+	+ fixed bug that caused I/P/B times on HP's to be wrong
+	+ fixed bug that made TwoLevel search out of the search window
+	+ fixed bug in -quiet 0
+	+ fixed memory leak when using PNM files
+	+ fixed bug:  crashed when CPU time was 0 (very rare)
+	+ fixed bug in -gop option
+	+ fixed bug in AppendFiles()
+
+= NEW FEATURES
+	+ added FORCE_ENCODE_LAST_FRAME option (allows encoding of all frames)
+	+ added PARALLEL_CHUNK_TAPER option
+	+ added -bit_rate_info option to show bit rate per frame
+	+ added -mv_histogram option to show motion vector histogram
+	+ custom quantization tables allowed
+	+ can specify frame rate, aspect ratio
+
+= SPEED IMPROVEMENTS
+	+ replaced most remaining binary multiplies/divides with shifts
+		(except those concerning negative numbers)
+
+= MAINTENANCE
+	+ got rid of & before array warning in block.c
+	+ got rid of references to srandom, random in pbmplus.h
+	+ undefine 'index' if defined as 'strchr' (since we use index as
+	  variable name)
+	+ modified frame type code to be more flexible
+
+= PORTABILITY
+	+ replaced all bzero() calls with memset() calls
+
+
+1.2 Release	20 October 1993
+
+Changes from 1.1 to 1.2
+-----------------------
+= BUG FIXES
+	+ allow comments in PPM files
+	+ first and last macroblocks in a slice may not be skipped macroblocks
+	+ fixed YUV bug:  should be able to handle dimensions which
+		aren't multiples of 16
+	+ fixed the separate I/O conversion for parallel NFS version
+	+ no_frame_summary can now be last option
+
+= NEW FEATURES
+	+ using DECODED frames as reference frames in parallel
+	  version now works
+	+ implemented multiple I/O Servers
+	+ FORCE_I_ALIGN added
+	+ reorganized Server structure slightly (only I/O Servers
+	  handle individual frame files on disk)
+	+ add option to allow exact division of frames per processor
+	  (PARALLEL_PERFECT)
+
+= SPEED IMPROVEMENTS
+	+ don't start Input server if not needed
+
+= MAINTENANCE
+	+ got rid of niceProcesses line in main.c
+	+ changed write() to SafeWrite() in parallel.c
+	+ commented stuff out after #endif's
+	+ fixed prototype warnings (eliminated non-4-byte args)
+
+
+1.1 Release	August 1993
+
+Changes from 1.0 to 1.1
+-----------------------
+= BUG FIXES
+	+ fixed bug in parallel Server code which didn't htonl() frame
+	  numbers correctly (so it didn't work on little-endian machines)
+	+ fixed bug -- B-frames were always getting just 1 slice
+	+ fixed listen() to use max connections allowed
+	+ fixed noparallel.c so it doesn't complain during non-parallel
+	  execution
+
+= NEW FEATURES
+	+ added level-2 p-search (exhaustive full, then half)
+	+ now prints signal-to-noise ratio
+	+ parallel code complains if absolute path not used for parameter
+	  file
+	+ changed single I/O server into separate Input and Output Servers
+	  (and have Output Server combine frames in parallel)
+
+= SPEED IMPROVEMENTS
+	+ slight improvement in Mpost_QuantZigBlock (.10 ms/call down to .08 ms
+	  on Sparc-10)
+	+ improvement in speed of BlockifyFrame (45.8 ms/call down to 21.2 ms)
+	+ improvement in ComputeMotionBlock (0.02 ms/call down to 0.01 ms)
+	+ improvement in ComputeMotionLumBlock (0.04 ms/call down to 0.02 ms)
+	+ improvement in LumAddMotionError (0.06 ms/call down to 0.05 ms)
+		(changed /2 to >>1)
+	
+= MAINTENANCE
+	+ removed most memory.h references (except jrevdct)
+	+ added CFLAGS lines in Makefile for SVR4.0 and SGI machines
+	+ removed mproto.h
+	+ got rid of printing connection times
+
+
+1.0 Release	July 1993
diff --git a/converter/ppm/ppmtompeg/COPYRIGHT b/converter/ppm/ppmtompeg/COPYRIGHT
new file mode 100644
index 00000000..08216f34
--- /dev/null
+++ b/converter/ppm/ppmtompeg/COPYRIGHT
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ * 
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ * 
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
diff --git a/converter/ppm/ppmtompeg/HISTORY b/converter/ppm/ppmtompeg/HISTORY
new file mode 100644
index 00000000..c9f4932a
--- /dev/null
+++ b/converter/ppm/ppmtompeg/HISTORY
@@ -0,0 +1,313 @@
+The entire ppmtojpeg directory was adapted by Bryan from the package
+mpeg_encode-1.5b-src (subdirectory mpeg_encode) on March 30, 1999.  The 
+program was called mpeg_encode in that package.  It was dated August 16,
+1995 and came from ftp://mm-ftp.cs.berkeley.edu/pub/multimedia/mpeg/
+encode/mpeg_encode-1.5b-src.tar.gz
+
+Changes for Netpbm include:
+
+  - mpeg_encode recognizes two input formats:  "PPM" and "PNM".  For
+    PPM, mpeg_encode parses it itself.  For PNM, it uses the Netpbm
+    PNM library routines.
+    
+    In the Netpbm version, PPM is gone and "PPM" is accepted as a 
+    synonym for "PNM".  For PNM, it uses the PPM (not PNM) Netpbm
+    library routines.
+
+  - mpeg_encode PNM code is broken for maxval != 255 (divides by zero
+    if maxval < 255 and overly quantize if > 255 because PNMtoYUV()
+    uses an integer divisor = maxval/256).
+
+In November 2004, Bryan rewrote large portions of the code so that he
+could read it easily enough to debug some problems.  He eliminated
+long subroutines, global variables, gotos, and the like.
+
+See the file LOGIC for some documentation on how the code works.
+
+
+The following is the README from the aforementioned mpeg_encode subdirectory.
+
+
+                 MPEG-1 Video Software Encoder
+                (Version 1.5; February 1, 1995)
+
+     Lawrence A. Rowe, Kevin Gong, Eugene Hung, Ketan Patel, Steve Smoot
+       and Dan Wallach
+    Computer Science Division-EECS, Univ. of Calif. at Berkeley
+
+This directory contains the freely distributed Berkeley MPEG-1 Video 
+Encoder.  The encoder implements the standard described in the ISO/IEC
+International Standard 11172-2.  The code has been compiled and tested 
+on the following platforms:
+
+ DECstation 5000 and Alpha
+ HP PA-RISC (HP/UX 9.X) (i.e., HP 9000/7XX and 9000/3XX)
+ SGI Indigo running IRIX 5.0.1
+ Sun Sparc (SunOS 4.X)
+
+In addition, Rainer Menes from the Technical University of Munich has
+ported the encoder and decoder to the Macintosh.  You can get that code
+directly from him (menes@statistik.tu-muenchen.de), or from the 
+Berkeley FTP archive (mm-ftp.CS.Berkeley.EDU).  If you decide to port 
+the code to a new architecture, please let us know so that we can 
+incorporate the changes into our sources.
+
+This directory contains everything required to build the encoder
+and run it.  We have included source code, makefiles, binaries
+for selected platforms, documentation, and test data.  Installation 
+instructions are given in the file named src/mpeg_encode/INSTALL.  A man 
+page is given in the file doc/mpeg_encode.1.  A detailed user 
+manual is provided in postscript format in the file doc/user-manual.ps.
+
+The encoder will accept any input file format as long as you provide 
+a script to convert the images to PPM, YUV, JPEG, or JMOVIE format.  Input 
+file processing is described in the file doc/INPUT.FORMAT.  Options to 
+control input file processing and compression parameters are specified in 
+a parameter file.  Very little error processing is done when reading 
+this file.  We suggest you start with the sample parameter file 
+examples/template.param and modify it.  See also examples/default.param.
+
+The convert directory of Mpeg-Tools contains utilities you might find 
+useful including: 
+
+programs to do PPM/YUV conversion and programs to convert Parallax
+XVideo JPEG files into PPM, YUV, or JPEG frames.
+
+The motion vector search window can be specified, including half-pixel
+block matching, in the parameter file.  We have implemented several 
+search algorithms for P-frames including: 1) exhaustive search, 
+2) subsampled search, and 3) logarithmic search.  We have also implemented
+several alternatives for B-frame block matching including: 1) interpolate
+best forward and best backward block, 2) find backward block for best
+forward or vice-versa (called CROSS2), and 3) exhaustive cross product
+(i.e., go out for coffee and a donut!). The search algorithms are controlled
+by options in the parameters file.  For tips on choosing the right search
+technique, see the user manual.
+
+The encoder can be run on one computer (i.e., sequential) or on several
+computers (i.e., parallel).  Our goal is to produce a portable, easy-to-use
+encoder that we can use to encode large volumes of video material for
+the Berkeley VOD system (see paper VodsProp93.ps.Z on the FTP archive).
+The parallelism is done on a sequence of pictures.  In other words, you 
+can spawn one or more children to encode continuous runs pictures. The 
+uncompressed data can be accessed either through NFS or TCP sockets.  
+The goal is to allow you to encode using multiple processors, think 
+spare cycles on workstations, to speed up the encoding time.  Although
+performance depends on the speed of individual processors, the file system
+and network, and the P/B frame search methods, we have encoded 3.75
+frames/second on 8 HP Snakes running in parallel as compared with 0.6
+frames/second on 1 Snake.  These are preliminary results. We are continuing 
+to experiment with and tune the code.  Instructions to run the parallel system 
+are given in the man page and the parallel.param example parameter file.
+
+We have done some tuning to produce a reasonable encoder, but there are
+many more optimizations that we would like to incorporate.  These 
+extensions are listed in the file doc/EXTENSIONS.  If you succeed in 
+implementing any of them, please let us know! 
+
+Send bug reports to:
+
+mpeg-bugs@CS.Berkeley.EDU
+   Problems, questions, or patches should be sent to this address.
+
+Anyone interested in providing financial support for this research or 
+discussing other aspects of this project should contact Larry Rowe at 
+Rowe@CS.Berkeley.EDU (+1 510-642-5117).
+
+This software is freely distributed.  That means, you may use it for 
+any non-commercial purpose.  However, patents are held by several companies 
+on various aspects of the MPEG video standard.  Companies or individuals
+who want to develop commercial products that include this code must
+acquire licenses from these companies.  For information on licensing, see
+Appendix F in the standard.
+
+ACKNOWLEDGEMENTS:
+
+We gratefully thank Hewlett-Packard and Fujitsu who provided financial
+support for this work.  We also want to thank the following people and
+organizations for their help:
+
+    Jef Poskanzer who developed the pbmplus package.
+    ---------
+    Copyright (C) 1989, 1991 by Jef Poskanzer.
+
+    Permission to use, copy, modify, and distribute this software and its
+    documentation for any purpose and without fee is hereby granted, provided
+    that the above copyright notice appear in all copies and that both that
+    copyright notice and this permission notice appear in supporting
+    documentation.  This software is provided "as is" without express or
+    implied warranty.
+    ---------
+
+    Eiichi Kowashi of Intel and Avideh Zakhor of U.C. Berkeley who
+    provided valuable suggestions on motion vector searching.
+
+    Chad Fogg of the University of Washington who has helped us 
+    understand many issues in MPEG coding and decoding.
+
+    Rainer Menes of the Technical University of Munich who has ported the
+    the Berkeley MPEG encoder and decoder to the Macintosh, and he has 
+    provided us with many suggestions to improve the code.
+
+    Robert Safranek of ATT for comments, suggestions, and most of the
+    code for custom quantization tables.
+
+    Jim Boucher of Boston University for jmovie2jpeg.
+
+    The San Diego SuperComputing Center for providing facilities to 
+    develop some of the code contained within.
+
+
+This is the TODO file from the original Berkeley package:
+
+
+TODO list for next release
+--------------------------
+
+Add option to do searches in Cr/Cb as well as Lum blocks
+jpeg5! (below)
+last-frame must be P/I error, and pattern interact badly
+add gnuconfigure so the Makefile is cake
+YUV correct (cf mail below)
+fix the "ifdef BUGGY_CODE" code in bframe.c
+Change sizing stuff so it works with non multiples of 16
+Does "RESIZE WxH" work?  Seems to for PPm but not JPG.  Fix it.  Document it
+mpeg_encode in parallel generates a "zero size warning"  It should 
+    exit(1) here, when not in parallel, and not warn when in parallel.
+     sometimes it generates a 0x0 MPEG!
+Give time estimates for parallel encoding
+Verify YUV file sizes with stat() call (when not STDIN)
+
+--------------------
+
+YUV mail:
+Please have a look on these few lines extracted from the ISO
+mpeg2encode/readpic.c/read_ppm() available on 
+ftp.netcom.com:/pub/cf/cfogg/mpeg2 :
+
+    .........
+
+     /* convert to YUV */
+
+     y = cr*r +cg*g +cb*b;
+     u = cu*(b-y);
+     v = cv*(r-y);
+     yp[j] = (219.0/256.0)*y + 16.5;  /* nominal range : 16..235 */
+     up[j] = (224.0/256.0)*u + 128.5; /* nominal range : 16..240 */
+     vp[j] = (224.0/256.0)*v + 128.5; /* nominal range : 16..240 */
+    ...........
+
+I think there is a slight misunderstanding in the Berkeley's mpeg1 codec about
+what the YUV format looks like, exactly about how to translate from PPM to YUV 
+and vice versa : the dynamic of YUV format has to be reduced as described
+above. Otherwise, on a full color display a Berkeley's MPEG bitstream has not 
+exactly the right colors if played by an ISO compliant player.
+
+Best regards
+
+
+                            Thierry GODIN
+
+--------------------
+And just for fun, kevin's list:
+To-do list	(in no particular order)
+----------
+	- should delete decoded frame files when done with them
+		(need to make sure no one else needs it)
+	- port to CM5
+	- try on Snake cluster, and other clusters (FDDI -- 100Mb/s)
+	- fix bug on snakes (look at header file for queue length)
+	- look at 24-bit display
+	- try having I/O server getting things in order, and asking Master
+		where to send them
+	- bug:  closing connections at end (on DEC 5000)
+	- GOP on space in input list
+	- pnm convolve
+	- telescopic search
+	- include system layer
+	- update documentation
+	- show error images
+	- graphical interface (showing motion vectors, etc.)
+	- use DCT-space when computing error terms
+	- vary the q-scale according to the error term
+	- modify the program to have a finer-grained parallelism option -- we
+	  can probably encode slices in parallel (this will only be useful if
+	  we want to do a few B-frames using exhaustive search)
+	- make search technique stop at x.5, not x.0
+	- pel aspect ratio in parameter file (2.4.3.2)
+	- skipped blocks options?
+	- recover from parallel machine errors?
+	- subsample B-search
+	- bug:  decoded with 1 machine can freeze
+	- malloc bug:  hello.param, with DECODED frames only
+	- portability:
+		times() function
+		popen/pclose
+
+Oh yes, I liked the concept of a spiral for your full search algorithm,
+however I thought this code a little difficult to read.  What about
+using a look up table (pre generated at compile time) to generate
+the coord offsets that would then spiral around the location in question?
+
+	+ change MAXPATHLEN to something else
+	+ put ./ in test in Makefile
+
+Currently, the IPPBPBB sequence is fixed for the entire sequence.  A later
+version should probably either test for scene changes or allow the user to
+specify them.
+
+	+ check all << and >> to make sure they are used properly
+		(note truncation of >>)
+	+ allow variable bit rate
+	+ allow size of video sequences to be set
+	+ make REMOTE usage more clear
+	+ fix bug:  when I-frame only, and decoded, does a lot of extra work
+	+ replace ZAG[i] with a pointer? (in quantization)
+		(and speed up by using 31 times the space (one for each
+		 q-value)
+	+ add interrupt handler to parallel encoder
+	+ should pad black instead of truncating
+	- graph histogram of motion vectors
+	- allow new PATTERN statements inside of file listing
+	- put in run-time checks for size of int32, int16, etc.
+	- replace pnm crap with ppm.dwallach
+	- add option to allow different p-search in b-search
+	- allow -frames option along with parallel option (shouldn't be
+		too difficult)
+	- incorrect compression rates given if do -frames option
+
+	- enforce:  >Hmmm...I will have to look at the standard.  I did find something earlier --
+>"forced updating" makes it illegal to have more than 132 P-frames without an
+>I-frame.  But "forced updating" does not disallow any number of consecutive
+>B-frames.  I'll have to check on limits for GOP lengths...
+
+	- rectangular search windows
+
+	- make parallel stats to 4 digits
+
+One of my friend just fixed the problem.....she 
+retype the whole parameter file and it is working
+now.  I think the problem was there were some 
+spacing problem......for example, if there
+are some space is the line, when the 
+program read in....it just mess everything up.
+
+It really become a problem if there is space after the image name...
+or even after the path name.
+
+	Subject: may not want to >> 4	in postdct.c
+
+------------------------------------------------------------------------
+P.S. In the future versions (is one already been released), you could add
+option for encoder to remove picture after encoding it & therefore saving
+space on disk + option to sleep while picture it's waiting for is not done.
+I've hacked this: (in readframe.c)
+
+        while ((tempfile = fopen(fullFileName, "r")) == NULL) {
+            fprintf(stderr, "Cannot open '%s', retrying...\n", fullFileName);
+            sleep(120);
+        }
+
+        fclose(tempfile);
+
+arijan@kette.fer.uni-lj.si
diff --git a/converter/ppm/ppmtompeg/LOGIC b/converter/ppm/ppmtompeg/LOGIC
new file mode 100644
index 00000000..8c19dc8d
--- /dev/null
+++ b/converter/ppm/ppmtompeg/LOGIC
@@ -0,0 +1,126 @@
+This file describes (a little) how the program works.
+
+PARALLEL MODE
+-------------
+
+In parallel mode, two processes run on the machine where you invoke
+Ppmtompeg: the master server and the combine server.  Sometimes, there's
+a third process called a decode server, but I don't know what that's for
+yet.
+
+Other processes, which are typically on separate machines, one per
+machine, are called encoder processes.  The code normally calls these
+"child" processes and the documentation normally calls them "slave"
+processes.  We really should fix that.
+
+The master server's job is to feed work assignments to the encoder
+processes.  A work assignment is a set of frames to encode.
+
+The combine server's job is to take the encoded output from the encoder
+processes and combine them into a single MPEG movie.
+
+The master process is the first process that exists.  The first thing
+it does is create the combine server.  Then it creates the encoder
+processes.  It creates each encoder process with an initial
+assignment.  The master process then waits in a loop for an encoder
+process to report that it has finished its assignment and gives a new
+assignment to it.
+
+The master process and the combine process both have a listening TCP
+port.  They choose an available port number.  When the master server
+creates the combine server, it passes the master server's TCP listen
+port number to the combine server.  It then waits to hear from the
+combine process what TCP listen port it has chosen.  The combine
+server connects to the master server's listen port and tells it.  The
+master server then passes to each encode server, as it creates it,
+the TCP listen ports of both the master server and the combine server.
+
+When the combine server has processed all the frames, it shuts down.
+It connects to the master server TCP listen port and tells the master
+server it is shutting down.
+
+When an encoder server finishes a frame, it connects to the combine
+server's TCP listen port and tells the combine server that the frame
+is ready.
+
+When an encoder server finishes an assignment, it connects to the master
+server TCP listen port and tells the master it is done, and receives over
+the same connetion its next assignment.  If there is no more work to do,
+the master server instead tells the encoder server just to terminate.
+
+When the master server has told every encoder server to terminate, it
+waits for the combine server to say that it has terminated.  The master
+server then terminates.
+
+To create the combine server, the master server forks and execs
+'ppmtompeg' with the -output_server option.
+
+To create an encoder server, the master server invokes Ssh (or something
+like it) and tells the remote shell to execute 'ppmtompeg' with the
+-child option.
+
+The various processes communicate frame data via a shared filesystem
+(e.g. NFS).  An encoder server grabs the input frames from the shared
+filesystem and writes the encoded frames to it.  The combine server
+grabs the encoded frames from it and writes the MPEG movie file to it.
+The encoded frames go in individual files.  The combine server deletes
+each file after it has copied it to the MPEG movie file.  Use the
+KEEP_TEMP_FILES parameter file statement to keep them around for 
+debugging.
+
+There's also an alternative "remote I/O" method of communication that
+doesn't require a shared filesystem.  I haven't studied that.
+
+The master server and combine server code are in parallel.c.  The
+encoder server code is roughly the same as what the single encoder
+process executes when you aren't running in parallel mode.
+
+
+THE ENCODING PROCEDURE
+----------------------
+
+Encoding is done by ppmtompeg.c, which calls GenMPEGStream in mpeg.c to
+do most of the work.
+
+The encoder goes through the input frames in movie sequence.  But the
+frames don't go into an MPEG stream in movie sequence.  A B frame not
+only can't be encoded without the subsequent I or P frame (reference
+frame); it can't be decoded without it either.  So in the MPEG stream,
+B frames come immediately after the reference frame which comes
+immediately after the B frames in the actual movie.
+
+When the input is from a sequential stream (the only way that's possible
+today is with Standard Input), the encoder saves up B frame input until
+after it has encoded and output the post reference frame.  It does
+this by chaining the input frames to the pre reference frame.  We really
+should clean this up so that a single module handles input of all kinds
+and presents only a sequential stream to the encoder.  The encoder should
+not have special cases for the different types of input.  That input
+module would let the encoder ask from Frame N even if the input is
+sequential.  The input module would buffer frames from the sequential
+input as necessary.
+
+In parallel mode, the combine server takes encoded frames from the
+encoder servers as it comes.  It can be in any order.  The combine
+server knows which frames go where in the output stream and outputs them
+in the proper order.  This is important for two reasons.  First, the
+encoder servers don't finish assignments in the same order in which they
+get them.  Second, when an encoder server gets an assignment that ends
+with a B frame, the combine server has to wait for the encoder server
+that has the next assignment to produce the post reference frame before
+the combine server can do anything with that trailing B frame.
+
+genMPEGStream() encodes a frame at a time, but it inserts a stream
+header and GOP headers where they belong.  genMPEGStream() operates in
+three modes: Whole Stream, GOP, and Just Frames.  In Whole Stream
+mode, it inserts all the required headers.  In GOP mode, it inserts
+GOP headers but not the stream header.  In Just Frames mode, it
+inserts no headers at all.  In parallel mode, genMPEGStream generates
+one frame per file, and only Just Frames mode makes any sense.  We
+really should fix this up so that the encoder always works in Just
+Frames mode and a GOP builder module takes the encoder's output and
+splices it with GOP headers and a stream builder module takes the GOP
+builder's output and adds it to a stream header.  In parallel mode,
+the combine server would run the GOP builder and stream builder
+modules.
+
diff --git a/converter/ppm/ppmtompeg/Makefile b/converter/ppm/ppmtompeg/Makefile
new file mode 100644
index 00000000..5e923fee
--- /dev/null
+++ b/converter/ppm/ppmtompeg/Makefile
@@ -0,0 +1,140 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/../../..
+  BUILDDIR = $(SRCDIR)
+endif
+SUBDIR = converter/ppm/ppmtompeg
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+include $(BUILDDIR)/Makefile.config
+
+ifeq ($(JPEGLIB),NONE)
+  # 'nojpeg' is a module that implements all the jpeg access routines as
+  # error messages that tell you we don't have jpeg capability
+  JPEG_MODULE = nojpeg
+  JPEGLIBX =
+else
+  # 'jpeg' is a module that accesses J-movies via the JPEG library.
+  JPEG_MODULE = jpeg
+  JPEGLIBX = $(JPEGLIB)
+endif
+
+INCLUDES = -I$(SRCDIR)/$(SUBDIR)/headers 
+
+ifneq ($(JPEGHDR_DIR),NONE)
+  ifneq ($(JPEGHDR_DIR)x,x)
+    INCLUDES += -I$(JPEGHDR_DIR)
+  endif
+endif
+
+# use -DLONG_32 iff
+#	1) long's are 32 bits and
+#	2) int's are not
+#
+# if you are using a non-ANSI compiler, then use:
+#	-DNON_ANSI_COMPILER
+#
+# one other option:
+#	-DHEINOUS_DEBUG_MODE
+#
+
+MP_BASE_OBJS = mfwddct.o postdct.o huff.o bitio.o mheaders.o
+MP_ENCODE_OBJS = iframe.o pframe.o bframe.o psearch.o bsearch.o block.o 
+MP_OTHER_OBJS = mpeg.o subsample.o param.o rgbtoycc.o \
+	readframe.o combine.o jrevdct.o frame.o fsize.o frametype.o \
+	specifics.o rate.o opts.o input.o gethostname.o
+ifeq ($(OMIT_NETWORK),y)
+  MP_PARALLEL_OBJS = noparallel.o
+else
+  MP_PARALLEL_OBJS = parallel.o psocket.o
+endif
+NONMAIN_OBJS = $(MP_BASE_OBJS) $(MP_OTHER_OBJS) $(MP_ENCODE_OBJS) \
+	      $(MP_PARALLEL_OBJS) $(JPEG_MODULE).o
+OBJECTS = ppmtompeg.o $(NONMAIN_OBJS)
+MERGE_OBJECTS = ppmtompeg.o2 $(NONMAIN_OBJS)
+MP_INCLUDE = mproto.h mtypes.h huff.h bitio.h
+MP_MISC = Makefile huff.table parse_huff.pl
+
+BINARIES = ppmtompeg
+MERGEBINARIES = $(BINARIES)
+SCRIPTS = 
+
+.PHONY: all
+all: ppmtompeg
+
+include $(SRCDIR)/Makefile.common
+
+ifeq ($(NEED_RUNTIME_PATH),Y)
+  LIBOPTR = -runtime
+else
+  LIBOPTR =
+endif
+
+ppmtompeg: $(OBJECTS) $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o $@ $(LDFLAGS) \
+          $(OBJECTS) $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR) $(JPEGLIBX)) \
+	  $(NETWORKLD) $(MATHLIB) $(LDLIBS) \
+	  $(RPATH) $(LADD)
+
+profile: $(OBJECTS) $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o $@ -Bstatic -pg $(LDFLAGS) \
+          $(OBJECTS) $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR) $(JPEGLIBX)) \
+	  $(NETWORKLD) $(MATHLIB) $(LDLIBS) \
+	  $(RPATH) $(LADD)
+
+
+#########
+# OTHER #
+#########
+
+#
+# Perl is necessary if you want to modify the Huffman RLE encoding table.
+#
+PERL = perl
+
+# The following stuff is for the Huffman encoding tables.  It's commented-out
+# because you probably don't want to change this.  If you do, then uncommment
+# it.
+#
+# huff.h: huff.c
+#
+# huff.c: parse_huff.pl huff.table
+#	$(PERL) parse_huff.pl huff.table
+
+MP_ALL_SRCS = $(patsubst %.o, %.c, $(MP_ALL_OBJS))
+
+wc:;		wc -l *.[ch] headers/*.h *.pl *.table
+ci:;		ci -l $(MP_ALL_SRCS) $(MP_INCLUDE) $(MP_MISC)
+tags: $(MP_ALL_SRCS)
+	ctags -t $(MP_ALL_SRCS)
+	etags -f TAGS -t $(MP_ALL_SRCS) headers/*.h
+
+#
+# WARNING: this assumes you're using GNU indent...
+#
+indent:;	indent -T FILE -T int8 -T int16 -T int32 -T uint8 -T uint16 -T uint32  -T BitBucket -T MpegFrame -T Block -T FlatBlock $(MP_ALL_SRCS)
+
+spotless: clean	
+	rm -f huff.c huff.h *.pure.a
+
+FORCE:
+
+# 
+# Copyright (c) 1995 The Regents of the University of California.
+# All rights reserved.
+# 
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose, without fee, and without written agreement is
+# hereby granted, provided that the above copyright notice and the following
+# two paragraphs appear in all copies of this software.
+# 
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# 
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+# 
diff --git a/converter/ppm/ppmtompeg/bframe.c b/converter/ppm/ppmtompeg/bframe.c
new file mode 100644
index 00000000..5dfb76d3
--- /dev/null
+++ b/converter/ppm/ppmtompeg/bframe.c
@@ -0,0 +1,1347 @@
+/*===========================================================================*
+ * bframe.c
+ *
+ *  Procedures concerned with the B-frame encoding
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "all.h"
+#include <sys/param.h>
+#include <assert.h>
+
+#include "ppm.h"
+
+#include "mtypes.h"
+#include "bitio.h"
+#include "frames.h"
+#include "prototypes.h"
+#include "block.h"
+#include "fsize.h"
+#include "param.h"
+#include "mheaders.h"
+#include "postdct.h"
+#include "rate.h"
+#include "opts.h"
+#include "specifics.h"
+
+extern int **bfmvHistogram;
+extern int **bbmvHistogram;
+
+/*==================*
+ * STATIC VARIABLES *
+ *==================*/
+
+static int32 totalTime = 0;
+static int qscaleB;
+static float    totalSNR = 0.0;
+static float    totalPSNR = 0.0;
+
+static struct bframeStats {
+    unsigned int BSkipped;
+    unsigned int BIBits;
+    unsigned int BBBits;
+    unsigned int Frames;
+    unsigned int FrameBits;
+    unsigned int BIBlocks;
+    unsigned int BBBlocks;
+    unsigned int BFOBlocks;    /* forward only */
+    unsigned int BBABlocks;    /* backward only */
+    unsigned int BINBlocks;    /* interpolate */
+    unsigned int BFOBits;
+    unsigned int BBABits;
+    unsigned int BINBits;
+} bframeStats = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+
+/*====================*
+ * EXTERNAL VARIABLES *
+ *====================*/
+
+extern Block **dct, **dctr, **dctb;
+extern dct_data_type **dct_data;
+#define NO_MOTION 0
+#define MOTION 1
+#define SKIP 2  /* used in useMotion in dct_data */
+
+/*=====================*
+ * INTERNAL PROCEDURES *
+ *=====================*/
+
+static void
+zeroMotion(motion * const motionP) {
+    
+    motionP->fwd.y = motionP->fwd.x = motionP->bwd.y = motionP->bwd.x = 0;
+}
+
+
+
+static motion
+halfMotion(motion const motion) {
+    struct motion half;
+
+    half.fwd.y = motion.fwd.y / 2;
+    half.fwd.x = motion.fwd.x / 2;
+    half.bwd.y = motion.bwd.y / 2;
+    half.bwd.x = motion.bwd.x / 2;
+
+    return half;
+}
+
+
+
+
+/*===========================================================================*
+ *
+ *  compute the block resulting from motion compensation
+ *
+ * RETURNS: motionBlock is modified
+ *
+ * SIDE EFFECTS:    none
+ *
+ * PRECONDITION:    the motion vectors must be valid!
+ *
+ *===========================================================================*/
+static void
+ComputeBMotionBlock(MpegFrame * const prev,
+                    MpegFrame * const next,
+                    int         const by,
+                    int         const bx,
+                    int         const mode,
+                    motion      const motion,
+                    Block *     const motionBlockP,
+                    int         const type) {
+
+    Block prevBlock, nextBlock;
+
+    switch(mode) {
+    case MOTION_FORWARD:
+        switch (type) {
+        case LUM_BLOCK:
+            ComputeMotionBlock(prev->ref_y, by, bx, motion.fwd, motionBlockP);
+            break;
+        case CB_BLOCK:
+            ComputeMotionBlock(prev->ref_cb, by, bx, motion.fwd, motionBlockP);
+            break;
+        case CR_BLOCK:
+            ComputeMotionBlock(prev->ref_cr, by, bx, motion.fwd, motionBlockP);
+        }
+        break;
+    case MOTION_BACKWARD:
+        switch (type) {
+        case LUM_BLOCK:
+            ComputeMotionBlock(next->ref_y, by, bx, motion.bwd, motionBlockP);
+            break;
+        case CB_BLOCK:
+            ComputeMotionBlock(next->ref_cb, by, bx, motion.bwd, motionBlockP);
+            break;
+        case CR_BLOCK:
+            ComputeMotionBlock(next->ref_cr, by, bx, motion.bwd, motionBlockP);
+            break;
+        }
+        break;
+    case MOTION_INTERPOLATE:
+        switch (type) {
+        case LUM_BLOCK:
+            ComputeMotionBlock(prev->ref_y, by, bx, motion.fwd, &prevBlock);
+            ComputeMotionBlock(next->ref_y, by, bx, motion.bwd, &nextBlock);
+            break;
+        case CB_BLOCK:
+            ComputeMotionBlock(prev->ref_cb, by, bx, motion.fwd, &prevBlock);
+            ComputeMotionBlock(next->ref_cb, by, bx, motion.bwd, &nextBlock);
+            break;
+        case CR_BLOCK:
+            ComputeMotionBlock(prev->ref_cr, by, bx, motion.fwd, &prevBlock);
+            ComputeMotionBlock(next->ref_cr, by, bx, motion.bwd, &nextBlock);
+            break;
+        }
+        {
+            unsigned int y;
+            for (y = 0; y < 8; ++y) {
+                int16 * const blockRow = (*motionBlockP)[y];
+                int16 * const prevRow  = prevBlock[y];
+                int16 * const nextRow  = nextBlock[y];
+                unsigned int x;
+                for (x = 0; x < 8; ++x)
+                    blockRow[x] = (prevRow[x] + nextRow[x] + 1) / 2;
+            }
+        }
+        break;
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ *  compute the DCT of the error term
+ *
+ * RETURNS: appropriate blocks of current will contain the DCTs
+ *
+ * SIDE EFFECTS:    none
+ *
+ * PRECONDITION:    the motion vectors must be valid!
+ *
+ *===========================================================================*/
+static void
+ComputeBDiffDCTs(MpegFrame * const current,
+                 MpegFrame * const prev,
+                 MpegFrame * const next,
+                 int         const by,
+                 int         const bx,
+                 int         const mode,
+                 motion      const motion,
+                 int *       const patternP) {
+
+    Block motionBlock;
+    
+    if (*patternP & 0x20) {
+        boolean significantDiff;
+        ComputeBMotionBlock(prev, next, by, bx, mode, motion,
+                            &motionBlock, LUM_BLOCK);
+        ComputeDiffDCTBlock(current->y_blocks[by][bx], dct[by][bx],
+                            motionBlock, &significantDiff);
+        if (!significantDiff) 
+            *patternP ^=  0x20;
+    }
+
+    if (*patternP & 0x10) {
+        boolean significantDiff;
+        ComputeBMotionBlock(prev, next, by, bx+1, mode, motion,
+                            &motionBlock, LUM_BLOCK);
+        ComputeDiffDCTBlock(current->y_blocks[by][bx+1], dct[by][bx+1],
+                            motionBlock, &significantDiff);
+        if (!significantDiff) 
+            *patternP ^=  0x10;
+    }
+
+    if (*patternP & 0x8) {
+        boolean significantDiff;
+        ComputeBMotionBlock(prev, next, by+1, bx, mode, motion,
+                            &motionBlock, LUM_BLOCK);
+        ComputeDiffDCTBlock(current->y_blocks[by+1][bx], dct[by+1][bx],
+                            motionBlock, &significantDiff);
+        if (!significantDiff)
+            *patternP ^= 0x8;
+    }
+
+    if (*patternP & 0x4) {
+        boolean significantDiff;
+        ComputeBMotionBlock(prev, next, by+1, bx+1, mode, motion,
+                            &motionBlock, LUM_BLOCK);
+        ComputeDiffDCTBlock(current->y_blocks[by+1][bx+1], dct[by+1][bx+1],
+                            motionBlock, &significantDiff);
+        if (!significantDiff)
+            *patternP ^= 0x4;
+    }
+
+    if (*patternP & 0x2) {
+        boolean significantDiff;
+        ComputeBMotionBlock(prev, next, by/2, bx/2, mode,
+                            halfMotion(motion), &motionBlock, CB_BLOCK);
+        ComputeDiffDCTBlock(current->cb_blocks[by/2][bx/2],
+                            dctb[by/2][bx/2], motionBlock,
+                            &significantDiff);
+        if (!significantDiff)
+            *patternP ^= 0x2;
+    }
+
+    if (*patternP & 0x1) {
+        boolean significantDiff;
+        ComputeBMotionBlock(prev, next, by/2, bx/2, mode,
+                            halfMotion(motion),
+                            &motionBlock, CR_BLOCK);
+        ComputeDiffDCTBlock(current->cr_blocks[by/2][bx/2],
+                            dctr[by/2][bx/2], motionBlock,
+                            &significantDiff);
+        if (!significantDiff)
+            *patternP ^= 0x1;
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ *  decides if this block should be coded as intra-block
+ *
+ * RETURNS: TRUE if intra-coding should be used; FALSE otherwise
+ *
+ * SIDE EFFECTS:    none
+ *
+ * PRECONDITION:    the motion vectors must be valid!
+ *
+ *===========================================================================*/
+static boolean
+DoBIntraCode(MpegFrame * const current,
+             MpegFrame * const prev,
+             MpegFrame * const next,
+             int         const by,
+             int         const bx,
+             int         const mode,
+             motion      const motion) {
+
+    boolean retval;
+    unsigned int y;
+    int32 sum = 0, vard = 0, varc = 0;
+    LumBlock motionBlock;
+    int fy, fx;
+
+    ComputeBMotionLumBlock(prev, next, by, bx, mode, motion, &motionBlock);
+
+    MotionToFrameCoord(by, bx, 0, 0, &fy, &fx);
+
+    for (y = 0; y < 16; ++y) {
+        unsigned int x;
+        for (x = 0; x < 16; ++x) {
+            int32 const currPixel = current->orig_y[fy+y][fx+x];
+            int32 const prevPixel = motionBlock.l[y][x];
+            int32 const dif = currPixel - prevPixel;
+
+            sum += currPixel;
+            varc += SQR(currPixel);
+            vard += SQR(dif);
+        }
+    }
+
+    vard >>= 8;     /* divide by 256; assumes mean is close to zero */
+    varc = (varc>>8) - (sum>>8)*(sum>>8);
+
+    if (vard <= 64)
+        retval = FALSE;
+    else if (vard < varc)
+        retval = FALSE;
+    else
+        retval = TRUE;
+    return retval;
+}
+
+
+
+static int
+ComputeBlockColorDiff(Block current,
+                      Block motionBlock) {
+
+    unsigned int y;
+    int diffTotal;
+    
+    diffTotal = 0;
+
+    for (y = 0; y < 8; ++y) {
+        unsigned int x;
+        for (x = 0; x < 8; ++x) {
+            int const diffTmp = current[y][x] - motionBlock[y][x];
+            diffTotal += ABS(diffTmp);
+        }
+    }
+    return diffTotal;
+}
+
+
+
+/*=====================*
+ * EXPORTED PROCEDURES *
+ *=====================*/
+
+
+/*===========================================================================*
+ * MotionSufficient
+ *
+ *  decides if this motion vector is sufficient without DCT coding
+ *
+ * RETURNS: TRUE if no DCT is needed; FALSE otherwise
+ *
+ * SIDE EFFECTS:    none
+ *
+ * PRECONDITION:    the motion vectors must be valid!
+ *
+ *===========================================================================*/
+static boolean
+MotionSufficient(MpegFrame *      const curr,
+                 const LumBlock * const currBlockP,
+                 MpegFrame *      const prev,
+                 MpegFrame *      const next,
+                 int              const by,
+                 int              const bx,
+                 int              const mode,
+                 motion           const motion) {
+
+    LumBlock mLumBlock;
+    Block mColorBlock;
+    int lumErr, colorErr;
+
+    /* check bounds */
+    if ( mode != MOTION_BACKWARD ) {
+        if ( (by*DCTSIZE+(motion.fwd.y-1)/2 < 0) ||
+             ((by+2)*DCTSIZE+(motion.fwd.y+1)/2-1 >= Fsize_y) ) {
+            return FALSE;
+        }
+        if ( (bx*DCTSIZE+(motion.fwd.x-1)/2 < 0) ||
+             ((bx+2)*DCTSIZE+(motion.fwd.x+1)/2-1 >= Fsize_x) ) {
+            return FALSE;
+        }
+    }
+
+    if ( mode != MOTION_FORWARD ) {
+        if ( (by*DCTSIZE+(motion.bwd.y-1)/2 < 0) ||
+             ((by+2)*DCTSIZE+(motion.bwd.y+1)/2-1 >= Fsize_y) ) {
+            return FALSE;
+        }
+        if ( (bx*DCTSIZE+(motion.bwd.x-1)/2 < 0) ||
+             ((bx+2)*DCTSIZE+(motion.bwd.x+1)/2-1 >= Fsize_x) ) {
+            return FALSE;
+        }
+    }
+
+    /* check Lum */
+    ComputeBMotionLumBlock(prev, next, by, bx, mode, motion, &mLumBlock);
+    lumErr =  LumBlockMAD(currBlockP, &mLumBlock, 0x7fffffff);
+    if (lumErr > 512) {
+        return FALSE;
+    }
+
+    /* check color */
+    ComputeBMotionBlock(prev, next, by/2, bx/2, mode,
+                        halfMotion(motion), &mColorBlock, CR_BLOCK);
+    colorErr = ComputeBlockColorDiff(curr->cr_blocks[by/2][bx/2],
+                                     mColorBlock);
+    ComputeBMotionBlock(prev, next, by/2, bx/2, mode, halfMotion(motion),
+                        &mColorBlock, CB_BLOCK);
+    colorErr += ComputeBlockColorDiff(curr->cr_blocks[by/2][bx/2],
+                                      mColorBlock);
+    
+    return (colorErr < 256); /* lumErr checked above */
+}
+
+
+
+
+struct stats {
+    int IBlocks;
+    int BBlocks;
+    int Skipped;
+    int totalBits;
+    int IBits;
+    int BBits;
+};
+
+
+
+static void
+initializeStats(struct stats * const statsP) {
+    statsP->IBlocks = 0;
+    statsP->BBlocks = 0;
+    statsP->Skipped = 0;
+    statsP->totalBits  = 0;
+    statsP->IBits   = 0;
+    statsP->BBits   = 0;
+}
+
+
+
+static void
+checkSpecifics(MpegFrame *      const curr, 
+               int              const mbAddress,
+               int              const QScale,
+               boolean *        const skipItP,
+               boolean *        const doBsearchP,
+               int *            const modeP,
+               motion *         const motionP) {
+/*----------------------------------------------------------------------------
+   We return *modeP iff we return *doBsearchP == FALSE.
+
+   We return *motionP iff we return *skipItP == FALSE.
+-----------------------------------------------------------------------------*/
+    BlockMV * info;
+
+    SpecLookup(curr->id, 2, mbAddress, &info, QScale);
+    if (info == NULL) {
+        *doBsearchP = TRUE;
+        *skipItP = FALSE;
+    } else {
+        *doBsearchP = FALSE;
+
+        switch (info->typ) {
+        case TYP_SKIP:
+            *skipItP = TRUE;
+            break;
+        case TYP_FORW:
+            *skipItP = FALSE;
+            motionP->fwd.y = info->fy;
+            motionP->fwd.x = info->fx;
+            *modeP = MOTION_FORWARD;
+            break;
+        case TYP_BACK:
+            *skipItP = FALSE;
+            motionP->bwd.y = info->by;
+            motionP->bwd.x = info->bx;
+            *modeP = MOTION_BACKWARD;
+            break;
+        case TYP_BOTH:
+            *skipItP = FALSE;
+            motionP->fwd.y = info->fy;
+            motionP->fwd.x = info->fx;
+            motionP->bwd.y = info->by;
+            motionP->bwd.x = info->bx;
+            *modeP = MOTION_INTERPOLATE;
+            break;
+        default:
+            pm_error("Unreachable code in GenBFrame!");
+        }
+    }
+}
+
+
+
+static void
+makeNonSkipBlock(int              const y,
+                 int              const x, 
+                 MpegFrame *      const curr, 
+                 MpegFrame *      const prev, 
+                 MpegFrame *      const next,
+                 boolean          const specificsOn,
+                 int              const mbAddress,
+                 int              const QScale,
+                 const LumBlock * const currentBlockP,
+                 int *            const modeP,
+                 int *            const oldModeP,
+                 boolean          const IntrPBAllowed,
+                 boolean *        const lastIntraP,
+                 motion *         const motionP,
+                 motion *         const oldMotionP,
+                 struct stats *   const statsP) {
+
+    motion motion;
+    int mode;
+    boolean skipIt;
+    boolean doBsearch;
+
+    if (specificsOn)
+        checkSpecifics(curr, mbAddress, QScale, &skipIt, &doBsearch,
+                       &mode, &motion);
+    else {
+        skipIt = FALSE;
+        doBsearch = TRUE;
+    }
+    if (skipIt)
+        dct_data[y][x].useMotion = SKIP;
+    else {
+        if (doBsearch) {
+            motion = *motionP;  /* start with old motion */
+            mode = BMotionSearch(currentBlockP, prev, next, y, x,
+                                 &motion, mode);
+        }
+        /* STEP 2:  INTRA OR NON-INTRA CODING */
+        if (IntraPBAllowed && 
+            DoBIntraCode(curr, prev, next, y, x, mode, motion)) {
+            /* output I-block inside a B-frame */
+            ++statsP->IBlocks;
+            zeroMotion(oldMotionP);
+            *lastIntraP = TRUE;
+            dct_data[y][x].useMotion = NO_MOTION;
+            *oldModeP = MOTION_FORWARD;
+            /* calculate forward dct's */
+            if (collect_quant && (collect_quant_detailed & 1)) 
+                fprintf(collect_quant_fp, "l\n");
+            mp_fwd_dct_block2(curr->y_blocks[y][x], dct[y][x]);
+            mp_fwd_dct_block2(curr->y_blocks[y][x+1], dct[y][x+1]);
+            mp_fwd_dct_block2(curr->y_blocks[y+1][x], dct[y+1][x]);
+            mp_fwd_dct_block2(curr->y_blocks[y+1][x+1], dct[y+1][x+1]);
+            if (collect_quant && (collect_quant_detailed & 1)) {
+                fprintf(collect_quant_fp, "c\n");
+            }
+            mp_fwd_dct_block2(curr->cb_blocks[y>>1][x>>1], 
+                              dctb[y>>1][x>>1]);
+            mp_fwd_dct_block2(curr->cr_blocks[y>>1][x>>1], 
+                              dctr[y>>1][x>>1]);
+
+        } else { /* dct P/Bi/B block */
+            int pattern;
+
+            pattern = 63;
+            *lastIntraP = FALSE;
+            ++statsP->BBlocks;
+            dct_data[y][x].mode = mode;
+            *oldModeP = mode;
+            dct_data[y][x].fmotionY = motion.fwd.y;
+            dct_data[y][x].fmotionX = motion.fwd.x;
+            dct_data[y][x].bmotionY = motion.bwd.y;
+            dct_data[y][x].bmotionX = motion.bwd.x;
+
+            switch (mode) {
+            case MOTION_FORWARD:
+                ++bframeStats.BFOBlocks;
+                oldMotionP->fwd = motion.fwd;
+                break;
+            case MOTION_BACKWARD:
+                ++bframeStats.BBABlocks;
+                oldMotionP->bwd = motion.bwd;
+                break;
+            case MOTION_INTERPOLATE:
+                ++bframeStats.BINBlocks;
+                *oldMotionP = motion;
+                break;
+            default:
+                pm_error("INTERNAL ERROR:  Illegal mode: %d", mode);
+            }
+        
+            ComputeBDiffDCTs(curr, prev, next, y, x, mode, motion, &pattern);
+        
+            dct_data[y][x].pattern = pattern;
+            dct_data[y][x].useMotion = MOTION;
+            if ( computeMVHist ) {
+                assert(motion.fwd.x + searchRangeB + 1 >= 0);
+                assert(motion.fwd.y + searchRangeB + 1 >= 0);
+                assert(motion.fwd.x + searchRangeB + 1 <= 2*searchRangeB + 2);
+                assert(motion.fwd.y + searchRangeB + 1 <= 2*searchRangeB + 2);
+                assert(motion.bwd.x + searchRangeB + 1 >= 0);
+                assert(motion.bwd.y + searchRangeB + 1 >= 0);
+                assert(motion.bwd.x + searchRangeB + 1 <= 2*searchRangeB + 2);
+                assert(motion.bwd.y + searchRangeB + 1 <= 2*searchRangeB + 2);
+                
+                ++bfmvHistogram[motion.fwd.x + searchRangeB + 1]
+                    [motion.fwd.y + searchRangeB + 1];
+                ++bbmvHistogram[motion.bwd.x + searchRangeB + 1]
+                    [motion.bwd.y + searchRangeB + 1];
+            }
+        } /* motion-block */
+    }
+    *motionP = motion;
+    *modeP   = mode;
+}
+
+
+
+/*===========================================================================*
+ *
+ * GenBFrame
+ *
+ *  generate a B-frame from previous and next frames, adding the result
+ *  to the given bit bucket
+ *
+ * RETURNS: frame appended to bb
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+GenBFrame(BitBucket * const bb, 
+          MpegFrame * const curr, 
+          MpegFrame * const prev, 
+          MpegFrame * const next) {
+
+    FlatBlock fba[6], fb[6];
+    Block     dec[6];
+    int32 y_dc_pred, cr_dc_pred, cb_dc_pred;
+    int x, y;
+    struct motion motion;
+    struct motion oldMotion;
+    int oldMode = MOTION_FORWARD;
+    int mode = MOTION_FORWARD;
+    int offsetX, offsetY;
+    struct motion motionRem;
+    struct motion motionQuot;
+    struct stats stats;
+    boolean lastIntra = TRUE;
+    boolean    motionForward, motionBackward;
+    int     totalFrameBits;
+    int32    startTime, endTime;
+    int lastX, lastY;
+    int lastBlockX, lastBlockY;
+    int ix, iy;
+    LumBlock currentBlock;
+    int         fy, fx;
+    boolean make_skip_block;
+    int mbAddrInc = 1;
+    int mbAddress;
+    int     slicePos;
+    float   snr[3], psnr[3];
+    int     idx;
+    int     QScale;
+    BlockMV *info;
+    int     bitstreamMode, newQScale;
+    int     rc_blockStart=0;
+    boolean overflowChange=FALSE;
+    int overflowValue = 0;
+
+    assert(prev != NULL);
+    assert(next != NULL);
+
+    initializeStats(&stats);
+
+    if (collect_quant) {fprintf(collect_quant_fp, "# B\n");}
+    if (dct == NULL) AllocDctBlocks();
+    ++bframeStats.Frames;
+    totalFrameBits = bb->cumulativeBits;
+    startTime = time_elapsed();
+
+    /*   Rate Control */
+    bitstreamMode = getRateMode();
+    if (bitstreamMode == FIXED_RATE) {
+        targetRateControl(curr);
+    }
+ 
+    QScale = GetBQScale();
+    Mhead_GenPictureHeader(bb, B_FRAME, curr->id, fCodeB);
+    /* Check for Qscale change */
+    if (specificsOn) {
+        newQScale = SpecLookup(curr->id, 0, 0 /* junk */, &info, QScale);
+        if (newQScale != -1) {
+            QScale = newQScale;
+        }
+        /* check for slice */
+        newQScale = SpecLookup(curr->id, 1, 1, &info, QScale);
+        if (newQScale != -1) {
+            QScale = newQScale;
+        }
+    }
+
+    Mhead_GenSliceHeader(bb, 1, QScale, NULL, 0);
+
+    Frame_AllocBlocks(curr);
+    BlockifyFrame(curr);
+
+    if ( printSNR ) {
+        Frame_AllocDecoded(curr, FALSE);
+    }
+
+    /* for I-blocks */
+    y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
+
+    stats.totalBits = bb->cumulativeBits;
+
+    if ( ! pixelFullSearch ) {
+        if ( ! prev->halfComputed ) {
+            ComputeHalfPixelData(prev);
+        }
+
+        if ( ! next->halfComputed ) {
+            ComputeHalfPixelData(next);
+        }
+    }
+
+    lastBlockX = Fsize_x / 8;
+    lastBlockY = Fsize_y / 8;
+    lastX = lastBlockX - 2;
+    lastY = lastBlockY - 2;
+    mbAddress = 0;
+
+    /* Start with zero motion assumption */
+    zeroMotion(&motion); 
+    zeroMotion(&oldMotion);
+    zeroMotion(&motionRem);
+    zeroMotion(&motionQuot);
+
+    /* find motion vectors and do dcts */
+    /* In this first loop, all MVs are in half-pixel scope, (if FULL
+       is set then they will be multiples of 2).  This is not true in
+       the second loop. 
+    */
+    for (y = 0;  y < lastBlockY;  y += 2) {
+        for (x = 0;  x < lastBlockX;  x += 2) {
+            slicePos = (mbAddress % blocksPerSlice);
+
+            /* compute currentBlock */
+            BLOCK_TO_FRAME_COORD(y, x, fy, fx);
+            for ( iy = 0; iy < 16; iy++ ) {
+                for ( ix = 0; ix < 16; ix++ ) {
+                    currentBlock.l[iy][ix] = (int16)curr->orig_y[fy+iy][fx+ix];
+                }
+            }
+        
+            if (slicePos == 0) {
+                zeroMotion(&oldMotion);
+                oldMode = MOTION_FORWARD;
+                lastIntra = TRUE;
+            }
+
+            /* STEP 1:  Select Forward, Backward, or Interpolated motion 
+               vectors */
+            /* see if old motion is good enough */
+            /* but force last block to be non-skipped */
+            /* can only skip if:
+             *     1)  not the last block in frame
+             *     2)  not the last block in slice
+             *     3)  not the first block in slice
+             *     4)  previous block was not intra-coded
+             */
+            if ( ((y < lastY) || (x < lastX)) &&
+                 (slicePos+1 != blocksPerSlice) &&
+                 (slicePos != 0) &&
+                 (! lastIntra) &&
+                 (BSkipBlocks) ) {
+                make_skip_block =
+                    MotionSufficient(curr, &currentBlock, 
+                                     prev, next, y, x, oldMode, oldMotion);
+            } else
+                make_skip_block = FALSE;
+
+            if (make_skip_block) {
+                /* skipped macro block */
+                dct_data[y][x].useMotion = SKIP;
+            } else
+                makeNonSkipBlock(y, x, curr, prev, next, specificsOn,
+                                 mbAddress,
+                                 QScale, &currentBlock,
+                                 &mode, &oldMode,
+                                 IntraPBAllowed,
+                                 &lastIntra, &motion, &oldMotion, &stats);
+
+            ++mbAddress;
+        }
+    }
+
+    /* reset everything */
+    zeroMotion(&oldMotion);
+    oldMode = MOTION_FORWARD;
+    lastIntra = TRUE;
+    y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
+    mbAddress = 0;
+
+    /* Now generate the frame */
+    for (y = 0; y < lastBlockY; y += 2) {
+      for (x = 0; x < lastBlockX; x += 2) {
+    slicePos = (mbAddress % blocksPerSlice);
+
+    if ( (slicePos == 0) && (mbAddress != 0) ) {
+      if (specificsOn) {
+        /* Make sure no slice Qscale change */
+        newQScale = 
+            SpecLookup(curr->id,1,mbAddress/blocksPerSlice, &info, QScale);
+        if (newQScale != -1) QScale = newQScale;
+      }
+      Mhead_GenSliceEnder(bb);
+      Mhead_GenSliceHeader(bb, 1+(y>>1), QScale, NULL, 0);
+
+      /* reset everything */
+      zeroMotion(&oldMotion);
+      oldMode = MOTION_FORWARD;
+      lastIntra = TRUE;
+      y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
+
+      mbAddrInc = 1+(x>>1);
+    }
+
+    /*  Determine if new Qscale needed for Rate Control purposes */
+    if (bitstreamMode == FIXED_RATE) {
+      rc_blockStart =  bb->cumulativeBits;
+      newQScale = needQScaleChange(QScale,
+                       curr->y_blocks[y][x],
+                       curr->y_blocks[y][x+1],
+                       curr->y_blocks[y+1][x],
+                       curr->y_blocks[y+1][x+1]);
+      if (newQScale > 0) {
+        QScale = newQScale;
+      }
+    }
+ 
+    if (specificsOn) {
+      newQScale = SpecLookup(curr->id, 2, mbAddress, &info, QScale);
+      if (newQScale != -1) {
+        QScale = newQScale;
+      }}
+
+    if (dct_data[y][x].useMotion == NO_MOTION) {
+
+      GEN_I_BLOCK(B_FRAME, curr, bb, mbAddrInc, QScale);
+      mbAddrInc = 1;
+      stats.IBits += (bb->cumulativeBits - stats.totalBits);
+      stats.totalBits = bb->cumulativeBits;
+          
+      /* reset because intra-coded */
+      zeroMotion(&oldMotion);
+      oldMode = MOTION_FORWARD;
+      lastIntra = TRUE;
+          
+      if ( printSNR ) {
+        /* need to decode block we just encoded */
+        /* and reverse the DCT transform */
+        for ( idx = 0; idx < 6; idx++ ) {
+          Mpost_UnQuantZigBlock(fb[idx], dec[idx], QScale, TRUE);
+          mpeg_jrevdct((int16 *)dec[idx]);
+        }
+
+        /* now, unblockify */
+        BlockToData(curr->decoded_y, dec[0], y, x);
+        BlockToData(curr->decoded_y, dec[1], y, x+1);
+        BlockToData(curr->decoded_y, dec[2], y+1, x);
+        BlockToData(curr->decoded_y, dec[3], y+1, x+1);
+        BlockToData(curr->decoded_cb, dec[4], y>>1, x>>1);
+        BlockToData(curr->decoded_cr, dec[5], y>>1, x>>1);
+      }
+    } else if (dct_data[y][x].useMotion == SKIP) {
+      ++stats.Skipped;
+      mbAddrInc++;
+          
+      /* decode skipped block */
+      if (printSNR) {
+          struct motion motion;
+        
+          for (idx = 0; idx < 6; ++idx)
+              memset((char *)dec[idx], 0, sizeof(Block)); 
+        
+          if (pixelFullSearch) {
+              motion.fwd.y = 2 * oldMotion.fwd.y;
+              motion.fwd.x = 2 * oldMotion.fwd.x;
+              motion.bwd.y = 2 * oldMotion.bwd.y;
+              motion.bwd.x = 2 * oldMotion.bwd.x;
+          } else
+              motion = oldMotion;
+          
+          /* now add the motion block */
+          AddBMotionBlock(dec[0], prev->decoded_y,
+                          next->decoded_y, y, x, mode, motion);
+          AddBMotionBlock(dec[1], prev->decoded_y,
+                          next->decoded_y, y, x+1, mode, motion);
+          AddBMotionBlock(dec[2], prev->decoded_y,
+                          next->decoded_y, y+1, x, mode, motion);
+          AddBMotionBlock(dec[3], prev->decoded_y,
+                          next->decoded_y, y+1, x+1, mode, motion);
+          AddBMotionBlock(dec[4], prev->decoded_cb,
+                          next->decoded_cb, y/2, x/2, mode,
+                          halfMotion(motion));
+          AddBMotionBlock(dec[5], prev->decoded_cr,
+                          next->decoded_cr, y/2, x/2, mode,
+                          halfMotion(motion));
+        
+          /* now, unblockify */
+          BlockToData(curr->decoded_y, dec[0], y, x);
+          BlockToData(curr->decoded_y, dec[1], y, x+1);
+          BlockToData(curr->decoded_y, dec[2], y+1, x);
+          BlockToData(curr->decoded_y, dec[3], y+1, x+1);
+          BlockToData(curr->decoded_cb, dec[4], y/2, x/2);
+          BlockToData(curr->decoded_cr, dec[5], y/2, x/2);
+      }
+    } else   /* B block */ {
+        int const fCode = fCodeB;   
+        int pattern;
+        
+        pattern = dct_data[y][x].pattern;
+        motion.fwd.y = dct_data[y][x].fmotionY;
+        motion.fwd.x = dct_data[y][x].fmotionX;
+        motion.bwd.y = dct_data[y][x].bmotionY;
+        motion.bwd.x = dct_data[y][x].bmotionX;
+
+        if (pixelFullSearch)
+            motion = halfMotion(motion);
+          
+        /* create flat blocks and update pattern if necessary */
+    calc_blocks:
+        /* Note DoQuant references QScale, overflowChange, overflowValue,
+           pattern, and the calc_blocks label                 */
+        DoQuant(0x20, dct[y][x], fba[0]);
+        DoQuant(0x10, dct[y][x+1], fba[1]);
+        DoQuant(0x08, dct[y+1][x], fba[2]);
+        DoQuant(0x04, dct[y+1][x+1], fba[3]);
+        DoQuant(0x02, dctb[y/2][x/2], fba[4]);
+        DoQuant(0x01, dctr[y/2][x/2], fba[5]);
+
+        motionForward  = (dct_data[y][x].mode != MOTION_BACKWARD);
+        motionBackward = (dct_data[y][x].mode != MOTION_FORWARD);
+        
+        /* Encode Vectors */
+        if (motionForward) {
+            /* transform the fMotion vector into the appropriate values */
+            offsetY = motion.fwd.y - oldMotion.fwd.y;
+            offsetX = motion.fwd.x - oldMotion.fwd.x;
+
+            encodeMotionVector(offsetX, offsetY,
+                               &motionQuot.fwd, &motionRem.fwd,
+                               FORW_F, fCode);
+            oldMotion.fwd = motion.fwd;
+        }
+          
+        if (motionBackward) {
+            /* transform the bMotion vector into the appropriate values */
+            offsetY = motion.bwd.y - oldMotion.bwd.y;
+            offsetX = motion.bwd.x - oldMotion.bwd.x;
+            encodeMotionVector(offsetX, offsetY,
+                               &motionQuot.bwd, &motionRem.bwd,
+                               BACK_F, fCode);
+            oldMotion.bwd = motion.bwd;
+        }
+          
+        oldMode = dct_data[y][x].mode;
+          
+        if (printSNR) { /* Need to decode */
+            if (pixelFullSearch) {
+                motion.fwd.x *= 2; motion.fwd.y *= 2;
+                motion.bwd.x *= 2; motion.bwd.y *= 2;
+            }
+            for ( idx = 0; idx < 6; idx++ ) {
+                if ( pattern & (1 << (5-idx)) ) {
+                    Mpost_UnQuantZigBlock(fba[idx], dec[idx], QScale, FALSE);
+                    mpeg_jrevdct((int16 *)dec[idx]);
+                } else {
+                    memset((char *)dec[idx], 0, sizeof(Block));
+                }
+            }
+
+            /* now add the motion block */
+            AddBMotionBlock(dec[0], prev->decoded_y,
+                            next->decoded_y, y, x, mode, motion);
+            AddBMotionBlock(dec[1], prev->decoded_y,
+                            next->decoded_y, y, x+1, mode, motion);
+            AddBMotionBlock(dec[2], prev->decoded_y,
+                            next->decoded_y, y+1, x, mode, motion);
+            AddBMotionBlock(dec[3], prev->decoded_y,
+                            next->decoded_y, y+1, x+1, mode, motion);
+            AddBMotionBlock(dec[4], prev->decoded_cb,
+                            next->decoded_cb, y/2, x/2, mode,
+                            halfMotion(motion));
+            AddBMotionBlock(dec[5], prev->decoded_cr,
+                            next->decoded_cr, y/2, x/2, mode,
+                            halfMotion(motion));
+
+            /* now, unblockify */
+            BlockToData(curr->decoded_y,  dec[0], y,   x);
+            BlockToData(curr->decoded_y,  dec[1], y,   x+1);
+            BlockToData(curr->decoded_y,  dec[2], y+1, x);
+            BlockToData(curr->decoded_y,  dec[3], y+1, x+1);
+            BlockToData(curr->decoded_cb, dec[4], y/2, x/2);
+            BlockToData(curr->decoded_cr, dec[5], y/2, x/2);
+        }
+
+        /* reset because non-intra-coded */
+        y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
+        lastIntra = FALSE;
+        mode = dct_data[y][x].mode;
+        
+        /*      DBG_PRINT(("MB Header(%d,%d)\n", x, y));  */
+        Mhead_GenMBHeader(
+            bb, 3 /* pict_code_type */, mbAddrInc /* addr_incr */,
+            QScale /* q_scale */,
+            fCodeB /* forw_f_code */, fCodeB /* back_f_code */,
+            motionRem.fwd.x /* horiz_forw_r */,
+            motionRem.fwd.y /* vert_forw_r */,
+            motionRem.bwd.x /* horiz_back_r */,
+            motionRem.bwd.y /* vert_back_r */,
+            motionForward /* motion_forw */,
+            motionQuot.fwd.x /* m_horiz_forw */,
+            motionQuot.fwd.y /* m_vert_forw */,
+            motionBackward /* motion_back */,
+            motionQuot.bwd.x /* m_horiz_back */,
+            motionQuot.bwd.y /* m_vert_back */,
+            pattern /* mb_pattern */, FALSE /* mb_intra */);
+
+        mbAddrInc = 1;
+          
+        /* now output the difference */
+        {
+            unsigned int x;
+            for (x = 0; x < 6; ++x) {
+                if (GET_ITH_BIT(pattern, 5-x))
+                    Mpost_RLEHuffPBlock(fba[x], bb);
+            }
+        }
+          
+        switch (mode) {
+        case MOTION_FORWARD:
+            bframeStats.BFOBits += (bb->cumulativeBits - stats.totalBits);
+            break;
+        case MOTION_BACKWARD:
+            bframeStats.BBABits += (bb->cumulativeBits - stats.totalBits);
+            break;
+        case MOTION_INTERPOLATE:
+            bframeStats.BINBits += (bb->cumulativeBits - stats.totalBits);
+            break;
+        default:
+            pm_error("PROGRAMMER ERROR:  Illegal mode: %d", mode);
+      }
+      
+      stats.BBits += (bb->cumulativeBits - stats.totalBits);
+      stats.totalBits = bb->cumulativeBits;
+    
+      if (overflowChange) {
+        /* undo an overflow-caused Qscale change */
+        overflowChange = FALSE;
+        QScale -= overflowValue;
+        overflowValue = 0;
+      }
+    } /* if I-block, skip, or B */
+
+    mbAddress++;
+    /*   Rate Control  */
+    if (bitstreamMode == FIXED_RATE) {
+      incMacroBlockBits( bb->cumulativeBits - rc_blockStart);
+      rc_blockStart = bb->cumulativeBits;
+      MB_RateOut(TYPE_BFRAME);
+    }
+    
+      }
+    }
+
+    if ( printSNR ) {
+      BlockComputeSNR(curr,snr,psnr);
+      totalSNR += snr[0];
+      totalPSNR += psnr[0];
+    }
+    
+    Mhead_GenSliceEnder(bb);
+    /*   Rate Control  */
+    if (bitstreamMode == FIXED_RATE) {
+      updateRateControl(TYPE_BFRAME);
+    }
+    
+    endTime = time_elapsed();
+    totalTime += (endTime-startTime);
+    
+    if ( showBitRatePerFrame ) {
+      /* ASSUMES 30 FRAMES PER SECOND */
+      fprintf(bitRateFile, "%5d\t%8d\n", curr->id,
+          30*(bb->cumulativeBits-totalFrameBits));
+    }
+    
+    if ( frameSummary && !realQuiet) {
+      fprintf(stdout, "FRAME %d (B):  "
+              "I BLOCKS: %5d;  B BLOCKS: %5d   SKIPPED: %5d (%ld seconds)\n",
+              curr->id, stats.IBlocks, stats.BBlocks, stats.Skipped,
+              (long)((endTime-startTime)/TIME_RATE));
+      if ( printSNR )
+    fprintf(stdout, "FRAME %d:  "
+            "SNR:  %.1f\t%.1f\t%.1f\tPSNR:  %.1f\t%.1f\t%.1f\n",
+            curr->id, snr[0], snr[1], snr[2],
+            psnr[0], psnr[1], psnr[2]);
+    }
+    
+    bframeStats.FrameBits += (bb->cumulativeBits-totalFrameBits);
+    bframeStats.BIBlocks += stats.IBlocks;
+    bframeStats.BBBlocks += stats.BBlocks;
+    bframeStats.BSkipped += stats.Skipped;
+    bframeStats.BIBits   += stats.IBits;
+    bframeStats.BBBits   += stats.BBits;
+  }
+
+
+/*===========================================================================*
+ *
+ * SetBQScale
+ *
+ *  set the B-frame Q-scale
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    qscaleB
+ *
+ *===========================================================================*/
+void
+SetBQScale(qB)
+    int qB;
+{
+    qscaleB = qB;
+}
+
+
+/*===========================================================================*
+ *
+ * GetBQScale
+ *
+ *  get the B-frame Q-scale
+ *
+ * RETURNS: the Q-scale
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+int
+GetBQScale()
+{
+    return qscaleB;
+}
+
+
+/*===========================================================================*
+ *
+ * ResetBFrameStats
+ *
+ *  reset the B-frame stats
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+ResetBFrameStats() {
+
+    bframeStats.BIBlocks = 0;
+    bframeStats.BBBlocks = 0;
+    bframeStats.BSkipped = 0;
+    bframeStats.BIBits = 0;
+    bframeStats.BBBits = 0;
+    bframeStats.Frames = 0;
+    bframeStats.FrameBits = 0;
+    totalTime = 0;
+}
+
+
+
+float
+BFrameTotalTime(void) {
+    return (float)totalTime/(float)TIME_RATE;
+}
+
+
+
+void
+ShowBFrameSummary(unsigned int const inputFrameBits, 
+                  unsigned int const totalBits, 
+                  FILE *       const fpointer) {
+
+    if (bframeStats.Frames > 0) {
+        fprintf(fpointer, "-------------------------\n");
+        fprintf(fpointer, "*****B FRAME SUMMARY*****\n");
+        fprintf(fpointer, "-------------------------\n");
+
+        if (bframeStats.BIBlocks > 0) {
+            fprintf(fpointer,
+                    "  I Blocks:  %5d     (%6d bits)     (%5d bpb)\n",
+                    bframeStats.BIBlocks, bframeStats.BIBits,
+                    bframeStats.BIBits/bframeStats.BIBlocks);
+        } else
+            fprintf(fpointer, "  I Blocks:  %5d\n", 0);
+
+        if (bframeStats.BBBlocks > 0) {
+            fprintf(fpointer,
+                    "  B Blocks:  %5d     (%6d bits)     (%5d bpb)\n",
+                    bframeStats.BBBlocks, bframeStats.BBBits,
+                    bframeStats.BBBits/bframeStats.BBBlocks);
+            fprintf(fpointer,
+                    "  B types:   %5d     (%4d bpb) "
+                    "forw  %5d (%4d bpb) back   %5d (%4d bpb) bi\n",
+                    bframeStats.BFOBlocks,
+                    (bframeStats.BFOBlocks==0) ? 
+                        0 : bframeStats.BFOBits/bframeStats.BFOBlocks,
+                    bframeStats.BBABlocks,
+                    (bframeStats.BBABlocks==0) ? 
+                        0 : bframeStats.BBABits/bframeStats.BBABlocks,
+                    bframeStats.BINBlocks,
+                    (bframeStats.BINBlocks==0) ? 
+                        0 : bframeStats.BINBits/bframeStats.BINBlocks);
+        } else
+            fprintf(fpointer, "  B Blocks:  %5d\n", 0);
+
+        fprintf(fpointer, "  Skipped:   %5d\n", bframeStats.BSkipped);
+
+        fprintf(fpointer, "  Frames:    %5d     (%6d bits)     "
+                "(%5d bpf)     (%2.1f%% of total)\n",
+                bframeStats.Frames, bframeStats.FrameBits,
+                bframeStats.FrameBits/bframeStats.Frames,
+                100.0*(float)bframeStats.FrameBits/(float)totalBits);        
+        fprintf(fpointer, "  Compression:  %3d:1     (%9.4f bpp)\n",
+                bframeStats.Frames*inputFrameBits/bframeStats.FrameBits,
+                24.0*(float)bframeStats.FrameBits/
+                    (float)(bframeStats.Frames*inputFrameBits));
+        if (printSNR)
+            fprintf(fpointer, "  Avg Y SNR/PSNR:  %.1f     %.1f\n",
+                    totalSNR/(float)bframeStats.Frames,
+                    totalPSNR/(float)bframeStats.Frames);
+        if (totalTime == 0) {
+            fprintf(fpointer, "  Seconds:  NONE\n");
+        } else {
+            fprintf(fpointer, "  Seconds:  %9ld     (%9.4f fps)  "
+                    "(%9ld pps)  (%9ld mps)\n",
+                    (long)(totalTime/TIME_RATE),
+                    (float)((float)(TIME_RATE*bframeStats.Frames)/
+                            (float)totalTime),
+                    (long)((float)TIME_RATE*(float)bframeStats.Frames *
+                           (float)inputFrameBits/(24.0*(float)totalTime)),
+                    (long)((float)TIME_RATE*(float)bframeStats.Frames *
+                           (float)inputFrameBits/(256.0*24.0 *
+                                                  (float)totalTime)));
+        }
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ *  compute the luminance block resulting from motion compensation
+ *
+ * RETURNS: motionBlock modified
+ *
+ * SIDE EFFECTS:    none
+ *
+ * PRECONDITION:    the motion vectors must be valid!
+ *
+ *===========================================================================*/
+void
+ComputeBMotionLumBlock(MpegFrame * const prev,
+                       MpegFrame * const next,
+                       int         const by,
+                       int         const bx,
+                       int         const mode,
+                       motion      const motion,
+                       LumBlock *  const motionBlockP) {
+
+    switch(mode) {
+    case MOTION_FORWARD:
+        ComputeMotionLumBlock(prev, by, bx, motion.fwd, motionBlockP);
+        break;
+    case MOTION_BACKWARD:
+        ComputeMotionLumBlock(next, by, bx, motion.bwd, motionBlockP);
+        break;
+    case MOTION_INTERPOLATE: {
+        LumBlock prevBlock, nextBlock;
+        unsigned int y;
+
+        ComputeMotionLumBlock(prev, by, bx, motion.fwd, &prevBlock);
+        ComputeMotionLumBlock(next, by, bx, motion.bwd, &nextBlock);
+        
+        for (y = 0; y < 16; ++y) {
+            unsigned int x;
+            for (x = 0; x < 16; ++x)
+                motionBlockP->l[y][x] =
+                    (prevBlock.l[y][x] + nextBlock.l[y][x] + 1) / 2;
+        }
+    } break;
+    default:
+        pm_error("Bad mode!  Programmer error!");
+    }  /* switch */
+}
+
+
+/*===========================================================================*
+ *
+ *  estimate the seconds to compute a B-frame
+ *
+ * RETURNS: the time, in seconds
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+float
+EstimateSecondsPerBFrame() {
+    if (bframeStats.Frames == 0)
+        return 20.0;
+    else
+        return (float)totalTime/((float)TIME_RATE*(float)bframeStats.Frames);
+}
+
+
diff --git a/converter/ppm/ppmtompeg/bitio.c b/converter/ppm/ppmtompeg/bitio.c
new file mode 100644
index 00000000..e0dc4d4e
--- /dev/null
+++ b/converter/ppm/ppmtompeg/bitio.c
@@ -0,0 +1,536 @@
+/*===========================================================================*
+ * bitio.c
+ *
+ *  Procedures concerned with the bit-wise I/O
+ *
+ * EXPORTED PROCEDURES:
+ *  Bitio_New
+ *  Bitio_Free
+ *  Bitio_Write
+ *  Bitio_Flush
+ *  Bitio_WriteToSocket
+ *  Bitio_BytePad
+ *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include <assert.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "pm.h"
+#include "intcode.h"
+
+#include "all.h"
+#include "byteorder.h"
+#include "bitio.h"
+#include "mtypes.h"
+
+
+
+/*==================*
+ * STATIC VARIABLES *
+ *==================*/
+
+static uint32 lower_mask[33] = {
+    0,
+    0x1, 0x3, 0x7, 0xf,
+    0x1f, 0x3f, 0x7f, 0xff,
+    0x1ff, 0x3ff, 0x7ff, 0xfff,
+    0x1fff, 0x3fff, 0x7fff, 0xffff,
+    0x1ffff, 0x3ffff, 0x7ffff, 0xfffff,
+    0x1fffff, 0x3fffff, 0x7fffff, 0xffffff,
+    0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff,
+    0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff
+};
+
+
+extern time_t IOtime;
+
+
+/*===========================================================================*
+ *
+ * Dump
+ *
+ *  Writes out the first MAX_BITS bits of the bit bucket to the
+ *  appropriate output file
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:  none
+ *
+ *===========================================================================*/
+static void
+Dump(BitBucket * const bbPtr) {
+    struct bitBucket *ptr, *tempPtr;
+    int i, nitems;
+    int     bitsWritten = 0;
+    time_t  tempTimeStart, tempTimeEnd;
+
+    time(&tempTimeStart);
+
+    for (ptr = bbPtr->firstPtr; ptr && (bitsWritten < MAX_BITS);
+         ptr = ptr->nextPtr) {
+
+        bigend32 buffer[WORDS_PER_BUCKET];
+
+        if (ptr->bitsleftcur == 32 && ptr->currword == 0) {
+            continue;       /* empty */
+        }
+
+        for (i = 0; i <= ptr->currword; ++i)
+            buffer[i] = pm_bigendFromUint32(ptr->bits[i]);
+
+        nitems = fwrite(buffer, sizeof(buffer[0]), ptr->currword + 1, 
+                        bbPtr->filePtr);
+        if (nitems != ptr->currword+1) {
+            fprintf(stderr, 
+                    "Whoa!  Trouble writing %u words (wrote %u words)!  "
+                    "Game over, dude!\n",
+                    ptr->currword+1, nitems);
+            exit(1);
+        }
+
+        bitsWritten += ((ptr->currword + 1) * 32);
+    }
+
+    while ( bbPtr->firstPtr != ptr ) {
+        tempPtr = bbPtr->firstPtr;
+        bbPtr->firstPtr = tempPtr->nextPtr;
+        free(tempPtr);
+    }
+
+    bbPtr->totalbits -= bitsWritten;
+    bbPtr->bitsWritten += bitsWritten;
+
+    time(&tempTimeEnd);
+    IOtime += (tempTimeEnd-tempTimeStart);
+}
+
+
+/*=====================*
+ * EXPORTED PROCEDURES *
+ *=====================*/
+
+
+/*===========================================================================*
+ *
+ * Bitio_New
+ *
+ *  Create a new bit bucket; filePtr is a pointer to the open file the
+ *  bits should ultimately be written to.
+ *
+ * RETURNS: pointer to the resulting bit bucket
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+BitBucket *
+Bitio_New(FILE * const filePtr) {
+
+    BitBucket *bbPtr;
+
+    bbPtr = (BitBucket *) malloc(sizeof(BitBucket));
+    ERRCHK(bbPtr, "malloc");
+
+    bbPtr->firstPtr = bbPtr->lastPtr = malloc(sizeof(struct bitBucket));
+    ERRCHK(bbPtr->firstPtr, "malloc");
+
+    bbPtr->totalbits = 0;
+    bbPtr->cumulativeBits = 0;
+    bbPtr->bitsWritten = 0;
+    bbPtr->filePtr = filePtr;
+
+    bbPtr->firstPtr->nextPtr = NULL;
+    bbPtr->firstPtr->bitsleft = MAXBITS_PER_BUCKET;
+    bbPtr->firstPtr->bitsleftcur = 32;
+    bbPtr->firstPtr->currword = 0;
+    memset((char *)bbPtr->firstPtr->bits, 0, 
+           sizeof(uint32) * WORDS_PER_BUCKET);
+
+    return bbPtr;
+}
+
+
+
+BitBucket *
+Bitio_New_Filename(const char * const fileName) {
+
+    FILE * outputFile;
+    
+    outputFile = fopen(fileName, "wb");
+    if (outputFile == NULL)
+        pm_error("Could not open output file '%s'.  "
+                 "Errno=%d (%s)", fileName, errno, strerror(errno));
+
+    return Bitio_New(outputFile);
+}
+
+
+
+/*===========================================================================*
+ *
+ * Bitio_Free
+ *
+ *  Frees the memory associated with the given bit bucket
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+Bitio_Free(BitBucket * const bbPtr) {
+
+    struct bitBucket *tmpPtr, *nextPtr;
+
+    for (tmpPtr = bbPtr->firstPtr; tmpPtr != NULL; tmpPtr = nextPtr) {
+        nextPtr = tmpPtr->nextPtr;
+        free(tmpPtr);
+    }
+    free(bbPtr);
+}
+
+
+/*===========================================================================*
+ *
+ * Bitio_Write
+ *
+ *  Writes 'nbits' bits from 'bits' into the given bit bucket
+ *  'nbits' must be between 0 and 32
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    if the number of bits in the bit bucket surpasses
+ *          MAX_BITS, then that many bits are flushed to the
+ *          appropriate output file
+ *
+ *===========================================================================*/
+void
+Bitio_Write(BitBucket * const bbPtr, 
+            uint32      const bits_arg, 
+            int         const nbits) {
+
+    register struct bitBucket *lastPtr, *newPtr;
+    register int delta;
+    uint32 bits;
+    
+    bits=bits_arg;
+    assert(nbits <= 32 && nbits >= 0);
+
+    /*
+     * Clear top bits if not part of data, necessary due to down and
+     * dirty calls of Bitio_Write with unecessary top bits set.
+     */
+
+    bits &= lower_mask[nbits];
+    bits = bits & lower_mask[nbits];
+
+    bbPtr->totalbits += nbits;
+    bbPtr->cumulativeBits += nbits;
+    lastPtr = bbPtr->lastPtr;
+
+    delta = nbits - lastPtr->bitsleft;
+    if (delta >= 0) {
+        /*
+         * there's not enough room in the current bucket, so we're
+         * going to have to allocate another bucket
+         */
+        newPtr = lastPtr->nextPtr = (struct bitBucket *) 
+            malloc(sizeof(struct bitBucket));
+        ERRCHK(newPtr, "malloc");
+        newPtr->nextPtr = NULL;
+        newPtr->bitsleft = MAXBITS_PER_BUCKET;
+        newPtr->bitsleftcur = 32;
+        newPtr->currword = 0;
+        memset((char *)newPtr->bits, 0, sizeof(uint32) * WORDS_PER_BUCKET);
+        bbPtr->lastPtr = newPtr;
+
+        assert(lastPtr->currword == WORDS_PER_BUCKET - 1);
+        lastPtr->bits[WORDS_PER_BUCKET - 1] |= (bits >> delta);
+        lastPtr->bitsleft = 0;
+        lastPtr->bitsleftcur = 0;
+        /* lastPtr->currword++; */
+
+        if (!delta) {
+            if ( bbPtr->totalbits > MAX_BITS ) {
+                Dump(bbPtr);
+            }
+        }
+
+        assert(delta <= 32);
+        newPtr->bits[0] = (bits & lower_mask[delta]) << (32 - delta);
+        newPtr->bitsleft -= delta;
+        newPtr->bitsleftcur -= delta;
+    } else {
+        /*
+         * the current bucket will be sufficient
+         */
+        delta = nbits - lastPtr->bitsleftcur;
+        lastPtr->bitsleftcur -= nbits;
+        lastPtr->bitsleft -= nbits;
+
+        if (delta >= 0)
+        {
+            /*
+             * these bits will span more than one word
+             */
+            lastPtr->bits[lastPtr->currword] |= (bits >> delta);
+            lastPtr->currword++;
+            lastPtr->bits[lastPtr->currword] = 
+                (bits & lower_mask[delta]) << (32 - delta);
+            lastPtr->bitsleftcur = 32 - delta;
+        } else {
+            /*
+         * these bits will fit, whole
+         */
+            lastPtr->bits[lastPtr->currword] |= (bits << (-delta));
+        }
+    }
+
+    if ( bbPtr->totalbits > MAX_BITS )  /* flush bits */
+        Dump(bbPtr);
+}
+
+
+/*===========================================================================*
+ *
+ * Bitio_Flush
+ *
+ *  Flushes all of the remaining bits in the given bit bucket to the
+ *  appropriate output file.  It will generate up to the nearest 8-bit
+ *  unit of bits, which means that up to 7 extra 0 bits will be appended
+ *  to the end of the file.
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    frees the bit bucket
+ *
+ *===========================================================================*/
+void
+Bitio_Flush(BitBucket * const bbPtr) {
+
+    struct bitBucket *ptr, *tempPtr;
+    uint32  lastWord;
+    int i, nitems;
+    int     bitsWritten = 0;
+    int     bitsLeft;
+    unsigned int     numWords;
+    uint8   charBuf[4];
+    boolean    flushHere = FALSE;
+    time_t  tempTimeStart, tempTimeEnd;
+
+    time(&tempTimeStart);
+
+    bitsLeft = bbPtr->totalbits;
+
+    for (ptr = bbPtr->firstPtr; ptr; ptr = ptr->nextPtr) {
+        if (ptr->bitsleftcur == 32 && ptr->currword == 0) {
+            continue;       /* empty */
+        }
+
+        if ( bitsLeft >= 32 ) {
+            bigend32 buffer[WORDS_PER_BUCKET];
+
+            if ( ((ptr->currword + 1) * 32) > bitsLeft ) {
+                numWords = ptr->currword;
+                flushHere = TRUE;
+            } else
+                numWords = ptr->currword+1;
+
+            for (i = 0; i < numWords; ++i)
+                buffer[i] = pm_bigendFromUint32(ptr->bits[i]);
+
+            nitems = fwrite(buffer, sizeof(buffer[0]), numWords,
+                            bbPtr->filePtr);
+            if (nitems != numWords) {
+                if (ferror(bbPtr->filePtr))
+                    pm_error("Error writing %u words to flush a bit bucket.  "
+                             "fwrite() gives errno %d (%s)", 
+                             numWords, errno, strerror(errno));
+                else
+                    pm_error("Problem writing %u words "
+                             "to flush a bit bucket.  "
+                             "Only %d words transferred.", 
+                             numWords, nitems);
+            }
+
+            bitsWritten += (numWords * 32);
+            bitsLeft -= (numWords * 32);
+        } else {
+            flushHere = TRUE;
+        }
+
+        if ( (bitsLeft < 32) && flushHere ) {
+            lastWord = ptr->bits[ptr->currword];
+
+            /* output the lastPtr word in big-endian order (network) */
+
+            /* now write out lastPtr bits */
+            while ( bitsLeft > 0 ) {
+                charBuf[0] = (lastWord >> 24);
+                charBuf[0] &= lower_mask[8];
+                fwrite(charBuf, 1, sizeof(uint8), bbPtr->filePtr);
+                lastWord = (lastWord << 8);
+                bitsLeft -= 8;
+                bitsWritten += 8;
+            }
+        }
+    }
+    fflush(bbPtr->filePtr);
+    while ( bbPtr->firstPtr != ptr ) {
+        tempPtr = bbPtr->firstPtr;
+        bbPtr->firstPtr = tempPtr->nextPtr;
+        free(tempPtr);
+    }
+
+    free(bbPtr);
+
+    time(&tempTimeEnd);
+    IOtime += (tempTimeEnd-tempTimeStart);
+}
+
+
+
+void
+Bitio_Close(BitBucket * const bbPtr) {
+
+    fclose(bbPtr->filePtr);
+}
+
+
+
+/*===========================================================================*
+ *
+ * Bitio_WriteToSocket
+ *
+ *  Writes all of the remaining bits in the given bit bucket to the
+ *  given socket.  May pad the end of the socket stream with extra 0
+ *  bits as does Bitio_Flush.
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    frees the bit bucket
+ *
+ *===========================================================================*/
+void
+Bitio_WriteToSocket(BitBucket * const bbPtr, 
+                    int         const socket) {
+
+    struct bitBucket *ptr, *tempPtr;
+    uint32  lastWord;
+    int i, nitems;
+    int     bitsWritten = 0;
+    int     bitsLeft;
+    int     numWords;
+    uint8   charBuf[4];
+    boolean    flushHere = FALSE;
+
+    bitsLeft = bbPtr->totalbits;
+
+    for (ptr = bbPtr->firstPtr; ptr; ptr = ptr->nextPtr) {
+        if (ptr->bitsleftcur == 32 && ptr->currword == 0) {
+            continue;       /* empty */
+        }
+
+        if ( bitsLeft >= 32 ) {
+            bigend32 buffer[WORDS_PER_BUCKET];
+
+            if ( ((ptr->currword + 1) * 32) > bitsLeft ) {
+                numWords = ptr->currword;
+                flushHere = TRUE;
+            } else {
+                numWords = ptr->currword+1;
+            }
+
+            for (i = 0; i < numWords; ++i)
+                buffer[i] = pm_bigendFromUint32(ptr->bits[i]);
+
+            nitems = write(socket, buffer, numWords * sizeof(buffer[0]));
+            if (nitems != numWords*sizeof(uint32)) {
+                fprintf(stderr, "Whoa!  Trouble writing %u bytes "
+                        "(wrote %u bytes)!  "
+                        "Game over, dude!\n",
+                        (unsigned)(numWords*sizeof(buffer[0])), nitems);
+                exit(1);
+            }
+
+            bitsWritten += (numWords * 32);
+            bitsLeft -= (numWords * 32);
+        } else {
+            flushHere = TRUE;
+        }
+
+        if ( (bitsLeft < 32) && flushHere ) {
+            lastWord = ptr->bits[ptr->currword];
+
+            /* output the lastPtr word in big-endian order (network) */
+
+            /* now write out lastPtr bits */
+            while ( bitsLeft > 0 ) {
+                charBuf[0] = (lastWord >> 24);
+                charBuf[0] &= lower_mask[8];
+                if ( write(socket, charBuf, 1) != 1 ) {
+                    fprintf(stderr, "ERROR:  write of lastPtr bits\n");
+                    exit(1);
+                }
+                lastWord = (lastWord << 8);
+                bitsLeft -= 8;
+                bitsWritten += 8;
+            }
+        }
+    }
+
+    while ( bbPtr->firstPtr != ptr ) {
+        tempPtr = bbPtr->firstPtr;
+        bbPtr->firstPtr = tempPtr->nextPtr;
+        free(tempPtr);
+    }
+
+    free(bbPtr);
+}
+
+
+/*===========================================================================*
+ *
+ * Bitio_BytePad
+ *
+ *  Pads the end of the bit bucket to the nearest byte with 0 bits
+ *
+ * RETURNS: nothing
+ *
+ *===========================================================================*/
+void
+Bitio_BytePad(BitBucket * const bbPtr) {
+
+    struct bitBucket *lastPtrPtr = bbPtr->lastPtr;
+
+    if (lastPtrPtr->bitsleftcur % 8) {
+        Bitio_Write(bbPtr, 0, lastPtrPtr->bitsleftcur % 8);
+    }
+}
diff --git a/converter/ppm/ppmtompeg/block.c b/converter/ppm/ppmtompeg/block.c
new file mode 100644
index 00000000..913518c4
--- /dev/null
+++ b/converter/ppm/ppmtompeg/block.c
@@ -0,0 +1,1045 @@
+/*===========================================================================*
+ * block.c
+ *
+ *  Block routines
+ *
+ * NOTES:   MAD =   Mean Absolute Difference
+ *===========================================================================*/
+
+/* Copyright information is at end of file */
+
+#include <assert.h>
+
+#include "pm_c_util.h"
+#include "all.h"
+#include "mtypes.h"
+#include "frames.h"
+#include "bitio.h"
+#include "prototypes.h"
+#include "fsize.h"
+#include "opts.h"
+#include "postdct.h"
+
+#include "block.h"
+
+#define TRUNCATE_UINT8(x)   ((x < 0) ? 0 : ((x > 255) ? 255 : x))
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+
+
+extern Block **dct, **dctb, **dctr;
+
+
+static vector
+halfVector(vector const v) {
+    vector half;
+
+    half.y = v.y/2;
+    half.x = v.x/2;
+
+    return half;
+}
+
+/*===========================*
+ * COMPUTE DCT OF DIFFERENCE *
+ *===========================*/
+
+/*===========================================================================*
+ *
+ *  compute current-motionBlock, take the DCT, and put the difference
+ *  back into current
+ *
+ * RETURNS: current block modified
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+ComputeDiffDCTBlock(Block           current,
+                    Block           dest,
+                    Block           motionBlock,
+                    boolean * const significantDifferenceP) {
+
+    unsigned int y;
+    int diff;
+
+    diff = 0;  /* initial value */
+
+    for (y = 0; y < 8; ++y) {
+        unsigned int x;
+        for (x = 0; x < 8; ++x) {
+            current[y][x] -= motionBlock[y][x];
+            diff += ABS(current[y][x]);
+        }
+    }
+    /* Kill the block if change is too small     */
+    /* (block_bound defaults to 128, see opts.c) */
+    if (diff < block_bound)
+        *significantDifferenceP = FALSE;
+    else {
+        mp_fwd_dct_block2(current, dest);
+        *significantDifferenceP = TRUE;
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ *  appropriate (according to pattern, the coded block pattern) blocks
+ *  of 'current' are diff'ed and DCT'd.
+ *
+ * RETURNS: current blocks modified
+ *
+ * SIDE EFFECTS:    Can remove too-small difference blocks from pattern
+ *
+ * PRECONDITIONS:   appropriate blocks of 'current' have not yet been
+ *          modified
+ *
+ *===========================================================================*/
+void
+ComputeDiffDCTs(MpegFrame * const current,
+                MpegFrame * const prev,
+                int         const by,
+                int         const bx,
+                vector      const m,
+                int *       const patternP) {
+    
+    Block motionBlock;
+
+    if (collect_quant && (collect_quant_detailed & 1))
+        fprintf(collect_quant_fp, "l\n");
+    if (*patternP & 0x20) {
+        boolean significantDiff;
+        ComputeMotionBlock(prev->ref_y, by, bx, m, &motionBlock);
+        ComputeDiffDCTBlock(current->y_blocks[by][bx], dct[by][bx],
+                            motionBlock, &significantDiff);
+        if (!significantDiff)
+            *patternP ^= 0x20;
+    }
+
+    if (*patternP & 0x10) {
+        boolean significantDiff;
+        ComputeMotionBlock(prev->ref_y, by, bx+1, m, &motionBlock);
+        ComputeDiffDCTBlock(current->y_blocks[by][bx+1], dct[by][bx+1],
+                            motionBlock, &significantDiff);
+        if (!significantDiff)
+            *patternP ^= 0x10;
+    }
+
+    if (*patternP & 0x8) {
+        boolean significantDiff;
+        ComputeMotionBlock(prev->ref_y, by+1, bx, m, &motionBlock);
+        ComputeDiffDCTBlock(current->y_blocks[by+1][bx], dct[by+1][bx],
+                            motionBlock, &significantDiff);
+        if (!significantDiff)
+            *patternP ^= 0x8;
+    }
+
+    if (*patternP & 0x4) {
+        boolean significantDiff;
+        ComputeMotionBlock(prev->ref_y, by+1, bx+1, m, &motionBlock);
+        ComputeDiffDCTBlock(current->y_blocks[by+1][bx+1], dct[by+1][bx+1],
+                            motionBlock, &significantDiff);
+        if (!significantDiff)
+            *patternP ^= 0x4;
+    }
+
+    if (collect_quant && (collect_quant_detailed & 1))
+        fprintf(collect_quant_fp, "c\n");
+
+    if (*patternP & 0x2) {
+        boolean significantDiff;
+        ComputeMotionBlock(prev->ref_cb, by/2, bx/2, halfVector(m),
+                           &motionBlock);
+        ComputeDiffDCTBlock(current->cb_blocks[by/2][bx/2],
+                            dctb[by/2][bx/2], motionBlock,
+                            &significantDiff);
+        if (!significantDiff)
+            *patternP ^= 0x2;
+    }
+
+    if (*patternP & 0x1) {
+        boolean significantDiff;
+        ComputeMotionBlock(prev->ref_cr, by/2, bx/2, halfVector(m),
+                           &motionBlock);
+        ComputeDiffDCTBlock(current->cr_blocks[by/2][bx/2],
+                            dctr[by/2][bx/2], motionBlock,
+                            &significantDiff);
+        if (!significantDiff)
+            *patternP ^= 0x1;
+    }
+}
+
+
+
+static void
+computePrevFyFx(MpegFrame * const prevFrame,
+                int         const by,
+                int         const bx,
+                vector      const m,
+                uint8 ***   const prevP,
+                int *       const fyP,
+                int *       const fxP) {
+
+    boolean const xHalf = (ABS(m.x) % 2 == 1);
+    boolean const yHalf = (ABS(m.y) % 2 == 1);
+
+    MotionToFrameCoord(by, bx, m.y/2, m.x/2, fyP, fxP);
+
+    assert(*fyP >= 0); assert(*fxP >= 0);
+
+    /* C integer arithmetic rounds toward zero.  But what we need is a
+       "floor" -- i.e. round down.  So we adjust now for where the dividend
+       in the above divide by two was negative.
+    */
+
+    if (xHalf) {
+        if (m.x < 0)
+            --*fxP;
+
+        if (yHalf) {
+            if (m.y < 0)
+                --*fyP;
+        
+            *prevP = prevFrame->halfBoth;
+        } else
+            *prevP = prevFrame->halfX;
+    } else if (yHalf) {
+        if (m.y < 0)
+            --*fyP;
+        
+        *prevP = prevFrame->halfY;
+    } else
+        *prevP = prevFrame->ref_y;
+}
+
+
+
+/*======================*
+ * COMPUTE MOTION BLOCK *
+ *======================*/
+
+/*===========================================================================*
+ *
+ *  compute the motion-compensated block
+ *
+ * RETURNS: motionBlock
+ *
+ * SIDE EFFECTS:    none
+ *
+ * PRECONDITIONS:   motion vector MUST be valid
+ *
+ * NOTE:  could try to speed this up using halfX, halfY, halfBoth,
+ *    but then would have to compute for chrominance, and it's just
+ *    not worth the trouble (this procedure is not called relatively
+ *    often -- a constant number of times per macroblock)
+ *
+ *===========================================================================*/
+void
+ComputeMotionBlock(uint8 ** const prev,
+                   int      const by,
+                   int      const bx,
+                   vector   const m,
+                   Block *  const motionBlockP) {
+
+    int fy, fx;
+    boolean xHalf, yHalf;
+
+    xHalf = (ABS(m.x) % 2 == 1);
+    yHalf = (ABS(m.y) % 2 == 1);
+
+    MotionToFrameCoord(by, bx, m.y/2, m.x/2, &fy, &fx);
+
+    if (xHalf && yHalf) {
+        unsigned int y;
+        /* really should be fy+y-1 and fy+y so do (fy-1)+y = fy+y-1 and
+           (fy-1)+y+1 = fy+y
+        */
+        if (m.y < 0)
+            --fy;
+
+        if (m.x < 0)
+            --fx;
+    
+        for (y = 0; y < 8; ++y) {
+            int16 * const destPtr = (*motionBlockP)[y];
+            uint8 * const srcPtr  = &(prev[fy+y][fx]);
+            uint8 * const srcPtr2 = &(prev[fy+y+1][fx]);
+            unsigned int x;
+
+            for (x = 0; x < 8; ++x)
+                destPtr[x] =
+                    (srcPtr[x]+srcPtr[x+1]+srcPtr2[x]+srcPtr2[x+1]+2) >> 2;
+        }
+    } else if (xHalf) {
+        unsigned int y;
+        if (m.x < 0)
+            --fx;
+        
+        for (y = 0; y < 8; ++y) {
+            int16 * const destPtr = (*motionBlockP)[y];
+            uint8 * const srcPtr  = &(prev[fy+y][fx]);
+            unsigned int x;
+
+            for (x = 0; x < 8; ++x)
+                destPtr[x] = (srcPtr[x]+srcPtr[x+1]+1) >> 1;
+        }
+    } else if (yHalf) {
+        unsigned int y;
+        if ( m.y < 0 )
+            fy--;
+
+        for (y = 0; y < 8; ++y) {
+            int16 * const destPtr = (*motionBlockP)[y];
+            uint8 * const srcPtr  = &(prev[fy+y][fx]);
+            uint8 * const srcPtr2 = &(prev[fy+y+1][fx]);
+            unsigned int x;
+
+            for (x = 0; x < 8; ++x)
+                destPtr[x] = (srcPtr[x]+srcPtr2[x]+1) >> 1;
+        }
+    } else {
+        unsigned int y;
+        for (y = 0; y < 8; ++y) {
+            int16 * const destPtr = (*motionBlockP)[y];
+            uint8 * const srcPtr  = &(prev[fy+y][fx]);
+            unsigned int x;
+
+            for (x = 0; x < 8; ++x)
+                destPtr[x] = srcPtr[x];
+        }
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ *  compute the motion-compensated luminance block
+ *
+ * RETURNS: motionBlock
+ *
+ * SIDE EFFECTS:    none
+ *
+ * PRECONDITIONS:   motion vector MUST be valid
+ *
+ * NOTE:  see ComputeMotionBlock
+ *
+ *===========================================================================*/
+void
+ComputeMotionLumBlock(MpegFrame * const prevFrame,
+                      int         const by,
+                      int         const bx,
+                      vector      const m,
+                      LumBlock *  const motionBlockP) {
+
+    unsigned int y;
+    uint8 ** prev;
+    int fy, fx;
+
+    computePrevFyFx(prevFrame, by, bx, m, &prev, &fy, &fx);
+
+    for (y = 0; y < 16; ++y) {
+        uint8 * const across  = &(prev[fy+y][fx]);
+        int32 * const macross = motionBlockP->l[y];
+        unsigned int x;
+
+        for (x = 0; x < 16; ++x)
+            macross[x] = across[x];
+    }
+
+    /* this is what's really happening, in slow motion:
+     *
+     *  for (y = 0; y < 16; ++y, ++py)
+     *      for (x = 0; x < 16; ++x, ++px)
+     *          motionBlock[y][x] = prev[fy+y][fx+x];
+     *
+     */
+}
+
+
+/*=======================*
+ * BASIC ERROR FUNCTIONS *
+ *=======================*/
+
+
+/*===========================================================================*
+ *
+ *  return the MAD of two luminance blocks
+ *
+ * RETURNS: the MAD, if less than bestSoFar, or some number bigger if not
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+int32
+LumBlockMAD(const LumBlock * const currentBlockP,
+            const LumBlock * const motionBlockP,
+            int32            const bestSoFar) {
+
+    int32 diff;    /* max value of diff is 255*256 = 65280 */
+    unsigned int y;
+
+    diff = 0;  /* initial value */
+
+    for (y = 0; y < 16; ++y) {
+        const int32 * const currentRow = currentBlockP->l[y];
+        const int32 * const motionRow  = motionBlockP->l[y];
+        unsigned int x;
+        for (x = 0; x < 16; ++x)
+            diff += ABS(currentRow[x] - motionRow[x]);
+
+        if (diff > bestSoFar)
+            /* We already know the MAD won't be less than bestSoFar;
+               Caller doesn't care by how much we missed, so just return
+               this.
+            */
+            return diff;
+    }
+    /* Return the actual MAD */
+    return diff;
+}
+
+
+
+/*===========================================================================*
+ *
+ *  return the MAD of the currentBlock and the motion-compensated block
+ *      (without TUNEing)
+ *
+ *  (by, bx) is the location of the block in the frame 
+ *  (block number coordinates).  'm' is the motion of the block in pixels.
+ *  The moved block must be wholly within the frame.
+ *
+ * RETURNS: the MAD, if less than bestSoFar, or
+ *      some number bigger if not
+ *
+ * SIDE EFFECTS:    none
+ *
+ * PRECONDITIONS:  motion vector MUST be valid
+ *
+ * NOTES:  this is the procedure that is called the most, and should therefore
+ *         be the most optimized!!!
+ *
+ *===========================================================================*/
+int32
+LumMotionError(const LumBlock * const currentBlockP,
+               MpegFrame *      const prevFrame,
+               int              const by,
+               int              const bx,
+               vector           const m,
+               int32            const bestSoFar) {
+
+    int32 adiff;
+    int32 diff;    /* max value of diff is 255*256 = 65280 */
+    int y;
+    uint8 **prev;
+    int fy, fx;
+
+    computePrevFyFx(prevFrame, by, bx, m, &prev, &fy, &fx);
+
+    assert(fy >= 0); assert(fx >= 0);
+
+    adiff = 0;  /* initial value */
+    diff = 0; /* initial value */
+
+    switch (SearchCompareMode) {
+    case DEFAULT_SEARCH: /* Default. */
+        for (y = 0; y < 16; ++y) {
+            const int32 * const cacross = currentBlockP->l[y];
+            uint8 *       const across  = &prev[fy+y][fx];
+            unsigned int x;
+            
+            for (x = 0; x < 16; ++x) {
+                int32 const localDiff = across[x]-cacross[x];
+                diff += ABS(localDiff);
+            }
+            if (diff > bestSoFar)
+                return diff;
+        }
+        break;
+      
+    case LOCAL_DCT: {
+        Block     dctdiff[4], dctquant[4];
+        FlatBlock quant;
+        int x, i, tmp;
+        int distortion=0, datarate=0;
+        int pq = GetPQScale();
+      
+        for (y = 0;  y < 16;  ++y) {
+            const int32 * const cacross = currentBlockP->l[y];
+            uint8 * const across = &(prev[fy+y][fx]);
+            for (x = 0;  x < 16;  ++x) {
+                dctdiff[(x>7)+2*(y>7)][y%8][x%8] = cacross[x]-across[x];
+            }}
+
+        /* Calculate rate */
+        for (i = 0;  i < 4;  ++i) {
+            mp_fwd_dct_block2(dctdiff[i], dctdiff[i]);
+            if (Mpost_QuantZigBlock(dctdiff[i], quant, pq, FALSE) ==
+                MPOST_ZERO) {
+                /* no sense in continuing */
+                memset((char *)dctquant[i], 0, sizeof(Block));
+            } else {
+                Mpost_UnQuantZigBlock(quant, dctquant[i], pq, FALSE);
+                mpeg_jrevdct((int16 *)dctquant[i]);
+                datarate += CalcRLEHuffLength(quant);
+            }
+        }
+      
+        /* Calculate distortion */
+        for (y = 0;  y < 16;  ++y) {
+            const int32 * const cacross = currentBlockP->l[y];
+            uint8 * const across = &(prev[fy+y][fx]);
+            for (x = 0;  x < 16;  ++x) {
+                tmp = across[x] - cacross[x] +
+                    dctquant[(x>7)+2*(y>7)][y%8][x%8];
+                distortion += tmp*tmp;
+            }}
+        distortion /= 256;
+        distortion *= LocalDCTDistortScale;
+        datarate *= LocalDCTRateScale;
+        diff = (int) sqrt(distortion*distortion + datarate*datarate);
+        break;
+    }
+
+    case NO_DC_SEARCH: {
+        extern int32 niqtable[];
+        int pq = niqtable[0]*GetPQScale();
+        unsigned int y;
+        
+        for (y = 0; y < 16; ++y) {
+            const int32 * const cacross = currentBlockP->l[y];
+            uint8 * const across = &(prev[fy+y][fx]);
+            unsigned int x;
+            
+            for (x = 0; x < 16; ++x) {
+                int32 const localDiff = across[x]-cacross[x];
+                diff += localDiff;
+                adiff += ABS(localDiff);
+            }
+        }
+
+        diff /= 64*pq;  /* diff is now the DC difference (with QSCALE 1) */
+        adiff -= 64*pq*ABS(diff);
+        diff = adiff;
+    }
+    break;
+
+    case DO_Mean_Squared_Distortion:
+        for (y = 0; y < 16; ++y) {
+            const int32 * const cacross = currentBlockP->l[y];
+            uint8 * const across = &(prev[fy+y][fx]);
+            unsigned int x;
+
+            for (x = 0; x < 16; ++x) {
+                int32 const localDiff = across[x] - cacross[x];
+                diff += localDiff * localDiff;
+            }
+            if (diff > bestSoFar)
+                return diff;
+        }
+        break;
+    } /* End of Switch */
+
+    return diff;
+}
+
+
+
+/*===========================================================================*
+ *
+ *  return the MAD of the currentBlock and the average of the blockSoFar
+ *  and the motion-compensated block (this is used for B-frame searches)
+ *
+ * RETURNS: the MAD, if less than bestSoFar, or
+ *      some number bigger if not
+ *
+ * SIDE EFFECTS:    none
+ *
+ * PRECONDITIONS:  motion vector MUST be valid
+ *
+ *===========================================================================*/
+int32
+LumAddMotionError(const LumBlock * const currentBlockP,
+                  const LumBlock * const blockSoFarP,
+                  MpegFrame *      const prevFrame,
+                  int              const by,
+                  int              const bx,
+                  vector           const m,
+                  int32            const bestSoFar) {
+
+    int32 diff;    /* max value of diff is 255*256 = 65280 */
+    int y;
+    uint8 **prev;
+    int fy, fx;
+
+    computePrevFyFx(prevFrame, by, bx, m, &prev, &fy, &fx);
+
+    diff = 0; /* initial value */
+
+    /* do we add 1 before dividing by two?  Yes -- see MPEG-1 doc page 46 */
+
+    for (y = 0; y < 16; ++y) {
+        unsigned int x;
+        const uint8 * const across  = &prev[fy+y][fx];
+        const int32 * const bacross = blockSoFarP->l[y];
+        const int32 * const cacross = currentBlockP->l[y];
+
+        for (x = 0; x < 16; ++x) {
+            int32 const localDiff =
+                ((across[x] + bacross[x] + 1) / 2) - cacross[x];
+            diff += ABS(localDiff);
+        }
+
+        if (diff > bestSoFar)
+            return diff;
+    }
+    
+    /* This is what's happening:
+     *
+     *  ComputeMotionLumBlock(prevFrame, by, bx, my, mx, lumMotionBlock);
+     *
+     *  for (y = 0; y < 16; ++y)
+     *      for (x = 0; x < 16; ++x) {
+     *          localDiff = currentBlock[y][x] - lumMotionBlock[y][x];
+     *          diff += ABS(localDiff);
+     *      }
+     */
+
+    return diff;
+}
+
+
+
+/*===========================================================================*
+ *
+ *  adds the motion-compensated block to the given block
+ *
+ * RETURNS: block modified
+ *
+ * SIDE EFFECTS:    none
+ *
+ * PRECONDITIONS:  motion vector MUST be valid
+ *
+ *===========================================================================*/
+void
+AddMotionBlock(Block          block,
+               uint8 ** const prev,
+               int      const by,
+               int      const bx,
+               vector   const m) {
+
+    int     fy, fx;
+    boolean xHalf, yHalf;
+
+    xHalf = (ABS(m.x) % 2 == 1);
+    yHalf = (ABS(m.y) % 2 == 1);
+
+    MotionToFrameCoord(by, bx, (m.y/2), (m.x/2), &fy, &fx);
+
+    if (xHalf && yHalf) {
+        unsigned int y;
+        /* really should be fy+y-1 and fy+y so do (fy-1)+y = fy+y-1 and
+           (fy-1)+y+1 = fy+y
+        */
+        if (m.y < 0)
+            --fy;
+        if (m.x < 0)
+            --fx;
+
+        for (y = 0; y < 8; ++y) {
+            unsigned int x;
+            for (x = 0; x < 8; ++x)
+                block[y][x] += (prev[fy+y][fx+x]+prev[fy+y][fx+x+1]+
+                                prev[fy+y+1][fx+x]+prev[fy+y+1][fx+x+1]+2)>>2;
+        }
+    } else if (xHalf) {
+        unsigned int y;
+        if (m.x < 0)
+            --fx;
+
+        for (y = 0; y < 8; ++y) {
+            unsigned int x;
+            for (x = 0; x < 8; ++x) {
+                block[y][x] += (prev[fy+y][fx+x]+prev[fy+y][fx+x+1]+1)>>1;
+            }
+        }
+    } else if ( yHalf ) {
+        unsigned int y;
+        if (m.y < 0)
+            --fy;
+
+        for (y = 0; y < 8; ++y) {
+            unsigned int x;
+            for (x = 0; x < 8; ++x) {
+                block[y][x] += (prev[fy+y][fx+x]+prev[fy+y+1][fx+x]+1)>>1;
+            }
+        }
+    } else {
+        unsigned int y;
+        for (y = 0; y < 8; ++y) {
+            unsigned int x;
+            for (x = 0; x < 8; ++x) {
+                block[y][x] += (int16)prev[fy+y][fx+x];
+            }
+        }
+    }
+}
+
+
+/*===========================================================================*
+ *
+ *  adds the motion-compensated B-frame block to the given block
+ *
+ * RETURNS: block modified
+ *
+ * SIDE EFFECTS:    none
+ *
+ * PRECONDITIONS:  motion vectors MUST be valid
+ *
+ *===========================================================================*/
+void
+AddBMotionBlock(Block          block,
+                uint8 ** const prev,
+                uint8 ** const next,
+                int      const by,
+                int      const bx,
+                int      const mode,
+                motion   const motion) {
+
+    unsigned int y;
+    Block prevBlock, nextBlock;
+
+    switch (mode) {
+    case MOTION_FORWARD:
+        AddMotionBlock(block, prev, by, bx, motion.fwd);
+        break;
+    case MOTION_BACKWARD:
+        AddMotionBlock(block, next, by, bx, motion.bwd);
+        break;
+    default:
+        ComputeMotionBlock(prev, by, bx, motion.fwd, &prevBlock);
+        ComputeMotionBlock(next, by, bx, motion.bwd, &nextBlock);
+    }
+    for (y = 0; y < 8; ++y) {
+        unsigned int x;
+        for (x = 0; x < 8; ++x) {
+            block[y][x] += (prevBlock[y][x] + nextBlock[y][x] + 1) / 2;
+        }
+    }
+}
+
+
+/*===========================================================================*
+ *
+ *  copies the given block into the appropriate data area
+ *
+ * RETURNS: data modified
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+BlockToData(uint8 ** const data,
+            Block          block,
+            int      const by,
+            int      const bx) {
+
+    int x, y;
+    int fy, fx;
+    int16    blockItem;
+
+    BLOCK_TO_FRAME_COORD(by, bx, fy, fx);
+
+    for ( y = 0; y < 8; y++ ) {
+    for ( x = 0; x < 8; x++ ) {
+        blockItem = block[y][x];
+        data[fy+y][fx+x] = TRUNCATE_UINT8(blockItem);
+    }
+    }
+}
+
+
+/*===========================================================================*
+ *
+ *  copies data into appropriate blocks
+ *
+ * RETURNS: mf modified
+ *
+ * SIDE EFFECTS:    none
+ *
+ * NOTES:  probably shouldn't be in this file
+ *
+ *===========================================================================*/
+void
+BlockifyFrame(MpegFrame * const frameP) {
+
+    int dctx, dcty;
+    int x, y;
+    int bx, by;
+    int fy, fx;
+    int16 *destPtr;
+    uint8 *srcPtr;
+    int16 *destPtr2;
+    uint8 *srcPtr2;
+    Block *blockPtr;
+    Block *blockPtr2;
+
+    dctx = Fsize_x / DCTSIZE;
+    dcty = Fsize_y / DCTSIZE;
+
+    /*
+     * copy y data into y_blocks
+     */
+    for (by = 0; by < dcty; by++) {
+    fy = by*DCTSIZE;
+    for (bx = 0; bx < dctx; bx++) {
+        fx = bx*DCTSIZE;
+        blockPtr = (Block *) &(frameP->y_blocks[by][bx][0][0]);
+        for (y = 0; y < DCTSIZE; y++) {
+        destPtr = &((*blockPtr)[y][0]);
+        srcPtr = &(frameP->orig_y[fy+y][fx]);
+        for (x = 0; x < DCTSIZE; x++) {
+            destPtr[x] = srcPtr[x];
+        }
+        }
+    }
+    }
+
+    /*
+     * copy cr/cb data into cr/cb_blocks
+     */
+    for (by = 0; by < (dcty >> 1); by++) {
+    fy = by*DCTSIZE;
+    for (bx = 0; bx < (dctx >> 1); bx++) {
+        fx = bx*DCTSIZE;
+        blockPtr = (Block *) &(frameP->cr_blocks[by][bx][0][0]);
+        blockPtr2 = (Block *) &(frameP->cb_blocks[by][bx][0][0]);
+        for (y = 0; y < DCTSIZE; y++) {
+        destPtr = &((*blockPtr)[y][0]);
+        srcPtr = &(frameP->orig_cr[fy+y][fx]);
+        destPtr2 = &((*blockPtr2)[y][0]);
+        srcPtr2 = &(frameP->orig_cb[fy+y][fx]);
+        for (x = 0; x < DCTSIZE; x++) {
+            destPtr[x] = srcPtr[x];
+            destPtr2[x] = srcPtr2[x];
+        }
+        }
+    }
+    }
+}
+
+
+/*===========================================================================*
+ *                                       *
+ * UNUSED PROCEDURES                                 *
+ *                                       *
+ *  The following procedures are all unused by the encoder           *
+ *                                       *
+ *  They are listed here for your convenience.  You might want to use    *
+ *  them if you experiment with different search techniques          *
+ *                                       *
+ *===========================================================================*/
+
+#ifdef UNUSED_PROCEDURES
+
+/* this procedure calculates the subsampled motion block (obviously)
+ *
+ * for speed, this procedure is probably not called anywhere (it is
+ * incorporated directly into LumDiffA, LumDiffB, etc.
+ *
+ * but leave it here anyway for clarity
+ *
+ * (startY, startX) = (0,0) for A....(0,1) for B...(1,0) for C...(1,1) for D
+ *  
+ */
+void
+ComputeSubSampledMotionLumBlock(MpegFrame * const prevFrame,
+                                int         const by,
+                                int         const bx,
+                                int         const my,
+                                int         const mx,
+                                LumBlock    const motionBlock,
+                                int         const startY,
+                                int         const startX) {
+
+    uint8 *across;
+    int32 *macross;
+    int32 *lastx;
+    int y;
+    uint8 **prev;
+    int    fy, fx;
+    boolean xHalf, yHalf;
+
+    xHalf = (ABS(mx) % 2 == 1);
+    yHalf = (ABS(my) % 2 == 1);
+
+    MotionToFrameCoord(by, bx, my/2, mx/2, &fy, &fx);
+
+    if ( xHalf ) {
+    if ( mx < 0 ) {
+        fx--;
+    }
+
+    if ( yHalf ) {
+        if ( my < 0 ) {
+        fy--;
+        }
+        
+        prev = prevFrame->halfBoth;
+    } else {
+        prev = prevFrame->halfX;
+    }
+    } else if ( yHalf ) {
+    if ( my < 0 ) {
+        fy--;
+    }
+
+    prev = prevFrame->halfY;
+    } else {
+    prev = prevFrame->ref_y;
+    }
+
+    for ( y = startY; y < 16; y += 2 ) {
+    across = &(prev[fy+y][fx+startX]);
+    macross = &(motionBlock[y][startX]);
+    lastx = &(motionBlock[y][16]);
+    while ( macross < lastx ) {
+        (*macross) = (*across);
+        across += 2;
+        macross += 2;
+    }
+    }
+
+    /* this is what's really going on in slow motion:
+     *
+     *  for ( y = startY; y < 16; y += 2 )
+     *      for ( x = startX; x < 16; x += 2 )
+     *      motionBlock[y][x] = prev[fy+y][fx+x];
+     *
+     */
+}
+
+
+/*===========================================================================*
+ *
+ *  return the MAD of the currentBlock and the motion-compensated block,
+ *  subsampled 4:1 with given starting coordinates (startY, startX)
+ *
+ * RETURNS: the MAD
+ *
+ * SIDE EFFECTS:    none
+ *
+ * PRECONDITIONS:  motion vector MUST be valid
+ *
+ * NOTES:  this procedure is never called.  Instead, see subsample.c.  This
+ *         procedure is provided only for possible use in extensions
+ *
+ *===========================================================================*/
+int32
+LumMotionErrorSubSampled(LumBlock    const currentBlock,
+                         MpegFrame * const prevFrame,
+                         int         const by,
+                         int         const bx,
+                         int         const my,
+                         int         const mx,
+                         int         const startY,
+                         int         const startX) {
+
+    int32 diff;     /* max value of diff is 255*256 = 65280 */
+    int32 localDiff;
+    int32 *cacross;
+    uint8 *macross;
+    int32 *lastx;
+    int y;
+    uint8 **prev;
+    int    fy, fx;
+    boolean xHalf, yHalf;
+
+    xHalf = (ABS(mx) % 2 == 1);
+    yHalf = (ABS(my) % 2 == 1);
+
+    motionToFrameCoord(by, bx, my/2, mx/2, &fy, &fx);
+
+    if ( xHalf ) {
+    if ( mx < 0 ) {
+        fx--;
+    }
+
+    if ( yHalf ) {
+        if ( my < 0 ) {
+        fy--;
+        }
+        
+        prev = prevFrame->halfBoth;
+    } else {
+        prev = prevFrame->halfX;
+    }
+    } else if ( yHalf ) {
+    if ( my < 0 ) {
+        fy--;
+    }
+
+    prev = prevFrame->halfY;
+    } else {
+    prev = prevFrame->ref_y;
+    }
+
+    diff = 0; /* initial value */
+
+    for ( y = startY; y < 16; y += 2 ) {
+    macross = &(prev[fy+y][fx+startX]);
+    cacross = &(currentBlock[y][startX]);
+    lastx = &(currentBlock[y][16]);
+    while ( cacross < lastx ) {
+        localDiff = (*cacross)-(*macross);
+        diff += ABS(localDiff);
+        macross += 2;
+        cacross += 2;
+    }
+    }
+
+    /* this is what's really happening:
+     *
+     *  ComputeSubSampledMotionLumBlock(prevFrame, by, bx, my, mx,
+     *                  lumMotionBlock, startY, startX);
+     *
+     *  for ( y = startY; y < 16; y += 2 )
+     *      for ( x = startX; x < 16; x += 2 )
+     *      {
+     *          localDiff = currentBlock[y][x] - lumMotionBlock[y][x];
+     *      diff += ABS(localDiff);
+     *      }
+     *
+     */
+
+    return (int32)diff;
+}
+
+
+#endif /* UNUSED_PROCEDURES */
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
diff --git a/converter/ppm/ppmtompeg/bsearch.c b/converter/ppm/ppmtompeg/bsearch.c
new file mode 100644
index 00000000..142987f5
--- /dev/null
+++ b/converter/ppm/ppmtompeg/bsearch.c
@@ -0,0 +1,1088 @@
+/*===========================================================================*
+ * bsearch.c
+ *
+ *  Procedures concerned with the B-frame motion search
+ *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /n/picasso/project/mpeg/mpeg_dist/mpeg_encode/RCS/bsearch.c,v 1.10 1995/08/07 21:49:01 smoot Exp $
+ *  $Log: bsearch.c,v $
+ *  Revision 1.10  1995/08/07 21:49:01  smoot
+ *  fixed bug in initial-B-frame searches
+ *
+ *  Revision 1.9  1995/06/26 21:36:07  smoot
+ *  added new ordering constraints
+ *  (B frames which are backward P's at the start of a sequence)
+ *
+ *  Revision 1.8  1995/03/27 19:17:43  smoot
+ *  killed useless type error messge (int32 defiend as int)
+ *
+ * Revision 1.7  1995/01/19  23:07:20  eyhung
+ * Changed copyrights
+ *
+ * Revision 1.6  1994/12/07  00:40:36  smoot
+ * Added seperate P and B search ranges
+ *
+ * Revision 1.5  1994/03/15  00:27:11  keving
+ * nothing
+ *
+ * Revision 1.4  1993/12/22  19:19:01  keving
+ * nothing
+ *
+ * Revision 1.3  1993/07/22  22:23:43  keving
+ * nothing
+ *
+ * Revision 1.2  1993/06/30  20:06:09  keving
+ * nothing
+ *
+ * Revision 1.1  1993/06/03  21:08:08  keving
+ * nothing
+ *
+ * Revision 1.1  1993/03/02  18:27:05  keving
+ * nothing
+ *
+ */
+
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "pm_c_util.h"
+#include "pm.h"
+#include "all.h"
+#include "mtypes.h"
+#include "frames.h"
+#include "motion_search.h"
+#include "fsize.h"
+
+
+/*==================*
+ * STATIC VARIABLES *
+ *==================*/
+
+static int  bsearchAlg;
+
+
+/*===========================*
+ * INITIALIZATION PROCEDURES *
+ *===========================*/
+
+
+/*===========================================================================*
+ *
+ * SetBSearchAlg
+ *
+ *  set the B-search algorithm
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    bsearchAlg modified
+ *
+ *===========================================================================*/
+void
+SetBSearchAlg(const char * const alg) {
+    if (strcmp(alg, "SIMPLE") == 0)
+        bsearchAlg = BSEARCH_SIMPLE;
+    else if (strcmp(alg, "CROSS2") == 0)
+        bsearchAlg = BSEARCH_CROSS2;
+    else if (strcmp(alg, "EXHAUSTIVE") == 0)
+        bsearchAlg = BSEARCH_EXHAUSTIVE;
+    else
+        pm_error("ERROR:  Impossible bsearch alg:  %s", alg);
+}
+
+
+/*===========================================================================*
+ *
+ * BSearchName
+ *
+ *  return the text of the B-search algorithm
+ *
+ * RETURNS: a pointer to the string
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+const char *
+BSearchName(void)
+{
+    const char *retval;
+
+    switch(bsearchAlg) {
+    case BSEARCH_SIMPLE:
+        retval = "SIMPLE";break;
+    case BSEARCH_CROSS2:
+        retval = "CROSS2";break;
+    case BSEARCH_EXHAUSTIVE:
+        retval = "EXHAUSTIVE";break;
+    default:
+        pm_error("ERROR:  Impossible BSEARCH ALG:  %d", psearchAlg);
+    }
+    return retval;
+}
+
+
+
+/*===========================================================================*
+ *
+ * FindBestMatchExhaust
+ *
+ *  tries to find matching motion vector
+ *  see FindBestMatch for generic description
+ *
+ * DESCRIPTION:  uses an exhaustive search
+ *
+ *===========================================================================*/
+static int32
+FindBestMatchExhaust(const LumBlock * const blockP,
+                     const LumBlock * const currentBlockP,
+                     MpegFrame *      const prev,
+                     int              const by,
+                     int              const bx,
+                     vector *         const motionP,
+                     int32            const bestSoFar,
+                     int              const searchRange) {
+
+    register int mx, my;
+    int32 bestDiff;
+    int   stepSize;
+    int   leftMY, leftMX;
+    int   rightMY, rightMX;
+    int   distance;
+    int   tempRightMY, tempRightMX;
+    boolean changed = FALSE;
+
+    stepSize = (pixelFullSearch ? 2 : 1);
+
+    COMPUTE_MOTION_BOUNDARY(by,bx,stepSize,leftMY,leftMX,rightMY,rightMX);
+
+    /* try old motion vector first */
+    if (VALID_MOTION(*motionP)) {
+        bestDiff = LumAddMotionError(currentBlockP, blockP, prev, by, bx,
+                                     *motionP, bestSoFar);
+
+        if (bestSoFar < bestDiff)
+            bestDiff = bestSoFar;
+    } else {
+        motionP->y = motionP->x = 0;
+        bestDiff = bestSoFar;
+    }
+
+    /* maybe should try spiral pattern centered around  prev motion vector? */
+
+    /* try a spiral pattern */    
+    for (distance = stepSize;
+         distance <= searchRange;
+         distance += stepSize) {
+        tempRightMY = MIN(distance, rightMY);
+        tempRightMX = MIN(distance, rightMX);
+
+        /* do top, bottom */
+        for (my = -distance; my < tempRightMY;
+             my += max(tempRightMY+distance-stepSize, stepSize)) {
+            if (my >= leftMY) {
+                for (mx = -distance; mx < tempRightMX; mx += stepSize) {
+                    if (mx >= leftMX) {
+                        int diff;
+                        vector m;
+                        m.y = my; m.x = mx;
+                        diff = LumAddMotionError(currentBlockP, blockP, prev,
+                                                 by, bx, m, bestDiff);
+                        
+                        if (diff < bestDiff) {
+                            *motionP = m;
+                            bestDiff = diff;
+                        }
+                    }
+                }
+            }
+        }
+
+        /* do left, right */
+        for (mx = -distance;
+             mx < tempRightMX;
+             mx += max(tempRightMX+distance-stepSize, stepSize)) {
+            if (mx >= leftMX) {
+                for (my = -distance+stepSize;
+                     my < tempRightMY-stepSize;
+                     my += stepSize) {
+                    if (my >= leftMY) {
+                        int diff;
+                        vector m;
+                        m.y = my; m.x = mx;
+                        diff = LumAddMotionError(currentBlockP, blockP, prev,
+                                                 by, bx,
+                                                 m, bestDiff);
+                        
+                        if (diff < bestDiff) {
+                            *motionP = m;
+                            bestDiff = diff;
+                            changed = TRUE;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    if (!changed)
+        ++bestDiff;
+
+    return bestDiff;
+}
+
+
+/*===========================================================================*
+ *
+ * FindBestMatchTwoLevel
+ *
+ *  tries to find matching motion vector
+ *  see FindBestMatch for generic description
+ *
+ * DESCRIPTION:  uses an exhaustive full-pixel search, then looks at
+ *       neighboring half-pixels
+ *
+ *===========================================================================*/
+static int32
+FindBestMatchTwoLevel(const LumBlock * const blockP,
+                      const LumBlock * const currentBlockP,
+                      MpegFrame *      const prev,
+                      int              const by,
+                      int              const bx,
+                      vector *         const motionP,
+                      int32            const bestSoFar,
+                      int              const searchRange) {
+
+    int mx, my;
+    int32 bestDiff;
+    int leftMY, leftMX;
+    int rightMY, rightMX;
+    int distance;
+    int tempRightMY, tempRightMX;
+    boolean changed = FALSE;
+    int yOffset, xOffset;
+
+    /* exhaustive full-pixel search first */
+
+    COMPUTE_MOTION_BOUNDARY(by,bx,2,leftMY,leftMX,rightMY,rightMX);
+
+    --rightMY;
+    --rightMX;
+
+    /* convert vector into full-pixel vector */
+    if (motionP->y > 0 ) {
+        if ((motionP->y % 2) == 1)
+            --motionP->y;
+    } else if ((-motionP->y % 2) == 1)
+        ++motionP->y;
+
+    if (motionP->x > 0 ) {
+        if ((motionP->x % 2) == 1 )
+            --motionP->x;
+    } else if ((-motionP->x % 2) == 1)
+        ++motionP->x;
+
+    /* try old motion vector first */
+    if (VALID_MOTION(*motionP)) {
+        bestDiff = LumAddMotionError(currentBlockP, blockP, prev, by, bx,
+                                     *motionP, bestSoFar);
+        
+        if (bestSoFar < bestDiff)
+            bestDiff = bestSoFar;
+    } else {
+        motionP->y = motionP->x = 0;
+        bestDiff = bestSoFar;
+    }
+
+    ++rightMY;
+    ++rightMX;
+
+    /* maybe should try spiral pattern centered around  prev motion vector? */
+
+    /* try a spiral pattern */    
+    for ( distance = 2; distance <= searchRange; distance += 2 ) {
+        tempRightMY = MIN(distance, rightMY);
+        tempRightMX = MIN(distance, rightMX);
+
+        /* do top, bottom */
+        for (my = -distance; my < tempRightMY;
+             my += max(tempRightMY+distance-2, 2)) {
+            if (my >= leftMY) {
+                for ( mx = -distance; mx < tempRightMX; mx += 2 ) {
+                    if (mx >= leftMX) {
+                        int diff;
+                        vector m;
+                        m.y = my; m.x = mx;
+                        diff = LumAddMotionError(currentBlockP, blockP, prev,
+                                                 by, bx, m, bestDiff);
+                        
+                        if (diff < bestDiff) {
+                            *motionP = m;
+                            bestDiff = diff;
+                        }
+                    }
+                }
+            }
+        }
+
+        /* do left, right */
+        for (mx = -distance;
+             mx < tempRightMX;
+             mx += max(tempRightMX+distance-2, 2)) {
+            if (mx >= leftMX) {
+                for (my = -distance+2; my < tempRightMY-2; my += 2) {
+                    if (my >= leftMY) {
+                        int diff;
+                        vector m;
+                        m.y = my; m.x = mx;
+                        diff = LumAddMotionError(currentBlockP, blockP, prev,
+                                                 by, bx, m, bestDiff);
+                        
+                        if (diff < bestDiff) {
+                            *motionP = m;
+                            bestDiff = diff;
+                            changed = TRUE;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /* now look at neighboring half-pixels */
+    my = motionP->y;
+    mx = motionP->x;
+
+    --rightMY;
+    --rightMX;
+
+    for (yOffset = -1; yOffset <= 1; ++yOffset) {
+        for (xOffset = -1; xOffset <= 1; ++xOffset) {
+            if ((yOffset != 0) || (xOffset != 0)) {
+                vector m;
+                m.y = my + yOffset;
+                m.x = mx + xOffset;
+                if (VALID_MOTION(m)) {
+                    int diff;
+                    diff = LumAddMotionError(currentBlockP, blockP,
+                                             prev, by, bx, m, bestDiff);
+                    if (diff < bestDiff) {
+                        *motionP = m;
+                        bestDiff = diff;
+                        changed = TRUE;
+                    }
+                }
+            }
+        }
+    }
+
+    if (!changed)
+        ++bestDiff;
+
+    return bestDiff;
+}
+
+
+
+static void
+trySpacing(int              const spacing,
+           vector           const center,
+           int              const bestDiffSoFar,
+           vector *         const newCenterP,
+           int32 *          const newBestDiffP,
+           int              const leftMY,
+           int              const leftMX,
+           int              const rightMY,
+           int              const rightMX,
+           const LumBlock * const currentBlockP,
+           const LumBlock * const blockP,
+           MpegFrame *      const prev,
+           int              const by,
+           int              const bx) {
+           
+    int tempRightMY, tempRightMX;
+    int my;
+    int bestDiff;
+    vector newCenter;
+
+    /* Initial values */
+    newCenter = center;
+    bestDiff   = bestDiffSoFar;
+
+    tempRightMY = MIN(rightMY, center.y + spacing + 1);
+    tempRightMX = MIN(rightMX, center.x + spacing + 1);
+    
+    for (my = center.y - spacing; my < tempRightMY; my += spacing) {
+        if (my >= leftMY) {
+            int mx;
+            for (mx = center.x - spacing; mx < tempRightMX; mx += spacing) {
+                if (mx >= leftMX) {
+                    int32 diff;
+                    vector m;
+                    m.y = my; m.x = mx;
+                    diff = LumAddMotionError(currentBlockP, blockP, prev,
+                                             by, bx, m, bestDiff);
+                    
+                    if (diff < bestDiff) {
+                        /* We have a new best */
+                        newCenter = m;
+                        bestDiff   = diff;
+                    }
+                }
+            }
+        }
+    }
+    *newCenterP  = newCenter;
+    *newBestDiffP = bestDiff;
+}
+
+
+
+static void
+chooseNewSpacing(int   const oldSpacing,
+                 int   const stepSize,
+                 int * const newSpacingP) {
+        
+    if (stepSize == 2) {  /* make sure spacing is even */
+        if (oldSpacing == 2)
+            *newSpacingP = 0;
+        else {
+            int const trialSpacing = (oldSpacing + 1) / 2;
+            if ((trialSpacing % 2) != 0)
+                *newSpacingP = trialSpacing + 1;
+            else
+                *newSpacingP = trialSpacing;
+        }
+    } else {
+        if (oldSpacing == 1)
+            *newSpacingP = 0;
+        else
+            *newSpacingP = (oldSpacing + 1) / 2;
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ * FindBestMatchLogarithmic
+ *
+ *  tries to find matching motion vector
+ *  see FindBestMatch for generic description
+ *
+ * DESCRIPTION:  uses a logarithmic search
+ *
+ *===========================================================================*/
+static int32
+FindBestMatchLogarithmic(const LumBlock * const blockP,
+                         const LumBlock * const currentBlockP,
+                         MpegFrame *      const prev,
+                         int              const by,
+                         int              const bx,
+                         vector *         const motionP,
+                         int32            const bestSoFar,
+                         int              const searchRange) {
+
+    int const stepSize = (pixelFullSearch ? 2 : 1);
+
+    int32 diff, bestDiff;
+    int leftMY, leftMX;
+    int rightMY, rightMX;
+    int spacing;
+    vector center;
+
+    COMPUTE_MOTION_BOUNDARY(by, bx, stepSize,
+                            leftMY, leftMX, rightMY, rightMX);
+
+    bestDiff = 0x7fffffff;
+
+    /* grid spacing */
+    if (stepSize == 2) {  /* make sure spacing is even */
+        spacing = (searchRange + 1) / 2;
+        if ((spacing % 2) != 0)
+            ++spacing;
+    } else
+        spacing = (searchRange + 1) / 2;
+
+    /* Start at (0,0) */
+    center.y = center.x = 0;
+    
+    while (spacing >= stepSize) {
+        trySpacing(spacing, center, bestDiff,
+                   &center, &bestDiff,
+                   leftMY, leftMX, rightMY, rightMX,
+                   currentBlockP, blockP, prev, by, bx);
+
+        chooseNewSpacing(spacing, stepSize, &spacing);
+    }
+
+    /* check old motion -- see if it's better */
+    if ((motionP->y >= leftMY) && (motionP->y < rightMY) &&
+        (motionP->x >= leftMX) && (motionP->x < rightMX)) {
+        diff = LumAddMotionError(currentBlockP, blockP, prev, by, bx,
+                                 *motionP, bestDiff);
+    } else
+        diff = 0x7fffffff;
+
+    if (bestDiff < diff)
+        *motionP = center;
+    else
+        bestDiff = diff;
+
+    return bestDiff;
+}
+
+
+
+/*===========================================================================*
+ *
+ * FindBestMatchSubSample
+ *
+ *  tries to find matching motion vector
+ *  see FindBestMatch for generic description
+ *
+ * DESCRIPTION:  should use subsampling method, but too lazy to write all
+ *       the code for it (so instead just calls FindBestMatchExhaust)
+ *
+ *===========================================================================*/
+static int32
+FindBestMatchSubSample(const LumBlock * const blockP,
+                       const LumBlock * const currentBlockP,
+                       MpegFrame *      const prev,
+                       int              const by,
+                       int              const bx,
+                       vector *         const motionP,
+                       int32            const bestSoFar,
+                       int              const searchRange) {
+
+    /* too lazy to write the code for this... */
+    
+    return FindBestMatchExhaust(blockP, currentBlockP, prev,
+                                by, bx, motionP, bestSoFar,
+                                searchRange);
+}
+
+
+/*===========================================================================*
+ *
+ * FindBestMatch
+ *
+ *  given a motion-compensated block in one direction, tries to find
+ *  the best motion vector in the opposite direction to match it
+ *
+ * RETURNS: the best vector (*motionY, *motionX), and the corresponding
+ *      error is returned if it is better than bestSoFar.  If not,
+ *      then a number greater than bestSoFar is returned and
+ *      (*motionY, *motionX) has no meaning.
+ *
+ * SIDE EFFECTS:  none
+ *
+ *===========================================================================*/
+static int32
+FindBestMatch(const LumBlock * const blockP,
+              const LumBlock * const currentBlockP,
+              MpegFrame *      const prev,
+              int              const by,
+              int              const bx,
+              vector *         const motionP,
+              int32            const bestSoFar,
+              int              const searchRange) {
+
+    int32 result;
+
+    switch(psearchAlg) {
+    case PSEARCH_SUBSAMPLE:
+        result = FindBestMatchSubSample(
+            blockP, currentBlockP, prev, by, bx,
+            motionP, bestSoFar, searchRange);
+        break;
+    case PSEARCH_EXHAUSTIVE:
+        result = FindBestMatchExhaust(
+            blockP, currentBlockP, prev, by, bx,
+            motionP, bestSoFar, searchRange);
+        break;
+    case PSEARCH_LOGARITHMIC:
+        result = FindBestMatchLogarithmic(
+            blockP, currentBlockP, prev, by, bx,
+            motionP, bestSoFar, searchRange);
+        break;
+    case PSEARCH_TWOLEVEL:
+        result = FindBestMatchTwoLevel(
+            blockP, currentBlockP, prev, by, bx,
+            motionP, bestSoFar, searchRange);
+        break;
+    default:
+        pm_error("ERROR:  Impossible P-search alg %d", psearchAlg);
+    }
+    return result;
+}
+
+
+
+/*===========================================================================*
+ *
+ *  finds the best backward and forward motion vectors
+ *  if backNeeded == FALSE, then won't find best backward vector if it
+ *  is worse than the best forward vector
+ *
+ * *motionP is input as well as output.  We do not update it
+ * if it would make the error worse than the existing value.
+ *
+ * RETURNS: *motionP and associated errors *forwardErrP and *backErrP.
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+BMotionSearchNoInterp(const LumBlock * const currentBlockP,
+                      MpegFrame *      const prev,
+                      MpegFrame *      const next,
+                      int              const by,
+                      int              const bx,
+                      motion *         const motionP,
+                      int32 *          const forwardErrP,
+                      int32 *          const backErrP,
+                      boolean          const backNeeded) {
+
+    /* CALL SEARCH PROCEDURE */
+    switch(psearchAlg) {
+    case PSEARCH_SUBSAMPLE:
+        *forwardErrP = PSubSampleSearch(currentBlockP, prev, by, bx, 
+                                        &motionP->fwd,searchRangeB);
+        *backErrP = PSubSampleSearch(currentBlockP, next, by, bx, 
+                                     &motionP->bwd, searchRangeB);
+        break;
+    case PSEARCH_EXHAUSTIVE:
+        *forwardErrP = PLocalSearch(currentBlockP, prev, by, bx,
+                                    &motionP->fwd,
+                                    0x7fffffff, searchRangeB);
+        if (backNeeded)
+            *backErrP = PLocalSearch(currentBlockP, next, by, bx,
+                                     &motionP->bwd,
+                                     0x7fffffff, searchRangeB);
+        else
+            *backErrP = PLocalSearch(currentBlockP, next, by, bx,
+                                     &motionP->bwd,
+                                     *forwardErrP, searchRangeB);
+        break;
+    case PSEARCH_LOGARITHMIC:
+        *forwardErrP = PLogarithmicSearch(currentBlockP, prev, by, bx, 
+                                          &motionP->fwd, searchRangeB);
+        *backErrP = PLogarithmicSearch(currentBlockP, next, by, bx, 
+                                       &motionP->bwd, searchRangeB);
+        break;
+    case PSEARCH_TWOLEVEL:
+        *forwardErrP =
+            PTwoLevelSearch(currentBlockP, prev, by, bx,
+                            &motionP->fwd, 0x7fffffff, searchRangeB);
+        if ( backNeeded ) {
+            *backErrP =
+                PTwoLevelSearch(currentBlockP, next, by, bx,
+                                &motionP->bwd, 0x7fffffff, searchRangeB);
+        } else {
+            *backErrP =
+                PTwoLevelSearch(currentBlockP, next, by, bx,
+                                &motionP->bwd, *forwardErrP, searchRangeB);
+        }
+        break;
+    default:
+        pm_error("ERROR:  Impossible PSEARCH ALG:  %d", psearchAlg);
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ * BMotionSearchSimple
+ *
+ *  does a simple search for B-frame motion vectors
+ *  see BMotionSearch for generic description
+ *
+ * DESCRIPTION:
+ *  1)  find best backward and forward vectors
+ *  2)  compute interpolated error using those two vectors
+ *  3)  return the best of the three choices
+ *
+ * *fmyP,fmxP,bmyP,bmxP are inputs as well as outputs.  We do not update
+ * them if it would make the error worse than the existing values.  Otherwise,
+ * we update them to the vectors we find to be best.
+ * 
+ *===========================================================================*/
+static int
+BMotionSearchSimple(const LumBlock * const currentBlockP,
+                    MpegFrame *      const prev,
+                    MpegFrame *      const next,
+                    int              const by,
+                    int              const bx,
+                    motion *         const motionP,
+                    int              const oldMode) {
+
+    int retval;
+    int32 forwardErr, backErr, interpErr;
+    LumBlock interpBlock;
+    int32 bestSoFar;
+
+    /* STEP 1 */
+    BMotionSearchNoInterp(currentBlockP, prev, next, by, bx, motionP,
+                          &forwardErr, &backErr, TRUE);
+              
+    /* STEP 2 */
+
+    ComputeBMotionLumBlock(prev, next, by, bx, MOTION_INTERPOLATE,
+                           *motionP, &interpBlock);
+    bestSoFar = min(backErr, forwardErr);
+    interpErr =
+        LumBlockMAD(currentBlockP, &interpBlock, bestSoFar);
+
+    /* STEP 3 */
+
+    if (interpErr <= forwardErr) {
+        if (interpErr <= backErr)
+            retval = MOTION_INTERPOLATE;
+        else
+            retval = MOTION_BACKWARD;
+    } else if (forwardErr <= backErr)
+        retval = MOTION_FORWARD;
+    else
+        retval = MOTION_BACKWARD;
+
+    return retval;
+}
+
+
+/*===========================================================================*
+ *
+ * BMotionSearchCross2
+ *
+ *  does a cross-2 search for B-frame motion vectors
+ *  see BMotionSearch for generic description
+ *
+ * DESCRIPTION:
+ *  1)  find best backward and forward vectors
+ *  2)  find best matching interpolating vectors
+ *  3)  return the best of the 4 choices
+ *
+ * *fmyP,fmxP,bmyP,bmxP are inputs as well as outputs.  We do not update
+ * them if it would make the error worse than the existing values.  Otherwise,
+ * we update them to the vectors we find to be best.
+ *===========================================================================*/
+static int
+BMotionSearchCross2(const LumBlock * const currentBlockP,
+                    MpegFrame *      const prev,
+                    MpegFrame *      const next,
+                    int              const by,
+                    int              const bx,
+                    motion *         const motionP,
+                    int              const oldMode) {
+    
+    int retval;
+    LumBlock forwardBlock, backBlock;
+    int32   forwardErr, backErr;
+    motion newMotion;
+    int32   interpErrF, interpErrB, interpErr;
+    int32   bestErr;
+
+    /* STEP 1 */
+
+    BMotionSearchNoInterp(currentBlockP, prev, next, by, bx, motionP,
+                          &forwardErr, &backErr, TRUE);
+
+    bestErr = min(forwardErr, backErr);
+
+    {
+        /* STEP 2 */
+        
+        struct motion motion;
+        motion.fwd = motionP->fwd;
+        motion.bwd.y = motion.bwd.x = 0;
+        ComputeBMotionLumBlock(prev, next, by, bx, MOTION_FORWARD, motion,
+                               &forwardBlock);
+        
+        motion.fwd.y = motion.fwd.x = 0;
+        motion.bwd = motionP->bwd;
+        ComputeBMotionLumBlock(prev, next, by, bx, MOTION_BACKWARD, motion,
+                               &backBlock);
+    }
+    /* try a cross-search; total of 4 local searches */    
+    newMotion = *motionP;
+
+    interpErrF = FindBestMatch(&forwardBlock, currentBlockP,
+                               next, by, bx, &newMotion.bwd,
+                               bestErr, searchRangeB);
+    bestErr = min(bestErr, interpErr);
+    interpErrB = FindBestMatch(&backBlock, currentBlockP,
+                               prev, by, bx, &newMotion.fwd,
+                               bestErr, searchRangeB);
+
+    /* STEP 3 */
+
+    if (interpErrF <= interpErrB) {
+        newMotion.fwd = motionP->fwd;
+        interpErr = interpErrF;
+    } else {
+        newMotion.bwd = motionP->bwd;
+        interpErr = interpErrB;
+    }
+
+    if (interpErr <= forwardErr) {
+        if (interpErr <= backErr) {
+            *motionP = newMotion;
+            retval = MOTION_INTERPOLATE;
+        } else
+            retval = MOTION_BACKWARD;
+    } else if (forwardErr <= backErr)
+        retval = MOTION_FORWARD;
+    else
+        retval = MOTION_BACKWARD;
+
+    return retval;
+}
+
+
+/*===========================================================================*
+ *
+ * BMotionSearchExhaust
+ *
+ *  does an exhaustive search for B-frame motion vectors
+ *  see BMotionSearch for generic description
+ *
+ * DESCRIPTION:
+ *  1)  find best backward and forward vectors
+ *  2)  use exhaustive search to find best interpolating vectors
+ *  3)  return the best of the 3 choices
+ *
+ * *fmyP,fmxP,bmyP,bmxP are inputs as well as outputs.  We do not update
+ * them if it would make the error worse than the existing values.  Otherwise,
+ * we update them to the vectors we find to be best.
+ *===========================================================================*/
+static int
+BMotionSearchExhaust(const LumBlock * const currentBlockP,
+                     MpegFrame *      const prev,
+                     MpegFrame *      const next,
+                     int              const by,
+                     int              const bx,
+                     motion *         const motionP,
+                     int              const oldMode) {
+
+    int mx, my;
+    int32 bestDiff;
+    int     stepSize;
+    LumBlock    forwardBlock;
+    int32   forwardErr, backErr;
+    int     leftMY, leftMX;
+    int     rightMY, rightMX;
+    boolean result;
+
+    /* STEP 1 */
+
+    BMotionSearchNoInterp(currentBlockP, prev, next, by, bx, motionP,
+                          &forwardErr, &backErr, FALSE);
+
+    if (forwardErr <= backErr) {
+        bestDiff = forwardErr;
+        result = MOTION_FORWARD;
+    } else {
+        bestDiff = backErr;
+        result = MOTION_BACKWARD;
+    }
+
+    /* STEP 2 */
+
+    stepSize = (pixelFullSearch ? 2 : 1);
+
+    COMPUTE_MOTION_BOUNDARY(by,bx,stepSize,leftMY,leftMX,rightMY,rightMX);
+
+    if (searchRangeB < rightMY)
+        rightMY = searchRangeB;
+    if (searchRangeB < rightMX)
+        rightMX = searchRangeB;
+
+    for (my = -searchRangeB; my < rightMY; my += stepSize) {
+        if (my >= leftMY) {
+            for (mx = -searchRangeB; mx < rightMX; mx += stepSize) {
+                if (mx >= leftMX) {
+                    struct motion motion;
+                    vector newMotion;
+                    int32 diff;
+                    motion.fwd.y = my; motion.fwd.x = mx;
+                    motion.bwd.y = 0;  motion.bwd.x = 0;
+                    ComputeBMotionLumBlock(prev, next, by, bx, MOTION_FORWARD,
+                                           motion, &forwardBlock);
+
+                    newMotion = motion.fwd;
+                    
+                    diff = FindBestMatch(&forwardBlock,
+                                         currentBlockP, next, by, bx,
+                                         &newMotion, bestDiff, searchRangeB);
+                    
+                    if (diff < bestDiff) {
+                        motionP->fwd = motion.fwd;
+                        motionP->bwd = newMotion;
+                        bestDiff = diff;
+                        result = MOTION_INTERPOLATE;
+                    }
+                }
+            }
+        }
+    }
+    return result;
+}
+
+
+
+/*===========================================================================*
+ *
+ *  search for the best B-frame motion vectors
+ *
+ * RETURNS: MOTION_FORWARD      forward motion should be used
+ *      MOTION_BACKWARD     backward motion should be used
+ *      MOTION_INTERPOLATE  both should be used and interpolated
+ *
+ * OUTPUTS: *motionP  =   TWICE the forward motion vectors
+ *
+ * SIDE EFFECTS:    none
+ *
+ * PRECONDITIONS:   The relevant block in 'current' is valid (it has not
+ *          been dct'd).  Thus, the data in 'current' can be
+ *          accesed through y_blocks, cr_blocks, and cb_blocks.
+ *          This is not the case for the blocks in 'prev' and
+ *          'next.'  Therefore, references into 'prev' and 'next'
+ *          should be done
+ *          through the struct items ref_y, ref_cr, ref_cb
+ *
+ * POSTCONDITIONS:  current, prev, next should be unchanged.
+ *          Some computation could be saved by requiring
+ *          the dct'd difference to be put into current's block
+ *          elements here, depending on the search technique.
+ *          However, it was decided that it mucks up the code
+ *          organization a little, and the saving in computation
+ *          would be relatively little (if any).
+ *
+ * NOTES:   the search procedure MAY return (0,0) motion vectors
+ *
+ *===========================================================================*/
+int
+BMotionSearch(const LumBlock * const currentBlockP,
+              MpegFrame *      const prev,
+              MpegFrame *      const next,
+              int              const by,
+              int              const bx,
+              motion *         const motionP,
+              int              const oldMode) {
+
+    int retval;
+
+    /* If we are an initial B frame, no possibility of forward motion */
+    if (prev == (MpegFrame *) NULL) {
+        PMotionSearch(currentBlockP, next, by, bx, &motionP->bwd);
+        return MOTION_BACKWARD;
+    }
+  
+    /* otherwise simply call the appropriate algorithm, based on user
+       preference
+    */
+
+    switch(bsearchAlg) {
+    case BSEARCH_SIMPLE:
+        retval = BMotionSearchSimple(currentBlockP, prev, next, by, bx,
+                                     motionP, oldMode);
+        break;
+    case BSEARCH_CROSS2:
+        retval = BMotionSearchCross2(currentBlockP, prev, next, by, bx,
+                                     motionP, oldMode);
+        break;
+    case BSEARCH_EXHAUSTIVE:
+        retval = BMotionSearchExhaust(currentBlockP, prev, next, by, bx,
+                                      motionP, oldMode);
+        break;
+    default:
+        pm_error("Impossible B-frame motion search algorithm:  %d",
+                 bsearchAlg);
+    }
+    return retval;
+}
+
+
+/*===========================================================================*
+ *                                       *
+ * UNUSED PROCEDURES                                 *
+ *                                       *
+ *  The following procedures are all unused by the encoder           *
+ *                                       *
+ *  They are listed here for your convenience.  You might want to use    *
+ *  them if you experiment with different search techniques          *
+ *                                       *
+ *===========================================================================*/
+
+#ifdef UNUSED_PROCEDURES
+
+/*===========================================================================*
+ *
+ * ValidBMotion
+ *
+ *  decides if the given B-frame motion is valid
+ *
+ * RETURNS: TRUE if the motion is valid, FALSE otherwise
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+boolean
+ValidBMotion(by, bx, mode, fmy, fmx, bmy, bmx)
+    int by;
+    int bx;
+    int mode;
+    int fmy;
+    int fmx;
+    int bmy;
+    int bmx;
+{
+    if ( mode != MOTION_BACKWARD ) {
+    /* check forward motion for bounds */
+    if ( (by*DCTSIZE+(fmy-1)/2 < 0) || ((by+2)*DCTSIZE+(fmy+1)/2-1 >= Fsize_y) ) {
+        return FALSE;
+    }
+    if ( (bx*DCTSIZE+(fmx-1)/2 < 0) || ((bx+2)*DCTSIZE+(fmx+1)/2-1 >= Fsize_x) ) {
+        return FALSE;
+    }
+    }
+
+    if ( mode != MOTION_FORWARD ) {
+    /* check backward motion for bounds */
+    if ( (by*DCTSIZE+(bmy-1)/2 < 0) || ((by+2)*DCTSIZE+(bmy+1)/2-1 >= Fsize_y) ) {
+        return FALSE;
+    }
+    if ( (bx*DCTSIZE+(bmx-1)/2 < 0) || ((bx+2)*DCTSIZE+(bmx+1)/2-1 >= Fsize_x) ) {
+        return FALSE;
+    }
+    }
+
+    return TRUE;
+}
+
+
+#endif /* UNUSED_PROCEDURES */
diff --git a/converter/ppm/ppmtompeg/combine.c b/converter/ppm/ppmtompeg/combine.c
new file mode 100644
index 00000000..341bb5dc
--- /dev/null
+++ b/converter/ppm/ppmtompeg/combine.c
@@ -0,0 +1,357 @@
+/*===========================================================================*
+ * combine.c
+ *
+ *  Procedures to combine frames or GOPS into an MPEG sequence
+ *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "all.h"
+#include <time.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "ppm.h"
+#include "nstring.h"
+
+#include "mtypes.h"
+#include "frames.h"
+#include "frametype.h"
+#include "motion_search.h"
+#include "mpeg.h"
+#include "prototypes.h"
+#include "parallel.h"
+#include "param.h"
+#include "readframe.h"
+#include "mheaders.h"
+#include "fsize.h"
+#include "input.h"
+#include "combine.h"
+
+
+#define READ_ATTEMPTS 5 /* number of times (seconds) to retry an input file */
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+extern int  yuvWidth, yuvHeight;
+
+
+/*===========================================================================*
+ *
+ * AppendFile
+ *
+ *  appends the output file with the contents of the given input file
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+AppendFile(FILE * const ofP,
+           FILE * const ifP) {
+
+    uint8 data[9999];
+    unsigned int readItems;
+
+    readItems = 9999;
+    while (readItems == 9999) {
+        readItems = fread(data, sizeof(uint8), 9999, ifP);
+        if (readItems > 0)
+            fwrite(data, sizeof(uint8), readItems, ofP);
+    }
+    fclose(ifP);
+}
+
+
+
+static void
+appendSpecifiedGopFiles(struct inputSource * const inputSourceP,
+                        const char *         const currentGopPath,
+                        FILE *               const ofP) {
+
+    unsigned int fileSeq;
+
+    for (fileSeq = 0; fileSeq < inputSourceP->numInputFiles; ++fileSeq) {
+        const char * inputFileName;
+        const char * fileName;
+        unsigned int nAttempts;
+        FILE * ifP;
+
+        GetNthInputFileName(inputSourceP, fileSeq, &inputFileName);
+        asprintfN(&fileName, "%s/%s", currentGOPPath, inputFileName);
+
+        for (nAttempts = 0, ifP = NULL;
+             nAttempts < READ_ATTEMPTS && !ifP;
+             ++nAttempts) {
+
+            FILE * ifP;
+            ifP = fopen(fileName, "rb");
+            if (ifP == NULL) {
+                pm_message("ERROR:  Couldn't read file '%s'.  retry %u", 
+                           fileName, nAttempts);
+                sleep(1);
+            }
+        }
+        if (ifP) {
+            if (!realQuiet)
+                pm_message("Appending file %u '%s'", fileSeq, fileName);
+            AppendFile(ofP, ifP);
+        } else
+            pm_error("Unable to read file '%s' after %u attempts.",
+                     fileName, READ_ATTEMPTS);
+        strfree(fileName);
+        strfree(inputFileName);
+    }
+} 
+
+
+
+static void
+appendDefaultGopFiles(const char * const outputFileName,
+                      FILE *       const ofP) {
+
+    unsigned int fileSeq;
+    bool endOfFiles;
+    
+    for (fileSeq = 0, endOfFiles = FALSE; !endOfFiles; ++fileSeq) {
+        const char * fileName;
+        FILE * ifP;
+
+        asprintfN(&fileName, "%s.gop.%u", outputFileName, fileSeq);
+        
+        ifP = fopen(fileName, "rb");
+        if (ifP == NULL)
+            endOfFiles = TRUE;
+        else {
+            if (!realQuiet)
+                pm_message("appending file:  %s", fileName);
+            
+            AppendFile(ofP, ifP);
+        }
+        strfree(fileName);
+    }
+}
+
+
+
+void
+GOPsToMPEG(struct inputSource * const inputSourceP,
+           const char *         const outputFileName, 
+           FILE *               const ofP) {
+/*----------------------------------------------------------------------------
+   Combine individual GOPs (one per file) into a single MPEG sequence file.
+-----------------------------------------------------------------------------*/
+    BitBucket * bb;
+
+    {
+        /* Why is this reset called? */
+        int x=Fsize_x, y=Fsize_y;
+        Fsize_Reset();
+        Fsize_Note(0, yuvWidth, yuvHeight);
+        if (Fsize_x == 0 || Fsize_y == 0)
+            Fsize_Note(0, x, y);
+    }
+    
+    bb = Bitio_New(ofP);
+
+    Mhead_GenSequenceHeader(bb, Fsize_x, Fsize_y, /* pratio */ aspectRatio,
+                            /* pict_rate */ frameRate, /* bit_rate */ -1,
+                            /* buf_size */ -1, /*c_param_flag */ 1,
+                            /* iq_matrix */ customQtable, 
+                            /* niq_matrix */ customNIQtable,
+                            /* ext_data */ NULL, /* ext_data_size */ 0,
+                            /* user_data */ NULL, /* user_data_size */ 0);
+
+    /* it's byte-padded, so we can dump it now */
+    Bitio_Flush(bb);
+
+    if (inputSourceP->stdinUsed)
+        AppendFile(ofP, stdin);
+    else {
+        if (inputSourceP->numInputFiles > 0)
+            appendSpecifiedGopFiles(inputSourceP, currentGOPPath, ofP);
+        else
+            appendDefaultGopFiles(outputFileName, ofP);
+    }
+    bb = Bitio_New(ofP);
+
+    /* SEQUENCE END CODE */
+    Mhead_GenSequenceEnder(bb);
+
+    Bitio_Flush(bb);
+
+    fclose(ofP);
+}
+
+
+
+static void
+makeGOPHeader(FILE *       const outputFileP,
+              unsigned int const totalFramesSent,
+              unsigned int const frameNumber,
+              unsigned int const seqWithinGop) {
+
+    boolean closed = (totalFramesSent == frameNumber);
+
+    BitBucket * bbP;
+
+    if (!realQuiet)
+        fprintf(stdout, "Creating new GOP (closed = %d) after %d frames\n",
+                closed, seqWithinGop);
+
+    /* new GOP */
+    bbP = Bitio_New(outputFileP);
+    Mhead_GenGOPHeader(bbP, /* drop_frame_flag */ 0,
+                       tc_hrs, tc_min, tc_sec, tc_pict,
+                       closed, /* broken_link */ 0,
+                       /* ext_data */ NULL, /* ext_data_size */ 0,
+                       /* user_data */ NULL, 
+                       /* user_data_size */ 0);
+    Bitio_Flush(bbP);
+    SetGOPStartTime(frameNumber);
+}        
+
+
+
+void
+FramesToMPEG(FILE *               const outputFile, 
+             void *               const inputHandle,
+             fileAcquisitionFn          acquireInputFile,
+             fileDispositionFn          disposeInputFile) {
+/*----------------------------------------------------------------------------
+   Combine a bunch of frames, one per file, into a single MPEG
+   sequence file.
+
+   acquireInputFile() opens a file that contains an encoded frame,
+   identified by frame number.  It returns NULL when the frame number
+   is beyond the frames available.
+-----------------------------------------------------------------------------*/
+    unsigned int frameNumber;
+    BitBucket *bb;
+    FILE *inputFile;
+    int pastRefNum = -1;
+    int futureRefNum = -1;
+    boolean inputLeft;
+    unsigned int seqWithinGop;
+        /* The sequence of the current frame within its GOP.  0 is the
+           first frame of a GOP, etc.
+        */
+
+    tc_hrs = 0; tc_min = 0; tc_sec = 0; tc_pict = 0; tc_extra = 0;
+
+    {
+        /* Why is this reset called? */
+        int x=Fsize_x, y=Fsize_y;
+        Fsize_Reset();
+        Fsize_Note(0, yuvWidth, yuvHeight);
+        if (Fsize_x == 0 || Fsize_y == 0)
+            Fsize_Note(0, x, y);
+    }
+    SetBlocksPerSlice();
+
+    bb = Bitio_New(outputFile);
+    Mhead_GenSequenceHeader(bb, Fsize_x, Fsize_y, /* pratio */ aspectRatio,
+                            /* pict_rate */ frameRate, /* bit_rate */ -1,
+                            /* buf_size */ -1, /*c_param_flag */ 1,
+                            /* iq_matrix */ qtable, /* niq_matrix */ niqtable,
+                            /* ext_data */ NULL, /* ext_data_size */ 0,
+                            /* user_data */ NULL, /* user_data_size */ 0);
+    /* it's byte-padded, so we can dump it now */
+    Bitio_Flush(bb);
+
+    /* need to do these in the right order!!! */
+    /* also need to add GOP headers */
+
+    seqWithinGop = 0;
+    totalFramesSent = 0;
+
+    inputLeft = TRUE;
+    frameNumber = 0;
+
+    makeGOPHeader(outputFile, totalFramesSent, frameNumber, seqWithinGop);
+    
+    while (inputLeft) {
+        if (FType_Type(frameNumber) != 'b') {
+            pastRefNum = futureRefNum;
+            futureRefNum = frameNumber;
+
+            if ((FType_Type(frameNumber) == 'i') && seqWithinGop >= gopSize) {
+                makeGOPHeader(outputFile,
+                              totalFramesSent, frameNumber, seqWithinGop);
+                seqWithinGop -= gopSize;
+            }
+
+            acquireInputFile(inputHandle, frameNumber, &inputFile);
+            if (inputFile == NULL)
+                inputLeft = FALSE;
+            else {
+                AppendFile(outputFile, inputFile);
+
+                disposeInputFile(inputHandle, frameNumber);
+
+                ++seqWithinGop;
+                IncrementTCTime();
+
+                /* now, output the B-frames */
+                if (pastRefNum != -1) {
+                    unsigned int bNum;
+                    
+                    for (bNum = pastRefNum+1; bNum < futureRefNum; ++bNum) {
+                        acquireInputFile(inputHandle, bNum, &inputFile);
+
+                        if (inputFile) {
+                            AppendFile(outputFile, inputFile);
+
+                            disposeInputFile(inputHandle, bNum);
+            
+                            ++seqWithinGop;
+                            IncrementTCTime();
+                        }
+                    }
+                }
+            }
+        }
+        ++frameNumber;
+    }
+
+    if (!realQuiet)
+        fprintf(stdout, "Wrote %d frames\n", totalFramesSent);
+
+    bb = Bitio_New(outputFile);
+
+    /* SEQUENCE END CODE */
+    Mhead_GenSequenceEnder(bb);
+
+    Bitio_Flush(bb);
+
+    fclose(outputFile);
+}
+
+
+
diff --git a/converter/ppm/ppmtompeg/docs/EXTENSIONS b/converter/ppm/ppmtompeg/docs/EXTENSIONS
new file mode 100644
index 00000000..c683fbf8
--- /dev/null
+++ b/converter/ppm/ppmtompeg/docs/EXTENSIONS
@@ -0,0 +1,41 @@
+EXTENSIONS
+----------
+
+This is a list of things that we'd like to incorporate into the encoder.
+If you succeed in implementing any of them, please let us know!
+
+*  better B-frame search technique
+*  use DCT-space when computing error terms
+*  vary the q-scale according to the error term
+*  other motion vector search techniques
+*  modify the program to have a finer-grained parallelism option -- we
+   can probably encode slices in parallel (this will only be useful if we
+   want to do a few B-frames using exhaustive search)
+*  include system layer
+*  VBV delay with rate control
+
+
+CREATING YOUR OWN MOTION SEARCH ROUTINES
+----------------------------------------
+
+Adding your own special motion search routine is very easy.  We'll explain
+adding a P-frame search routine; adding a B-frame routine is similar.
+
+First, edit the procedures PMotionSearch and SetPSearchAlg (both in the
+file psearch.c) to recognize your new search routine.  You probably want
+to define a constant
+    PSEARCH_<your search name> in headers/search.h
+
+Have PMotionSearch call your search procedure just as it calls the other
+standard search procedures.  Make sure your procedure follows the guidelines
+in the comments for PMotionSearch.
+
+Note:  The encoder uses MAD as its search criterion.  The reason for this:
+	"Among the various criteria that can be used as a measure of the
+	 match between the two blocks, the mean absolute difference (MAD)
+	 is favored because it requires no multiplication and gives
+	 similar performance as the mean squared error (MSE)."
+	- Liu and Zaccarin,
+	  "New Fast Algorithms for the Estimation of Block Motion Vectors,"
+	  IEEE Transactions on Circuits and Systems for Video Technology
+	  Volume 3 No. 2 (April 1993)
diff --git a/converter/ppm/ppmtompeg/docs/INPUT.FORMAT b/converter/ppm/ppmtompeg/docs/INPUT.FORMAT
new file mode 100644
index 00000000..8a663d3a
--- /dev/null
+++ b/converter/ppm/ppmtompeg/docs/INPUT.FORMAT
@@ -0,0 +1,79 @@
+			----------------
+			| FILE FORMATS |
+			----------------
+
+PPM FORMAT
+----------
+
+See http://netpbm.sourceforge.net/doc/ppm.html .
+
+
+UCB YUV FORMAT
+--------------
+
+You should be aware that the YUV format used in the MPEG encoder is DIFFERENT
+than the Abekas YUV format.  The reason for this is that in MPEG, the U and
+V components are subsampled 4:1.
+
+To give you an idea of what format the YUV file must be in, the following
+code will read in a YUV file:
+
+    unsigned char **y_data, **cr_data, **cb_data;
+
+    void	ReadYUV(char *fileName, int width, int height)
+    {
+	FILE *fpointer;
+	register int y;
+
+	/* should allocate memory for y_data, cr_data, cb_data here */
+
+	fpointer = fopen(fileName, "r");
+
+	for (y = 0; y < height; y++)			/* Y */
+	    fread(y_data[y], 1, width, fpointer);
+
+	for (y = 0; y < height / 2; y++)			/* U */
+	    fread(cb_data[y], 1, width / 2, fpointer);
+
+	for (y = 0; y < height / 2; y++)			/* V */
+	    fread(cr_data[y], 1, width / 2, fpointer);
+
+	fclose(fpointer);
+    }
+
+There are two reasons why you'd want to use YUV files rather than PPM files:
+	1)  The YUV files are 50% the size of the corresponding PPM files
+	2)  The ENCODER will run slightly faster, since it doesn't have to
+	    do the RGB to YUV conversion itself.
+
+
+ABEKAS YUV FORMAT 
+-----------------
+
+The Abekas YUV Format interlaces the Y, U, and V values in a 4:2:2 format.
+The interlacing pattern is
+
+UYVY
+
+for each group of 4 bytes in the file.
+
+
+PHILLIPS YUV FORMAT 
+-------------------
+
+The Phillips YUV Format interlaces the Y, U, and V values in a 4:2:2 format.
+The interlacing pattern is
+
+YVYU
+
+for each group of 4 bytes in the file.
+
+
+You may specify either ABEKAS, PHILLIPS, or UCB as the YUV_FORMAT when
+encoding ; the encoder defaults to UCB YUV_FORMAT if not specified.
+In addition, if you've got a weird interlacing format, you can also
+try and de-interlace it by giving the YUV pattern in the YUV_FORMAT.
+So a YUV 4:4:4 format would be
+
+YUVYUV
+
diff --git a/converter/ppm/ppmtompeg/docs/parallel.param b/converter/ppm/ppmtompeg/docs/parallel.param
new file mode 100644
index 00000000..0702d32c
--- /dev/null
+++ b/converter/ppm/ppmtompeg/docs/parallel.param
@@ -0,0 +1,142 @@
+# parameter file template with parallel execution
+#
+# you can use this as a template, copying it to a separate file then modifying
+# the copy
+#
+#
+# any line beginning with '#' is a comment
+#
+# no line should be longer than 255 characters
+#
+#
+# general format of each line is:
+#	<option> <spaces and/or tabs> <value>
+#
+# lines can generally be in any order
+#
+# only exception is the option 'INPUT' which must be followed by input
+# files in the order in which they must appear, followed by 'END_INPUT'
+#
+# <option> MUST be in UPPER CASE
+#
+
+PATTERN		IBBPBBI
+OUTPUT		/n/picasso/users/keving/encode/output.mpg
+
+# mpeg_encode really only accepts 3 different file formats, but using a
+# conversion statement it can effectively handle ANY file format
+#
+# you must specify whether you will convert to PNM or PPM or YUV format
+#	(must be upper case)
+#
+BASE_FILE_FORMAT	YUV
+
+#
+# if YUV format (or using parallel version), must provide width and height
+# YUV_SIZE	widthxheight
+# this option is ignored if BASE_FILE_FORMAT is PPM or PNM and you're running
+# on just one machine
+#
+YUV_SIZE	352x240
+
+# the conversion statement
+#
+# Each occurrence of '*' will be replaced by the input file
+#
+# e.g., if you have a bunch of GIF files, then this might be:
+#	INPUT_CONVERT	giftoppm *
+#
+# e.g., if you have a bunch of files like a.Y a.U a.V, etc., then:
+#	INPUT_CONVERT	cat *.Y *.U *.V
+#
+# e.g., if you are grabbing from laser disc you might have something like
+#	INPUT_CONVERT	goto frame *; grabppm
+# 'INPUT_CONVERT *' means the files are already in the base file format
+#
+INPUT_CONVERT	*
+
+# number of frames in a GOP.
+#
+# since each GOP must have at least one I-frame, the encoder will find the
+# the first I-frame after GOP_SIZE frames to start the next GOP
+#
+# later, will add more flexible GOP signalling
+#
+GOP_SIZE	6
+
+# number of slices in a frame
+#
+# 1 is a good number.  another possibility is the number of macroblock rows
+# (which is the height divided by 16)
+#
+SLICES_PER_FRAME	1
+
+# directory to get all input files from (makes this file easier to read)
+# can't use stdin with parallel encoding
+INPUT_DIR	/n/picasso/users/keving/encode/input/tennis
+
+INPUT
+# '*' is replaced by the numbers 01, 02, 03, 04
+# if I instead do [01-11], it would be 01, 02, ..., 09, 10, 11
+# if I instead do [1-11], it would be 1, 2, 3, ..., 9, 10, 11
+# if I instead do [1-11+3], it would be 1, 4, 7, 10
+# the program assumes none of your input files has a name ending in ']'
+# if you do, too bad!!!
+#
+#
+stennis.*.yuv	[0-7]
+# can have more files here if you want...there is no limit on the number
+# of files
+END_INPUT
+
+
+
+# all of the remaining options have to do with the motion search and qscale
+
+# FULL or HALF -- must be upper case
+PIXEL		HALF
+
+# means +/- this many pixels
+RANGE		10
+
+# this must be one of {EXHAUSTIVE, SUBSAMPLE, LOGARITHMIC}
+PSEARCH_ALG	LOGARITHMIC
+
+# this must be one of {SIMPLE, CROSS2, EXHAUSTIVE}
+#
+# note that EXHAUSTIVE is really, really, really slow
+#
+BSEARCH_ALG	CROSS2
+
+#
+# these specify the q-scale for I, P, and B frames
+# (values must be between 1 and 31)
+#
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# this must be ORIGINAL or DECODED
+REFERENCE_FRAME	ORIGINAL
+
+
+# the following two are optional  (default = 10, 60)
+
+# number of frames to do initially to gauge speed of machine
+PARALLEL_TEST_FRAMES	3
+
+# number of seconds per chunk thereafter
+PARALLEL_TIME_CHUNKS	30
+
+
+PARALLEL
+# lines must be of form "machine <whitespace> username <whitespace> executable"
+charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+#woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+#REMOTE charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode ~keving/encode/examples/parallel.param
+# remote machine: "REMOTE machine username executable param_file"
+# mickey		keving	~keving/encode/bin/dec-5000/mpeg_encode
+#REMOTE mickey		keving	~keving/encode/bin/dec-5000/mpeg_encode ~keving/encode/examples/parallel.param
+#REMOTE mickey		keving	~keving/encode/bin/dec-5000/mpeg_encode ~keving/encode/examples/parallel.param
+REMOTE woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode ~keving/encode/examples/parallel.param
+END_PARALLEL
diff --git a/converter/ppm/ppmtompeg/docs/param-summary b/converter/ppm/ppmtompeg/docs/param-summary
new file mode 100644
index 00000000..d8322bfb
--- /dev/null
+++ b/converter/ppm/ppmtompeg/docs/param-summary
@@ -0,0 +1,14 @@
+Different MPEG coding strategies
+--------------------------------
+
+Strategy			Speed	Compression	Quality
+--------			-----	-----------	-------
+Increase MV Search Range	Down	Up		Up?
+Increasing Q-Scale		Same	Up		Down
+Decreasing Q-Scale		Same	Down		Up
+Use half-pixel search		Down	Up		Up?
+Use pixel subsampling		Up	Down		Down?
+Use motion vector subsampling	Up	Down		Down?
+Use decoded frame as reference	Same	Unknown		Up?
+Varying q-scale			Down	Up		Down
+
diff --git a/converter/ppm/ppmtompeg/docs/template.param b/converter/ppm/ppmtompeg/docs/template.param
new file mode 100644
index 00000000..66b6dd98
--- /dev/null
+++ b/converter/ppm/ppmtompeg/docs/template.param
@@ -0,0 +1,154 @@
+# parameter file template with lots of comments to assist you
+#
+# you can use this as a template, copying it to a separate file then modifying
+# the copy
+#
+#
+# any line beginning with '#' is a comment
+#
+# no line should be longer than 255 characters
+#
+#
+# general format of each line is:
+#	<option> <spaces and/or tabs> <value>
+#
+# lines can generally be in any order
+#
+# an exception is the option 'INPUT' which must be followed by input
+# files in the order in which they must appear, followed by 'END_INPUT'
+#
+# Also, if you use the `command` method of generating input file names,
+# the command will only be executed in the INPUT_DIR if INPUT_DIR preceeds
+# the INPUT parameter.
+#
+# <option> MUST be in UPPER CASE
+#
+
+PATTERN		IBBPBBPBBPBBPBBP
+OUTPUT		output.mpg
+
+# mpeg_encode really only accepts 3 different file formats, but using a
+# conversion statement it can effectively handle ANY file format
+#
+# You must specify the type of the input files.  The choices are:
+#    YUV, PPM, JMOVIE, Y, JPEG, PNM
+#	(must be upper case)
+#
+BASE_FILE_FORMAT	YUV
+
+#
+# if YUV format (or using parallel version), must provide width and height
+# YUV_SIZE	widthxheight
+# this option is ignored if BASE_FILE_FORMAT is not YUV and you're running
+# on just one machine
+#
+YUV_SIZE	352x240
+
+# If you are using YUV, there are different supported file formats.
+# EYUV or UCB are the same as previous versions of this encoder.
+# (All the Y's, then U's then V's, in 4:2:0 subsampling.)
+# Other formats, such as Abekas, Phillips, or a general format are
+# permissible, the general format is a string of Y's, U's, and V's
+# to specify the file order.
+
+INPUT_FORMAT UCB
+
+# the conversion statement
+#
+# Each occurrence of '*' will be replaced by the input file
+#
+# e.g., if you have a bunch of GIF files, then this might be:
+#	INPUT_CONVERT	giftoppm *
+#
+# e.g., if you have a bunch of files like a.Y a.U a.V, etc., then:
+#	INPUT_CONVERT	cat *.Y *.U *.V
+#
+# e.g., if you are grabbing from laser disc you might have something like
+#	INPUT_CONVERT	goto frame *; grabppm
+# 'INPUT_CONVERT *' means the files are already in the base file format
+#
+INPUT_CONVERT	*
+
+# number of frames in a GOP.
+#
+# since each GOP must have at least one I-frame, the encoder will find the
+# the first I-frame after GOP_SIZE frames to start the next GOP
+#
+# later, will add more flexible GOP signalling
+#
+GOP_SIZE	16
+
+# number of slices in a frame
+#
+# 1 is a good number.  another possibility is the number of macroblock rows
+# (which is the height divided by 16)
+#
+SLICES_PER_FRAME	1
+
+# directory to get all input files from (makes this file easier to read)
+INPUT_DIR	../input/tennis
+
+# There are a bunch of ways to specify the input files.
+# from a simple one-per-line listing, to the following 
+# way of numbering them.  See the manual for more information.
+INPUT
+# '*' is replaced by the numbers 01, 02, 03, 04
+# if I instead do [01-11], it would be 01, 02, ..., 09, 10, 11
+# if I instead do [1-11], it would be 1, 2, 3, ..., 9, 10, 11
+# if I instead do [1-11+3], it would be 1, 4, 7, 10
+# the program assumes none of your input files has a name ending in ']'
+# if you do, too bad!!!
+#
+#
+stennis.*.yuv	[0-23]
+# can have more files here if you want...there is no limit on the number
+# of files
+END_INPUT
+
+
+
+# Many of the remaining options have to do with the motion search and qscale
+
+# FULL or HALF -- must be upper case
+PIXEL		HALF
+
+# means +/- this many pixels for both P and B frame searches
+# specify two numbers if you wish to serc different ranges in the two.
+RANGE		10
+
+# this must be one of {EXHAUSTIVE, SUBSAMPLE, LOGARITHMIC}
+PSEARCH_ALG	LOGARITHMIC
+
+# this must be one of {SIMPLE, CROSS2, EXHAUSTIVE}
+#
+# note that EXHAUSTIVE is really, really, really slow
+#
+BSEARCH_ALG	CROSS2
+
+#
+# these specify the q-scale for I, P, and B frames
+# (values must be between 1 and 31)
+# These are the Qscale values for the entire frame in variable bit-rate
+# mode, and starting points (but not important) for constant bit rate
+#
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# this must be ORIGINAL or DECODED
+REFERENCE_FRAME	ORIGINAL
+
+# for parallel parameters see parallel.param in the exmaples subdirectory
+
+# if you want constant bit-rate mode, specify it as follows (number is bits/sec):
+BIT_RATE  1000000
+
+# To specify the buffer size (327680 is default, measused in bits, for 16bit words)
+BUFFER_SIZE 327680
+
+# The frame rate is the number of frames/second (legal values:
+# 23.976, 24, 25, 29.97, 30, 50 ,59.94, 60
+FRAME_RATE 30
+
+# There are many more options, see the users manual for examples....
+# ASPECT_RATIO, USER_DATA, GAMMA, IQTABLE, etc.
diff --git a/converter/ppm/ppmtompeg/docs/users-guide.ps b/converter/ppm/ppmtompeg/docs/users-guide.ps
new file mode 100644
index 00000000..2e39be0a
--- /dev/null
+++ b/converter/ppm/ppmtompeg/docs/users-guide.ps
@@ -0,0 +1,3233 @@
+%!
+%%BoundingBox: (atend)
+%%Pages: (atend)
+%%DocumentFonts: (atend)
+%%EndComments
+%
+% FrameMaker PostScript Prolog 3.0, for use with FrameMaker 3.0
+% Copyright (c) 1986,87,89,90,91 by Frame Technology Corporation.
+% All rights reserved.
+%
+% Known Problems:
+%	Due to bugs in Transcript, the 'PS-Adobe-' is omitted from line 1
+/FMversion (3.0) def 
+% Set up Color vs. Black-and-White
+	/FMPrintInColor systemdict /colorimage known
+		systemdict /currentcolortransfer known or def
+% Uncomment this line to force b&w on color printer
+%   /FMPrintInColor false def
+/FrameDict 195 dict def 
+systemdict /errordict known not {/errordict 10 dict def
+		errordict /rangecheck {stop} put} if
+% The readline in 23.0 doesn't recognize cr's as nl's on AppleTalk
+FrameDict /tmprangecheck errordict /rangecheck get put 
+errordict /rangecheck {FrameDict /bug true put} put 
+FrameDict /bug false put 
+mark 
+% Some PS machines read past the CR, so keep the following 3 lines together!
+currentfile 5 string readline
+00
+0000000000
+cleartomark 
+errordict /rangecheck FrameDict /tmprangecheck get put 
+FrameDict /bug get { 
+	/readline {
+		/gstring exch def
+		/gfile exch def
+		/gindex 0 def
+		{
+			gfile read pop 
+			dup 10 eq {exit} if 
+			dup 13 eq {exit} if 
+			gstring exch gindex exch put 
+			/gindex gindex 1 add def 
+		} loop
+		pop 
+		gstring 0 gindex getinterval true 
+		} def
+	} if
+/FMVERSION {
+	FMversion ne {
+		/Times-Roman findfont 18 scalefont setfont
+		100 100 moveto
+		(FrameMaker version does not match postscript_prolog!)
+		dup =
+		show showpage
+		} if
+	} def 
+/FMLOCAL {
+	FrameDict begin
+	0 def 
+	end 
+	} def 
+	/gstring FMLOCAL
+	/gfile FMLOCAL
+	/gindex FMLOCAL
+	/orgxfer FMLOCAL
+	/orgproc FMLOCAL
+	/organgle FMLOCAL
+	/orgfreq FMLOCAL
+	/yscale FMLOCAL
+	/xscale FMLOCAL
+	/manualfeed FMLOCAL
+	/paperheight FMLOCAL
+	/paperwidth FMLOCAL
+/FMDOCUMENT { 
+	array /FMfonts exch def 
+	/#copies exch def
+	FrameDict begin
+	0 ne dup {setmanualfeed} if
+	/manualfeed exch def
+	/paperheight exch def
+	/paperwidth exch def
+	/yscale exch def
+	/xscale exch def
+	currenttransfer cvlit /orgxfer exch def
+	currentscreen cvlit /orgproc exch def
+	/organgle exch def /orgfreq exch def
+	setpapername 
+	manualfeed {true} {papersize} ifelse 
+	{manualpapersize} {false} ifelse 
+	{desperatepapersize} if
+	end 
+	} def 
+	/pagesave FMLOCAL
+	/orgmatrix FMLOCAL
+	/landscape FMLOCAL
+/FMBEGINPAGE { 
+	FrameDict begin 
+	/pagesave save def
+	3.86 setmiterlimit
+	/landscape exch 0 ne def
+	landscape { 
+		90 rotate 0 exch neg translate pop 
+		}
+		{pop pop}
+		ifelse
+	xscale yscale scale
+	/orgmatrix matrix def
+	gsave 
+	} def 
+/FMENDPAGE {
+	grestore 
+	pagesave restore
+	end 
+	showpage
+	} def 
+/FMFONTDEFINE { 
+	FrameDict begin
+	findfont 
+	ReEncode 
+	1 index exch 
+	definefont 
+	FMfonts 3 1 roll 
+	put
+	end 
+	} def 
+/FMFILLS {
+	FrameDict begin
+	array /fillvals exch def
+	end 
+	} def 
+/FMFILL {
+	FrameDict begin
+	 fillvals 3 1 roll put
+	end 
+	} def 
+/FMNORMALIZEGRAPHICS { 
+	newpath
+	0.0 0.0 moveto
+	1 setlinewidth
+	0 setlinecap
+	0 0 0 sethsbcolor
+	0 setgray 
+	} bind def
+	/fx FMLOCAL
+	/fy FMLOCAL
+	/fh FMLOCAL
+	/fw FMLOCAL
+	/llx FMLOCAL
+	/lly FMLOCAL
+	/urx FMLOCAL
+	/ury FMLOCAL
+/FMBEGINEPSF { 
+	end 
+	/FMEPSF save def 
+	/showpage {} def 
+	FMNORMALIZEGRAPHICS 
+	[/fy /fx /fh /fw /ury /urx /lly /llx] {exch def} forall 
+	fx fy translate 
+	rotate
+	fw urx llx sub div fh ury lly sub div scale 
+	llx neg lly neg translate 
+	} bind def
+/FMENDEPSF {
+	FMEPSF restore
+	FrameDict begin 
+	} bind def
+FrameDict begin 
+/setmanualfeed {
+%%BeginFeature *ManualFeed True
+	 statusdict /manualfeed true put
+%%EndFeature
+	} def
+/max {2 copy lt {exch} if pop} bind def
+/min {2 copy gt {exch} if pop} bind def
+/inch {72 mul} def
+/pagedimen { 
+	paperheight sub abs 16 lt exch 
+	paperwidth sub abs 16 lt and
+	{/papername exch def} {pop} ifelse
+	} def
+	/papersizedict FMLOCAL
+/setpapername { 
+	/papersizedict 14 dict def 
+	papersizedict begin
+	/papername /unknown def 
+		/Letter 8.5 inch 11.0 inch pagedimen
+		/LetterSmall 7.68 inch 10.16 inch pagedimen
+		/Tabloid 11.0 inch 17.0 inch pagedimen
+		/Ledger 17.0 inch 11.0 inch pagedimen
+		/Legal 8.5 inch 14.0 inch pagedimen
+		/Statement 5.5 inch 8.5 inch pagedimen
+		/Executive 7.5 inch 10.0 inch pagedimen
+		/A3 11.69 inch 16.5 inch pagedimen
+		/A4 8.26 inch 11.69 inch pagedimen
+		/A4Small 7.47 inch 10.85 inch pagedimen
+		/B4 10.125 inch 14.33 inch pagedimen
+		/B5 7.16 inch 10.125 inch pagedimen
+	end
+	} def
+/papersize {
+	papersizedict begin
+		/Letter {lettertray letter} def
+		/LetterSmall {lettertray lettersmall} def
+		/Tabloid {11x17tray 11x17} def
+		/Ledger {ledgertray ledger} def
+		/Legal {legaltray legal} def
+		/Statement {statementtray statement} def
+		/Executive {executivetray executive} def
+		/A3 {a3tray a3} def
+		/A4 {a4tray a4} def
+		/A4Small {a4tray a4small} def
+		/B4 {b4tray b4} def
+		/B5 {b5tray b5} def
+		/unknown {unknown} def
+	papersizedict dup papername known {papername} {/unknown} ifelse get
+	end
+	/FMdicttop countdictstack 1 add def 
+	statusdict begin stopped end 
+	countdictstack -1 FMdicttop {pop end} for 
+	} def
+/manualpapersize {
+	papersizedict begin
+		/Letter {letter} def
+		/LetterSmall {lettersmall} def
+		/Tabloid {11x17} def
+		/Ledger {ledger} def
+		/Legal {legal} def
+		/Statement {statement} def
+		/Executive {executive} def
+		/A3 {a3} def
+		/A4 {a4} def
+		/A4Small {a4small} def
+		/B4 {b4} def
+		/B5 {b5} def
+		/unknown {unknown} def
+	papersizedict dup papername known {papername} {/unknown} ifelse get
+	end
+	stopped 
+	} def
+/desperatepapersize {
+	statusdict /setpageparams known
+		{
+		paperwidth paperheight 0 1 
+		statusdict begin
+		{setpageparams} stopped pop 
+		end
+		} if
+	} def
+/savematrix {
+	orgmatrix currentmatrix pop
+	} bind def
+/restorematrix {
+	orgmatrix setmatrix
+	} bind def
+/dmatrix matrix def
+/dpi    72 0 dmatrix defaultmatrix dtransform
+    dup mul exch   dup mul add   sqrt def
+/freq dpi 18.75 div 8 div round dup 0 eq {pop 1} if 8 mul dpi exch div def
+/sangle 1 0 dmatrix defaultmatrix dtransform exch atan def
+/DiacriticEncoding [
+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /.notdef /.notdef /.notdef /space /exclam /quotedbl
+/numbersign /dollar /percent /ampersand /quotesingle /parenleft
+/parenright /asterisk /plus /comma /hyphen /period /slash /zero /one
+/two /three /four /five /six /seven /eight /nine /colon /semicolon
+/less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J /K
+/L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash
+/bracketright /asciicircum /underscore /grave /a /b /c /d /e /f /g /h
+/i /j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar
+/braceright /asciitilde /.notdef /Adieresis /Aring /Ccedilla /Eacute
+/Ntilde /Odieresis /Udieresis /aacute /agrave /acircumflex /adieresis
+/atilde /aring /ccedilla /eacute /egrave /ecircumflex /edieresis
+/iacute /igrave /icircumflex /idieresis /ntilde /oacute /ograve
+/ocircumflex /odieresis /otilde /uacute /ugrave /ucircumflex
+/udieresis /dagger /.notdef /cent /sterling /section /bullet
+/paragraph /germandbls /registered /copyright /trademark /acute
+/dieresis /.notdef /AE /Oslash /.notdef /.notdef /.notdef /.notdef
+/yen /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/ordfeminine /ordmasculine /.notdef /ae /oslash /questiondown
+/exclamdown /logicalnot /.notdef /florin /.notdef /.notdef
+/guillemotleft /guillemotright /ellipsis /.notdef /Agrave /Atilde
+/Otilde /OE /oe /endash /emdash /quotedblleft /quotedblright
+/quoteleft /quoteright /.notdef /.notdef /ydieresis /Ydieresis
+/fraction /currency /guilsinglleft /guilsinglright /fi /fl /daggerdbl
+/periodcentered /quotesinglbase /quotedblbase /perthousand
+/Acircumflex /Ecircumflex /Aacute /Edieresis /Egrave /Iacute
+/Icircumflex /Idieresis /Igrave /Oacute /Ocircumflex /.notdef /Ograve
+/Uacute /Ucircumflex /Ugrave /dotlessi /circumflex /tilde /macron
+/breve /dotaccent /ring /cedilla /hungarumlaut /ogonek /caron
+] def
+/ReEncode { 
+	dup 
+	length 
+	dict begin 
+	{
+	1 index /FID ne 
+		{def} 
+		{pop pop} ifelse 
+	} forall 
+	0 eq {/Encoding DiacriticEncoding def} if 
+	currentdict 
+	end 
+	} bind def
+/graymode true def
+	/bwidth FMLOCAL
+	/bpside FMLOCAL
+	/bstring FMLOCAL
+	/onbits FMLOCAL
+	/offbits FMLOCAL
+	/xindex FMLOCAL
+	/yindex FMLOCAL
+	/x FMLOCAL
+	/y FMLOCAL
+/setpattern {
+	 /bwidth  exch def
+	 /bpside  exch def
+	 /bstring exch def
+	 /onbits 0 def  /offbits 0 def
+	 freq sangle landscape {90 add} if 
+		{/y exch def
+		 /x exch def
+		 /xindex x 1 add 2 div bpside mul cvi def
+		 /yindex y 1 add 2 div bpside mul cvi def
+		 bstring yindex bwidth mul xindex 8 idiv add get
+		 1 7 xindex 8 mod sub bitshift and 0 ne
+		 {/onbits  onbits  1 add def 1}
+		 {/offbits offbits 1 add def 0}
+		 ifelse
+		}
+		setscreen
+	 {} settransfer
+	 offbits offbits onbits add div FMsetgray
+	/graymode false def
+	} bind def
+/grayness {
+	FMsetgray
+	graymode not {
+		/graymode true def
+		orgxfer cvx settransfer
+		orgfreq organgle orgproc cvx setscreen
+		} if
+	} bind def
+	/HUE FMLOCAL
+	/SAT FMLOCAL
+	/BRIGHT FMLOCAL
+	/Colors FMLOCAL
+FMPrintInColor 
+	
+	{
+	/HUE 0 def
+	/SAT 0 def
+	/BRIGHT 0 def
+	% array of arrays Hue and Sat values for the separations [HUE BRIGHT]
+	/Colors   
+	[[0    0  ]    % black
+	 [0    0  ]    % white
+	 [0.00 1.0]    % red
+	 [0.37 1.0]    % green
+	 [0.60 1.0]    % blue
+	 [0.50 1.0]    % cyan
+	 [0.83 1.0]    % magenta
+	 [0.16 1.0]    % comment / yellow
+	 ] def
+      
+	/BEGINBITMAPCOLOR { 
+		BITMAPCOLOR} def
+	/BEGINBITMAPCOLORc { 
+		BITMAPCOLORc} def
+	/BEGINBITMAPTRUECOLOR { 
+		BITMAPTRUECOLOR } def
+	/BEGINBITMAPTRUECOLORc { 
+		BITMAPTRUECOLORc } def
+	/K { 
+		Colors exch get dup
+		0 get /HUE exch store 
+		1 get /BRIGHT exch store
+		  HUE 0 eq BRIGHT 0 eq and
+			{1.0 SAT sub setgray}
+			{HUE SAT BRIGHT sethsbcolor} 
+		  ifelse
+		} def
+	/FMsetgray { 
+		/SAT exch 1.0 exch sub store 
+		  HUE 0 eq BRIGHT 0 eq and
+			{1.0 SAT sub setgray}
+			{HUE SAT BRIGHT sethsbcolor} 
+		  ifelse
+		} bind def
+	}
+	
+	{
+	/BEGINBITMAPCOLOR { 
+		BITMAPGRAY} def
+	/BEGINBITMAPCOLORc { 
+		BITMAPGRAYc} def
+	/BEGINBITMAPTRUECOLOR { 
+		BITMAPTRUEGRAY } def
+	/BEGINBITMAPTRUECOLORc { 
+		BITMAPTRUEGRAYc } def
+	/FMsetgray {setgray} bind def
+	/K { 
+		pop
+		} def
+	}
+ifelse
+/normalize {
+	transform round exch round exch itransform
+	} bind def
+/dnormalize {
+	dtransform round exch round exch idtransform
+	} bind def
+/lnormalize { 
+	0 dtransform exch cvi 2 idiv 2 mul 1 add exch idtransform pop
+	} bind def
+/H { 
+	lnormalize setlinewidth
+	} bind def
+/Z {
+	setlinecap
+	} bind def
+	/fillvals FMLOCAL
+/X { 
+	fillvals exch get
+	dup type /stringtype eq
+	{8 1 setpattern} 
+	{grayness}
+	ifelse
+	} bind def
+/V { 
+	gsave eofill grestore
+	} bind def
+/N { 
+	stroke
+	} bind def
+/M {newpath moveto} bind def
+/E {lineto} bind def
+/D {curveto} bind def
+/O {closepath} bind def
+	/n FMLOCAL
+/L { 
+ 	/n exch def
+	newpath
+	normalize
+	moveto 
+	2 1 n {pop normalize lineto} for
+	} bind def
+/Y { 
+	L 
+	closepath
+	} bind def
+	/x1 FMLOCAL
+	/x2 FMLOCAL
+	/y1 FMLOCAL
+	/y2 FMLOCAL
+	/rad FMLOCAL
+/R { 
+	/y2 exch def
+	/x2 exch def
+	/y1 exch def
+	/x1 exch def
+	x1 y1
+	x2 y1
+	x2 y2
+	x1 y2
+	4 Y 
+	} bind def
+/RR { 
+	/rad exch def
+	normalize
+	/y2 exch def
+	/x2 exch def
+	normalize
+	/y1 exch def
+	/x1 exch def
+	newpath
+	x1 y1 rad add moveto
+	x1 y2 x2 y2 rad arcto
+	x2 y2 x2 y1 rad arcto
+	x2 y1 x1 y1 rad arcto
+	x1 y1 x1 y2 rad arcto
+	closepath
+	16 {pop} repeat
+	} bind def
+/C { 
+	grestore
+	gsave
+	R 
+	clip
+	} bind def
+	/FMpointsize FMLOCAL
+/F { 
+	FMfonts exch get
+	FMpointsize scalefont
+	setfont
+	} bind def
+/Q { 
+	/FMpointsize exch def
+	F 
+	} bind def
+/T { 
+	moveto show
+	} bind def
+/RF { 
+	rotate
+	0 ne {-1 1 scale} if
+	} bind def
+/TF { 
+	gsave
+	moveto 
+	RF
+	show
+	grestore
+	} bind def
+/P { 
+	moveto
+	0 32 3 2 roll widthshow
+	} bind def
+/PF { 
+	gsave
+	moveto 
+	RF
+	0 32 3 2 roll widthshow
+	grestore
+	} bind def
+/S { 
+	moveto
+	0 exch ashow
+	} bind def
+/SF { 
+	gsave
+	moveto
+	RF
+	0 exch ashow
+	grestore
+	} bind def
+/B { 
+	moveto
+	0 32 4 2 roll 0 exch awidthshow
+	} bind def
+/BF { 
+	gsave
+	moveto
+	RF
+	0 32 4 2 roll 0 exch awidthshow
+	grestore
+	} bind def
+/G { 
+	gsave
+	newpath
+	normalize translate 0.0 0.0 moveto 
+	dnormalize scale 
+	0.0 0.0 1.0 5 3 roll arc 
+	closepath fill
+	grestore
+	} bind def
+/A { 
+	gsave
+	savematrix
+	newpath
+	2 index 2 div add exch 3 index 2 div sub exch 
+	normalize 2 index 2 div sub exch 3 index 2 div add exch 
+	translate 
+	scale 
+	0.0 0.0 1.0 5 3 roll arc 
+	restorematrix
+	stroke
+	grestore
+	} bind def
+	/x FMLOCAL
+	/y FMLOCAL
+	/w FMLOCAL
+	/h FMLOCAL
+	/xx FMLOCAL
+	/yy FMLOCAL
+	/ww FMLOCAL
+	/hh FMLOCAL
+	/FMsaveobject FMLOCAL
+	/FMoptop FMLOCAL
+	/FMdicttop FMLOCAL
+/BEGINPRINTCODE { 
+	/FMdicttop countdictstack 1 add def 
+	/FMoptop count 4 sub def 
+	/FMsaveobject save def
+	userdict begin 
+	/showpage {} def 
+	FMNORMALIZEGRAPHICS 
+	3 index neg 3 index neg translate
+	} bind def
+/ENDPRINTCODE {
+	count -1 FMoptop {pop pop} for 
+	countdictstack -1 FMdicttop {pop end} for 
+	FMsaveobject restore 
+	} bind def
+/gn { 
+	0 
+	{	46 mul 
+		cf read pop 
+		32 sub 
+		dup 46 lt {exit} if 
+		46 sub add 
+		} loop
+	add 
+	} bind def
+	/str FMLOCAL
+/cfs { 
+	/str sl string def 
+	0 1 sl 1 sub {str exch val put} for 
+	str def 
+	} bind def
+/ic [ 
+	0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0223
+	0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0223
+	0
+	{0 hx} {1 hx} {2 hx} {3 hx} {4 hx} {5 hx} {6 hx} {7 hx} {8 hx} {9 hx}
+	{10 hx} {11 hx} {12 hx} {13 hx} {14 hx} {15 hx} {16 hx} {17 hx} {18 hx}
+	{19 hx} {gn hx} {0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11} {12}
+	{13} {14} {15} {16} {17} {18} {19} {gn} {0 wh} {1 wh} {2 wh} {3 wh}
+	{4 wh} {5 wh} {6 wh} {7 wh} {8 wh} {9 wh} {10 wh} {11 wh} {12 wh}
+	{13 wh} {14 wh} {gn wh} {0 bl} {1 bl} {2 bl} {3 bl} {4 bl} {5 bl} {6 bl}
+	{7 bl} {8 bl} {9 bl} {10 bl} {11 bl} {12 bl} {13 bl} {14 bl} {gn bl}
+	{0 fl} {1 fl} {2 fl} {3 fl} {4 fl} {5 fl} {6 fl} {7 fl} {8 fl} {9 fl}
+	{10 fl} {11 fl} {12 fl} {13 fl} {14 fl} {gn fl}
+	] def
+	/sl FMLOCAL
+	/val FMLOCAL
+	/ws FMLOCAL
+	/im FMLOCAL
+	/bs FMLOCAL
+	/cs FMLOCAL
+	/len FMLOCAL
+	/pos FMLOCAL
+/ms { 
+	/sl exch def 
+	/val 255 def 
+	/ws cfs 
+	/im cfs 
+	/val 0 def 
+	/bs cfs 
+	/cs cfs 
+	} bind def
+400 ms 
+/ip { 
+	is 
+	0 
+	cf cs readline pop 
+	{	ic exch get exec 
+		add 
+		} forall 
+	pop 
+	
+	} bind def
+/wh { 
+	/len exch def 
+	/pos exch def 
+	ws 0 len getinterval im pos len getinterval copy pop
+	pos len 
+	} bind def
+/bl { 
+	/len exch def 
+	/pos exch def 
+	bs 0 len getinterval im pos len getinterval copy pop
+	pos len 
+	} bind def
+/s1 1 string def
+/fl { 
+	/len exch def 
+	/pos exch def 
+	/val cf s1 readhexstring pop 0 get def
+	pos 1 pos len add 1 sub {im exch val put} for
+	pos len 
+	} bind def
+/hx { 
+	3 copy getinterval 
+	cf exch readhexstring pop pop 
+	} bind def
+	/h FMLOCAL
+	/w FMLOCAL
+	/d FMLOCAL
+	/lb FMLOCAL
+	/bitmapsave FMLOCAL
+	/is FMLOCAL
+	/cf FMLOCAL
+/wbytes { 
+	dup 
+	8 eq {pop} {1 eq {7 add 8 idiv} {3 add 4 idiv} ifelse} ifelse
+	} bind def
+/BEGINBITMAPBWc { 
+	1 {} COMMONBITMAPc
+	} bind def
+/BEGINBITMAPGRAYc { 
+	8 {} COMMONBITMAPc
+	} bind def
+/BEGINBITMAP2BITc { 
+	2 {} COMMONBITMAPc
+	} bind def
+/COMMONBITMAPc { 
+	/r exch def
+	/d exch def
+	gsave
+	translate rotate scale /h exch def /w exch def
+	/lb w d wbytes def 
+	sl lb lt {lb ms} if 
+	/bitmapsave save def 
+	r                    
+	/is im 0 lb getinterval def 
+	ws 0 lb getinterval is copy pop 
+	/cf currentfile def 
+	w h d [w 0 0 h neg 0 h] 
+	{ip} image 
+	bitmapsave restore 
+	grestore
+	} bind def
+/BEGINBITMAPBW { 
+	1 {} COMMONBITMAP
+	} bind def
+/BEGINBITMAPGRAY { 
+	8 {} COMMONBITMAP
+	} bind def
+/BEGINBITMAP2BIT { 
+	2 {} COMMONBITMAP
+	} bind def
+/COMMONBITMAP { 
+	/r exch def
+	/d exch def
+	gsave
+	translate rotate scale /h exch def /w exch def
+	/bitmapsave save def 
+	r                    
+	/is w d wbytes string def
+	/cf currentfile def 
+	w h d [w 0 0 h neg 0 h] 
+	{cf is readhexstring pop} image
+	bitmapsave restore 
+	grestore
+	} bind def
+	/proc1 FMLOCAL
+	/proc2 FMLOCAL
+	/newproc FMLOCAL
+/Fmcc {
+    /proc2 exch cvlit def
+    /proc1 exch cvlit def
+    /newproc proc1 length proc2 length add array def
+    newproc 0 proc1 putinterval
+    newproc proc1 length proc2 putinterval
+    newproc cvx
+} bind def
+/ngrayt 256 array def
+/nredt 256 array def
+/nbluet 256 array def
+/ngreent 256 array def
+	/gryt FMLOCAL
+	/blut FMLOCAL
+	/grnt FMLOCAL
+	/redt FMLOCAL
+	/indx FMLOCAL
+	/cynu FMLOCAL
+	/magu FMLOCAL
+	/yelu FMLOCAL
+	/k FMLOCAL
+	/u FMLOCAL
+/colorsetup {
+	currentcolortransfer
+	/gryt exch def
+	/blut exch def
+	/grnt exch def
+	/redt exch def
+	0 1 255 {
+		/indx exch def
+		/cynu 1 red indx get 255 div sub def
+		/magu 1 green indx get 255 div sub def
+		/yelu 1 blue indx get 255 div sub def
+		/k cynu magu min yelu min def
+		/u k currentundercolorremoval exec def
+		nredt indx 1 0 cynu u sub max sub redt exec put
+		ngreent indx 1 0 magu u sub max sub grnt exec put
+		nbluet indx 1 0 yelu u sub max sub blut exec put
+		ngrayt indx 1 k currentblackgeneration exec sub gryt exec put
+	} for
+	{255 mul cvi nredt exch get}
+	{255 mul cvi ngreent exch get}
+	{255 mul cvi nbluet exch get}
+	{255 mul cvi ngrayt exch get}
+	setcolortransfer
+	{pop 0} setundercolorremoval
+	{} setblackgeneration
+	} bind def
+	/tran FMLOCAL
+/fakecolorsetup {
+	/tran 256 string def
+	0 1 255 {/indx exch def 
+		tran indx
+		red indx get 77 mul
+		green indx get 151 mul
+		blue indx get 28 mul
+		add add 256 idiv put} for
+	currenttransfer
+	{255 mul cvi tran exch get 255.0 div}
+	exch Fmcc settransfer
+} bind def
+/BITMAPCOLOR { 
+	/d 8 def
+	gsave
+	translate rotate scale /h exch def /w exch def
+	/bitmapsave save def 
+	colorsetup
+	/is w d wbytes string def
+	/cf currentfile def 
+	w h d [w 0 0 h neg 0 h] 
+	{cf is readhexstring pop} {is} {is} true 3 colorimage 
+	bitmapsave restore 
+	grestore
+	} bind def
+/BITMAPCOLORc { 
+	/d 8 def
+	gsave
+	translate rotate scale /h exch def /w exch def
+	/lb w d wbytes def 
+	sl lb lt {lb ms} if 
+	/bitmapsave save def 
+	colorsetup
+	/is im 0 lb getinterval def 
+	ws 0 lb getinterval is copy pop 
+	/cf currentfile def 
+	w h d [w 0 0 h neg 0 h] 
+	{ip} {is} {is} true 3 colorimage
+	bitmapsave restore 
+	grestore
+	} bind def
+/BITMAPTRUECOLORc { 
+        gsave
+        translate rotate scale /h exch def /w exch def
+        /bitmapsave save def 
+        
+        /is w string def
+        
+        ws 0 w getinterval is copy pop 
+        /cf currentfile def 
+        w h 8 [w 0 0 h neg 0 h] 
+        {ip} {gip} {bip} true 3 colorimage
+        bitmapsave restore 
+        grestore
+        } bind def
+/BITMAPTRUECOLOR { 
+        gsave
+        translate rotate scale /h exch def /w exch def
+        /bitmapsave save def 
+        /is w string def
+        /gis w string def
+        /bis w string def
+        /cf currentfile def 
+        w h 8 [w 0 0 h neg 0 h] 
+        { cf is readhexstring pop } 
+        { cf gis readhexstring pop } 
+        { cf bis readhexstring pop } 
+        true 3 colorimage 
+        bitmapsave restore 
+        grestore
+        } bind def
+/BITMAPTRUEGRAYc { 
+        gsave
+        translate rotate scale /h exch def /w exch def
+        /bitmapsave save def 
+        
+        /is w string def
+        
+        ws 0 w getinterval is copy pop 
+        /cf currentfile def 
+        w h 8 [w 0 0 h neg 0 h] 
+        {ip gip bip w gray} image
+        bitmapsave restore 
+        grestore
+        } bind def
+/ww FMLOCAL
+/r FMLOCAL
+/g FMLOCAL
+/b FMLOCAL
+/i FMLOCAL
+/gray { 
+        /ww exch def
+        /b exch def
+        /g exch def
+        /r exch def
+        0 1 ww 1 sub { /i exch def r i get .299 mul g i get .587 mul
+			b i get .114 mul add add r i 3 -1 roll floor cvi put } for
+        r
+        } bind def
+/BITMAPTRUEGRAY { 
+        gsave
+        translate rotate scale /h exch def /w exch def
+        /bitmapsave save def 
+        /is w string def
+        /gis w string def
+        /bis w string def
+        /cf currentfile def 
+        w h 8 [w 0 0 h neg 0 h] 
+        { cf is readhexstring pop 
+          cf gis readhexstring pop 
+          cf bis readhexstring pop w gray}  image
+        bitmapsave restore 
+        grestore
+        } bind def
+/BITMAPGRAY { 
+	8 {fakecolorsetup} COMMONBITMAP
+	} bind def
+/BITMAPGRAYc { 
+	8 {fakecolorsetup} COMMONBITMAPc
+	} bind def
+/ENDBITMAP {
+	} bind def
+end 
+	/ALDsave FMLOCAL
+	/ALDmatrix matrix def ALDmatrix currentmatrix pop
+/StartALD {
+	/ALDsave save def
+	 savematrix
+	 ALDmatrix setmatrix
+	} bind def
+/InALD {
+	 restorematrix
+	} bind def
+/DoneALD {
+	 ALDsave restore
+	} bind def
+%%EndProlog
+%%BeginSetup
+(3.0) FMVERSION
+1 1 612 792 0 1 12 FMDOCUMENT
+0 0 /Times-Roman FMFONTDEFINE
+1 0 /Times-Bold FMFONTDEFINE
+2 0 /Courier FMFONTDEFINE
+3 0 /Times-Italic FMFONTDEFINE
+32 FMFILLS
+0 0 FMFILL
+1 .1 FMFILL
+2 .3 FMFILL
+3 .5 FMFILL
+4 .7 FMFILL
+5 .9 FMFILL
+6 .97 FMFILL
+7 1 FMFILL
+8 <0f1e3c78f0e1c387> FMFILL
+9 <0f87c3e1f0783c1e> FMFILL
+10 <cccccccccccccccc> FMFILL
+11 <ffff0000ffff0000> FMFILL
+12 <8142241818244281> FMFILL
+13 <03060c183060c081> FMFILL
+14 <8040201008040201> FMFILL
+16 1 FMFILL
+17 .9 FMFILL
+18 .7 FMFILL
+19 .5 FMFILL
+20 .3 FMFILL
+21 .1 FMFILL
+22 0.03 FMFILL
+23 0 FMFILL
+24 <f0e1c3870f1e3c78> FMFILL
+25 <f0783c1e0f87c3e1> FMFILL
+26 <3333333333333333> FMFILL
+27 <0000ffff0000ffff> FMFILL
+28 <7ebddbe7e7dbbd7e> FMFILL
+29 <fcf9f3e7cf9f3f7e> FMFILL
+30 <7fbfdfeff7fbfdfe> FMFILL
+%%EndSetup
+%%Page: "11" 11
+%%BeginPaperSize: Letter
+%%EndPaperSize
+612 792 0 FMBEGINPAGE
+57.97 26.65 554.03 40.82 R
+7 X
+0 K
+V
+0 10 Q
+0 X
+(11) 301 34.15 T
+56.69 54.99 297.64 735.31 R
+7 X
+V
+1 12 Q
+0 X
+(7. Fr) 56.69 727.31 T
+(equently Asked Questions) 81.12 727.31 T
+0 F
+(7.1 Questions) 56.69 699.31 T
+(1. How do I encode a sequence that can be) 82.49 672.31 T
+(played by the Xing player?) 56.69 658.31 T
+(2. I\325m using the Parallax XV) 82.49 644.31 T
+(ideo card to) 220.34 644.31 T
+(digitize; how do I MPEG-encode the resulting) 56.69 630.31 T
+(data?) 56.69 616.31 T
+(3. How do I convert the MPEG-encoder) 82.49 602.31 T
+(YUV \336les into PPM \336les?) 56.69 588.31 T
+(7.2 Answers) 56.69 546.31 T
+-0.76 (1. The XING player samples video at 160x120 and) 56.69 518.31 P
+(expands to output 320x240. This is where their) 56.69 504.31 T
+(speed comes from. The player cannot buf) 56.69 490.31 T
+(fer a) 255.32 490.31 T
+(320x240 and thus had data overruns. The xing) 56.69 476.31 T
+(player would \325) 56.69 462.31 T
+(theoretically\325 handle 160x120 I) 126.42 462.31 T
+(frames.) 56.69 448.31 T
+(Thus, to encode, use P) 56.69 420.31 T
+(A) 163.52 420.31 T
+(TTERN I and 160x120) 170.85 420.31 T
+(frames.) 56.69 406.31 T
+(\050jboucher@\337ash.bu.edu\051) 56.69 392.31 T
+(2. Use the type JMOVIE, or use the jmovie2jpeg) 56.69 364.31 T
+(utility in the misc/ directory) 56.69 350.31 T
+(.) 189.84 350.31 T
+(3. Stanford\325) 56.69 322.31 T
+(s CVv1.2.2.tar) 113.33 322.31 T
+(.Z includes) 182.62 322.31 T
+(cyuv2ppm.c.) 56.69 308.31 T
+-0.2 (Which after you split the Y) 56.69 294.31 P
+-0.2 (, U, and V components) 185.05 294.31 P
+(out, works \336ne. \050curly@hsn.cftnet.com\051) 56.69 280.31 T
+(This can be ftp\325d from) 56.69 252.31 T
+2 F
+(havefun.stanford.edu) 56.69 238.31 T
+0 F
+(, in the directory) 200.61 238.31 T
+2 F
+(/) 282.89 238.31 T
+(pub/cv/) 56.69 224.31 T
+0 F
+(.) 107.07 224.31 T
+314.36 54.99 552.76 735.31 R
+7 X
+V
+FMENDPAGE
+%%EndPage: "11" 10
+%%Page: "10" 10
+612 792 0 FMBEGINPAGE
+57.97 26.65 554.03 40.82 R
+7 X
+0 K
+V
+0 10 Q
+0 X
+(10) 301 34.15 T
+56.69 54.99 297.64 735.31 R
+7 X
+V
+0 X
+(Usage:) 85.04 728.64 T
+2 F
+(ppmtoeyuv < input.ppm > output.yuv) 85.04 715.64 T
+0 F
+0.33 (This takes as input a ppm file and outputs a subsam-) 85.04 689.64 P
+(pled yuv file suitable for the encoder.) 56.69 678.64 T
+0 12 Q
+(6.2 jmovie2jpeg) 56.69 636.31 T
+0 10 Q
+(Usage:) 85.04 610.64 T
+2 F
+4.9 (jmovie2jpeg infile outfile start-) 85.04 597.64 P
+(frame end-frame) 56.69 586.64 T
+(infile) 85.04 560.64 T
+0 F
+( is a version 2 Parallax J_Movie) 121.02 560.64 T
+2 F
+(outfile) 85.04 547.64 T
+0 F
+( is a base file name for the output files) 127.02 547.64 T
+2 F
+5.44 (start-frame) 85.04 534.64 P
+0 F
+2.27 ( and) 151 534.64 P
+2 F
+5.44 (end-frame) 174.97 534.64 P
+0 F
+2.27 ( are the starting) 228.94 534.64 P
+(and ending frame numbers) 56.69 523.64 T
+1.39 (This takes as input a J_Movie and creates separate) 85.04 497.64 P
+0.09 (JFIF compatible JPEG files with the names base<num>.jpg,) 56.69 486.64 P
+(where base is outfile, and <num> are the frame numbers.) 56.69 475.64 T
+9.6 (jmovie2jpeg was written by Jim Boucher) 85.04 462.64 P
+(\050jboucher@\337ash.bu.edu\051.) 56.69 451.64 T
+0 12 Q
+(6.3 movieT) 56.69 424.31 T
+(oV) 111.15 424.31 T
+(id) 125.09 424.31 T
+0 10 Q
+(Usage:) 85.04 398.64 T
+2 F
+22.34 (movieToVid movieFile dataDir) 85.04 385.64 P
+(indexDir srcHostName) 56.69 374.64 T
+0 F
+0.95 (This program is used to convert a Parallax J Movie) 85.04 348.64 P
+0.58 (into a \322.vid\323 file, which is video only. vid files are used by) 56.69 337.64 P
+(some of the programs described later.) 56.69 326.64 T
+0.55 (See the README file in misc/mtv/ for more details) 85.04 313.64 P
+(on usage.) 56.69 302.64 T
+0.58 (movieToVid was written by Brian Smith \050bsmith@-) 85.04 289.64 P
+(cs.berkeley.edu\051) 56.69 278.64 T
+0 12 Q
+(6.4 eyuvtojpeg) 56.69 236.31 T
+0 10 Q
+(Usage:) 85.04 210.64 T
+2 F
+(eyuvtojpeg infile outfile) 85.04 197.64 T
+0 F
+0.27 (This takes as input an encoder yuv file and outputs a) 85.04 171.64 P
+(jpeg file. It uses cjpeg to do the compression.) 56.69 160.64 T
+0 12 Q
+(6.5 blockrun) 56.69 118.31 T
+0 10 Q
+(Usage:) 85.04 92.64 T
+2 F
+2.9 (blockrun command num_args firstnum) 85.04 79.64 P
+(lastnum skip arg1 ... argn) 56.69 68.64 T
+314.36 54.99 552.76 735.31 R
+7 X
+V
+0 F
+0 X
+7.53 (This runs the given command \050which has) 342.71 715.64 P
+2 F
+0.32 (num_args) 314.36 704.64 P
+0 F
+0.13 ( args\051, with the args) 362.34 704.64 P
+2 F
+0.32 (arg1 ... argn) 444.61 704.64 P
+0 F
+0.13 (, where) 523.21 704.64 P
+-0.04 (any \325=\325 character is replaced by a number from) 314.36 693.64 P
+2 F
+-0.09 (firstnum) 504.78 693.64 P
+0 F
+(to) 314.36 682.64 T
+2 F
+(lastnum) 324.64 682.64 T
+0 F
+( skipping by) 366.61 682.64 T
+2 F
+(skip) 418.54 682.64 T
+0 F
+(. For example:) 442.52 682.64 T
+2 F
+7.23 (blockrun eyuvtojpeg 2 13 19 3) 342.71 669.64 P
+(flow=.yuv flow=.jpg) 314.36 658.64 T
+0 F
+(will run:) 342.71 632.64 T
+2 F
+(eyuvtojpeg flow13.yuv flow13.jpg) 342.71 606.64 T
+(eyuvtojpeg flow16.yuv flow16.jpg) 342.71 593.64 T
+(eyuvtojpeg flow19.yuv flow19.jpg) 342.71 580.64 T
+0 12 Q
+(6.6 vidtoppm) 314.36 553.31 T
+0 10 Q
+(Usage:) 342.71 527.64 T
+2 F
+10.05 (vidtoppm filename width height) 342.71 514.64 P
+(start end outbase [quality]) 314.36 503.64 T
+0 F
+0.39 (This takes as input a .vid file of given) 342.71 477.64 P
+2 F
+0.94 (height) 499.45 477.64 P
+0 F
+0.39 ( and) 535.43 477.64 P
+2 F
+2.91 (width) 314.36 466.64 P
+0 F
+1.22 (, and turns them into a bunch of ppm files named) 344.35 466.64 P
+2 F
+(outbase) 314.36 455.64 T
+0 F
+(.N, where N is a number from) 356.34 455.64 T
+2 F
+(start) 478.74 455.64 T
+0 F
+( to) 508.73 455.64 T
+2 F
+(end) 521.5 455.64 T
+0 F
+(.) 539.49 455.64 T
+0 12 Q
+(6.7 vidtojpeg) 314.36 428.31 T
+0 10 Q
+(Usage:) 342.71 402.64 T
+2 F
+8.05 (vidtojpeg filename width height) 342.71 389.64 P
+(start end outbase [quality]) 314.36 378.64 T
+0 F
+2.83 (This is the same as vidtoppm, except it outputs) 342.71 352.64 P
+(JPEG files instead of PPM files.) 314.36 341.64 T
+0 12 Q
+(6.8 vidtoeyuv) 314.36 314.31 T
+0 10 Q
+(Usage:) 342.71 288.64 T
+2 F
+8.05 (vidtoeyuv filename width height) 342.71 275.64 P
+(start nth outbase [quality]) 314.36 264.64 T
+0 F
+0.39 (This takes as input a .vid file of given) 342.71 238.64 P
+2 F
+0.94 (height) 499.45 238.64 P
+0 F
+0.39 ( and) 535.43 238.64 P
+2 F
+3.58 (width) 314.36 227.64 P
+0 F
+1.49 (, and turns them into a bunch of yuv files named) 344.35 227.64 P
+2 F
+2.87 (outbase) 314.36 216.64 P
+0 F
+1.2 (.N, where N is a number from) 356.34 216.64 P
+2 F
+2.87 (start) 487.12 216.64 P
+0 F
+1.2 ( to) 517.1 216.64 P
+2 F
+2.87 (end) 532.27 216.64 P
+0 F
+1.2 (,) 550.26 216.64 P
+(skipping by) 314.36 205.64 T
+2 F
+(nth) 363.79 205.64 T
+0 F
+(.) 381.77 205.64 T
+0 12 Q
+(6.8 PBMPLUS) 314.36 176.31 T
+0 10 Q
+-0.04 (There is a very useful package called pbmplus avail-) 342.71 150.64 P
+1.46 (able for ftp \050ee.utah.edu:/pbmplus for example\051. This has) 314.36 139.64 P
+0.31 (conversions from TIFF, GIF, and many other common for-) 314.36 128.64 P
+0.86 (mats to PPMs, which the encoder can read. You can even) 314.36 117.64 P
+0.58 (keep the originals in their own format, and do conversions) 314.36 106.64 P
+(via) 314.36 95.64 T
+2 F
+(INPUT_CONVERT.) 329.07 95.64 T
+FMENDPAGE
+%%EndPage: "10" 9
+%%Page: "9" 9
+612 792 0 FMBEGINPAGE
+57.97 26.65 554.03 40.82 R
+7 X
+0 K
+V
+0 10 Q
+0 X
+(9) 303.5 34.15 T
+56.69 54.99 297.64 735.31 R
+7 X
+V
+0 X
+0.08 (ating input files must work on the remote machine. Also the) 56.69 728.64 P
+1.78 (USER_DATA and CDL_FILE files must be available on) 56.69 717.64 P
+2.53 (the remote sites as specified in the parameter file. This) 56.69 706.64 P
+(should be fixed in future versions.) 56.69 695.64 T
+1 12 Q
+(4. Performance) 56.69 668.31 T
+0 10 Q
+1.23 (Table seven shows a comparison of sequential per-) 85.04 641.64 P
+(formance on different machine types.) 56.69 630.64 T
+1.31 (Parallel performance is dependent not only on pro-) 85.04 422.64 P
+1.87 (cessor performance, but network performance. If you are) 56.69 411.64 P
+-0.21 (using a 10 Mb/s Ethernet, don\325t expect to get better than 4 or) 56.69 400.64 P
+0.89 (5 frames per second -- no matter how fast your processors) 56.69 389.64 P
+(are.) 56.69 378.64 T
+2.5 (Parallel performance is also greatly dependent on) 85.04 365.64 P
+1.16 (how big the input files are \050YUV is better than PPM, and) 56.69 354.64 P
+0.81 (JPEG is better than both\051, and how big the output files are) 56.69 343.64 P
+(\050better compression will lead to less I/O\051.) 56.69 332.64 T
+1 12 Q
+(5. Other Options) 56.69 305.31 T
+0 10 Q
+-0 (This section gives example of some more rarely used) 85.04 278.64 P
+0.12 (options in the parameter \336le, such as customizing the Quan-) 56.69 267.64 P
+(tization tables, or setting the aspect ratio.) 56.69 256.64 T
+0 12 Q
+(5.1 Custom Quantization T) 56.69 229.31 T
+(ables \050parameter \336le\051) 186.45 229.31 T
+0 10 Q
+(You can specify your own custom quantization tables.) 56.69 206.64 T
+-0.31 (Currently you can only do this once per MPEG file.) 56.69 194.64 P
+-0.31 ( Y) 260.99 194.64 P
+-0.31 (ou can) 269.39 194.64 P
+-0.06 (specify both Intra- and Non-intra quantization tables. If you) 56.69 182.64 P
+-0.44 (don\325) 56.69 170.64 P
+-0.44 (t specify them, then the default tables are used \050c.f. page) 74.83 170.64 P
+(D-16, D-17 of the standard\051.) 56.69 158.64 T
+(Usage:) 85.04 141.64 T
+2 F
+(IQTABLE) 85.04 115.64 T
+(table row 1) 85.04 102.64 T
+(table row 2) 85.04 89.64 T
+(...) 85.04 76.64 T
+(table row 8) 85.04 63.64 T
+100.63 478.31 253.7 484.31 C
+0 0 612 792 C
+0 10 Q
+0 X
+0 K
+0.06 (a. Macroblocks per second; a) 118.63 471.64 P
+1.5 (320x240 pixel image is 300) 118.63 459.64 P
+(macroblocks per frame.) 118.63 447.64 T
+1 12 Q
+(T) 99.59 594.31 T
+(able 7: Machine Comparison) 106.49 594.31 T
+0 10 Q
+(Machine) 121.41 572.64 T
+(MPS) 203.66 572.64 T
+0 8 Q
+(a) 223.66 576.64 T
+0 10 Q
+(HP 9000/755) 120.13 554.64 T
+(280) 207.94 554.64 T
+(DEC 3000/400) 112.92 538.64 T
+(247) 207.94 538.64 T
+(HP 9000/750) 120.13 522.64 T
+(191) 207.94 522.64 T
+(Sparc 10) 137.91 506.64 T
+(104) 207.94 506.64 T
+(DEC 5000) 130.69 490.64 T
+(68) 210.44 490.64 T
+100.63 584.06 100.63 484.56 2 L
+V
+0.5 H
+0 Z
+N
+177.16 584.56 177.16 484.06 2 L
+V
+N
+253.7 584.06 253.7 484.56 2 L
+V
+N
+100.38 584.31 253.95 584.31 2 L
+V
+N
+100.88 565.56 253.45 565.56 2 L
+V
+N
+100.88 563.06 253.45 563.06 2 L
+V
+N
+100.38 548.31 253.95 548.31 2 L
+V
+N
+100.38 532.31 253.95 532.31 2 L
+V
+N
+100.38 516.31 253.95 516.31 2 L
+V
+N
+100.38 500.31 253.95 500.31 2 L
+V
+N
+100.38 484.31 253.95 484.31 2 L
+V
+N
+314.36 54.99 552.76 735.31 R
+7 X
+V
+0 X
+0.96 (This specifies the intra-coding quantization table \050I) 342.71 715.64 P
+0.01 (frames and I-blocks in P and B frames\051. Each) 314.36 704.64 P
+2 F
+0.03 (table row) 498.76 704.64 P
+0 F
+(is simply 8 integers, separated by tabs and/or spaces.) 314.36 693.64 T
+(Usage:) 342.71 680.64 T
+2 F
+(NIQTABLE) 342.71 654.64 T
+(table row 1) 342.71 641.64 T
+(table row 2) 342.71 628.64 T
+(...) 342.71 615.64 T
+(table row 8) 342.71 602.64 T
+0 F
+4.63 (This specifies the non-intra-coding quantization) 342.71 576.64 P
+(table \050difference vectors in P and B frames\051.) 314.36 565.64 T
+0 12 Q
+(5.2 Aspect Ratio \050parameter \336le\051) 314.36 538.31 T
+0 10 Q
+(Y) 340.16 512.64 T
+(ou can specify the aspect ratio to be one of the) 346.37 512.64 T
+(fourteen legal values as speci\336ed in the standard \050c.f.) 314.36 500.64 T
+(Section 2.4.3.2\051. This sets the requested aspect ration for) 314.36 488.64 T
+(playback.) 314.36 476.64 T
+0 12 Q
+(Usage:) 340.16 463.31 T
+(ASPECT_RA) 340.16 449.31 T
+(TIO \337oat) 406.13 449.31 T
+2 10 Q
+8.03 (float) 342.71 436.64 P
+0 F
+3.34 ( is one of {1.0, 0.6735, 0.7031, 0.7615,) 372.69 436.64 P
+2.25 (0.8055, 0.8437, 0.8935, 0.9157, 0.9815, 1.0255, 1.0695,) 314.36 425.64 P
+(1.0950, 1.1575, 1.2015}.) 314.36 414.64 T
+0 12 Q
+(5.3 Frame Rate \050parameter \336le\051) 314.36 374.31 T
+0 10 Q
+-0 (You can specify the frame rate to be one of the eight) 342.71 348.64 P
+1.97 (legal values \050c.f. Section 2.4.3.2\051. This is used by some) 314.36 337.64 P
+(playback systems to gauge the playback rate.) 314.36 326.64 T
+(Usage:) 342.71 313.64 T
+2 F
+(FRAME_RATE float) 342.71 300.64 T
+4.91 (float) 342.71 287.64 P
+0 F
+2.05 ( is one of {23.976, 24, 25, 29.97, 30, 50,) 372.69 287.64 P
+(59.94, 60}.) 314.36 276.64 T
+0 12 Q
+(5.4 Floating Point DCT \050command line\051) 314.36 249.31 T
+0 10 Q
+2.13 (The encoder normally uses a quick algorithm for) 342.71 236.64 P
+2.06 (forward and reverse DCTs. However, in sequences with) 314.36 225.64 P
+0.5 (many P frames, this can result in errors when decoded ref-) 314.36 214.64 P
+0.4 (erence frames are used. To use the \050slow\051 double precision) 314.36 203.64 P
+(accurate dcts, use the following flag:) 314.36 192.64 T
+(Usage:) 342.71 179.64 T
+(mpeg_encode -float_dct) 342.71 166.64 T
+1 12 Q
+(6. Other T) 314.36 139.31 T
+(ools) 366.89 139.31 T
+0 10 Q
+(The misc/ directory contains several useful tools.) 314.36 112.64 T
+0 12 Q
+(6.1 ppmtoeyuv) 314.36 83.31 T
+FMENDPAGE
+%%EndPage: "9" 8
+%%Page: "8" 8
+612 792 0 FMBEGINPAGE
+57.97 26.65 554.03 40.82 R
+7 X
+0 K
+V
+0 10 Q
+0 X
+(8) 303.5 34.15 T
+56.69 54.99 297.64 735.31 R
+7 X
+V
+0 X
+(frame-to-I-frame scale.) 56.69 728.64 T
+(Usage:) 85.04 715.64 T
+2 F
+(-bit_rate_info rate_file) 85.04 702.64 T
+0 F
+(This puts the bit rate info into the specified file) 85.04 689.64 T
+(\050order of info, etc.\051) 85.04 676.64 T
+1 12 Q
+(3. Parallel Usage) 56.69 641.31 T
+0 10 Q
+1.03 (In parallel execution there are slave processes. You) 85.04 610.64 P
+(can have those processes run nicely if you want.) 56.69 599.64 T
+(Usage:) 85.04 586.64 T
+2 F
+(-nice) 85.04 573.64 T
+0 F
+3.56 (This makes all slave processes run nicely. This) 85.04 560.64 P
+0.8 (means that interactive users take precedence, so they don\325t) 56.69 549.64 P
+-0.2 (feel like they\325re running in molasses. If you want to be mean) 56.69 538.64 P
+(to them, don\325t use this option. :-\051) 56.69 527.64 T
+0 12 Q
+(3.1 Architecture Overview) 56.69 500.31 T
+0 10 Q
+1.3 (Figure 1 shows a diagram of the system architecture. The) 56.69 474.64 P
+-0.03 (slaves exist on the different slave machines which you spec-) 56.69 463.64 P
+1.5 (ify \050see Section 3.2\051. The server processes all live on the) 56.69 452.64 P
+(machine you run the encoder on.) 56.69 441.64 T
+0 12 Q
+(3.2 Specifying Slave Machines \050both\051) 56.69 412.31 T
+0 10 Q
+0.03 (You specify the slave machines in the parameter file.) 85.04 386.64 P
+-0.2 (For each slave you must specify the username to use, as well) 56.69 375.64 P
+0.06 (as the executable mpeg_encode program. If a slave does not) 56.69 364.64 P
+1.52 (have NFS access, then it is REMOTE and you must also) 56.69 353.64 P
+(specify where the parameter file is.) 56.69 342.64 T
+(Usage:) 85.04 316.64 T
+2 F
+(PARALLEL) 85.04 303.64 T
+(slave_specification) 85.04 290.64 T
+(END_PARALLEL) 85.04 277.64 T
+(slave_specification) 85.04 251.64 T
+0 F
+( can be either:) 198.98 251.64 T
+2 F
+(machine username executable) 85.04 238.64 T
+0 F
+(or) 85.04 225.64 T
+2 F
+2.9 (REMOTE machine username executable) 85.04 212.64 P
+(param_file) 56.69 201.64 T
+0 F
+0.76 (You must have an account with the given username) 85.04 175.64 P
+0.06 (on each machine, and you must place your machine/login in) 56.69 164.64 P
+(the appropriate .rhosts files.) 56.69 153.64 T
+1.59 (To make it easier to run experiments with varying) 85.04 127.64 P
+1.35 (numbers of processors, there is a command-line argument) 56.69 116.64 P
+(which limits the number of slave machines.) 56.69 105.64 T
+(Usage:) 85.04 79.64 T
+2 F
+(-max_machines num_machines) 85.04 66.64 T
+314.36 54.99 552.76 735.31 R
+7 X
+V
+0 F
+0 X
+0.98 (This means that the encoder will use no more than) 342.71 728.64 P
+2 F
+(num_machines) 314.36 717.64 T
+0 F
+( machines as slaves.) 386.32 717.64 T
+0 12 Q
+(3.3 Remote Shell \050parameter \336le\051) 314.36 677.31 T
+0 10 Q
+0.98 (To run processes on the slave machines, mpeg_en-) 342.71 651.64 P
+1.52 (code uses the remote shell command. On most machines) 314.36 640.64 P
+-0.09 (this is the command) 314.36 629.64 P
+2 F
+-0.2 (rsh) 396.76 629.64 P
+0 F
+-0.09 (. On HP machines, however, rsh is) 414.75 629.64 P
+0.39 (the restricted shell; on HP machines, the right command to) 314.36 618.64 P
+(use is) 314.36 607.64 T
+2 F
+(remsh) 339.35 607.64 T
+0 F
+(, rather than) 369.33 607.64 T
+2 F
+(rsh) 419.84 607.64 T
+0 F
+(.) 437.83 607.64 T
+(Usage:) 342.71 594.64 T
+2 F
+(RSH <rsh command>) 342.71 568.64 T
+0 12 Q
+(3.4 Scheduling Algorithms \050parameter \336le\051) 314.36 528.31 T
+0 10 Q
+0.87 (The encoder provides 3 different scheduling algorithms to) 314.36 502.64 P
+(schedule which processors get which frames.) 314.36 491.64 T
+2.03 (The first scheduling algorithm simply assigns N/P) 340.16 478.64 P
+0.28 (frames to each processor, where N is the number of frames) 314.36 467.64 P
+0.72 (and P is the number of processors. This has the advantage) 314.36 456.64 P
+-0.01 (of minimal overhead, but only works well when all the pro-) 314.36 445.64 P
+0.3 (cessors run at nearly the same speed. Also, since most pro-) 314.36 434.64 P
+0.37 (cessors will finish at about the same time, you will have to) 314.36 423.64 P
+1.41 (wait at the end while the Combine Server gathers all the) 314.36 412.64 P
+(frame files together.) 314.36 401.64 T
+(Usage:) 340.16 388.64 T
+(PARALLEL_PERFECT) 340.16 375.64 T
+3.6 (The second scheduling algorithm first assigns S) 340.16 349.64 P
+-0.09 (frames to each processor. When a processor is finished, it is) 314.36 338.64 P
+1.49 (assigned T seconds of work \050the scheduler estimates this) 314.36 327.64 P
+1.97 (based on previous performance\051. S should be at least 3,) 314.36 316.64 P
+0.37 (preferably at least 5 or 6, to insure a good estimate of each) 314.36 305.64 P
+(processor\325s speed.) 314.36 294.64 T
+(Usage:) 340.16 281.64 T
+(PARALLEL_TEST_FRAMES S) 340.16 268.64 T
+(PARALLEL_TIME_CHUNKS T) 340.16 255.64 T
+0.79 (The third scheduling algorithm is probably the best.) 340.16 229.64 P
+2.43 (It also first assigns S frames to each processor. Subse-) 314.36 218.64 P
+3.44 (quently, however, whenever a processor finishes, it is) 314.36 207.64 P
+1.1 (assigned enough work to keep it busy until almost every-) 314.36 196.64 P
+2.04 (thing is done. Effectively, a processor is assigned many) 314.36 185.64 P
+-0.06 (frames, and then fewer and fewer frames as more work gets) 314.36 174.64 P
+2.92 (done. This insures good load balancing, while limiting) 314.36 163.64 P
+(scheduling overhead.) 314.36 152.64 T
+(Usage:) 340.16 139.64 T
+(PARALLEL_TEST_FRAMES S) 340.16 126.64 T
+(PARALLEL_CHUNK_TAPER) 340.16 113.64 T
+0 12 Q
+(3.5 Parallel problems \050parameter \336le\051) 314.36 86.31 T
+0 10 Q
+8.16 (There are some unsupported features using) 340.16 73.64 P
+-0.18 (REMOTE to specify slaves: The \324command\324 form of gener-) 314.36 62.64 P
+FMENDPAGE
+%%EndPage: "8" 7
+%%Page: "7" 7
+612 792 0 FMBEGINPAGE
+57.97 26.65 554.03 40.82 R
+7 X
+0 K
+V
+0 10 Q
+0 X
+(7) 303.5 34.15 T
+56.69 54.99 297.64 477.36 R
+7 X
+V
+0 X
+(you can specify frame files to combine.) 56.69 470.69 T
+1.11 (The parameter file may specify input frame files in) 85.04 457.69 P
+0.94 (the same manner as normal input files -- except instead of) 56.69 446.69 P
+7.11 (using INPUT_DIR, INPUT, and END_INPUT, use) 56.69 435.69 P
+28.3 (FRAME_INPUT_DIR, FRAME_INPUT, and) 56.69 424.69 P
+1.83 (FRAME_END_INPUT. If no input frame files are speci-) 56.69 413.69 P
+0.16 (fied, then the default is to use the output file name with suf-) 56.69 402.69 P
+(fix \322.frame.<frame_num>\323 starting from 0 as the input files.) 56.69 391.69 T
+0 12 Q
+(2.15 Stats and Other Options \050command line\051) 56.69 364.36 T
+0 10 Q
+0.43 (There are several options for printing or suppressing) 85.04 338.69 P
+(useful information.) 56.69 327.69 T
+0.75 (The encoder always prints \050to stdout\051 parameter file) 85.04 314.69 P
+2.87 (information and statistics about how many I, P, and B) 56.69 303.69 P
+0.8 (frames there were, and information about compression and) 56.69 292.69 P
+2.31 (quality. You can send these statistics, in addition to the) 56.69 281.69 P
+(screen, to a file.) 56.69 270.69 T
+(Usage:) 85.04 257.69 T
+2 F
+( -stat stat_file) 110.83 244.69 T
+0 F
+2.56 (This appends the parameter file info and stats to) 85.04 231.69 P
+2 F
+(stat_file) 56.69 220.69 T
+0 F
+0.87 (Normally, the statistics do not include any informa-) 85.04 194.69 P
+1.77 (tion about quality. This is because computing the quality) 56.69 183.69 P
+2.02 (takes a little more time. If you wish to have the quality) 56.69 172.69 P
+1.17 (included in the statistics, use the -snr command line argu-) 56.69 161.69 P
+(ment.) 56.69 150.69 T
+(Usage:) 85.04 137.69 T
+2 F
+(-snr) 85.04 124.69 T
+0 F
+1.78 (This prints the signal-to-noise ratio \050snr\051 and peak) 85.04 111.69 P
+(snr.) 56.69 100.69 T
+3.69 (An additional statistic measure is mean squared) 85.04 74.69 P
+0.78 (error. If you wish to see the per-block mean squared error,) 56.69 63.69 P
+314.36 54.99 552.76 477.36 R
+7 X
+V
+0 X
+(use the -mse command line flag \050sets -snr as a side effect\051.) 314.36 470.69 T
+(Usage:) 342.71 457.69 T
+2 F
+(-mse) 342.71 444.69 T
+0 F
+(This prints the MSE for each block encoded) 342.71 431.69 T
+1.02 (Another set of data which can be useful is a histo-) 342.71 418.69 P
+0.44 (gram of the motion vectors. The encoder can keep track of) 314.36 407.69 P
+-0.16 (P-frame motion vectors and forward and backward B-frame) 314.36 396.69 P
+0.4 (motion vectors. The output is in the form of a matrix, each) 314.36 385.69 P
+0.98 (entry corresponding to a motion vector in the search win-) 314.36 374.69 P
+0.49 (dow. The center of the matrix represents \0500,0\051 motion vec-) 314.36 363.69 P
+(tors.) 314.36 352.69 T
+(Usage:) 342.71 339.69 T
+2 F
+(-mv_histogram) 342.71 326.69 T
+0 F
+1.47 (During normal execution, the encoder outputs two) 342.71 300.69 P
+0.58 (kinds of information. It prints a single line for each frame,) 314.36 289.69 P
+0.86 (summarizing block type and time info. It also prints, after) 314.36 278.69 P
+-0.07 (each frame, an estimate of the remaining running time. You) 314.36 267.69 P
+(can modify how often or if this information is to be shown.) 314.36 256.69 T
+(Usage:) 342.71 243.69 T
+2 F
+( -quiet num) 342.71 230.69 T
+( -no_frame_summary) 342.71 217.69 T
+(-realquiet) 349.8 204.69 T
+0 F
+-0.13 (If) 342.71 191.69 P
+2 F
+-0.31 (num) 351.74 191.69 P
+0 F
+-0.13 ( is negative, the time estimate is never shown;) 369.73 191.69 P
+1.94 (otherwise, it reports a time estimate no more often than) 314.36 180.69 P
+1.22 (every) 314.36 169.69 P
+2 F
+2.92 (num) 340.27 169.69 P
+0 F
+1.22 ( seconds \050unless the time estimate rises, which) 358.26 169.69 P
+1 (will happen near the beginning of the run\051. The default is) 314.36 158.69 P
+2 F
+(num) 314.36 147.69 T
+0 F
+( = 0, which means report after every frame.) 332.35 147.69 T
+1.08 (If) 342.71 134.69 P
+2 F
+2.59 (-no_frame_summary) 352.94 134.69 P
+0 F
+1.08 ( is given, then informa-) 454.89 134.69 P
+(tion about each frame is not printed.) 314.36 123.69 T
+2 F
+10.05 (-realquiet stops all printing,) 342.71 110.69 P
+(other than error messages.) 314.36 99.69 T
+0 F
+1 (Another nice feature is that the encoder can output) 342.71 73.69 P
+0.75 (the bit rate, on both a frame-to-frame scale, and also an I-) 314.36 62.69 P
+385.51 518.46 470.55 575.15 R
+7 X
+V
+0.5 H
+0 Z
+0 X
+N
+141.05 721.49 294.05 766.49 18 RR
+7 X
+V
+0 X
+N
+1 18 Q
+(Master Server) 165.05 738.43 T
+102.05 623.49 181.05 660.49 R
+7 X
+V
+0 X
+N
+(Slave) 121.05 637.49 T
+452.05 625.49 531.05 662.49 R
+7 X
+V
+0 X
+N
+(Slave) 471.05 639.49 T
+333.05 624.49 412.05 661.49 R
+7 X
+V
+0 X
+N
+(Slave) 352.05 638.49 T
+218.05 623.49 297.05 660.49 R
+7 X
+V
+0 X
+N
+(Slave) 237.05 637.49 T
+147.47 523.06 300.47 568.06 18 RR
+7 X
+V
+0 X
+N
+(Combine Server) 165.31 539.33 T
+498.64 673.25 501.04 661.49 492.77 670.19 495.71 671.72 4 Y
+V
+472.44 709.73 470.04 721.49 478.31 712.79 475.37 711.26 4 Y
+V
+495.71 671.72 475.38 711.26 2 L
+7 X
+V
+0 X
+N
+137.07 670.41 129.04 661.49 131.12 673.31 134.09 671.86 4 Y
+V
+149.02 710.57 157.04 719.49 154.97 707.67 151.99 709.12 4 Y
+V
+134.1 671.86 152 709.12 2 L
+7 X
+V
+0 X
+N
+164.04 661.55 152.04 661.49 162.18 667.9 163.11 664.73 4 Y
+V
+344.03 719.43 356.03 719.49 345.89 713.08 344.96 716.26 4 Y
+V
+163.12 664.72 344.98 716.25 2 L
+7 X
+V
+0 X
+N
+392.55 667.26 382.02 661.5 387.89 671.96 390.22 669.61 4 Y
+V
+430.5 714.73 441.02 720.49 435.15 710.03 432.82 712.38 4 Y
+V
+390.24 669.6 432.85 712.37 2 L
+7 X
+V
+0 X
+N
+277.89 664.38 266.04 662.49 275.09 670.37 276.49 667.37 4 Y
+V
+377.19 717.6 389.04 719.49 379.98 711.61 378.59 714.61 4 Y
+V
+276.5 667.37 378.6 714.61 2 L
+7 X
+V
+0 X
+N
+241.78 672.73 248.04 662.49 237.31 667.86 239.55 670.29 4 Y
+V
+192.3 709.25 186.04 719.49 196.78 714.12 194.54 711.69 4 Y
+V
+239.55 670.29 194.54 711.69 2 L
+7 X
+V
+0 X
+N
+353.94 670.32 363.03 662.49 351.17 664.31 352.56 667.32 4 Y
+V
+245.13 712.66 236.04 720.49 247.9 718.67 246.52 715.67 4 Y
+V
+352.57 667.31 246.52 715.66 2 L
+7 X
+V
+0 X
+N
+470.93 667.95 481.05 661.49 469.05 661.61 469.99 664.78 4 Y
+V
+287.16 714.03 277.05 720.49 289.05 720.37 288.1 717.2 4 Y
+V
+469.99 664.78 288.1 717.2 2 L
+7 X
+V
+0 X
+N
+336.05 720.49 489.05 765.49 18 RR
+7 X
+V
+0 X
+N
+(Decode Server) 360.05 737.43 T
+134.71 613.56 130.39 624.76 139.99 617.55 137.35 615.56 4 Y
+V
+168.59 579.26 172.91 568.07 163.31 575.27 165.95 577.27 4 Y
+V
+137.35 615.56 165.96 577.26 2 L
+7 X
+V
+0 X
+N
+234.18 617.55 243.77 624.76 239.45 613.56 236.82 615.56 4 Y
+V
+210.85 575.27 201.26 568.07 205.58 579.26 208.21 577.27 4 Y
+V
+236.82 615.56 208.22 577.26 2 L
+7 X
+V
+0 X
+N
+352.39 622.81 364.23 624.77 355.23 616.83 353.81 619.82 4 Y
+V
+255.6 570.03 243.76 568.08 252.77 576.01 254.18 573.02 4 Y
+V
+353.83 619.81 254.2 573.01 2 L
+7 X
+V
+0 X
+N
+465.63 624.68 477.63 624.76 467.5 618.33 466.56 621.51 4 Y
+V
+291.21 568.14 279.21 568.07 289.34 574.49 290.28 571.32 4 Y
+V
+466.57 621.51 290.28 571.31 2 L
+7 X
+V
+0 X
+N
+393.94 616.24 385.49 624.76 397.17 622.01 395.55 619.12 4 Y
+V
+440.83 597.86 449.27 589.33 437.59 592.09 439.21 594.98 4 Y
+V
+395.57 619.11 439.23 594.97 2 L
+7 X
+V
+0 X
+N
+281.34 617.08 272.12 624.76 284.01 623.14 282.67 620.11 4 Y
+V
+376.28 582.84 385.5 575.16 373.61 576.78 374.94 579.81 4 Y
+V
+282.68 620.1 374.96 579.8 2 L
+7 X
+V
+0 X
+N
+168.9 618.38 158.74 624.76 170.74 624.73 169.82 621.56 4 Y
+V
+375.34 567.36 385.51 560.98 373.51 561 374.43 564.18 4 Y
+V
+169.82 621.55 374.43 564.18 2 L
+7 X
+V
+0 X
+N
+312.01 543.5 300.47 546.8 312.01 550.11 312.01 546.8 4 Y
+V
+373.98 550.11 385.51 546.8 373.98 543.5 373.98 546.8 4 Y
+V
+312.01 546.8 373.98 546.8 2 L
+7 X
+V
+0 X
+N
+302.9 498.61 259.93 498.61 2 L
+V
+1.14 H
+N
+1 12 Q
+(Figure 1) 259.93 499.8 T
+385.51 498.49 302.9 498.49 2 L
+V
+0.59 H
+N
+0 F
+(: Network Model) 302.9 499.8 T
+495.43 619 505.95 624.77 500.08 614.3 497.76 616.65 4 Y
+V
+473.96 588.02 463.44 582.25 469.3 592.72 471.63 590.37 4 Y
+V
+497.79 616.64 471.66 590.35 2 L
+7 X
+V
+0.5 H
+0 X
+N
+1 18 Q
+(Disk) 410.52 530.49 T
+7 X
+90 450 42.52 14.17 428.03 575.15 G
+0 X
+90 450 42.52 14.17 428.03 575.15 A
+7 X
+180 270 42.94 21.26 428.45 521.28 G
+2 Z
+0 X
+180 270 42.94 21.26 428.45 521.28 A
+7 X
+270 360 42.94 21.26 427.68 521.61 G
+0 X
+270 360 42.94 21.26 427.68 521.61 A
+FMENDPAGE
+%%EndPage: "7" 6
+%%Page: "6" 6
+612 792 0 FMBEGINPAGE
+57.97 26.65 554.03 40.82 R
+7 X
+0 K
+V
+0 10 Q
+0 X
+(6) 303.5 34.15 T
+56.69 54.99 297.64 735.31 R
+7 X
+V
+0 X
+3.03 (number\051. This field entry can be changed by adding a) 56.69 728.64 P
+1.27 (USER_DATA parameter whose vale is the name of a file) 56.69 717.64 P
+(continuing the data to add to the header.) 56.69 706.64 T
+(Usage:) 85.04 693.64 T
+(USER_DATA ./user_data.txt) 85.04 667.64 T
+0 12 Q
+(2.1) 56.69 640.31 T
+(1 Compression Decision List \050CDL, also) 71.24 640.31 T
+(Speci\336cs File \050parameter \336le\051\051) 56.69 626.31 T
+0 10 Q
+0.18 (If you want to be very exact in what is set during the) 85.04 599.64 P
+1.71 (encoding, use CDL_FILE \050the older SPECIFICS_FILE is) 56.69 588.64 P
+0.18 (supported as well\051 to point to a file describing the exact set-) 56.69 577.64 P
+0.22 (tings wished for the encoding. The version 1.0 of CDL sup-) 56.69 566.64 P
+(port has the following format:) 56.69 555.64 T
+(version 1) 85.04 542.64 T
+(frame FN T Q) 85.04 529.64 T
+(slice SN Q) 85.04 516.64 T
+(block BN Q | BN Q skip | BN Q bi fx fy bx by |) 85.04 503.64 T
+(BN Q forw fx fy | BN Q back bx by) 109.7 490.64 T
+3.51 (FN, SN, and BN signal which frame/slice/block) 85.04 477.64 P
+1.64 (number the command applies to. Note that if you have a) 56.69 466.64 P
+2.22 (block or slice command, must be proceeded by a frame) 56.69 455.64 P
+0.63 (command for that frame. T sets the type of the frame \050I, P,) 56.69 444.64 P
+-0.06 (B, or - to not set\051. Q sets the q-scale \0501-31 or +N -N for rela-) 56.69 433.64 P
+0.17 (tive scaling, or 0 for no change\051. The detailed block specifi-) 56.69 422.64 P
+2.81 (cations set the motion vectors \050in half-pixel units\051. See) 56.69 411.64 P
+(specifications.c for more information.) 56.69 400.64 T
+2.25 (Version 2 CDL files have relative Qscales, so \3222) 85.04 387.64 P
+1.89 (\322means decrease the Qscale by 2, \3222\323 means increase it.) 56.69 376.64 P
+(Unsigned numbers like \3224\323 set the Qscale \050to 4\051.) 56.69 365.64 T
+(Usage:) 85.04 352.64 T
+(CDL_FILE filename) 85.04 326.64 T
+(CDL_DEFINES string) 85.04 313.64 T
+3 (where filename contains the specifics, and string) 85.04 300.64 P
+0.61 (\050optional\051 are defines to be passed to the C preprocessor to) 56.69 289.64 P
+(use on the file \050-Db=block for example\051.) 56.69 278.64 T
+0 12 Q
+(2.12 Gamma Correction \050parameter \336le\051) 56.69 251.31 T
+0 10 Q
+-0.13 (If your movies are too light or too dark for your play-) 85.04 224.64 P
+(back system, you can pre-gamma correct them.) 56.69 213.64 T
+(Usage:) 85.04 200.64 T
+2 F
+(GAMMA gamma-val) 85.04 174.64 T
+0 F
+1.5 (gamma-corrects by raising each luminance fraction) 85.04 161.64 P
+(to the power) 56.69 150.64 T
+2 F
+(gamma-val) 109.15 150.64 T
+0 F
+(\050a float\051) 169.12 150.64 T
+0.18 (This works by converting the luminance \050brightness\051) 85.04 137.64 P
+-0.17 (of the input image to a fraction zero to one, and then raises it) 56.69 126.64 P
+-0.17 (to the power) 56.69 115.64 P
+2 F
+-0.4 (gamma-val) 108.65 115.64 P
+0 F
+-0.17 (. Thus values less than 1 brighten,) 162.62 115.64 P
+2.36 (and greater than 1 dim. If your output device has good) 56.69 104.64 P
+0.92 (brightness controls, it is better to control brightness at that) 56.69 93.64 P
+(end.) 56.69 82.64 T
+314.36 54.99 552.76 735.31 R
+7 X
+V
+0 12 Q
+0 X
+(2.13 Encoding GOPs at a T) 314.36 727.31 T
+(ime \050command line\051) 445.86 727.31 T
+0 10 Q
+2.65 (Instead of encoding an entire sequence, you can) 342.71 700.64 P
+1.57 (encode a single GOP. GOPs can later be joined together) 314.36 689.64 P
+(with the encoder to form an MPEG file.) 314.36 678.64 T
+(Usage:) 342.71 665.64 T
+2 F
+(-gop num) 342.71 652.64 T
+0 F
+1.81 (This only encodes the numbered GOP \050which are) 342.71 639.64 P
+(numbered beginning at 0.) 314.36 628.64 T
+1.2 (The output file will be the normal output filename) 342.71 615.64 P
+(with the suffix \322.gop.<gop_num>\323) 314.36 604.64 T
+1.18 (GOP files can be joined at any time using the fol-) 342.71 578.64 P
+(lowing command-line argument.) 314.36 567.64 T
+(Usage:) 342.71 554.64 T
+2 F
+(-combine_gops) 342.71 541.64 T
+0 F
+2.05 (This causes the encoder to simply combine some) 342.71 528.64 P
+0.52 (GOP files into a single MPEG stream. A sequence header/) 314.36 517.64 P
+0.03 (ender are inserted. In this case, the parameter file need only) 314.36 506.64 P
+0.18 (contain the YUV_SIZE value, an output file, and perhaps a) 314.36 495.64 P
+0.21 (list of input GOP files. If no list of input GOP files is used,) 314.36 484.64 P
+0.45 (then the encoder assumes you\325re using the same parameter) 314.36 473.64 P
+-0.08 (file you used with the) 314.36 462.64 P
+2 F
+-0.19 (-gop) 403.08 462.64 P
+0 F
+-0.08 (option, and calculates the cor-) 432.88 462.64 P
+0.52 (responding gop filenames itself. If this is not the case, you) 314.36 451.64 P
+0.58 (can specify input GOP files in the same manner as normal) 314.36 440.64 P
+0.44 (input files -- except instead of using INPUT_DIR, INPUT,) 314.36 429.64 P
+1.79 (and END_INPUT, use GOP_INPUT_DIR, GOP_INPUT,) 314.36 418.64 P
+1.38 (and GOP_END_INPUT. If no input GOP files are speci-) 314.36 407.64 P
+-0.05 (fied, then the default is to use the output file name with suf-) 314.36 396.64 P
+(fix \322.gop.<gop_num>\323 starting from 0 as the input files.) 314.36 385.64 T
+4.1 (Thus, to summarize, unless you\325re mixing and) 342.71 372.64 P
+0.2 (matching GOP files from different sources, you can simply) 314.36 361.64 P
+1.37 (use the same parameter file for the) 314.36 350.64 P
+2 F
+3.28 (-gop) 464.63 350.64 P
+0 F
+1.37 ( and) 488.62 350.64 P
+2 F
+3.28 (-combi-) 510.78 350.64 P
+(ne_gops) 314.36 339.64 T
+0 F
+( options.) 356.34 339.64 T
+0 12 Q
+(2.14 Encoding Frames at a T) 314.36 299.31 T
+(ime \050command line\051) 452.51 299.31 T
+0 10 Q
+2.65 (Instead of encoding an entire sequence, you can) 342.71 273.64 P
+0.34 (encode individual frames. These frames can later be joined) 314.36 262.64 P
+(together to form an MPEG file.) 314.36 251.64 T
+(Usage:) 342.71 238.64 T
+(-frames first_frame last_frame) 342.71 225.64 T
+2.37 (This causes the encoder to encode the numbered) 342.71 212.64 P
+(frames in the given range, inclusive.) 314.36 201.64 T
+0.89 (The output will be placed in separate files, one per) 342.71 188.64 P
+0.21 (frame, with the filenames being the normal output file with) 314.36 177.64 P
+(the suffix \322.frame.<frame num>\323) 314.36 166.64 T
+(The frame files can later be combined as follows:) 342.71 140.64 T
+(Usage:) 342.71 127.64 T
+(-combine_frames) 342.71 114.64 T
+2.05 (This causes the encoder to simply combine some) 342.71 101.64 P
+2.21 (frames into a single MPEG stream. Sequence and GOP) 314.36 90.64 P
+1.11 (headers are inserted appropriately. You can either use the) 314.36 79.64 P
+1.39 (same parameter file for -frames and -combine_frames, or) 314.36 68.64 P
+FMENDPAGE
+%%EndPage: "6" 5
+%%Page: "5" 5
+612 792 0 FMBEGINPAGE
+57.97 26.65 554.03 40.82 R
+7 X
+0 K
+V
+0 10 Q
+0 X
+(5) 303.5 34.15 T
+72 72 297 732.47 R
+7 X
+V
+2 F
+0 X
+(sflowg.07.yuv) 100.35 725.81 T
+(sflowg.08.yuv) 100.35 712.81 T
+(sflowg.09.yuv) 100.35 699.81 T
+(sflowg.10.yuv) 100.35 686.81 T
+0 F
+1.37 (If there is no star, then the file name is simple) 100.35 660.81 P
+0.99 (repeated the appropriate number of times \050[1-10] is 10) 72 649.81 P
+(times\051.) 72 638.81 T
+-0.18 (Commands can be used to dynamically create the) 100.35 625.81 P
+(list of files, for example:) 72 614.81 T
+2 F
+(INPUT) 100.35 588.81 T
+(\324ls July-*.ppm\324) 100.35 575.81 T
+(\324cat file-list\324) 100.35 562.81 T
+(END_INPUT) 100.35 549.81 T
+0 F
+1.41 (The command\050s\051 will be executed in the direc-) 100.35 523.81 P
+0.44 (tory named by INPUT_DIR if it appears before INPUT) 72 512.81 P
+2.09 (in the parameter file. Note that the encoder-provided) 72 501.81 P
+(filling in of *\325s is not supported in this mode.) 72 490.81 T
+0.36 (The encoder allows you to use other file formats) 100.35 477.81 P
+1.61 (by providing an input conversion specifier. You must) 72 466.81 P
+0.18 (describe how to convert the input format into one of the) 72 455.81 P
+(base file types.) 72 444.81 T
+2 F
+(Usage:) 100.35 431.81 T
+(INPUT_CONVERT conversion) 100.35 405.81 T
+3.25 (conversion) 100.35 379.81 P
+0 F
+1.35 ( must be a multi-star expression.) 160.31 379.81 P
+-0.16 (If) 72 368.81 P
+2 F
+-0.37 (conversion) 81 368.81 P
+0 F
+-0.16 ( is simply \324*\325, then no conversion takes) 140.97 368.81 P
+0.92 (place. Otherwise, each of the file lines are replaced by) 72 357.81 P
+0.3 (the conversion line with the file name wherever there is) 72 346.81 P
+0.88 (a \324*\325. The conversion line must send the output to std-) 72 335.81 P
+-0.12 (out. For example, suppose we have a bunch of GIF files.) 72 324.81 P
+(Then we would do:) 72 313.81 T
+2 F
+(BASE_FILE_FORMAT) 100.35 300.81 T
+( PPM) 196.29 300.81 T
+(INPUT) 100.35 287.81 T
+(pictures.*.gif [0-10]) 100.35 274.81 T
+(END_INPUT) 100.35 261.81 T
+(INPUT_CONVERT giftoppm *) 100.35 248.81 T
+0 F
+0.9 (Another example: Suppose we have separate Y,) 100.35 222.81 P
+1.18 (U, and V files \050where the U and V have already been) 72 211.81 P
+(subsampled\051. Then we might have:) 72 200.81 T
+2 F
+(BASE_FILE_FORMAT) 100.35 187.81 T
+( YUV) 196.29 187.81 T
+(INPUT) 100.35 174.81 T
+(pictures.* [0-10]) 100.35 161.81 T
+(END_INPUT) 100.35 148.81 T
+(INPUT_CONVERT cat *.Y *.U *.V) 100.35 135.81 T
+(YUV_FORMAT UCB) 100.35 122.81 T
+0 F
+0.68 (As you can see, the \322files\323 between) 100.35 109.81 P
+2 F
+1.63 (INPUT) 249.41 109.81 P
+0 F
+0.68 ( and) 279.39 109.81 P
+2 F
+2.41 (END_INPUT) 72 98.81 P
+0 F
+1 ( don\325t have to be files at all! This can be) 125.97 98.81 P
+(very useful.) 72 87.81 T
+315 72 540 732.47 R
+7 X
+V
+0 X
+(To read data from standard input, set:) 343.35 712.81 T
+2 F
+(INPUT_DIR stdin) 343.35 699.81 T
+0 F
+1.05 (Note that you cannot use the stdin option when) 343.35 686.81 P
+0.07 (coding in parallel. \050Use GOPINPUTDIR or FRAMEIN-) 315 675.81 P
+(PUTDIR if combining frames/GOPs.\051) 315 664.81 T
+(The output file is specified by:) 343.35 638.81 T
+2 F
+(OUTPUT filename) 343.35 625.81 T
+0 F
+(for example:) 343.35 612.81 T
+2 F
+(OUTPUT /u/keving/mpg/flowers.mpg) 343.35 599.81 T
+0 12 Q
+(2.8 Original or Decoded \050parameter \336le\051) 315 559.47 T
+0 10 Q
+0.09 (The encoder can use either the original frames as) 343.35 532.81 P
+3 (reference frames, or the decoded frames. Using the) 315 521.81 P
+2.48 (decoded frames gives better playback quality, but is) 315 510.81 P
+1.93 (slower and seems to give worse compression. It also) 315 499.81 P
+0.63 (causes some complications with parallel encoding. \050see) 315 488.81 P
+0.95 (the section on parallel encoding\051 One recommendation) 315 477.81 P
+0.52 (is to use original, and lower the q-scale if the quality is) 315 466.81 P
+(not good enough. Table six shows the trade-offs.) 315 455.81 T
+(Usage:) 343.35 429.81 T
+2 F
+(REFERENCE_FRAME ORIGINAL) 343.35 403.81 T
+0 12 Q
+(2.9 Bit-rate Control \050parameter \336le\051) 315 272.47 T
+0 10 Q
+1.53 (The default encoding uses variable bit rate. To) 343.35 245.81 P
+0.33 (limit the bit rate, the MPEG-2 Standard\325s algorithm has) 315 234.81 P
+2.39 (been implemented \050suitably adjusted\051. There are two) 315 223.81 P
+(parameters which must be set to use bit-rate control:) 315 212.81 T
+2 F
+(BUFFER_SIZE N \050in bits\051) 343.35 199.81 T
+(BIT_RATE M \050in bytes/sec\051) 343.35 186.81 T
+0 F
+-0.09 (N sets the largest required buffer, M specifies the) 343.35 173.81 P
+1 (continual rate. N is set in number of bits, the buffer is) 315 162.81 P
+(actually in 16bit ints.) 315 151.81 T
+0 12 Q
+(2.10 Userdata \050parameter \336le\051) 315 124.47 T
+0 10 Q
+0.01 (An identification string is added by default to the) 343.35 97.81 P
+2.96 (Sequence layer user-data field. It is \322UCB Encoder) 315 86.81 P
+1.41 (Vers\323 \050where Vers is replaced by the encoder version) 315 75.81 P
+1 12 Q
+-0.15 (T) 315 380.47 P
+-0.15 (able 6: Original or Decoded? \050Normalized\051) 321.9 380.47 P
+0 10 Q
+(Reference) 323.62 352.81 T
+(Compress) 373.49 358.81 T
+(ion) 387.1 346.81 T
+(Speed) 429.46 352.81 T
+(Quality) 486.21 358.81 T
+(I/P/B) 490.65 346.81 T
+(Decoded) 329.87 328.81 T
+(1000) 383.49 328.81 T
+(1000) 431.68 328.81 T
+(1000/969/919) 473.44 328.81 T
+(Original) 332.08 312.81 T
+(885) 385.99 312.81 T
+(1373) 431.68 312.81 T
+(1000/912/884) 473.44 312.81 T
+318.37 370.22 318.37 306.72 2 L
+V
+0.5 H
+0 Z
+N
+369.39 370.72 369.39 306.22 2 L
+V
+N
+417.58 370.72 417.58 306.22 2 L
+V
+N
+465.77 370.72 465.77 306.22 2 L
+V
+N
+536.63 370.22 536.63 306.72 2 L
+V
+N
+318.12 370.47 536.88 370.47 2 L
+V
+N
+318.62 339.72 536.38 339.72 2 L
+V
+N
+318.62 337.22 536.38 337.22 2 L
+V
+N
+318.12 322.47 536.88 322.47 2 L
+V
+N
+318.12 306.47 536.88 306.47 2 L
+V
+N
+FMENDPAGE
+%%EndPage: "5" 4
+%%Page: "4" 4
+612 792 0 FMBEGINPAGE
+57.97 26.65 554.03 40.82 R
+7 X
+0 K
+V
+0 10 Q
+0 X
+(4) 303.5 34.15 T
+56.69 54.99 297.64 735.31 R
+7 X
+V
+0 X
+(A standard sequence is IBBPBBPBBPBBPB) 85.04 715.64 T
+(Usage:) 85.04 702.64 T
+2 F
+(PATTERN) 85.04 676.64 T
+( <IPB pattern>) 127.02 676.64 T
+0 F
+1.84 (Note that if the last frame in an encoding is a B-) 85.04 650.64 P
+0.07 (frame, it will not be encoded \050since it has no future frame to) 56.69 639.64 P
+1.81 (reference from\051. Pre-I patters like BBIBBP are legal, but) 56.69 628.64 P
+0 (seem to have bugs, so watch out! To insure that every frame) 56.69 617.64 P
+0.63 (is encoded, the encoder can force the last frame to be an I-) 56.69 606.64 P
+(frame.) 56.69 595.64 T
+(Usage:) 85.04 582.64 T
+2 F
+(FORCE_ENCODE_LAST_FRAME) 85.04 556.64 T
+0 12 Q
+(2.7 Specifying Input Files \050parameter \336le\051) 56.69 516.31 T
+0 10 Q
+0.03 (The encoder can accept five base types of input files:) 85.04 489.64 P
+0.08 (PPM, PNM, JMOVIE, JPEG, and YUV. Note that PPM is a) 56.69 478.64 P
+1.38 (subset of PNM; the PPM option is available because it is) 56.69 467.64 P
+0.49 (faster to read if the files are known to be PPM. JMOVIE is) 56.69 456.64 P
+0.19 (the format created by the Parallax video grabber. JPEGs are) 56.69 445.64 P
+-0.06 (a standard image format. YUV formats are described below.) 56.69 434.64 P
+0.98 (If you use YUV format, you must specify the pixel) 85.04 421.64 P
+0.61 (size of the image in the parameter file and the YUV_FOR-) 56.69 410.64 P
+(MAT.) 56.69 399.64 T
+(Usage:) 85.04 386.64 T
+2 F
+(BASE_FILE_FORMAT format) 85.04 360.64 T
+(YUV_SIZE widthxheight) 85.04 347.64 T
+(YUV_FORMAT yuv_format) 85.04 334.64 T
+0.1 (format) 85.04 308.64 P
+0 F
+0.04 ( is one of {) 121.02 308.64 P
+2 F
+0.1 (YUV, PPM, PNM, JMOVIE,) 165.4 308.64 P
+(JPEG) 56.69 297.64 T
+0 F
+(}) 80.68 297.64 T
+2 F
+(width) 85.04 284.64 T
+0 F
+( and) 115.02 284.64 T
+2 F
+(height) 134.45 284.64 T
+0 F
+( are integers \050like 320x240\051) 170.43 284.64 T
+2 F
+5.81 (yuv_format) 85.04 271.64 P
+0 F
+2.42 (is one of) 156.81 271.64 P
+2 F
+5.81 ( {ABEKAS, EYUV,) 196.07 271.64 P
+1.66 (PHILLIPS, UCB, {SPECIAL}},) 56.69 260.64 P
+0 F
+0.69 (where) 223.59 260.64 P
+2 F
+1.66 ( SPECIAL) 248 260.64 P
+0 F
+1.83 (is a specification of the pattern of Y, U, and V, such as) 56.69 249.64 P
+2 F
+-0.57 (UYVY) 56.69 238.64 P
+0 F
+-0.24 (for) 86.1 238.64 P
+2 F
+-0.57 ( ABEKAS. The pattern can be of any) 97.76 238.64 P
+1.18 (length, or order, but must consist only) 56.69 227.64 P
+0.15 (of Ys, Us, andVs, and must represent two) 56.69 216.64 P
+3.18 (pixels of data \050thus YUVYUV for 4:4:4) 56.69 205.64 P
+(source\051.) 56.69 194.64 T
+0 F
+1.73 (You must specify the directory in which the input) 85.04 168.64 P
+-0.12 (files are located. You can use \324.\325 to specify the current direc-) 56.69 157.64 P
+(tory.) 56.69 146.64 T
+(Usage:) 85.04 133.64 T
+(INPUT_DIR directory) 85.04 107.64 T
+1.08 (You must also specify the names of the files them-) 85.04 81.64 P
+1.11 (selves. You list them sequentially, one per line, in display) 56.69 70.64 P
+2.12 (order. There are shortcuts, however, which allow you to) 56.69 59.64 P
+314.36 54.99 552.76 735.31 R
+7 X
+V
+0 X
+(condense many files into one line.) 314.36 728.64 T
+(Usage:) 342.71 715.64 T
+2 F
+(INPUT) 342.71 689.64 T
+(file) 342.71 676.64 T
+2 8 Q
+(1) 366.7 674.14 T
+2 10 Q
+(file) 342.71 663.64 T
+2 8 Q
+(2) 366.7 661.14 T
+2 10 Q
+(...) 342.71 650.64 T
+(file) 342.71 637.64 T
+2 8 Q
+(n) 366.7 635.14 T
+2 10 Q
+(END_INPUT) 342.71 624.64 T
+8.17 (file) 342.71 598.64 P
+2 8 Q
+6.53 (i) 366.7 596.14 P
+0 10 Q
+3.4 ( can be either a file name, a single-star) 371.49 598.64 P
+0.28 (expression followed by a bracketed expansion for star, or a) 314.36 587.64 P
+0.28 (command to be executed. There are two types of bracketed) 314.36 576.64 P
+(expansions. For example:) 314.36 565.64 T
+2 F
+(sflowg.*.yuv [0-10]) 342.71 539.64 T
+0 F
+(is expanded to:) 342.71 513.64 T
+2 F
+(sflowg.0.yuv) 342.71 487.64 T
+(sflowg.1.yuv) 342.71 474.64 T
+(sflowg.2.yuv) 342.71 461.64 T
+(sflowg.3.yuv) 342.71 448.64 T
+(sflowg.4.yuv) 342.71 435.64 T
+(sflowg.5.yuv) 342.71 422.64 T
+(sflowg.6.yuv) 342.71 409.64 T
+(sflowg.7.yuv) 342.71 396.64 T
+(sflowg.8.yuv) 342.71 383.64 T
+(sflowg.9.yuv) 342.71 370.64 T
+(sflowg.10.yuv) 342.71 357.64 T
+(sflowg.*.yuv [0-10+3]) 342.71 331.64 T
+0 F
+(is expanded to:) 342.71 305.64 T
+2 F
+(sflowg.0.yuv) 342.71 279.64 T
+(sflowg.3.yuv) 342.71 266.64 T
+(sflowg.6.yuv) 342.71 253.64 T
+(sflowg.9.yuv) 342.71 240.64 T
+0 F
+(Also, the encoder will pad with 0\325s if necessary:) 342.71 214.64 T
+2 F
+(sflowg.*.yuv [00-10]) 342.71 188.64 T
+0 F
+(is expanded to:) 342.71 162.64 T
+2 F
+(sflowg.00.yuv) 342.71 136.64 T
+(sflowg.01.yuv) 342.71 123.64 T
+(sflowg.02.yuv) 342.71 110.64 T
+(sflowg.03.yuv) 342.71 97.64 T
+(sflowg.04.yuv) 342.71 84.64 T
+(sflowg.05.yuv) 342.71 71.64 T
+(sflowg.06.yuv) 342.71 58.64 T
+FMENDPAGE
+%%EndPage: "4" 3
+%%Page: "3" 3
+612 792 0 FMBEGINPAGE
+57.97 26.65 554.03 40.82 R
+7 X
+0 K
+V
+0 10 Q
+0 X
+(3) 303.5 34.15 T
+56.69 54.99 297.64 735.31 R
+7 X
+V
+0 X
+1.31 (For some reason Simple seems to give better com-) 85.04 616.64 P
+(pression, but it depends on the image sequence.) 56.69 605.64 T
+(Usage:) 85.04 579.64 T
+2 F
+(PSEARCH_ALG ptechnique) 85.04 553.64 T
+(BSEARCH_ALG btechnique) 85.04 540.64 T
+0 F
+0.87 (where) 85.04 514.64 P
+2 F
+2.08 (ptechnique) 112.82 514.64 P
+0 F
+0.87 (is one of {LOGARITHMIC,) 180.87 514.64 P
+(SUBSAMPLE, TWOLEVEL, EXHAUSTIVE}) 56.69 503.64 T
+3.14 (where) 85.04 490.64 P
+2 F
+7.54 (btechnique) 115.1 490.64 P
+0 F
+3.14 ( is one of {EXHAUSTIVE,) 175.07 490.64 P
+(CROSS2, SIMPLE}) 56.69 479.64 T
+0 12 Q
+(2.3 GOP \050parameter \336le\051) 56.69 439.31 T
+0 10 Q
+1.94 (A Group of Pictures \050GOP\051 is a roughly indepen-) 85.04 412.64 P
+3.02 (dently decodable sequence of frames. An MPEG video) 56.69 401.64 P
+0 (stream is made of one or more GOPs. You may specify how) 56.69 390.64 P
+0.8 (many frames each GOP should be. A GOP must start with) 56.69 379.64 P
+0.2 (an I-frame, and the encoder will enforce that by taking your) 56.69 368.64 P
+(number as the) 56.69 357.64 T
+3 F
+(minimum) 115.26 357.64 T
+0 F
+( number of frames in a GOP.) 152.46 357.64 T
+(Usage:) 85.04 331.64 T
+2 F
+(GOP_SIZE) 85.04 305.64 T
+( num) 133.01 305.64 T
+0 F
+(where) 85.04 292.64 T
+2 F
+(num) 111.96 292.64 T
+0 F
+( = the number of frames in a GOP) 129.95 292.64 T
+0 12 Q
+(2.4 Slice \050parameter \336le\051) 56.69 252.31 T
+0 10 Q
+-0.25 (A slice is an independently decodable unit in a frame.) 85.04 226.64 P
+0.54 (It can be as small as one macroblock, or it can be as big as) 56.69 215.64 P
+1.47 (the entire frame. Barring transmission error, adding slices) 56.69 204.64 P
+0.55 (does not change quality or speed; the only effect is slightly) 56.69 193.64 P
+-0.1 (worse compression. More slices are used for noisy transmis-) 56.69 182.64 P
+2.81 (sion so that errors are more recoverable. Because most) 56.69 171.64 P
+0.28 (transmission systems have more sophisticated error correct-) 56.69 160.64 P
+(ing routines, we usually just use one slice per frame.) 56.69 149.64 T
+(Usage:) 85.04 123.64 T
+2 F
+(SLICES_PER_FRAME) 85.04 97.64 T
+( num) 180.99 97.64 T
+0 F
+(where) 85.04 84.64 T
+2 F
+(num) 111.96 84.64 T
+0 F
+( is the number of slices in a frame) 129.95 84.64 T
+2.31 (Note: Some MPEG playback systems require that) 85.04 58.64 P
+1 12 Q
+(T) 76.29 727.31 T
+(able 4: B-frame Motion V) 83.18 727.31 T
+(ector Sear) 213.99 727.31 T
+(ch) 266.05 727.31 T
+(\050Normalized\051) 143.19 713.31 T
+0 10 Q
+(T) 84.14 691.64 T
+(echnique) 89.54 691.64 T
+(Compression) 139.45 691.64 T
+(Speed) 204.64 691.64 T
+(Quality) 242.96 691.64 T
+(Exhaustive) 86.23 673.64 T
+(1000) 155.83 673.64 T
+(?) 214.63 673.64 T
+(1000) 247.96 673.64 T
+(Cross2) 102.88 657.64 T
+(975) 158.33 657.64 T
+(1000) 206.86 657.64 T
+(996) 250.46 657.64 T
+(Simple) 102.32 641.64 T
+(938) 158.33 641.64 T
+(1765) 206.86 641.64 T
+(991) 250.46 641.64 T
+75.12 703.06 75.12 635.56 2 L
+V
+0.5 H
+0 Z
+N
+134.65 703.56 134.65 635.06 2 L
+V
+N
+197.01 703.56 197.01 635.06 2 L
+V
+N
+236.69 703.56 236.69 635.06 2 L
+V
+N
+279.21 703.06 279.21 635.56 2 L
+V
+N
+74.87 703.31 279.46 703.31 2 L
+V
+N
+75.37 684.56 278.96 684.56 2 L
+V
+N
+75.37 682.06 278.96 682.06 2 L
+V
+N
+74.87 667.31 279.46 667.31 2 L
+V
+N
+74.87 651.31 279.46 651.31 2 L
+V
+N
+74.87 635.31 279.46 635.31 2 L
+V
+N
+314.36 54.99 552.76 735.31 R
+7 X
+V
+0 X
+1.26 (each slice must consist of whole rows of macroblocks. If) 314.36 728.64 P
+0.55 (this is the case, then if the height of the image is H pixels,) 314.36 717.64 P
+1.97 (then you should set the SLICES_PER_FRAME to some) 314.36 706.64 P
+0.32 (number which divides H/16. For example, if H = 240, then) 314.36 695.64 P
+0.82 (you should only use SLICES_PER_FRAME values of 15,) 314.36 684.64 P
+(5, 3, or 1.) 314.36 673.64 T
+0.3 (Note to the note: these MPEG playback systems are) 342.71 660.64 P
+1.07 (really at fault, since the MPEG standard says this doesn\325t) 314.36 649.64 P
+(have to be so.) 314.36 638.64 T
+0 12 Q
+(2.5 Search W) 314.36 611.31 T
+(indow \050parameter \336le\051) 378.83 611.31 T
+0 10 Q
+0.65 (The search window is the window in which motion) 342.71 585.64 P
+0.47 (vectors are searched for. The window is a square. You can) 314.36 574.64 P
+1.22 (specify the size of the square, and whether to allow half-) 314.36 563.64 P
+(pixel motion vectors or not.) 314.36 552.64 T
+(Usage:) 342.71 526.64 T
+2 F
+(PIXEL) 342.71 500.64 T
+( <FULL or HALF>) 372.69 500.64 T
+(RANGE num [numB]) 342.71 487.64 T
+-0.54 (HALF) 342.71 461.64 P
+0 F
+-0.22 ( means that half-pixel vectors are allowed. The) 366.7 461.64 P
+0.19 (search window is +/-) 314.36 450.64 P
+2 F
+0.47 (num) 401.27 450.64 P
+0 F
+0.19 ( pixels in the X and Y directions.) 419.26 450.64 P
+-0.02 (It is usually important that you use) 314.36 439.64 P
+2 F
+-0.05 (HALF) 455.54 439.64 P
+0 F
+-0.02 (, because it results) 479.53 439.64 P
+2.12 (in both better quality and better compression. It is only) 314.36 428.64 P
+(undesirable for computer-generated images.) 314.36 417.64 T
+2 F
+-0.25 (num) 342.71 404.64 P
+0 F
+-0.1 ( should probably be set to at least 8 or 10 pixels.) 360.7 404.64 P
+2.35 (This number depends on the image. Using much larger) 314.36 393.64 P
+0.68 (numbers such as 20 or 30 doesn\325t seem to help much, and) 314.36 382.64 P
+0.02 (increases the CPU cost drastically. The optional numB is in) 314.36 371.64 P
+2.67 (case you wish to specify different ranges for predicted) 314.36 360.64 P
+3.37 (frames \050P-frames, num\051, and Bi-directional frames \050B-) 314.36 349.64 P
+0.31 (frames, numB\051. B-frame limits are optional as indicated by) 314.36 338.64 P
+-0 (the braces above \050so \322RANGE 10 6\323 is a valid command as) 314.36 327.64 P
+(is \322RANGE 9\323\051.) 314.36 316.64 T
+0 12 Q
+(2.6 IPB Pattern \050parameter \336le\051) 314.36 276.31 T
+0 10 Q
+2.24 (You can set the sequence of I, P, and B-frames.) 342.71 249.64 P
+0.45 (Later versions will allow you to do more than set a repeat-) 314.36 238.64 P
+2.49 (ing IPB pattern. The pattern affects speed, quality, and) 314.36 227.64 P
+(compression. Table five shows some of the trade-offs.) 314.36 216.64 T
+(\050this is given a certain Q-scale\051) 342.71 59.64 T
+1 12 Q
+(T) 337.17 193.31 T
+(able 5: Comparison of I/P/B-Frames) 344.06 193.31 T
+(\050Normalized\051) 399.59 179.31 T
+0 F
+(Frame) 331.84 156.31 T
+(T) 335.26 142.31 T
+(ype) 341.74 142.31 T
+(Compress) 384.37 156.31 T
+(ion) 400.7 142.31 T
+(Speed) 451.3 149.31 T
+(Quality) 505.57 149.31 T
+(I-frames) 334.94 122.31 T
+(1000) 396.36 122.31 T
+(1000) 453.96 122.31 T
+(1000) 511.57 122.31 T
+(P-frames) 332.26 104.31 T
+(409) 399.36 104.31 T
+(601) 456.96 104.31 T
+(969) 514.56 104.31 T
+(B-frames) 330.93 86.31 T
+(72) 402.36 86.31 T
+(260) 456.96 86.31 T
+(919) 514.56 86.31 T
+314.76 169.06 314.76 79.56 2 L
+V
+N
+379.56 169.56 379.56 79.06 2 L
+V
+N
+437.16 169.56 437.16 79.06 2 L
+V
+N
+494.76 169.56 494.76 79.06 2 L
+V
+N
+552.36 169.06 552.36 79.56 2 L
+V
+N
+314.51 169.31 552.61 169.31 2 L
+V
+N
+315.01 134.56 552.11 134.56 2 L
+V
+N
+315.01 132.06 552.11 132.06 2 L
+V
+N
+314.51 115.31 552.61 115.31 2 L
+V
+N
+314.51 97.31 552.61 97.31 2 L
+V
+N
+314.51 79.31 552.61 79.31 2 L
+V
+N
+FMENDPAGE
+%%EndPage: "3" 2
+%%Page: "2" 2
+612 792 0 FMBEGINPAGE
+57.97 26.65 554.03 40.82 R
+7 X
+0 K
+V
+0 10 Q
+0 X
+(2) 303.5 34.15 T
+72 72 297 720 R
+7 X
+V
+0 X
+2.84 (Here is a description of the different command-line) 72 700.33 P
+0.03 (options available and parameter-file options available in) 72 689.33 P
+2.37 (sequential \050one-machine\051 encoding. You should defi-) 72 678.33 P
+3.43 (nitely read sections 2.1-2.9. The other sections are) 72 667.33 P
+(optional.) 72 656.33 T
+0.21 (In the following, whenever a space in the parameter file) 72 630.33 P
+4.29 (appears, it can be represented by any amount of) 72 619.33 P
+(whitespace \050tabs or spaces\051.) 72 608.33 T
+0 12 Q
+(2.1 Q-Scale \050parameter \336le\051) 72 581 T
+0 10 Q
+1.78 (The quantization scale values \050Q-Scale\051 give a) 100.35 554.33 P
+1.37 (trade-off between quality and compression. Using dif-) 72 543.33 P
+-0.16 (ferent Q-Scale values has very little effect on speed. The) 72 532.33 P
+1.74 (Q-Scale values can be set separately for I, P, and B-) 72 521.33 P
+(frames.) 72 510.33 T
+(Usage:) 100.35 484.33 T
+2 F
+(IQ-Scale) 126.21 471.33 T
+( num) 174.18 471.33 T
+(PQ-Scale num) 125.5 458.33 T
+(BQ-Scale num) 126.21 445.33 T
+0 F
+(num in all three cases is a number from 1 to 31.) 100.35 432.33 T
+3.47 (Larger numbers give better compression, but) 100.35 406.33 P
+0.3 (worse quality. In the following, the quality numbers are) 72 395.33 P
+(peak signal-to-noise ratio, defined as:) 72 384.33 T
+(where MSE is the mean squared error.) 100.35 332.18 T
+0.12 (Tables one and two show the Q-scale vs. Quality) 100.35 306.18 P
+(relationship for the flower-garden sequence.) 72 295.18 T
+1.84 (Note that when rate-control \050Section 2.9\051 is in) 100.35 282.18 P
+0.19 (use, the rate control mechanism will change the Q-scale) 72 271.18 P
+1.37 (throughout the blocks of the frame, so these specified) 72 260.18 P
+(values are merely starting points.) 72 249.18 T
+1 12 Q
+(T) 95.77 212.85 T
+(able 1: Q-Scale vs. Quality \050SNR\051) 102.66 212.85 T
+0 10 Q
+(Q-Scale) 91.87 191.18 T
+(I-Frames) 140.95 191.18 T
+(P-Frames) 190.86 191.18 T
+(B-Frames) 241.33 191.18 T
+(1) 124.48 173.18 T
+(43.2) 150.24 173.18 T
+(46.3) 201.27 173.18 T
+(46.5) 252.29 173.18 T
+(6) 124.48 157.18 T
+(32.6) 150.24 157.18 T
+(34.6) 201.27 157.18 T
+(34.3) 252.29 157.18 T
+(1) 119.85 141.18 T
+(1) 124.48 141.18 T
+(28.6) 150.24 141.18 T
+(29.5) 201.27 141.18 T
+(30.0) 252.29 141.18 T
+(16) 119.48 125.18 T
+(26.3) 150.24 125.18 T
+(26.8) 201.27 125.18 T
+(28.6) 252.29 125.18 T
+(21) 119.48 109.18 T
+(24.7) 150.24 109.18 T
+(25.0) 201.27 109.18 T
+(27.9) 252.29 109.18 T
+(26) 119.48 93.18 T
+(23.5) 150.24 93.18 T
+(23.9) 201.27 93.18 T
+(27.5) 252.29 93.18 T
+82.45 202.6 82.45 87.1 2 L
+V
+0.5 H
+0 Z
+N
+133.48 203.1 133.48 86.6 2 L
+V
+N
+184.5 203.1 184.5 86.6 2 L
+V
+N
+235.52 203.1 235.52 86.6 2 L
+V
+N
+286.55 202.6 286.55 87.1 2 L
+V
+N
+82.2 202.85 286.8 202.85 2 L
+V
+N
+82.7 184.1 286.3 184.1 2 L
+V
+N
+82.7 181.6 286.3 181.6 2 L
+V
+N
+82.2 166.85 286.8 166.85 2 L
+V
+N
+82.2 150.85 286.8 150.85 2 L
+V
+N
+82.2 134.85 286.8 134.85 2 L
+V
+N
+82.2 118.85 286.8 118.85 2 L
+V
+N
+82.2 102.85 286.8 102.85 2 L
+V
+N
+82.2 86.85 286.8 86.85 2 L
+V
+N
+72 72 297 720 C
+72 341.85 297 381 C
+0 12 Q
+0 X
+0 K
+(2) 148.86 360.39 T
+(0) 154.85 360.39 T
+3 F
+(l) 161.56 360.39 T
+(o) 165.6 360.39 T
+(g) 172.3 360.39 T
+0 9 Q
+(1) 178.76 356.63 T
+(0) 183.25 356.63 T
+0 12 Q
+(2) 196.32 367.58 T
+(5) 202.32 367.58 T
+(5) 208.31 367.58 T
+3 F
+(M) 196.45 349.78 T
+(S) 207.15 349.78 T
+(E) 213.85 349.78 T
+221.18 360.98 196.45 360.98 2 L
+0.33 H
+0 Z
+N
+196.45 360.98 193.45 347.78 2 L
+N
+193.45 347.78 191.45 351.58 2 L
+N
+191.45 351.58 190.45 349.68 2 L
+N
+189.45 362.98 220.93 362.98 2 L
+N
+72 72 297 720 C
+0 0 612 792 C
+315 72 540 720 R
+7 X
+0 K
+V
+0 12 Q
+0 X
+(2.2 Search T) 315 471 T
+(echniques \050parameter \336le\051) 375.11 471 T
+0 10 Q
+0.77 (There are several different motion vector search) 343.35 445.33 P
+2.44 (techniques available for both P-frame search and B-) 315 434.33 P
+0.54 (frame search. Using different search techniques present) 315 423.33 P
+-0.04 (little difference in quality, but a large difference in com-) 315 412.33 P
+(pression and speed.) 315 401.33 T
+0.26 (There are 4 types of P-frame search: Exhaustive,) 343.35 388.33 P
+(TwoLevel, SubSample, and Logarithmic.) 315 377.33 T
+0.1 (There are 3 types of B-frame search: Exhaustive,) 343.35 364.33 P
+(Cross2, and Simple.) 315 353.33 T
+1.53 (The suggested search techniques are TwoLevel) 343.35 340.33 P
+2.17 (and Logarithmic for P-frame search, and Cross2 and) 315 329.33 P
+0.68 (Simple for B-frame search. Tables three and four com-) 315 318.33 P
+(pare the different search methods:) 315 307.33 T
+318.37 170 536.63 176 C
+0 0 612 792 C
+0 10 Q
+0 X
+0 K
+(a. Smaller numbers mean better compression) 336.37 163.33 T
+(b. Larger numbers mean faster execution) 336.37 151.33 T
+(c. Larger numbers mean better quality) 336.37 139.33 T
+(31) 362.48 672.33 T
+(22.6) 393.24 672.33 T
+(23.0) 444.27 672.33 T
+(27.3) 495.29 672.33 T
+1 12 Q
+(T) 342.04 646 T
+(able 2: Q-Scale vs. Compr) 348.94 646 T
+(ession) 482.3 646 T
+0 10 Q
+(Q-Scale) 334.87 624.33 T
+(I-Frames) 383.95 624.33 T
+(P-Frames) 433.86 624.33 T
+(B-Frames) 484.33 624.33 T
+(1) 367.48 606.33 T
+(2:1) 395.6 606.33 T
+(2:1) 446.62 606.33 T
+(2:1) 497.65 606.33 T
+(6) 367.48 590.33 T
+(7) 399.49 590.33 T
+(10) 448.01 590.33 T
+(15) 499.04 590.33 T
+(1) 362.85 574.33 T
+(1) 367.48 574.33 T
+(1) 397.18 574.33 T
+(1) 401.8 574.33 T
+(18) 448.01 574.33 T
+(43) 499.04 574.33 T
+(16) 362.48 558.33 T
+(15) 396.99 558.33 T
+(29) 448.01 558.33 T
+(97) 499.04 558.33 T
+(21) 362.48 542.33 T
+(19) 396.99 542.33 T
+(41) 448.01 542.33 T
+(173) 496.54 542.33 T
+(26) 362.48 526.33 T
+(24) 396.99 526.33 T
+(56) 448.01 526.33 T
+(256) 496.54 526.33 T
+(31) 362.48 510.33 T
+(28) 396.99 510.33 T
+(73) 448.01 510.33 T
+(330) 496.54 510.33 T
+1 12 Q
+(T) 326.96 284 T
+(able 3: P-frame Motion V) 333.86 284 T
+(ector Sear) 463.98 284 T
+(ch) 516.05 284 T
+(\050Normalized\051) 393.53 270 T
+0 10 Q
+(T) 327.39 248.33 T
+(echnique) 332.79 248.33 T
+(Compression) 382.34 248.33 T
+0 8 Q
+(a) 435.09 252.33 T
+0 10 Q
+(Speed) 454.39 248.33 T
+0 8 Q
+(b) 478.82 252.33 T
+0 10 Q
+(Quality) 498.61 248.33 T
+0 8 Q
+(c) 528.59 252.33 T
+0 10 Q
+(Exhaustive) 329.48 230.33 T
+(1000) 400.5 230.33 T
+(1000) 458.61 230.33 T
+(1000) 505.38 230.33 T
+(SubSample) 328.36 214.33 T
+(1008) 400.5 214.33 T
+(2456) 458.61 214.33 T
+(1000) 505.38 214.33 T
+(T) 333.52 198.33 T
+(woLevel) 338.92 198.33 T
+(1009) 400.5 198.33 T
+(3237) 458.61 198.33 T
+(1000) 505.38 198.33 T
+(Logarithmic) 324.48 182.33 T
+(1085) 400.5 182.33 T
+(8229) 458.61 182.33 T
+(998) 507.88 182.33 T
+1 12 Q
+(T) 338.77 712 T
+(able 1: Q-Scale vs. Quality \050SNR\051) 345.66 712 T
+0 10 Q
+(Q-Scale) 334.87 690.33 T
+(I-Frames) 383.95 690.33 T
+(P-Frames) 433.86 690.33 T
+(B-Frames) 484.33 690.33 T
+325.45 701.75 325.45 666.25 2 L
+V
+0.5 H
+0 Z
+N
+376.48 702.25 376.48 665.75 2 L
+V
+N
+427.5 702.25 427.5 665.75 2 L
+V
+N
+478.52 702.25 478.52 665.75 2 L
+V
+N
+529.55 701.75 529.55 666.25 2 L
+V
+N
+325.2 702 529.8 702 2 L
+V
+N
+325.7 683.25 529.3 683.25 2 L
+V
+N
+325.7 680.75 529.3 680.75 2 L
+V
+N
+325.2 666 529.8 666 2 L
+V
+N
+325.45 635.75 325.45 504.25 2 L
+V
+N
+376.48 636.25 376.48 503.75 2 L
+V
+N
+427.5 636.25 427.5 503.75 2 L
+V
+N
+478.52 636.25 478.52 503.75 2 L
+V
+N
+529.55 635.75 529.55 504.25 2 L
+V
+N
+325.2 636 529.8 636 2 L
+V
+N
+325.7 617.25 529.3 617.25 2 L
+V
+N
+325.7 614.75 529.3 614.75 2 L
+V
+N
+325.2 600 529.8 600 2 L
+V
+N
+325.2 584 529.8 584 2 L
+V
+N
+325.2 568 529.8 568 2 L
+V
+N
+325.2 552 529.8 552 2 L
+V
+N
+325.2 536 529.8 536 2 L
+V
+N
+325.2 520 529.8 520 2 L
+V
+N
+325.2 504 529.8 504 2 L
+V
+N
+318.37 259.75 318.37 176.25 2 L
+V
+N
+377.89 260.25 377.89 175.75 2 L
+V
+N
+443.09 260.25 443.09 175.75 2 L
+V
+N
+494.11 260.25 494.11 175.75 2 L
+V
+N
+536.63 259.75 536.63 176.25 2 L
+V
+N
+318.12 260 536.88 260 2 L
+V
+N
+318.62 241.25 536.38 241.25 2 L
+V
+N
+318.62 238.75 536.38 238.75 2 L
+V
+N
+318.12 224 536.88 224 2 L
+V
+N
+318.12 208 536.88 208 2 L
+V
+N
+318.12 192 536.88 192 2 L
+V
+N
+318.12 176 536.88 176 2 L
+V
+N
+FMENDPAGE
+%%EndPage: "2" 1
+%%Page: "1" 1
+612 792 0 FMBEGINPAGE
+56.69 111.69 297.64 565.23 R
+7 X
+0 K
+V
+1 12 Q
+0 X
+(Contents) 56.69 557.23 T
+0 10 Q
+(0. Contacts/History) 56.69 539.56 T
+(1. Installation) 56.69 526.56 T
+(2. Sequential Usage) 56.69 513.56 T
+(2.1 Q-Scale) 85.04 500.56 T
+(2.2 Search Techniques) 85.04 487.56 T
+(2.3 GOP) 85.04 474.56 T
+(2.4 Slices) 85.04 461.56 T
+(2.5) 85.04 448.56 T
+( Search window) 97.53 448.56 T
+(2.6 IPB pattern) 85.04 435.56 T
+(2.7 Specifying Input Files) 85.04 422.56 T
+(2.8) 85.04 409.56 T
+( Original or Decoded) 97.53 409.56 T
+(2.9 Bit-rate Control) 85.04 396.56 T
+(2.10 User-data) 85.04 383.56 T
+(2.11 Compression Decision List \050CDL\051) 85.04 370.56 T
+(2.12 Gamma Correction) 85.04 357.56 T
+(2.13 Encoding GOPs at a time) 85.04 344.56 T
+(2.14) 85.04 331.56 T
+( Encoding Frames at a time) 102.53 331.56 T
+(2.15) 85.04 318.56 T
+( Stats and other info) 102.53 318.56 T
+(3. Parallel Usage) 56.69 305.56 T
+(3.1) 85.04 292.56 T
+( Architecture) 97.53 292.56 T
+(3.2 Specifying slave machines) 85.04 279.56 T
+(3.3) 85.04 266.56 T
+( Remote Shell) 97.53 266.56 T
+(3.4 Scheduling Algorithms) 85.04 253.56 T
+(3.5 Parallel Problems) 85.04 240.56 T
+0 12 Q
+(4. Performance) 56.69 226.23 T
+0 10 Q
+(5. Other Options) 56.69 213.56 T
+(5.1) 85.04 200.56 T
+( Custom Quantization Tables) 97.53 200.56 T
+(5.2 Aspect Ratio) 85.04 187.56 T
+(5.3) 85.04 174.56 T
+( Frame Rate) 97.53 174.56 T
+(6. Other Tools) 56.69 161.56 T
+(6.1) 85.04 148.56 T
+(ppmtoeyuv) 100.03 148.56 T
+(6.2 jmovie2jpeg) 85.04 135.56 T
+(6.3 movieToVid) 85.04 122.56 T
+314.36 54.99 552.76 565.23 R
+7 X
+V
+0 X
+(6.4) 342.71 558.56 T
+(yuvtojpeg) 357.7 558.56 T
+(6.5) 342.71 545.56 T
+( blockrun) 355.2 545.56 T
+(6.6) 342.71 532.56 T
+( vidtoppm) 355.2 532.56 T
+(6.7 vidtojpeg) 342.71 519.56 T
+(6.8 vidtoeyuv) 342.71 506.56 T
+(7. Frequently Asked Questions) 314.36 493.56 T
+(7.1 Questions) 342.71 480.56 T
+(7.2 Answers) 342.71 467.56 T
+1 12 Q
+(0. Contacts/History) 314.36 432.23 T
+0 10 Q
+2.56 (The Berkeley MPEG encoder was written by Kevin L.) 314.36 414.56 P
+0.59 (Gong in the Berkeley Plateau Multimedia Research group,) 314.36 403.56 P
+2.29 (headed by Professor Lawrence Rowe. It has since been) 314.36 392.56 P
+2.69 (modified by Stephen Smoot, Eugene Hung, and Darryl) 314.36 381.56 P
+0.69 (Brown. Please use the following e-mail addresses to reach) 314.36 370.56 P
+(us:) 314.36 359.56 T
+-0.23 (mpeg-bugs@plateau.cs.berkeley.edu \050bug reports and ques-) 314.36 346.56 P
+(tions\051 larry@cs.berkeley.edu \050research funding!\051) 314.36 335.56 T
+1 12 Q
+(1. Installation) 314.36 300.23 T
+0 10 Q
+(To install, read the directions in doc/INSTALL.) 342.71 282.56 T
+1.32 (Note that the) 342.71 269.56 P
+2 F
+3.17 (bin/) 400.8 269.56 P
+0 F
+1.32 ( directory contains binaries for) 424.79 269.56 P
+0.35 (several different platforms. The program has been success-) 314.36 258.56 P
+(fully ported to the following platforms:) 314.36 247.56 T
+(SunOS 4.x) 342.71 234.56 T
+(DEC Alpha running OSF1) 342.71 221.56 T
+(DECstation 5000 running Ultrix) 342.71 208.56 T
+(HP 9000 series) 342.71 195.56 T
+-0.06 (If you are successful in porting to a new platform, or) 342.71 169.56 P
+0.15 (have problems installing, please let us know \050at the address) 314.36 158.56 P
+(above\051.) 314.36 147.56 T
+1 12 Q
+(2. Sequential Usage) 314.36 112.23 T
+0 10 Q
+(The encoder is invoked in the following manner:) 314.36 81.56 T
+1 F
+(mpeg_encode) 352.7 68.56 T
+0 F
+( <options> parameter_file) 410.44 68.56 T
+56.69 570.9 552.76 735.31 R
+7 X
+V
+1 18 Q
+0 X
+(Berkeley MPEG-1 V) 174.89 723.31 T
+(ideo Encoder) 333.11 723.31 T
+290.64 685.53 254.68 685.53 2 L
+V
+1.71 H
+0 Z
+N
+(User) 254.68 687.31 T
+296.95 685.53 290.96 685.53 2 L
+V
+N
+(\325) 290.96 687.31 T
+354.77 685.53 296.29 685.53 2 L
+V
+N
+(s Guide) 296.29 687.31 T
+3 12 Q
+(Plateau Resear) 245.54 657.31 T
+(ch Gr) 318.71 657.31 T
+(oup) 345.92 657.31 T
+(Computer Science Division) 239.1 643.31 T
+(University of California) 247.08 629.31 T
+(Berkeley) 239.59 615.31 T
+(, California 94720) 280.89 615.31 T
+(mpeg-bugs@cs.berkeley) 236.26 596.31 T
+(.edu) 352.87 596.31 T
+56.69 54.99 297.64 104.6 R
+7 X
+V
+56.69 94.59 297.64 104.6 C
+56.69 94.59 297.64 104.6 R
+7 X
+0 K
+V
+56.69 103.59 525.7 103.59 2 L
+V
+1 H
+2 Z
+0 X
+N
+0 0 612 792 C
+0 9 Q
+0 X
+0 K
+(Last Updated: 30 January 1995) 56.69 88.59 T
+FMENDPAGE
+%%EndPage: "1" 0
+%%Trailer
+%%BoundingBox: 0 0 612 792
+%%Pages: 11 -1
+%%DocumentFonts: Times-Roman
+%%+ Times-Bold
+%%+ Courier
+%%+ Times-Italic
diff --git a/converter/ppm/ppmtompeg/examples/basicspeed.param b/converter/ppm/ppmtompeg/examples/basicspeed.param
new file mode 100644
index 00000000..94b03de7
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/basicspeed.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/speed.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/decoded.test b/converter/ppm/ppmtompeg/examples/decoded.test
new file mode 100644
index 00000000..7496524c
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/decoded.test
@@ -0,0 +1,81 @@
+# speed test parameter file
+
+PATTERN		ibpbpb
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	cat *.Y *.U *.V
+
+INPUT_DIR	/n/picasso/users/keving/links/flowg
+
+INPUT
+sflowg.*	[0-6]
+END_INPUT
+
+# the following two are optional  (default = 10, 60)
+
+# number of frames to do initially to gauge speed of machine
+PARALLEL_TEST_FRAMES	3
+
+# number of seconds per chunk thereafter
+PARALLEL_TIME_CHUNKS	30
+
+
+PARALLEL
+# lines must be of form "machine <whitespace> username <whitespace> executable"
+# these guys are sorta slow:
+#elmer-fudd	keving	~keving/encode/bin/sun/mpeg_encode
+#zonker		keving	~keving/encode/bin/sun/mpeg_encode
+#roger-rabbit	keving	~keving/encode/bin/sun/mpeg_encode
+#tweety		keving	~keving/encode/bin/sun/mpeg_encode
+#mickey		keving	~keving/encode/bin/mickey/mpeg_encode
+#
+# these guys are pretty fast:
+#
+#big-bird	keving	~keving/encode/bin/hp/mpeg_encode
+#gumby		keving	~keving/encode/bin/hp/mpeg_encode
+#charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+#woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+#bugs-bunny	keving	~keving/encode/bin/sun/mpeg_encode
+#
+# remotes
+#
+#REMOTE anaconda	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE adder	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE moccasin	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE cobra	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE boa	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE asp	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE rattler	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE viper	keving	~keving/mpeg_encode ~keving/parallel.test
+# mamba doesn't seem to work for whatever reason...don't know why
+#REMOTE mamba	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE cse.lbl.gov kevin	~kevin/mpeg_encode ~kevin/parallel.test
+#REMOTE roger-rabbit keving	~keving/src/encode/bin/sun/mpeg_encode ~keving/src/encode/ParamExamples/parallel.test
+END_PARALLEL
+
+
+# motion vector search parameters
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		FULL
+
+# means +/- this many pixels
+RANGE		8
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+IQSCALE		1
+PQSCALE		1
+BQSCALE		25
+
+REFERENCE_FRAME		DECODED
+#REFERENCE_FRAME		ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/decoded2.test b/converter/ppm/ppmtompeg/examples/decoded2.test
new file mode 100644
index 00000000..b5e9a865
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/decoded2.test
@@ -0,0 +1,81 @@
+# speed test parameter file
+
+PATTERN		ibbbpbbbbbp
+OUTPUT		/tmp/ts.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	512x512
+
+INPUT_CONVERT	giftoppm *
+
+INPUT_DIR	../test/ts
+
+INPUT
+med*.gif [030-039]
+END_INPUT
+
+# the following two are optional  (default = 10, 60)
+
+# number of frames to do initially to gauge speed of machine
+PARALLEL_TEST_FRAMES	3
+
+# number of seconds per chunk thereafter
+PARALLEL_TIME_CHUNKS	30
+
+
+PARALLEL
+# lines must be of form "machine <whitespace> username <whitespace> executable"
+# these guys are sorta slow:
+#elmer-fudd	keving	~keving/encode/bin/sun/mpeg_encode
+#zonker		keving	~keving/encode/bin/sun/mpeg_encode
+#roger-rabbit	keving	~keving/encode/bin/sun/mpeg_encode
+#tweety		keving	~keving/encode/bin/sun/mpeg_encode
+#mickey		keving	~keving/encode/bin/mickey/mpeg_encode
+#
+# these guys are pretty fast:
+#
+#big-bird	keving	~keving/encode/bin/hp/mpeg_encode
+#gumby		keving	~keving/encode/bin/hp/mpeg_encode
+#charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+#woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+#bugs-bunny	keving	~keving/encode/bin/sun/mpeg_encode
+#
+# remotes
+#
+#REMOTE anaconda	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE adder	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE moccasin	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE cobra	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE boa	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE asp	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE rattler	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE viper	keving	~keving/mpeg_encode ~keving/parallel.test
+# mamba doesn't seem to work for whatever reason...don't know why
+#REMOTE mamba	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE cse.lbl.gov kevin	~kevin/mpeg_encode ~kevin/parallel.test
+#REMOTE roger-rabbit keving	~keving/src/encode/bin/sun/mpeg_encode ~keving/src/encode/ParamExamples/parallel.test
+END_PARALLEL
+
+
+# motion vector search parameters
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		FULL
+
+# means +/- this many pixels
+RANGE		8
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+REFERENCE_FRAME		DECODED
+#REFERENCE_FRAME		ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/decorig.param b/converter/ppm/ppmtompeg/examples/decorig.param
new file mode 100644
index 00000000..3c570bcd
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/decorig.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBP
+
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-3]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/default.param b/converter/ppm/ppmtompeg/examples/default.param
new file mode 100644
index 00000000..17d8fe5d
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/default.param
@@ -0,0 +1,34 @@
+# parameter file with good default values
+#
+# use this as a guideline for any parameters you don't really understand
+# or don't care about
+#
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		output.mpg
+
+BASE_FILE_FORMAT	YUV
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+PIXEL		HALF
+RANGE		10
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+REFERENCE_FRAME	ORIGINAL
+
+#
+# you really need to understand the following
+#
+YUV_SIZE	352x240
+INPUT_CONVERT	*
+
+INPUT_DIR	input/flowg
+
+INPUT
+sflowg.*.yuv	[0-23]
+END_INPUT
diff --git a/converter/ppm/ppmtompeg/examples/fastspeed.param b/converter/ppm/ppmtompeg/examples/fastspeed.param
new file mode 100644
index 00000000..c45e0341
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/fastspeed.param
@@ -0,0 +1,46 @@
+# speed test parameter file
+
+PATTERN		ibbpbbpbbpbbpbb
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	cat *.Y *.U *.V
+
+INPUT_DIR	/n/picasso/project/mm/mpeg/mpeg_encode/input/flowg
+
+INPUT
+sflowg.*	[0-149]
+END_INPUT
+
+PARALLEL_TEST_FRAMES	3
+PARALLEL_TIME_CHUNKS	15
+
+PARALLEL
+charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+END_PARALLEL
+
+# motion vector search parameters
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		FULL
+
+# means +/- this many pixels
+RANGE		8
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+REFERENCE_FRAME	ORIGINAL
+
diff --git a/converter/ppm/ppmtompeg/examples/foobar.param b/converter/ppm/ppmtompeg/examples/foobar.param
new file mode 100644
index 00000000..1ba6f029
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/foobar.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard20.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[000-027]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		FULL
+
+RANGE		10
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/frame.test b/converter/ppm/ppmtompeg/examples/frame.test
new file mode 100644
index 00000000..fbefb8c4
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/frame.test
@@ -0,0 +1,37 @@
+# speed test parameter file
+
+PATTERN		IBPB
+OUTPUT		output/food
+GOP_SIZE	20
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	cat *.Y *.U *.V
+
+INPUT_DIR	links/flowg
+
+INPUT
+sflowg.*	[0-4]
+END_INPUT
+
+
+# motion vector search parameters
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		FULL
+
+# means +/- this many pixels
+RANGE		8
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+IQSCALE		10
+PQSCALE		31
+BQSCALE		31
+
diff --git a/converter/ppm/ppmtompeg/examples/gop.combine b/converter/ppm/ppmtompeg/examples/gop.combine
new file mode 100644
index 00000000..6b5c3e89
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/gop.combine
@@ -0,0 +1,11 @@
+# speed test parameter file
+
+OUTPUT		output/gop.mpg
+
+YUV_SIZE	352x240
+
+INPUT_DIR	.
+
+INPUT
+output/food.gop.*	[0-2]
+END_INPUT
diff --git a/converter/ppm/ppmtompeg/examples/gop.test b/converter/ppm/ppmtompeg/examples/gop.test
new file mode 100644
index 00000000..c2ae346b
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/gop.test
@@ -0,0 +1,43 @@
+# speed test parameter file
+
+PATTERN		IBPBP
+
+OUTPUT		output/food
+GOP_SIZE	5
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	cat *.Y *.U *.V
+
+INPUT_DIR	links/flowg
+
+INPUT
+sflowg.*	[0-14]
+END_INPUT
+
+
+GOP_INPUT_DIR	output
+GOP_INPUT
+food.gop.*	[1-2]
+GOP_END_INPUT
+
+# motion vector search parameters
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		FULL
+
+# means +/- this many pixels
+RANGE		8
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+IQSCALE		10
+PQSCALE		31
+BQSCALE		31
+
diff --git a/converter/ppm/ppmtompeg/examples/gop1.param b/converter/ppm/ppmtompeg/examples/gop1.param
new file mode 100644
index 00000000..c89a5b9a
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/gop1.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	6
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/hello.param b/converter/ppm/ppmtompeg/examples/hello.param
new file mode 100644
index 00000000..579b01ed
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/hello.param
@@ -0,0 +1,60 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/hello.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-49]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		FULL
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+#REFERENCE_FRAME	DECODED
+REFERENCE_FRAME	ORIGINAL
+
+PARALLEL_TEST_FRAMES	3
+
+# number of seconds per chunk thereafter
+PARALLEL_TIME_CHUNKS	30
+
+PARALLEL
+#big-bird	keving	~keving/encode/bin/hp/mpeg_encode
+#gumby		keving	~keving/encode/bin/hp/mpeg_encode
+charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+#woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+#REMOTE cory keving ~keving/bin/mpeg_encode ~keving/hello.param
+REMOTE scorpius.EECS.Berkeley.EDU keving ~keving/bin/mpeg_encode ~keving/hello.param
+REMOTE monoceros.EECS.Berkeley.EDU keving ~keving/bin/mpeg_encode ~keving/hello.param
+REMOTE lepus.EECS.Berkeley.EDU keving ~keving/bin/mpeg_encode ~keving/hello.param
+REMOTE fornax.EECS.Berkeley.EDU keving ~keving/bin/mpeg_encode ~keving/hello.param
+REMOTE delphinus.EECS.Berkeley.EDU keving ~keving/bin/mpeg_encode ~keving/hello.param
+REMOTE cephus.EECS.Berkeley.EDU keving ~keving/bin/mpeg_encode ~keving/hello.param
+REMOTE carina.EECS.Berkeley.EDU keving ~keving/bin/mpeg_encode ~keving/hello.param
+REMOTE bootes.EECS.Berkeley.EDU keving ~keving/bin/mpeg_encode ~keving/hello.param
+REMOTE aquila.EECS.Berkeley.EDU keving ~keving/bin/mpeg_encode ~keving/hello.param
+#
+END_PARALLEL
+
+# FORCE_I_ALIGN
diff --git a/converter/ppm/ppmtompeg/examples/i.test b/converter/ppm/ppmtompeg/examples/i.test
new file mode 100644
index 00000000..af62afae
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/i.test
@@ -0,0 +1,37 @@
+# speed test parameter file
+
+PATTERN		I
+OUTPUT		output/food
+GOP_SIZE	20
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	cat *.Y *.U *.V
+
+INPUT_DIR	links/flowg
+
+INPUT
+sflowg.*	[0-5]
+END_INPUT
+
+
+# motion vector search parameters
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		FULL
+
+# means +/- this many pixels
+RANGE		8
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+IQSCALE		10
+PQSCALE		31
+BQSCALE		31
+
diff --git a/converter/ppm/ppmtompeg/examples/ispeed.jpeg.param b/converter/ppm/ppmtompeg/examples/ispeed.jpeg.param
new file mode 100644
index 00000000..ce3d4ed3
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/ispeed.jpeg.param
@@ -0,0 +1,48 @@
+# speed test parameter file
+
+PATTERN		I
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard1.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	djpeg *
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg/jpeg
+
+INPUT
+sflowg.*.jpeg	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		FULL
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
+
+
+PARALLEL_TEST_FRAMES	3
+PARALLEL_TIME_CHUNKS	30
+
+PARALLEL
+big-bird	keving	~keving/encode/bin/hp/mpeg_encode
+gumby		keving	~keving/encode/bin/hp/mpeg_encode
+charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+END_PARALLEL
+
+IO_SERVER_CONVERT       *
+SLAVE_CONVERT           djpeg *
diff --git a/converter/ppm/ppmtompeg/examples/ispeed.param b/converter/ppm/ppmtompeg/examples/ispeed.param
new file mode 100644
index 00000000..01381e85
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/ispeed.param
@@ -0,0 +1,45 @@
+# speed test parameter file
+
+PATTERN		I
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard1.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		FULL
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
+
+
+PARALLEL_TEST_FRAMES	3
+PARALLEL_TIME_CHUNKS	30
+
+PARALLEL
+big-bird	keving	~keving/encode/bin/hp/mpeg_encode
+gumby		keving	~keving/encode/bin/hp/mpeg_encode
+charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+END_PARALLEL
diff --git a/converter/ppm/ppmtompeg/examples/jpeg.test b/converter/ppm/ppmtompeg/examples/jpeg.test
new file mode 100644
index 00000000..75e3eb8f
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/jpeg.test
@@ -0,0 +1,66 @@
+# speed test parameter file
+
+PATTERN		ibbpbbpbbpbbpbb
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.jpeg.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	352x240
+
+INPUT_CONVERT	djpeg *
+
+INPUT_DIR	/n/picasso/project/mm/mpeg/mpeg_encode/input/flowg/jpeg
+
+INPUT
+sflowg.*.jpeg	[1-20]
+END_INPUT
+
+# the following two are optional  (default = 10, 60)
+
+# number of frames to do initially to gauge speed of machine
+PARALLEL_TEST_FRAMES	3
+
+# number of seconds per chunk thereafter
+PARALLEL_TIME_CHUNKS	30
+
+# specifies what the IO server must do before transmitting to remote sites
+IO_SERVER_CONVERT	*
+
+# specifies what the remote slave must do after receiving from IO server
+SLAVE_CONVERT		djpeg *
+
+PARALLEL
+# lines must be of form "machine <whitespace> username <whitespace> executable"
+# these guys are sorta slow:
+#elmer-fudd	keving	~keving/encode/bin/sun/mpeg_encode
+#roger-rabbit	keving	~keving/encode/bin/sun/mpeg_encode
+#tweety		keving	~keving/encode/bin/sun/mpeg_encode
+#mickey		keving	~keving/encode/bin/mickey/mpeg_encode
+#
+# these guys are pretty fast:
+#
+#big-bird	keving	~keving/encode/bin/hp/mpeg_encode
+#gumby		keving	~keving/encode/bin/hp/mpeg_encode
+charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+#bugs-bunny	keving	~keving/encode/bin/sun/mpeg_encode
+#
+# remotes
+#
+END_PARALLEL
+
+
+# motion vector search parameters
+
+PIXEL		HALF
+RANGE		8
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+REFERENCE_FRAME	ORIGINAL
+
diff --git a/converter/ppm/ppmtompeg/examples/jpeg19.param b/converter/ppm/ppmtompeg/examples/jpeg19.param
new file mode 100644
index 00000000..15013895
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/jpeg19.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	JPEG
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg/jpeg
+
+INPUT
+sflowg.*.jpeg	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/jpegout19.param b/converter/ppm/ppmtompeg/examples/jpegout19.param
new file mode 100644
index 00000000..d31383d3
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/jpegout19.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	352x240
+
+INPUT_CONVERT	djpeg *
+
+INPUT_DIR	../input/flowg/jpeg
+
+INPUT
+sflowg.*.jpeg	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/localdisk.param b/converter/ppm/ppmtompeg/examples/localdisk.param
new file mode 100644
index 00000000..e7f49f33
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/localdisk.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		I
+OUTPUT		/usr/tmp/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/usr/tmp
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		FULL
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/localremote.test b/converter/ppm/ppmtompeg/examples/localremote.test
new file mode 100644
index 00000000..6c91721f
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/localremote.test
@@ -0,0 +1,80 @@
+# speed test parameter file
+
+#PATTERN		ibbpbbpbbpbbpbb
+PATTERN		iiiiiiii
+OUTPUT		/n/picasso/users/keving/src/encode/output/good
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	cat *.Y *.U *.V
+
+INPUT_DIR	/n/picasso/users/keving/links/flowg
+
+INPUT
+sflowg.*	[0-149]
+END_INPUT
+
+# the following two are optional  (default = 10, 60)
+
+# number of frames to do initially to gauge speed of machine
+PARALLEL_TEST_FRAMES	3
+
+# number of seconds per chunk thereafter
+PARALLEL_TIME_CHUNKS	30
+
+
+PARALLEL
+# lines must be of form "machine <whitespace> username <whitespace> executable"
+# these guys are sorta slow:
+#REMOTE charlie-brown	keving	~keving/src/encode/bin/dec/mpeg_encode ~keving/src/encode/ParamExamples/localremote.test
+#REMOTE woodstock	keving	~keving/src/encode/bin/dec/mpeg_encode ~keving/src/encode/ParamExamples/localremote.test
+#REMOTE gumby		keving	~keving/src/encode/bin/hp/mpeg_encode ~keving/src/encode/ParamExamples/localremote.test
+#REMOTE big-bird		keving	~keving/src/encode/bin/hp/mpeg_encode ~keving/src/encode/ParamExamples/localremote.test
+#REMOTE elmer-fudd	keving	~keving/src/encode/bin/sun/mpeg_encode ~keving/src/encode/ParamExamples/localremote.test
+#REMOTE mickey		keving	~keving/src/encode/bin/mickey/mpeg_encode ~keving/src/encode/ParamExamples/localremote.test
+#zonker		keving	~keving/src/encode/bin/sun/mpeg_encode
+#roger-rabbit	keving	~keving/src/encode/bin/sun/mpeg_encode
+#tweety		keving	~keving/src/encode/bin/sun/mpeg_encode
+#
+# these guys are pretty fast:
+#
+#bugs-bunny	keving	~keving/src/encode/bin/sun/mpeg_encode
+#
+# remotes
+#
+#REMOTE anaconda	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE adder	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE moccasin	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE cobra	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE boa	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE asp	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE rattler	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE viper	keving	~keving/mpeg_encode ~keving/parallel.test
+# mamba doesn't seem to work for whatever reason...don't know why
+#REMOTE mamba	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE cse.lbl.gov kevin	~kevin/mpeg_encode ~kevin/parallel.test
+#REMOTE roger-rabbit keving	~keving/src/encode/bin/sun/mpeg_encode ~keving/src/encode/ParamExamples/parallel.test
+END_PARALLEL
+
+
+# motion vector search parameters
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		FULL
+
+# means +/- this many pixels
+RANGE		8
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
diff --git a/converter/ppm/ppmtompeg/examples/luxo.param b/converter/ppm/ppmtompeg/examples/luxo.param
new file mode 100644
index 00000000..6c92dca1
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/luxo.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/luxo.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	320x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/luxo
+
+INPUT
+luxo*.yuv	[1201-1400]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		20
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/luxo18.param b/converter/ppm/ppmtompeg/examples/luxo18.param
new file mode 100644
index 00000000..4a020325
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/luxo18.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/luxo19.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	320x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/luxo
+
+INPUT
+luxo*.yuv	[1201-1400]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/luxo19.5.param b/converter/ppm/ppmtompeg/examples/luxo19.5.param
new file mode 100644
index 00000000..edacc7c7
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/luxo19.5.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/luxo19.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	320x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/luxo
+
+INPUT
+luxo*.yuv	[1201-1216]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/luxo19.param b/converter/ppm/ppmtompeg/examples/luxo19.param
new file mode 100644
index 00000000..7accb23a
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/luxo19.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/luxo19.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	320x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/luxo
+
+INPUT
+luxo*.yuv	[1201-1400]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/luxo2.param b/converter/ppm/ppmtompeg/examples/luxo2.param
new file mode 100644
index 00000000..f75b7e1c
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/luxo2.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		I
+OUTPUT		/n/picasso/users/keving/encode/output/luxo2.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	320x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/luxo
+
+INPUT
+luxo1399.yuv
+luxo1400.yuv
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		20
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/luxo48.param b/converter/ppm/ppmtompeg/examples/luxo48.param
new file mode 100644
index 00000000..599f6d8c
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/luxo48.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/luxo19.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	320x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/luxo
+
+INPUT
+luxo*.yuv	[1201-1400]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	SUBSAMPLE
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/luxo49.param b/converter/ppm/ppmtompeg/examples/luxo49.param
new file mode 100644
index 00000000..5a493e40
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/luxo49.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/luxo19.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	320x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/luxo
+
+INPUT
+luxo*.yuv	[1201-1400]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	TWOLEVEL
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/luxo50.param b/converter/ppm/ppmtompeg/examples/luxo50.param
new file mode 100644
index 00000000..f3afe8e8
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/luxo50.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/luxo19.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	320x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/luxo
+
+INPUT
+luxo*.yuv	[1201-1400]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/luxo52.5.param b/converter/ppm/ppmtompeg/examples/luxo52.5.param
new file mode 100644
index 00000000..f3f16854
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/luxo52.5.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/luxo19.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	320x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/luxo
+
+INPUT
+luxo*.yuv	[1201-1216]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/luxo52.param b/converter/ppm/ppmtompeg/examples/luxo52.param
new file mode 100644
index 00000000..8874ad97
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/luxo52.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/luxo19.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	320x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/luxo
+
+INPUT
+luxo*.yuv	[1201-1400]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/luxo53.param b/converter/ppm/ppmtompeg/examples/luxo53.param
new file mode 100644
index 00000000..d084b18b
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/luxo53.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/luxo19.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	320x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/luxo
+
+INPUT
+luxo*.yuv	[1201-1216]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	EXHAUSTIVE
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/luxobug.param b/converter/ppm/ppmtompeg/examples/luxobug.param
new file mode 100644
index 00000000..73e9de9f
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/luxobug.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/luxobug.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	320x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/luxo-skip10
+
+INPUT
+luxo*.yuv		[1351-1701+5]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/luxoskip.param b/converter/ppm/ppmtompeg/examples/luxoskip.param
new file mode 100644
index 00000000..12768ed4
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/luxoskip.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/luxoskip.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	320x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/luxo-skip10
+
+INPUT
+luxo*1 		[1-307]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		20
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		20
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/med.param b/converter/ppm/ppmtompeg/examples/med.param
new file mode 100644
index 00000000..0e3bbd8d
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/med.param
@@ -0,0 +1,36 @@
+# 'med' parameter file
+
+PATTERN		IBBPBBPBBPBBPBBI
+OUTPUT		output/med.mpg
+GOP_SIZE	20
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+INPUT_CONVERT	giftoppm *
+
+INPUT_DIR	links/gcmovie
+
+INPUT
+med*.gif	[001-073]
+END_INPUT
+
+
+# motion vector search parameters
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		HALF
+
+# means +/- this many pixels
+RANGE		8
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	CROSS2
+
+
+IQSCALE		13
+PQSCALE		16
+BQSCALE		26
+
diff --git a/converter/ppm/ppmtompeg/examples/med18.param b/converter/ppm/ppmtompeg/examples/med18.param
new file mode 100644
index 00000000..b8ad664c
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/med18.param
@@ -0,0 +1,34 @@
+# 'med' parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/med18.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+INPUT_CONVERT	giftoppm *
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/gcmovie
+
+INPUT
+med*.gif	[001-073]
+END_INPUT
+
+
+# motion vector search parameters
+
+# FULL or HALF -- must be upper case
+PIXEL		HALF
+
+# means +/- this many pixels
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/medspeed.param b/converter/ppm/ppmtompeg/examples/medspeed.param
new file mode 100644
index 00000000..d91f4dda
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/medspeed.param
@@ -0,0 +1,38 @@
+# speed test parameter file
+
+PATTERN		ibbpbbpbbpbbpbb
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	cat *.Y *.U *.V
+
+INPUT_DIR	/n/picasso/project/mm/mpeg/mpeg_encode/input/flowg
+
+INPUT
+sflowg.*	[0-149]
+END_INPUT
+
+# motion vector search parameters
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		FULL
+
+# means +/- this many pixels
+RANGE		10
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	CROSS2
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+REFERENCE_FRAME	ORIGINAL
+
diff --git a/converter/ppm/ppmtompeg/examples/nametest.param b/converter/ppm/ppmtompeg/examples/nametest.param
new file mode 100644
index 00000000..445622fb
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/nametest.param
@@ -0,0 +1,60 @@
+# test suite parameter file
+
+PATTERN		IBBBPBBBBP
+OUTPUT		/tmp/foobar.mpg
+
+YUV_SIZE	352x240
+
+BASE_FILE_FORMAT	YUV
+INPUT_CONVERT	cat *.Y *.U *.V
+GOP_SIZE	30
+SLICES_PER_FRAME  1
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/tennis
+
+INPUT
+stennis.0
+stennis.*	[1-3]
+stennis.*	[4-5]
+stennis.*	[6-6]
+stennis.7
+stennis.*	[8-15]
+stennis.16
+stennis.17
+stennis.*	[18-34]
+END_INPUT
+
+
+
+# all of the remaining options have to do with the motion search and qscale
+#
+# change this only if you're unsatisfied with the CPU time or quality, or
+# are experimenting
+#
+
+# if this appears in the file, then in addition to testing luminance when
+# computing motion vectors, program will also take into account chrominance
+#
+# this option MUST appear before ERROR option, or it will be ignored
+#
+# CHROMINANCE
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		FULL
+
+# means +/- this many pixels
+RANGE		8
+
+PSEARCH_ALG	LOGARITHMIC
+
+BSEARCH_ALG	SIMPLE
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/nosearch.param b/converter/ppm/ppmtompeg/examples/nosearch.param
new file mode 100644
index 00000000..453356c0
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/nosearch.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		I
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard1.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		FULL
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/par3.param b/converter/ppm/ppmtompeg/examples/par3.param
new file mode 100644
index 00000000..ca664334
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/par3.param
@@ -0,0 +1,43 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-39]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
+
+PARALLEL_TEST_FRAMES	3
+PARALLEL_TIME_CHUNKS	30
+
+PARALLEL
+bugs-bunny	keving	~keving/encode/bin/sun/mpeg_encode
+linus		keving	~keving/encode/bin/sun/mpeg_encode
+END_PARALLEL
diff --git a/converter/ppm/ppmtompeg/examples/par4.param b/converter/ppm/ppmtompeg/examples/par4.param
new file mode 100644
index 00000000..95a72c34
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/par4.param
@@ -0,0 +1,45 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-49]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
+
+PARALLEL_TEST_FRAMES	3
+# PARALLEL_TIME_CHUNKS	20
+PARALLEL_CHUNK_TAPER
+
+PARALLEL
+bugs-bunny	keving	~keving/encode/bin/sun/mpeg_encode
+linus		keving	~keving/encode/bin/sun/mpeg_encode
+zonker		keving	~keving/encode/bin/sun/mpeg_encode
+END_PARALLEL
diff --git a/converter/ppm/ppmtompeg/examples/par5.param b/converter/ppm/ppmtompeg/examples/par5.param
new file mode 100644
index 00000000..ad51a519
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/par5.param
@@ -0,0 +1,47 @@
+# speed test parameter file
+
+#PATTERN		IBBPBBPBBPBBPBB
+PATTERN		I
+
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
+
+PARALLEL_TEST_FRAMES	3
+PARALLEL_CHUNK_TAPER
+
+PARALLEL
+woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+gumby		keving	~keving/encode/bin/hp/mpeg_encode
+big-bird	keving	~keving/encode/bin/hp/mpeg_encode
+roger-rabbit	keving	~keving/encode/bin/sun/mpeg_encode
+END_PARALLEL
diff --git a/converter/ppm/ppmtompeg/examples/parallel.2 b/converter/ppm/ppmtompeg/examples/parallel.2
new file mode 100644
index 00000000..0ab153fb
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/parallel.2
@@ -0,0 +1,87 @@
+# speed test parameter file
+
+PATTERN		ibbpbbpbbpbbpbb
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	352x240
+
+INPUT_CONVERT	djpeg *
+
+INPUT_DIR	/n/picasso/project/mm/mpeg/mpeg_encode/input/flowg/jpeg
+
+INPUT
+sflowg.*.jpeg	[1-30]
+END_INPUT
+
+# the following are optional
+
+PARALLEL_PERFECT
+
+
+
+# specifies what the IO server must do before transmitting to remote sites
+IO_SERVER_CONVERT	*
+
+# specifies what the remote slave must do after receiving from IO server
+SLAVE_CONVERT		djpeg *
+
+PARALLEL
+# lines must be of form "machine <whitespace> username <whitespace> executable"
+# these guys are sorta slow:
+#elmer-fudd	keving	~keving/encode/bin/sun/mpeg_encode
+#elmer-fudd	keving	~keving/encode/bin/sun/mpeg_encode
+#bugs-bunny	keving	~keving/encode/bin/sun/mpeg_encode
+#REMOTE bugs-bunny keving ~keving/encode/src/mpeg_encode ~keving/encode/examples/parallel.test
+#roger-rabbit	keving	~keving/encode/bin/sun/mpeg_encode
+#tweety		keving	~keving/encode/bin/sun/mpeg_encode
+#mickey		keving	~keving/encode/bin/mickey/mpeg_encode
+#
+# these guys are pretty fast:
+#
+#big-bird	keving	~keving/encode/bin/hp/mpeg_encode
+#gumby		keving	~keving/encode/bin/hp/mpeg_encode
+charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+#bugs-bunny	keving	~keving/encode/bin/sun/mpeg_encode
+#
+# remotes
+#
+#REMOTE anaconda	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE adder	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE moccasin	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE cobra	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE boa	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE asp	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE rattler	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE viper	keving	~keving/mpeg_encode ~keving/parallel.test
+# mamba doesn't seem to work for whatever reason...don't know why
+#REMOTE mamba	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE cse.lbl.gov kevin	~kevin/mpeg_encode ~kevin/parallel.test
+#REMOTE roger-rabbit keving	~keving/src/encode/bin/sun/mpeg_encode ~keving/src/encode/ParamExamples/parallel.test
+END_PARALLEL
+
+
+# motion vector search parameters
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		FULL
+
+# means +/- this many pixels
+RANGE		8
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+
+REFERENCE_FRAME	ORIGINAL
+
diff --git a/converter/ppm/ppmtompeg/examples/parallel.param b/converter/ppm/ppmtompeg/examples/parallel.param
new file mode 100644
index 00000000..a158eae5
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/parallel.param
@@ -0,0 +1,141 @@
+# parameter file template with parallel execution
+#
+# you can use this as a template, copying it to a separate file then modifying
+# the copy
+#
+#
+# any line beginning with '#' is a comment
+#
+# no line should be longer than 255 characters
+#
+#
+# general format of each line is:
+#	<option> <spaces and/or tabs> <value>
+#
+# lines can generally be in any order
+#
+# only exception is the option 'INPUT' which must be followed by input
+# files in the order in which they must appear, followed by 'END_INPUT'
+#
+# <option> MUST be in UPPER CASE
+#
+
+PATTERN		IBBPBBPBBPBBP
+OUTPUT		/n/picasso/users/keving/encode/output.mpg
+
+# mpeg_encode really only accepts 3 different file formats, but using a
+# conversion statement it can effectively handle ANY file format
+#
+# you must specify whether you will convert to PNM or PPM or YUV format
+#	(must be upper case)
+#
+BASE_FILE_FORMAT	YUV
+
+#
+# if YUV format (or using parallel version), must provide width and height
+# YUV_SIZE	widthxheight
+# this option is ignored if BASE_FILE_FORMAT is PPM or PNM and you're running
+# on just one machine
+#
+YUV_SIZE	352x240
+
+# the conversion statement
+#
+# Each occurrence of '*' will be replaced by the input file
+#
+# e.g., if you have a bunch of GIF files, then this might be:
+#	INPUT_CONVERT	giftoppm *
+#
+# e.g., if you have a bunch of files like a.Y a.U a.V, etc., then:
+#	INPUT_CONVERT	cat *.Y *.U *.V
+#
+# e.g., if you are grabbing from laser disc you might have something like
+#	INPUT_CONVERT	goto frame *; grabppm
+# 'INPUT_CONVERT *' means the files are already in the base file format
+#
+INPUT_CONVERT	*
+
+# number of frames in a GOP.
+#
+# since each GOP must have at least one I-frame, the encoder will find the
+# the first I-frame after GOP_SIZE frames to start the next GOP
+#
+# later, will add more flexible GOP signalling
+#
+GOP_SIZE	6
+
+# number of slices in a frame
+#
+# 1 is a good number.  another possibility is the number of macroblock rows
+# (which is the height divided by 16)
+#
+SLICES_PER_FRAME	1
+
+# directory to get all input files from (makes this file easier to read)
+INPUT_DIR	/n/picasso/users/keving/encode/input/tennis
+
+INPUT
+# '*' is replaced by the numbers 01, 02, 03, 04
+# if I instead do [01-11], it would be 01, 02, ..., 09, 10, 11
+# if I instead do [1-11], it would be 1, 2, 3, ..., 9, 10, 11
+# if I instead do [1-11+3], it would be 1, 4, 7, 10
+# the program assumes none of your input files has a name ending in ']'
+# if you do, too bad!!!
+#
+#
+stennis.*.yuv	[0-7]
+# can have more files here if you want...there is no limit on the number
+# of files
+END_INPUT
+
+
+
+# all of the remaining options have to do with the motion search and qscale
+
+# FULL or HALF -- must be upper case
+PIXEL		HALF
+
+# means +/- this many pixels
+RANGE		10
+
+# this must be one of {EXHAUSTIVE, SUBSAMPLE, LOGARITHMIC}
+PSEARCH_ALG	LOGARITHMIC
+
+# this must be one of {SIMPLE, CROSS2, EXHAUSTIVE}
+#
+# note that EXHAUSTIVE is really, really, really slow
+#
+BSEARCH_ALG	CROSS2
+
+#
+# these specify the q-scale for I, P, and B frames
+# (values must be between 1 and 31)
+#
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# this must be ORIGINAL or DECODED
+REFERENCE_FRAME	ORIGINAL
+
+
+# the following two are optional  (default = 10, 60)
+
+# number of frames to do initially to gauge speed of machine
+PARALLEL_TEST_FRAMES	3
+
+# number of seconds per chunk thereafter
+PARALLEL_TIME_CHUNKS	30
+
+
+PARALLEL
+# lines must be of form "machine <whitespace> username <whitespace> executable"
+charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+#woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+#REMOTE charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode ~keving/encode/examples/parallel.param
+# remote machine: "REMOTE machine username executable param_file"
+# mickey		keving	~keving/encode/bin/dec-5000/mpeg_encode
+#REMOTE mickey		keving	~keving/encode/bin/dec-5000/mpeg_encode ~keving/encode/examples/parallel.param
+#REMOTE mickey		keving	~keving/encode/bin/dec-5000/mpeg_encode ~keving/encode/examples/parallel.param
+REMOTE woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode ~keving/encode/examples/parallel.param
+END_PARALLEL
diff --git a/converter/ppm/ppmtompeg/examples/parallel.test b/converter/ppm/ppmtompeg/examples/parallel.test
new file mode 100644
index 00000000..2489d847
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/parallel.test
@@ -0,0 +1,85 @@
+# speed test parameter file
+
+PATTERN		ibbpbbpbbpbbpbb
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	352x240
+
+INPUT_CONVERT	djpeg *
+
+INPUT_DIR	/n/picasso/project/mm/mpeg/mpeg_encode/input/flowg/jpeg
+
+INPUT
+sflowg.*.jpeg	[1-30]
+END_INPUT
+
+# the following two are optional  (default = 10, 60)
+
+# number of frames to do initially to gauge speed of machine
+PARALLEL_TEST_FRAMES	3
+
+# number of seconds per chunk thereafter
+PARALLEL_TIME_CHUNKS	30
+
+# specifies what the IO server must do before transmitting to remote sites
+IO_SERVER_CONVERT	*
+
+# specifies what the remote slave must do after receiving from IO server
+SLAVE_CONVERT		djpeg *
+
+PARALLEL
+# lines must be of form "machine <whitespace> username <whitespace> executable"
+# these guys are sorta slow:
+#REMOTE bugs-bunny keving ~keving/encode/src/mpeg_encode ~keving/encode/examples/parallel.test
+#mickey		keving	~keving/encode/bin/mickey/mpeg_encode
+#
+# these guys are pretty fast:
+#
+#big-bird	keving	~keving/encode/bin/hp/mpeg_encode
+#gumby		keving	~keving/encode/bin/hp/mpeg_encode
+#charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+bugs-bunny	keving	~keving/encode/bin/sun/mpeg_encode
+#roger-rabbit	keving	~keving/encode/bin/sun/mpeg_encode
+#
+# remotes
+#
+#REMOTE anaconda	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE adder	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE moccasin	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE cobra	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE boa	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE asp	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE rattler	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE viper	keving	~keving/mpeg_encode ~keving/parallel.test
+# mamba doesn't seem to work for whatever reason...don't know why
+#REMOTE mamba	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE cse.lbl.gov kevin	~kevin/mpeg_encode ~kevin/parallel.test
+#REMOTE roger-rabbit keving	~keving/src/encode/bin/sun/mpeg_encode ~keving/src/encode/ParamExamples/parallel.test
+END_PARALLEL
+
+
+# motion vector search parameters
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		FULL
+
+# means +/- this many pixels
+RANGE		8
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+
+REFERENCE_FRAME	ORIGINAL
+
diff --git a/converter/ppm/ppmtompeg/examples/param.template b/converter/ppm/ppmtompeg/examples/param.template
new file mode 100644
index 00000000..ce81e474
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/param.template
@@ -0,0 +1,107 @@
+# parameter file template
+#
+# any line beginning with '#' is a comment
+#
+# no line should be longer than 255 characters
+#
+#
+# general format of each line is:
+#	<option> <spaces and/or tabs> <value>
+#
+# lines can generally be in any order
+#
+# only exception is the option 'INPUT' which must be followed by input
+# files in the order in which they must appear, followed by 'END_INPUT'
+#
+# <option> MUST be in UPPER CASE
+#
+
+PATTERN		IBBPBBPBBPBBP
+OUTPUT		output/food
+
+# mpeg_encode really only accepts 2 different file formats, but using a
+# conversion statement it can effectively handle ANY file format
+#
+# you must specify whether you will convert to PPM or YUV format
+#	(must be upper case)
+#
+BASE_FILE_FORMAT	YUV
+
+#
+# if YUV format, must provide width and height
+# YUV_SIZE	width height
+# this option is ignored if BASE_FILE_FORMAT is PPM
+#
+YUV_SIZE	352x240
+
+# the conversion statement
+#
+# Each occurrence of '*' will be replaced by the input file
+#
+# e.g., if you have a bunch of GIF files, then this might be:
+#	INPUT_CONVERT	giftoppm *
+#
+# e.g., if you have a bunch of files like a.Y a.U a.V, etc., then:
+#	INPUT_CONVERT	cat *.Y *.U *.V
+#
+# e.g., if you are grabbing from laser disc you might have something like
+#	INPUT_CONVERT	goto frame *; grabppm
+# 'INPUT_CONVERT *' means the files are already in the base file format
+#
+INPUT_CONVERT	cat *.Y *.U *.V
+
+# number of frames in a GOP.
+#
+# since each GOP must have at least one I-frame, the encoder will find the
+# the first I-frame after GOP_SIZE frames to start the next GOP
+#
+# later, will add more flexible GOP signalling
+#
+GOP_SIZE	30
+
+# directory to get all input files from (makes this file easier to read)
+INPUT_DIR	links/payam
+
+INPUT
+# '*' is replaced by the numbers 01, 02, 03, 04
+# if I instead do [01-11], it would be 01, 02, ..., 09, 10, 11
+# if I instead do [1-11], it would be 1, 2, 3, ..., 9, 10, 11
+# the program assumes none of your input files has a name ending in ']'
+# if you do, too bad!!!
+#
+#
+stennis.*	[0-23]
+# can have more files here if you want...as many as you want
+END_INPUT
+
+
+
+# all of the remaining options have to do with the motion search and qscale
+#
+# change this only if you're unsatisfied with the CPU time or quality, or
+# are experimenting
+#
+
+# if this appears in the file, then in addition to testing luminance when
+# computing motion vectors, program will also take into account chrominance
+#
+# this option MUST appear before ERROR option, or it will be ignored
+#
+# CHROMINANCE
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		FULL
+
+# means +/- this many pixels
+RANGE		8
+
+# YES or NO -- must be upper case
+SUBSAMPLE	NO
+
+IQSCALE		10
+PQSCALE		15
+BQSCALE		25
+
diff --git a/converter/ppm/ppmtompeg/examples/payam.param b/converter/ppm/ppmtompeg/examples/payam.param
new file mode 100644
index 00000000..ce886914
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/payam.param
@@ -0,0 +1,37 @@
+# parameter file for payam's images
+
+#PATTERN		IBBPBBPBBPBBPBBI
+PATTERN		II
+OUTPUT		output/payam.mpg
+GOP_SIZE	20
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PNM
+
+INPUT_CONVERT *
+INPUT_DIR	links/payam
+
+INPUT
+kh*.pnm	[1-3]
+END_INPUT
+
+
+# motion vector search paramters
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		FULL
+
+# means +/- this many pixels
+RANGE		8
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+
+IQSCALE		10
+PQSCALE		15
+BQSCALE		25
+
diff --git a/converter/ppm/ppmtompeg/examples/payam18.param b/converter/ppm/ppmtompeg/examples/payam18.param
new file mode 100644
index 00000000..7f7b767e
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/payam18.param
@@ -0,0 +1,34 @@
+# parameter file for payam's images
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/payam18.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PNM
+
+INPUT_CONVERT *
+INPUT_DIR	/n/picasso/users/keving/encode/input/payam
+
+INPUT
+kh*.pnm	[1-39]
+END_INPUT
+
+
+# motion vector search paramters
+
+# FULL or HALF -- must be upper case
+PIXEL		HALF
+
+# means +/- this many pixels
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/pnm.param b/converter/ppm/ppmtompeg/examples/pnm.param
new file mode 100644
index 00000000..6fce2be4
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/pnm.param
@@ -0,0 +1,37 @@
+# speed test parameter file
+
+PATTERN		I
+OUTPUT		output/food
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	links/flowg
+
+INPUT
+sflowg.*.ppm	[01-10]
+END_INPUT
+
+
+# motion vector search parameters
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		FULL
+
+# means +/- this many pixels
+RANGE		8
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+IQSCALE		31
+PQSCALE		10
+BQSCALE		25
+
diff --git a/converter/ppm/ppmtompeg/examples/ppm.param b/converter/ppm/ppmtompeg/examples/ppm.param
new file mode 100644
index 00000000..6fce2be4
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/ppm.param
@@ -0,0 +1,37 @@
+# speed test parameter file
+
+PATTERN		I
+OUTPUT		output/food
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	links/flowg
+
+INPUT
+sflowg.*.ppm	[01-10]
+END_INPUT
+
+
+# motion vector search parameters
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		FULL
+
+# means +/- this many pixels
+RANGE		8
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+IQSCALE		31
+PQSCALE		10
+BQSCALE		25
+
diff --git a/converter/ppm/ppmtompeg/examples/prof.b.param b/converter/ppm/ppmtompeg/examples/prof.b.param
new file mode 100644
index 00000000..2b8253fd
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/prof.b.param
@@ -0,0 +1,48 @@
+# test suite parameter file
+
+PATTERN		IBBBBBBBBI
+OUTPUT		output/food
+
+BASE_FILE_FORMAT	PPM
+INPUT_CONVERT	giftoppm *
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+INPUT_DIR	Test/ts
+
+INPUT
+med*.gif	[030-039]
+END_INPUT
+
+
+
+# all of the remaining options have to do with the motion search and qscale
+#
+# change this only if you're unsatisfied with the CPU time or quality, or
+# are experimenting
+#
+
+# if this appears in the file, then in addition to testing luminance when
+# computing motion vectors, program will also take into account chrominance
+#
+# this option MUST appear before ERROR option, or it will be ignored
+#
+# CHROMINANCE
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		FULL
+
+# means +/- this many pixels
+RANGE		8
+
+# YES or NO -- must be upper case
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
diff --git a/converter/ppm/ppmtompeg/examples/prof.bhalf.param b/converter/ppm/ppmtompeg/examples/prof.bhalf.param
new file mode 100644
index 00000000..8d6de83a
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/prof.bhalf.param
@@ -0,0 +1,48 @@
+# test suite parameter file
+
+PATTERN		IBBBBBBBBI
+OUTPUT		output/food
+
+BASE_FILE_FORMAT	PPM
+INPUT_CONVERT	giftoppm *
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+INPUT_DIR	Test/ts
+
+INPUT
+med*.gif	[030-039]
+END_INPUT
+
+
+
+# all of the remaining options have to do with the motion search and qscale
+#
+# change this only if you're unsatisfied with the CPU time or quality, or
+# are experimenting
+#
+
+# if this appears in the file, then in addition to testing luminance when
+# computing motion vectors, program will also take into account chrominance
+#
+# this option MUST appear before ERROR option, or it will be ignored
+#
+# CHROMINANCE
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		HALF
+
+# means +/- this many pixels
+RANGE		8
+
+# YES or NO -- must be upper case
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	CROSS2
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
diff --git a/converter/ppm/ppmtompeg/examples/prof.param b/converter/ppm/ppmtompeg/examples/prof.param
new file mode 100644
index 00000000..591eaa67
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/prof.param
@@ -0,0 +1,36 @@
+# speed test parameter file
+
+PATTERN I
+#PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	TWOLEVEL
+BSEARCH_ALG	CROSS2
+
+#REFERENCE_FRAME	DECODED
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/prof.ss.param b/converter/ppm/ppmtompeg/examples/prof.ss.param
new file mode 100644
index 00000000..ef339e7a
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/prof.ss.param
@@ -0,0 +1,48 @@
+# test suite parameter file
+
+PATTERN		IPPPPPPPPP
+OUTPUT		output/food
+
+BASE_FILE_FORMAT	PPM
+INPUT_CONVERT	giftoppm *
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+INPUT_DIR	Test/ts
+
+INPUT
+med*.gif	[030-039]
+END_INPUT
+
+
+
+# all of the remaining options have to do with the motion search and qscale
+#
+# change this only if you're unsatisfied with the CPU time or quality, or
+# are experimenting
+#
+
+# if this appears in the file, then in addition to testing luminance when
+# computing motion vectors, program will also take into account chrominance
+#
+# this option MUST appear before ERROR option, or it will be ignored
+#
+# CHROMINANCE
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		FULL
+
+# means +/- this many pixels
+RANGE		16
+
+# YES or NO -- must be upper case
+PSEARCH_ALG	SUBSAMPLE
+BSEARCH_ALG	SIMPLE
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
diff --git a/converter/ppm/ppmtompeg/examples/prof2.param b/converter/ppm/ppmtompeg/examples/prof2.param
new file mode 100644
index 00000000..4073606a
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/prof2.param
@@ -0,0 +1,36 @@
+# speed test parameter file
+
+PATTERN IPPP
+#PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	TWOLEVEL
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
+
diff --git a/converter/ppm/ppmtompeg/examples/prof3.param b/converter/ppm/ppmtompeg/examples/prof3.param
new file mode 100644
index 00000000..4581eade
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/prof3.param
@@ -0,0 +1,36 @@
+# speed test parameter file
+
+PATTERN IBB
+#PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	TWOLEVEL
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
+
diff --git a/converter/ppm/ppmtompeg/examples/prof4.param b/converter/ppm/ppmtompeg/examples/prof4.param
new file mode 100644
index 00000000..583fb43c
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/prof4.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	TWOLEVEL
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
+
diff --git a/converter/ppm/ppmtompeg/examples/remote.test b/converter/ppm/ppmtompeg/examples/remote.test
new file mode 100644
index 00000000..d548510f
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/remote.test
@@ -0,0 +1,85 @@
+# speed test parameter file
+
+PATTERN		ibbpbbpbbpbbpbb
+OUTPUT		/n/picasso/users/keving/encode/output/good.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	cat *.Y *.U *.V
+
+INPUT_DIR	/n/picasso/users/keving/links/flowg
+
+INPUT
+sflowg.*	[0-40]
+END_INPUT
+
+# the following two are optional  (default = 10, 60)
+
+# number of frames to do initially to gauge speed of machine
+PARALLEL_TEST_FRAMES	3
+
+# number of seconds per chunk thereafter
+PARALLEL_TIME_CHUNKS	30
+
+
+PARALLEL
+# lines must be of form "machine <whitespace> username <whitespace> executable"
+# these guys are sorta slow:
+#elmer-fudd	keving	~keving/src/encode/bin/sun/mpeg_encode
+#zonker		keving	~keving/src/encode/bin/sun/mpeg_encode
+#roger-rabbit	keving	~keving/src/encode/bin/sun/mpeg_encode
+#tweety		keving	~keving/src/encode/bin/sun/mpeg_encode
+#mickey		keving	~keving/src/encode/bin/mickey/mpeg_encode
+#
+REMOTE zonker keving ~keving/encode/src/mpeg_encode ~keving/encode/examples/remote.test
+REMOTE linus keving ~keving/encode/src/mpeg_encode ~keving/encode/examples/remote.test
+REMOTE roger-rabbit keving ~keving/encode/src/mpeg_encode ~keving/encode/examples/remote.test
+REMOTE bugs-bunny keving ~keving/encode/src/mpeg_encode ~keving/encode/examples/remote.test
+REMOTE elmer-fudd keving ~keving/encode/src/mpeg_encode ~keving/encode/examples/remote.test
+# these guys are pretty fast:
+#
+#big-bird	keving	~keving/src/encode/bin/hp/mpeg_encode
+#gumby		keving	~keving/src/encode/bin/hp/mpeg_encode
+#charlie-brown	keving	~keving/src/encode/bin/dec/mpeg_encode
+#woodstock	keving	~keving/src/encode/bin/dec/mpeg_encode
+#bugs-bunny	keving	~keving/src/encode/bin/sun/mpeg_encode
+#
+# remotes
+#
+#REMOTE anaconda	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE adder	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE moccasin	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE cobra	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE boa	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE asp	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE rattler	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE viper	keving	~keving/mpeg_encode ~keving/parallel.test
+# mamba doesn't seem to work for whatever reason...don't know why
+#REMOTE mamba	keving	~keving/mpeg_encode ~keving/parallel.test
+#REMOTE cse.lbl.gov kevin	~kevin/mpeg_encode ~kevin/parallel.test
+#REMOTE roger-rabbit keving	~keving/src/encode/bin/sun/mpeg_encode ~keving/src/encode/ParamExamples/parallel.test
+END_PARALLEL
+
+
+# motion vector search parameters
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		FULL
+
+# means +/- this many pixels
+RANGE		4
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search1.param b/converter/ppm/ppmtompeg/examples/search1.param
new file mode 100644
index 00000000..779ffa0f
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search1.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard1.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		FULL
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search10.param b/converter/ppm/ppmtompeg/examples/search10.param
new file mode 100644
index 00000000..c44c7c72
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search10.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard10.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search11.param b/converter/ppm/ppmtompeg/examples/search11.param
new file mode 100644
index 00000000..78935268
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search11.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard11.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		FULL
+
+RANGE		20
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/search12.param b/converter/ppm/ppmtompeg/examples/search12.param
new file mode 100644
index 00000000..d7a115c3
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search12.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard12.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search13.param b/converter/ppm/ppmtompeg/examples/search13.param
new file mode 100644
index 00000000..80bb57f5
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search13.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard13.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		20
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search14.param b/converter/ppm/ppmtompeg/examples/search14.param
new file mode 100644
index 00000000..af0ebb9c
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search14.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/search15.param b/converter/ppm/ppmtompeg/examples/search15.param
new file mode 100644
index 00000000..1df18350
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search15.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard15.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		FULL
+
+RANGE		20
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/search16.param b/converter/ppm/ppmtompeg/examples/search16.param
new file mode 100644
index 00000000..3523dce3
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search16.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard16.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		20
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search17.param b/converter/ppm/ppmtompeg/examples/search17.param
new file mode 100644
index 00000000..89c3cb91
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search17.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard17.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		20
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/search18.param b/converter/ppm/ppmtompeg/examples/search18.param
new file mode 100644
index 00000000..d659d914
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search18.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard18.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search19.5.param b/converter/ppm/ppmtompeg/examples/search19.5.param
new file mode 100644
index 00000000..22827fce
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search19.5.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-15]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/search19.param b/converter/ppm/ppmtompeg/examples/search19.param
new file mode 100644
index 00000000..88f9d613
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search19.param
@@ -0,0 +1,42 @@
+# speed test parameter file
+
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/charlie-brown/project/mm/mpeg/mpeg_encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+
+
+
+PATTERN		IBBPBBPBBPBBPBB
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+# LOGARITHMIC, TWOLEVEL, SUBSAMPLE, EXHAUSTIVE
+PSEARCH_ALG	LOGARITHMIC
+
+# CROSS2, SIMPLE
+BSEARCH_ALG	CROSS2
+
+# DECODED or ORIGINAL
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/search2.param b/converter/ppm/ppmtompeg/examples/search2.param
new file mode 100644
index 00000000..c4f6300c
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search2.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard2.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		FULL
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/search20.param b/converter/ppm/ppmtompeg/examples/search20.param
new file mode 100644
index 00000000..efd05f6d
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search20.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard20.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		FULL
+
+RANGE		10
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search21.param b/converter/ppm/ppmtompeg/examples/search21.param
new file mode 100644
index 00000000..6acb79ac
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search21.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard21.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search22.param b/converter/ppm/ppmtompeg/examples/search22.param
new file mode 100644
index 00000000..252cb25b
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search22.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard22.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		FULL
+
+RANGE		20
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search23.param b/converter/ppm/ppmtompeg/examples/search23.param
new file mode 100644
index 00000000..5e7a7620
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search23.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard23.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		20
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search24.param b/converter/ppm/ppmtompeg/examples/search24.param
new file mode 100644
index 00000000..0ca71e6d
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search24.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard24.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	SUBSAMPLE
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search25.param b/converter/ppm/ppmtompeg/examples/search25.param
new file mode 100644
index 00000000..724ce5a4
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search25.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard25.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	SUBSAMPLE
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search26.param b/converter/ppm/ppmtompeg/examples/search26.param
new file mode 100644
index 00000000..1a7081cd
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search26.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard26.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		FULL
+
+RANGE		10
+
+PSEARCH_ALG	SUBSAMPLE
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search27.param b/converter/ppm/ppmtompeg/examples/search27.param
new file mode 100644
index 00000000..49da7e7a
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search27.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard27.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		FULL
+
+RANGE		20
+
+PSEARCH_ALG	SUBSAMPLE
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search28.param b/converter/ppm/ppmtompeg/examples/search28.param
new file mode 100644
index 00000000..f78331aa
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search28.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard28.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		20
+
+PSEARCH_ALG	SUBSAMPLE
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search29.param b/converter/ppm/ppmtompeg/examples/search29.param
new file mode 100644
index 00000000..52f89a90
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search29.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard29.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	TWOLEVEL
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search3.param b/converter/ppm/ppmtompeg/examples/search3.param
new file mode 100644
index 00000000..4c00af6c
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search3.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard3.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		FULL
+
+RANGE		20
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search30.param b/converter/ppm/ppmtompeg/examples/search30.param
new file mode 100644
index 00000000..5664dbb8
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search30.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard30.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		20
+
+PSEARCH_ALG	TWOLEVEL
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search31.param b/converter/ppm/ppmtompeg/examples/search31.param
new file mode 100644
index 00000000..3d8bc0cd
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search31.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	TWOLEVEL
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search32.param b/converter/ppm/ppmtompeg/examples/search32.param
new file mode 100644
index 00000000..a4675cee
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search32.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard32.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		4
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search33.param b/converter/ppm/ppmtompeg/examples/search33.param
new file mode 100644
index 00000000..465132c6
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search33.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard33.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		4
+
+PSEARCH_ALG	TWOLEVEL
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search34.param b/converter/ppm/ppmtompeg/examples/search34.param
new file mode 100644
index 00000000..f53a91f3
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search34.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard34.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		4
+
+PSEARCH_ALG	SUBSAMPLE
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search35.param b/converter/ppm/ppmtompeg/examples/search35.param
new file mode 100644
index 00000000..5a7fa27f
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search35.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard35.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		4
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search36.param b/converter/ppm/ppmtompeg/examples/search36.param
new file mode 100644
index 00000000..66fb8e7f
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search36.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard36.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		4
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search37.param b/converter/ppm/ppmtompeg/examples/search37.param
new file mode 100644
index 00000000..f5f5d4d3
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search37.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard37.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		4
+
+PSEARCH_ALG	SUBSAMPLE
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search38.param b/converter/ppm/ppmtompeg/examples/search38.param
new file mode 100644
index 00000000..b8186ce2
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search38.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard38.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		4
+
+PSEARCH_ALG	TWOLEVEL
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search39.param b/converter/ppm/ppmtompeg/examples/search39.param
new file mode 100644
index 00000000..ab18d28b
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search39.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard39.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		4
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search4.param b/converter/ppm/ppmtompeg/examples/search4.param
new file mode 100644
index 00000000..68285e6d
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search4.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard4.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		20
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/search40.param b/converter/ppm/ppmtompeg/examples/search40.param
new file mode 100644
index 00000000..3fd65b6e
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search40.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard40.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		8
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search41.param b/converter/ppm/ppmtompeg/examples/search41.param
new file mode 100644
index 00000000..3a47baf7
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search41.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard41.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		8
+
+PSEARCH_ALG	TWOLEVEL
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search42.param b/converter/ppm/ppmtompeg/examples/search42.param
new file mode 100644
index 00000000..3ade2c85
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search42.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard42.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		8
+
+PSEARCH_ALG	SUBSAMPLE
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search43.param b/converter/ppm/ppmtompeg/examples/search43.param
new file mode 100644
index 00000000..e2c044a4
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search43.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard43.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		8
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search44.param b/converter/ppm/ppmtompeg/examples/search44.param
new file mode 100644
index 00000000..47c97e89
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search44.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard44.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		8
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search45.param b/converter/ppm/ppmtompeg/examples/search45.param
new file mode 100644
index 00000000..c4131d33
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search45.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard45.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		8
+
+PSEARCH_ALG	SUBSAMPLE
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search46.param b/converter/ppm/ppmtompeg/examples/search46.param
new file mode 100644
index 00000000..cc9c67bf
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search46.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard46.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		8
+
+PSEARCH_ALG	TWOLEVEL
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search47.param b/converter/ppm/ppmtompeg/examples/search47.param
new file mode 100644
index 00000000..7527228e
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search47.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard47.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		8
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search48.param b/converter/ppm/ppmtompeg/examples/search48.param
new file mode 100644
index 00000000..3d75a6a2
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search48.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	SUBSAMPLE
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/search49.param b/converter/ppm/ppmtompeg/examples/search49.param
new file mode 100644
index 00000000..c25ab724
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search49.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	TWOLEVEL
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/search5.param b/converter/ppm/ppmtompeg/examples/search5.param
new file mode 100644
index 00000000..5a1ad629
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search5.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard5.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		20
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/search50.param b/converter/ppm/ppmtompeg/examples/search50.param
new file mode 100644
index 00000000..6711ebb7
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search50.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/search51.param b/converter/ppm/ppmtompeg/examples/search51.param
new file mode 100644
index 00000000..6609e381
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search51.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-19]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	EXHAUSTIVE
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/search52.5.param b/converter/ppm/ppmtompeg/examples/search52.5.param
new file mode 100644
index 00000000..be34be4b
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search52.5.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-15]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/search52.param b/converter/ppm/ppmtompeg/examples/search52.param
new file mode 100644
index 00000000..246aa978
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search52.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/search53.param b/converter/ppm/ppmtompeg/examples/search53.param
new file mode 100644
index 00000000..81afb3bc
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search53.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-15]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	EXHAUSTIVE
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/search6.param b/converter/ppm/ppmtompeg/examples/search6.param
new file mode 100644
index 00000000..47c36a0c
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search6.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard6.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		20
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/search7.param b/converter/ppm/ppmtompeg/examples/search7.param
new file mode 100644
index 00000000..f5d1224d
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search7.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard7.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		FULL
+
+RANGE		10
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search8.param b/converter/ppm/ppmtompeg/examples/search8.param
new file mode 100644
index 00000000..f3b17e96
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search8.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard8.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		20
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/search9.param b/converter/ppm/ppmtompeg/examples/search9.param
new file mode 100644
index 00000000..80051112
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/search9.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard9.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		FULL
+
+RANGE		20
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/seq.param b/converter/ppm/ppmtompeg/examples/seq.param
new file mode 100644
index 00000000..665c22a7
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/seq.param
@@ -0,0 +1,36 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/zonker/video/sequoia.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	320x240
+
+INPUT_CONVERT	/n/zonker/video/getframe *
+
+INPUT_DIR	/n/zonker/video/seqframes
+
+INPUT
+# really goes up to 200
+*	[0-1000]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		15
+PQSCALE		18
+BQSCALE		30
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/sequoia.param b/converter/ppm/ppmtompeg/examples/sequoia.param
new file mode 100644
index 00000000..1b93d880
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/sequoia.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/sequoia.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	352x240
+
+INPUT_CONVERT	djpeg *
+
+INPUT_DIR	/n/zonker/video/seqframes
+
+INPUT
+sequoia*.jpeg	[378-600]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		22
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/sequoia19.param b/converter/ppm/ppmtompeg/examples/sequoia19.param
new file mode 100644
index 00000000..52e5a72b
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/sequoia19.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/charlie-brown/project/mm/mpeg/mpeg_encode/output/seq.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	352x240
+
+INPUT_CONVERT	/n/zonker/video/seqframes/gframe /n/video/video/sequoia * 640x480.100 352 240
+
+INPUT_DIR	/n/zonker/video
+
+INPUT
+*	[0-199]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/sequoia2.param b/converter/ppm/ppmtompeg/examples/sequoia2.param
new file mode 100644
index 00000000..676cc2e4
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/sequoia2.param
@@ -0,0 +1,36 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/sequoia.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	352x240
+
+INPUT_CONVERT	djpeg *
+
+INPUT_DIR	/n/zonker/video/seqframes
+
+INPUT
+# really goes up to 200
+sequoia*.jpeg	[001-200]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		15
+PQSCALE		18
+BQSCALE		30
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/simple.param b/converter/ppm/ppmtompeg/examples/simple.param
new file mode 100644
index 00000000..14964829
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/simple.param
@@ -0,0 +1,40 @@
+# Simple parameter file
+
+OUTPUT		./test.mpg
+GOP_SIZE	15
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/charlie-brown/project/mm/mpeg/mpeg_encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-14]
+END_INPUT
+
+PATTERN		IBBPBBPBBPBBPBBPBBPBBP
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10 4
+
+# LOGARITHMIC, TWOLEVEL, SUBSAMPLE, EXHAUSTIVE
+PSEARCH_ALG	 LOGARITHMIC
+
+# CROSS2, SIMPLE
+BSEARCH_ALG	CROSS2
+
+# DECODED or ORIGINAL
+REFERENCE_FRAME	ORIGINAL
+
diff --git a/converter/ppm/ppmtompeg/examples/slice.param b/converter/ppm/ppmtompeg/examples/slice.param
new file mode 100644
index 00000000..308d2053
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/slice.param
@@ -0,0 +1,47 @@
+# test suite parameter file
+
+PATTERN		IIIIIIIII
+OUTPUT		ts.mpg
+
+BASE_FILE_FORMAT	PPM
+INPUT_CONVERT	giftoppm *
+GOP_SIZE		1
+SLICES_PER_FRAME	170000
+
+INPUT_DIR	ts
+
+INPUT
+med*.gif	[030-034]
+END_INPUT
+
+
+
+# all of the remaining options have to do with the motion search and qscale
+#
+# change this only if you're unsatisfied with the CPU time or quality, or
+# are experimenting
+#
+
+# if this appears in the file, then in addition to testing luminance when
+# computing motion vectors, program will also take into account chrominance
+#
+# this option MUST appear before ERROR option, or it will be ignored
+#
+# CHROMINANCE
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		HALF
+
+# means +/- this many pixels
+RANGE		4
+
+# YES or NO -- must be upper case
+SUBSAMPLE	NO
+
+IQSCALE		31
+PQSCALE		10
+BQSCALE		25
+
diff --git a/converter/ppm/ppmtompeg/examples/slimed.param b/converter/ppm/ppmtompeg/examples/slimed.param
new file mode 100644
index 00000000..b5938b94
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/slimed.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		I
+OUTPUT		/n/picasso/users/keving/encode/output/slimed.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	480x360
+
+INPUT_CONVERT	djpeg *
+
+INPUT_DIR	../input/slimed
+
+INPUT
+slimed.*.jpeg	[1-100]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		20
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/slowspeed.param b/converter/ppm/ppmtompeg/examples/slowspeed.param
new file mode 100644
index 00000000..321313be
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/slowspeed.param
@@ -0,0 +1,38 @@
+# speed test parameter file
+
+PATTERN		ibbpbbpbbpbbpbb
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	cat *.Y *.U *.V
+
+INPUT_DIR	/n/picasso/project/mm/mpeg/mpeg_encode/input/flowg
+
+INPUT
+sflowg.*	[0-149]
+END_INPUT
+
+# motion vector search parameters
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		HALF
+
+# means +/- this many pixels
+RANGE		12
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	CROSS2
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+REFERENCE_FRAME	ORIGINAL
+
diff --git a/converter/ppm/ppmtompeg/examples/stanford.param b/converter/ppm/ppmtompeg/examples/stanford.param
new file mode 100644
index 00000000..4c87334c
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/stanford.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/stanford.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		4
+PQSCALE		4
+BQSCALE		8
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		8
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/subtest.param b/converter/ppm/ppmtompeg/examples/subtest.param
new file mode 100644
index 00000000..7fb4f585
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/subtest.param
@@ -0,0 +1,34 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard18.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	SUB4
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg/yuvsub
+
+INPUT
+*	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/temp.param b/converter/ppm/ppmtompeg/examples/temp.param
new file mode 100644
index 00000000..209fdfb4
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/temp.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/flow.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/flowg
+
+INPUT
+sflowg.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/template.param b/converter/ppm/ppmtompeg/examples/template.param
new file mode 100644
index 00000000..66b6dd98
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/template.param
@@ -0,0 +1,154 @@
+# parameter file template with lots of comments to assist you
+#
+# you can use this as a template, copying it to a separate file then modifying
+# the copy
+#
+#
+# any line beginning with '#' is a comment
+#
+# no line should be longer than 255 characters
+#
+#
+# general format of each line is:
+#	<option> <spaces and/or tabs> <value>
+#
+# lines can generally be in any order
+#
+# an exception is the option 'INPUT' which must be followed by input
+# files in the order in which they must appear, followed by 'END_INPUT'
+#
+# Also, if you use the `command` method of generating input file names,
+# the command will only be executed in the INPUT_DIR if INPUT_DIR preceeds
+# the INPUT parameter.
+#
+# <option> MUST be in UPPER CASE
+#
+
+PATTERN		IBBPBBPBBPBBPBBP
+OUTPUT		output.mpg
+
+# mpeg_encode really only accepts 3 different file formats, but using a
+# conversion statement it can effectively handle ANY file format
+#
+# You must specify the type of the input files.  The choices are:
+#    YUV, PPM, JMOVIE, Y, JPEG, PNM
+#	(must be upper case)
+#
+BASE_FILE_FORMAT	YUV
+
+#
+# if YUV format (or using parallel version), must provide width and height
+# YUV_SIZE	widthxheight
+# this option is ignored if BASE_FILE_FORMAT is not YUV and you're running
+# on just one machine
+#
+YUV_SIZE	352x240
+
+# If you are using YUV, there are different supported file formats.
+# EYUV or UCB are the same as previous versions of this encoder.
+# (All the Y's, then U's then V's, in 4:2:0 subsampling.)
+# Other formats, such as Abekas, Phillips, or a general format are
+# permissible, the general format is a string of Y's, U's, and V's
+# to specify the file order.
+
+INPUT_FORMAT UCB
+
+# the conversion statement
+#
+# Each occurrence of '*' will be replaced by the input file
+#
+# e.g., if you have a bunch of GIF files, then this might be:
+#	INPUT_CONVERT	giftoppm *
+#
+# e.g., if you have a bunch of files like a.Y a.U a.V, etc., then:
+#	INPUT_CONVERT	cat *.Y *.U *.V
+#
+# e.g., if you are grabbing from laser disc you might have something like
+#	INPUT_CONVERT	goto frame *; grabppm
+# 'INPUT_CONVERT *' means the files are already in the base file format
+#
+INPUT_CONVERT	*
+
+# number of frames in a GOP.
+#
+# since each GOP must have at least one I-frame, the encoder will find the
+# the first I-frame after GOP_SIZE frames to start the next GOP
+#
+# later, will add more flexible GOP signalling
+#
+GOP_SIZE	16
+
+# number of slices in a frame
+#
+# 1 is a good number.  another possibility is the number of macroblock rows
+# (which is the height divided by 16)
+#
+SLICES_PER_FRAME	1
+
+# directory to get all input files from (makes this file easier to read)
+INPUT_DIR	../input/tennis
+
+# There are a bunch of ways to specify the input files.
+# from a simple one-per-line listing, to the following 
+# way of numbering them.  See the manual for more information.
+INPUT
+# '*' is replaced by the numbers 01, 02, 03, 04
+# if I instead do [01-11], it would be 01, 02, ..., 09, 10, 11
+# if I instead do [1-11], it would be 1, 2, 3, ..., 9, 10, 11
+# if I instead do [1-11+3], it would be 1, 4, 7, 10
+# the program assumes none of your input files has a name ending in ']'
+# if you do, too bad!!!
+#
+#
+stennis.*.yuv	[0-23]
+# can have more files here if you want...there is no limit on the number
+# of files
+END_INPUT
+
+
+
+# Many of the remaining options have to do with the motion search and qscale
+
+# FULL or HALF -- must be upper case
+PIXEL		HALF
+
+# means +/- this many pixels for both P and B frame searches
+# specify two numbers if you wish to serc different ranges in the two.
+RANGE		10
+
+# this must be one of {EXHAUSTIVE, SUBSAMPLE, LOGARITHMIC}
+PSEARCH_ALG	LOGARITHMIC
+
+# this must be one of {SIMPLE, CROSS2, EXHAUSTIVE}
+#
+# note that EXHAUSTIVE is really, really, really slow
+#
+BSEARCH_ALG	CROSS2
+
+#
+# these specify the q-scale for I, P, and B frames
+# (values must be between 1 and 31)
+# These are the Qscale values for the entire frame in variable bit-rate
+# mode, and starting points (but not important) for constant bit rate
+#
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# this must be ORIGINAL or DECODED
+REFERENCE_FRAME	ORIGINAL
+
+# for parallel parameters see parallel.param in the exmaples subdirectory
+
+# if you want constant bit-rate mode, specify it as follows (number is bits/sec):
+BIT_RATE  1000000
+
+# To specify the buffer size (327680 is default, measused in bits, for 16bit words)
+BUFFER_SIZE 327680
+
+# The frame rate is the number of frames/second (legal values:
+# 23.976, 24, 25, 29.97, 30, 50 ,59.94, 60
+FRAME_RATE 30
+
+# There are many more options, see the users manual for examples....
+# ASPECT_RATIO, USER_DATA, GAMMA, IQTABLE, etc.
diff --git a/converter/ppm/ppmtompeg/examples/tennis.param b/converter/ppm/ppmtompeg/examples/tennis.param
new file mode 100644
index 00000000..978e1904
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/tennis.param
@@ -0,0 +1,37 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		output/tennis.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	cat *.Y *.U *.V
+
+INPUT_DIR	links/tennis
+
+INPUT
+stennis.*	[0-149]
+END_INPUT
+
+
+# motion vector search parameters
+
+# MAD or MSE -- must be upper case
+ERROR		MAD
+
+# FULL or HALF -- must be upper case
+PIXEL		HALF
+
+# means +/- this many pixels
+RANGE		8
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	CROSS2
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
diff --git a/converter/ppm/ppmtompeg/examples/tennis18.param b/converter/ppm/ppmtompeg/examples/tennis18.param
new file mode 100644
index 00000000..48979f3e
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/tennis18.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/tennis.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/tennis
+
+INPUT
+stennis.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/tennis19.5.param b/converter/ppm/ppmtompeg/examples/tennis19.5.param
new file mode 100644
index 00000000..196b7a28
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/tennis19.5.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/tennis.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/tennis
+
+INPUT
+stennis.*.yuv	[0-15]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/tennis19.param b/converter/ppm/ppmtompeg/examples/tennis19.param
new file mode 100644
index 00000000..542c237c
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/tennis19.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/tennis.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/tennis
+
+INPUT
+stennis.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/tennis48.param b/converter/ppm/ppmtompeg/examples/tennis48.param
new file mode 100644
index 00000000..9db63638
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/tennis48.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/tennis.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/tennis
+
+INPUT
+stennis.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	SUBSAMPLE
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/tennis49.param b/converter/ppm/ppmtompeg/examples/tennis49.param
new file mode 100644
index 00000000..cbecb035
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/tennis49.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/tennis.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/tennis
+
+INPUT
+stennis.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	TWOLEVEL
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/tennis50.param b/converter/ppm/ppmtompeg/examples/tennis50.param
new file mode 100644
index 00000000..bbfe3cb0
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/tennis50.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/tennis.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/tennis
+
+INPUT
+stennis.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/tennis52.5.param b/converter/ppm/ppmtompeg/examples/tennis52.5.param
new file mode 100644
index 00000000..a00e4322
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/tennis52.5.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/tennis.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/tennis
+
+INPUT
+stennis.*.yuv	[0-15]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/tennis52.param b/converter/ppm/ppmtompeg/examples/tennis52.param
new file mode 100644
index 00000000..0ae84f00
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/tennis52.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/tennis.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/tennis
+
+INPUT
+stennis.*.yuv	[0-149]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/tennis53.param b/converter/ppm/ppmtompeg/examples/tennis53.param
new file mode 100644
index 00000000..bc311376
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/tennis53.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/tennis.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/tennis
+
+INPUT
+stennis.*.yuv	[0-15]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	EXHAUSTIVE
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/tennisbug.param b/converter/ppm/ppmtompeg/examples/tennisbug.param
new file mode 100644
index 00000000..4a655b4a
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/tennisbug.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IPPPPPPPPPPP
+
+OUTPUT		/n/picasso/users/keving/encode/output/tennis.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	../input/tennis
+
+INPUT
+stennis.*.yuv	[0-49]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		1
+PQSCALE		1
+BQSCALE		1
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/testp.param b/converter/ppm/ppmtompeg/examples/testp.param
new file mode 100644
index 00000000..ea8dee18
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/testp.param
@@ -0,0 +1,45 @@
+# speed test parameter file
+
+PATTERN		IPPPPPPPPP
+
+OUTPUT		/n/picasso/users/keving/encode/output/testp.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input
+
+INPUT
+me.0.ppm
+me.0.ppm
+me.0.ppm
+me.0.ppm
+me.0.ppm
+me.0.ppm
+me.0.ppm
+me.0.ppm
+me.0.ppm
+me.0.ppm
+me.0.ppm
+END_INPUT
+
+# quality parameters
+
+IQSCALE		4
+PQSCALE		4
+BQSCALE		4
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/walk.param b/converter/ppm/ppmtompeg/examples/walk.param
new file mode 100644
index 00000000..52be9d2e
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/walk.param
@@ -0,0 +1,61 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/walk1.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	320x240
+
+INPUT_CONVERT	zcat *
+
+INPUT_DIR	/n/zonker/cluster/keving/walk
+
+INPUT
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+f.*.Z	[1-1800]
+END_INPUT
+
+PARALLEL_TEST_FRAMES	10
+PARALLEL_TIME_CHUNKS	30
+
+
+IO_SERVER_CONVERT *
+SLAVE_CONVERT zcat *
+
+PARALLEL
+#charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+#woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+END_PARALLEL
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/walk1.param b/converter/ppm/ppmtompeg/examples/walk1.param
new file mode 100644
index 00000000..52be9d2e
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/walk1.param
@@ -0,0 +1,61 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/walk1.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	320x240
+
+INPUT_CONVERT	zcat *
+
+INPUT_DIR	/n/zonker/cluster/keving/walk
+
+INPUT
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+f.*.Z	[1-1800]
+END_INPUT
+
+PARALLEL_TEST_FRAMES	10
+PARALLEL_TIME_CHUNKS	30
+
+
+IO_SERVER_CONVERT *
+SLAVE_CONVERT zcat *
+
+PARALLEL
+#charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+#woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+END_PARALLEL
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/walk18.param b/converter/ppm/ppmtompeg/examples/walk18.param
new file mode 100644
index 00000000..80ed48f3
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/walk18.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/walk19.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	320x240
+
+INPUT_CONVERT	zcat *
+
+INPUT_DIR	/n/zonker/cluster/keving/walk
+
+INPUT
+f.*.Z	[1-200]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/walk19.5.param b/converter/ppm/ppmtompeg/examples/walk19.5.param
new file mode 100644
index 00000000..7fb724d1
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/walk19.5.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/walk19.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	320x240
+
+INPUT_CONVERT	zcat *
+
+INPUT_DIR	/n/zonker/cluster/keving/walk
+
+INPUT
+f.*.Z	[1-16]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/walk19.param b/converter/ppm/ppmtompeg/examples/walk19.param
new file mode 100644
index 00000000..acc8f627
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/walk19.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/walk19.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	320x240
+
+INPUT_CONVERT	zcat *
+
+INPUT_DIR	/n/zonker/cluster/keving/walk
+
+INPUT
+f.*.Z	[1-200]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/walk2.param b/converter/ppm/ppmtompeg/examples/walk2.param
new file mode 100644
index 00000000..cbb28705
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/walk2.param
@@ -0,0 +1,61 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/walk2.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	320x240
+
+INPUT_CONVERT	zcat *
+
+INPUT_DIR	/n/zonker/cluster/keving/walk
+
+INPUT
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+f.*.Z	[1-1800]
+END_INPUT
+
+PARALLEL_TEST_FRAMES	10
+PARALLEL_TIME_CHUNKS	30
+
+
+IO_SERVER_CONVERT *
+SLAVE_CONVERT zcat *
+
+PARALLEL
+#charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+#woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+END_PARALLEL
+
+# quality parameters
+
+IQSCALE		6
+PQSCALE		8
+BQSCALE		15
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/examples/walk3.param b/converter/ppm/ppmtompeg/examples/walk3.param
new file mode 100644
index 00000000..86a30812
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/walk3.param
@@ -0,0 +1,61 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/walk3.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	320x240
+
+INPUT_CONVERT	zcat *
+
+INPUT_DIR	/n/zonker/cluster/keving/walk
+
+INPUT
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+f.*.Z	[1-1800]
+END_INPUT
+
+PARALLEL_TEST_FRAMES	10
+PARALLEL_TIME_CHUNKS	30
+
+
+IO_SERVER_CONVERT *
+SLAVE_CONVERT zcat *
+
+PARALLEL
+#charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+#woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+END_PARALLEL
+
+# quality parameters
+
+IQSCALE		6
+PQSCALE		8
+BQSCALE		15
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	TWOLEVEL
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/walk4.param b/converter/ppm/ppmtompeg/examples/walk4.param
new file mode 100644
index 00000000..12d1f505
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/walk4.param
@@ -0,0 +1,61 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+OUTPUT		/n/picasso/users/keving/encode/output/walk4.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	320x240
+
+INPUT_CONVERT	zcat *
+
+INPUT_DIR	/n/zonker/cluster/keving/walk
+
+INPUT
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+f.*.Z	[1-1800]
+END_INPUT
+
+PARALLEL_TEST_FRAMES	10
+PARALLEL_TIME_CHUNKS	30
+
+
+IO_SERVER_CONVERT *
+SLAVE_CONVERT zcat *
+
+PARALLEL
+#charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+#woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+END_PARALLEL
+
+# quality parameters
+
+IQSCALE		4
+PQSCALE		6
+BQSCALE		10
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		7
+
+PSEARCH_ALG	TWOLEVEL
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/walk48.param b/converter/ppm/ppmtompeg/examples/walk48.param
new file mode 100644
index 00000000..2c6df697
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/walk48.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/walk19.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	320x240
+
+INPUT_CONVERT	zcat *
+
+INPUT_DIR	/n/zonker/cluster/keving/walk
+
+INPUT
+f.*.Z	[1-200]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	SUBSAMPLE
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/walk49.param b/converter/ppm/ppmtompeg/examples/walk49.param
new file mode 100644
index 00000000..72c17a94
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/walk49.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/walk19.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	320x240
+
+INPUT_CONVERT	zcat *
+
+INPUT_DIR	/n/zonker/cluster/keving/walk
+
+INPUT
+f.*.Z	[1-200]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	TWOLEVEL
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/walk5.param b/converter/ppm/ppmtompeg/examples/walk5.param
new file mode 100644
index 00000000..e792064f
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/walk5.param
@@ -0,0 +1,62 @@
+# speed test parameter file
+
+#PATTERN		IBBPBBPBBPBBPBB
+PATTERN		I
+OUTPUT		/n/picasso/users/keving/encode/output/walk5.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PNM
+YUV_SIZE	320x240
+
+INPUT_CONVERT	zcat *
+
+INPUT_DIR	/n/zonker/cluster/keving/walk
+
+INPUT
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+f.*.Z	[1-80]
+END_INPUT
+
+PARALLEL_TEST_FRAMES	10
+PARALLEL_TIME_CHUNKS	30
+
+
+IO_SERVER_CONVERT *
+SLAVE_CONVERT zcat *
+
+PARALLEL
+#charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+#woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+END_PARALLEL
+
+# quality parameters
+
+IQSCALE		1
+PQSCALE		6
+BQSCALE		10
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		7
+
+PSEARCH_ALG	TWOLEVEL
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/walk50.param b/converter/ppm/ppmtompeg/examples/walk50.param
new file mode 100644
index 00000000..8f4d27e6
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/walk50.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/walk19.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	320x240
+
+INPUT_CONVERT	zcat *
+
+INPUT_DIR	/n/zonker/cluster/keving/walk
+
+INPUT
+f.*.Z	[1-200]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	EXHAUSTIVE
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/walk52.5.param b/converter/ppm/ppmtompeg/examples/walk52.5.param
new file mode 100644
index 00000000..f9d038f6
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/walk52.5.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/walk19.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	320x240
+
+INPUT_CONVERT	zcat *
+
+INPUT_DIR	/n/zonker/cluster/keving/walk
+
+INPUT
+f.*.Z	[1-16]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/walk52.param b/converter/ppm/ppmtompeg/examples/walk52.param
new file mode 100644
index 00000000..69626d2c
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/walk52.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/walk19.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	320x240
+
+INPUT_CONVERT	zcat *
+
+INPUT_DIR	/n/zonker/cluster/keving/walk
+
+INPUT
+f.*.Z	[1-200]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/walk53.param b/converter/ppm/ppmtompeg/examples/walk53.param
new file mode 100644
index 00000000..72f57c7a
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/walk53.param
@@ -0,0 +1,35 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/walk19.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	320x240
+
+INPUT_CONVERT	zcat *
+
+INPUT_DIR	/n/zonker/cluster/keving/walk
+
+INPUT
+f.*.Z	[1-16]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	EXHAUSTIVE
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/examples/walk93.param b/converter/ppm/ppmtompeg/examples/walk93.param
new file mode 100644
index 00000000..243d6032
--- /dev/null
+++ b/converter/ppm/ppmtompeg/examples/walk93.param
@@ -0,0 +1,62 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+#PATTERN		I
+OUTPUT		/n/picasso/users/keving/encode/output/walk93.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	1
+
+BASE_FILE_FORMAT	PPM
+YUV_SIZE	320x240
+
+INPUT_CONVERT	zcat *
+
+INPUT_DIR	/n/zonker/cluster/keving/walk
+
+INPUT
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+title.ppm.Z
+f.*.Z	[1-2]
+END_INPUT
+
+PARALLEL_TEST_FRAMES	10
+PARALLEL_TIME_CHUNKS	30
+
+
+IO_SERVER_CONVERT *
+SLAVE_CONVERT zcat *
+
+PARALLEL
+#charlie-brown	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+#woodstock	keving	~keving/encode/bin/dec-alpha/mpeg_encode
+END_PARALLEL
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		7
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	DECODED
diff --git a/converter/ppm/ppmtompeg/file.c b/converter/ppm/ppmtompeg/file.c
new file mode 100644
index 00000000..ae741962
--- /dev/null
+++ b/converter/ppm/ppmtompeg/file.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /n/picasso/project/mm/mpeg/mpeg_dist/mpeg_encode/RCS/file.c,v 1.2 1993/06/30 20:06:09 keving Exp $
+ *  $Log: file.c,v $
+ * Revision 1.2  1993/06/30  20:06:09  keving
+ * nothing
+ *
+ * Revision 1.1  1993/06/03  21:08:08  keving
+ * nothing
+ *
+ */
+
+#include "tk.h"
+
+#include "all.h"
+
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <time.h>
+#include <string.h>
+#include <dirent.h>
+#include <strings.h>
+
+#define MAX_FILES   1000
+#define MAX_NAME_LEN	256
+#define MAX_STRING_LEN	MAX_NAME_LEN
+
+typedef int boolean;
+#define TRUE 1
+#define FALSE 0
+
+extern char currentPath[MAXPATHLEN];
+
+char	globString[1024];
+
+static DIR *dfd;
+
+void	ResetPath(void);
+int ListDirectory(ClientData nulldata, Tcl_Interp *interp, int argc,
+		  char **argv);
+int ChangeDirectory(ClientData nulldata, Tcl_Interp *interp, int argc,
+		  char **argv);
+void	SortFiles(int numStrings, char strings[MAX_FILES][MAX_NAME_LEN],
+		  boolean *dirList, int permute[]);
+
+static void	UpdatePath(Tcl_Interp *interp, char *directory);
+static boolean	MatchesGlob(char *string, char *glob);
+
+
+
+void	ResetPath()
+{
+    if ( getwd(currentPath) == 0 )
+    {
+	fprintf(stderr, "Error getting pathname!!!\n");
+	exit(1);
+    }
+
+    strcpy(&currentPath[strlen(currentPath)], "/");
+
+    dfd = opendir(currentPath);
+    if ( dfd == NULL )
+    {
+	fprintf(stderr, "can't open '%s'\n", currentPath);
+	exit(1);
+    }
+}
+
+
+static void	UpdatePath(Tcl_Interp *interp, char *directory)
+{
+    int length;
+    char *charPtr;
+
+    length = strlen(currentPath);
+
+    if ( strcmp(directory, "./") == 0 )
+	return /* nothing */ ;
+    else if ( strcmp(directory, "../") == 0 )
+    {
+	/* delete backwards up to '/' */
+
+	if ( length < 2 )
+	{
+	    fprintf(stderr, "Error:  backing up from root directory!!!\n");
+	    exit(1);
+	}
+
+	charPtr = &currentPath[length-2];
+	while ( (charPtr != currentPath) && (*charPtr != '/') )
+	    charPtr--;
+	charPtr++;	/* leave the '/' */
+	*charPtr = '\0';
+    }
+    else
+    {
+	strcpy(&currentPath[length], directory);
+    }
+}
+
+
+int ChangeDirectory(ClientData nulldata, Tcl_Interp *interp, int argc,
+		  char **argv)
+{
+    char *directory = argv[1];
+
+    UpdatePath(interp, directory);
+
+    fprintf(stdout, "Opening directory: '%s'\n", currentPath);
+
+    dfd = opendir(currentPath);
+    if ( dfd == NULL )
+    {
+	fprintf(stderr, "can't open '%s'\n", currentPath);
+	return TCL_OK;	/* shouldn't, really */
+    }
+
+    return TCL_OK;
+}
+
+
+int ListDirectory(ClientData nulldata, Tcl_Interp *interp, int argc,
+		  char **argv)
+{
+    struct dirent *dp;
+    struct stat stbuf;
+    char command[256];
+    char fileName[MAX_FILES][MAX_NAME_LEN];
+    boolean dirList[MAX_FILES];
+    int permute[MAX_FILES];
+    int	fileCount = 0;
+    register int index;
+    char fullName[MAXPATHLEN];
+    char    *restPtr;
+
+    sprintf(command, "ShowCurrentDirectory %s", currentPath);
+    Tcl_Eval(interp, command, 0, (char **) NULL);
+
+    if ( dfd == NULL )
+    {
+	fprintf(stderr, "TRIED TO LIST NULL DIRECTORY\n");
+
+	return TCL_OK;
+    }
+
+/* check if root directory */
+    if ( strlen(currentPath) != 1 )
+    {
+	sprintf(fileName[fileCount], "../");
+	dirList[fileCount] = TRUE;
+	fileCount++;
+    }
+
+    strcpy(fullName, currentPath);
+    restPtr = &fullName[strlen(fullName)];
+
+    while ( (dp = readdir(dfd)) != NULL )
+    {
+	strcpy(restPtr, dp->d_name);
+	stat(fullName, &stbuf);
+
+	if ( dp->d_name[0] != '.' )
+	{
+	    if ( S_ISDIR(stbuf.st_mode) )
+	    {
+		sprintf(fileName[fileCount], "%s/", dp->d_name);
+		dirList[fileCount] = TRUE;
+		fileCount++;
+	    }
+	    else
+	    {
+		if ( MatchesGlob(dp->d_name, globString) )
+		{
+		    strcpy(fileName[fileCount], dp->d_name);
+		    dirList[fileCount] = FALSE;
+		    fileCount++;
+		}
+	    }
+	}
+    }
+
+    SortFiles(fileCount, fileName, dirList, permute);
+
+    for ( index = 0; index < fileCount; index++ )
+    {
+	sprintf(command, "AddBrowseFile %s", fileName[permute[index]]);
+	Tcl_Eval(interp, command, 0, (char **) NULL);
+    }
+
+    closedir(dfd);
+
+    return TCL_OK;
+}
+
+
+void	SortFiles(int numStrings, char strings[MAX_FILES][MAX_NAME_LEN],
+		  boolean *dirList, int permute[])
+{
+    register int i, j;
+    int temp;
+    int	numDirs;
+    int	ptr;
+
+    for ( i = 0; i < numStrings; i++ )
+	permute[i] = i;
+
+    /* put all directories at front */
+    numDirs = 0;
+    ptr = numStrings-1;
+    while ( numDirs != ptr )
+    {
+	/* go past dirs */
+	while ( (numDirs < ptr) && (dirList[permute[numDirs]]) )
+	    numDirs++;
+
+	/* go past non-dirs */
+	while ( (numDirs < ptr) && (! dirList[permute[ptr]]) )
+	    ptr--;
+
+	if ( numDirs != ptr )
+	{
+	    temp = permute[numDirs];
+	    permute[numDirs] = ptr;
+	    permute[ptr] = temp;
+	}
+    }
+
+    if ( dirList[permute[numDirs]] )
+	numDirs++;
+
+    for ( i = 0; i < numDirs; i++ )
+	for ( j = i+1; j < numDirs; j++ )
+	{
+	    if ( strcmp(&strings[permute[j]][0], &strings[permute[i]][0]) < 0 )
+	    {
+		temp = permute[j];
+		permute[j] = permute[i];
+		permute[i] = temp;
+	    }
+	}
+
+    for ( i = numDirs; i < numStrings; i++ )
+	for ( j = i+1; j < numStrings; j++ )
+	{
+	    if ( strcmp(&strings[permute[j]][0], &strings[permute[i]][0]) < 0 )
+	    {
+		temp = permute[j];
+		permute[j] = permute[i];
+		permute[i] = temp;
+	    }
+	}
+}
+
+
+int SetBrowseGlob (ClientData nulldata, Tcl_Interp *interp,
+		   int argc, char **argv)
+{
+    if (argc == 2 )
+    {
+	strcpy(globString, argv[1]);
+
+	fprintf(stdout, "GLOB:  %s\n", globString);
+
+	return TCL_OK;
+    }
+
+	Tcl_AppendResult (interp, 
+            "wrong args: should be \"", argv[0]," string\"", (char *) NULL);
+	return TCL_ERROR;
+}
+
+
+static boolean	MatchesGlob(char *string, char *glob)
+{
+    char    *stringRight, *globRight;
+
+    while ( (*glob != '\0') && (*glob != '*') )	    /* match left side */
+    {
+	if ( (*string == '\0') || (*string != *glob) )
+	    return FALSE;
+	string++;
+	glob++;
+    }
+
+    if ( *glob == '\0' )	/* no star */
+	return TRUE;
+
+    /* now match right side */
+    stringRight = &string[strlen(string)-1];
+    globRight = &glob[strlen(glob)-1];
+
+    while ( *globRight != '*' )
+    {
+	if ( (stringRight < string) || (*stringRight != *globRight) )
+	    return FALSE;
+	globRight--;
+	stringRight--;
+    }
+
+    return TRUE;
+}
diff --git a/converter/ppm/ppmtompeg/frame.c b/converter/ppm/ppmtompeg/frame.c
new file mode 100644
index 00000000..09f46f66
--- /dev/null
+++ b/converter/ppm/ppmtompeg/frame.c
@@ -0,0 +1,836 @@
+/*===========================================================================*
+ * frame.c                                   *
+ *                                       *
+ *  basic frame procedures                           *
+ *                                       *
+ * EXPORTED PROCEDURES:                              *
+ *  Frame_Init                               *
+ *  Frame_Exit                               *
+ *  Frame_New                                *
+ *  Frame_Free                               *
+ *  Frame_AllocBlocks                            *
+ *  Frame_AllocYCC                               *
+ *  Frame_AllocDecoded                           *
+ *  Frame_AllocHalf                                  *
+ *  Frame_Resize                                     * 
+ *                                       *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+
+#include "mallocvar.h"
+
+#include "all.h"
+#include "mtypes.h"
+#include "frames.h"
+#include "frame.h"
+#include "fsize.h"
+#include "dct.h"
+
+/*===========*
+ * CONSTANTS *
+ *===========*/
+
+/* The maximum number of B-Frames allowed between reference frames. */
+#define  B_FRAME_RUN  16    
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+
+static MpegFrame * frameMemory[B_FRAME_RUN+2];
+static unsigned int numOfFrames;
+
+
+/*====================================================
+* Resize_Array_Width
+*    
+*   This function will resize any array width up
+* or down in size.  The algorithm is based on the
+* least common multiple approach more commonly
+* used in audio frequency adjustments.
+*=====================================================*/
+static void 
+Resize_Array_Width(uint8 ** const inarray,
+                   int      const in_x,
+                   int      const in_y,
+                   uint8 ** const outarray,
+                   int      const out_x) {
+
+    unsigned int i;
+    int in_total;
+    int out_total;
+    uint8 *inptr;
+    uint8 *outptr;
+    uint8 pointA,pointB;
+    /* double slope,diff; */
+    
+    for (i = 0; i < in_y; ++i) {     /* For each row */
+        unsigned int j;
+        inptr = &inarray[i][0];
+        outptr = &outarray[i][0];
+        in_total = 0;
+        out_total = 0;
+        for (j=0; j < out_x; ++j) {      /* For each output value */
+            if (in_total == out_total) {
+                *outptr = *inptr;
+                outptr++;
+                out_total=out_total+in_x;
+                while(in_total < out_total){
+                    in_total = in_total + out_x;
+                    ++inptr;
+                }
+                if (in_total > out_total) {
+                    in_total = in_total - out_x;
+                    --inptr;
+                }
+            } else {  
+                pointA = *inptr;
+                ++inptr;
+                pointB = *inptr;
+                --inptr;
+#if 0
+                /*Interpolative solution */
+                slope = ((double)(pointB -pointA))/((double)(out_x));
+                diff = (((double)(out_total - in_total)));
+                if (diff < (out_x/2)){
+                    *outptr = (pointA + (uint8)(slope*diff));
+                } else {
+                    *outptr = (pointB -
+                               (uint8)(slope*(((float)(out_x)) - diff)));
+                } 
+#endif
+                /* Non-Interpolative solution */
+                *outptr = *inptr;  
+
+                ++outptr;
+                out_total = out_total + in_x;
+                while(in_total < out_total) {
+                    in_total = in_total + out_x;
+                    ++inptr;
+                }
+                if (in_total > out_total) {
+                    in_total = in_total - out_x;
+                    --inptr;
+                }
+            }  /* end if */
+        }  /* end for each output value */
+    }  /* end for each row */
+}  /* end main */
+
+
+
+/*==============================
+* Resize_Array_Height
+*
+*    Resize any array height larger or smaller.
+* Same as Resize_array_Width except pointer
+* manipulation must change.
+*===============================*/
+static void 
+Resize_Array_Height(uint8 ** const inarray,
+                    int      const in_x,
+                    int      const in_y,
+                    uint8 ** const outarray,
+                    int      const out_y) {
+
+    unsigned int i;
+
+    for(i=0; i < in_x; ++i){    /* for each column */
+        int in_total;
+        int out_total;
+        uint8 pointA, pointB;
+        double slope, diff;
+        unsigned int j;
+        int k;
+
+        in_total = 0;
+        out_total = 0;
+        k = 0;
+        for(j=0; j < out_y; ++j){  /* for each output value */
+            if (in_total == out_total) {  
+                outarray[j][i] = inarray[k][i];
+                out_total=out_total+in_y;
+                while(in_total < out_total){
+                    in_total = in_total + out_y;
+                    ++k;
+                }
+                if (in_total > out_total) {
+                    in_total = in_total - out_y;
+                    --k;
+                }
+            } else {  
+                pointA = inarray[k][i];
+                if (k != (in_y -1)) {
+                    pointB = inarray[k+1][i];
+                } else
+                    pointB = pointA;
+                /* Interpolative case */
+                slope = ((double)(pointB -pointA))/(double)(out_y);
+                diff = (double)(out_total - in_total);
+                /*  outarray[j][i] = (inarray[k][i] + (uint8)(slope*diff)); */
+                /* Non-Interpolative case */
+                outarray[j][i] = inarray[k][i];
+                out_total = out_total + in_y;
+                while (in_total < out_total) {
+                    in_total = in_total + out_y;
+                    ++k;
+                }
+                if (in_total > out_total){
+                    in_total = in_total - out_y;
+                    --k;
+                }
+            } 
+        }
+    }
+}
+
+
+
+/*========================================================
+* Resize_Width
+*======================================================*/
+static void  
+Resize_Width(MpegFrame * const omfrw,
+             MpegFrame * const mfrw,
+             int         const in_x,
+             int         const in_y,
+             int         const out_x) {
+
+    int y;
+
+    omfrw->orig_y = NULL;
+    Fsize_x = out_x;
+
+    /* Allocate new frame memory */
+    MALLOCARRAY(omfrw->orig_y, Fsize_y);
+    ERRCHK(omfrw->orig_y, "malloc");
+    for (y = 0; y < Fsize_y; ++y) {
+        MALLOCARRAY(omfrw->orig_y[y], out_x);
+        ERRCHK(omfrw->orig_y[y], "malloc");
+    }
+
+    MALLOCARRAY(omfrw->orig_cr, Fsize_y / 2);
+    ERRCHK(omfrw->orig_cr, "malloc");
+    for (y = 0; y < Fsize_y / 2; ++y) {
+        MALLOCARRAY(omfrw->orig_cr[y], out_x / 2);
+        ERRCHK(omfrw->orig_cr[y], "malloc");
+    }
+
+    MALLOCARRAY(omfrw->orig_cb, Fsize_y / 2);
+    ERRCHK(omfrw->orig_cb, "malloc");
+    for (y = 0; y < Fsize_y / 2; ++y) {
+        MALLOCARRAY(omfrw->orig_cb[y], out_x / 2);
+        ERRCHK(omfrw->orig_cb[y], "malloc");
+    }
+
+    if (referenceFrame == ORIGINAL_FRAME) {
+        omfrw->ref_y = omfrw->orig_y;
+        omfrw->ref_cr = omfrw->orig_cr;
+        omfrw->ref_cb = omfrw->orig_cb;
+    }
+
+    /* resize each component array separately */
+    Resize_Array_Width(mfrw->orig_y, in_x, in_y, omfrw->orig_y, out_x);
+    Resize_Array_Width(mfrw->orig_cr, (in_x/2), (in_y/2), omfrw->orig_cr,
+                       (out_x/2));
+    Resize_Array_Width(mfrw->orig_cb, (in_x/2), (in_y/2), omfrw->orig_cb,
+                       (out_x/2));
+
+    /* Free old frame memory */
+    if (mfrw->orig_y) {
+        unsigned int i;
+        for (i = 0; i < in_y; ++i) {
+            free(mfrw->orig_y[i]);
+        }
+        free(mfrw->orig_y);
+        
+        for (i = 0; i < in_y / 2; ++i) {
+            free(mfrw->orig_cr[i]);
+        }
+        free(mfrw->orig_cr);
+        
+        for (i = 0; i < in_y / 2; ++i) {
+            free(mfrw->orig_cb[i]);
+        }
+        free(mfrw->orig_cb);
+    }
+}
+
+
+
+/*=======================================================
+* Resize_Height
+*
+*   Resize Frame height up or down
+*=======================================================*/
+static  void
+Resize_Height(MpegFrame * const omfrh,
+              MpegFrame * const mfrh,
+              int         const in_x,
+              int         const in_y,
+              int         const out_y) {
+    
+    unsigned int y; 
+    
+    Fsize_y = out_y;
+
+    /* Allocate new frame memory */
+    MALLOCARRAY(omfrh->orig_y, out_y);
+    ERRCHK(omfrh->orig_y, "malloc");
+    for (y = 0; y < out_y; ++y) {
+        MALLOCARRAY(omfrh->orig_y[y], Fsize_x);
+        ERRCHK(omfrh->orig_y[y], "malloc");
+    }
+
+    MALLOCARRAY(omfrh->orig_cr, out_y / 2);
+    ERRCHK(omfrh->orig_cr, "malloc");
+    for (y = 0; y < out_y / 2; ++y) {
+        MALLOCARRAY(omfrh->orig_cr[y], Fsize_x / 2);
+        ERRCHK(omfrh->orig_cr[y], "malloc");
+    }
+
+    MALLOCARRAY(omfrh->orig_cb, out_y / 2);
+    ERRCHK(omfrh->orig_cb, "malloc");
+    for (y = 0; y < out_y / 2; ++y) {
+        MALLOCARRAY(omfrh->orig_cb[y], Fsize_x / 2);
+        ERRCHK(omfrh->orig_cb[y], "malloc");
+    }
+
+    if (referenceFrame == ORIGINAL_FRAME) {
+        omfrh->ref_y = omfrh->orig_y;
+        omfrh->ref_cr = omfrh->orig_cr;
+        omfrh->ref_cb = omfrh->orig_cb;
+    }
+
+    /* resize component arrays separately */
+    Resize_Array_Height(mfrh->orig_y, in_x, in_y, omfrh->orig_y, out_y);
+    Resize_Array_Height(mfrh->orig_cr, (in_x/2), (in_y/2), omfrh->orig_cr,
+                        (out_y/2));
+    Resize_Array_Height(mfrh->orig_cb, (in_x/2), (in_y/2), omfrh->orig_cb,
+                        (out_y/2));
+
+    /* Free old frame memory */
+    if (mfrh->orig_y) {
+        unsigned int i;
+        for (i = 0; i < in_y; ++i) {
+            free(mfrh->orig_y[i]);
+        }
+        free(mfrh->orig_y);
+        
+    for (i = 0; i < in_y / 2; ++i) {
+        free(mfrh->orig_cr[i]);
+    }
+    free(mfrh->orig_cr);
+    
+    for (i = 0; i < in_y / 2; ++i) {
+        free(mfrh->orig_cb[i]);
+    }
+    free(mfrh->orig_cb);
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ * Frame_Init
+ *
+ *  initializes the memory associated with all frames ever
+ *  If the input is not coming in from stdin, only 3 frames are needed ;
+ *      else, the program must create frames equal to the greatest distance
+ *      between two reference frames to hold the B frames while it is parsing
+ *      the input from stdin.
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    frameMemory, numOfFrames
+ *
+ *===========================================================================*/
+void
+Frame_Init(unsigned int const numOfFramesRequested) {
+    int idx;
+
+    numOfFrames = numOfFramesRequested;
+
+    for (idx = 0; idx < numOfFrames; ++idx) {
+        MALLOCVAR(frameMemory[idx]);
+        frameMemory[idx]->inUse = FALSE;
+        frameMemory[idx]->orig_y = NULL;    
+        frameMemory[idx]->y_blocks = NULL; 
+        frameMemory[idx]->decoded_y = NULL;
+        frameMemory[idx]->halfX = NULL;
+        frameMemory[idx]->next = NULL;
+    }
+}
+
+
+/*===========================================================================*
+ *
+ * FreeFrame
+ *
+ *  frees the memory associated with the given frame
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+FreeFrame(MpegFrame * const frameP) {
+
+    if (frameP) {
+        if (frameP->orig_y) {
+            unsigned int i;
+            for (i = 0; i < Fsize_y; ++i)
+                free(frameP->orig_y[i]);
+            free(frameP->orig_y);
+
+            for (i = 0; i < (Fsize_y / 2); ++i)
+                free(frameP->orig_cr[i]);
+            free(frameP->orig_cr);
+
+            for (i = 0; i < (Fsize_y / 2); ++i)
+                free(frameP->orig_cb[i]);
+            free(frameP->orig_cb);
+        }
+        if (frameP->decoded_y) {
+            unsigned int i;
+            for (i = 0; i < Fsize_y; ++i)
+                free(frameP->decoded_y[i]);
+            free(frameP->decoded_y);
+
+            for (i = 0; i < (Fsize_y / 2); ++i)
+                free(frameP->decoded_cr[i]);
+            free(frameP->decoded_cr);
+
+            for (i = 0; i < (Fsize_y / 2); ++i)
+                free(frameP->decoded_cb[i]);
+            free(frameP->decoded_cb);
+        }
+
+        if (frameP->y_blocks) {
+            unsigned int i;
+            for (i = 0; i < Fsize_y / DCTSIZE; ++i)
+                free(frameP->y_blocks[i]);
+            free(frameP->y_blocks);
+
+            for (i = 0; i < Fsize_y / (2 * DCTSIZE); ++i)
+                free(frameP->cr_blocks[i]);
+            free(frameP->cr_blocks);
+
+            for (i = 0; i < Fsize_y / (2 * DCTSIZE); ++i)
+                free(frameP->cb_blocks[i]);
+            free(frameP->cb_blocks);
+        }
+        if (frameP->halfX) {
+            unsigned int i;
+            for ( i = 0; i < Fsize_y; ++i )
+                free(frameP->halfX[i]);
+            free(frameP->halfX);
+            
+            for (i = 0; i < Fsize_y-1; ++i)
+                free(frameP->halfY[i]);
+            free(frameP->halfY);
+            
+            for (i = 0; i < Fsize_y-1; ++i)
+                free(frameP->halfBoth[i]);
+            free(frameP->halfBoth);
+        }
+        free(frameP);
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ * Frame_Exit
+ *
+ *  frees the memory associated with frames
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    frameMemory
+ *
+ *===========================================================================*/
+void
+Frame_Exit(void) {
+
+    int idx;
+
+    for (idx = 0; idx < numOfFrames; ++idx) {
+        FreeFrame(frameMemory[idx]);
+    }
+}
+
+
+/*===========================================================================*
+ *
+ * Frame_Free
+ *
+ *  frees the given frame -- allows it to be re-used
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+Frame_Free(MpegFrame * const frameP) {
+    frameP->inUse = FALSE;
+}
+
+
+
+/*===========================================================================*
+ *
+ * GetUnusedFrame
+ *
+ *  return an unused frame
+ *
+ * RETURNS: the frame
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static MpegFrame *
+GetUnusedFrame() {
+    unsigned int idx;
+
+    for (idx = 0; idx < numOfFrames; ++idx) {
+        if (!frameMemory[idx]->inUse) {
+            frameMemory[idx]->inUse = TRUE;
+            break;
+        }
+    }
+    if (idx >= numOfFrames) {
+        fprintf(stderr, "ERROR:  No unused frames!!!\n");
+        fprintf(stderr, "        If you are using stdin for input, "
+                "it is likely that you have too many\n");
+        fprintf(stderr, "        B-frames between two reference frames.  "
+                "See the man page for help.\n");
+        exit(1);
+    }
+    return frameMemory[idx]; 
+}
+
+
+
+/*===========================================================================*
+ *
+ * ResetFrame
+ *
+ *  reset a frame to the given id and type
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+ResetFrame(int         const id,
+           int         const type,
+           MpegFrame * const frame) {
+
+    switch (type) {
+    case 'i':
+        frame->type = TYPE_IFRAME;
+        break;
+    case 'p':
+        frame->type = TYPE_PFRAME;
+        break;
+    case 'b':
+        frame->type = TYPE_BFRAME;
+        break;
+    default:
+        fprintf(stderr, "Invalid MPEG frame type %c\n", type);
+        exit(1);
+    }
+
+    frame->id = id;
+    frame->halfComputed = FALSE;
+    frame->next = NULL;
+}
+
+
+
+/*===========================================================================*
+ *
+ * Frame_New
+ *
+ *  finds a frame that isn't currently being used and resets it
+ *
+ * RETURNS: the frame
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+MpegFrame *
+Frame_New(int const id,
+          int const type) {
+
+    MpegFrame *frame;
+
+    frame = GetUnusedFrame();
+    ResetFrame(id, type, frame);
+
+    return frame;
+}
+
+
+
+/*===========================================================================*
+ *
+ * Frame_AllocBlocks
+ *
+ *  allocate memory for blocks for the given frame, if required
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+Frame_AllocBlocks(MpegFrame * const frameP) {
+
+    if (frameP->y_blocks != NULL) {
+        /* already allocated */
+    } else {
+        int const dctx = Fsize_x / DCTSIZE;
+        int const dcty = Fsize_y / DCTSIZE;
+
+        unsigned int i;
+
+        MALLOCARRAY(frameP->y_blocks, dcty);
+        ERRCHK(frameP->y_blocks, "malloc");
+        for (i = 0; i < dcty; ++i) {
+            MALLOCARRAY(frameP->y_blocks[i], dctx);
+            ERRCHK(frameP->y_blocks[i], "malloc");
+        }
+    
+        MALLOCARRAY(frameP->cr_blocks, dcty / 2);
+        ERRCHK(frameP->cr_blocks, "malloc");
+        MALLOCARRAY(frameP->cb_blocks, dcty / 2);
+        ERRCHK(frameP->cb_blocks, "malloc");
+        for (i = 0; i < (dcty / 2); ++i) {
+            MALLOCARRAY(frameP->cr_blocks[i], dctx / 2);
+            ERRCHK(frameP->cr_blocks[i], "malloc");
+            MALLOCARRAY(frameP->cb_blocks[i], dctx / 2);
+            ERRCHK(frameP->cb_blocks[i], "malloc");
+        }
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ * Frame_AllocYCC
+ *
+ *  allocate memory for YCC info for the given frame, if required
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+Frame_AllocYCC(MpegFrame * const frameP) {
+
+    if (frameP->orig_y != NULL) {
+        /* already allocated */
+    } else {
+        unsigned int y;
+    
+        DBG_PRINT(("ycc_calc:\n"));
+        /*
+         * first, allocate tons of memory
+         */
+        MALLOCARRAY(frameP->orig_y, Fsize_y);
+        ERRCHK(frameP->orig_y, "malloc");
+        for (y = 0; y < Fsize_y; ++y) {
+            MALLOCARRAY(frameP->orig_y[y], Fsize_x);
+            ERRCHK(frameP->orig_y[y], "malloc");
+        }
+
+        MALLOCARRAY(frameP->orig_cr, Fsize_y / 2);
+        ERRCHK(frameP->orig_cr, "malloc");
+        for (y = 0; y < (Fsize_y / 2); ++y) {
+            MALLOCARRAY(frameP->orig_cr[y], Fsize_x / 2);
+            ERRCHK(frameP->orig_cr[y], "malloc");
+        }
+
+        MALLOCARRAY(frameP->orig_cb, Fsize_y / 2);
+        ERRCHK(frameP->orig_cb, "malloc");
+        for (y = 0; y < (Fsize_y / 2); ++y) {
+            MALLOCARRAY(frameP->orig_cb[y], Fsize_x / 2);
+            ERRCHK(frameP->orig_cb[y], "malloc");
+        }
+
+        if (referenceFrame == ORIGINAL_FRAME) {
+            frameP->ref_y  = frameP->orig_y;
+            frameP->ref_cr = frameP->orig_cr;
+            frameP->ref_cb = frameP->orig_cb;
+        }
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ * Frame_AllocHalf
+ *
+ *  allocate memory for half-pixel values for the given frame, if required
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+Frame_AllocHalf(MpegFrame * const frameP) {
+
+    if (frameP->halfX != NULL) {
+    } else {
+        unsigned int y;
+
+        MALLOCARRAY(frameP->halfX, Fsize_y);
+        ERRCHK(frameP->halfX, "malloc");
+        for (y = 0; y < Fsize_y; ++y) {
+            MALLOCARRAY(frameP->halfX[y], Fsize_x - 1);
+            ERRCHK(frameP->halfX[y], "malloc");
+        }
+        MALLOCARRAY(frameP->halfY, Fsize_y - 1);
+        ERRCHK(frameP->halfY, "malloc");
+        for (y = 0; y < Fsize_y - 1; ++y) {
+            MALLOCARRAY(frameP->halfY[y], Fsize_x);
+            ERRCHK(frameP->halfY[y], "malloc");
+        }
+        MALLOCARRAY(frameP->halfBoth, Fsize_y - 1);
+        ERRCHK(frameP->halfBoth, "malloc");
+        for (y = 0; y < Fsize_y - 1; ++y) {
+            MALLOCARRAY(frameP->halfBoth[y], Fsize_x - 1);
+            ERRCHK(frameP->halfBoth[y], "malloc");
+        }
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ * Frame_AllocDecoded
+ *
+ *  allocate memory for decoded frame for the given frame, if required
+ *  if makeReference == TRUE, then makes it reference frame
+ * 
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+Frame_AllocDecoded(MpegFrame * const frameP,
+                   boolean     const makeReference) {
+
+    if (frameP->decoded_y != NULL) {
+        /* already allocated */
+    } else {
+        unsigned int y;
+
+        /* allocate memory for decoded image */
+        /* can probably reuse original image memory, but may decide to use
+           it for some reason, so do it this way at least for now -- more
+           flexible
+        */
+        MALLOCARRAY(frameP->decoded_y, Fsize_y);
+        ERRCHK(frameP->decoded_y, "malloc");
+        for (y = 0; y < Fsize_y; ++y) {
+            MALLOCARRAY(frameP->decoded_y[y], Fsize_x);
+            ERRCHK(frameP->decoded_y[y], "malloc");
+        }
+        
+        MALLOCARRAY(frameP->decoded_cr, Fsize_y / 2);
+        ERRCHK(frameP->decoded_cr, "malloc");
+        for (y = 0; y < (Fsize_y / 2); ++y) {
+            MALLOCARRAY(frameP->decoded_cr[y], Fsize_x / 2);
+            ERRCHK(frameP->decoded_cr[y], "malloc");
+        }
+        
+        MALLOCARRAY(frameP->decoded_cb, Fsize_y / 2);
+        ERRCHK(frameP->decoded_cb, "malloc");
+        for (y = 0; y < (Fsize_y / 2); ++y) {
+            MALLOCARRAY(frameP->decoded_cb[y], Fsize_x / 2);
+            ERRCHK(frameP->decoded_cb[y], "malloc");
+        }
+
+        if (makeReference) {
+            frameP->ref_y  = frameP->decoded_y;
+            frameP->ref_cr = frameP->decoded_cr;
+            frameP->ref_cb = frameP->decoded_cb;
+        }
+    }
+}
+
+
+
+/*===============================================================
+ *
+ * Frame_Resize                  by James Boucher
+ *                Boston University Multimedia Communications Lab
+ *  
+ *     This function takes the mf input frame, read in READFrame(),
+ * and resizes all the input component arrays to the output
+ * dimensions specified in the parameter file as OUT_SIZE.
+ * The new frame is returned with the omf pointer.  As well,
+ * the values of Fsize_x and Fsize_y are adjusted.
+ ***************************************************************/
+void
+Frame_Resize(MpegFrame * const omf,
+             MpegFrame * const mf,
+             int         const insize_x,
+             int         const insize_y,
+             int         const outsize_x,
+             int         const outsize_y) {
+
+    MpegFrame * frameAP;  /* intermediate frame */
+
+    MALLOCVAR_NOFAIL(frameAP);
+    
+    if (insize_x != outsize_x && insize_y != outsize_y) {
+        Resize_Width(frameAP, mf, insize_x, insize_y, outsize_x);
+        Resize_Height(omf, frameAP, outsize_x, insize_y, outsize_y);
+    } else 
+        if (insize_x ==outsize_x && insize_y != outsize_y) {
+            Resize_Height(omf, mf, insize_x, insize_y, outsize_y);
+        } else
+            if (insize_x !=outsize_x && insize_y == outsize_y) {
+                Resize_Width(omf, mf, insize_x, insize_y, outsize_x);
+            } else
+                exit(1);
+
+    free(frameAP);
+    free(mf);
+}
diff --git a/converter/ppm/ppmtompeg/frametype.c b/converter/ppm/ppmtompeg/frametype.c
new file mode 100644
index 00000000..b7daacc9
--- /dev/null
+++ b/converter/ppm/ppmtompeg/frametype.c
@@ -0,0 +1,365 @@
+/*===========================================================================*
+ * frametype.c								     *
+ *									     *
+ *	procedures to keep track of frame types (I, P, B)		     *
+ *									     *
+ * EXPORTED PROCEDURES:							     *
+ *	FType_Type						             *
+ *	FType_FutureRef						             *
+ *	FType_PastRef						             *
+ *									     *
+ * SYNOPSIS								     *
+ *	FType_Type	returns the type of the given numbered frame	     *
+ *	FType_FutureRef	returns the number of the future reference frame     *
+ *	FType_PastRef	returns the number of the past reference frame	     *
+ *									     *
+ * 00.12.07 change malloc from frameTable to calloc to fix bug 
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "mallocvar.h"
+#include "all.h"
+#include "frames.h"
+#include "frame.h"
+#include "param.h"
+#include "specifics.h"
+#include "frametype.h"
+
+
+static FrameTable *frameTable=NULL;
+static boolean use_cache = FALSE;
+static int firstI = 0;
+static int numFrames;
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+
+extern int framePatternLen;
+extern char * framePattern;
+
+
+/*=====================*
+ * EXPORTED PROCEDURES *
+ *=====================*/
+
+/*===========================================================================*
+ *
+ * FType_Type
+ *
+ *	returns the type of the given numbered frame
+ *
+ * RETURNS:	the type
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+char
+FType_Type(unsigned int const frameNum) {
+
+    char const patternedType = framePattern[frameNum % framePatternLen];
+
+    char retval;
+
+    if (use_cache) 
+        return frameTable[frameNum].typ;
+  
+    if (frameNum+1 == numFrames) {
+        /* It's the last frame in the sequence.  If the pattern says it's
+           a B, we convert it to I because a B frame makes no sense as the
+           last frame of a sequence.
+        */
+        if (patternedType == 'b') 
+            retval = 'i';
+        else 
+            retval = patternedType;
+    } else {
+        if (specificsOn) {
+            static int lastI = -1;
+            int newtype;
+      
+            if (lastI > frameNum) 
+                lastI = -1;
+            newtype = SpecTypeLookup(frameNum);
+            switch (newtype) {
+            case 1:
+                lastI = frameNum;
+                retval = 'i';
+                break;
+            case 2:
+                retval = 'p';
+                break;
+            case 3:
+                retval = 'b';
+                break;
+            default:
+                if (lastI != -1) {
+                    unsigned int const pretendFrameNumber = 
+                        (frameNum - lastI + firstI) % framePatternLen;
+                    retval = framePattern[pretendFrameNumber];
+                } else 
+                    retval = patternedType;
+            }
+        } else 
+            retval = patternedType;
+    }
+    return retval;
+}
+
+
+
+unsigned int
+FType_FutureRef(unsigned int const currFrameNum) {
+/*----------------------------------------------------------------------------
+  Return the number of the future reference frame for the B frame
+  'currentFrameNum'.
+-----------------------------------------------------------------------------*/
+    unsigned int retval;
+
+    if (use_cache) {
+        retval = frameTable[currFrameNum].next->number;
+    } else {
+        int const index = currFrameNum % framePatternLen;
+        int const futureIndex = frameTable[index].next->number;
+        unsigned int const patternedFutureRef =
+            currFrameNum +
+            (((futureIndex-index)+framePatternLen) % framePatternLen);
+
+        retval = MIN(patternedFutureRef, numFrames-1);
+    }
+    return retval;
+}
+
+
+
+/*===========================================================================*
+ *
+ * FType_PastRef
+ *
+ *	returns the number of the past reference frame
+ *
+ * RETURNS:	the number
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+int
+FType_PastRef(currFrameNum)
+    int currFrameNum;
+{
+    int	    index;
+    int	    pastIndex;
+
+    if (use_cache) {
+      return frameTable[currFrameNum].prev->number;
+    } else {
+      index = currFrameNum % framePatternLen;
+      pastIndex = frameTable[index].prev->number;
+      
+      return currFrameNum -
+	(((index-pastIndex)+framePatternLen) % framePatternLen);
+    }
+}
+
+
+/*===========================================================================*
+ *
+ * SetFramePattern
+ *
+ *	set the IPB pattern; calls ComputeFrameTable to set up table
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    framePattern, framePatternLen, frameTable
+ *
+ *===========================================================================*/
+#define SIMPLE_ASCII_UPPER(x)  (((x)>='a') ? ((x)-'a'+'A') : (x))
+void
+SetFramePattern(const char * const pattern) {
+    unsigned int const len = strlen(pattern);
+
+    char *buf;
+    unsigned int index;
+
+    if (!pattern)
+        pm_error("INTERNAL ERROR: pattern cannot be NULL "
+            "in SetFramePattern");
+
+    if (SIMPLE_ASCII_UPPER(pattern[0]) != 'I') {
+        unsigned int index;
+        for (index = 0; index < len; ++index) {
+            if (SIMPLE_ASCII_UPPER(pattern[index]) == 'I') {
+                break;
+            } else if (SIMPLE_ASCII_UPPER(pattern[index]) == 'P')
+                pm_error("first reference frame must be 'i', not '%c'",
+                         pattern[index]);
+        }
+    }
+
+    buf = (char *)malloc(sizeof(char)*(len+1));
+    ERRCHK(buf, "malloc");
+
+    firstI = -1;
+    for (index = 0; index < len; index++) {
+        switch( SIMPLE_ASCII_UPPER(pattern[index]) ) {
+        case 'I':	
+            buf[index] = 'i';
+            if (firstI == -1) firstI = index;
+            break;
+        case 'P':	
+            buf[index] = 'p'; 
+            break;
+        case 'B':	
+            buf[index] = 'b';
+            break;
+        default:
+            pm_error("Invalid MPEG Frame type '%c'.", pattern[index]);
+        }
+    }
+    buf[len] = 0;
+
+    if (firstI == -1)
+        pm_error("Must have an I-frame in PATTERN");
+
+    framePattern = buf;
+    framePatternLen = len;
+    
+    /* Used to ComputeFrameTable(), but now must wait until param
+       parsed. (STDIN or not)
+    */
+}
+
+
+
+void
+ComputeFrameTable(unsigned int const numFramesArg) {
+/*----------------------------------------------------------------------------
+  Compute a table of I, P, B frames to help in determining dependencie
+
+  'numFrames' == 0 means number of frames is not known at this time.
+-----------------------------------------------------------------------------*/
+    int index;
+    FrameTable	*lastI, *lastIP, *firstB, *secondIP;
+    FrameTable	*ptr;
+    char typ;
+    int table_size;
+
+    numFrames = numFramesArg;
+
+    if (numFrames)
+        table_size = numFrames;
+    else
+        table_size = framePatternLen;
+
+    MALLOCARRAY_NOFAIL(frameTable, 1 + table_size);
+
+    lastI = NULL;
+    lastIP = NULL;
+    firstB = NULL;
+    secondIP = NULL;
+    for ( index = 0; index < table_size; index++ ) {
+        frameTable[index].number = index;
+        typ = FType_Type(index);
+        frameTable[index].typ = typ;
+        switch( typ ) {
+	    case 'i':
+            ptr = firstB;
+            while ( ptr != NULL ) {
+                ptr->next = &(frameTable[index]);
+                ptr = ptr->nextOutput;
+            }
+            frameTable[index].nextOutput = firstB;
+            frameTable[index].prev = lastIP;	/* for freeing */
+            if ( lastIP != NULL ) {
+                lastIP->next = &(frameTable[index]);
+                if ( secondIP == NULL ) {
+                    secondIP = &(frameTable[index]);
+                }
+            }
+            lastIP = &(frameTable[index]);
+            firstB = NULL;
+            break;
+	    case 'p':
+            ptr = firstB;
+            while ( ptr != NULL ) {
+                ptr->next = &(frameTable[index]);
+                ptr = ptr->nextOutput;
+            }
+            frameTable[index].nextOutput = firstB;
+            frameTable[index].prev = lastIP;
+            if ( lastIP != NULL ) {
+                lastIP->next = &(frameTable[index]);
+                if ( secondIP == NULL ) {
+                    secondIP = &(frameTable[index]);
+                }
+            }
+            lastIP = &(frameTable[index]);
+            firstB = NULL;
+            break;
+	    case 'b':
+            if ( (index+1 == framePatternLen) ||
+                 (FType_Type(index+1) != 'b') ) {
+                frameTable[index].nextOutput = NULL;
+            } else {
+                frameTable[index].nextOutput = &(frameTable[index+1]);
+            }
+            frameTable[index].prev = lastIP;
+            if ( firstB == NULL ) {
+                firstB = &(frameTable[index]);
+            }
+            break;
+	    default:
+	        fprintf(stderr, "Programmer Error in ComputeFrameTable (%d)\n",
+                    framePattern[index]);
+	        exit(1);
+	        break;
+        }
+    }
+    
+    /* why? SRS */
+    frameTable[table_size].number = framePatternLen;
+    ptr = firstB;
+    while ( ptr != NULL ) {
+        ptr->next = &(frameTable[table_size]);
+        ptr = ptr->nextOutput;
+    }
+    frameTable[table_size].nextOutput = firstB;
+    frameTable[table_size].prev = lastIP;
+    if ( secondIP == NULL )
+        frameTable[table_size].next = &(frameTable[0]);
+    else
+        frameTable[table_size].next = secondIP;
+
+    frameTable[0].prev = lastIP;
+    if ( lastIP != NULL ) {
+        lastIP->next = &(frameTable[table_size]);
+    }
+
+    if (numFrames)
+        use_cache = TRUE;
+}
diff --git a/converter/ppm/ppmtompeg/fsize.c b/converter/ppm/ppmtompeg/fsize.c
new file mode 100644
index 00000000..3808405c
--- /dev/null
+++ b/converter/ppm/ppmtompeg/fsize.c
@@ -0,0 +1,134 @@
+/*===========================================================================*
+ * fsize.c								     *
+ *									     *
+ *	procedures to keep track of frame size				     *
+ *									     *
+ * EXPORTED PROCEDURES:							     *
+ *	Fsize_Reset							     *
+ *	Fsize_Note							     *
+ *	Fsize_Validate							     *
+ *									     *
+ * EXPORTED VARIABLES:							     *
+ *	Fsize_x								     *
+ *	Fsize_y								     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "all.h"
+#include "fsize.h"
+#include "dct.h"
+
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+int Fsize_x = 0;
+int Fsize_y = 0;
+
+
+/*=====================*
+ * EXPORTED PROCEDURES *
+ *=====================*/
+
+/*===========================================================================*
+ *
+ * Fsize_Reset
+ *
+ *	reset the frame size to 0
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    Fsize_x, Fsize_y
+ *
+ *===========================================================================*/
+void
+Fsize_Reset(void) {
+    Fsize_x = Fsize_y = 0;
+}
+
+
+
+/*===========================================================================*
+ *
+ * Fsize_Validate
+ *
+ *	make sure that the x, y values are 16-pixel aligned
+ *
+ * RETURNS:	modifies the x, y values to 16-pixel alignment
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+Fsize_Validate(int * const xP,
+               int * const yP) {
+
+    *xP &= ~(DCTSIZE * 2 - 1);  /* Zero the low-order bits */
+    *yP &= ~(DCTSIZE * 2 - 1);  /* Zero the low-order bits */
+}
+
+
+/*===========================================================================*
+ *
+ * Fsize_Note
+ *
+ *	note the given frame size and modify the global values as appropriate
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    Fsize_x, Fsize_y
+ *
+ *===========================================================================*/
+void
+Fsize_Note(int          const id,
+           unsigned int const width,
+           unsigned int const height) {
+
+    Fsize_x = width;
+    Fsize_y = height;
+    Fsize_Validate(&Fsize_x, &Fsize_y);
+
+    if ((Fsize_x == 0) || (Fsize_y == 0)) {
+        fprintf(stderr,"Frame %d:  size is less than the minimum: %d x %d!\n",
+                id, DCTSIZE*2, DCTSIZE*2);
+        exit(1);
+    }
+
+#ifdef BLEAH
+    if (Fsize_x == 0) {
+	Fsize_x = width;
+	Fsize_y = height;
+	Fsize_Validate(&Fsize_x, &Fsize_y);
+    } else if (width < Fsize_x || height < Fsize_y) {
+	fprintf(stderr, "Frame %d: wrong size: (%d,%d).  Should be greater or equal to: (%d,%d)\n",
+		id, width, height, Fsize_x, Fsize_y);
+	exit(1);
+    }
+#endif
+}
diff --git a/converter/ppm/ppmtompeg/gethostname.c b/converter/ppm/ppmtompeg/gethostname.c
new file mode 100644
index 00000000..014b42e8
--- /dev/null
+++ b/converter/ppm/ppmtompeg/gethostname.c
@@ -0,0 +1,26 @@
+#define _BSD_SOURCE   /* Make sure strdup() is in string.h */
+
+#include <string.h>
+#include <errno.h>
+#include <sys/utsname.h>
+
+#include "pm.h"
+
+#include "gethostname.h"
+
+const char *
+GetHostName(void) {
+/*----------------------------------------------------------------------------
+   Return the host name of this system.
+-----------------------------------------------------------------------------*/
+    struct utsname utsname;
+    int rc;
+
+    rc = uname(&utsname);
+
+    if (rc < 0)
+        pm_error("Unable to find out host name.  "
+                 "uname() failed with errno %d (%s)", errno, strerror(errno));
+
+    return strdup(utsname.nodename);
+}
diff --git a/converter/ppm/ppmtompeg/gethostname.h b/converter/ppm/ppmtompeg/gethostname.h
new file mode 100644
index 00000000..e5450175
--- /dev/null
+++ b/converter/ppm/ppmtompeg/gethostname.h
@@ -0,0 +1,7 @@
+#ifndef GETHOSTNAME_H_INCLUDED
+#define GETHOSTNAME_H_INCLUDED
+
+const char *
+GetHostName(void);
+
+#endif
diff --git a/converter/ppm/ppmtompeg/headers/all.h b/converter/ppm/ppmtompeg/headers/all.h
new file mode 100644
index 00000000..e350aab8
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/all.h
@@ -0,0 +1,95 @@
+/*===========================================================================*
+ * all.h								     *
+ *									     *
+ *	stuff included from ALL source files				     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /u/smoot/md/mpeg_encode/headers/RCS/all.h,v 1.9 1995/06/05 21:11:06 smoot Exp $
+ *  $Log: all.h,v $
+ * Revision 1.9  1995/06/05  21:11:06  smoot
+ * added little_endian force for irizx
+ *
+ * Revision 1.8  1995/02/02  22:02:18  smoot
+ * added ifdefs for compatability on stranger and stranger architectures...
+ *
+ * Revision 1.7  1995/02/02  07:26:45  eyhung
+ * added parens to all.h to remove compiler warning
+ *
+ * Revision 1.6  1995/02/02  01:47:11  eyhung
+ * added MAXINT
+ *
+ * Revision 1.5  1995/01/19  23:54:33  eyhung
+ * Changed copyrights
+ *
+ * Revision 1.4  1994/11/14  22:52:04  smoot
+ * Added linux #include for time.h
+ *
+ * Revision 1.3  1994/11/12  02:12:13  keving
+ * nothing
+ *
+ * Revision 1.2  1993/07/22  22:24:23  keving
+ * nothing
+ *
+ * Revision 1.1  1993/07/09  00:17:23  keving
+ * nothing
+ *
+ */
+
+
+#ifndef ENCODE_ALL_INCLUDED
+#define ENCODE_ALL_INCLUDED
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <memory.h>
+#include <limits.h>
+
+/* There's got to be a better way.... */
+#ifdef LINUX
+#include <time.h>
+#endif
+#ifdef MIPS
+#include <time.h>
+#endif
+#ifdef IRIX
+#define FORCE_LITTLE_ENDIAN
+#include <time.h>
+#endif
+
+#include "ansi.h"
+#include "general.h"
+
+/* some machines have #define index strchr; get rid of this nonsense */
+#ifdef index
+#undef index
+#endif /* index */
+
+#ifndef MAXINT
+#define MAXINT 0x7fffffff
+#endif
+
+#endif /* ENCODE_ALL_INCLUDED */
diff --git a/converter/ppm/ppmtompeg/headers/ansi.h b/converter/ppm/ppmtompeg/headers/ansi.h
new file mode 100644
index 00000000..b3c3ab17
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/ansi.h
@@ -0,0 +1,76 @@
+/*===========================================================================*
+ * ansi.h								     *
+ *									     *
+ *	macro for non-ansi compilers					     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /n/picasso/project/mpeg/mpeg_dist/mpeg_encode/headers/RCS/ansi.h,v 1.6 1995/08/15 23:43:13 smoot Exp $
+ *  $Log: ansi.h,v $
+ *  Revision 1.6  1995/08/15 23:43:13  smoot
+ *  *** empty log message ***
+ *
+ *  Revision 1.5  1995/01/19 23:54:35  eyhung
+ *  Changed copyrights
+ *
+ * Revision 1.4  1994/11/12  02:12:13  keving
+ * nothing
+ *
+ * Revision 1.3  1993/07/22  22:24:23  keving
+ * nothing
+ *
+ * Revision 1.2  1993/07/09  00:17:23  keving
+ * nothing
+ *
+ * Revision 1.1  1993/06/14  22:50:22  keving
+ * nothing
+ *
+ */
+
+
+#ifndef ANSI_INCLUDED
+#define ANSI_INCLUDED
+
+
+/*  
+ *  _ANSI_ARGS_ macro stolen from Tcl6.5 by John Ousterhout
+ */
+#undef _ANSI_ARGS_
+#undef const
+#ifdef NON_ANSI_COMPILER
+#define _ANSI_ARGS_(x)       ()
+#define CONST
+#else
+#define _ANSI_ARGS_(x)   x
+#define CONST const
+#ifdef __cplusplus
+#define VARARGS (...)
+#else
+#define VARARGS ()
+#endif
+#endif
+
+
+#endif /* ANSI_INCLUDED */
diff --git a/converter/ppm/ppmtompeg/headers/bitio.h b/converter/ppm/ppmtompeg/headers/bitio.h
new file mode 100644
index 00000000..89e61fbb
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/bitio.h
@@ -0,0 +1,140 @@
+/*===========================================================================*
+ * bitio.h								     *
+ *									     *
+ *	bitwise input/output						     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /n/charlie-brown/project/mm/mpeg/mpeg_dist/mpeg_encode/headers/RCS/bitio.h,v 1.8 1995/01/19 23:54:37 eyhung Exp $
+ *  $Log: bitio.h,v $
+ * Revision 1.8  1995/01/19  23:54:37  eyhung
+ * Changed copyrights
+ *
+ * Revision 1.7  1994/11/12  02:12:14  keving
+ * nothing
+ *
+ * Revision 1.6  1993/07/22  22:24:23  keving
+ * nothing
+ *
+ * Revision 1.5  1993/07/09  00:17:23  keving
+ * nothing
+ *
+ * Revision 1.4  1993/06/03  21:08:53  keving
+ * nothing
+ *
+ * Revision 1.3  1993/01/18  10:20:02  dwallach
+ * *** empty log message ***
+ *
+ * Revision 1.2  1993/01/18  10:17:29  dwallach
+ * RCS headers installed, code indented uniformly
+ *
+ * Revision 1.2  1993/01/18  10:17:29  dwallach
+ * RCS headers installed, code indented uniformly
+ *
+ */
+
+
+#ifndef BIT_IO_INCLUDED
+#define BIT_IO_INCLUDED
+
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "general.h"
+#include "ansi.h"
+
+
+/*===========*
+ * CONSTANTS *
+ *===========*/
+
+#define WORDS_PER_BUCKET 128
+#define MAXBITS_PER_BUCKET	(WORDS_PER_BUCKET * 32)
+#define	MAX_BUCKETS	128
+#define MAX_BITS	MAX_BUCKETS*MAXBITS_PER_BUCKET
+
+
+/*=======================*
+ * STRUCTURE DEFINITIONS *
+ *=======================*/
+
+typedef struct bitBucket {
+    struct bitBucket *nextPtr;
+    uint32 bits[WORDS_PER_BUCKET];
+    int bitsleft, bitsleftcur, currword;
+} ActualBucket;
+
+typedef struct _BitBucket {
+    int totalbits;
+    int	cumulativeBits;
+    int	bitsWritten;
+    FILE    *filePtr;
+    ActualBucket *firstPtr;
+    ActualBucket *lastPtr;
+} BitBucket;
+
+
+/*========*
+ * MACROS *
+ *========*/
+
+#define	SET_ITH_BIT(bits, i)	(bits |= (1 << (i)))
+#define	GET_ITH_BIT(bits, i)	(bits & (1 << (i)))
+
+
+/*===============================*
+ * EXTERNAL PROCEDURE prototypes *
+ *===============================*/
+
+void	    
+Bitio_Free(BitBucket * const bbPtr);
+
+void
+Bitio_Write(BitBucket * const bbPtr, 
+            uint32      const bits, 
+            int         const nbits);
+
+void
+Bitio_BytePad(BitBucket * const bbPtr);
+
+BitBucket *
+Bitio_New(FILE * const filePtr);
+
+BitBucket *
+Bitio_New_Filename(const char * const fileName);
+
+void
+Bitio_Flush(BitBucket * const bbPtr);
+
+void
+Bitio_Close(BitBucket * const bbPtr);
+
+void
+Bitio_WriteToSocket(BitBucket * const bbPtr, 
+                    int         const socket);
+
+#endif /* BIT_IO_INCLUDED */
diff --git a/converter/ppm/ppmtompeg/headers/block.h b/converter/ppm/ppmtompeg/headers/block.h
new file mode 100644
index 00000000..46050492
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/block.h
@@ -0,0 +1,53 @@
+void
+ComputeDiffDCTs(MpegFrame * const current,
+                MpegFrame * const prev,
+                int         const by,
+                int         const bx,
+                vector      const m,
+                int *       const pattern);
+
+void
+ComputeDiffDCTBlock(Block           current,
+                    Block           dest,
+                    Block           motionBlock,
+                    boolean * const significantDifferenceP);
+
+void
+ComputeMotionBlock(uint8 ** const prev,
+                   int      const by,
+                   int      const bx,
+                   vector   const m,
+                   Block *  const motionBlockP);
+
+void
+ComputeMotionLumBlock(MpegFrame * const prevFrame,
+                      int         const by,
+                      int         const bx,
+                      vector      const m,
+                      LumBlock *  const motionBlockP);
+
+void
+BlockToData(uint8 ** const data,
+            Block          block,
+            int      const by,
+            int      const bx);
+
+void
+AddMotionBlock(Block          block,
+               uint8 ** const prev,
+               int      const by,
+               int      const bx,
+               vector   const m);
+
+void
+AddBMotionBlock(Block          block,
+                uint8 ** const prev,
+                uint8 ** const next,
+                int      const by,
+                int      const bx,
+                int      const mode,
+                motion   const motion);
+
+void
+BlockifyFrame(MpegFrame * const frameP);
+
diff --git a/converter/ppm/ppmtompeg/headers/byteorder.h b/converter/ppm/ppmtompeg/headers/byteorder.h
new file mode 100644
index 00000000..0070252a
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/byteorder.h
@@ -0,0 +1,77 @@
+/*===========================================================================*
+ * byteorder.h								     *
+ *									     *
+ *	stuff to handle different byte order				     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /u/smoot/md/mpeg_encode/headers/RCS/byteorder.h,v 1.3 1995/01/19 23:54:39 eyhung Exp $
+ *  $Log: byteorder.h,v $
+ * Revision 1.3  1995/01/19  23:54:39  eyhung
+ * Changed copyrights
+ *
+ * Revision 1.3  1995/01/19  23:54:39  eyhung
+ * Changed copyrights
+ *
+ * Revision 1.2  1994/11/12  02:12:15  keving
+ * nothing
+ *
+ * Revision 1.1  1993/07/22  22:24:23  keving
+ * nothing
+ *
+ */
+
+
+#include "general.h"
+
+
+#ifdef FORCE_BIG_ENDIAN
+    /* leave byte order as it is */
+#define htonl(x) (x)
+#define ntohl(x) (x)
+#define htons(x) (x)
+#define ntohs(x) (x)
+#else
+#ifdef FORCE_LITTLE_ENDIAN
+    /* need to reverse byte order */
+    /* note -- we assume here that htonl is called on a variable, not a
+     * constant; thus, this is not for general use, but works with bitio.c
+     */
+#define htonl(x)    \
+    ((((unsigned char *)(&x))[0] << 24) |	\
+     (((unsigned char *)(&x))[1] << 16) |	\
+     (((unsigned char *)(&x))[2] << 8) |	\
+     (((unsigned char *)(&x))[3]))
+#define ntohl(x)    htonl(x)
+#define htons(x)    \
+    ((((unsigned char *)(&x))[0] << 8) |	\
+     ((unsigned char *)(&x))[1])
+#define ntohs(x)    htons(x)
+#else
+    /* let in.h handle it, if possible */		   
+#include <sys/types.h>
+#include <netinet/in.h>
+#endif /* FORCE_LITTLE_ENDIAN */
+#endif /* FORCE_BIG_ENDIAN */
diff --git a/converter/ppm/ppmtompeg/headers/combine.h b/converter/ppm/ppmtompeg/headers/combine.h
new file mode 100644
index 00000000..e28c6dee
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/combine.h
@@ -0,0 +1,20 @@
+struct inputSource;
+
+void
+GOPsToMPEG(struct inputSource * const inputSourceP,
+           const char *         const outputFileName, 
+           FILE *               const outputFilePtr);
+
+typedef void (*fileAcquisitionFn)(void *       const handle,
+                                  unsigned int const frameNumber,
+                                  FILE **      const ifPP);
+
+
+typedef void (*fileDispositionFn)(void *       const handle,
+                                  unsigned int const frameNumber);
+
+void
+FramesToMPEG(FILE *               const outputFile, 
+             void *               const inputHandle,
+             fileAcquisitionFn          acquireInputFile,
+             fileDispositionFn          disposeInputFile);
diff --git a/converter/ppm/ppmtompeg/headers/dct.h b/converter/ppm/ppmtompeg/headers/dct.h
new file mode 100644
index 00000000..e024b6c1
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/dct.h
@@ -0,0 +1,79 @@
+/*===========================================================================*
+ * dct.h								     *
+ *									     *
+ *	DCT procedures							     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+
+#ifndef DCT_INCLUDED
+#define DCT_INCLUDED
+
+
+#include "ansi.h"
+
+
+
+#define DCTSIZE     8   /* you really don't want to change this */
+#define DCTSIZE_SQ 64   /* you really don't want to change this */
+
+#define DCTSIZE2    64
+typedef short DCTELEM;
+typedef DCTELEM DCTBLOCK[DCTSIZE2];
+typedef DCTELEM DCTBLOCK_2D[DCTSIZE][DCTSIZE];
+
+
+/*  
+ *  from mfwddct.c:
+ */
+extern void mp_fwd_dct_block2 _ANSI_ARGS_((DCTBLOCK_2D src, DCTBLOCK_2D dest));
+
+/* jrevdct.c */
+extern void init_pre_idct _ANSI_ARGS_((void ));
+extern void mpeg_jrevdct _ANSI_ARGS_((DCTBLOCK data ));
+
+
+/* We assume that right shift corresponds to signed division by 2 with
+ * rounding towards minus infinity.  This is correct for typical "arithmetic
+ * shift" instructions that shift in copies of the sign bit.  But some
+ * C compilers implement >> with an unsigned shift.  For these machines you
+ * must define RIGHT_SHIFT_IS_UNSIGNED.
+ * RIGHT_SHIFT provides a proper signed right shift of an int32 quantity.
+ * It is only applied with constant shift counts.  SHIFT_TEMPS must be
+ * included in the variables of any routine using RIGHT_SHIFT.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define SHIFT_TEMPS     int32 shift_temp;
+#define RIGHT_SHIFT(x,shft)  \
+        ((shift_temp = (x)) < 0 ? \
+         (shift_temp >> (shft)) | ((~((int32) 0)) << (32-(shft))) : \
+         (shift_temp >> (shft)))
+#else
+#define SHIFT_TEMPS
+#define RIGHT_SHIFT(x,shft)     ((x) >> (shft))
+#endif
+
+
+#endif /* DCT_INCLUDED */
diff --git a/converter/ppm/ppmtompeg/headers/frame.h b/converter/ppm/ppmtompeg/headers/frame.h
new file mode 100644
index 00000000..1003ee15
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/frame.h
@@ -0,0 +1,147 @@
+/*===========================================================================*
+ * frame.h								     *
+ *									     *
+ *	basic frames procedures						     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+
+#ifndef FRAME_INCLUDED
+#define FRAME_INCLUDED
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "general.h"
+#include "ansi.h"
+#include "mtypes.h"
+
+/*===========*
+ * CONSTANTS *
+ *===========*/
+#define TYPE_IFRAME	2
+#define TYPE_PFRAME	3
+#define TYPE_BFRAME	4
+
+
+/*=======================*
+ * STRUCTURE DEFINITIONS *
+ *=======================*/
+
+typedef struct mpegFrame {
+    int type;
+    char    inputFileName[256];
+    int id;           /* the frame number -- starts at 0 */
+    boolean inUse;	/* TRUE iff this frame is currently being used */
+			/* FALSE means any data here can be thrashed */
+
+    /*  
+     *  now, the YCrCb data.  All pixel information is stored in unsigned
+     *  8-bit pieces.  We separate y, cr, and cb because cr and cb are
+     *  subsampled by a factor of 2.
+     *
+     *  if orig_y is NULL, then orig_cr, orig_cb are undefined
+     */
+    uint8 **orig_y, **orig_cr, **orig_cb;
+
+    /* now, the decoded data -- relevant only if
+     *	    referenceFrame == DECODED_FRAME
+     *
+     * if decoded_y is NULL, then decoded_cr, decoded_cb are undefined 
+     */
+    uint8 **decoded_y, **decoded_cr, **decoded_cb;
+
+    /* reference data */
+    uint8 **ref_y, **ref_cr, **ref_cb;
+
+    /*  
+     *  these are the Blocks which will ultimately compose MacroBlocks.
+     *  A Block is in a format that mp_fwddct() can crunch.
+     *  if y_blocks is NULL, then cr_blocks, cb_blocks are undefined
+     */
+    Block **y_blocks, **cr_blocks, **cb_blocks;
+
+    /*
+     *  this is the half-pixel luminance data (for reference frames)
+     */
+    uint8 **halfX, **halfY, **halfBoth;
+
+    boolean   halfComputed;        /* TRUE iff half-pixels already computed */
+
+    struct mpegFrame *next;  /* points to the next B-frame to be encoded, if
+		       * stdin is used as the input. 
+		       */
+} MpegFrame;
+
+
+void
+Frame_Init(unsigned int const numOfFramesRequested);
+
+void
+Frame_Exit(void);
+
+void
+Frame_Free(MpegFrame * const frameP);
+
+MpegFrame *
+Frame_New(int const id,
+          int const type);
+
+void
+Frame_AllocBlocks(MpegFrame * const frameP);
+
+void
+Frame_AllocYCC(MpegFrame * const frameP);
+
+void
+Frame_AllocHalf(MpegFrame * const frameP);
+
+void
+Frame_AllocDecoded(MpegFrame * const frameP,
+                   boolean     const makeReference);
+
+void
+Frame_Resize(MpegFrame * const omf,
+             MpegFrame * const mf,
+             int         const insize_x,
+             int         const insize_y,
+             int         const outsize_x,
+             int         const outsize_y);
+
+
+extern void	  Frame_Free _ANSI_ARGS_((MpegFrame *frame));
+extern void	  Frame_Exit _ANSI_ARGS_((void));
+extern void	  Frame_AllocPPM _ANSI_ARGS_((MpegFrame * frame));
+extern void	  Frame_AllocYCC _ANSI_ARGS_((MpegFrame * mf));
+extern void	  Frame_AllocDecoded _ANSI_ARGS_((MpegFrame *frame,
+						  boolean makeReference));
+extern void	  Frame_AllocHalf _ANSI_ARGS_((MpegFrame *frame));
+extern void	  Frame_AllocBlocks _ANSI_ARGS_((MpegFrame *mf));
+extern void	  Frame_Resize _ANSI_ARGS_((MpegFrame *omf, MpegFrame *mf,
+					    int insize_x, int insize_y,
+					    int outsize_x, int outsize_y));
+
+
+#endif /* FRAME_INCLUDED */
diff --git a/converter/ppm/ppmtompeg/headers/frames.h b/converter/ppm/ppmtompeg/headers/frames.h
new file mode 100644
index 00000000..3fefaea7
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/frames.h
@@ -0,0 +1,487 @@
+/*===========================================================================*
+ * frames.h                                  
+ *                                       
+ *  stuff dealing with frames                        
+ *                                       
+ *===========================================================================*/
+
+#ifndef FRAMES_INCLUDED
+#define FRAMES_INCLUDED
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "ansi.h"
+#include "mtypes.h"
+#include "mheaders.h"
+#include "frame.h"
+
+
+/*===========*
+ * CONSTANTS *
+ *===========*/
+
+#define I_FRAME 1
+#define P_FRAME 2
+#define B_FRAME 3
+
+#define LUM_BLOCK   0
+#define CHROM_BLOCK 1
+#define CR_BLOCK    2
+#define CB_BLOCK    3
+
+#define MOTION_FORWARD      0
+#define MOTION_BACKWARD     1
+#define MOTION_INTERPOLATE  2
+
+
+#define USE_HALF    0
+#define USE_FULL    1
+
+    /* motion vector stuff */
+#define FORW_F_CODE fCode       /* from picture header */
+#define BACK_F_CODE fCode
+#define FORW_F  (1 << (FORW_F_CODE - 1))
+#define BACK_F  (1 << (BACK_F_CODE - 1))
+#define RANGE_NEG   (-(1 << (3 + FORW_F_CODE)))
+#define RANGE_POS   ((1 << (3 + FORW_F_CODE))-1)
+#define MODULUS     (1 << (4 + FORW_F_CODE))
+
+#define ORIGINAL_FRAME  0
+#define DECODED_FRAME   1
+
+
+/*=======================*
+ * STRUCTURE DEFINITIONS *
+ *=======================*/
+
+typedef struct FrameTableStruct {
+    /* the following are all initted once and never changed */
+    /* (they depend only on the pattern */
+    char typ;
+    struct FrameTableStruct *next;
+    struct FrameTableStruct *prev;
+
+    /* nextOutput is a pointer to next frame table entry to output */
+    struct FrameTableStruct *nextOutput;
+
+    boolean freeNow;    /* TRUE iff no frames point back to this */
+
+    int number;
+
+    int bFrameNumber;       /* actual frame number, if a b-frame */
+    
+} FrameTable;
+
+
+/*==================*
+ * TYPE DEFINITIONS *
+ *==================*/
+
+typedef struct dct_data_tye_struct {
+  char useMotion;
+  char pattern, mode;
+  int fmotionX, fmotionY, bmotionX, bmotionY;
+} dct_data_type;
+
+void    EncodeYDC _ANSI_ARGS_((int32 dc_term, int32 *pred_term, BitBucket *bb));
+void
+EncodeCDC(int32       const dc_term,
+          int32     * const pred_term,
+          BitBucket * const bb);
+
+
+/*========*
+ * MACROS *
+ *========*/
+
+/* return ceiling(a/b) where a, b are ints, using temp value c */
+#define int_ceil_div(a,b,c)     ((b*(c = a/b) < a) ? (c+1) : c)
+#define int_floor_div(a,b,c)    ((b*(c = a/b) > a) ? (c-1) : c)
+
+/* assumes many things:
+ * block indices are (y,x)
+ * variables y_dc_pred, cr_dc_pred, and cb_dc_pred
+ * flat block fb exists
+ */
+#define GEN_I_BLOCK(frameType, frame, bb, mbAI, qscale) {                   \
+    boolean overflow, overflowChange=FALSE;                             \
+        int overflowValue = 0;                                              \
+        do {                                                                \
+      overflow =  Mpost_QuantZigBlock(dct[y][x], fb[0],                 \
+             qscale, TRUE)==MPOST_OVERFLOW;                     \
+          overflow |= Mpost_QuantZigBlock(dct[y][x+1], fb[1],               \
+                 qscale, TRUE)==MPOST_OVERFLOW;                     \
+      overflow |= Mpost_QuantZigBlock(dct[y+1][x], fb[2],               \
+                         qscale, TRUE)==MPOST_OVERFLOW;                     \
+      overflow |= Mpost_QuantZigBlock(dct[y+1][x+1], fb[3],             \
+                         qscale, TRUE)==MPOST_OVERFLOW;                     \
+      overflow |= Mpost_QuantZigBlock(dctb[y >> 1][x >> 1],             \
+                         fb[4], qscale, TRUE)==MPOST_OVERFLOW;              \
+      overflow |= Mpost_QuantZigBlock(dctr[y >> 1][x >> 1],             \
+             fb[5], qscale, TRUE)==MPOST_OVERFLOW;              \
+          if ((overflow) && (qscale!=31)) {                                 \
+           overflowChange = TRUE; overflowValue++;                          \
+       qscale++;                                                        \
+       } else overflow = FALSE;                                         \
+    } while (overflow);                                                 \
+        Mhead_GenMBHeader(bb,                           \
+            frameType /* pict_code_type */, mbAI /* addr_incr */,   \
+            qscale /* q_scale */,                               \
+            0 /* forw_f_code */, 0 /* back_f_code */,           \
+            0 /* horiz_forw_r */, 0 /* vert_forw_r */,          \
+            0 /* horiz_back_r */, 0 /* vert_back_r */,          \
+            0 /* motion_forw */, 0 /* m_horiz_forw */,          \
+            0 /* m_vert_forw */, 0 /* motion_back */,           \
+            0 /* m_horiz_back */, 0 /* m_vert_back */,          \
+            0 /* mb_pattern */, TRUE /* mb_intra */);           \
+                                        \
+    /* Y blocks */                              \
+        EncodeYDC(fb[0][0], &y_dc_pred, bb);                            \
+    Mpost_RLEHuffIBlock(fb[0], bb);                         \
+    EncodeYDC(fb[1][0], &y_dc_pred, bb);                        \
+        Mpost_RLEHuffIBlock(fb[1], bb);                             \
+    EncodeYDC(fb[2][0], &y_dc_pred, bb);                        \
+    Mpost_RLEHuffIBlock(fb[2], bb);                         \
+    EncodeYDC(fb[3][0], &y_dc_pred, bb);                        \
+    Mpost_RLEHuffIBlock(fb[3], bb);                         \
+                                        \
+    /* CB block */                              \
+    EncodeCDC(fb[4][0], &cb_dc_pred, bb);                   \
+    Mpost_RLEHuffIBlock(fb[4], bb);                     \
+                                        \
+    /* CR block */                              \
+    EncodeCDC(fb[5][0], &cr_dc_pred, bb);                   \
+    Mpost_RLEHuffIBlock(fb[5], bb);                     \
+    if (overflowChange) qscale -= overflowValue;                        \
+    }
+
+#define BLOCK_TO_FRAME_COORD(bx1, bx2, x1, x2) {    \
+    x1 = (bx1)*DCTSIZE;             \
+    x2 = (bx2)*DCTSIZE;             \
+    }
+
+static __inline__ void
+MotionToFrameCoord(int   const by,
+                   int   const bx,
+                   int   const my,
+                   int   const mx,
+                   int * const yP,
+                   int * const xP) {
+/*----------------------------------------------------------------------------
+   Given a DCT block location and a motion vector, return the pixel
+   coordinates to which the upper left corner of the block moves.
+
+   Return negative coordinates if it moves out of frame.
+-----------------------------------------------------------------------------*/
+    *yP = by * DCTSIZE + my;
+    *xP = bx * DCTSIZE + mx;
+}
+
+#define COORD_IN_FRAME(fy,fx, type)                 \
+    ((type == LUM_BLOCK) ?                      \
+     ((fy >= 0) && (fx >= 0) && (fy < Fsize_y) && (fx < Fsize_x)) : \
+     ((fy >= 0) && (fx >= 0) && (fy < (Fsize_y>>1)) && (fx < (Fsize_x>>1))))
+
+
+static __inline__ void
+encodeMotionVector(int      const x,
+                   int      const y,
+                   vector * const qP,
+                   vector * const rP,
+                   int      const f,
+                   int      const fCode) {
+
+    int tempX;
+    int tempY;
+    int tempC;
+
+    if (x < RANGE_NEG)
+        tempX = x + MODULUS;
+    else if (x > RANGE_POS)
+        tempX = x - MODULUS;
+    else
+        tempX = x;
+
+    if (y < RANGE_NEG)
+        tempY = y + MODULUS;
+    else if (y > RANGE_POS)
+        tempY = y - MODULUS;
+    else
+        tempY = y;
+
+    if (tempX >= 0) {
+        qP->x = int_ceil_div(tempX, f, tempC);
+        rP->x = f - 1 + tempX - qP->x*f;
+    } else {
+        qP->x = int_floor_div(tempX, f, tempC);
+        rP->x = f - 1 - tempX + qP->x*f;
+    }
+
+    if (tempY >= 0) {
+        qP->y = int_ceil_div(tempY, f, tempC);
+        rP->y = f - 1 + tempY - qP->y*f;
+    } else {
+        qP->y = int_floor_div(tempY, f, tempC);
+        rP->y = f - 1 - tempY + qP->y*f;
+    }
+}
+
+
+#define DoQuant(bit, src, dest)                                         \
+  if (pattern & bit) {                                                  \
+    switch (Mpost_QuantZigBlock(src, dest, QScale, FALSE)) {            \
+    case MPOST_NON_ZERO:                                                \
+      break;                                                            \
+    case MPOST_ZERO:                                                    \
+      pattern ^= bit;                                                   \
+      break;                                                            \
+    case MPOST_OVERFLOW:                                                \
+      if (QScale != 31) {                                               \
+    QScale++;                                                       \
+    overflowChange = TRUE;                                          \
+    overflowValue++;                                                \
+    goto calc_blocks;                                               \
+      }                                                                 \
+      break;                                                            \
+    }                                                                   \
+  }
+
+/*===============================*
+ * EXTERNAL PROCEDURE prototypes *
+ *===============================*/
+
+void
+ComputeBMotionLumBlock(MpegFrame * const prev,
+                       MpegFrame * const next,
+                       int         const by,
+                       int         const bx,
+                       int         const mode,
+                       motion      const motion,
+                       LumBlock *  const motionBlockP);
+
+int
+BMotionSearch(const LumBlock * const currentBlockP,
+              MpegFrame *      const prev,
+              MpegFrame *      const next,
+              int              const by,
+              int              const bx,
+              motion *         const motionP,
+              int              const oldMode);
+
+void GenIFrame (BitBucket * const bb,
+                MpegFrame * const mf);
+void GenPFrame (BitBucket * const bb,
+                MpegFrame * const current,
+                MpegFrame * const prev);
+void GenBFrame (BitBucket * const bb,
+                MpegFrame * const curr,
+                MpegFrame * const prev,
+                MpegFrame * const next);
+void    AllocDctBlocks _ANSI_ARGS_((void ));
+
+
+float
+IFrameTotalTime(void);
+
+float
+PFrameTotalTime(void);
+
+float
+BFrameTotalTime(void);
+
+void
+ShowIFrameSummary(unsigned int const inputFrameBits, 
+                  unsigned int const totalBits, 
+                  FILE *       const fpointer);
+
+void
+ShowPFrameSummary(unsigned int const inputFrameBits, 
+                  unsigned int const totalBits, 
+                  FILE *       const fpointer);
+
+void
+ShowBFrameSummary(unsigned int const inputFrameBits, 
+                  unsigned int const totalBits, 
+                  FILE *       const fpointer);
+
+/* DIFFERENCE FUNCTIONS */
+
+int32
+LumBlockMAD(const LumBlock * const currentBlockP,
+            const LumBlock * const motionBlockP,
+            int32            const bestSoFar);
+
+int32
+LumBlockMSE(const LumBlock * const currentBlockP,
+            const LumBlock * const motionBlockP,
+            int32            const bestSoFar);
+
+int32
+LumMotionError(const LumBlock * const currentBlockP,
+               MpegFrame *      const prev,
+               int              const by,
+               int              const bx,
+               vector           const m,
+               int32            const bestSoFar);
+
+int32
+LumAddMotionError(const LumBlock * const currentBlockP,
+                  const LumBlock * const blockSoFarP,
+                  MpegFrame *      const prev,
+                  int              const by,
+                  int              const bx,
+                  vector           const m,
+                  int32            const bestSoFar);
+
+int32
+LumMotionErrorA(const LumBlock * const currentBlockP,
+                MpegFrame *      const prevFrame,
+                int              const by,
+                int              const bx,
+                vector           const m,
+                int32            const bestSoFar);
+
+int32
+LumMotionErrorB(const LumBlock * const currentP,
+                MpegFrame *      const prevFrame,
+                int              const by,
+                int              const bx,
+                vector           const m,
+                int32            const bestSoFar);
+
+int32
+LumMotionErrorC(const LumBlock * const currentP,
+                MpegFrame *      const prevFrame,
+                int              const by,
+                int              const bx,
+                vector           const m,
+                int32            const bestSoFar);
+
+int32
+LumMotionErrorD(const LumBlock * const currentP,
+                MpegFrame *      const prevFrame,
+                int              const by,
+                int              const bx,
+                vector           const m,
+                int32            const bestSoFar);
+
+int32
+LumMotionErrorSubSampled(const LumBlock * const currentBlockP,
+                         MpegFrame *      const prevFrame,
+                         int              const by,
+                         int              const bx,
+                         vector           const m,
+                         int              const startY,
+                         int              const startX);
+
+void
+BlockComputeSNR(MpegFrame * const current,
+                float *     const snr,
+                float *     const psnr);
+
+int32
+time_elapsed(void);
+
+void
+AllocDctBlocks(void);
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+
+extern int pixelFullSearch;
+extern int searchRangeP,searchRangeB;  /* defined in psearch.c */
+extern int qscaleI;
+extern int gopSize;
+extern int slicesPerFrame;
+extern int blocksPerSlice;
+extern int referenceFrame;
+extern int specificsOn;
+extern int quietTime;       /* shut up for at least quietTime seconds;
+                 * negative means shut up forever
+                 */
+extern boolean realQuiet;   /* TRUE = no messages to stdout */
+
+extern boolean frameSummary;    /* TRUE = frame summaries should be printed */
+extern boolean  printSNR;
+extern boolean  printMSE;
+extern boolean  decodeRefFrames;    /* TRUE = should decode I and P frames */
+extern int  fCodeI,fCodeP,fCodeB;
+extern boolean    forceEncodeLast;
+extern int TIME_RATE;
+
+#endif /* FRAMES_INCLUDED */
+
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /n/picasso/project/mpeg/mpeg_dist/mpeg_encode/headers/RCS/frames.h,v 1.13 1995/08/15 23:43:04 smoot Exp $
+ *  $Log: frames.h,v $
+ *  Revision 1.13  1995/08/15 23:43:04  smoot
+ *  *** empty log message ***
+ *
+ * Revision 1.12  1995/04/14  23:13:18  smoot
+ * Reorganized for better rate control.  Added overflow in DCT values
+ * handling.
+ *
+ * Revision 1.11  1995/01/19  23:54:46  smoot
+ * allow computediffdcts to un-assert parts of the pattern
+ *
+ * Revision 1.10  1995/01/16  07:43:10  eyhung
+ * Added realQuiet
+ *
+ * Revision 1.9  1995/01/10  23:15:28  smoot
+ * Fixed searchRange lack of def
+ *
+ * Revision 1.8  1994/11/15  00:55:36  smoot
+ * added printMSE
+ *
+ * Revision 1.7  1994/11/14  22:51:02  smoot
+ * added specifics flag.  Added BlockComputeSNR parameters
+ *
+ * Revision 1.6  1994/11/01  05:07:23  darryl
+ *  with rate control changes added
+ *
+ * Revision 1.1  1994/09/27  01:02:55  darryl
+ * Initial revision
+ *
+ * Revision 1.5  1993/07/22  22:24:23  keving
+ * nothing
+ *
+ * Revision 1.4  1993/07/09  00:17:23  keving
+ * nothing
+ *
+ * Revision 1.3  1993/06/03  21:08:53  keving
+ * nothing
+ *
+ * Revision 1.2  1993/03/02  19:00:27  keving
+ * nothing
+ *
+ * Revision 1.1  1993/02/19  20:15:51  keving
+ * nothing
+ *
+ */
+
+
diff --git a/converter/ppm/ppmtompeg/headers/frametype.h b/converter/ppm/ppmtompeg/headers/frametype.h
new file mode 100644
index 00000000..63bee964
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/frametype.h
@@ -0,0 +1,17 @@
+#ifndef FRAMETYPE_H_INCLUDED
+#define FRAMETYPE_H_INCLUDED
+
+char
+FType_Type(unsigned int const frameNum);
+
+unsigned int
+FType_FutureRef(unsigned int const currFrameNum);
+
+int	FType_PastRef _ANSI_ARGS_((int currFrameNum));
+
+void SetFramePattern(const char * const pattern);
+
+void
+ComputeFrameTable(unsigned int const numFrames);
+
+#endif
diff --git a/converter/ppm/ppmtompeg/headers/fsize.h b/converter/ppm/ppmtompeg/headers/fsize.h
new file mode 100644
index 00000000..6a1c910e
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/fsize.h
@@ -0,0 +1,49 @@
+/*===========================================================================*
+ * fsize.h								     *
+ *									     *
+ *	procedures to deal with frame size				     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+
+#ifndef FSIZE_H_INCLUDED
+#define FSIZE_H_INCLUDED
+
+extern int Fsize_x;
+extern int Fsize_y;
+
+
+void
+Fsize_Reset(void);
+
+void
+Fsize_Validate(int * const xP,
+               int * const yP);
+
+void
+Fsize_Note(int          const id,
+           unsigned int const width,
+           unsigned int const height);
+
+#endif
diff --git a/converter/ppm/ppmtompeg/headers/general.h b/converter/ppm/ppmtompeg/headers/general.h
new file mode 100644
index 00000000..f29c9445
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/general.h
@@ -0,0 +1,174 @@
+/*===========================================================================*
+ * general.h								     *
+ *									     *
+ *	very general stuff						     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /n/picasso/project/mpeg/mpeg_dist/mpeg_encode/headers/RCS/general.h,v 1.7 1995/08/04 23:34:13 smoot Exp $
+ *  $Log: general.h,v $
+ *  Revision 1.7  1995/08/04 23:34:13  smoot
+ *  jpeg5 changed the silly HAVE_BOOLEAN define....
+ *
+ *  Revision 1.6  1995/01/19 23:54:49  eyhung
+ *  Changed copyrights
+ *
+ * Revision 1.5  1994/11/12  02:12:48  keving
+ * nothing
+ *
+ * Revision 1.4  1993/07/22  22:24:23  keving
+ * nothing
+ *
+ * Revision 1.3  1993/07/09  00:17:23  keving
+ * nothing
+ *
+ * Revision 1.2  1993/06/03  21:08:53  keving
+ * nothing
+ *
+ * Revision 1.1  1993/02/22  22:39:19  keving
+ * nothing
+ *
+ */
+
+
+#ifndef GENERAL_INCLUDED
+#define GENERAL_INCLUDED
+
+
+/* prototypes for library procedures
+ *
+ * if your /usr/include headers do not have these, then pass -DMISSING_PROTOS
+ * to your compiler
+ *
+ */ 
+#ifdef MISSING_PROTOS
+int fprintf();
+int fwrite();
+int fread();
+int fflush();
+int fclose();
+
+int sscanf();
+int bzero();
+int bcopy();
+int system();
+int time();
+int perror();
+
+int socket();
+int bind();
+int listen();
+int accept();
+int connect();
+int close();
+int read();
+int write();
+
+int pclose();
+
+#endif
+
+
+/*===========*
+ * CONSTANTS *
+ *===========*/
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define SPACE ' '
+#define TAB '\t'
+#define SEMICOLON ';'
+#define NULL_CHAR '\0'
+#define NEWLINE '\n'
+
+
+/*==================*
+ * TYPE DEFINITIONS *
+ *==================*/
+
+#ifndef HAVE_BOOLEAN
+typedef int boolean;
+#define HAVE_BOOLEAN
+/* JPEG library also defines boolean */
+#endif
+
+/* In the following, we need the "signed" in order to make these typedefs
+   match those in AIX system header files.  Otherwise, compile fails on 
+   AIX.  2000.09.11.
+*/
+typedef unsigned char uint8;
+typedef signed char int8;
+typedef unsigned short uint16;
+typedef signed short int16;
+
+/* The 32 bit integer types are probably obsolete.
+
+   parallel.c used to use them as buffers for socket I/O, because in the
+   protocol on the socket, an integer is represented by 4 octets.  But
+   the proper type for that is unsigned char[4], so we changed parallel.c
+   to that in September 2004.
+
+   A user of TRU64 4.0f in May 2000 used a -DLONG_32 option, but did
+   not indicate that it was really necessary.  After that, Configure
+   added -DLONG_32 for all TRU64 builds.  A user of TRU64 5.1A in July
+   2003 demonstrated that int is in fact 4 bytes on his machine (and
+   long is 8 bytes).  So we removed the -DLONG_32 from Configure.  This
+   whole issue may too be obsolete because of the fixing of parallel.c
+   mentioned above.
+*/
+
+    /* LONG_32 should only be defined iff
+     *	    1) long's are 32 bits and
+     *	    2) int's are not
+     */
+#ifdef LONG_32		
+typedef unsigned long uint32;
+typedef long int32;
+#else
+typedef unsigned int uint32;
+typedef signed int int32;
+#endif
+
+
+/*========*
+ * MACROS *
+ *========*/
+
+#undef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#undef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#undef abs
+#define abs(a) ((a) >= 0 ? (a) : -(a))
+
+
+#endif
diff --git a/converter/ppm/ppmtompeg/headers/huff.h b/converter/ppm/ppmtompeg/headers/huff.h
new file mode 100644
index 00000000..47ffb843
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/huff.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /n/charlie-brown/project/mm/mpeg/mpeg_dist/mpeg_encode/headers/RCS/huff.h,v 1.3 1995/01/19 23:54:51 eyhung Exp $
+ */
+
+/*  
+ *  THIS FILE IS MACHINE GENERATED!  DO NOT EDIT!
+ */
+#define HUFF_MAXRUN	32
+#define HUFF_MAXLEVEL	41
+
+extern int huff_maxlevel[];
+extern uint32 *huff_table[];
+extern int *huff_bits[];
diff --git a/converter/ppm/ppmtompeg/headers/input.h b/converter/ppm/ppmtompeg/headers/input.h
new file mode 100644
index 00000000..75734237
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/input.h
@@ -0,0 +1,70 @@
+#ifndef INPUT_H_INCLUDED
+#define INPUT_H_INCLUDED
+
+#include "pm_c_util.h"
+#include "ppm.h"
+#include "frame.h"
+
+struct InputFileEntry;
+
+struct inputSource {
+/*----------------------------------------------------------------------------
+   This describes the source of data for the program.
+   Typically, the source data is a bunch of raw frames in PPM format.
+   But sometimes, it is a bunch of already encoded frames or GOPs.
+-----------------------------------------------------------------------------*/
+    bool stdinUsed;
+    int numInputFiles;
+        /* This is the maximum number of input files available.  If
+           we're reading from explicitly named files, it is exactly
+           the number available.  If we're reading from a stream, it's
+           infinity.  (At the moment, "reading from a stream" is
+           equivalent to "reading from Standard Input").
+        */
+
+    /* Members below here defined only if 'stdinUsed' is false */
+
+    struct InputFileEntry ** inputFileEntries;
+        /* Each element of this array describes a set of input files.
+           Valid elements are consecutive starting at index 0.
+        */
+    unsigned int             numInputFileEntries;
+        /* Number of valid entries in array inputFileEntries[] */
+    unsigned int             ifArraySize;
+        /* Number of allocated entries in the array inputFileEntries[] */
+};
+
+
+void
+GetNthInputFileName(struct inputSource * const inputSourceP,
+                    unsigned int         const n,
+                    const char **        const fileName);
+
+void
+ReadNthFrame(struct inputSource * const inputSourceP,
+             unsigned int         const frameNumber,
+             boolean              const remoteIO,
+             boolean              const childProcess,
+             boolean              const separateConversion,
+             const char *         const slaveConversion,
+             const char *         const inputConversion,
+             MpegFrame *          const frameP,
+             bool *               const endOfStreamP);
+
+void
+JM2JPEG(struct inputSource * const inputSourceP);
+
+void
+AddInputFiles(struct inputSource * const inputSourceP,
+              const char *         const input);
+
+void
+SetStdinInput(struct inputSource * const inputSourceP);
+
+void
+CreateInputSource(struct inputSource ** const inputSourcePP);
+
+void
+DestroyInputSource(struct inputSource * const inputSourceP);
+
+#endif
diff --git a/converter/ppm/ppmtompeg/headers/jpeg.h b/converter/ppm/ppmtompeg/headers/jpeg.h
new file mode 100644
index 00000000..62c6f930
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/jpeg.h
@@ -0,0 +1,12 @@
+#include "ansi.h"
+
+
+void
+JMovie2JPEG(const char * const infilename,
+            const char * const obase,
+            int          const start,
+            int          const end);
+
+void
+ReadJPEG(MpegFrame * const mf,
+         FILE *      const fp);
diff --git a/converter/ppm/ppmtompeg/headers/mheaders.h b/converter/ppm/ppmtompeg/headers/mheaders.h
new file mode 100644
index 00000000..21d43e3d
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/mheaders.h
@@ -0,0 +1,114 @@
+/*===========================================================================*
+ * mheaders.h								     *
+ *									     *
+ *	MPEG headers							     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /n/picasso/project/mm/mpeg/mpeg_dist/mpeg_encode/headers/RCS/mheaders.h,v 1.4 1995/03/27 19:29:24 smoot Exp $
+ *  $Log: mheaders.h,v $
+ * Revision 1.4  1995/03/27  19:29:24  smoot
+ * changed to remove mb_quant
+ *
+ * Revision 1.3  1995/01/19  23:54:56  eyhung
+ * Changed copyrights
+ *
+ * Revision 1.2  1994/11/12  02:12:51  keving
+ * nothing
+ *
+ * Revision 1.1  1993/07/22  22:24:23  keving
+ * nothing
+ *
+ *
+ */
+
+
+#ifndef MHEADERS_INCLUDED
+#define MHEADERS_INCLUDED
+
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "general.h"
+#include "ansi.h"
+#include "bitio.h"
+
+
+/*===============================*
+ * EXTERNAL PROCEDURE prototypes *
+ *===============================*/
+
+void	SetGOPStartTime _ANSI_ARGS_((int index));
+
+void
+Mhead_GenSequenceHeader(BitBucket *   const bbPtr, 
+                        uint32        const hsize, 
+                        uint32        const vsize,
+                        int32         const pratio, 
+                        int32         const pict_rate, 
+                        int32         const bit_rate_arg,
+                        int32         const buf_size_arg, 
+                        int32         const c_param_flag_arg, 
+                        const int32 * const iq_matrix, 
+                        const int32 * const niq_matrix,
+                        uint8 *       const ext_data, 
+                        int32         const ext_data_size, 
+                        uint8 *       const user_data,
+                        int32         const user_data_size);
+
+void	Mhead_GenSequenceEnder _ANSI_ARGS_((BitBucket *bbPtr));
+void	Mhead_GenGOPHeader _ANSI_ARGS_((BitBucket *bbPtr,
+	   int32 drop_frame_flag,
+           int32 tc_hrs, int32 tc_min,
+           int32 tc_sec, int32 tc_pict,
+           int32 closed_gop, int32 broken_link,
+           uint8 *ext_data, int32 ext_data_size,
+           uint8 *user_data, int32 user_data_size));
+void	Mhead_GenPictureHeader _ANSI_ARGS_((BitBucket *bbPtr, int frameType,
+					    int pictCount, int f_code));
+void	Mhead_GenSliceHeader _ANSI_ARGS_((BitBucket *bbPtr, uint32 slicenum,
+					  uint32 qscale, uint8 *extra_info,
+					  uint32 extra_info_size));
+void	Mhead_GenSliceEnder _ANSI_ARGS_((BitBucket *bbPtr));
+void	Mhead_GenMBHeader _ANSI_ARGS_((BitBucket *bbPtr,
+	  uint32 pict_code_type, uint32 addr_incr,
+          uint32 q_scale,
+          uint32 forw_f_code, uint32 back_f_code,
+          uint32 horiz_forw_r, uint32 vert_forw_r,
+          uint32 horiz_back_r, uint32 vert_back_r,
+          int32 motion_forw, int32 m_horiz_forw,
+          int32 m_vert_forw, int32 motion_back,
+          int32 m_horiz_back, int32 m_vert_back,
+          uint32 mb_pattern, uint32 mb_intra));
+
+
+#endif /* MHEADERS_INCLUDED */
+
+
+
+
+
diff --git a/converter/ppm/ppmtompeg/headers/motion_search.h b/converter/ppm/ppmtompeg/headers/motion_search.h
new file mode 100644
index 00000000..ab83cbca
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/motion_search.h
@@ -0,0 +1,154 @@
+/*===========================================================================*
+ * search.h                                  *
+ *                                       *
+ *  stuff dealing with the motion search                     *
+ *                                       *
+ *===========================================================================*/
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "ansi.h"
+
+
+/*===========*
+ * CONSTANTS *
+ *===========*/
+
+#define PSEARCH_SUBSAMPLE   0
+#define PSEARCH_EXHAUSTIVE  1
+#define PSEARCH_LOGARITHMIC 2
+#define PSEARCH_TWOLEVEL    3
+
+#define BSEARCH_EXHAUSTIVE  0
+#define BSEARCH_CROSS2      1
+#define BSEARCH_SIMPLE      2
+
+
+/*========*
+ * MACROS *
+ *========*/
+
+#define COMPUTE_MOTION_BOUNDARY(by,bx,stepSize,leftMY,leftMX,rightMY,rightMX)\
+leftMY = -2*DCTSIZE*by; /* these are valid motion vectors */         \
+leftMX = -2*DCTSIZE*bx;                          \
+/* these are invalid motion vectors */       \
+rightMY = 2*(Fsize_y - (by+2)*DCTSIZE + 1) - 1;              \
+rightMX = 2*(Fsize_x - (bx+2)*DCTSIZE + 1) - 1;              \
+\
+if ( stepSize == 2 ) { \
+    rightMY++;      \
+    rightMX++;      \
+    }
+    
+#define VALID_MOTION(m)   \
+(((m).y >= leftMY) && ((m).y < rightMY) &&   \
+ ((m).x >= leftMX) && ((m).x < rightMX) )
+
+
+/*===============================*
+ * EXTERNAL PROCEDURE prototypes *
+ *===============================*/
+
+void 
+SetPSearchAlg(const char * const alg);
+void 
+SetBSearchAlg(const char * const alg);
+const char *
+BSearchName(void);
+const char *
+PSearchName(void);
+
+int
+PLogarithmicSearch(const LumBlock * const currentBlockP,
+                   MpegFrame *      const prev,
+                   int              const by,
+                   int              const bx,
+                   vector *         const motionP,
+                   int              const searchRange);
+
+int
+PSubSampleSearch(const LumBlock * const currentBlockP,
+                 MpegFrame *      const prev,
+                 int              const by,
+                 int              const bx,
+                 vector *         const motionP,
+                 int              const searchRange);
+
+int
+PLocalSearch(const LumBlock * const currentBlockP,
+             MpegFrame *      const prev,
+             int              const by,
+             int              const bx,
+             vector *         const motionP,
+             int              const bestSoFar,
+             int              const searchRange);
+
+int
+PTwoLevelSearch(const LumBlock * const currentBlockP,
+                MpegFrame *      const prev,
+                int              const by,
+                int              const bx,
+                vector *         const motionP,
+                int              const bestSoFar,
+                int              const searchRange);
+void
+PMotionSearch(const LumBlock * const currentBlockP,
+              MpegFrame *      const prev, 
+              int              const by,
+              int              const bx, 
+              vector *         const motionP);
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+
+extern int psearchAlg;
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /n/picasso/project/mpeg/mpeg_dist/mpeg_encode/headers/RCS/search.h,v 1.6 1995/08/15 23:43:36 smoot Exp $
+ *  $Log: search.h,v $
+ *  Revision 1.6  1995/08/15 23:43:36  smoot
+ *  *** empty log message ***
+ *
+ *  Revision 1.5  1995/01/19 23:55:20  eyhung
+ *  Changed copyrights
+ *
+ * Revision 1.4  1994/12/07  00:42:01  smoot
+ * Added seperate P and B search ranges
+ *
+ * Revision 1.3  1994/11/12  02:12:58  keving
+ * nothing
+ *
+ * Revision 1.2  1993/07/22  22:24:23  keving
+ * nothing
+ *
+ * Revision 1.1  1993/07/09  00:17:23  keving
+ * nothing
+ *
+ */
+
+
+
diff --git a/converter/ppm/ppmtompeg/headers/mpeg.h b/converter/ppm/ppmtompeg/headers/mpeg.h
new file mode 100644
index 00000000..d739dede
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/mpeg.h
@@ -0,0 +1,116 @@
+/*===========================================================================*
+ * mpeg.h								     *
+ *									     *
+ *	no comment							     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include <time.h>
+
+#include "pm_c_util.h"
+#include "ppm.h"
+#include "ansi.h"
+#include "mtypes.h"
+#include "frame.h"
+
+struct inputSource;
+
+/*===============================*
+ * EXTERNAL PROCEDURE prototypes *
+ *===============================*/
+
+enum frameContext {CONTEXT_WHOLESTREAM, CONTEXT_GOP, CONTEXT_JUSTFRAMES};
+
+void
+GenMPEGStream(struct inputSource * const inputSourceP,
+              enum frameContext    const context, 
+              unsigned int         const frameStart, 
+              unsigned int         const frameEnd, 
+              int32                const qtable[], 
+              int32                const niqtable[], 
+              bool                 const childProcess,
+              FILE *               const ofp, 
+              const char *         const outputFileName,
+              bool                 const wantVbvUnderflowWarning,
+              bool                 const wantVbvOverflowWarning,
+              unsigned int *       const inputFrameBitsP,
+              unsigned int *       const totalBitsP);
+
+void
+PrintStartStats(time_t               const startTime, 
+                bool                 const specificFrames,
+                unsigned int         const firstFrame, 
+                unsigned int         const lastFrame,
+                struct inputSource * const inputSourceP);
+
+void
+PrintEndStats(time_t       const startTime,
+              time_t       const endTime,
+              unsigned int const inputFrameBits, 
+              unsigned int const totalBits);
+
+void
+ComputeGOPFrames(int            const whichGOP, 
+                 unsigned int * const firstFrameP, 
+                 unsigned int * const lastFrameP, 
+                 unsigned int   const numFrames);
+
+extern void	IncrementTCTime _ANSI_ARGS_((void));
+void SetReferenceFrameType(const char * const type);
+
+boolean
+NonLocalRefFrame(int     const id);
+
+void
+ReadDecodedRefFrame(MpegFrame *  const frameP, 
+                    unsigned int const frameNumber);
+
+extern void	WriteDecodedFrame _ANSI_ARGS_((MpegFrame *frame));
+extern void	SetBitRateFileName _ANSI_ARGS_((char *fileName));
+extern void	SetFrameRate _ANSI_ARGS_((void));
+
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+
+extern MpegFrame *frameMemory[3];
+extern int32	  tc_hrs, tc_min, tc_sec, tc_pict, tc_extra;
+extern int	  totalFramesSent;
+extern int	  gopSize;
+extern char	 *framePattern;
+extern int	  framePatternLen;
+extern int32 qtable[];
+extern int32 niqtable[];
+extern int32 *customQtable;
+extern int32 *customNIQtable;
+extern int  aspectRatio;
+extern int  frameRate;
+extern int     frameRateRounded;
+extern boolean    frameRateInteger;
+
diff --git a/converter/ppm/ppmtompeg/headers/mproto.h b/converter/ppm/ppmtompeg/headers/mproto.h
new file mode 100644
index 00000000..c3b0f4b3
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/mproto.h
@@ -0,0 +1,132 @@
+/*===========================================================================*
+ * mproto.h								     *
+ *									     *
+ *	basically a lot of miscellaneous prototypes			     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /n/picasso/project/mm/mpeg/mpeg_dist/mpeg_encode/headers/RCS/mproto.h,v 1.12 1995/03/29 20:14:29 smoot Exp $
+ *  $Log: mproto.h,v $
+ * Revision 1.12  1995/03/29  20:14:29  smoot
+ * deleted unneeded dct prototype
+ *
+ * Revision 1.11  1995/01/19  23:55:02  eyhung
+ * Changed copyrights
+ *
+ * Revision 1.10  1995/01/16  06:20:10  eyhung
+ * Changed ReadYUV to ReadEYUV
+ *
+ * Revision 1.9  1993/07/22  22:24:23  keving
+ * nothing
+ *
+ * Revision 1.8  1993/07/09  00:17:23  keving
+ * nothing
+ *
+ * Revision 1.7  1993/06/03  21:08:53  keving
+ * nothing
+ *
+ * Revision 1.6  1993/02/24  19:13:33  keving
+ * nothing
+ *
+ * Revision 1.5  1993/02/17  23:18:20  dwallach
+ * checkin prior to keving's joining the project
+ *
+ * Revision 1.4  1993/01/18  10:20:02  dwallach
+ * *** empty log message ***
+ *
+ * Revision 1.3  1993/01/18  10:17:29  dwallach
+ * RCS headers installed, code indented uniformly
+ *
+ * Revision 1.3  1993/01/18  10:17:29  dwallach
+ * RCS headers installed, code indented uniformly
+ *
+ */
+
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "general.h"
+#include "ansi.h"
+#include "bitio.h"
+
+
+#define DCTSIZE2    DCTSIZE*DCTSIZE
+typedef short DCTELEM;
+typedef DCTELEM DCTBLOCK[DCTSIZE2];
+
+
+
+/*===============================*
+ * EXTERNAL PROCEDURE prototypes *
+ *===============================*/
+
+/*  
+ *  from mbasic.c:
+ */
+void mp_reset _ANSI_ARGS_((void));
+void mp_free _ANSI_ARGS_((MpegFrame *mf));
+MpegFrame *mp_new _ANSI_ARGS_((int fnumber, char type, MpegFrame *oldFrame));
+void mp_ycc_calc _ANSI_ARGS_((MpegFrame *mf));
+void mp_dct_blocks _ANSI_ARGS_((MpegFrame *mf));
+void	AllocDecoded _ANSI_ARGS_((MpegFrame *frame));
+
+/*  
+ *  from moutput.c:
+ */
+boolean mp_quant_zig_block _ANSI_ARGS_((Block in, FlatBlock out, int qscale, int iblock));
+void	UnQuantZig _ANSI_ARGS_((FlatBlock in, Block out, int qscale, boolean iblock));
+void mp_rle_huff_block _ANSI_ARGS_((FlatBlock in, BitBucket *out));
+void mp_rle_huff_pblock _ANSI_ARGS_((FlatBlock in, BitBucket *out));
+void mp_create_blocks _ANSI_ARGS_((MpegFrame *mf));
+
+
+
+
+void	ReadEYUV _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer, int width,
+			    int height));
+boolean	ReadPPM _ANSI_ARGS_((MpegFrame *mf, FILE *fpointer));
+void PPMtoYCC _ANSI_ARGS_((MpegFrame * mf));
+
+void	MotionSearchPreComputation _ANSI_ARGS_((MpegFrame *frame));
+boolean	PMotionSearch _ANSI_ARGS_((LumBlock currentBlock, MpegFrame *prev,
+				   int by, int bx, int *motionY, int *motionX));
+void	ComputeHalfPixelData _ANSI_ARGS_((MpegFrame *frame));
+void mp_validate_size _ANSI_ARGS_((int *x, int *y));
+void AllocYCC _ANSI_ARGS_((MpegFrame * mf));
+
+
+/* jrevdct.c */
+void init_pre_idct _ANSI_ARGS_((void ));
+void j_rev_dct_sparse _ANSI_ARGS_((DCTBLOCK data , int pos ));
+void j_rev_dct _ANSI_ARGS_((DCTBLOCK data ));
+void j_rev_dct_sparse _ANSI_ARGS_((DCTBLOCK data , int pos ));
+void j_rev_dct _ANSI_ARGS_((DCTBLOCK data ));
+
+/* block.c */
+void	BlockToData _ANSI_ARGS_((uint8 **data, Block block, int by, int bx));
+void	AddMotionBlock _ANSI_ARGS_((Block block, uint8 **prev, int by, int bx,
+		       int my, int mx));
diff --git a/converter/ppm/ppmtompeg/headers/mtypes.h b/converter/ppm/ppmtompeg/headers/mtypes.h
new file mode 100644
index 00000000..0db5a330
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/mtypes.h
@@ -0,0 +1,109 @@
+/*===========================================================================*
+ * mtypes.h
+ *
+ *	MPEG data types
+ *
+ *===========================================================================*/
+
+/* Copyright information is at end of file */
+
+#ifndef MTYPES_INCLUDED
+#define MTYPES_INCLUDED
+
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "general.h"
+#include "dct.h"
+
+
+/*===========*
+ * CONSTANTS *
+ *===========*/
+
+#define TYPE_BOGUS	0   /* for the header of the circular list */
+#define TYPE_VIRGIN	1
+
+#define STATUS_EMPTY	0
+#define STATUS_LOADED	1
+#define STATUS_WRITTEN	2
+
+
+typedef struct vector {
+    int y;
+    int x;
+} vector;
+
+typedef struct motion {
+    vector fwd;
+    vector bwd;
+} motion;
+
+/*==================*
+ * TYPE DEFINITIONS *
+ *==================*/
+
+/*  
+ *  your basic Block type
+ */
+typedef int16 Block[DCTSIZE][DCTSIZE];
+typedef int16 FlatBlock[DCTSIZE_SQ];
+typedef	struct {
+    int32 l[2*DCTSIZE][2*DCTSIZE];
+} LumBlock;
+typedef	int32 ChromBlock[DCTSIZE][DCTSIZE];
+
+/*========*
+ * MACROS *
+ *========*/
+
+#ifdef ABS
+#undef ABS
+#endif
+
+#define ABS(x) (((x)<0)?-(x):(x))
+
+#ifdef HEINOUS_DEBUG_MODE
+#define DBG_PRINT(x) {printf x; fflush(stdout);}
+#else
+#define DBG_PRINT(x)
+#endif
+
+#define ERRCHK(bool, str) {if(!(bool)) {perror(str); exit(1);}}
+
+/* For Specifics */
+typedef struct detalmv_def {
+  int typ,fx,fy,bx,by;
+} BlockMV;
+#define TYP_SKIP 0
+#define TYP_FORW 1
+#define TYP_BACK 2
+#define TYP_BOTH 3
+
+
+#endif /* MTYPES_INCLUDED */
+
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
diff --git a/converter/ppm/ppmtompeg/headers/opts.h b/converter/ppm/ppmtompeg/headers/opts.h
new file mode 100644
index 00000000..5901a677
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/opts.h
@@ -0,0 +1,125 @@
+/*
+ * opts.h - set optional parameters
+ */
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /n/picasso/project/mpeg/mpeg_dist/mpeg_encode/headers/RCS/opts.h,v 1.3 1995/08/15 23:43:43 smoot Exp $
+ *  $Log: opts.h,v $
+ *  Revision 1.3  1995/08/15 23:43:43  smoot
+ *  *** empty log message ***
+ *
+ * Revision 1.2  1995/05/02  22:00:51  smoot
+ * added TUNEing stuff
+ *
+ * Revision 1.1  1995/04/14  23:12:53  smoot
+ * Initial revision
+ *
+ */
+
+#include "general.h"
+#include "ansi.h"
+#include "mtypes.h"
+
+/*
+ TUNE b [limit] lower limit on how different a block must be to be DCT coded
+ TUNE c [file [color-diff]] Collect statistics on Quantization
+ TUNE d [RateScale DistortionScale] Do a DCT in the P search, not just DIFF
+ TUNE k [breakpt end [slope]] Squash small lum values
+ TUNE l Figure out Laplacian distrib and use them to dequantize and do snr calc
+ TUNE n Dont consider DC differenece in DCT searches
+ TUNE q Do MSE for distortion measure, not MAD
+ TUNE s [Max] | [LumMax ChromMax] Squash small differences in successive frames
+ TUNE u disallow skip blocks in B frames
+ TUNE w filename [c]  Write I block distortion numbers to file [with bit-rates]
+ TUNE z Zaps Intra blocks in P/B frames.
+
+ [ Note k and s make -snr numbers a lie, by playing with input ]
+ [ Note d n and q are contradictory (can only use one)         ]
+ [ Note c will not work on parallel encodings                  ]
+*/
+
+extern boolean tuneingOn;
+
+/* Smash to no-change a motion block DCT with MAD less than: */
+/* DETAL b value               */
+extern int block_bound;
+
+/* Collect info on quantization */
+extern boolean collect_quant;
+extern int collect_quant_detailed;
+extern FILE   *collect_quant_fp;
+
+/* Nuke dim areas */
+extern int kill_dim, kill_dim_break, kill_dim_end;
+extern float kill_dim_slope;
+
+
+/* Stuff to control MV search comparisons */
+#define DEFAULT_SEARCH 0
+#define LOCAL_DCT  1 /* Do DCT in search (SLOW!!!!) */
+#define NO_DC_SEARCH  2  /* Dont consider DC component in motion searches */
+#define DO_Mean_Squared_Distortion  3 /* Do Squared distortion, not ABS */
+
+/* Parameters for special searches */
+/* LOCAL_DCT */
+extern float LocalDCTRateScale, LocalDCTDistortScale;
+
+/* Search Type Variable */
+extern int SearchCompareMode;
+
+/* squash small differences */
+extern boolean squash_small_differences;
+extern int SquashMaxLum, SquashMaxChr;
+
+/* Disallows Intra blocks in P/B code */
+extern boolean IntraPBAllowed;
+
+/* Write out distortion numbers */
+extern boolean WriteDistortionNumbers;
+extern int collect_distortion_detailed;
+extern FILE *distortion_fp;
+extern FILE *fp_table_rate[31], *fp_table_dist[31];
+
+/* Laplacian Distrib */
+extern boolean DoLaplace;
+extern double **L1, **L2, **Lambdas;
+extern int LaplaceNum, LaplaceCnum;
+
+/* Turn on/off skipping in B frames */
+extern boolean BSkipBlocks;
+
+/* Procedures Prototypes */
+int	GetIQScale _ANSI_ARGS_((void));
+int	GetPQScale _ANSI_ARGS_((void));
+int	GetBQScale _ANSI_ARGS_((void));
+void	Tune_Init _ANSI_ARGS_((void));
+int     CalcRLEHuffLength _ANSI_ARGS_((FlatBlock in));
+void    ParseTuneParam(const char * const charPtr);
+int     mse _ANSI_ARGS_((Block blk1, Block blk2));
+void    Mpost_UnQuantZigBlockLaplace _ANSI_ARGS_((FlatBlock in, Block out, int qscale, boolean iblock));
+extern void CalcLambdas(void);
+
+
+
+
diff --git a/converter/ppm/ppmtompeg/headers/parallel.h b/converter/ppm/ppmtompeg/headers/parallel.h
new file mode 100644
index 00000000..e18d3f46
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/parallel.h
@@ -0,0 +1,135 @@
+/*===========================================================================*
+ * parallel.h          
+ *                     
+ *  parallel encoding  
+ *                     
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "ansi.h"
+#include "bitio.h"
+#include "frame.h"
+
+
+struct inputSource;
+
+/*===============================*
+ * EXTERNAL PROCEDURE prototypes *
+ *===============================*/
+
+void
+MasterServer(struct inputSource * const inputSourceP,
+             const char *         const paramFileName, 
+             const char *         const outputFileName);
+
+void
+NotifyMasterDone(const char * const hostName, 
+                 int          const portNum, 
+                 int          const machineNumber, 
+                 unsigned int const seconds, 
+                 boolean *    const moreWorkToDoP,
+                 int *        const frameStartP,
+                 int *        const frameEndP);
+
+void
+IoServer(struct inputSource * const inputSourceP,
+         const char *         const parallelHostName, 
+         int                  const portNum);
+
+void
+CombineServer(int          const numInputFiles, 
+              const char * const masterHostName, 
+              int          const masterPortNum,
+              const char*  const outputFileName);
+
+void
+DecodeServer(int          const numInputFiles, 
+             const char * const decodeFileName, 
+             const char * const parallelHostName, 
+             int          const portNum);
+
+void
+WaitForOutputFile(int number);
+
+void
+GetRemoteFrame(MpegFrame * const frameP,
+               int         const frameNumber);
+
+void
+SendRemoteFrame(int         const frameNumber,
+                BitBucket * const bbP);
+
+void
+NoteFrameDone(int frameStart, int frameEnd);
+
+void
+SetIOConvert(boolean separate);
+
+void
+SetRemoteShell(const char * const shell);
+
+void 
+NotifyDecodeServerReady(int const id);
+
+void 
+WaitForDecodedFrame(int id);
+
+void 
+SendDecodedFrame(MpegFrame * const frameP);
+
+void 
+GetRemoteDecodedRefFrame(MpegFrame * const frameP,
+                         int         const frameNumber);
+
+void 
+SetParallelPerfect(boolean val);
+
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+
+extern int parallelTestFrames;
+extern int parallelTimeChunks;
+
+extern const char *IOhostName;
+extern int ioPortNumber;
+extern int decodePortNumber;
+
+extern boolean  ioServer;
+extern boolean  niceProcesses;
+extern boolean  forceIalign;
+extern int    machineNumber;
+extern boolean remoteIO;
+extern boolean  separateConversion;
+
+
+
+
+
+
+
diff --git a/converter/ppm/ppmtompeg/headers/param.h b/converter/ppm/ppmtompeg/headers/param.h
new file mode 100644
index 00000000..31be61ee
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/param.h
@@ -0,0 +1,87 @@
+/*===========================================================================*
+ * param.h								     *
+ *									     *
+ *	reading the parameter file					     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "pm_c_util.h"
+#include "ansi.h"
+#include "input.h"
+
+
+/*===========*
+ * CONSTANTS *
+ *===========*/
+
+#define MAX_MACHINES	    256
+#ifndef MAXPATHLEN
+#define MAXPATHLEN  1024
+#endif
+
+#define	ENCODE_FRAMES	0
+#define COMBINE_GOPS	1
+#define COMBINE_FRAMES	2
+
+
+struct params {
+    struct inputSource * inputSourceP;
+    bool warnUnderflow;
+    bool warnOverflow;
+};
+
+
+void
+ReadParamFile(const char *    const fileName, 
+              int             const function,
+              struct params * const paramP);
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+
+/* All this stuff ought to be in a struct param instead */
+
+extern char	outputFileName[256];
+extern int	whichGOP;
+extern int numMachines;
+extern char	machineName[MAX_MACHINES][256];
+extern char	userName[MAX_MACHINES][256];
+extern char	executable[MAX_MACHINES][1024];
+extern char	remoteParamFile[MAX_MACHINES][1024];
+extern boolean	remote[MAX_MACHINES];
+extern char	currentPath[MAXPATHLEN];
+extern char	currentFramePath[MAXPATHLEN];
+extern char	currentGOPPath[MAXPATHLEN];
+extern char inputConversion[1024];
+extern char yuvConversion[256];
+extern int  yuvWidth, yuvHeight;
+extern int  realWidth, realHeight;
+extern char ioConversion[1024];
+extern char slaveConversion[1024];
+extern FILE *bitRateFile;
+extern boolean showBitRatePerFrame;
+extern boolean computeMVHist;
+extern const double VidRateNum[9];
+extern boolean keepTempFiles;
diff --git a/converter/ppm/ppmtompeg/headers/postdct.h b/converter/ppm/ppmtompeg/headers/postdct.h
new file mode 100644
index 00000000..3f3b51fe
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/postdct.h
@@ -0,0 +1,40 @@
+/*===========================================================================*
+ * postdct.h								     *
+ *									     *
+ *	MPEG post-DCT processing					     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "bitio.h"
+
+
+int     Mpost_QuantZigBlock (Block in, FlatBlock out, int qscale, int iblock);
+void	Mpost_UnQuantZigBlock (FlatBlock in, Block out,
+                               int qscale, boolean iblock);
+void	Mpost_RLEHuffIBlock (FlatBlock in, BitBucket *out);
+void	Mpost_RLEHuffPBlock (FlatBlock in, BitBucket *out);
+
+#define MPOST_ZERO 0
+#define MPOST_NON_ZERO 1
+#define MPOST_OVERFLOW (-1)
diff --git a/converter/ppm/ppmtompeg/headers/prototypes.h b/converter/ppm/ppmtompeg/headers/prototypes.h
new file mode 100644
index 00000000..d729aafa
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/prototypes.h
@@ -0,0 +1,78 @@
+/*===========================================================================*
+ * prototypes.h                                  *
+ *                                       *
+ *  miscellaneous prototypes                         *
+ *                                       *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "general.h"
+#include "ansi.h"
+#include "frame.h"
+
+
+/*===============================*
+ * EXTERNAL PROCEDURE prototypes *
+ *===============================*/
+
+int GetBQScale _ANSI_ARGS_((void));
+int GetPQScale _ANSI_ARGS_((void));
+void    ResetBFrameStats _ANSI_ARGS_((void));
+void    ResetPFrameStats _ANSI_ARGS_((void));
+void SetSearchRange (int const pixelsP,
+                     int const pixelsB);
+void    ResetIFrameStats _ANSI_ARGS_((void));
+void
+SetPixelSearch(const char * const searchType);
+void    SetIQScale _ANSI_ARGS_((int qI));
+void    SetPQScale _ANSI_ARGS_((int qP));
+void    SetBQScale _ANSI_ARGS_((int qB));
+float   EstimateSecondsPerIFrame _ANSI_ARGS_((void));
+float   EstimateSecondsPerPFrame _ANSI_ARGS_((void));
+float   EstimateSecondsPerBFrame _ANSI_ARGS_((void));
+void    SetGOPSize _ANSI_ARGS_((int size));
+void
+SetStatFileName(const char * const fileName);
+void    SetSlicesPerFrame _ANSI_ARGS_((int number));
+void    SetBlocksPerSlice _ANSI_ARGS_((void));
+
+
+void DCTFrame _ANSI_ARGS_((MpegFrame * mf));
+
+void PPMtoYCC _ANSI_ARGS_((MpegFrame * mf));
+
+void    MotionSearchPreComputation _ANSI_ARGS_((MpegFrame *frame));
+
+void    ComputeHalfPixelData _ANSI_ARGS_((MpegFrame *frame));
+void mp_validate_size _ANSI_ARGS_((int *x, int *y));
+
+extern void SetFCode _ANSI_ARGS_((void));
+
+
+/* psearch.c */
+void    ShowPMVHistogram _ANSI_ARGS_((FILE *fpointer));
+void    ShowBBMVHistogram _ANSI_ARGS_((FILE *fpointer));
+void    ShowBFMVHistogram _ANSI_ARGS_((FILE *fpointer));
diff --git a/converter/ppm/ppmtompeg/headers/psocket.h b/converter/ppm/ppmtompeg/headers/psocket.h
new file mode 100644
index 00000000..214f5dce
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/psocket.h
@@ -0,0 +1,41 @@
+#ifndef PSOCKET_H_INCLUDED
+#define PSOCKET_H_INCLUDED
+
+#include <netdb.h>
+
+void
+ReadInt(int   const socketFd,
+        int * const valueP);
+
+void
+ReadBytes(int             const fd,
+          unsigned char * const buf,
+          unsigned int    const nbyte);
+
+void
+WriteInt(int const socketFd,
+         int const value);
+
+void
+WriteBytes(int             const fd,
+           unsigned char * const buf,
+           unsigned int    const nbyte);
+
+void
+ConnectToSocket(const char *      const machineName, 
+                int               const portNum, 
+                struct hostent ** const hostEnt,
+                int *             const socketFdP,
+                const char **     const errorP);
+
+void
+CreateListeningSocket(int *         const socketP,
+                      int *         const portNumP,
+                      const char ** const errorP);
+
+void
+AcceptConnection(int           const listenSocketFd,
+                 int *         const connectSocketFdP,
+                 const char ** const errorP);
+
+#endif
diff --git a/converter/ppm/ppmtompeg/headers/rate.h b/converter/ppm/ppmtompeg/headers/rate.h
new file mode 100644
index 00000000..df5ca1cc
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/rate.h
@@ -0,0 +1,204 @@
+/*===========================================================================*
+ * rate.h								     *
+ *									     *
+ *	Procedures concerned with rate control
+ *									     *
+ * EXPORTED PROCEDURES:							     *
+ *  getRateMode()
+ *  setBitRate()
+ *  getBitRate()
+ *  setBufferSize()
+ *  getBufferSize()
+ *	initRateControl()
+ *	targetRateControl()
+ * 	updateRateControl()
+ *	MB_RateOut()
+ *									     *
+ *===========================================================================*/
+
+/* 	COPYRIGHT INFO HERE	*/
+
+#define VARIABLE_RATE 0
+#define FIXED_RATE 1
+
+
+/*==================*
+ * Exported VARIABLES *
+ *==================*/
+
+
+extern int rc_bitsThisMB;
+extern int rc_numBlocks;
+extern int rc_totalQuant;
+extern int rc_quantOverride;
+
+
+/*=====================*
+ * EXPORTED PROCEDURES *
+ *=====================*/
+
+/*===========================================================================*
+ *
+ * initRateControl
+ *
+ *	initialize the allocation parameters.
+ *===========================================================================*/
+int
+initRateControl(bool const wantUnderflowWarning,
+                bool const wantOverflowWarning);
+
+/*===========================================================================*
+ *
+ * targetRateControl
+ *
+ *      Determine the target allocation for given picture type.
+ *
+ * RETURNS:     target size in bits
+ *===========================================================================*/
+void
+targetRateControl(MpegFrame * const frameP);
+
+
+/*===========================================================================*
+ *
+ * MB_RateOut
+ *
+ *      Prints out sampling of MB rate control data.  Every "nth" block
+ *	stats are printed, with "n" controled by global RC_MB_SAMPLE_RATE
+ *
+ * RETURNS:     nothing
+ *===========================================================================*/
+extern void MB_RateOut _ANSI_ARGS_((int type));
+
+
+/*===========================================================================*
+ *
+ * updateRateControl
+ *
+ *      Update the statistics kept, after end of frame
+ *
+ * RETURNS:     nothing
+ *
+ * SIDE EFFECTS:   many global variables
+ *===========================================================================*/
+void
+updateRateControl(int const type);
+
+
+/*===========================================================================*
+ *
+ * needQScaleChange(current Q scale, 4 luminance blocks)
+ *
+ *
+ * RETURNS:     new Qscale
+ *===========================================================================*/
+extern int needQScaleChange _ANSI_ARGS_((int oldQScale,  Block blk0, Block blk1, Block blk2, Block blk3));
+
+/*===========================================================================*
+ *
+ * incNumBlocks()
+ *
+ *
+ * RETURNS:   nothing
+ *===========================================================================*/
+extern void incNumBlocks _ANSI_ARGS_((int num));
+
+
+/*===========================================================================*
+ *
+ * incMacroBlockBits()
+ *
+ *  Increments the number of Macro Block bits and the total of Frame
+ *  bits by the number passed.
+ *
+ * RETURNS:   nothing
+ *===========================================================================*/
+extern void incMacroBlockBits _ANSI_ARGS_((int num));
+
+
+/*===========================================================================*
+ *
+ * SetRateControl ()
+ *
+ *      Checks the string parsed from the parameter file.  Verifies
+ *  number and sets global values.
+ *
+ * RETURNS:     nothing
+ *===========================================================================*/
+extern void SetRateControl _ANSI_ARGS_((char *charPtr));
+
+
+/*===========================================================================*
+ *
+ * setBufferSize ()
+ *
+ *      Checks the string parsed from the parameter file.  Verifies
+ *  number and sets global values.
+ *
+ * RETURNS:     nothing
+ *===========================================================================*/
+extern void 
+setBufferSize(const char * const charPtr);
+
+
+/*===========================================================================*
+ *
+ * getBufferSize ()
+ *
+ *      returns the buffer size read from the parameter file.  Size is
+ *  in bits- not in units of 16k as written to the sequence header.
+ *
+ * RETURNS:     int (or -1 if invalid)
+ *===========================================================================*/
+extern int getBufferSize _ANSI_ARGS_((void));
+
+
+/*===========================================================================*
+ *
+ * setBitRate ()
+ *
+ *      Checks the string parsed from the parameter file.  Verifies
+ *  number and sets global values.
+ *
+ * RETURNS:     nothing
+ *
+ * SIDE EFFECTS:   global variables
+ *===========================================================================*/
+extern void 
+setBitRate(const char * const charPtr);
+
+
+/*===========================================================================*
+ *
+ * getBitRate ()
+ *
+ *      Returns the bit rate read from the parameter file.  This is the
+ *  real rate in bits per second, not in 400 bit units as is written to
+ *  the sequence header.
+ *
+ * RETURNS:     int (-1 if Variable mode operation)
+ *===========================================================================*/
+extern int getBitRate _ANSI_ARGS_((void));
+
+
+/*===========================================================================*
+ *
+ * getRateMode ()
+ *
+ *      Returns the rate mode- interpreted waa either Fixed or Variable
+ *
+ * RETURNS:     integer
+ *===========================================================================*/
+extern int getRateMode _ANSI_ARGS_((void));
+
+
+/*===========================================================================*
+ *
+ * incQuantOverride()
+ *
+ *  counter of override of quantization
+ *
+ * RETURNS:   nothing
+ *===========================================================================*/
+extern void incQuantOverride  _ANSI_ARGS_((int num));
+
diff --git a/converter/ppm/ppmtompeg/headers/readframe.h b/converter/ppm/ppmtompeg/headers/readframe.h
new file mode 100644
index 00000000..3a6876b1
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/readframe.h
@@ -0,0 +1,69 @@
+/*===========================================================================*
+ * readframe.h								     *
+ *									     *
+ *	stuff dealing with reading frames				     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "pm_c_util.h"
+
+/*===========*
+ * CONSTANTS *
+ *===========*/
+
+#define	PPM_FILE_TYPE	    0
+#define YUV_FILE_TYPE	    2
+#define ANY_FILE_TYPE	    3
+#define BASE_FILE_TYPE	    4
+#define PNM_FILE_TYPE	    5
+#define SUB4_FILE_TYPE	    6
+#define JPEG_FILE_TYPE	    7
+#define JMOVIE_FILE_TYPE    8
+#define Y_FILE_TYPE	    9
+
+
+struct inputSource;
+
+void
+ReadFrameFile(MpegFrame *  const frameP,
+              FILE *       const ifP,
+              const char * const conversion,
+              bool *       const eofP);
+
+void
+ReadFrame(MpegFrame *          const frameP, 
+          struct inputSource * const inputSourceP,
+          unsigned int         const frameNumber,
+          const char *         const conversion,
+          bool *               const endOfStreamP);
+
+FILE *
+ReadIOConvert(struct inputSource * const inputSourceP,
+              unsigned int         const frameNumber);
+
+extern void	SetFileType(const char * const conversion);
+extern void	SetFileFormat(const char * const format);
+extern void	SetResize(bool const set);
+
+extern int	baseFormat;
diff --git a/converter/ppm/ppmtompeg/headers/rgbtoycc.h b/converter/ppm/ppmtompeg/headers/rgbtoycc.h
new file mode 100644
index 00000000..52159963
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/rgbtoycc.h
@@ -0,0 +1,39 @@
+/*===========================================================================*
+ * rgbtoycc.h								     *
+ *									     *
+ *	Procedures to convert from RGB space to YUV space		     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+
+
+#include "frame.h"
+#include "pnm.h"
+
+void
+PNMtoYUV(MpegFrame *  const frame,
+         xel **       const xels,
+         unsigned int const cols,
+         unsigned int const rows,
+         xelval       const maxval);
diff --git a/converter/ppm/ppmtompeg/headers/specifics.h b/converter/ppm/ppmtompeg/headers/specifics.h
new file mode 100644
index 00000000..7bcf4ace
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/specifics.h
@@ -0,0 +1,36 @@
+#include "ansi.h"
+
+
+/*===========*
+ * TYPES     *
+ *===========*/
+
+typedef struct bs_def {
+  int num;
+  boolean relative;
+  char qscale;
+  BlockMV *mv;  /* defined in mtypes.h */
+  struct bs_def *next;
+} Block_Specifics;
+
+typedef struct detail_def {
+  int num;
+  char qscale;
+  struct detail_def *next;
+}  Slice_Specifics;
+
+typedef struct fsl_def {
+  int framenum; 
+  int frametype;
+  char qscale;
+  Slice_Specifics *slc;
+  Block_Specifics *bs;
+  struct fsl_def *next;
+} FrameSpecList;
+
+
+void	Specifics_Init _ANSI_ARGS_((void));
+int     SpecLookup _ANSI_ARGS_((int fn, int typ, int num, 
+				BlockMV **info, int start_qs));
+int SpecTypeLookup _ANSI_ARGS_((int fn));
+
diff --git a/converter/ppm/ppmtompeg/huff.c b/converter/ppm/ppmtompeg/huff.c
new file mode 100644
index 00000000..821daca1
--- /dev/null
+++ b/converter/ppm/ppmtompeg/huff.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /n/charlie-brown/project/mm/mpeg/mpeg_dist/mpeg_encode/RCS/huff.c,v 1.6 1995/01/19 23:07:39 eyhung Exp $
+ */
+
+/*  
+ *  THIS FILE IS MACHINE GENERATED!  DO NOT EDIT!
+ */
+#include "mtypes.h"
+#include "huff.h"
+
+int huff_maxlevel[32] = { 41, 19, 6, 5, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
+
+uint32 huff_table0[41] = { 0x0, 0x6, 0x8, 0xa, 0xc, 0x4c, 0x42, 0x14, 0x3a, 0x30, 0x26, 0x20, 0x34, 0x32, 0x30, 0x2e, 0x3e, 0x3c, 0x3a, 0x38, 0x36, 0x34, 0x32, 0x30, 0x2e, 0x2c, 0x2a, 0x28, 0x26, 0x24, 0x22, 0x20, 0x30, 0x2e, 0x2c, 0x2a, 0x28, 0x26, 0x24, 0x22, 0x20 };
+int huff_bits0[41] = { 0, 3, 5, 6, 8, 9, 9, 11, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16 };
+
+uint32 huff_table1[19] = { 0x0, 0x6, 0xc, 0x4a, 0x18, 0x36, 0x2c, 0x2a, 0x3e, 0x3c, 0x3a, 0x38, 0x36, 0x34, 0x32, 0x26, 0x24, 0x22, 0x20 };
+int huff_bits1[19] = { 0, 4, 7, 9, 11, 13, 14, 14, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17 };
+
+uint32 huff_table2[6] = { 0x0, 0xa, 0x8, 0x16, 0x28, 0x28 };
+int huff_bits2[6] = { 0, 5, 8, 11, 13, 14 };
+
+uint32 huff_table3[5] = { 0x0, 0xe, 0x48, 0x38, 0x26 };
+int huff_bits3[5] = { 0, 6, 9, 13, 14 };
+
+uint32 huff_table4[4] = { 0x0, 0xc, 0x1e, 0x24 };
+int huff_bits4[4] = { 0, 6, 11, 13 };
+
+uint32 huff_table5[4] = { 0x0, 0xe, 0x12, 0x24 };
+int huff_bits5[4] = { 0, 7, 11, 14 };
+
+uint32 huff_table6[4] = { 0x0, 0xa, 0x3c, 0x28 };
+int huff_bits6[4] = { 0, 7, 13, 17 };
+
+uint32 huff_table7[3] = { 0x0, 0x8, 0x2a };
+int huff_bits7[3] = { 0, 7, 13 };
+
+uint32 huff_table8[3] = { 0x0, 0xe, 0x22 };
+int huff_bits8[3] = { 0, 8, 13 };
+
+uint32 huff_table9[3] = { 0x0, 0xa, 0x22 };
+int huff_bits9[3] = { 0, 8, 14 };
+
+uint32 huff_table10[3] = { 0x0, 0x4e, 0x20 };
+int huff_bits10[3] = { 0, 9, 14 };
+
+uint32 huff_table11[3] = { 0x0, 0x46, 0x34 };
+int huff_bits11[3] = { 0, 9, 17 };
+
+uint32 huff_table12[3] = { 0x0, 0x44, 0x32 };
+int huff_bits12[3] = { 0, 9, 17 };
+
+uint32 huff_table13[3] = { 0x0, 0x40, 0x30 };
+int huff_bits13[3] = { 0, 9, 17 };
+
+uint32 huff_table14[3] = { 0x0, 0x1c, 0x2e };
+int huff_bits14[3] = { 0, 11, 17 };
+
+uint32 huff_table15[3] = { 0x0, 0x1a, 0x2c };
+int huff_bits15[3] = { 0, 11, 17 };
+
+uint32 huff_table16[3] = { 0x0, 0x10, 0x2a };
+int huff_bits16[3] = { 0, 11, 17 };
+
+uint32 huff_table17[2] = { 0x0, 0x3e };
+int huff_bits17[2] = { 0, 13 };
+
+uint32 huff_table18[2] = { 0x0, 0x34 };
+int huff_bits18[2] = { 0, 13 };
+
+uint32 huff_table19[2] = { 0x0, 0x32 };
+int huff_bits19[2] = { 0, 13 };
+
+uint32 huff_table20[2] = { 0x0, 0x2e };
+int huff_bits20[2] = { 0, 13 };
+
+uint32 huff_table21[2] = { 0x0, 0x2c };
+int huff_bits21[2] = { 0, 13 };
+
+uint32 huff_table22[2] = { 0x0, 0x3e };
+int huff_bits22[2] = { 0, 14 };
+
+uint32 huff_table23[2] = { 0x0, 0x3c };
+int huff_bits23[2] = { 0, 14 };
+
+uint32 huff_table24[2] = { 0x0, 0x3a };
+int huff_bits24[2] = { 0, 14 };
+
+uint32 huff_table25[2] = { 0x0, 0x38 };
+int huff_bits25[2] = { 0, 14 };
+
+uint32 huff_table26[2] = { 0x0, 0x36 };
+int huff_bits26[2] = { 0, 14 };
+
+uint32 huff_table27[2] = { 0x0, 0x3e };
+int huff_bits27[2] = { 0, 17 };
+
+uint32 huff_table28[2] = { 0x0, 0x3c };
+int huff_bits28[2] = { 0, 17 };
+
+uint32 huff_table29[2] = { 0x0, 0x3a };
+int huff_bits29[2] = { 0, 17 };
+
+uint32 huff_table30[2] = { 0x0, 0x38 };
+int huff_bits30[2] = { 0, 17 };
+
+uint32 huff_table31[2] = { 0x0, 0x36 };
+int huff_bits31[2] = { 0, 17 };
+
+uint32 *huff_table[32] = { huff_table0, huff_table1, huff_table2, huff_table3, huff_table4, huff_table5, huff_table6, huff_table7, huff_table8, huff_table9, huff_table10, huff_table11, huff_table12, huff_table13, huff_table14, huff_table15, huff_table16, huff_table17, huff_table18, huff_table19, huff_table20, huff_table21, huff_table22, huff_table23, huff_table24, huff_table25, huff_table26, huff_table27, huff_table28, huff_table29, huff_table30, huff_table31 };
+int *huff_bits[32] = { huff_bits0, huff_bits1, huff_bits2, huff_bits3, huff_bits4, huff_bits5, huff_bits6, huff_bits7, huff_bits8, huff_bits9, huff_bits10, huff_bits11, huff_bits12, huff_bits13, huff_bits14, huff_bits15, huff_bits16, huff_bits17, huff_bits18, huff_bits19, huff_bits20, huff_bits21, huff_bits22, huff_bits23, huff_bits24, huff_bits25, huff_bits26, huff_bits27, huff_bits28, huff_bits29, huff_bits30, huff_bits31 };
diff --git a/converter/ppm/ppmtompeg/huff.h b/converter/ppm/ppmtompeg/huff.h
new file mode 100644
index 00000000..4d0b8840
--- /dev/null
+++ b/converter/ppm/ppmtompeg/huff.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /n/charlie-brown/project/mm/mpeg/mpeg_dist/mpeg_encode/RCS/huff.h,v 1.2 1995/01/19 23:08:28 eyhung Exp $
+ */
+
+/*  
+ *  THIS FILE IS MACHINE GENERATED!  DO NOT EDIT!
+ */
+#define HUFF_MAXRUN	32
+#define HUFF_MAXLEVEL	41
+
+extern int huff_maxlevel[];
+extern uint32 *huff_table[];
+extern int *huff_bits[];
diff --git a/converter/ppm/ppmtompeg/huff.table b/converter/ppm/ppmtompeg/huff.table
new file mode 100644
index 00000000..4f01d325
--- /dev/null
+++ b/converter/ppm/ppmtompeg/huff.table
@@ -0,0 +1,172 @@
+# 
+# Copyright (c) 1993 The Regents of the University of California.
+# All rights reserved.
+# 
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose, without fee, and without written agreement is
+# hereby granted, provided that the above copyright notice and the following
+# two paragraphs appear in all copies of this software.
+# 
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# 
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+# 
+
+#  
+#  $Header: /n/picasso/users/dwallach/vid2/mpeg_encode/RCS/huff.table,v 1.3 1993/02/17 23:21:58 dwallach Exp $
+#  $Log: huff.table,v $
+# Revision 1.3  1993/02/17  23:21:58  dwallach
+# checkin prior to keving's joining the project
+#
+# Revision 1.2  1993/01/18  10:20:02  dwallach
+# *** empty log message ***
+#
+#
+
+# this files is the raw Huffman encoding tables, from
+# the MPEG draft standard, P. D-41 - D-43 (Table D-2.15)
+
+# Format:
+# Run	Level	VLC Code
+
+# Run 0, Level 1 is special -- this table has the "NOT FIRST COEFF" entry
+# The "IF FIRST COEFF" would be: 0	1	1s
+
+0	1	11s
+
+0	2	0100 s
+0	3	0010 1s
+0	4	0000 110s
+0	5	0010 0110 s
+0	6	0010 0001 s
+0	7	0000 0010 10s
+0	8	0000 0001 1101 s
+0	9	0000 0001 1000 s
+0	10	0000 0001 0011 s
+0	11	0000 0001 0000 s
+0	12	0000 0000 1101 0s
+0	13	0000 0000 1100 1s
+0	14	0000 0000 1100 0s
+0	15	0000 0000 1011 1s
+0	16	0000 0000 0111 11s
+0	17	0000 0000 0111 10s
+0	18	0000 0000 0111 01s
+0	19	0000 0000 0111 00s
+0	20	0000 0000 0110 11s
+0	21	0000 0000 0110 10s
+0	22	0000 0000 0110 01s
+0	23	0000 0000 0110 00s
+0	24	0000 0000 0101 11s
+0	25	0000 0000 0101 10s
+0	26	0000 0000 0101 01s
+0	27	0000 0000 0101 00s
+0	28	0000 0000 0100 11s
+0	29	0000 0000 0100 10s
+0	30	0000 0000 0100 01s
+0	31	0000 0000 0100 00s
+0	32	0000 0000 0011 000s
+0	33	0000 0000 0010 111s
+0	34	0000 0000 0010 110s
+0	35	0000 0000 0010 101s
+0	36	0000 0000 0010 100s
+0	37	0000 0000 0010 011s
+0	38	0000 0000 0010 010s
+0	39	0000 0000 0010 001s
+0	40	0000 0000 0010 000s
+
+1	1	011s
+1	2	0001 10s
+1	3	0010 0101 s
+1	4	0000 0011 00s
+1	5	0000 0001 1011 s
+1	6	0000 0000 1011 0s
+1	7	0000 0000 1010 1s
+1	8	0000 0000 0011 111s
+1	9	0000 0000 0011 110s
+1	10	0000 0000 0011 101s
+1	11	0000 0000 0011 100s
+1	12	0000 0000 0011 011s
+1	13	0000 0000 0011 010s
+1	14	0000 0000 0011 001s
+1	15	0000 0000 0001 0011 s
+1	16	0000 0000 0001 0010 s
+1	17	0000 0000 0001 0001 s
+1	18	0000 0000 0001 0000 s
+
+2	1	0101 s
+2	2	0000 100s
+2	3	0000 0010 11s
+2	4	0000 0001 0100 s
+2	5	0000 0000 1010 0s
+
+3	1	0011 1s
+3	2	0010 0100 s
+3	3	0000 0001 1100 s
+3	4	0000 0000 1001 1s
+
+4	1	0011 0s
+4	2	0000 0011 11s
+4	3	0000 0001 0010 s
+
+5	1	0001 11s
+5	2	0000 0010 01s
+5	3	0000 0000 1001 0s
+
+6	1	0001 01s
+6	2	0000 0001 1110 s
+6	3	0000 0000 0001 0100 s
+
+7	1	0001 00s
+7	2	0000 0001 0101 s
+
+8	1	0000 111s
+8	2	0000 0001 0001 s
+
+9	1	0000 101s
+9	2	0000 0000 1000 1s
+
+10	1	0010 0111 s
+10	2	0000 0000 1000 0s
+
+11	1	0010 0011 s
+11	2	0000 0000 0001 1010 s
+
+12	1	0010 0010 s
+12	2	0000 0000 0001 1001 s
+
+13	1	0010 0000 s
+13	2	0000 0000 0001 1000 s
+
+14	1	0000 0011 10s
+14	2	0000 0000 0001 0111 s
+
+15	1	0000 0011 01s
+15	2	0000 0000 0001 0110 s
+
+16	1	0000 0010 00s
+16	2	0000 0000 0001 0101 s
+
+17	1	0000 0001 1111 s
+18	1	0000 0001 1010 s
+19	1	0000 0001 1001 s
+20	1	0000 0001 0111 s
+21	1	0000 0001 0110 s
+
+22	1	0000 0000 1111 1s
+23	1	0000 0000 1111 0s
+24	1	0000 0000 1110 1s
+25	1	0000 0000 1110 0s
+26	1	0000 0000 1101 1s
+
+27	1	0000 0000 0001 1111 s
+28	1	0000 0000 0001 1110 s
+29	1	0000 0000 0001 1101 s
+30	1	0000 0000 0001 1100 s
+31	1	0000 0000 0001 1011 s
diff --git a/converter/ppm/ppmtompeg/iframe.c b/converter/ppm/ppmtompeg/iframe.c
new file mode 100644
index 00000000..cb6d4683
--- /dev/null
+++ b/converter/ppm/ppmtompeg/iframe.c
@@ -0,0 +1,1062 @@
+/*===========================================================================*
+ * iframe.c                                  *
+ *                                       *
+ *  Procedures concerned with the I-frame encoding               *
+ *                                       *
+ * EXPORTED PROCEDURES:                              *
+ *  GenIFrame                                *
+ *  SetSlicesPerFrame                            *
+ *  SetBlocksPerSlice                            *
+ *  SetIQScale                               *
+ *  GetIQScale                               *
+ *  ResetIFrameStats                             *
+ *  ShowIFrameSummary                            *
+ *  EstimateSecondsPerIFrame                         *
+ *  EncodeYDC                                *
+ *  EncodeCDC                                *
+ *      time_elapsed                                                         *
+ *                                       *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+
+#ifdef CLOCKS_PER_SEC
+#include <times.h>
+#else
+#include <sys/times.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include "all.h"
+#include "mtypes.h"
+#include "frames.h"
+#include "prototypes.h"
+#include "block.h"
+#include "mpeg.h"
+#include "param.h"
+#include "mheaders.h"
+#include "fsize.h"
+#include "parallel.h"
+#include "postdct.h"
+#include "rate.h"
+#include "specifics.h"
+#include "opts.h"
+
+/*==================*
+ * STATIC VARIABLES *
+ *==================*/
+
+static  int lastNumBits = 0;
+static  int lastIFrame = 0;
+static int numBlocks = 0;
+static int numBits;
+static int numFrames = 0;
+static int numFrameBits = 0;
+static int32 totalTime = 0;
+static float    totalSNR = 0.0;
+static float    totalPSNR = 0.0;
+
+static int lengths[256] = {
+    0, 1, 2, 2, 3, 3, 3, 3,     /* 0 - 7 */
+    4, 4, 4, 4, 4, 4, 4, 4,     /* 8 - 15 */
+    5, 5, 5, 5, 5, 5, 5, 5,     /* 16 - 31 */
+    5, 5, 5, 5, 5, 5, 5, 5,
+    6, 6, 6, 6, 6, 6, 6, 6,     /* 32 - 63 */
+    6, 6, 6, 6, 6, 6, 6, 6,
+    6, 6, 6, 6, 6, 6, 6, 6,
+    6, 6, 6, 6, 6, 6, 6, 6,
+    7, 7, 7, 7, 7, 7, 7, 7,     /* 64 - 127 */
+    7, 7, 7, 7, 7, 7, 7, 7,
+    7, 7, 7, 7, 7, 7, 7, 7,
+    7, 7, 7, 7, 7, 7, 7, 7,
+    7, 7, 7, 7, 7, 7, 7, 7,
+    7, 7, 7, 7, 7, 7, 7, 7,
+    7, 7, 7, 7, 7, 7, 7, 7,
+    7, 7, 7, 7, 7, 7, 7, 7,
+    8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8
+};
+
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+
+int qscaleI;
+int slicesPerFrame;
+int blocksPerSlice;
+int fCodeI, fCodeP, fCodeB;
+boolean printSNR = FALSE;
+boolean printMSE = FALSE;
+boolean decodeRefFrames = FALSE;
+Block **dct=NULL, **dctr=NULL, **dctb=NULL;
+dct_data_type   **dct_data; /* used in p/bframe.c */
+int  TIME_RATE;
+
+
+/*=====================*
+ * EXPORTED PROCEDURES *
+ *=====================*/
+extern void PrintItoIBitRate _ANSI_ARGS_((int numBits, int frameNum));
+
+/*===============================*
+ * INTERNAL PROCEDURE prototypes *
+ *===============================*/
+void AllocDctBlocks(void );
+int SetFCodeHelper (int sr);
+void CalcDistortion (MpegFrame *current, int y, int x);
+
+int
+SetFCodeHelper(int const SR) {
+
+    int     range,fCode;
+
+    if ( pixelFullSearch ) {
+        range = SR;
+    } else {
+        range = SR*2;
+    }
+
+    if ( range < 256 ) {
+        if ( range < 64 ) {
+            if ( range < 32 ) {
+                fCode = 1;
+            } else {
+                fCode = 2;
+            }
+        } else {
+            if ( range < 128 ) {
+                fCode = 3;
+            } else {
+                fCode = 4;
+            }
+        }
+    } else {
+        if ( range < 1024 ) {
+            if ( range < 512 ) {
+                fCode = 5;
+            } else {
+                fCode = 6;
+            }
+        } else {
+            if ( range < 2048 ) {
+                fCode = 7;
+            } else {
+                fprintf(stderr, "ERROR:  INVALID SEARCH RANGE!!!\n");
+                exit(1);
+            }
+        }
+    }
+    return fCode;
+}
+
+
+
+/*===========================================================================*
+ *
+ * SetFCode
+ *
+ *  set the forward_f_code and backward_f_code according to the search
+ *  range.  Must be called AFTER pixelFullSearch and searchRange have
+ *  been initialized.  Irrelevant for I-frames, but computation is
+ *  negligible (done only once, as well)
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    fCodeI,fCodeP,fCodeB
+ *
+ *===========================================================================*/
+void
+SetFCode(void) {
+    fCodeI = SetFCodeHelper(1); /* GenIFrame ignores value */
+    fCodeP = SetFCodeHelper(searchRangeP);
+    fCodeB = SetFCodeHelper(searchRangeB);
+}
+
+
+
+/*===========================================================================*
+ *
+ * SetSlicesPerFrame
+ *
+ *  set the number of slices per frame
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    slicesPerFrame
+ *
+ *===========================================================================*/
+void
+SetSlicesPerFrame(int const number) {
+
+    slicesPerFrame = number;
+}
+
+
+
+/*===========================================================================*
+ *
+ * SetBlocksPerSlice
+ *
+ *  set the number of blocks per slice, based on slicesPerFrame
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    blocksPerSlice
+ *
+ *===========================================================================*/
+void
+SetBlocksPerSlice(void) {
+
+    int     totalBlocks;
+    
+    totalBlocks = (Fsize_y>>4)*(Fsize_x>>4);
+
+    if ( slicesPerFrame > totalBlocks ) {
+        blocksPerSlice = 1;
+    } else {
+        blocksPerSlice = totalBlocks/slicesPerFrame;
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ * SetIQScale
+ *
+ *  set the I-frame Q-scale
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    qscaleI
+ *
+ *===========================================================================*/
+void
+SetIQScale(int const qI) {
+    qscaleI = qI;
+}
+
+
+
+/*===========================================================================*
+ *
+ * GetIQScale
+ *
+ *  Get the I-frame Q-scale
+ *
+ * RETURNS: the Iframe Qscale
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+int
+GetIQScale(void) {
+    return qscaleI;
+}
+
+
+
+/*===========================================================================*
+ *
+ * GenIFrame
+ *
+ *  generate an I-frame; appends result to bb
+ *
+ * RETURNS: I-frame appended to bb
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+GenIFrame(BitBucket * const bb, 
+          MpegFrame * const current) {
+
+    int x, y;
+    int index;
+    FlatBlock    fb[6];
+    Block    dec[6];
+    int32 y_dc_pred, cr_dc_pred, cb_dc_pred;
+    int          totalBits;
+    int          totalFrameBits;
+    int32        startTime, endTime;
+    float        snr[3], psnr[3];
+    int          mbAddress;
+    int          QScale;
+    BlockMV      *info; /* Not used in Iframes, but nice to pass in anyway */
+    int          bitstreamMode, newQScale;
+    int          rc_blockStart=0;
+
+    if (dct==NULL) AllocDctBlocks();
+    if (collect_quant) {fprintf(collect_quant_fp, "# I\n");}
+
+    /* set-up for statistics */
+    numFrames++;
+    totalFrameBits = bb->cumulativeBits;
+    if ( showBitRatePerFrame ) {
+        if ( lastNumBits == 0 ) {
+            lastNumBits = bb->cumulativeBits;
+            lastIFrame = current->id;
+        } else {
+            /* ASSUMES 30 FRAMES PER SECOND */
+    
+            if (! realQuiet) {
+                fprintf(stdout, "I-to-I (frames %5d to %5d) bitrate:  %8d\n",
+                        lastIFrame, current->id-1,
+                        ((bb->cumulativeBits-lastNumBits)*30)/
+                        (current->id-lastIFrame));
+            }
+    
+            fprintf(bitRateFile, "I-to-I (frames %5d to %5d) bitrate:  %8d\n",
+                    lastIFrame, current->id-1,
+                    ((bb->cumulativeBits-lastNumBits)*30)/
+                    (current->id-lastIFrame));
+            lastNumBits = bb->cumulativeBits;       
+            lastIFrame = current->id;
+        }
+    }
+    
+    startTime = time_elapsed();
+    
+    Frame_AllocBlocks(current);
+    BlockifyFrame(current);
+
+    DBG_PRINT(("Generating iframe\n"));
+    QScale = GetIQScale();
+    /*   Allocate bits for this frame for rate control purposes */
+    bitstreamMode = getRateMode();
+    if (bitstreamMode == FIXED_RATE) {
+        targetRateControl(current);
+    }
+
+    Mhead_GenPictureHeader(bb, I_FRAME, current->id, fCodeI);
+    /* Check for Qscale change */
+    if (specificsOn) {
+        newQScale = SpecLookup(current->id, 0, 0 /* junk */, &info, QScale);
+        if (newQScale != -1) {
+            QScale = newQScale;
+        }
+        /* check for slice */
+        newQScale = SpecLookup(current->id, 1, 1, &info, QScale);
+        if (newQScale != -1) {
+            QScale = newQScale;
+        }
+    }
+    Mhead_GenSliceHeader(bb, 1, QScale, NULL, 0);
+    
+    if ( referenceFrame == DECODED_FRAME ) {
+        Frame_AllocDecoded(current, TRUE);
+    } else if ( printSNR ) {
+        Frame_AllocDecoded(current, FALSE);
+    }
+    
+    y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
+    totalBits = bb->cumulativeBits;
+    mbAddress = 0;
+
+    /* DCT the macroblocks */
+    for (y = 0;  y < (Fsize_y >> 3);  y += 2) {
+        for (x = 0;  x < (Fsize_x >> 3);  x += 2) {
+            if (collect_quant && (collect_quant_detailed & 1)) 
+                fprintf(collect_quant_fp, "l\n");
+            if (DoLaplace) {LaplaceCnum = 0;}
+            mp_fwd_dct_block2(current->y_blocks[y][x], dct[y][x]);
+            mp_fwd_dct_block2(current->y_blocks[y][x+1], dct[y][x+1]);
+            mp_fwd_dct_block2(current->y_blocks[y+1][x], dct[y+1][x]);
+            mp_fwd_dct_block2(current->y_blocks[y+1][x+1], dct[y+1][x+1]);
+            if (collect_quant && (collect_quant_detailed & 1)) 
+                fprintf(collect_quant_fp, "c\n");
+            if (DoLaplace) {LaplaceCnum = 1;}
+            mp_fwd_dct_block2(current->cb_blocks[y>>1][x>>1], 
+                              dctb[y>>1][x>>1]);
+            if (DoLaplace) {LaplaceCnum = 2;}
+            mp_fwd_dct_block2(current->cr_blocks[y>>1][x>>1], 
+                              dctr[y>>1][x>>1]);
+        }
+    }
+    
+    if (DoLaplace)
+        CalcLambdas();
+
+    for (y = 0;  y < (Fsize_y >> 3);  y += 2) {
+        for (x = 0;  x < (Fsize_x >> 3);  x += 2) {
+            /* Check for Qscale change */
+            if (specificsOn) {
+                newQScale = 
+                    SpecLookup(current->id, 2, mbAddress, &info, QScale);
+                if (newQScale != -1) {
+                    QScale = newQScale;
+                }
+            }
+    
+            /*  Determine if new Qscale needed for Rate Control purposes  */
+            if (bitstreamMode == FIXED_RATE) {
+                rc_blockStart = bb->cumulativeBits;
+                newQScale = needQScaleChange(qscaleI,
+                                             current->y_blocks[y][x],
+                                             current->y_blocks[y][x+1],
+                                             current->y_blocks[y+1][x],
+                                             current->y_blocks[y+1][x+1]);
+                if (newQScale > 0) {
+                    QScale = newQScale;
+                }
+            }
+    
+            if ( (mbAddress % blocksPerSlice == 0) && (mbAddress != 0) ) {
+                /* create a new slice */
+                if (specificsOn) {
+                    /* Make sure no slice Qscale change */
+                    newQScale = SpecLookup(current->id, 1,
+                                           mbAddress/blocksPerSlice, &info, 
+                                           QScale);
+                    if (newQScale != -1) QScale = newQScale;
+                }
+                Mhead_GenSliceEnder(bb);
+                Mhead_GenSliceHeader(bb, 1+(y>>1), QScale, NULL, 0);
+                y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
+      
+                GEN_I_BLOCK(I_FRAME, current, bb, 1+(x>>1), QScale);
+            } else {
+                GEN_I_BLOCK(I_FRAME, current, bb, 1, QScale);
+            }
+
+            if (WriteDistortionNumbers) {
+                CalcDistortion(current, y, x);
+            }
+    
+            if ( decodeRefFrames ) {
+                /* now, reverse the DCT transform */
+                LaplaceCnum = 0;
+                for ( index = 0; index < 6; index++ ) {
+                    if (!DoLaplace) {
+                        Mpost_UnQuantZigBlock(fb[index], dec[index], QScale, 
+                                              TRUE);
+                    } else {
+                        if (index == 4) {LaplaceCnum = 1;}
+                        if (index == 5) {LaplaceCnum = 2;}
+                        Mpost_UnQuantZigBlockLaplace(fb[index], dec[index], 
+                                                     QScale, TRUE);
+                    }
+                    mpeg_jrevdct((int16 *)dec[index]);      
+                }
+      
+                /* now, unblockify */
+                BlockToData(current->decoded_y, dec[0], y, x);
+                BlockToData(current->decoded_y, dec[1], y, x+1);
+                BlockToData(current->decoded_y, dec[2], y+1, x);
+                BlockToData(current->decoded_y, dec[3], y+1, x+1);
+                BlockToData(current->decoded_cb, dec[4], y>>1, x>>1);
+                BlockToData(current->decoded_cr, dec[5], y>>1, x>>1);
+            }
+    
+            numBlocks++;
+            mbAddress++;
+            /*   Rate Control */
+            if (bitstreamMode == FIXED_RATE) {
+                incMacroBlockBits(bb->cumulativeBits - rc_blockStart);
+                rc_blockStart = bb->cumulativeBits;
+                MB_RateOut(TYPE_IFRAME);
+            }
+        }
+    }
+    
+    if ( printSNR ) {
+        BlockComputeSNR(current,snr,psnr);
+        totalSNR += snr[0];
+        totalPSNR += psnr[0];
+    }
+    
+    numBits += (bb->cumulativeBits-totalBits);
+    
+    DBG_PRINT(("End of frame\n"));
+    
+    Mhead_GenSliceEnder(bb);
+    /*   Rate Control  */
+    if (bitstreamMode == FIXED_RATE) {
+        updateRateControl(TYPE_IFRAME);
+    }
+    
+    endTime = time_elapsed();
+    totalTime += (endTime-startTime);
+    
+    numFrameBits += (bb->cumulativeBits-totalFrameBits);
+    
+    if ( showBitRatePerFrame ) {
+        /* ASSUMES 30 FRAMES PER SECOND */
+        fprintf(bitRateFile, "%5d\t%8d\n", current->id,
+                30*(bb->cumulativeBits-totalFrameBits));
+    }
+    
+    if ( frameSummary && !realQuiet ) {
+        
+        /* ASSUMES 30 FRAMES PER SECOND */
+        fprintf(stdout, 
+                "FRAME %d (I):  %ld seconds  (%d bits/s output)\n", 
+                current->id, (long)((endTime-startTime)/TIME_RATE),
+                30*(bb->cumulativeBits-totalFrameBits));
+        if ( printSNR ) {
+            fprintf(stdout, 
+                    "FRAME %d:  SNR:  %.1f\t%.1f\t%.1f\t"
+                    "PSNR:  %.1f\t%.1f\t%.1f\n",
+                        current->id, snr[0], snr[1], snr[2],
+                    psnr[0], psnr[1], psnr[2]);
+        }
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ * ResetIFrameStats
+ *
+ *  reset the I-frame statistics
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+ResetIFrameStats(void) {
+    numBlocks = 0;
+    numBits = 0;
+    numFrames = 0;
+    numFrameBits = 0;
+    totalTime = 0;
+}
+
+
+
+float
+IFrameTotalTime(void) {
+    return (float)totalTime/(float)TIME_RATE;
+}
+
+
+
+void
+ShowIFrameSummary(unsigned int const inputFrameBits, 
+                  unsigned int const totalBits, 
+                  FILE *       const fpointer) {
+/*----------------------------------------------------------------------------
+   Print out statistics on all I frames.
+-----------------------------------------------------------------------------*/
+    if (numFrames > 0) {
+        fprintf(fpointer, "-------------------------\n");
+        fprintf(fpointer, "*****I FRAME SUMMARY*****\n");
+        fprintf(fpointer, "-------------------------\n");
+
+        fprintf(fpointer, "  Blocks:    %5d     (%6d bits)     (%5d bpb)\n",
+                numBlocks, numBits, numBits/numBlocks);
+        fprintf(fpointer, "  Frames:    %5d     (%6d bits)     (%5d bpf)"
+                "(%2.1f%% of total)\n",
+                numFrames, numFrameBits, numFrameBits/numFrames,
+                100.0*(float)numFrameBits/(float)totalBits);
+        fprintf(fpointer, "  Compression:  %3d:1     (%9.4f bpp)\n",
+                numFrames*inputFrameBits/numFrameBits,
+                24.0*(float)numFrameBits/(float)(numFrames*inputFrameBits));
+        if ( printSNR )
+            fprintf(fpointer, "  Avg Y SNR/PSNR:  %.1f     %.1f\n",
+                    totalSNR/(float)numFrames, totalPSNR/(float)numFrames);
+        if ( totalTime == 0 ) {
+            fprintf(fpointer, "  Seconds:  NONE\n");
+        } else {
+            fprintf(fpointer, "  Seconds:  %9ld     (%9.4f fps)  (%9ld pps)  "
+                    "(%9ld mps)\n",
+                    (long)(totalTime/TIME_RATE),
+                    (float)((float)(TIME_RATE*numFrames)/(float)totalTime),
+                    (long)((float)TIME_RATE * (float)numFrames *
+                           (float)inputFrameBits/(24.0*(float)totalTime)),
+                    (long)((float)TIME_RATE*(float)numFrames *
+                           (float)inputFrameBits/(256.0*24.0 *
+                                                  (float)totalTime)));
+        }
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ * EstimateSecondsPerIFrame
+ *
+ *  estimates the number of seconds required per I-frame
+ *
+ * RETURNS: seconds (floating point value)
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+float
+EstimateSecondsPerIFrame()
+{
+    return (float)totalTime/((float)TIME_RATE*(float)numFrames);
+}
+
+
+/*===========================================================================*
+ *
+ * EncodeYDC
+ *
+ *  Encode the DC portion of a DCT of a luminance block
+ *
+ * RETURNS: result appended to bb
+ *
+ * SIDE EFFECTS:    updates pred_term
+ *
+ *===========================================================================*/
+void
+EncodeYDC(int32       const dc_term,
+          int32 *     const pred_term,
+          BitBucket * const bb) {
+
+    /* see Table B.5a -- MPEG-I doc */
+    static int codes[9] = {
+    0x4, 0x0, 0x1, 0x5, 0x6, 0xe, 0x1e, 0x3e, 0x7e
+    };
+    static int codeLengths[9] = {
+    3,   2,   2,   3,   3,   4,   5,    6,    7
+    };
+    int ydiff, ydiff_abs;
+    int length;
+
+    ydiff = (dc_term - (*pred_term));
+    if (ydiff > 255) {
+#ifdef BLEAH 
+      fprintf(stdout, "TRUNCATED\n");
+#endif
+    ydiff = 255;
+    } else if (ydiff < -255) {
+#ifdef BLEAH 
+      fprintf(stdout, "TRUNCATED\n");
+#endif
+    ydiff = -255;
+    }
+
+    ydiff_abs = ABS(ydiff);
+    length = lengths[ydiff_abs];
+    Bitio_Write(bb, codes[length], codeLengths[length]);
+    if ( length != 0 ) {
+    if ( ydiff > 0 ) {
+        Bitio_Write(bb, ydiff_abs, length);
+    } else {
+        Bitio_Write(bb, ~ydiff_abs, length);
+    }
+    }
+
+    (*pred_term) += ydiff;
+}
+
+
+
+/*===========================================================================*
+ *
+ * EncodeCDC
+ *
+ *  Encode the DC portion of a DCT of a chrominance block
+ *
+ * RETURNS: result appended to bb
+ *
+ * SIDE EFFECTS:    updates pred_term
+ *
+ *===========================================================================*/
+void
+EncodeCDC(int32       const dc_term,
+          int32     * const pred_term,
+          BitBucket * const bb) {
+
+    /* see Table B.5b -- MPEG-I doc */
+    static int codes[9] = {
+        0x0, 0x1, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe
+    };
+    static int codeLengths[9] = {
+        2,   2,   2,   3,   4,   5,    6,    7,    8
+    };
+    int cdiff, cdiff_abs;
+    int length;
+
+    cdiff = (dc_term - (*pred_term));
+    if (cdiff > 255) {
+#ifdef BLEAH
+        fprintf(stdout, "TRUNCATED\n"); 
+#endif
+        cdiff = 255;
+    } else if (cdiff < -255) {
+#ifdef BLEAH
+        fprintf(stdout, "TRUNCATED\n"); 
+#endif
+        cdiff = -255;
+    }
+
+    cdiff_abs = ABS(cdiff);
+    length = lengths[cdiff_abs];
+    Bitio_Write(bb, codes[length], codeLengths[length]);
+    if ( length != 0 ) {
+        if ( cdiff > 0 ) {
+            Bitio_Write(bb, cdiff_abs, length);
+        } else {
+            Bitio_Write(bb, ~cdiff_abs, length);
+        }
+    }
+
+    (*pred_term) += cdiff;
+}
+
+
+
+void
+BlockComputeSNR(MpegFrame * const current,
+                float *     const snr,
+                float *     const psnr) {
+
+    int32    tempInt;
+    int y, x;
+    int32 varDiff[3];
+    double    ratio[3];
+    double    total[3];
+    uint8 **origY=current->orig_y, **origCr=current->orig_cr, 
+        **origCb=current->orig_cb;
+    uint8 **newY=current->decoded_y, **newCr=current->decoded_cr, 
+        **newCb=current->decoded_cb;
+    static int32       **SignalY,  **NoiseY;
+    static int32       **SignalCb, **NoiseCb;
+    static int32       **SignalCr, **NoiseCr;
+    static short   ySize[3], xSize[3];
+    static boolean needs_init=TRUE;
+  
+    /* Init */
+    if (needs_init) {
+        int ysz = (Fsize_y>>3) * sizeof(int32 *);
+        int xsz = (Fsize_x>>3);
+    
+        needs_init = FALSE;
+        for (y=0; y<3; y++) {
+            varDiff[y] = ratio[y] = total[y] = 0.0;
+        }
+        ySize[0]=Fsize_y;     xSize[0]=Fsize_x;
+        ySize[1]=Fsize_y>>1;  xSize[1]=Fsize_x>>1;
+        ySize[2]=Fsize_y>>1;  xSize[2]=Fsize_x>>1;
+        SignalY  = (int32 **) malloc(ysz);
+        NoiseY   = (int32 **) malloc(ysz);
+        SignalCb = (int32 **) malloc(ysz);
+        NoiseCb  = (int32 **) malloc(ysz);
+        SignalCr = (int32 **) malloc(ysz);
+        NoiseCr  = (int32 **) malloc(ysz);
+        if (SignalY == NULL || NoiseY == NULL || SignalCr == NULL || 
+            NoiseCb == NULL || SignalCb == NULL || NoiseCr == NULL) {
+            fprintf(stderr, "Out of memory in BlockComputeSNR\n");
+            exit(-1);
+        }
+        for (y = 0; y < ySize[0]>>3; y++) {
+            SignalY[y]  = (int32 *) calloc(xsz,4);
+            SignalCr[y]  = (int32 *) calloc(xsz,4);
+            SignalCb[y]  = (int32 *) calloc(xsz,4);
+            NoiseY[y]  = (int32 *) calloc(xsz,4);
+            NoiseCr[y]  = (int32 *) calloc(xsz,4);
+            NoiseCb[y]  = (int32 *) calloc(xsz,4);
+        }
+    } else {
+        for (y = 0; y < ySize[0]>>3; y++) {
+            memset((char *) &NoiseY[y][0], 0, (xSize[0]>>3) * 4);
+            memset((char *) &SignalY[y][0], 0, (xSize[0]>>3) * 4);
+            memset((char *) &NoiseCb[y][0], 0, (xSize[0]>>3) * 4);
+            memset((char *) &NoiseCr[y][0], 0, (xSize[0]>>3) * 4);
+            memset((char *) &SignalCb[y][0], 0, (xSize[0]>>3) * 4);
+            memset((char *) &SignalCr[y][0], 0, (xSize[0]>>3) * 4);
+        }
+    }
+  
+    /* find all the signal and noise */
+    for (y = 0; y < ySize[0]; y++) {
+        for (x = 0; x < xSize[0]; x++) {
+            tempInt = (origY[y][x] - newY[y][x]);
+            NoiseY[y>>4][x>>4] += tempInt*tempInt;
+            total[0] += (double)abs(tempInt);
+            tempInt = origY[y][x];
+            SignalY[y>>4][x>>4] += tempInt*tempInt;
+        }}
+    for (y = 0; y < ySize[1]; y++) {
+        for (x = 0; x < xSize[1]; x ++) {
+            tempInt = (origCb[y][x] - newCb[y][x]);
+            NoiseCb[y>>3][x>>3] += tempInt*tempInt;
+            total[1] += (double)abs(tempInt);
+            tempInt = origCb[y][x];
+            SignalCb[y>>3][x>>3] += tempInt*tempInt;
+            tempInt = (origCr[y][x]-newCr[y][x]);
+            NoiseCr[y>>3][x>>3] += tempInt*tempInt;
+            total[2] += (double)abs(tempInt);
+            tempInt = origCr[y][x];
+            SignalCr[y>>3][x>>3] += tempInt*tempInt;
+        }}
+  
+    /* Now sum up that noise */
+    for(y=0; y<Fsize_y>>4; y++){
+        for(x=0; x<Fsize_x>>4; x++){
+            varDiff[0] += NoiseY[y][x];
+            varDiff[1] += NoiseCb[y][x];
+            varDiff[2] += NoiseCr[y][x];
+            if (printMSE) printf("%4d ",(int)(NoiseY[y][x]/256.0));
+        }
+        if (printMSE) puts("");
+    }
+  
+    /* Now look at those ratios! */
+    for(y=0; y<Fsize_y>>4; y++){
+        for(x=0; x<Fsize_x>>4; x++){
+            ratio[0] += (double)SignalY[y][x]/(double)varDiff[0];
+            ratio[1] += (double)SignalCb[y][x]/(double)varDiff[1];
+            ratio[2] += (double)SignalCr[y][x]/(double)varDiff[2];
+        }}
+  
+    for (x=0; x<3; x++) {
+        snr[x] = 10.0 * log10(ratio[x]);
+        psnr[x] = 20.0 * log10(255.0/sqrt((double)varDiff[x]/
+                                          (double)(ySize[x]*xSize[x])));
+
+        if (! realQuiet) {
+            fprintf(stdout, "Mean error[%1d]:  %f\n",
+                    x, total[x] / (double)(xSize[x] * ySize[x]));
+        }
+
+    }
+}
+
+
+
+void
+WriteDecodedFrame(MpegFrame * const frame) {
+
+    FILE * fpointer;
+    char   fileName[256];
+    int    width, height;
+    int    y;
+
+    /* need to save decoded frame to disk because it might be accessed
+       by another process */
+
+    width = Fsize_x;
+    height = Fsize_y;
+
+    sprintf(fileName, "%s.decoded.%d", outputFileName, frame->id);
+
+    if (!realQuiet) {
+        fprintf(stdout, "Outputting to %s\n", fileName);
+        fflush(stdout);
+    }
+
+    fpointer = fopen(fileName, "wb");
+
+    for ( y = 0; y < height; y++ ) {
+        fwrite(frame->decoded_y[y], 1, width, fpointer);
+    }
+
+    for (y = 0; y < (height >> 1); y++) {           /* U */
+        fwrite(frame->decoded_cb[y], 1, width >> 1, fpointer);
+    }
+
+    for (y = 0; y < (height >> 1); y++) {           /* V */
+        fwrite(frame->decoded_cr[y], 1, width >> 1, fpointer);
+    }
+    fflush(fpointer);
+    fclose(fpointer);
+}
+
+
+
+void
+PrintItoIBitRate(int const numBits,
+                 int const frameNum) {
+
+    if ( showBitRatePerFrame ) {
+        /* ASSUMES 30 FRAMES PER SECOND */
+
+        if (! realQuiet) {
+            fprintf(stdout, "I-to-I (frames %5d to %5d) bitrate:  %8d\n",
+                    lastIFrame, frameNum-1,
+                    ((numBits-lastNumBits)*30)/
+                    (frameNum-lastIFrame));
+        }
+
+        fprintf(bitRateFile, "I-to-I (frames %5d to %5d) bitrate:  %8d\n",
+                lastIFrame, frameNum-1,
+                ((numBits-lastNumBits)*30)/
+                (frameNum-lastIFrame));
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ * AllocDctBlocks
+ *
+ *  allocate memory for dct blocks
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    creates dct, dctr, dctb
+ *
+ *===========================================================================*/
+void
+AllocDctBlocks(void) {
+    int dctx, dcty;
+    int i;
+
+    dctx = Fsize_x / DCTSIZE;
+    dcty = Fsize_y / DCTSIZE;
+
+    dct = (Block **) malloc(sizeof(Block *) * dcty);
+    ERRCHK(dct, "malloc");
+    for (i = 0; i < dcty; i++) {
+        dct[i] = (Block *) malloc(sizeof(Block) * dctx);
+        ERRCHK(dct[i], "malloc");
+    }
+
+    dct_data = (dct_data_type **) malloc(sizeof(dct_data_type *) * dcty);
+    ERRCHK(dct_data, "malloc");
+    for (i = 0; i < dcty; i++) {
+        dct_data[i] = (dct_data_type *) malloc(sizeof(dct_data_type) * dctx);
+        ERRCHK(dct[i], "malloc");
+    }
+
+    dctr = (Block **) malloc(sizeof(Block *) * (dcty >> 1));
+    dctb = (Block **) malloc(sizeof(Block *) * (dcty >> 1));
+    ERRCHK(dctr, "malloc");
+    ERRCHK(dctb, "malloc");
+    for (i = 0; i < (dcty >> 1); i++) {
+        dctr[i] = (Block *) malloc(sizeof(Block) * (dctx >> 1));
+        dctb[i] = (Block *) malloc(sizeof(Block) * (dctx >> 1));
+        ERRCHK(dctr[i], "malloc");
+        ERRCHK(dctb[i], "malloc");
+    }
+}
+
+
+
+/*======================================================================*
+ *
+ * time_elapsed
+ *
+ *     Handle different time systems on different machines
+ *
+ *  RETURNS number of seconds process time used
+ *
+ *======================================================================*/
+int32 time_elapsed(void) {
+#ifdef CLOCKS_PER_SEC
+    /* ANSI C */
+    TIME_RATE = CLOCKS_PER_SEC;
+    return (int32) clock();
+#else
+    struct tms   timeBuffer;
+    TIME_RATE = 60;
+    times(&timeBuffer);
+    return timeBuffer.tms_utime + timeBuffer.tms_stime;
+#endif
+}
+
+
+
+void
+CalcDistortion(MpegFrame * const current,
+               int         const y,
+               int         const x) {
+
+    int qscale, distort=0;
+    Block decblk;
+    FlatBlock fblk;
+    int datarate = 0;
+  
+    for (qscale = 1; qscale < 32; qscale ++) {
+        distort = 0;
+        datarate = 0;
+        Mpost_QuantZigBlock(dct[y][x], fblk, qscale, TRUE);
+        Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
+        if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
+        mpeg_jrevdct((int16 *)decblk);
+        distort += mse(current->y_blocks[y][x], decblk);
+
+        Mpost_QuantZigBlock(dct[y][x+1], fblk, qscale, TRUE);
+        Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
+        if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
+        mpeg_jrevdct((int16 *)decblk);
+        distort += mse(current->y_blocks[y][x+1], decblk);
+
+        Mpost_QuantZigBlock(dct[y+1][x], fblk, qscale, TRUE);
+        Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
+        if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
+        mpeg_jrevdct((int16 *)decblk);
+        distort += mse(current->y_blocks[y+1][x], decblk);
+
+        Mpost_QuantZigBlock(dct[y+1][x+1], fblk, qscale, TRUE);
+        Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
+        if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
+        mpeg_jrevdct((int16 *)decblk);
+        distort += mse(current->y_blocks[y+1][x+1], decblk);
+
+        Mpost_QuantZigBlock(dctb[y >> 1][x >> 1], fblk, qscale, TRUE);
+        Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
+        if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
+        mpeg_jrevdct((int16 *)decblk);
+        distort += mse(current->cb_blocks[y>>1][x>>1], decblk);
+
+        Mpost_QuantZigBlock(dctr[y >> 1][x >> 1], fblk, qscale, TRUE);
+        Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
+        if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
+        mpeg_jrevdct((int16 *)decblk);
+        distort += mse(current->cr_blocks[y >> 1][x >> 1], decblk);
+
+        if (!collect_distortion_detailed) {
+            fprintf(distortion_fp, "\t%d\n", distort);
+        } else if (collect_distortion_detailed == 1) {
+            fprintf(distortion_fp, "\t%d\t%d\n", distort, datarate);
+        } else {
+            fprintf(fp_table_rate[qscale-1], "%d\n", datarate);
+            fprintf(fp_table_dist[qscale-1], "%d\n", distort);
+        }
+    }
+}
+
+
+
+
diff --git a/converter/ppm/ppmtompeg/input.c b/converter/ppm/ppmtompeg/input.c
new file mode 100644
index 00000000..2b87afa7
--- /dev/null
+++ b/converter/ppm/ppmtompeg/input.c
@@ -0,0 +1,515 @@
+/*===========================================================================*
+ * input.c              
+ *                      
+ *  Stuff for getting the raw frame input for the program
+ *                                    
+ *===========================================================================*/
+
+/* COPYRIGHT INFORMATION IS AT THE END OF THIS FILE */
+
+#define _XOPEN_SOURCE 1
+    /* This makes sure popen() is in stdio.h.  In GNU libc 2.1.3, 
+     _POSIX_C_SOURCE = 2 is sufficient, but on AIX 4.3, the higher level
+     _XOPEN_SOURCE is required.  2000.09.09 
+    */
+
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+
+#include "nstring.h"
+#include "mallocvar.h"
+#include "parallel.h"
+#include "readframe.h"
+#include "param.h"
+#include "jpeg.h"
+#include "input.h"
+
+extern boolean realQuiet;	/* TRUE = no messages to stdout */
+
+struct InputFileEntry {
+    char    left[256];
+    char    right[256];
+    bool    glob;       /* if FALSE, left is complete name */
+    int     startID;
+    int     endID;
+    int     skip;
+    int     numPadding;     /* -1 if there is none */
+    int     numFiles;
+    bool    repeat;
+};
+
+
+struct inputSource inputSource;
+
+
+
+void
+GetNthInputFileName(struct inputSource * const inputSourceP,
+                    unsigned int         const n,
+                    const char **        const fileNameP) {
+/*----------------------------------------------------------------------------
+   Return the file name of the Nth input file.
+-----------------------------------------------------------------------------*/
+    static int	lastN = 0, lastMapN = 0, lastSoFar = 0;
+    int	    mapN;
+    int     index;
+    int	    soFar;
+    int	    numPadding;
+    struct InputFileEntry * mapNEntryP;
+
+    assert(!inputSourceP->stdinUsed);
+    assert(n < inputSourceP->numInputFiles);
+
+    if (n >= lastN) {
+        soFar = lastSoFar;
+        index = lastMapN;
+    } else {
+        soFar = 0;
+        index = 0;
+    }
+
+    assert(index < inputSourceP->numInputFileEntries);
+
+    while (soFar + inputSourceP->inputFileEntries[index]->numFiles <= n) {
+        soFar +=  inputSourceP->inputFileEntries[index]->numFiles;
+        ++index;
+        assert(index < inputSourceP->numInputFileEntries);
+    }
+
+    mapN = index;
+    
+    mapNEntryP = inputSourceP->inputFileEntries[mapN];
+
+    index = mapNEntryP->startID + mapNEntryP->skip*(n - soFar);
+
+    numPadding = mapNEntryP->numPadding;
+
+    if (numPadding != -1) {
+        char    numBuffer[33];
+        int	    loop;
+
+        sprintf(numBuffer, "%32d", index);
+        for (loop = 32-numPadding; loop < 32; ++loop) {
+            if (numBuffer[loop] != ' ')
+                break;
+            else
+                numBuffer[loop] = '0';
+        }
+
+        if (mapNEntryP->repeat != TRUE)
+            asprintfN(fileNameP, "%s%s%s",
+                      mapNEntryP->left, &numBuffer[32-numPadding],
+                      mapNEntryP->right);
+        else
+            asprintfN(fileNameP, "%s", mapNEntryP->left);
+    } else {
+        if (mapNEntryP->repeat != TRUE)
+            asprintfN(fileNameP, "%s%d%s",
+                      mapNEntryP->left, index, mapNEntryP->right);
+        else
+            asprintfN(fileNameP, "%s", mapNEntryP->left);
+    }
+
+    lastN = n;
+    lastMapN = mapN;
+    lastSoFar = soFar;
+}
+
+
+
+void
+ReadNthFrame(struct inputSource * const inputSourceP,
+             unsigned int         const frameNumber,
+             boolean              const remoteIO,
+             boolean              const childProcess,
+             boolean              const separateConversion,
+             const char *         const slaveConversion,
+             const char *         const inputConversion,
+             MpegFrame *          const frameP,
+             bool *               const endOfStreamP) {
+
+    if (remoteIO)
+        /* Get the frame from the remote I/O server */
+        GetRemoteFrame(frameP, frameNumber);
+    else {
+        /* Get the frame out of the file in which it lives */
+
+        const char * conversion;
+
+        if (childProcess && separateConversion)
+            conversion = slaveConversion;
+        else
+            conversion = inputConversion;
+
+        ReadFrame(frameP, inputSourceP, frameNumber, conversion, endOfStreamP);
+    }
+}
+
+
+
+/* Jim Boucher's code */
+
+void
+JM2JPEG(struct inputSource * const inputSourceP) {
+    char full_path[1024];
+    char inter_file[1024]; 
+    int ci;
+    
+    for(ci = 0; ci < inputSourceP->numInputFileEntries; ci++) {
+        inter_file[0] = '\0';
+        full_path[0] = '\0';
+        strcpy(full_path, currentPath);
+    
+        if (!inputSource.stdinUsed) {
+            strcat(full_path, "/");
+            strcat(full_path, inputSourceP->inputFileEntries[ci]->left);
+            strcpy(inter_file,full_path);
+    
+            if (!realQuiet)
+                fprintf(stdout, "Extracting JPEG's in the JMOVIE from %s\n",
+                        full_path);
+    
+            JMovie2JPEG(full_path,
+                        inter_file,
+                        inputSourceP->inputFileEntries[ci]->startID, 
+                        inputSourceP->inputFileEntries[ci]->endID);
+        } else
+            pm_error("ERROR: Cannot use JMovie format on Standard Input");
+    }
+}
+
+
+
+static const char *
+SkipSpacesTabs(const char * const start) {
+
+    const char * p;
+
+    for (p = start; *p == ' ' || *p == '\t'; ++p);
+
+    return p;
+}
+
+
+
+static void
+processGlob(const char *            const input, 
+            struct InputFileEntry * const inputFileEntryP) {
+
+    const char *globPtr;
+    char *  charPtr;
+    char    left[256], right[256];
+    char    leftNumText[256], rightNumText[256];
+    char    skipNumText[256];
+    int	    leftNum, rightNum;
+    int	    skipNum;
+    boolean padding;
+    int	    numPadding = 0;
+
+    inputFileEntryP->glob = TRUE;
+    inputFileEntryP->repeat = FALSE;
+
+    /* star expand */
+
+    globPtr = input;
+    charPtr = left;
+    /* copy left of '*' */
+    while ( (*globPtr != '\0') && (*globPtr != '*') ) {
+        *charPtr = *globPtr;
+        charPtr++;
+        globPtr++;
+    }
+    *charPtr = '\0';
+
+    if (*globPtr == '\0') {
+        fprintf(stderr, 
+                "WARNING: expanding non-star regular expression\n");
+        inputFileEntryP->repeat = TRUE;
+        globPtr = input;
+        charPtr = left;
+        /* recopy left of whitespace */
+        while ( (*globPtr != '\0') && (*globPtr != '*') && 
+                (*globPtr != ' ')  && (*globPtr != '\t')) {
+            *charPtr = *globPtr;
+            charPtr++;
+            globPtr++;
+        }
+        *charPtr = '\0';
+        *right = '\0';
+    } else {
+
+        globPtr++;
+        charPtr = right;
+        /* copy right of '*' */
+        while ( (*globPtr != '\0') && (*globPtr != ' ') &&
+                (*globPtr != '\t') ) {
+            *charPtr = *globPtr;
+            charPtr++;
+            globPtr++;
+        }
+        *charPtr = '\0';
+    }
+      
+    globPtr = SkipSpacesTabs(globPtr);
+
+    if ( *globPtr != '[' ) {
+        fprintf(stderr, 
+                "ERROR:  "
+                "Invalid input file expansion expression (no '[')\n");
+        exit(1);
+    }
+
+    globPtr++;
+    charPtr = leftNumText;
+    /* copy left number */
+    while ( ISDIGIT(*globPtr) ) {
+        *charPtr = *globPtr;
+        charPtr++;
+        globPtr++;
+    }
+    *charPtr = '\0';
+
+    if ( *globPtr != '-' ) {
+        fprintf(stderr, 
+                "ERROR:  "
+                "Invalid input file expansion expression (no '-')\n");
+        exit(1);
+    }
+
+    globPtr++;
+    charPtr = rightNumText;
+    /* copy right number */
+    while ( ISDIGIT(*globPtr) ) {
+        *charPtr = *globPtr;
+        charPtr++;
+        globPtr++;
+    }
+    *charPtr = '\0';
+    if ( atoi(rightNumText) < atoi(leftNumText) ) {
+        fprintf(stderr, 
+                "ERROR:  "
+                "Beginning of input range is higher than end.\n");
+        exit(1);
+    }
+
+
+    if ( *globPtr != ']' ) {
+        if ( *globPtr != '+' ) {
+            fprintf(stderr, 
+                    "ERROR:  "
+                    "Invalid input file expansion expression "
+                    "(no ']')\n");
+            exit(1);
+        }
+
+        globPtr++;
+        charPtr = skipNumText;
+        /* copy skip number */
+        while ( ISDIGIT(*globPtr) ) {
+            *charPtr = *globPtr;
+            charPtr++;
+            globPtr++;
+        }
+        *charPtr = '\0';
+
+        if ( *globPtr != ']' ) {
+            fprintf(stderr, 
+                    "ERROR:  Invalid input file expansion expression "
+                    "(no ']')\n");
+            exit(1);
+        }
+
+        skipNum = atoi(skipNumText);
+    } else {
+        skipNum = 1;
+    }
+
+    leftNum = atoi(leftNumText);
+    rightNum = atoi(rightNumText);
+
+    if ( (leftNumText[0] == '0') && (leftNumText[1] != '\0') ) {
+        padding = TRUE;
+        numPadding = strlen(leftNumText);
+    } else {
+        padding = FALSE;
+    }
+
+    inputFileEntryP->startID = leftNum;
+    inputFileEntryP->endID = rightNum;
+    inputFileEntryP->skip = skipNum;
+    inputFileEntryP->numFiles = 
+        (rightNum-leftNum+1)/skipNum;
+    strcpy(inputFileEntryP->left, left);
+    strcpy(inputFileEntryP->right, right);
+    if ( padding ) {
+        inputFileEntryP->numPadding = numPadding;
+    } else {
+        inputFileEntryP->numPadding = -1;
+    }
+}
+
+
+
+static void processJmovie(const char *            const input, 
+                          struct InputFileEntry * const inputFileEntryP) {
+    FILE    *jmovie;
+    char    full_path[1024];
+
+    inputFileEntryP->glob = TRUE;
+    full_path[0] = '\0';
+    strcpy(full_path, currentPath);
+    
+    strcat(full_path, "/");
+    strcat(full_path, input);
+    jmovie = fopen(input, "rb"); 
+    
+    if (jmovie == NULL) {
+        perror (input); 
+        exit (1);
+    }
+    
+    fseek (jmovie, (8*sizeof(char)), 0);
+    fseek (jmovie, (2*sizeof(int)), 1);
+    
+    if (fread(&(inputFileEntryP->numFiles),
+              sizeof(int), 1, jmovie) != 1) {
+        perror ("Error in reading number of frames in JMOVIE");
+        exit(1);
+    }
+    fclose (jmovie);
+
+    strcpy(inputFileEntryP->right,".jpg");
+    inputFileEntryP->numPadding = -1;
+    inputFileEntryP->startID = 1;
+    inputFileEntryP->endID = (inputFileEntryP->numFiles-1);
+    inputFileEntryP->skip = 1;
+    if (! realQuiet) {
+        fprintf (stdout, 
+                 "Encoding all %d frames from JMOVIE.\n", 
+                 inputFileEntryP->endID);
+    }
+} 
+
+
+
+static void
+processSimpleFileName(const char *            const input,
+                      struct InputFileEntry * const inputFileEntryP) {
+
+    inputFileEntryP->glob = FALSE;
+    inputFileEntryP->numFiles = 1;
+    /* fixes a bug from version 1.3: */
+    inputFileEntryP->numPadding = 0;
+    /* fixes a bug from version 1.4 */
+    strcpy(inputFileEntryP->right,"\0");
+    inputFileEntryP->startID = 0;
+    inputFileEntryP->endID = 0;
+    inputFileEntryP->skip = 0;
+}
+
+
+#define INPUT_ENTRY_BLOCK_SIZE   128
+
+void
+AddInputFiles(struct inputSource * const inputSourceP,
+              const char *         const input) {
+
+    unsigned int const currentIndex = inputSourceP->numInputFileEntries;
+
+    struct InputFileEntry * currentEntryP;
+
+    if (currentIndex >= inputSourceP->ifArraySize) {
+        /* Get more space */
+        inputSourceP->ifArraySize += INPUT_ENTRY_BLOCK_SIZE;
+        REALLOCARRAY_NOFAIL(inputSourceP->inputFileEntries, 
+                            inputSourceP->ifArraySize);
+    }
+    MALLOCVAR_NOFAIL(inputSourceP->inputFileEntries[currentIndex]);
+    currentEntryP = inputSourceP->inputFileEntries[currentIndex];
+
+    if (input[strlen(input)-1] == ']') 
+        processGlob(input, currentEntryP);
+    else {
+        strcpy(currentEntryP->left, input);
+        if (baseFormat == JMOVIE_FILE_TYPE) 
+            processJmovie(input, currentEntryP);
+        else 
+            processSimpleFileName(input, currentEntryP);
+    }
+    inputSourceP->numInputFiles += currentEntryP->numFiles;
+    ++inputSourceP->numInputFileEntries;
+}
+
+
+
+void
+SetStdinInput(struct inputSource * const inputSourceP) {
+
+    assert(inputSourceP->numInputFileEntries == 0);
+
+    inputSourceP->stdinUsed = TRUE;
+    inputSourceP->numInputFiles = INT_MAX;
+}
+
+
+
+void
+CreateInputSource(struct inputSource ** const inputSourcePP) {
+
+    struct inputSource * inputSourceP;
+
+    MALLOCVAR_NOFAIL(inputSourceP);
+
+    inputSourceP->stdinUsed = FALSE;
+    inputSourceP->numInputFileEntries = 0;
+    inputSourceP->ifArraySize = 1;
+    inputSourceP->numInputFiles = 0;
+    MALLOCARRAY_NOFAIL(inputSourceP->inputFileEntries, 1);
+    
+    *inputSourcePP = inputSourceP;
+}
+
+
+
+void
+DestroyInputSource(struct inputSource * const inputSourceP) {
+
+    unsigned int i;
+
+    for (i = 0; i < inputSourceP->numInputFileEntries; ++i)
+        free(inputSourceP->inputFileEntries[i]);
+
+    free(inputSourceP->inputFileEntries);
+
+    free(inputSourceP);
+}
+
+
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
diff --git a/converter/ppm/ppmtompeg/jpeg.c b/converter/ppm/ppmtompeg/jpeg.c
new file mode 100644
index 00000000..3aad6364
--- /dev/null
+++ b/converter/ppm/ppmtompeg/jpeg.c
@@ -0,0 +1,634 @@
+/*===========================================================================*
+ * jpeg.c                              
+ *                                     
+ *  procedures to deal with JPEG files 
+ *                                     
+ * EXPORTED PROCEDURES:                
+ *  JMovie2JPEG                        
+ *      ReadJPEG                      
+ *                                    
+ *===========================================================================*/
+
+/* COPYRIGHT INFORMATION IS AT THE END OF THIS FILE */
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+#define _XOPEN_SOURCE    /* Make sure stdio.h contains fileno() */
+#include <stdio.h>
+#include "all.h"
+/* With the lossless jpeg patch applied to the Jpeg library
+    (ftp://ftp.wizards.dupont.com/pub/ImageMagick/delegates/ljpeg-6b.tar.gz),
+    the name of min_DCT_scaled_size changes to min_codec_data_unit,
+    for some reason.  With this macro, we change it back.  
+*/
+#define min_codec_data_unit min_DCT_scaled_size
+#include <jpeglib.h>
+#undef min_codec_data_unit
+#include "mtypes.h"
+#include "frames.h"
+#include "prototypes.h"
+#include "param.h"
+#include "readframe.h"
+#include "fsize.h"
+#include "rgbtoycc.h"
+#include "jpeg.h"
+
+#include "mallocvar.h"
+
+/* make it happier.... */
+#undef DCTSIZE2
+
+/* jcopy_sample_rows() is an internal routine in the JPEG library, not 
+   meant for use by us.  We should figure out what the official interface
+   for this is and use it.  The following is copied out of jpegint.h, which
+   is part of the JPEG library source code.
+   */
+extern void jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row,
+                    JSAMPARRAY output_array, int dest_row,
+                    int num_rows, JDIMENSION num_cols));
+
+
+#define HEADER_SIZE 607   /*JFIF header size used on output images*/
+
+
+
+/*=======================================================================*
+ *                                                                       *
+ * JMovie2JPEG                                                           *
+ *                                                                       *
+ *      Splits up a Parallax J_Movie into a set of JFIF image files      *
+ *                                                                       *
+ * RETURNS:     nothing                                                  *
+ *                                                                       *
+ * SIDE EFFECTS:    none                                                 *
+ *                                                                       *
+ *   Contributed By James Boucher(jboucher@flash.bu.edu)                 *
+ *               Boston University Multimedia Communications Lab         *
+ * This code was adapted from the Berkeley Playone.c and Brian Smith's   *
+ * JGetFrame code after being modified on 10-7-93 by Dinesh Venkatesh    *
+ * of BU.                                                                *
+ *       This code converts a version 2 Parallax J_Movie into a          *
+ * set of JFIF compatible JPEG images. It works for all image            *
+ * sizes and qualities.                                                  *
+ ************************************************************************/
+void
+JMovie2JPEG(const char * const infilename,
+                /* input filename string */
+            const char * const obase,
+                /* output filename base string=>obase##.jpg */ 
+            int          const start,
+                /* first frame to be extracted */
+            int          const end
+                /* last frame to be extracted */
+    ) {
+
+    FILE *inFile;         /* Jmovie file pointer */
+    FILE *outFile;        /* JPEG file pointer for output file */
+    int fd, i;            /* input file descriptor and a counting variable*/
+    char ofname[256];     /* output filename string */
+    int Temp = 0, temp = 0;   /* dummy variables */
+    int image_offset = 0;     /* counting variable */
+    /* J_Movie header infomation */
+    int ver_no;           /* version number - expected to be 2 */
+    int fps;              /* frame rate - frames per second */
+    int no_frames;        /* total number of frames in jmovie */
+    int bandwidth;        /* bandwidth required for normal playback*/
+    int qfactor;          /* quality factor used to scale Q matrix */
+    int mapsize;          /* number of color map entries - 2^24 */
+    int audio_tracks;     /* number of audio tracks ==1    */
+    int audiosize;        /*number of bytes in audio tracks */
+    int *inoffsets;       /* input frame offsets from start of jmovie*/
+    int width;            /* image width */
+    int height;           /* image height */
+    int size;             /* total image size in bytes */
+    char op_code;         /* jmovie op_code */
+    char jpeg_size[4];        /* jpeg data size */
+    static char junk[1000];   /* data sink for audio data */
+    int last;             /* Number of last frame we will process */
+
+    /* The next array represents the default JFIF header for
+       quality = 100 and size = 320x240. The values are
+       adjusted as the J_Movie header is read.  The default
+       size of this array is set large so as to make room
+       for the appending of the jpeg bitstream. It can be
+       made smaller if you have a better idea of its expected size
+    */
+    static unsigned char inbuffer[300000] = {    
+        0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46,  
+        0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
+        0x00, 0x01, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x11,  
+        0x08, 0x00, 0xF0, 0x01, 0x40, 0x03, 0x01, 0x21,
+        0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xFF,  
+        0xDB, 0x00, 0x84, 0x00, 0x10, 0x0B, 0x0C, 0x0E,
+        0x0C, 0x0A, 0x10, 0x0E, 0x0D, 0x0E, 0x12,  
+        0x11, 0x10, 0x13, 0x18, 0x28, 0x1A, 0x18, 0x16,
+        0x16, 0x18, 0x31, 0x23, 0x25, 0x1D, 0x28, 0x3A,  
+        0x33, 0x3D, 0x3C, 0x39, 0x33, 0x38, 0x37, 0x40,
+        0x48, 0x5C, 0x4E, 0x40, 0x44, 0x57, 0x45, 0x37,  
+        0x38, 0x50, 0x6D, 0x51, 0x57, 0x5F, 0x62, 0x67,
+        0x68, 0x67, 0x3E, 0x4D, 0x71, 0x79, 0x70, 0x64,  
+        0x78, 0x5C, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12,
+        0x12, 0x18, 0x15, 0x18, 0x2F, 0x1A, 0x1A, 0x2F,  
+        0x63, 0x42, 0x38, 0x42, 0x63, 0x63, 0x63, 0x63,
+        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,  
+        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,  
+        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,  
+        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,  
+        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,  
+        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0xFF, 0xC4,
+        0x01, 0xA2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,  
+        0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,  
+        0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+        0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04,  
+        0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01,
+        0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05,  
+        0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61,
+        0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1,  
+        0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1,
+        0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09,   
+        0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26,
+        0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37,  
+        0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47,
+        0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57,  
+        0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67,
+        0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77,  
+        0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87,
+        0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96,  
+        0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5,
+        0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4,  
+        0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3,
+        0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2,  
+        0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,
+        0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8,  
+        0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6,
+        0xF7, 0xF8, 0xF9, 0xFA, 0x01, 0x00, 0x03, 0x01,  
+        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,  
+        0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 
+        0x0A, 0x0B, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04,  
+        0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00,
+        0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11,  
+        0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
+        0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08,  
+        0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23,
+        0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1,   
+        0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17,
+        0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A,  
+        0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44,
+        0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54,  
+        0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64,
+        0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74,  
+        0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83,
+        0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92,  
+        0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A,
+        0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9,  
+        0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8,
+        0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,  
+        0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+        0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5,  
+        0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4,
+        0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xDA,  
+        0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
+        0x11, 0x00, 0x3F, 0x00  
+
+    };
+    
+    if (start > end) {
+        fprintf(stderr,"bad frame numbers\n");
+        exit(1);
+    }
+    
+    /* open J_Movie */
+    inFile = fopen(infilename, "rb");
+    if (inFile == NULL) {
+        perror (infilename);
+        exit(1);
+    }
+    
+    /* get file descriptor */    
+    fd = fileno(inFile);
+    
+    /* The following lines parse the jpeg_movie header and recover the */
+    /* relavant information */
+
+    fseek(inFile, 8 * sizeof(char), 0);
+    
+    if (fread(&ver_no, sizeof(int), 1, inFile) != 1) {
+        perror("Error in reading version");
+        exit(1);
+    }  
+    if (ver_no != 2) {
+        perror("Unrecognized version - Quantization tables may be wrong\n");
+    }
+    if (fread(&fps, sizeof(int), 1, inFile) != 1) {
+        perror("Error in reading fps");
+        exit(1);
+    }  
+    if (fread (&no_frames, sizeof(int), 1, inFile) != 1) {
+        perror("Error in reading no_frames");
+        exit(1);
+    }  
+
+    MALLOCARRAY(inoffsets, no_frames);
+    
+    if (fread(&width, sizeof(int), 1, inFile) != 1) {
+        perror("Error in reading width");
+        exit(1);
+    }  
+    /* set image width in JFIF header */
+    inbuffer[27] = (char)(0xFF & (width >> 8));
+    inbuffer[28] = (char)(0xFF & width);
+ 
+    if (fread(&height, sizeof(int), 1, inFile) != 1) {
+        perror("Error in reading height");
+        exit(1);
+    }  
+    /* set image height in JFIF header */
+    inbuffer[25] = (char)(0xFF & (height >> 8));
+    inbuffer[26] = (char)(0xFF & height);
+    
+    if (fread(&bandwidth, sizeof(int), 1, inFile) != 1) {
+        perror("Error in reading bandwidth");
+        exit(1);
+    }  
+    
+    if (fread(&qfactor, sizeof(int), 1, inFile) != 1) {
+        perror("Error in reading qfactor");
+        exit(1);
+    }  
+    /* The default quality factor = 100, therefore, if
+       our quality factor does not equal 100 we must
+       scale the quantization matrices in the JFIF header
+    */    
+    /* Note values are clipped to a max of 255 */
+    if (qfactor != 100) {
+        for (Temp = 44; Temp < 108; ++Temp) {
+            temp= (inbuffer[Temp]*qfactor)/100;
+            inbuffer[Temp] = (char)((temp<255) ? temp : 255);
+        }
+        for (Temp = 109; Temp < 173; ++Temp) {
+            temp = (inbuffer[Temp]*qfactor)/100;
+            inbuffer[Temp] = (char)((temp<255) ? temp : 255);
+        }    
+    }
+  
+    if (fread(&mapsize, sizeof(int), 1, inFile) != 1) {
+        perror("Error in reading mapsize");
+        exit(1);
+    }  
+    if (fread (&image_offset, sizeof(int), 1, inFile) != 1) {
+        perror("Error in reading image offset");
+        exit(1);
+    }
+    if (fread (&audio_tracks, sizeof(int), 1, inFile) != 1) {
+        perror("Error in reading audio tracks");
+        exit(1);
+    }
+    
+    fread(junk,sizeof(int),1,inFile);
+    
+    if (fread (&audiosize, sizeof(int), 1, inFile) != 1) {
+        perror("Error in reading audiosize");
+        exit(1);
+    }
+    
+    fseek (inFile, image_offset, 0);
+    
+    last = MIN(end, no_frames-1);
+
+    for (i = 0; i < no_frames; ++i)  {
+        fread(&(inoffsets[i]), sizeof(int), 1, inFile);
+    } /* Reads in the frame sizes into the array */
+    
+    rewind(inFile);
+
+    /* Extract JFIF files from J_Movie */    
+    for (i = start; i <= last; ++i) {
+        size = inoffsets[i] - inoffsets[i-1]- 5;
+        lseek(fd, inoffsets[i-1], 0); 
+        read(fd, &(op_code), 1);
+        while (op_code !=  0xffffffec) {
+            read(fd,junk,audiosize);
+            read(fd, &(op_code), 1);  
+            size = size - audiosize ;
+        } /* To skip the audio bytes in each frame */
+        read(fd, jpeg_size, 4);
+        read(fd, &(inbuffer[607]), size);
+        sprintf(ofname, "%s%d.jpg", obase, i);
+        outFile = fopen(ofname, "wb");
+        fwrite(inbuffer, (size+607), sizeof(char), outFile);
+        fclose(outFile);        
+    }
+    free(inoffsets);
+    fclose(inFile);
+}
+
+
+
+
+/*===========================================================================*
+ *
+ * ReadJPEG  contributed by James Arthur Boucher of Boston University's
+ *                                Multimedia Communications Lab
+ *
+ *      read a JPEG file and copy data into frame original data arrays
+ *
+ * RETURNS:     mf modified
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+/*************************JPEG LIBRARY INTERFACE*********************/
+/*
+ * THE BIG PICTURE:
+ *
+ * The rough outline this JPEG decompression operation is:
+ *
+ *      allocate and initialize JPEG decompression object
+ *      specify data source (eg, a file)
+ *      jpeg_read_header();     // obtain image dimensions and other parameters
+ *      set parameters for decompression
+ *      jpeg_start_decompress();
+ *      while (scan lines remain to be read)
+ *              jpeg_read_scanlines(...);
+ *      jpeg_finish_decompress();
+ *      release JPEG decompression object
+ *
+ */
+void
+ReadJPEG(MpegFrame * const mf,
+         FILE *      const fp) {
+
+    static struct jpeg_decompress_struct cinfo;
+        /* The JPEG decompression parameters and pointers to
+           working data (which is allocated as needed by the JPEG library).
+        */
+    struct jpeg_error_mgr jerr;
+    JSAMPARRAY scanarray[3];
+    int ci,cd,cp;
+    JDIMENSION ncols[3];
+    JDIMENSION nrows[3];
+    jpeg_component_info *compptr;
+    int buffer_height;
+    int current_row[3];
+    uint8 **orig[3];
+    int h_samp[3],v_samp[3];
+    int max_h_samp,max_v_samp;
+    int temp_h, temp_v;
+    int temp;
+
+    /* Allocate and initialize JPEG decompression object */
+    cinfo.err = jpeg_std_error(&jerr);
+
+    /*
+    ** If we're reading from stdin we want to create the cinfo struct
+    ** ONCE (during the first read).  This is because when reading jpeg
+    ** from stdin we will not release the cinfo struct, because doing
+    ** so would totally screw up the read buffer and make it impossible
+    ** to read jpegs from stdin.
+    ** Dave Scott (dhs), UofO, 7/19/95
+    */
+    {
+        static int first_stdin;
+        first_stdin = TRUE;  /* initial value */
+        if ((fp != stdin) || first_stdin) {
+            first_stdin = FALSE;
+            /* Now we can initialize the JPEG decompression object. */
+            jpeg_create_decompress(&cinfo);
+            /* specify data source (eg, a file) */
+            jpeg_stdio_src(&cinfo, fp);
+        }
+    }
+  
+    /* specify data source (eg, a file) */
+  
+    jpeg_stdio_src(&cinfo, fp);
+  
+    /* read file parameters with jpeg_read_header() */
+  
+  
+    (void) jpeg_read_header(&cinfo, TRUE);
+    /* We can ignore the return value from jpeg_read_header since
+     *   (a) suspension is not possible with the stdio data source, and
+     *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
+     */
+  
+    /* set parameters for decompression */
+#ifdef JPEG4
+    cinfo.want_raw_output = TRUE;
+#else
+    cinfo.raw_data_out = TRUE;
+#endif
+    cinfo.out_color_space = JCS_YCbCr;
+  
+    /* calculate image output dimensions */
+    jpeg_calc_output_dimensions(&cinfo);
+    /* the above calculation will set these soon */
+    /* for now we'll set them ourselves */
+    
+    /* tell mpeg_encode the size of the JPEG Image*/
+    Fsize_Note(mf->id,(int)(cinfo.image_width),(int)(cinfo.image_height));
+  
+    /* Allocate memory for the raw YCbCr data to occupy*/
+    Frame_AllocYCC(mf);      /*allocate space for mpeg frame*/
+  
+    /* copy pointers to array structure- this make the following
+       code more compact
+    */
+    orig[0] = mf->orig_y;
+    orig[1] = mf->orig_cb;
+    orig[2] = mf->orig_cr;
+  
+    /* Note that we can use the info obtained from jpeg_read_header.
+     */
+  
+    /* Start decompressor */
+  
+    jpeg_start_decompress(&cinfo);
+  
+  
+    /* JSAMPLEs per row in output buffer  */
+    /* collect component subsample values*/
+    for (cp=0, compptr = cinfo.comp_info;
+         cp < cinfo.num_components;
+         cp++, compptr++) {
+        h_samp[cp] = compptr->h_samp_factor;
+        v_samp[cp] = compptr->v_samp_factor;
+    }
+    /* calculate max subsample values*/
+    temp_h = (h_samp[0]<h_samp[1]) ? h_samp[1] : h_samp[0];
+    max_h_samp = (temp_h<h_samp[2]) ? h_samp[2]:temp_h;
+    temp_v = (v_samp[0]<v_samp[1]) ? v_samp[1] : v_samp[0];
+    max_v_samp = (temp_v<v_samp[2]) ? v_samp[2]:temp_v;
+  
+    /* Make an 8-row-high sample array that will go away when done
+       with image
+    */
+#ifdef JPEG4
+    buffer_height = 8;  /* could be 2, 4,8 rows high */
+#else
+    buffer_height = cinfo.max_v_samp_factor * cinfo.min_DCT_scaled_size;
+#endif
+  
+    for(cp=0,compptr = cinfo.comp_info;cp<cinfo.num_components;
+        cp++,compptr++) {
+        ncols[cp] = (JDIMENSION)((cinfo.image_width*compptr->h_samp_factor)/
+                                 max_h_samp);
+    
+        nrows[cp] = (JDIMENSION)((buffer_height*compptr->v_samp_factor)/
+                                 max_v_samp);
+    
+        scanarray[cp] = (*cinfo.mem->alloc_sarray)
+            ((j_common_ptr) &cinfo, JPOOL_IMAGE, ncols[cp], nrows[cp]);
+    }
+  
+    /*  while (scan lines remain to be read)
+           jpeg_read_scanlines(...);
+    */
+  
+    /* Here we use the library's state variable cinfo.output_scanline as the
+     * loop counter, so that we don't have to keep track ourselves.
+     */
+
+    while (cinfo.output_scanline < cinfo.output_height) {
+
+#ifdef JPEG4
+        (void) jpeg_read_raw_scanlines(&cinfo, scanarray, buffer_height);
+#else
+        (void) jpeg_read_raw_data(&cinfo, scanarray, buffer_height);
+#endif
+
+        /* alter subsample ratio's if neccessary */
+        if ((h_samp[0]==2) && (h_samp[1]==1) && (h_samp[2]==1) &&
+            (v_samp[0]==2) && (v_samp[1]==1) && (v_samp[2]==1)) {
+            /* we are 4:1:1 as expected by the encoder*/
+        } else if((h_samp[0] == 2) && (h_samp[1] == 1) && (h_samp[2]==1) &&
+                  (v_samp[0] == 1) && (v_samp[1] == 1) && (v_samp[2]==1)) {
+            /* must subsample 2:1 vertically and adjust params*/
+            for (ci = 1; ci < 3; ++ci) {
+                for (cp = 0; cp < (buffer_height/2); cp = cp+1) {
+                    for (cd = 0; cd < ncols[ci]; ++cd) {
+                        temp = ((scanarray[ci][cp*2][cd] +
+                                 scanarray[ci][(cp*2)+1][cd]) / 2);
+                        scanarray[ci][cp][cd] = (JSAMPLE)(temp);
+                    }
+                }
+            }
+            /* only reset values the first time through*/
+            if (cinfo.output_scanline == buffer_height) {
+                nrows[1] = nrows[1]/2;
+                nrows[2] = nrows[2]/2;
+                max_v_samp = 2;
+                v_samp[0] = 2;
+            }
+        } else
+            pm_error("Invalid subsampling ratio");
+    
+        /* transfer data from jpeg buffer to MPEG frame */
+        /* calculate the row we wish to output into */
+        for (ci = 0, compptr = cinfo.comp_info;
+             ci < cinfo.num_components;
+             ++ci, ++compptr) {
+            current_row[ci] =((cinfo.output_scanline - buffer_height)*
+                              (v_samp[ci])/max_v_samp);  
+      
+            jcopy_sample_rows(scanarray[ci],0,(JSAMPARRAY)(orig[ci]),
+                              current_row[ci],nrows[ci],ncols[ci]);
+        }
+    }  
+  
+    /* Step 7: Finish decompression */
+  
+    (void) jpeg_finish_decompress(&cinfo);
+    /* We can ignore the return value since suspension is not possible
+     * with the stdio data source.
+     */
+  
+    /* Step 8: Release JPEG decompression object */
+  
+    /*
+    ** DO NOT release the cinfo struct if we are reading from stdin, this
+    ** is because the cinfo struct contains the read buffer, and the read
+    ** buffer may (and almost always does) contain the end of one image and
+    ** the beginning of another.  If we throw away the read buffer then
+    ** we loose the beginning of the next image, and we're screwed.
+    ** Dave Scott (dhs), UofO, 7/19/95
+    */
+    if (fp == stdin) {
+        static int no_from_stdin = 0;
+        ++no_from_stdin;
+    } else {
+        /* This is an important step since it will release a good deal
+           of memory.
+        */
+        jpeg_destroy_decompress(&cinfo);
+    }
+
+    /* After finish_decompress, we can close the input file.  Here we
+       postpone it until after no more JPEG errors are possible, so as
+       to simplify the setjmp error logic above.  (Actually, I don't
+       think that jpeg_destroy can do an error exit, but why assume
+       anything...)
+    */
+  
+    /* At this point you may want to check to see whether any corrupt-data
+     * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
+     * If you prefer to treat corrupt data as a fatal error, override the
+     * error handler's emit_message method to call error_exit on a warning.
+     */
+}
+
+
+
+/*
+ * SOME FINE POINTS:
+ *
+ * In the above loop, we ignored the return value of jpeg_read_scanlines,
+ * which is the number of scanlines actually read.  We could get away with
+ * this for the same reasons discussed in the compression example.  Actually
+ * there is one perfectly normal situation in which jpeg_read_scanlines may
+ * return fewer lines than you asked for: at the bottom of the image.  But the
+ * loop above can't ask for more lines than there are in the image since it
+ * reads only one line at a time.
+ *
+ * In some high-speed operating modes, some data copying can be saved by
+ * making the buffer passed to jpeg_read_scanlines be cinfo.rec_outbuf_height
+ * lines high (or a multiple thereof).  This will usually be 1, 2, or 4 lines.
+ *
+ * To decompress multiple images, you can repeat the whole sequence, or you
+ * can keep the JPEG object around and just repeat steps 2-7.  This will
+ * save a little bit of startup/shutdown time.
+ *
+ * As with compression, some operating modes may require temporary files.
+ * On some systems you may need to set up a signal handler to ensure that
+ * temporary files are deleted if the program is interrupted.
+ *
+ * Scanlines are returned in the same order as they appear in the JPEG file,
+ * which is standardly top-to-bottom.  If you must have data supplied
+ * bottom-to-top, you can use one of the virtual arrays provided by the
+ * JPEG memory manager to invert the data.  See wrrle.c for an example.
+ */
+
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
diff --git a/converter/ppm/ppmtompeg/jrevdct.c b/converter/ppm/ppmtompeg/jrevdct.c
new file mode 100644
index 00000000..2e99a67a
--- /dev/null
+++ b/converter/ppm/ppmtompeg/jrevdct.c
@@ -0,0 +1,1278 @@
+/*
+ * jrevdct.c
+ *
+ * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the basic inverse-DCT transformation subroutine.
+ *
+ * This implementation is based on an algorithm described in
+ *   C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT
+ *   Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics,
+ *   Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.
+ * The primary algorithm described there uses 11 multiplies and 29 adds.
+ * We use their alternate method with 12 multiplies and 32 adds.
+ * The advantage of this method is that no data path contains more than one
+ * multiplication; this allows a very simple and accurate implementation in
+ * scaled fixed-point arithmetic, with a minimal number of shifts.
+ * 
+ * I've made lots of modifications to attempt to take advantage of the
+ * sparse nature of the DCT matrices we're getting.  Although the logic
+ * is cumbersome, it's straightforward and the resulting code is much
+ * faster.
+ *
+ * A better way to do this would be to pass in the DCT block as a sparse
+ * matrix, perhaps with the difference cases encoded.
+ */
+
+#include <memory.h>
+#include "all.h"
+#include "ansi.h"
+#include "dct.h"
+
+
+#define CONST_BITS 13
+
+/*
+ * This routine is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+  Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/*
+ * A 2-D IDCT can be done by 1-D IDCT on each row followed by 1-D IDCT
+ * on each column.  Direct algorithms are also available, but they are
+ * much more complex and seem not to be any faster when reduced to code.
+ *
+ * The poop on this scaling stuff is as follows:
+ *
+ * Each 1-D IDCT step produces outputs which are a factor of sqrt(N)
+ * larger than the true IDCT outputs.  The final outputs are therefore
+ * a factor of N larger than desired; since N=8 this can be cured by
+ * a simple right shift at the end of the algorithm.  The advantage of
+ * this arrangement is that we save two multiplications per 1-D IDCT,
+ * because the y0 and y4 inputs need not be divided by sqrt(N).
+ *
+ * We have to do addition and subtraction of the integer inputs, which
+ * is no problem, and multiplication by fractional constants, which is
+ * a problem to do in integer arithmetic.  We multiply all the constants
+ * by CONST_SCALE and convert them to integer constants (thus retaining
+ * CONST_BITS bits of precision in the constants).  After doing a
+ * multiplication we have to divide the product by CONST_SCALE, with proper
+ * rounding, to produce the correct output.  This division can be done
+ * cheaply as a right shift of CONST_BITS bits.  We postpone shifting
+ * as long as possible so that partial sums can be added together with
+ * full fractional precision.
+ *
+ * The outputs of the first pass are scaled up by PASS1_BITS bits so that
+ * they are represented to better-than-integral precision.  These outputs
+ * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word
+ * with the recommended scaling.  (To scale up 12-bit sample data further, an
+ * intermediate int32 array would be needed.)
+ *
+ * To avoid overflow of the 32-bit intermediate results in pass 2, we must
+ * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26.  Error analysis
+ * shows that the values given below are the most effective.
+ */
+
+#ifdef EIGHT_BIT_SAMPLES
+#define PASS1_BITS  2
+#else
+#define PASS1_BITS  1		/* lose a little precision to avoid overflow */
+#endif
+
+#define ONE	((int32) 1)
+
+#define CONST_SCALE (ONE << CONST_BITS)
+
+/* Convert a positive real constant to an integer scaled by CONST_SCALE.
+ * IMPORTANT: if your compiler doesn't do this arithmetic at compile time,
+ * you will pay a significant penalty in run time.  In that case, figure
+ * the correct integer constant values and insert them by hand.
+ */
+
+/* Actually FIX is no longer used, we precomputed them all */
+#define FIX(x)	((int32) ((x) * CONST_SCALE + 0.5)) 
+
+/* Descale and correctly round an int32 value that's scaled by N bits.
+ * We assume RIGHT_SHIFT rounds towards minus infinity, so adding
+ * the fudge factor is correct for either sign of X.
+ */
+
+#define DESCALE(x,n)  RIGHT_SHIFT((x) + (ONE << ((n)-1)), n)
+
+/* Multiply an int32 variable by an int32 constant to yield an int32 result.
+ * For 8-bit samples with the recommended scaling, all the variable
+ * and constant values involved are no more than 16 bits wide, so a
+ * 16x16->32 bit multiply can be used instead of a full 32x32 multiply;
+ * this provides a useful speedup on many machines.
+ * There is no way to specify a 16x16->32 multiply in portable C, but
+ * some C compilers will do the right thing if you provide the correct
+ * combination of casts.
+ * NB: for 12-bit samples, a full 32-bit multiplication will be needed.
+ */
+
+#ifdef EIGHT_BIT_SAMPLES
+#ifdef SHORTxSHORT_32		/* may work if 'int' is 32 bits */
+#define MULTIPLY(var,const)  (((INT16) (var)) * ((INT16) (const)))
+#endif
+#ifdef SHORTxLCONST_32		/* known to work with Microsoft C 6.0 */
+#define MULTIPLY(var,const)  (((INT16) (var)) * ((int32) (const)))
+#endif
+#endif
+
+#ifndef MULTIPLY		/* default definition */
+#define MULTIPLY(var,const)  ((var) * (const))
+#endif
+
+
+/* 
+  Unlike our decoder where we approximate the FIXes, we need to use exact
+ones here or successive P-frames will drift too much with Reference frame coding 
+*/
+#define FIX_0_211164243 1730
+#define FIX_0_275899380 2260
+#define FIX_0_298631336 2446
+#define FIX_0_390180644 3196
+#define FIX_0_509795579 4176
+#define FIX_0_541196100 4433
+#define FIX_0_601344887 4926
+#define FIX_0_765366865 6270
+#define FIX_0_785694958 6436
+#define FIX_0_899976223 7373
+#define FIX_1_061594337 8697
+#define FIX_1_111140466 9102
+#define FIX_1_175875602 9633
+#define FIX_1_306562965 10703
+#define FIX_1_387039845 11363
+#define FIX_1_451774981 11893
+#define FIX_1_501321110 12299
+#define FIX_1_662939225 13623
+#define FIX_1_847759065 15137
+#define FIX_1_961570560 16069
+#define FIX_2_053119869 16819
+#define FIX_2_172734803 17799
+#define FIX_2_562915447 20995
+#define FIX_3_072711026 25172
+
+/*
+  Switch on reverse_dct choices
+*/
+void reference_rev_dct _ANSI_ARGS_((int16 *block));
+void mpeg_jrevdct_quick _ANSI_ARGS_((int16 *block));
+void init_idctref _ANSI_ARGS_((void));
+
+extern boolean pureDCT;
+
+void
+mpeg_jrevdct(data)
+    DCTBLOCK data;
+{
+  if (pureDCT) reference_rev_dct(data);
+  else mpeg_jrevdct_quick(data);
+}
+
+/*
+ * Perform the inverse DCT on one block of coefficients.
+ */
+
+void
+mpeg_jrevdct_quick(data)
+    DCTBLOCK data;
+{
+  int32 tmp0, tmp1, tmp2, tmp3;
+  int32 tmp10, tmp11, tmp12, tmp13;
+  int32 z1, z2, z3, z4, z5;
+  int32 d0, d1, d2, d3, d4, d5, d6, d7;
+  register DCTELEM *dataptr;
+  int rowctr;
+  SHIFT_TEMPS
+   
+  /* Pass 1: process rows. */
+  /* Note results are scaled up by sqrt(8) compared to a true IDCT; */
+  /* furthermore, we scale the results by 2**PASS1_BITS. */
+
+  dataptr = data;
+
+  for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) {
+    /* Due to quantization, we will usually find that many of the input
+     * coefficients are zero, especially the AC terms.  We can exploit this
+     * by short-circuiting the IDCT calculation for any row in which all
+     * the AC terms are zero.  In that case each output is equal to the
+     * DC coefficient (with scale factor as needed).
+     * With typical images and quantization tables, half or more of the
+     * row DCT calculations can be simplified this way.
+     */
+
+    register int *idataptr = (int*)dataptr;
+    d0 = dataptr[0];
+    d1 = dataptr[1];
+    if ((d1 == 0) && (idataptr[1] | idataptr[2] | idataptr[3]) == 0) {
+      /* AC terms all zero */
+      if (d0) {
+	  /* Compute a 32 bit value to assign. */
+	  DCTELEM dcval = (DCTELEM) (d0 << PASS1_BITS);
+	  register int v = (dcval & 0xffff) | ((dcval << 16) & 0xffff0000);
+	  
+	  idataptr[0] = v;
+	  idataptr[1] = v;
+	  idataptr[2] = v;
+	  idataptr[3] = v;
+      }
+      
+      dataptr += DCTSIZE;	/* advance pointer to next row */
+      continue;
+    }
+    d2 = dataptr[2];
+    d3 = dataptr[3];
+    d4 = dataptr[4];
+    d5 = dataptr[5];
+    d6 = dataptr[6];
+    d7 = dataptr[7];
+
+    /* Even part: reverse the even part of the forward DCT. */
+    /* The rotator is sqrt(2)*c(-6). */
+{
+    if (d6) {
+	if (d4) {
+	    if (d2) {
+		if (d0) {
+		    /* d0 != 0, d2 != 0, d4 != 0, d6 != 0 */
+		    z1 = MULTIPLY(d2 + d6, FIX_0_541196100);
+		    tmp2 = z1 + MULTIPLY(-d6, FIX_1_847759065);
+		    tmp3 = z1 + MULTIPLY(d2, FIX_0_765366865);
+
+		    tmp0 = (d0 + d4) << CONST_BITS;
+		    tmp1 = (d0 - d4) << CONST_BITS;
+
+		    tmp10 = tmp0 + tmp3;
+		    tmp13 = tmp0 - tmp3;
+		    tmp11 = tmp1 + tmp2;
+		    tmp12 = tmp1 - tmp2;
+		} else {
+		    /* d0 == 0, d2 != 0, d4 != 0, d6 != 0 */
+		    z1 = MULTIPLY(d2 + d6, FIX_0_541196100);
+		    tmp2 = z1 + MULTIPLY(-d6, FIX_1_847759065);
+		    tmp3 = z1 + MULTIPLY(d2, FIX_0_765366865);
+
+		    tmp0 = d4 << CONST_BITS;
+
+		    tmp10 = tmp0 + tmp3;
+		    tmp13 = tmp0 - tmp3;
+		    tmp11 = tmp2 - tmp0;
+		    tmp12 = -(tmp0 + tmp2);
+		}
+	    } else {
+		if (d0) {
+		    /* d0 != 0, d2 == 0, d4 != 0, d6 != 0 */
+		    tmp2 = MULTIPLY(-d6, FIX_1_306562965);
+		    tmp3 = MULTIPLY(d6, FIX_0_541196100);
+
+		    tmp0 = (d0 + d4) << CONST_BITS;
+		    tmp1 = (d0 - d4) << CONST_BITS;
+
+		    tmp10 = tmp0 + tmp3;
+		    tmp13 = tmp0 - tmp3;
+		    tmp11 = tmp1 + tmp2;
+		    tmp12 = tmp1 - tmp2;
+		} else {
+		    /* d0 == 0, d2 == 0, d4 != 0, d6 != 0 */
+		    tmp2 = MULTIPLY(-d6, FIX_1_306562965);
+		    tmp3 = MULTIPLY(d6, FIX_0_541196100);
+
+		    tmp0 = d4 << CONST_BITS;
+
+		    tmp10 = tmp0 + tmp3;
+		    tmp13 = tmp0 - tmp3;
+		    tmp11 = tmp2 - tmp0;
+		    tmp12 = -(tmp0 + tmp2);
+		}
+	    }
+	} else {
+	    if (d2) {
+		if (d0) {
+		    /* d0 != 0, d2 != 0, d4 == 0, d6 != 0 */
+		    z1 = MULTIPLY(d2 + d6, FIX_0_541196100);
+		    tmp2 = z1 + MULTIPLY(-d6, FIX_1_847759065);
+		    tmp3 = z1 + MULTIPLY(d2, FIX_0_765366865);
+
+		    tmp0 = d0 << CONST_BITS;
+
+		    tmp10 = tmp0 + tmp3;
+		    tmp13 = tmp0 - tmp3;
+		    tmp11 = tmp0 + tmp2;
+		    tmp12 = tmp0 - tmp2;
+		} else {
+		    /* d0 == 0, d2 != 0, d4 == 0, d6 != 0 */
+		    z1 = MULTIPLY(d2 + d6, FIX_0_541196100);
+		    tmp2 = z1 + MULTIPLY(-d6, FIX_1_847759065);
+		    tmp3 = z1 + MULTIPLY(d2, FIX_0_765366865);
+
+		    tmp10 = tmp3;
+		    tmp13 = -tmp3;
+		    tmp11 = tmp2;
+		    tmp12 = -tmp2;
+		}
+	    } else {
+		if (d0) {
+		    /* d0 != 0, d2 == 0, d4 == 0, d6 != 0 */
+		    tmp2 = MULTIPLY(-d6, FIX_1_306562965);
+		    tmp3 = MULTIPLY(d6, FIX_0_541196100);
+
+		    tmp0 = d0 << CONST_BITS;
+
+		    tmp10 = tmp0 + tmp3;
+		    tmp13 = tmp0 - tmp3;
+		    tmp11 = tmp0 + tmp2;
+		    tmp12 = tmp0 - tmp2;
+		} else {
+		    /* d0 == 0, d2 == 0, d4 == 0, d6 != 0 */
+		    tmp2 = MULTIPLY(-d6, FIX_1_306562965);
+		    tmp3 = MULTIPLY(d6, FIX_0_541196100);
+
+		    tmp10 = tmp3;
+		    tmp13 = -tmp3;
+		    tmp11 = tmp2;
+		    tmp12 = -tmp2;
+		}
+	    }
+	}
+    } else {
+	if (d4) {
+	    if (d2) {
+		if (d0) {
+		    /* d0 != 0, d2 != 0, d4 != 0, d6 == 0 */
+		    tmp2 = MULTIPLY(d2, FIX_0_541196100);
+		    tmp3 = MULTIPLY(d2, FIX_1_306562965);
+
+		    tmp0 = (d0 + d4) << CONST_BITS;
+		    tmp1 = (d0 - d4) << CONST_BITS;
+
+		    tmp10 = tmp0 + tmp3;
+		    tmp13 = tmp0 - tmp3;
+		    tmp11 = tmp1 + tmp2;
+		    tmp12 = tmp1 - tmp2;
+		} else {
+		    /* d0 == 0, d2 != 0, d4 != 0, d6 == 0 */
+		    tmp2 = MULTIPLY(d2, FIX_0_541196100);
+		    tmp3 = MULTIPLY(d2, FIX_1_306562965);
+
+		    tmp0 = d4 << CONST_BITS;
+
+		    tmp10 = tmp0 + tmp3;
+		    tmp13 = tmp0 - tmp3;
+		    tmp11 = tmp2 - tmp0;
+		    tmp12 = -(tmp0 + tmp2);
+		}
+	    } else {
+		if (d0) {
+		    /* d0 != 0, d2 == 0, d4 != 0, d6 == 0 */
+		    tmp10 = tmp13 = (d0 + d4) << CONST_BITS;
+		    tmp11 = tmp12 = (d0 - d4) << CONST_BITS;
+		} else {
+		    /* d0 == 0, d2 == 0, d4 != 0, d6 == 0 */
+		    tmp10 = tmp13 = d4 << CONST_BITS;
+		    tmp11 = tmp12 = -tmp10;
+		}
+	    }
+	} else {
+	    if (d2) {
+		if (d0) {
+		    /* d0 != 0, d2 != 0, d4 == 0, d6 == 0 */
+		    tmp2 = MULTIPLY(d2, FIX_0_541196100);
+		    tmp3 = MULTIPLY(d2, FIX_1_306562965);
+
+		    tmp0 = d0 << CONST_BITS;
+
+		    tmp10 = tmp0 + tmp3;
+		    tmp13 = tmp0 - tmp3;
+		    tmp11 = tmp0 + tmp2;
+		    tmp12 = tmp0 - tmp2;
+		} else {
+		    /* d0 == 0, d2 != 0, d4 == 0, d6 == 0 */
+		    tmp2 = MULTIPLY(d2, FIX_0_541196100);
+		    tmp3 = MULTIPLY(d2, FIX_1_306562965);
+
+		    tmp10 = tmp3;
+		    tmp13 = -tmp3;
+		    tmp11 = tmp2;
+		    tmp12 = -tmp2;
+		}
+	    } else {
+		if (d0) {
+		    /* d0 != 0, d2 == 0, d4 == 0, d6 == 0 */
+		    tmp10 = tmp13 = tmp11 = tmp12 = d0 << CONST_BITS;
+		} else {
+		    /* d0 == 0, d2 == 0, d4 == 0, d6 == 0 */
+		    tmp10 = tmp13 = tmp11 = tmp12 = 0;
+		}
+	    }
+	}
+      }
+
+    /* Odd part per figure 8; the matrix is unitary and hence its
+     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.
+     */
+
+    if (d7) {
+	if (d5) {
+	    if (d3) {
+		if (d1) {
+		    /* d1 != 0, d3 != 0, d5 != 0, d7 != 0 */
+		    z1 = d7 + d1;
+		    z2 = d5 + d3;
+		    z3 = d7 + d3;
+		    z4 = d5 + d1;
+		    z5 = MULTIPLY(z3 + z4, FIX_1_175875602);
+		    
+		    tmp0 = MULTIPLY(d7, FIX_0_298631336); 
+		    tmp1 = MULTIPLY(d5, FIX_2_053119869);
+		    tmp2 = MULTIPLY(d3, FIX_3_072711026);
+		    tmp3 = MULTIPLY(d1, FIX_1_501321110);
+		    z1 = MULTIPLY(-z1, FIX_0_899976223);
+		    z2 = MULTIPLY(-z2, FIX_2_562915447);
+		    z3 = MULTIPLY(-z3, FIX_1_961570560);
+		    z4 = MULTIPLY(-z4, FIX_0_390180644);
+		    
+		    z3 += z5;
+		    z4 += z5;
+		    
+		    tmp0 += z1 + z3;
+		    tmp1 += z2 + z4;
+		    tmp2 += z2 + z3;
+		    tmp3 += z1 + z4;
+		} else {
+		    /* d1 == 0, d3 != 0, d5 != 0, d7 != 0 */
+		    z2 = d5 + d3;
+		    z3 = d7 + d3;
+		    z5 = MULTIPLY(z3 + d5, FIX_1_175875602);
+		    
+		    tmp0 = MULTIPLY(d7, FIX_0_298631336); 
+		    tmp1 = MULTIPLY(d5, FIX_2_053119869);
+		    tmp2 = MULTIPLY(d3, FIX_3_072711026);
+		    z1 = MULTIPLY(-d7, FIX_0_899976223);
+		    z2 = MULTIPLY(-z2, FIX_2_562915447);
+		    z3 = MULTIPLY(-z3, FIX_1_961570560);
+		    z4 = MULTIPLY(-d5, FIX_0_390180644);
+		    
+		    z3 += z5;
+		    z4 += z5;
+		    
+		    tmp0 += z1 + z3;
+		    tmp1 += z2 + z4;
+		    tmp2 += z2 + z3;
+		    tmp3 = z1 + z4;
+		}
+	    } else {
+		if (d1) {
+		    /* d1 != 0, d3 == 0, d5 != 0, d7 != 0 */
+		    z1 = d7 + d1;
+		    z4 = d5 + d1;
+		    z5 = MULTIPLY(d7 + z4, FIX_1_175875602);
+		    
+		    tmp0 = MULTIPLY(d7, FIX_0_298631336); 
+		    tmp1 = MULTIPLY(d5, FIX_2_053119869);
+		    tmp3 = MULTIPLY(d1, FIX_1_501321110);
+		    z1 = MULTIPLY(-z1, FIX_0_899976223);
+		    z2 = MULTIPLY(-d5, FIX_2_562915447);
+		    z3 = MULTIPLY(-d7, FIX_1_961570560);
+		    z4 = MULTIPLY(-z4, FIX_0_390180644);
+		    
+		    z3 += z5;
+		    z4 += z5;
+		    
+		    tmp0 += z1 + z3;
+		    tmp1 += z2 + z4;
+		    tmp2 = z2 + z3;
+		    tmp3 += z1 + z4;
+		} else {
+		    /* d1 == 0, d3 == 0, d5 != 0, d7 != 0 */
+		    tmp0 = MULTIPLY(-d7, FIX_0_601344887); 
+		    z1 = MULTIPLY(-d7, FIX_0_899976223);
+		    z3 = MULTIPLY(-d7, FIX_1_961570560);
+		    tmp1 = MULTIPLY(-d5, FIX_0_509795579);
+		    z2 = MULTIPLY(-d5, FIX_2_562915447);
+		    z4 = MULTIPLY(-d5, FIX_0_390180644);
+		    z5 = MULTIPLY(d5 + d7, FIX_1_175875602);
+		    
+		    z3 += z5;
+		    z4 += z5;
+		    
+		    tmp0 += z3;
+		    tmp1 += z4;
+		    tmp2 = z2 + z3;
+		    tmp3 = z1 + z4;
+		}
+	    }
+	} else {
+	    if (d3) {
+		if (d1) {
+		    /* d1 != 0, d3 != 0, d5 == 0, d7 != 0 */
+		    z1 = d7 + d1;
+		    z3 = d7 + d3;
+		    z5 = MULTIPLY(z3 + d1, FIX_1_175875602);
+		    
+		    tmp0 = MULTIPLY(d7, FIX_0_298631336); 
+		    tmp2 = MULTIPLY(d3, FIX_3_072711026);
+		    tmp3 = MULTIPLY(d1, FIX_1_501321110);
+		    z1 = MULTIPLY(-z1, FIX_0_899976223);
+		    z2 = MULTIPLY(-d3, FIX_2_562915447);
+		    z3 = MULTIPLY(-z3, FIX_1_961570560);
+		    z4 = MULTIPLY(-d1, FIX_0_390180644);
+		    
+		    z3 += z5;
+		    z4 += z5;
+		    
+		    tmp0 += z1 + z3;
+		    tmp1 = z2 + z4;
+		    tmp2 += z2 + z3;
+		    tmp3 += z1 + z4;
+		} else {
+		    /* d1 == 0, d3 != 0, d5 == 0, d7 != 0 */
+		    z3 = d7 + d3;
+		    
+		    tmp0 = MULTIPLY(-d7, FIX_0_601344887); 
+		    z1 = MULTIPLY(-d7, FIX_0_899976223);
+		    tmp2 = MULTIPLY(d3, FIX_0_509795579);
+		    z2 = MULTIPLY(-d3, FIX_2_562915447);
+		    z5 = MULTIPLY(z3, FIX_1_175875602);
+		    z3 = MULTIPLY(-z3, FIX_0_785694958);
+		    
+		    tmp0 += z3;
+		    tmp1 = z2 + z5;
+		    tmp2 += z3;
+		    tmp3 = z1 + z5;
+		}
+	    } else {
+		if (d1) {
+		    /* d1 != 0, d3 == 0, d5 == 0, d7 != 0 */
+		    z1 = d7 + d1;
+		    z5 = MULTIPLY(z1, FIX_1_175875602);
+
+		    z1 = MULTIPLY(z1, FIX_0_275899380);
+		    z3 = MULTIPLY(-d7, FIX_1_961570560);
+		    tmp0 = MULTIPLY(-d7, FIX_1_662939225); 
+		    z4 = MULTIPLY(-d1, FIX_0_390180644);
+		    tmp3 = MULTIPLY(d1, FIX_1_111140466);
+
+		    tmp0 += z1;
+		    tmp1 = z4 + z5;
+		    tmp2 = z3 + z5;
+		    tmp3 += z1;
+		} else {
+		    /* d1 == 0, d3 == 0, d5 == 0, d7 != 0 */
+		    tmp0 = MULTIPLY(-d7, FIX_1_387039845);
+		    tmp1 = MULTIPLY(d7, FIX_1_175875602);
+		    tmp2 = MULTIPLY(-d7, FIX_0_785694958);
+		    tmp3 = MULTIPLY(d7, FIX_0_275899380);
+		}
+	    }
+	}
+    } else {
+	if (d5) {
+	    if (d3) {
+		if (d1) {
+		    /* d1 != 0, d3 != 0, d5 != 0, d7 == 0 */
+		    z2 = d5 + d3;
+		    z4 = d5 + d1;
+		    z5 = MULTIPLY(d3 + z4, FIX_1_175875602);
+		    
+		    tmp1 = MULTIPLY(d5, FIX_2_053119869);
+		    tmp2 = MULTIPLY(d3, FIX_3_072711026);
+		    tmp3 = MULTIPLY(d1, FIX_1_501321110);
+		    z1 = MULTIPLY(-d1, FIX_0_899976223);
+		    z2 = MULTIPLY(-z2, FIX_2_562915447);
+		    z3 = MULTIPLY(-d3, FIX_1_961570560);
+		    z4 = MULTIPLY(-z4, FIX_0_390180644);
+		    
+		    z3 += z5;
+		    z4 += z5;
+		    
+		    tmp0 = z1 + z3;
+		    tmp1 += z2 + z4;
+		    tmp2 += z2 + z3;
+		    tmp3 += z1 + z4;
+		} else {
+		    /* d1 == 0, d3 != 0, d5 != 0, d7 == 0 */
+		    z2 = d5 + d3;
+		    
+		    z5 = MULTIPLY(z2, FIX_1_175875602);
+		    tmp1 = MULTIPLY(d5, FIX_1_662939225);
+		    z4 = MULTIPLY(-d5, FIX_0_390180644);
+		    z2 = MULTIPLY(-z2, FIX_1_387039845);
+		    tmp2 = MULTIPLY(d3, FIX_1_111140466);
+		    z3 = MULTIPLY(-d3, FIX_1_961570560);
+		    
+		    tmp0 = z3 + z5;
+		    tmp1 += z2;
+		    tmp2 += z2;
+		    tmp3 = z4 + z5;
+		}
+	    } else {
+		if (d1) {
+		    /* d1 != 0, d3 == 0, d5 != 0, d7 == 0 */
+		    z4 = d5 + d1;
+		    
+		    z5 = MULTIPLY(z4, FIX_1_175875602);
+		    z1 = MULTIPLY(-d1, FIX_0_899976223);
+		    tmp3 = MULTIPLY(d1, FIX_0_601344887);
+		    tmp1 = MULTIPLY(-d5, FIX_0_509795579);
+		    z2 = MULTIPLY(-d5, FIX_2_562915447);
+		    z4 = MULTIPLY(z4, FIX_0_785694958);
+		    
+		    tmp0 = z1 + z5;
+		    tmp1 += z4;
+		    tmp2 = z2 + z5;
+		    tmp3 += z4;
+		} else {
+		    /* d1 == 0, d3 == 0, d5 != 0, d7 == 0 */
+		    tmp0 = MULTIPLY(d5, FIX_1_175875602);
+		    tmp1 = MULTIPLY(d5, FIX_0_275899380);
+		    tmp2 = MULTIPLY(-d5, FIX_1_387039845);
+		    tmp3 = MULTIPLY(d5, FIX_0_785694958);
+		}
+	    }
+	} else {
+	    if (d3) {
+		if (d1) {
+		    /* d1 != 0, d3 != 0, d5 == 0, d7 == 0 */
+		    z5 = d1 + d3;
+		    tmp3 = MULTIPLY(d1, FIX_0_211164243);
+		    tmp2 = MULTIPLY(-d3, FIX_1_451774981);
+		    z1 = MULTIPLY(d1, FIX_1_061594337);
+		    z2 = MULTIPLY(-d3, FIX_2_172734803);
+		    z4 = MULTIPLY(z5, FIX_0_785694958);
+		    z5 = MULTIPLY(z5, FIX_1_175875602);
+		    
+		    tmp0 = z1 - z4;
+		    tmp1 = z2 + z4;
+		    tmp2 += z5;
+		    tmp3 += z5;
+		} else {
+		    /* d1 == 0, d3 != 0, d5 == 0, d7 == 0 */
+		    tmp0 = MULTIPLY(-d3, FIX_0_785694958);
+		    tmp1 = MULTIPLY(-d3, FIX_1_387039845);
+		    tmp2 = MULTIPLY(-d3, FIX_0_275899380);
+		    tmp3 = MULTIPLY(d3, FIX_1_175875602);
+		}
+	    } else {
+		if (d1) {
+		    /* d1 != 0, d3 == 0, d5 == 0, d7 == 0 */
+		    tmp0 = MULTIPLY(d1, FIX_0_275899380);
+		    tmp1 = MULTIPLY(d1, FIX_0_785694958);
+		    tmp2 = MULTIPLY(d1, FIX_1_175875602);
+		    tmp3 = MULTIPLY(d1, FIX_1_387039845);
+		} else {
+		    /* d1 == 0, d3 == 0, d5 == 0, d7 == 0 */
+		    tmp0 = tmp1 = tmp2 = tmp3 = 0;
+		}
+	    }
+	}
+    }
+}
+    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+    dataptr[0] = (DCTELEM) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS);
+    dataptr[7] = (DCTELEM) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS);
+    dataptr[1] = (DCTELEM) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS);
+    dataptr[6] = (DCTELEM) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS);
+    dataptr[2] = (DCTELEM) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS);
+    dataptr[5] = (DCTELEM) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS);
+    dataptr[3] = (DCTELEM) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS);
+    dataptr[4] = (DCTELEM) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS);
+
+    dataptr += DCTSIZE;		/* advance pointer to next row */
+  }
+
+  /* Pass 2: process columns. */
+  /* Note that we must descale the results by a factor of 8 == 2**3, */
+  /* and also undo the PASS1_BITS scaling. */
+
+  dataptr = data;
+  for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) {
+    /* Columns of zeroes can be exploited in the same way as we did with rows.
+     * However, the row calculation has created many nonzero AC terms, so the
+     * simplification applies less often (typically 5% to 10% of the time).
+     * On machines with very fast multiplication, it's possible that the
+     * test takes more time than it's worth.  In that case this section
+     * may be commented out.
+     */
+
+    d0 = dataptr[DCTSIZE*0];
+    d1 = dataptr[DCTSIZE*1];
+    d2 = dataptr[DCTSIZE*2];
+    d3 = dataptr[DCTSIZE*3];
+    d4 = dataptr[DCTSIZE*4];
+    d5 = dataptr[DCTSIZE*5];
+    d6 = dataptr[DCTSIZE*6];
+    d7 = dataptr[DCTSIZE*7];
+
+    /* Even part: reverse the even part of the forward DCT. */
+    /* The rotator is sqrt(2)*c(-6). */
+    if (d6) {
+	if (d4) {
+	    if (d2) {
+		if (d0) {
+		    /* d0 != 0, d2 != 0, d4 != 0, d6 != 0 */
+		    z1 = MULTIPLY(d2 + d6, FIX_0_541196100);
+		    tmp2 = z1 + MULTIPLY(-d6, FIX_1_847759065);
+		    tmp3 = z1 + MULTIPLY(d2, FIX_0_765366865);
+
+		    tmp0 = (d0 + d4) << CONST_BITS;
+		    tmp1 = (d0 - d4) << CONST_BITS;
+
+		    tmp10 = tmp0 + tmp3;
+		    tmp13 = tmp0 - tmp3;
+		    tmp11 = tmp1 + tmp2;
+		    tmp12 = tmp1 - tmp2;
+		} else {
+		    /* d0 == 0, d2 != 0, d4 != 0, d6 != 0 */
+		    z1 = MULTIPLY(d2 + d6, FIX_0_541196100);
+		    tmp2 = z1 + MULTIPLY(-d6, FIX_1_847759065);
+		    tmp3 = z1 + MULTIPLY(d2, FIX_0_765366865);
+
+		    tmp0 = d4 << CONST_BITS;
+
+		    tmp10 = tmp0 + tmp3;
+		    tmp13 = tmp0 - tmp3;
+		    tmp11 = tmp2 - tmp0;
+		    tmp12 = -(tmp0 + tmp2);
+		}
+	    } else {
+		if (d0) {
+		    /* d0 != 0, d2 == 0, d4 != 0, d6 != 0 */
+		    tmp2 = MULTIPLY(-d6, FIX_1_306562965);
+		    tmp3 = MULTIPLY(d6, FIX_0_541196100);
+
+		    tmp0 = (d0 + d4) << CONST_BITS;
+		    tmp1 = (d0 - d4) << CONST_BITS;
+
+		    tmp10 = tmp0 + tmp3;
+		    tmp13 = tmp0 - tmp3;
+		    tmp11 = tmp1 + tmp2;
+		    tmp12 = tmp1 - tmp2;
+		} else {
+		    /* d0 == 0, d2 == 0, d4 != 0, d6 != 0 */
+		    tmp2 = MULTIPLY(-d6, FIX_1_306562965);
+		    tmp3 = MULTIPLY(d6, FIX_0_541196100);
+
+		    tmp0 = d4 << CONST_BITS;
+
+		    tmp10 = tmp0 + tmp3;
+		    tmp13 = tmp0 - tmp3;
+		    tmp11 = tmp2 - tmp0;
+		    tmp12 = -(tmp0 + tmp2);
+		}
+	    }
+	} else {
+	    if (d2) {
+		if (d0) {
+		    /* d0 != 0, d2 != 0, d4 == 0, d6 != 0 */
+		    z1 = MULTIPLY(d2 + d6, FIX_0_541196100);
+		    tmp2 = z1 + MULTIPLY(-d6, FIX_1_847759065);
+		    tmp3 = z1 + MULTIPLY(d2, FIX_0_765366865);
+
+		    tmp0 = d0 << CONST_BITS;
+
+		    tmp10 = tmp0 + tmp3;
+		    tmp13 = tmp0 - tmp3;
+		    tmp11 = tmp0 + tmp2;
+		    tmp12 = tmp0 - tmp2;
+		} else {
+		    /* d0 == 0, d2 != 0, d4 == 0, d6 != 0 */
+		    z1 = MULTIPLY(d2 + d6, FIX_0_541196100);
+		    tmp2 = z1 + MULTIPLY(-d6, FIX_1_847759065);
+		    tmp3 = z1 + MULTIPLY(d2, FIX_0_765366865);
+
+		    tmp10 = tmp3;
+		    tmp13 = -tmp3;
+		    tmp11 = tmp2;
+		    tmp12 = -tmp2;
+		}
+	    } else {
+		if (d0) {
+		    /* d0 != 0, d2 == 0, d4 == 0, d6 != 0 */
+		    tmp2 = MULTIPLY(-d6, FIX_1_306562965);
+		    tmp3 = MULTIPLY(d6, FIX_0_541196100);
+
+		    tmp0 = d0 << CONST_BITS;
+
+		    tmp10 = tmp0 + tmp3;
+		    tmp13 = tmp0 - tmp3;
+		    tmp11 = tmp0 + tmp2;
+		    tmp12 = tmp0 - tmp2;
+		} else {
+		    /* d0 == 0, d2 == 0, d4 == 0, d6 != 0 */
+		    tmp2 = MULTIPLY(-d6, FIX_1_306562965);
+		    tmp3 = MULTIPLY(d6, FIX_0_541196100);
+
+		    tmp10 = tmp3;
+		    tmp13 = -tmp3;
+		    tmp11 = tmp2;
+		    tmp12 = -tmp2;
+		}
+	    }
+	}
+    } else {
+	if (d4) {
+	    if (d2) {
+		if (d0) {
+		    /* d0 != 0, d2 != 0, d4 != 0, d6 == 0 */
+		    tmp2 = MULTIPLY(d2, FIX_0_541196100);
+		    tmp3 = MULTIPLY(d2, FIX_1_306562965);
+
+		    tmp0 = (d0 + d4) << CONST_BITS;
+		    tmp1 = (d0 - d4) << CONST_BITS;
+
+		    tmp10 = tmp0 + tmp3;
+		    tmp13 = tmp0 - tmp3;
+		    tmp11 = tmp1 + tmp2;
+		    tmp12 = tmp1 - tmp2;
+		} else {
+		    /* d0 == 0, d2 != 0, d4 != 0, d6 == 0 */
+		    tmp2 = MULTIPLY(d2, FIX_0_541196100);
+		    tmp3 = MULTIPLY(d2, FIX_1_306562965);
+
+		    tmp0 = d4 << CONST_BITS;
+
+		    tmp10 = tmp0 + tmp3;
+		    tmp13 = tmp0 - tmp3;
+		    tmp11 = tmp2 - tmp0;
+		    tmp12 = -(tmp0 + tmp2);
+		}
+	    } else {
+		if (d0) {
+		    /* d0 != 0, d2 == 0, d4 != 0, d6 == 0 */
+		    tmp10 = tmp13 = (d0 + d4) << CONST_BITS;
+		    tmp11 = tmp12 = (d0 - d4) << CONST_BITS;
+		} else {
+		    /* d0 == 0, d2 == 0, d4 != 0, d6 == 0 */
+		    tmp10 = tmp13 = d4 << CONST_BITS;
+		    tmp11 = tmp12 = -tmp10;
+		}
+	    }
+	} else {
+	    if (d2) {
+		if (d0) {
+		    /* d0 != 0, d2 != 0, d4 == 0, d6 == 0 */
+		    tmp2 = MULTIPLY(d2, FIX_0_541196100);
+		    tmp3 = MULTIPLY(d2, FIX_1_306562965);
+
+		    tmp0 = d0 << CONST_BITS;
+
+		    tmp10 = tmp0 + tmp3;
+		    tmp13 = tmp0 - tmp3;
+		    tmp11 = tmp0 + tmp2;
+		    tmp12 = tmp0 - tmp2;
+		} else {
+		    /* d0 == 0, d2 != 0, d4 == 0, d6 == 0 */
+		    tmp2 = MULTIPLY(d2, FIX_0_541196100);
+		    tmp3 = MULTIPLY(d2, FIX_1_306562965);
+
+		    tmp10 = tmp3;
+		    tmp13 = -tmp3;
+		    tmp11 = tmp2;
+		    tmp12 = -tmp2;
+		}
+	    } else {
+		if (d0) {
+		    /* d0 != 0, d2 == 0, d4 == 0, d6 == 0 */
+		    tmp10 = tmp13 = tmp11 = tmp12 = d0 << CONST_BITS;
+		} else {
+		    /* d0 == 0, d2 == 0, d4 == 0, d6 == 0 */
+		    tmp10 = tmp13 = tmp11 = tmp12 = 0;
+		}
+	    }
+	}
+    }
+
+    /* Odd part per figure 8; the matrix is unitary and hence its
+     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.
+     */
+    if (d7) {
+	if (d5) {
+	    if (d3) {
+		if (d1) {
+		    /* d1 != 0, d3 != 0, d5 != 0, d7 != 0 */
+		    z1 = d7 + d1;
+		    z2 = d5 + d3;
+		    z3 = d7 + d3;
+		    z4 = d5 + d1;
+		    z5 = MULTIPLY(z3 + z4, FIX_1_175875602);
+		    
+		    tmp0 = MULTIPLY(d7, FIX_0_298631336); 
+		    tmp1 = MULTIPLY(d5, FIX_2_053119869);
+		    tmp2 = MULTIPLY(d3, FIX_3_072711026);
+		    tmp3 = MULTIPLY(d1, FIX_1_501321110);
+		    z1 = MULTIPLY(-z1, FIX_0_899976223);
+		    z2 = MULTIPLY(-z2, FIX_2_562915447);
+		    z3 = MULTIPLY(-z3, FIX_1_961570560);
+		    z4 = MULTIPLY(-z4, FIX_0_390180644);
+		    
+		    z3 += z5;
+		    z4 += z5;
+		    
+		    tmp0 += z1 + z3;
+		    tmp1 += z2 + z4;
+		    tmp2 += z2 + z3;
+		    tmp3 += z1 + z4;
+		} else {
+		    /* d1 == 0, d3 != 0, d5 != 0, d7 != 0 */
+		    z1 = d7;
+		    z2 = d5 + d3;
+		    z3 = d7 + d3;
+		    z5 = MULTIPLY(z3 + d5, FIX_1_175875602);
+		    
+		    tmp0 = MULTIPLY(d7, FIX_0_298631336); 
+		    tmp1 = MULTIPLY(d5, FIX_2_053119869);
+		    tmp2 = MULTIPLY(d3, FIX_3_072711026);
+		    z1 = MULTIPLY(-d7, FIX_0_899976223);
+		    z2 = MULTIPLY(-z2, FIX_2_562915447);
+		    z3 = MULTIPLY(-z3, FIX_1_961570560);
+		    z4 = MULTIPLY(-d5, FIX_0_390180644);
+		    
+		    z3 += z5;
+		    z4 += z5;
+		    
+		    tmp0 += z1 + z3;
+		    tmp1 += z2 + z4;
+		    tmp2 += z2 + z3;
+		    tmp3 = z1 + z4;
+		}
+	    } else {
+		if (d1) {
+		    /* d1 != 0, d3 == 0, d5 != 0, d7 != 0 */
+		    z1 = d7 + d1;
+		    z2 = d5;
+		    z3 = d7;
+		    z4 = d5 + d1;
+		    z5 = MULTIPLY(z3 + z4, FIX_1_175875602);
+		    
+		    tmp0 = MULTIPLY(d7, FIX_0_298631336); 
+		    tmp1 = MULTIPLY(d5, FIX_2_053119869);
+		    tmp3 = MULTIPLY(d1, FIX_1_501321110);
+		    z1 = MULTIPLY(-z1, FIX_0_899976223);
+		    z2 = MULTIPLY(-d5, FIX_2_562915447);
+		    z3 = MULTIPLY(-d7, FIX_1_961570560);
+		    z4 = MULTIPLY(-z4, FIX_0_390180644);
+		    
+		    z3 += z5;
+		    z4 += z5;
+		    
+		    tmp0 += z1 + z3;
+		    tmp1 += z2 + z4;
+		    tmp2 = z2 + z3;
+		    tmp3 += z1 + z4;
+		} else {
+		    /* d1 == 0, d3 == 0, d5 != 0, d7 != 0 */
+		    tmp0 = MULTIPLY(-d7, FIX_0_601344887); 
+		    z1 = MULTIPLY(-d7, FIX_0_899976223);
+		    z3 = MULTIPLY(-d7, FIX_1_961570560);
+		    tmp1 = MULTIPLY(-d5, FIX_0_509795579);
+		    z2 = MULTIPLY(-d5, FIX_2_562915447);
+		    z4 = MULTIPLY(-d5, FIX_0_390180644);
+		    z5 = MULTIPLY(d5 + d7, FIX_1_175875602);
+		    
+		    z3 += z5;
+		    z4 += z5;
+		    
+		    tmp0 += z3;
+		    tmp1 += z4;
+		    tmp2 = z2 + z3;
+		    tmp3 = z1 + z4;
+		}
+	    }
+	} else {
+	    if (d3) {
+		if (d1) {
+		    /* d1 != 0, d3 != 0, d5 == 0, d7 != 0 */
+		    z1 = d7 + d1;
+		    z3 = d7 + d3;
+		    z5 = MULTIPLY(z3 + d1, FIX_1_175875602);
+		    
+		    tmp0 = MULTIPLY(d7, FIX_0_298631336); 
+		    tmp2 = MULTIPLY(d3, FIX_3_072711026);
+		    tmp3 = MULTIPLY(d1, FIX_1_501321110);
+		    z1 = MULTIPLY(-z1, FIX_0_899976223);
+		    z2 = MULTIPLY(-d3, FIX_2_562915447);
+		    z3 = MULTIPLY(-z3, FIX_1_961570560);
+		    z4 = MULTIPLY(-d1, FIX_0_390180644);
+		    
+		    z3 += z5;
+		    z4 += z5;
+		    
+		    tmp0 += z1 + z3;
+		    tmp1 = z2 + z4;
+		    tmp2 += z2 + z3;
+		    tmp3 += z1 + z4;
+		} else {
+		    /* d1 == 0, d3 != 0, d5 == 0, d7 != 0 */
+		    z3 = d7 + d3;
+		    
+		    tmp0 = MULTIPLY(-d7, FIX_0_601344887); 
+		    z1 = MULTIPLY(-d7, FIX_0_899976223);
+		    tmp2 = MULTIPLY(d3, FIX_0_509795579);
+		    z2 = MULTIPLY(-d3, FIX_2_562915447);
+		    z5 = MULTIPLY(z3, FIX_1_175875602);
+		    z3 = MULTIPLY(-z3, FIX_0_785694958);
+		    
+		    tmp0 += z3;
+		    tmp1 = z2 + z5;
+		    tmp2 += z3;
+		    tmp3 = z1 + z5;
+		}
+	    } else {
+		if (d1) {
+		    /* d1 != 0, d3 == 0, d5 == 0, d7 != 0 */
+		    z1 = d7 + d1;
+		    z5 = MULTIPLY(z1, FIX_1_175875602);
+
+		    z1 = MULTIPLY(z1, FIX_0_275899380);
+		    z3 = MULTIPLY(-d7, FIX_1_961570560);
+		    tmp0 = MULTIPLY(-d7, FIX_1_662939225); 
+		    z4 = MULTIPLY(-d1, FIX_0_390180644);
+		    tmp3 = MULTIPLY(d1, FIX_1_111140466);
+
+		    tmp0 += z1;
+		    tmp1 = z4 + z5;
+		    tmp2 = z3 + z5;
+		    tmp3 += z1;
+		} else {
+		    /* d1 == 0, d3 == 0, d5 == 0, d7 != 0 */
+		    tmp0 = MULTIPLY(-d7, FIX_1_387039845);
+		    tmp1 = MULTIPLY(d7, FIX_1_175875602);
+		    tmp2 = MULTIPLY(-d7, FIX_0_785694958);
+		    tmp3 = MULTIPLY(d7, FIX_0_275899380);
+		}
+	    }
+	}
+    } else {
+	if (d5) {
+	    if (d3) {
+		if (d1) {
+		    /* d1 != 0, d3 != 0, d5 != 0, d7 == 0 */
+		    z2 = d5 + d3;
+		    z4 = d5 + d1;
+		    z5 = MULTIPLY(d3 + z4, FIX_1_175875602);
+		    
+		    tmp1 = MULTIPLY(d5, FIX_2_053119869);
+		    tmp2 = MULTIPLY(d3, FIX_3_072711026);
+		    tmp3 = MULTIPLY(d1, FIX_1_501321110);
+		    z1 = MULTIPLY(-d1, FIX_0_899976223);
+		    z2 = MULTIPLY(-z2, FIX_2_562915447);
+		    z3 = MULTIPLY(-d3, FIX_1_961570560);
+		    z4 = MULTIPLY(-z4, FIX_0_390180644);
+		    
+		    z3 += z5;
+		    z4 += z5;
+		    
+		    tmp0 = z1 + z3;
+		    tmp1 += z2 + z4;
+		    tmp2 += z2 + z3;
+		    tmp3 += z1 + z4;
+		} else {
+		    /* d1 == 0, d3 != 0, d5 != 0, d7 == 0 */
+		    z2 = d5 + d3;
+		    
+		    z5 = MULTIPLY(z2, FIX_1_175875602);
+		    tmp1 = MULTIPLY(d5, FIX_1_662939225);
+		    z4 = MULTIPLY(-d5, FIX_0_390180644);
+		    z2 = MULTIPLY(-z2, FIX_1_387039845);
+		    tmp2 = MULTIPLY(d3, FIX_1_111140466);
+		    z3 = MULTIPLY(-d3, FIX_1_961570560);
+		    
+		    tmp0 = z3 + z5;
+		    tmp1 += z2;
+		    tmp2 += z2;
+		    tmp3 = z4 + z5;
+		}
+	    } else {
+		if (d1) {
+		    /* d1 != 0, d3 == 0, d5 != 0, d7 == 0 */
+		    z4 = d5 + d1;
+		    
+		    z5 = MULTIPLY(z4, FIX_1_175875602);
+		    z1 = MULTIPLY(-d1, FIX_0_899976223);
+		    tmp3 = MULTIPLY(d1, FIX_0_601344887);
+		    tmp1 = MULTIPLY(-d5, FIX_0_509795579);
+		    z2 = MULTIPLY(-d5, FIX_2_562915447);
+		    z4 = MULTIPLY(z4, FIX_0_785694958);
+		    
+		    tmp0 = z1 + z5;
+		    tmp1 += z4;
+		    tmp2 = z2 + z5;
+		    tmp3 += z4;
+		} else {
+		    /* d1 == 0, d3 == 0, d5 != 0, d7 == 0 */
+		    tmp0 = MULTIPLY(d5, FIX_1_175875602);
+		    tmp1 = MULTIPLY(d5, FIX_0_275899380);
+		    tmp2 = MULTIPLY(-d5, FIX_1_387039845);
+		    tmp3 = MULTIPLY(d5, FIX_0_785694958);
+		}
+	    }
+	} else {
+	    if (d3) {
+		if (d1) {
+		    /* d1 != 0, d3 != 0, d5 == 0, d7 == 0 */
+		    z5 = d1 + d3;
+		    tmp3 = MULTIPLY(d1, FIX_0_211164243);
+		    tmp2 = MULTIPLY(-d3, FIX_1_451774981);
+		    z1 = MULTIPLY(d1, FIX_1_061594337);
+		    z2 = MULTIPLY(-d3, FIX_2_172734803);
+		    z4 = MULTIPLY(z5, FIX_0_785694958);
+		    z5 = MULTIPLY(z5, FIX_1_175875602);
+		    
+		    tmp0 = z1 - z4;
+		    tmp1 = z2 + z4;
+		    tmp2 += z5;
+		    tmp3 += z5;
+		} else {
+		    /* d1 == 0, d3 != 0, d5 == 0, d7 == 0 */
+		    tmp0 = MULTIPLY(-d3, FIX_0_785694958);
+		    tmp1 = MULTIPLY(-d3, FIX_1_387039845);
+		    tmp2 = MULTIPLY(-d3, FIX_0_275899380);
+		    tmp3 = MULTIPLY(d3, FIX_1_175875602);
+		}
+	    } else {
+		if (d1) {
+		    /* d1 != 0, d3 == 0, d5 == 0, d7 == 0 */
+		    tmp0 = MULTIPLY(d1, FIX_0_275899380);
+		    tmp1 = MULTIPLY(d1, FIX_0_785694958);
+		    tmp2 = MULTIPLY(d1, FIX_1_175875602);
+		    tmp3 = MULTIPLY(d1, FIX_1_387039845);
+		} else {
+		    /* d1 == 0, d3 == 0, d5 == 0, d7 == 0 */
+		    tmp0 = tmp1 = tmp2 = tmp3 = 0;
+		}
+	    }
+	}
+    }
+
+    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+    dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp3,
+					   CONST_BITS+PASS1_BITS+3);
+    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp10 - tmp3,
+					   CONST_BITS+PASS1_BITS+3);
+    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp11 + tmp2,
+					   CONST_BITS+PASS1_BITS+3);
+    dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(tmp11 - tmp2,
+					   CONST_BITS+PASS1_BITS+3);
+    dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp12 + tmp1,
+					   CONST_BITS+PASS1_BITS+3);
+    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12 - tmp1,
+					   CONST_BITS+PASS1_BITS+3);
+    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp13 + tmp0,
+					   CONST_BITS+PASS1_BITS+3);
+    dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp13 - tmp0,
+					   CONST_BITS+PASS1_BITS+3);
+    
+    dataptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/* here is the reference one, in case of problems with the normal one */
+
+/* idctref.c, Inverse Discrete Fourier Transform, double precision          */
+
+/* Copyright (C) 1994, MPEG Software Simulation Group. All Rights Reserved. */
+
+/*
+ * Disclaimer of Warranty
+ *
+ * These software programs are available to the user without any license fee or
+ * royalty on an "as is" basis.  The MPEG Software Simulation Group disclaims
+ * any and all warranties, whether express, implied, or statuary, including any
+ * implied warranties or merchantability or of fitness for a particular
+ * purpose.  In no event shall the copyright-holder be liable for any
+ * incidental, punitive, or consequential damages of any kind whatsoever
+ * arising from the use of these programs.
+ *
+ * This disclaimer of warranty extends to the user of these programs and user's
+ * customers, employees, agents, transferees, successors, and assigns.
+ *
+ * The MPEG Software Simulation Group does not represent or warrant that the
+ * programs furnished hereunder are free of infringement of any third-party
+ * patents.
+ *
+ * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware,
+ * are subject to royalty fees to patent holders.  Many of these patents are
+ * general enough such that they are unavoidable regardless of implementation
+ * design.
+ *
+ */
+
+/*  Perform IEEE 1180 reference (64-bit floating point, separable 8x1
+ *  direct matrix multiply) Inverse Discrete Cosine Transform
+*/
+
+
+/* Here we use math.h to generate constants.  Compiler results may
+   vary a little */
+
+#ifndef PI
+#ifdef M_PI
+#define PI M_PI
+#else
+#define PI 3.14159265358979323846
+#endif
+#endif
+
+/* cosine transform matrix for 8x1 IDCT */
+static double itrans_coef[8][8];
+
+/* initialize DCT coefficient matrix */
+
+void init_idctref()
+{
+  int freq, time;
+  double scale;
+
+  for (freq=0; freq < 8; freq++)
+  {
+    scale = (freq == 0) ? sqrt(0.125) : 0.5;
+    for (time=0; time<8; time++)
+      itrans_coef[freq][time] = scale*cos((PI/8.0)*freq*(time + 0.5));
+  }
+}
+
+/* perform IDCT matrix multiply for 8x8 coefficient block */
+
+void reference_rev_dct(block)
+int16 *block;
+{
+  int i, j, k, v;
+  double partial_product;
+  double tmp[64];
+
+  for (i=0; i<8; i++)
+    for (j=0; j<8; j++)
+    {
+      partial_product = 0.0;
+
+      for (k=0; k<8; k++)
+        partial_product+= itrans_coef[k][j]*block[8*i+k];
+
+      tmp[8*i+j] = partial_product;
+    }
+
+  /* Transpose operation is integrated into address mapping by switching 
+     loop order of i and j */
+
+  for (j=0; j<8; j++)
+    for (i=0; i<8; i++)
+    {
+      partial_product = 0.0;
+
+      for (k=0; k<8; k++)
+        partial_product+= itrans_coef[k][i]*tmp[8*k+j];
+
+      v = floor(partial_product+0.5);
+      block[8*i+j] = (v<-256) ? -256 : ((v>255) ? 255 : v);
+    }
+}
diff --git a/converter/ppm/ppmtompeg/memory.c b/converter/ppm/ppmtompeg/memory.c
new file mode 100644
index 00000000..f117994a
--- /dev/null
+++ b/converter/ppm/ppmtompeg/memory.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*
+ *  $Header: /n/charlie-brown/project/mm/mpeg/mpeg_dist/mpeg_encode/RCS/memory.c,v 1.3 1995/01/19 23:08:43 eyhung Exp $
+ *  $Log: memory.c,v $
+ * Revision 1.3  1995/01/19  23:08:43  eyhung
+ * Changed copyrights
+ *
+ * Revision 1.2  1993/06/03  21:08:08  keving
+ * nothing
+ *
+ * Revision 1.1  1993/04/27  21:32:26  keving
+ * nothing
+ *
+ *
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "memory.h"
+
+
+/* memory handling routines
+ *
+ */
+
+long	totalMemory = 0;
+long	maxMemory = 0;
+
+
+char	*MemAlloc(size_t size)
+{
+    totalMemory += (long)size;
+    if ( totalMemory > maxMemory )
+    {
+	maxMemory = totalMemory;
+    }
+
+    return malloc(size);
+}
+
+void	MemFree(char *ptr, long bytes)
+{
+    totalMemory -= bytes;
+    free(ptr);
+}
+
+void	PrintMaxMemory(void)
+{
+    fprintf(stdout, "MMMMM-----MAX MEMORY-----MMMMM = %ld\n", maxMemory);
+}
diff --git a/converter/ppm/ppmtompeg/mfwddct.c b/converter/ppm/ppmtompeg/mfwddct.c
new file mode 100644
index 00000000..4643bf25
--- /dev/null
+++ b/converter/ppm/ppmtompeg/mfwddct.c
@@ -0,0 +1,393 @@
+
+/*
+ * mfwddct.c (derived from jfwddct.c, which carries the following info)
+ *
+ * Copyright (C) 1991, 1992, Thomas G. Lane. This file is part of the
+ * Independent JPEG Group's software. For conditions of distribution and use,
+ * see the accompanying README file.
+ *
+ * This file contains the basic DCT (Discrete Cosine Transform) transformation
+ * subroutine.
+ *
+ * This implementation is based on Appendix A.2 of the book "Discrete Cosine
+ * Transform---Algorithms, Advantages, Applications" by K.R. Rao and P. Yip
+ * (Academic Press, Inc, London, 1990). It uses scaled fixed-point arithmetic
+ * instead of floating point.
+ */
+
+#include "all.h"
+
+#include "dct.h"
+#include "mtypes.h"
+#include "opts.h"
+
+/*
+ * The poop on this scaling stuff is as follows:
+ *
+ * We have to do addition and subtraction of the integer inputs, which is no
+ * problem, and multiplication by fractional constants, which is a problem to
+ * do in integer arithmetic.  We multiply all the constants by DCT_SCALE and
+ * convert them to integer constants (thus retaining LG2_DCT_SCALE bits of
+ * precision in the constants).  After doing a multiplication we have to
+ * divide the product by DCT_SCALE, with proper rounding, to produce the
+ * correct output.  The division can be implemented cheaply as a right shift
+ * of LG2_DCT_SCALE bits.  The DCT equations also specify an additional
+ * division by 2 on the final outputs; this can be folded into the
+ * right-shift by shifting one more bit (see UNFIXH).
+ *
+ * If you are planning to recode this in assembler, you might want to set
+ * LG2_DCT_SCALE to 15.  This loses a bit of precision, but then all the
+ * multiplications are between 16-bit quantities (given 8-bit JSAMPLEs!) so
+ * you could use a signed 16x16=>32 bit multiply instruction instead of full
+ * 32x32 multiply.  Unfortunately there's no way to describe such a multiply
+ * portably in C, so we've gone for the extra bit of accuracy here.
+ */
+
+#define EIGHT_BIT_SAMPLES
+#ifdef EIGHT_BIT_SAMPLES
+#define LG2_DCT_SCALE 16
+#else
+#define LG2_DCT_SCALE 15	/* lose a little precision to avoid overflow */
+#endif
+
+#define ONE	((int32) 1)
+
+#define DCT_SCALE (ONE << LG2_DCT_SCALE)
+
+/* In some places we shift the inputs left by a couple more bits, */
+/* so that they can be added to fractional results without too much */
+/* loss of precision. */
+#define LG2_OVERSCALE 2
+#define OVERSCALE  (ONE << LG2_OVERSCALE)
+#define OVERSHIFT(x)  ((x) <<= LG2_OVERSCALE)
+
+/* Scale a fractional constant by DCT_SCALE */
+#define FIX(x)	((int32) ((x) * DCT_SCALE + 0.5))
+
+/* Scale a fractional constant by DCT_SCALE/OVERSCALE */
+/* Such a constant can be multiplied with an overscaled input */
+/* to produce something that's scaled by DCT_SCALE */
+#define FIXO(x)  ((int32) ((x) * DCT_SCALE / OVERSCALE + 0.5))
+
+/* Descale and correctly round a value that's scaled by DCT_SCALE */
+#define UNFIX(x)   RIGHT_SHIFT((x) + (ONE << (LG2_DCT_SCALE-1)), LG2_DCT_SCALE)
+
+/* Same with an additional division by 2, ie, correctly rounded UNFIX(x/2) */
+#define UNFIXH(x)  RIGHT_SHIFT((x) + (ONE << LG2_DCT_SCALE), LG2_DCT_SCALE+1)
+
+/* Take a value scaled by DCT_SCALE and round to integer scaled by OVERSCALE */
+#define UNFIXO(x)  RIGHT_SHIFT((x) + (ONE << (LG2_DCT_SCALE-1-LG2_OVERSCALE)),\
+			       LG2_DCT_SCALE-LG2_OVERSCALE)
+
+/* Here are the constants we need */
+/* SIN_i_j is sine of i*pi/j, scaled by DCT_SCALE */
+/* COS_i_j is cosine of i*pi/j, scaled by DCT_SCALE */
+
+#define SIN_1_4 FIX(0.707106781)
+#define COS_1_4 SIN_1_4
+
+#define SIN_1_8 FIX(0.382683432)
+#define COS_1_8 FIX(0.923879533)
+#define SIN_3_8 COS_1_8
+#define COS_3_8 SIN_1_8
+
+#define SIN_1_16 FIX(0.195090322)
+#define COS_1_16 FIX(0.980785280)
+#define SIN_7_16 COS_1_16
+#define COS_7_16 SIN_1_16
+
+#define SIN_3_16 FIX(0.555570233)
+#define COS_3_16 FIX(0.831469612)
+#define SIN_5_16 COS_3_16
+#define COS_5_16 SIN_3_16
+
+/* OSIN_i_j is sine of i*pi/j, scaled by DCT_SCALE/OVERSCALE */
+/* OCOS_i_j is cosine of i*pi/j, scaled by DCT_SCALE/OVERSCALE */
+
+#define OSIN_1_4 FIXO(0.707106781)
+#define OCOS_1_4 OSIN_1_4
+
+#define OSIN_1_8 FIXO(0.382683432)
+#define OCOS_1_8 FIXO(0.923879533)
+#define OSIN_3_8 OCOS_1_8
+#define OCOS_3_8 OSIN_1_8
+
+#define OSIN_1_16 FIXO(0.195090322)
+#define OCOS_1_16 FIXO(0.980785280)
+#define OSIN_7_16 OCOS_1_16
+#define OCOS_7_16 OSIN_1_16
+
+#define OSIN_3_16 FIXO(0.555570233)
+#define OCOS_3_16 FIXO(0.831469612)
+#define OSIN_5_16 OCOS_3_16
+#define OCOS_5_16 OSIN_3_16
+
+/* Prototypes */
+void reference_fwd_dct _ANSI_ARGS_((Block block, Block dest));
+void mp_fwd_dct_fast _ANSI_ARGS_((Block data2d, Block dest2d));
+void init_fdct _ANSI_ARGS_((void));
+
+/*
+ * --------------------------------------------------------------
+ *
+ * mp_fwd_dct_block2 --
+ *
+ * Select the appropriate mp_fwd_dct routine
+ *
+ * Results: None
+ *
+ * Side effects: None
+ *
+ * --------------------------------------------------------------
+ */
+extern boolean pureDCT;
+void
+mp_fwd_dct_block2(data, dest)
+    Block data, dest;
+{
+  if (pureDCT) reference_fwd_dct(data, dest);
+  else mp_fwd_dct_fast(data, dest);
+}
+
+/*
+ * --------------------------------------------------------------
+ *
+ * mp_fwd_dct_fast --
+ *
+ * Perform the forward DCT on one block of samples.
+ *
+ * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT on each
+ * column.
+ *
+ * Results: None
+ *
+ * Side effects: Overwrites the input data
+ *
+ * --------------------------------------------------------------
+ */
+
+void
+mp_fwd_dct_fast(data2d, dest2d)
+    Block data2d, dest2d;
+{
+    int16 *data = (int16 *) data2d;	/* this algorithm wants
+					 * a 1-d array */
+    int16 *dest = (int16 *) dest2d;
+    int pass, rowctr;
+    register int16 *inptr, *outptr;
+    int16 workspace[DCTSIZE_SQ];
+    SHIFT_TEMPS
+
+#ifdef ndef
+    {
+	int y;
+
+	printf("fwd_dct (beforehand):\n");
+	for (y = 0; y < 8; y++)
+	    printf("%4d %4d %4d %4d %4d %4d %4d %4d\n",
+		   data2d[y][0], data2d[y][1],
+		   data2d[y][2], data2d[y][3],
+		   data2d[y][4], data2d[y][5],
+		   data2d[y][6], data2d[y][7]);
+    }
+#endif
+
+    /*
+     * Each iteration of the inner loop performs one 8-point 1-D DCT. It
+     * reads from a *row* of the input matrix and stores into a *column*
+     * of the output matrix.  In the first pass, we read from the data[]
+     * array and store into the local workspace[].  In the second pass,
+     * we read from the workspace[] array and store into data[], thus
+     * performing the equivalent of a columnar DCT pass with no variable
+     * array indexing.
+     */
+
+    inptr = data;		/* initialize pointers for first pass */
+    outptr = workspace;
+    for (pass = 1; pass >= 0; pass--) {
+	for (rowctr = DCTSIZE - 1; rowctr >= 0; rowctr--) {
+	    /*
+	     * many tmps have nonoverlapping lifetime -- flashy
+	     * register colorers should be able to do this lot
+	     * very well
+	     */
+	    int32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+	    int32 tmp10, tmp11, tmp12, tmp13;
+	    int32 tmp14, tmp15, tmp16, tmp17;
+	    int32 tmp25, tmp26;
+	    /* SHIFT_TEMPS */
+
+	    /* temp0 through tmp7:  -512 to +512 */
+	    /* if I-block, then -256 to +256 */
+	    tmp0 = inptr[7] + inptr[0];
+	    tmp1 = inptr[6] + inptr[1];
+	    tmp2 = inptr[5] + inptr[2];
+	    tmp3 = inptr[4] + inptr[3];
+	    tmp4 = inptr[3] - inptr[4];
+	    tmp5 = inptr[2] - inptr[5];
+	    tmp6 = inptr[1] - inptr[6];
+	    tmp7 = inptr[0] - inptr[7];
+
+	    /* tmp10 through tmp13:  -1024 to +1024 */
+	    /* if I-block, then -512 to +512 */
+	    tmp10 = tmp3 + tmp0;
+	    tmp11 = tmp2 + tmp1;
+	    tmp12 = tmp1 - tmp2;
+	    tmp13 = tmp0 - tmp3;
+
+	    outptr[0] = (int16) UNFIXH((tmp10 + tmp11) * SIN_1_4);
+	    outptr[DCTSIZE * 4] = (int16) UNFIXH((tmp10 - tmp11) * COS_1_4);
+
+	    outptr[DCTSIZE * 2] = (int16) UNFIXH(tmp13 * COS_1_8 + tmp12 * SIN_1_8);
+	    outptr[DCTSIZE * 6] = (int16) UNFIXH(tmp13 * SIN_1_8 - tmp12 * COS_1_8);
+
+	    tmp16 = UNFIXO((tmp6 + tmp5) * SIN_1_4);
+	    tmp15 = UNFIXO((tmp6 - tmp5) * COS_1_4);
+
+	    OVERSHIFT(tmp4);
+	    OVERSHIFT(tmp7);
+
+	    /*
+	     * tmp4, tmp7, tmp15, tmp16 are overscaled by
+	     * OVERSCALE
+	     */
+
+	    tmp14 = tmp4 + tmp15;
+	    tmp25 = tmp4 - tmp15;
+	    tmp26 = tmp7 - tmp16;
+	    tmp17 = tmp7 + tmp16;
+
+	    outptr[DCTSIZE] = (int16) UNFIXH(tmp17 * OCOS_1_16 + tmp14 * OSIN_1_16);
+	    outptr[DCTSIZE * 7] = (int16) UNFIXH(tmp17 * OCOS_7_16 - tmp14 * OSIN_7_16);
+	    outptr[DCTSIZE * 5] = (int16) UNFIXH(tmp26 * OCOS_5_16 + tmp25 * OSIN_5_16);
+	    outptr[DCTSIZE * 3] = (int16) UNFIXH(tmp26 * OCOS_3_16 - tmp25 * OSIN_3_16);
+
+	    inptr += DCTSIZE;	/* advance inptr to next row */
+	    outptr++;		/* advance outptr to next column */
+	}
+	/* end of pass; in case it was pass 1, set up for pass 2 */
+	inptr = workspace;
+	outptr = dest;
+    }
+#ifdef ndef
+    {
+	int y;
+
+	printf("fwd_dct (afterward):\n");
+	for (y = 0; y < 8; y++)
+	    printf("%4d %4d %4d %4d %4d %4d %4d %4d\n",
+		   dest2d[y][0], dest2d[y][1],
+		   dest2d[y][2], dest2d[y][3],
+		   dest2d[y][4], dest2d[y][5],
+		   dest2d[y][6], dest2d[y][7]);
+    }
+#endif
+}
+
+
+/* Modifies from the MPEG2 verification coder */
+/* fdctref.c, forward discrete cosine transform, double precision           */
+
+/* Copyright (C) 1994, MPEG Software Simulation Group. All Rights Reserved. */
+
+/*
+ * Disclaimer of Warranty
+ *
+ * These software programs are available to the user without any license fee or
+ * royalty on an "as is" basis.  The MPEG Software Simulation Group disclaims
+ * any and all warranties, whether express, implied, or statuary, including any
+ * implied warranties or merchantability or of fitness for a particular
+ * purpose.  In no event shall the copyright-holder be liable for any
+ * incidental, punitive, or consequential damages of any kind whatsoever
+ * arising from the use of these programs.
+ *
+ * This disclaimer of warranty extends to the user of these programs and user's
+ * customers, employees, agents, transferees, successors, and assigns.
+ *
+ * The MPEG Software Simulation Group does not represent or warrant that the
+ * programs furnished hereunder are free of infringement of any third-party
+ * patents.
+ *
+ * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware,
+ * are subject to royalty fees to patent holders.  Many of these patents are
+ * general enough such that they are unavoidable regardless of implementation
+ * design.
+ *
+ */
+
+#ifndef PI
+#ifdef M_PI
+#define PI M_PI
+#else
+#define PI 3.14159265358979323846
+#endif
+#endif
+
+/* private data */
+static double trans_coef[8][8]; /* transform coefficients */
+
+void init_fdct()
+{
+  int i, j;
+  double s;
+
+  for (i=0; i<8; i++)
+  {
+    s = (i==0) ? sqrt(0.125) : 0.5;
+
+    for (j=0; j<8; j++)
+      trans_coef[i][j] = s * cos((PI/8.0)*i*(j+0.5));
+  }
+}
+
+void reference_fwd_dct(block, dest)
+Block block, dest;
+{
+  int i, j, k;
+  double s;
+  double tmp[64];
+
+  if (DoLaplace) {
+    LaplaceNum++;
+  }
+
+  for (i=0; i<8; i++)
+    for (j=0; j<8; j++)
+    {
+      s = 0.0;
+
+      for (k=0; k<8; k++)
+        s += trans_coef[j][k] * block[i][k];
+
+      tmp[8*i+j] = s;
+    }
+
+  for (i=0; i<8; i++)
+    for (j=0; j<8; j++)
+    {
+      s = 0.0;
+
+      for (k=0; k<8; k++)
+        s += trans_coef[i][k] * tmp[8*k+j];
+
+      if (collect_quant) {
+	fprintf(collect_quant_fp, "%d %f\n", 8*i+j, s);
+      } 
+      if (DoLaplace) {
+	L1[LaplaceCnum][i*8+j] += s*s;
+	L2[LaplaceCnum][i*8+j] += s;
+      }
+
+
+      dest[i][j] = (int)floor(s+0.499999);
+      /*
+       * reason for adding 0.499999 instead of 0.5:
+       * s is quite often x.5 (at least for i and/or j = 0 or 4)
+       * and setting the rounding threshold exactly to 0.5 leads to an
+       * extremely high arithmetic implementation dependency of the result;
+       * s being between x.5 and x.500001 (which is now incorrectly rounded
+       * downwards instead of upwards) is assumed to occur less often
+       * (if at all)
+       */
+    }
+}
diff --git a/converter/ppm/ppmtompeg/mheaders.c b/converter/ppm/ppmtompeg/mheaders.c
new file mode 100644
index 00000000..2a5f2c63
--- /dev/null
+++ b/converter/ppm/ppmtompeg/mheaders.c
@@ -0,0 +1,1192 @@
+/*===========================================================================*
+ * mheaders.c								     *
+ *									     *
+ *	Procedures to generate MPEG headers				     *
+ *									     *
+ * EXPORTED PROCEDURES:							     *
+ *	Mhead_GenPictureHeader						     *
+ *	Mhead_GenSequenceHeader						     *
+ *	Mhead_GenSequenceEnder						     *
+ *	Mhead_GenGOPHeader						     *
+ *	Mhead_GenSliceHeader						     *
+ *	Mhead_GenSliceEnder						     *
+ *	Mhead_GenMBHeader						     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*
+ *  $Header: /n/picasso/project/mpeg/mpeg_dist/mpeg_encode/RCS/mheaders.c,v 1.15 1995/08/07 21:45:19 smoot Exp $
+ *  $Log: mheaders.c,v $
+ *  Revision 1.15  1995/08/07 21:45:19  smoot
+ *  check for illegal MVs (shouldnt ever be called, but....)
+ *  fix bug which made us not weite Iframe Qscale changes
+ *  warns if writing a size=0 mpeg
+ *
+ *  Revision 1.14  1995/05/22 20:53:35  smoot
+ *  corrected bit_rate value in constrained params flag
+ *
+ * Revision 1.13  1995/05/02  01:50:38  eyhung
+ * made VidRateNum un-static
+ *
+ * Revision 1.12  1995/03/27  19:28:23  smoot
+ * auto-determines Qscale changes (was mb_quant)
+ *
+ * Revision 1.11  1995/02/16  09:12:39  eyhung
+ * fixed compile bug with HP7xx
+ *
+ * Revision 1.10  1995/01/25  22:53:50  smoot
+ * Better buf_size checking, and actually check constrained params
+ *
+ * Revision 1.9  1995/01/19  23:08:47  eyhung
+ * Changed copyrights
+ *
+ * Revision 1.8  1995/01/16  08:45:10  eyhung
+ * BLEAH'ed hsize and vsize
+ *
+ * Revision 1.7  1994/12/09  22:27:17  smoot
+ * Fixed buffer size in stream
+ *
+ * Revision 1.6  1994/11/12  02:11:54  keving
+ * nothing
+ *
+ * Revision 1.5  1994/03/15  00:27:11  keving
+ * nothing
+ *
+ * Revision 1.4  1993/12/22  19:19:01  keving
+ * nothing
+ *
+ * Revision 1.3  1993/07/22  22:23:43  keving
+ * nothing
+ *
+ * Revision 1.2  1993/06/30  20:06:09  keving
+ * nothing
+ *
+ * Revision 1.1  1993/06/03  21:08:08  keving
+ * nothing
+ *
+ * Revision 1.6  1993/03/01  23:03:40  keving
+ * nothing
+ *
+ * Revision 1.5  1993/02/17  23:18:20  dwallach
+ * checkin prior to keving's joining the project
+ *
+ * Revision 1.4  1993/01/18  10:20:02  dwallach
+ * *** empty log message ***
+ *
+ * Revision 1.3  1993/01/18  10:17:29  dwallach
+ * RCS headers installed, code indented uniformly
+ *
+ * Revision 1.3  1993/01/18  10:17:29  dwallach
+ * RCS headers installed, code indented uniformly
+ *
+ */
+
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "all.h"
+#include "bitio.h"
+#include "frames.h"
+#include "mheaders.h"
+
+
+/*==================*
+ * STATIC VARIABLES *
+ *==================*/
+
+static int gopStartFrame = 0;
+static int lastGOPStart = 0;
+static int lastQSSet;
+
+static uint32 mbAddrIncrTable[][2] = {
+    {0x0, 0},
+    {0x1, 1},
+    {0x3, 3},
+    {0x2, 3},
+    {0x3, 4},
+    {0x2, 4},
+    {0x3, 5},
+    {0x2, 5},
+    {0x7, 7},
+    {0x6, 7},
+    {0xb, 8},
+    {0xa, 8},
+    {0x9, 8},
+    {0x8, 8},
+    {0x7, 8},
+    {0x6, 8},
+    {0x17, 10},
+    {0x16, 10},
+    {0x15, 10},
+    {0x14, 10},
+    {0x13, 10},
+    {0x12, 10},
+    {0x23, 11},
+    {0x22, 11},
+    {0x21, 11},
+    {0x20, 11},
+    {0x1f, 11},
+    {0x1e, 11},
+    {0x1d, 11},
+    {0x1c, 11},
+    {0x1b, 11},
+    {0x1a, 11},
+    {0x19, 11},
+    {0x18, 11}};
+
+static uint32 mbMotionVectorTable[][2] = {
+    {0x19, 11},
+    {0x1b, 11},
+    {0x1d, 11},
+    {0x1f, 11},
+    {0x21, 11},
+    {0x23, 11},
+    {0x13, 10},
+    {0x15, 10},
+    {0x17, 10},
+    {0x7, 8},
+    {0x9, 8},
+    {0xb, 8},
+    {0x7, 7},
+    {0x3, 5},
+    {0x3, 4},
+    {0x3, 3},
+    {0x1, 1},
+    {0x2, 3},
+    {0x2, 4},
+    {0x2, 5},
+    {0x6, 7},
+    {0xa, 8},
+    {0x8, 8},
+    {0x6, 8},
+    {0x16, 10},
+    {0x14, 10},
+    {0x12, 10},
+    {0x22, 11},
+    {0x20, 11},
+    {0x1e, 11},
+    {0x1c, 11},
+    {0x1a, 11},
+    {0x18, 11}};
+
+static uint32 mbPatTable[][2] = {
+    {0x0, 0},
+    {0xb, 5},
+    {0x9, 5},
+    {0xd, 6},
+    {0xd, 4},
+    {0x17, 7},
+    {0x13, 7},
+    {0x1f, 8},
+    {0xc, 4},
+    {0x16, 7},
+    {0x12, 7},
+    {0x1e, 8},
+    {0x13, 5},
+    {0x1b, 8},
+    {0x17, 8},
+    {0x13, 8},
+    {0xb, 4},
+    {0x15, 7},
+    {0x11, 7},
+    {0x1d, 8},
+    {0x11, 5},
+    {0x19, 8},
+    {0x15, 8},
+    {0x11, 8},
+    {0xf, 6},
+    {0xf, 8},
+    {0xd, 8},
+    {0x3, 9},
+    {0xf, 5},
+    {0xb, 8},
+    {0x7, 8},
+    {0x7, 9},
+    {0xa, 4},
+    {0x14, 7},
+    {0x10, 7},
+    {0x1c, 8},
+    {0xe, 6},
+    {0xe, 8},
+    {0xc, 8},
+    {0x2, 9},
+    {0x10, 5},
+    {0x18, 8},
+    {0x14, 8},
+    {0x10, 8},
+    {0xe, 5},
+    {0xa, 8},
+    {0x6, 8},
+    {0x6, 9},
+    {0x12, 5},
+    {0x1a, 8},
+    {0x16, 8},
+    {0x12, 8},
+    {0xd, 5},
+    {0x9, 8},
+    {0x5, 8},
+    {0x5, 9},
+    {0xc, 5},
+    {0x8, 8},
+    {0x4, 8},
+    {0x4, 9},
+    {0x7, 3},
+    {0xa, 5},	/* grrr... 61, 62, 63 added - Kevin */
+    {0x8, 5},
+    {0xc, 6}
+};
+
+/*===========*
+ * CONSTANTS *
+ *===========*/
+
+#define SEQ_HEAD_CODE 0x000001b3
+#define EXT_START_CODE 0x000001b5
+#define USER_START_CODE 0x000001b2
+#define GOP_START_CODE 0x000001b8
+#define PICT_START_CODE 0x00000100
+#define SLICE_BASE_CODE 0x00000100
+
+#define SEQ_END_CODE	0x000001b7
+
+/* not static anymore because information is used for computing frame rate 
+ * and for statistics */
+const double VidRateNum[9]={1.0, 23.976, 24.0, 25.0, 29.97, 30.0,
+                             50.0 ,59.94, 60.0};
+
+
+/*===============================*
+ * INTERNAL PROCEDURE prototypes *
+ *===============================*/
+
+static void	GenMBAddrIncr _ANSI_ARGS_((BitBucket *bb, uint32 addr_incr));
+static void	GenPictHead _ANSI_ARGS_((BitBucket *bb, uint32 temp_ref,
+		    uint32 code_type, uint32 vbv_delay,
+		    int32 full_pel_forw_flag, uint32 forw_f_code,
+		    int32 full_pel_back_flag, uint32 back_f_code,
+		    uint8 *extra_info, uint32 extra_info_size,
+		    uint8 *ext_data, uint32 ext_data_size,
+		    uint8 *user_data, uint32 user_data_size));
+static void	GenMBType _ANSI_ARGS_((BitBucket *bb, uint32 pict_code_type,
+		  uint32 mb_quant, uint32 motion_forw, uint32 motion_back,
+		  uint32 mb_pattern, uint32 mb_intra));
+static void	GenMotionCode _ANSI_ARGS_((BitBucket *bb, int32 vector));
+static void	GenBlockPattern _ANSI_ARGS_((BitBucket *bb,
+					     uint32 mb_pattern));
+
+
+/*=====================*
+ * EXPORTED PROCEDURES *
+ *=====================*/
+
+
+/*===========================================================================*
+ *
+ * SetGOPStartTime
+ *
+ *	sets the start frame of the GOP; to be used with GenPictureHeader
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+SetGOPStartTime(index)
+    int index;
+{
+    lastGOPStart = gopStartFrame;
+    gopStartFrame = index;
+}
+
+
+/*===========================================================================*
+ *
+ * Mhead_GenPictureHeader
+ *
+ *	generate picture header with given frame type and picture count
+ *	append result to the specified bitstream
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+Mhead_GenPictureHeader(bbPtr, frameType, pictCount, f_code)
+    BitBucket *bbPtr;
+    int frameType;
+    int pictCount;
+    int f_code;
+{
+    int	    temporalRef;
+
+    if ( pictCount >= gopStartFrame ) {
+	temporalRef = (pictCount-gopStartFrame);
+    } else {
+	temporalRef = (pictCount-lastGOPStart);
+    }
+    temporalRef = (temporalRef % 1024);
+	
+    DBG_PRINT(("Picture Header\n"));
+    GenPictHead(bbPtr, temporalRef, frameType,
+		0 /* vbv_delay */,
+		pixelFullSearch /* full_pel_forw_flag */,
+		f_code /* forw_f_code */,
+		pixelFullSearch /* full_pel_back_flag */,
+		f_code /* back_f_code */,
+		NULL, 0, NULL, 0, NULL, 0);
+}
+
+
+/*===========================================================================*
+ *
+ * Mhead_GenSequenceHeader
+ *
+ *	generate sequence header with given attributes
+ *	append result to the specified bitstream
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+Mhead_GenSequenceHeader(BitBucket *   const bbPtr, 
+                        uint32        const hsize, 
+                        uint32        const vsize,
+                        int32         const pratio, 
+                        int32         const pict_rate, 
+                        int32         const bit_rate_arg,
+                        int32         const buf_size_arg, 
+                        int32         const c_param_flag_arg, 
+                        const int32 * const iq_matrix, 
+                        const int32 * const niq_matrix,
+                        uint8 *       const ext_data, 
+                        int32         const ext_data_size, 
+                        uint8 *       const user_data,
+                        int32         const user_data_size) {
+
+    extern int ZAG[];
+    int i;
+    int32 bit_rate;
+    int32 buf_size;
+    int32 c_param_flag;
+
+    /* Write seq start code. */
+
+    Bitio_Write(bbPtr, SEQ_HEAD_CODE, 32);
+
+    /* Write horiz. and vert. sizes. */
+
+#ifdef BLEAH
+    fprintf(stdout, "hsize, vsize = %d, %d\n", hsize, vsize);
+#endif
+
+    if (hsize==0 || vsize==0) {
+        fprintf(stderr, "Writing zero size to stream!\n");
+    }
+    Bitio_Write(bbPtr, hsize, 12);
+    Bitio_Write(bbPtr, vsize, 12);
+
+    /* Write pixel aspect ratio, negative values default to 1. */
+
+    if (pratio < 0) {
+        fprintf(stderr, "PROGRAMMER ERROR:  pratio = %d\n", pratio);
+        exit(1);
+    }
+    Bitio_Write(bbPtr, pratio, 4);
+
+    /* Wrtie picture rate, negative values default to 30 fps. */
+
+    if (pict_rate < 0) {
+        fprintf(stderr, "PROGRAMMER ERROR:  pict_rate = %d\n", pict_rate);
+        exit(1);
+    }
+    Bitio_Write(bbPtr, pict_rate, 4);
+
+    /* Write bit rate, negative values default to variable. */
+
+    if (bit_rate_arg < 0) {
+        bit_rate = -1;
+    } else {
+        bit_rate = bit_rate_arg / 400;
+    }
+
+    Bitio_Write(bbPtr, bit_rate, 18);
+
+    /* Marker bit. */
+    Bitio_Write(bbPtr, 0x1, 1);
+
+    /* Write VBV buffer size. Negative values default to zero. */
+    if (buf_size_arg < 0)
+        buf_size = 0;
+    else
+        buf_size = buf_size_arg;
+
+    buf_size = (buf_size + (16*1024 - 1)) / (16*1024);
+    if (buf_size>=0x400) 
+        buf_size=0x3ff;
+    Bitio_Write(bbPtr, buf_size, 10);
+
+    /* Write constrained parameter flag. */
+    {
+        int num_mb = ((hsize+15)/16) * ((vsize+15)/16);
+        /* At present we cheat on buffer size */
+        c_param_flag = ((bit_rate <= 4640) &&
+                        (bit_rate >0) &&
+                        (buf_size <= 20) &&
+                        (pict_rate >= 1) &&
+                        (pict_rate <= 5) &&
+                        (hsize <= 768) &&
+                        (vsize <= 576) &&
+                        (num_mb <= 396) &&
+                        (num_mb*VidRateNum[pict_rate] <= 9900) &&
+                        (fCodeP<=4) &&
+                        (fCodeB<=4));
+    }
+
+    if (c_param_flag) {
+        Bitio_Write(bbPtr, 0x01, 1);
+    } else {
+        Bitio_Write(bbPtr, 0x00, 1);
+    }
+
+    /* Write intra quant matrix if present. */
+
+    if (iq_matrix != NULL) {
+        Bitio_Write(bbPtr, 0x01, 1);
+        for (i = 0; i < 64; i++) {
+            Bitio_Write(bbPtr, iq_matrix[ZAG[i]], 8);
+        }
+    } else {
+        Bitio_Write(bbPtr, 0x00, 1);
+    }
+
+    /* Write non intra quant matrix if present. */
+
+    if (niq_matrix != NULL) {
+        Bitio_Write(bbPtr, 0x01, 1);
+        for (i = 0; i < 64; i++) {
+            Bitio_Write(bbPtr, niq_matrix[ZAG[i]], 8);
+        }
+    } else {
+        Bitio_Write(bbPtr, 0x00, 1);
+    }
+
+    /* next start code */
+    Bitio_BytePad(bbPtr);
+
+
+    /* Write ext data if present. */
+
+    if (ext_data != NULL) {
+        Bitio_Write(bbPtr, EXT_START_CODE, 32);
+
+        for (i = 0; i < ext_data_size; i++) {
+            Bitio_Write(bbPtr, ext_data[i], 8);
+        }
+        Bitio_BytePad(bbPtr);
+    }
+    /* Write user data if present. */
+    if ((user_data != NULL) && (user_data_size != 0)) {
+        Bitio_Write(bbPtr, USER_START_CODE, 32);
+
+        for (i = 0; i < user_data_size; i++) {
+            Bitio_Write(bbPtr, user_data[i], 8);
+        }
+        Bitio_BytePad(bbPtr);
+    }
+}
+
+
+/*===========================================================================*
+ *
+ * Mhead_GenSequenceEnder
+ *
+ *	generate sequence ender
+ *	append result to the specified bitstream
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+Mhead_GenSequenceEnder(bbPtr)
+    BitBucket *bbPtr;
+{
+    Bitio_Write(bbPtr, SEQ_END_CODE, 32);
+}
+
+
+/*===========================================================================*
+ *
+ * Mhead_GenGOPHeader
+ *
+ *	generate GOP header with specified attributes
+ *	append result to the specified bitstream
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+Mhead_GenGOPHeader(bbPtr, drop_frame_flag, tc_hrs, tc_min, tc_sec, tc_pict,
+		   closed_gop, broken_link, ext_data, ext_data_size,
+		   user_data, user_data_size)
+    BitBucket *bbPtr;
+    int32 drop_frame_flag;
+    int32 tc_hrs;
+    int32 tc_min;
+    int32 tc_sec;
+    int32 tc_pict;
+    int32 closed_gop;
+    int32 broken_link;
+    uint8 *ext_data;
+    int32 ext_data_size;
+    uint8 *user_data;
+    int32 user_data_size;
+{
+    int i;
+
+    /* Write gop start code. */
+    Bitio_Write(bbPtr, GOP_START_CODE, 32);
+
+		/* Construct and write timecode. */
+
+    /* Drop frame flag. */
+    if (drop_frame_flag) {
+	Bitio_Write(bbPtr, 0x01, 1);
+    } else {
+	Bitio_Write(bbPtr, 0x00, 1);
+    }
+
+    /* Time code hours. */
+    Bitio_Write(bbPtr, tc_hrs, 5);
+
+    /* Time code minutes. */
+    Bitio_Write(bbPtr, tc_min, 6);
+
+    /* Marker bit. */
+    Bitio_Write(bbPtr, 0x01, 1);
+
+    /* Time code seconds. */
+    Bitio_Write(bbPtr, tc_sec, 6);
+
+    /* Time code pictures. */
+    Bitio_Write(bbPtr, tc_pict, 6);
+
+
+    /* Closed gop flag. */
+    if (closed_gop) {
+	Bitio_Write(bbPtr, 0x01, 1);
+    } else {
+	Bitio_Write(bbPtr, 0x00, 1);
+    }
+
+    /* Broken link flag. */
+    if (broken_link) {
+	Bitio_Write(bbPtr, 0x01, 1);
+    } else {
+	Bitio_Write(bbPtr, 0x00, 1);
+    }
+
+    /* next start code */
+    Bitio_BytePad(bbPtr);
+
+    /* Write ext data if present. */
+
+    if (ext_data != NULL) {
+	Bitio_Write(bbPtr, EXT_START_CODE, 32);
+
+	for (i = 0; i < ext_data_size; i++) {
+	    Bitio_Write(bbPtr, ext_data[i], 8);
+	}
+	Bitio_BytePad(bbPtr);
+    }
+    /* Write user data if present. */
+    if (user_data != NULL) {
+	Bitio_Write(bbPtr, USER_START_CODE, 32);
+
+	for (i = 0; i < user_data_size; i++) {
+	    Bitio_Write(bbPtr, user_data[i], 8);
+	}
+	Bitio_BytePad(bbPtr);
+    }
+}
+
+
+/*===========================================================================*
+ *
+ * Mhead_GenSliceHeader
+ *
+ *	generate slice header with specified attributes
+ *	append result to the specified bitstream
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+Mhead_GenSliceHeader(bbPtr, verticalPos, qscale, extra_info, extra_info_size)
+    BitBucket *bbPtr;
+    uint32 verticalPos;
+    uint32 qscale;
+    uint8 *extra_info;
+    uint32 extra_info_size;
+{
+    int i;
+
+    /* Write slice start code. */
+    Bitio_Write(bbPtr, (SLICE_BASE_CODE + verticalPos), 32);
+
+    /* Quant. scale. */
+    Bitio_Write(bbPtr, qscale, 5);
+    lastQSSet = qscale;
+
+    /* Extra bit slice info. */
+
+    if (extra_info != NULL) {
+	for (i = 0; i < extra_info_size; i++) {
+	    Bitio_Write(bbPtr, 0x01, 1);
+	    Bitio_Write(bbPtr, extra_info[i], 8);
+	}
+    }
+
+    /* extra_bit_slice */
+    Bitio_Write(bbPtr, 0x00, 1);
+}
+
+
+/*===========================================================================*
+ *
+ * Mhead_GenSliceEnder
+ *
+ *	generate slice ender
+ *	append result to the specified bitstream
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+Mhead_GenSliceEnder(bbPtr)
+    BitBucket *bbPtr;
+{
+    Bitio_BytePad(bbPtr);
+}
+
+
+/*===========================================================================*
+ *
+ * Mhead_GenMBHeader
+ *
+ *	generate macroblock header with given attributes
+ *	append result to the specified bitstream
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+Mhead_GenMBHeader(bbPtr, pict_code_type, addr_incr, q_scale,
+		  forw_f_code, back_f_code, horiz_forw_r, vert_forw_r,
+		  horiz_back_r, vert_back_r, motion_forw, m_horiz_forw,
+		  m_vert_forw, motion_back, m_horiz_back, m_vert_back,
+		  mb_pattern, mb_intra)
+    BitBucket *bbPtr;
+    uint32 pict_code_type;
+    uint32 addr_incr;
+    uint32 q_scale;
+    uint32 forw_f_code;
+    uint32 back_f_code;
+    uint32 horiz_forw_r;
+    uint32 vert_forw_r;
+    uint32 horiz_back_r;
+    uint32 vert_back_r;
+    int32 motion_forw;
+    int32 m_horiz_forw;
+    int32 m_vert_forw;
+    int32 motion_back;
+    int32 m_horiz_back;
+    int32 m_vert_back;
+    uint32 mb_pattern;
+    uint32 mb_intra;
+{
+    uint32 mb_quant;
+
+    /* MB escape sequences if necessary. */
+
+#ifdef BLEAH
+if ( addr_incr != 1 )
+    fprintf(stdout, "Creating MB_INCR:  %d\n", addr_incr);
+#endif
+
+    while (addr_incr > 33) {
+	Bitio_Write(bbPtr, 0x008, 11);
+	addr_incr -= 33;
+    }
+
+    /* Generate addr incr code. */
+    GenMBAddrIncr(bbPtr, addr_incr);
+
+    /* Determine mb_quant  (true if change in q scale) */
+    if ((q_scale != lastQSSet) && ((mb_pattern != 0) || (mb_intra == TRUE))) {
+      mb_quant = TRUE;
+      lastQSSet = q_scale;
+    } else {
+      mb_quant = FALSE;
+    }
+
+    /* Generate mb type code. */
+    GenMBType(bbPtr, pict_code_type, mb_quant, motion_forw, motion_back, mb_pattern, mb_intra);
+
+    /* MB quant. */
+    if (mb_quant) {
+	Bitio_Write(bbPtr, q_scale, 5);
+    }
+    /* Forward predictive vector stuff. */
+
+    if (motion_forw) {
+	int forw_f, forw_r_size;
+
+	forw_r_size = forw_f_code - 1;
+	forw_f = 1 << forw_r_size;	/* 1 > 0 */
+	if ((m_horiz_forw > 16*forw_f-1) || (m_horiz_forw < -16*forw_f)) {
+	  fprintf(stderr, "Illegal motion? %d %d\n", m_horiz_forw, 16*forw_f);
+	}
+	if ((m_vert_forw > 16*forw_f-1) || (m_vert_forw < -16*forw_f)) {
+	  fprintf(stderr, "Illegal motion? %d %d\n", m_vert_forw, 16*forw_f);
+	}
+	GenMotionCode(bbPtr, m_horiz_forw);
+
+	if ((forw_f != 1) && (m_horiz_forw != 0)) {
+	    Bitio_Write(bbPtr, horiz_forw_r, forw_r_size);
+	}
+	GenMotionCode(bbPtr, m_vert_forw);
+
+	if ((forw_f != 1) && (m_vert_forw != 0)) {
+	    Bitio_Write(bbPtr, vert_forw_r, forw_r_size);
+	}
+    }
+    /* Back predicted vector stuff. */
+
+    if (motion_back) {
+	int back_f, back_r_size;
+
+	back_r_size = back_f_code - 1;
+	back_f = 1 << back_r_size;	/* 1 > 0 */
+
+	if ((m_horiz_back > 16*back_f-1) || (m_horiz_back < -16*back_f)) {
+	  fprintf(stderr, "Illegal motion? %d %d\n", m_horiz_back, 16*back_f);
+	}
+	if ((m_vert_back > 16*back_f-1) || (m_vert_back < -16*back_f)) {
+	  fprintf(stderr, "Illegal motion? %d %d\n", m_vert_back, 16*back_f);
+	}
+
+	GenMotionCode(bbPtr, m_horiz_back);
+
+	if ((back_f != 1) && (m_horiz_back != 0)) {
+	    Bitio_Write(bbPtr, horiz_back_r, back_r_size);
+	}
+	GenMotionCode(bbPtr, m_vert_back);
+
+	if ((back_f != 1) && (m_vert_back != 0)) {
+	    Bitio_Write(bbPtr, vert_back_r, back_r_size);
+	}
+    }
+    /* MB pattern. */
+
+    if (mb_pattern) {
+	GenBlockPattern(bbPtr, mb_pattern);
+    }
+}
+
+
+/*=====================*
+ * INTERNAL PROCEDURES *
+ *=====================*/
+
+/*===========================================================================*
+ *
+ * GenMBType
+ *
+ *	generate macroblock type with given attributes
+ *	append result to the specified bitstream
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+GenMBType(bbPtr, pict_code_type, mb_quant, motion_forw, motion_back,
+	  mb_pattern, mb_intra)
+    BitBucket *bbPtr;
+    uint32 pict_code_type;
+    uint32 mb_quant;
+    uint32 motion_forw;
+    uint32 motion_back;
+    uint32 mb_pattern;
+    uint32 mb_intra;
+{
+    int code;
+
+    switch (pict_code_type) {
+    case 1:
+	if ((motion_forw != 0) || (motion_back != 0) || (mb_pattern != 0) || (mb_intra != 1)) {
+	    perror("Illegal parameters for macroblock type.");
+	    exit(-1);
+	}
+	if (mb_quant) {
+	    Bitio_Write(bbPtr, 0x1, 2);
+	} else {
+	    Bitio_Write(bbPtr, 0x1, 1);
+	}
+	break;
+
+    case 2:
+	code = 0;
+	if (mb_quant) {
+	    code += 16;
+	}
+	if (motion_forw) {
+	    code += 8;
+	}
+	if (motion_back) {
+	    code += 4;
+	}
+	if (mb_pattern) {
+	    code += 2;
+	}
+	if (mb_intra) {
+	    code += 1;
+	}
+
+	switch (code) {
+	case 1:
+	    Bitio_Write(bbPtr, 0x3, 5);
+	    break;
+	case 2:
+	    Bitio_Write(bbPtr, 0x1, 2);
+	    break;
+	case 8:
+	    Bitio_Write(bbPtr, 0x1, 3);
+	    break;
+	case 10:
+	    Bitio_Write(bbPtr, 0x1, 1);
+	    break;
+	case 17:
+	    Bitio_Write(bbPtr, 0x1, 6);
+	    break;
+	case 18:
+	    Bitio_Write(bbPtr, 0x1, 5);
+	    break;
+	case 26:
+	    Bitio_Write(bbPtr, 0x2, 5);
+	    break;
+	default:
+	    perror("Illegal parameters for macroblock type.");
+	    exit(-1);
+	    break;
+	}
+	break;
+
+    case 3:
+	code = 0;
+	if (mb_quant) {
+	    code += 16;
+	}
+	if (motion_forw) {
+	    code += 8;
+	}
+	if (motion_back) {
+	    code += 4;
+	}
+	if (mb_pattern) {
+	    code += 2;
+	}
+	if (mb_intra) {
+	    code += 1;
+	}
+
+	switch (code) {
+	case 12:
+	    Bitio_Write(bbPtr, 0x2, 2);
+	    break;
+	case 14:
+	    Bitio_Write(bbPtr, 0x3, 2);
+	    break;
+	case 4:
+	    Bitio_Write(bbPtr, 0x2, 3);
+	    break;
+	case 6:
+	    Bitio_Write(bbPtr, 0x3, 3);
+	    break;
+	case 8:
+	    Bitio_Write(bbPtr, 0x2, 4);
+	    break;
+	case 10:
+	    Bitio_Write(bbPtr, 0x3, 4);
+	    break;
+	case 1:
+	    Bitio_Write(bbPtr, 0x3, 5);
+	    break;
+	case 30:
+	    Bitio_Write(bbPtr, 0x2, 5);
+	    break;
+	case 26:
+	    Bitio_Write(bbPtr, 0x3, 6);
+	    break;
+	case 22:
+	    Bitio_Write(bbPtr, 0x2, 6);
+	    break;
+	case 17:
+	    Bitio_Write(bbPtr, 0x1, 6);
+	    break;
+	default:
+	    perror("Illegal parameters for macroblock type.");
+	    exit(-1);
+	    break;
+	}
+	break;
+    }
+}
+
+
+/*===========================================================================*
+ *
+ * GenMotionCode
+ *
+ *	generate motion vector output with given value
+ *	append result to the specified bitstream
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+GenMotionCode(BitBucket * const bbPtr,
+              int32       const vector) {
+
+    uint32 code, num;
+
+    if ((vector < -16) || (vector > 16)) {
+	perror("Motion vector out of range.");
+	fprintf(stderr, "Motion vector out of range:  vector = %d\n", vector);
+	exit(-1);
+    }
+    code = mbMotionVectorTable[vector + 16][0];
+    num = mbMotionVectorTable[vector + 16][1];
+
+    Bitio_Write(bbPtr, code, num);
+}
+
+
+/*===========================================================================*
+ *
+ * GenBlockPattern
+ *
+ *	generate macroblock pattern output
+ *	append result to the specified bitstream
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+GenBlockPattern(bbPtr, mb_pattern)
+    BitBucket *bbPtr;
+    uint32 mb_pattern;
+{
+    uint32 code, num;
+
+    code = mbPatTable[mb_pattern][0];
+    num = mbPatTable[mb_pattern][1];
+
+    Bitio_Write(bbPtr, code, num);
+}
+
+
+/*===========================================================================*
+ *
+ * GenMBAddrIncr
+ *
+ *	generate macroblock address increment output
+ *	append result to the specified bitstream
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+GenMBAddrIncr(bbPtr, addr_incr)
+    BitBucket *bbPtr;
+    uint32 addr_incr;
+{
+    uint32 code;
+    uint32 num;
+
+    code = mbAddrIncrTable[addr_incr][0];
+    num = mbAddrIncrTable[addr_incr][1];
+
+    Bitio_Write(bbPtr, code, num);
+}
+
+
+/*===========================================================================*
+ *
+ * GenPictHead
+ *
+ *	generate picture header with given attributes
+ *	append result to the specified bitstream
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+GenPictHead(bbPtr, temp_ref, code_type, vbv_delay, full_pel_forw_flag,
+	    forw_f_code, full_pel_back_flag, back_f_code, extra_info,
+	    extra_info_size, ext_data, ext_data_size, user_data,
+	    user_data_size)
+    BitBucket *bbPtr;
+    uint32 temp_ref;
+    uint32 code_type;
+    uint32 vbv_delay;
+    int32 full_pel_forw_flag;
+    uint32 forw_f_code;
+    int32 full_pel_back_flag;
+    uint32 back_f_code;
+    uint8 *extra_info;
+    uint32 extra_info_size;
+    uint8 *ext_data;
+    uint32 ext_data_size;
+    uint8 *user_data;
+    uint32 user_data_size;
+{
+    int i;
+
+    /* Write picture start code. */
+    Bitio_Write(bbPtr, PICT_START_CODE, 32);
+
+    /* Temp reference. */
+    Bitio_Write(bbPtr, temp_ref, 10);
+
+    /* Code_type. */
+    if (code_type == 0) {
+	code_type = 1;
+    }
+    Bitio_Write(bbPtr, code_type, 3);
+
+    /* vbv_delay. */
+    vbv_delay = 0xffff;		    /* see page 36 (section 2.4.3.4) */
+    Bitio_Write(bbPtr, vbv_delay, 16);
+
+    if ((code_type == 2) || (code_type == 3)) {
+
+	/* Full pel forw flag. */
+
+	if (full_pel_forw_flag) {
+	    Bitio_Write(bbPtr, 0x01, 1);
+	} else {
+	    Bitio_Write(bbPtr, 0x00, 1);
+	}
+
+	/* Forw f code. */
+
+	Bitio_Write(bbPtr, forw_f_code, 3);
+    }
+    if (code_type == 3) {
+
+	/* Full pel back flag. */
+
+	if (full_pel_back_flag) {
+	    Bitio_Write(bbPtr, 0x01, 1);
+	} else {
+	    Bitio_Write(bbPtr, 0x00, 1);
+	}
+
+	/* Back f code. */
+
+	Bitio_Write(bbPtr, back_f_code, 3);
+    }
+    /* Extra bit picture info. */
+
+    if (extra_info != NULL) {
+	for (i = 0; i < extra_info_size; i++) {
+	    Bitio_Write(bbPtr, 0x01, 1);
+	    Bitio_Write(bbPtr, extra_info[i], 8);
+	}
+    }
+    Bitio_Write(bbPtr, 0x00, 1);
+
+    /* next start code */
+    Bitio_BytePad(bbPtr);
+
+    /* Write ext data if present. */
+
+    if (ext_data != NULL) {
+	Bitio_Write(bbPtr, EXT_START_CODE, 32);
+
+	for (i = 0; i < ext_data_size; i++) {
+	    Bitio_Write(bbPtr, ext_data[i], 8);
+	}
+	Bitio_BytePad(bbPtr);
+    }
+    /* Write user data if present. */
+    if (user_data != NULL) {
+	Bitio_Write(bbPtr, USER_START_CODE, 32);
+
+	for (i = 0; i < user_data_size; i++) {
+	    Bitio_Write(bbPtr, user_data[i], 8);
+	}
+	Bitio_BytePad(bbPtr);
+    }
+}
+
+
+#ifdef UNUSED_PROCEDURES
+
+/* GenMBEnd only used for `D` pictures. Shouldn't really ever be called. */
+/* - dwallach */
+void
+GenMBEnd(bbPtr)
+    BitBucket *bbPtr;
+{
+    Bitio_Write(bbPtr, 0x01, 1);
+}
+
+#endif /* UNUSED_PROCEDURES */
diff --git a/converter/ppm/ppmtompeg/moutput.c b/converter/ppm/ppmtompeg/moutput.c
new file mode 100644
index 00000000..b682efab
--- /dev/null
+++ b/converter/ppm/ppmtompeg/moutput.c
@@ -0,0 +1,442 @@
+/*===========================================================================*
+ * moutput.c								     *
+ *									     *
+ *	Procedures concerned with quantization and RLE			     *
+ *									     *
+ * EXPORTED PROCEDURES:							     *
+ *	mp_quant_zig_block						     *
+ *	mp_rle_huff_block						     *
+ *	mp_rle_huff_pblock						     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*
+ *  $Header: /n/charlie-brown/project/mm/mpeg/mpeg_dist/mpeg_encode/RCS/moutput.c,v 1.12 1995/01/19 23:08:49 eyhung Exp $
+ *  $Log: moutput.c,v $
+ * Revision 1.12  1995/01/19  23:08:49  eyhung
+ * Changed copyrights
+ *
+ * Revision 1.11  1993/07/22  22:23:43  keving
+ * nothing
+ *
+ * Revision 1.10  1993/06/30  20:06:09  keving
+ * nothing
+ *
+ * Revision 1.9  1993/06/03  21:08:08  keving
+ * nothing
+ *
+ * Revision 1.8  1993/02/24  18:57:19  keving
+ * nothing
+ *
+ * Revision 1.7  1993/02/23  22:58:36  keving
+ * nothing
+ *
+ * Revision 1.6  1993/02/23  22:54:56  keving
+ * nothing
+ *
+ * Revision 1.5  1993/02/17  23:18:20  dwallach
+ * checkin prior to keving's joining the project
+ *
+ * Revision 1.4  1993/01/18  10:20:02  dwallach
+ * *** empty log message ***
+ *
+ * Revision 1.3  1993/01/18  10:17:29  dwallach
+ * RCS headers installed, code indented uniformly
+ *
+ * Revision 1.3  1993/01/18  10:17:29  dwallach
+ * RCS headers installed, code indented uniformly
+ *
+ */
+
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "all.h"
+#include "mtypes.h"
+#include "mproto.h"
+#include "huff.h"
+
+
+/*==================*
+ * STATIC VARIABLES *
+ *==================*/
+
+/* ZAG[i] is the natural-order position of the i'th element of zigzag order. */
+static int ZAG[] =
+{
+    0, 1, 8, 16, 9, 2, 3, 10,
+    17, 24, 32, 25, 18, 11, 4, 5,
+    12, 19, 26, 33, 40, 48, 41, 34,
+    27, 20, 13, 6, 7, 14, 21, 28,
+    35, 42, 49, 56, 57, 50, 43, 36,
+    29, 22, 15, 23, 30, 37, 44, 51,
+    58, 59, 52, 45, 38, 31, 39, 46,
+    53, 60, 61, 54, 47, 55, 62, 63
+};
+
+
+/*
+ * possible optimization: reorder the qtable in the correct zigzag order, to
+ * reduce the number of necessary lookups
+ *
+ * this table comes from the MPEG draft, p. D-16, Fig. 2-D.15.
+ */
+static int qtable[] =
+{
+    8, 16, 19, 22, 26, 27, 29, 34,
+    16, 16, 22, 24, 27, 29, 34, 37,
+    19, 22, 26, 27, 29, 34, 34, 38,
+    22, 22, 26, 27, 29, 34, 37, 40,
+    22, 26, 27, 29, 32, 35, 40, 48,
+    26, 27, 29, 32, 35, 40, 48, 58,
+    26, 27, 29, 34, 38, 46, 56, 69,
+    27, 29, 35, 38, 46, 56, 69, 83};
+
+
+/*=====================*
+ * EXPORTED PROCEDURES *
+ *=====================*/
+
+
+void	UnQuantZig(FlatBlock in, Block out, int qscale, boolean iblock)
+{
+    register int index;
+    int	    start;
+    int	    position;
+    register int	    qentry;
+    int	    level, coeff;
+    register int16 temp;
+
+    if ( iblock )
+    {
+	((int16 *)out)[0] = (int16)(in[0]*qtable[0]);
+
+	start = 1;
+    }
+    else
+	start = 0;
+
+    for ( index = start; index < DCTSIZE_SQ; index++ )
+    {
+	position = ZAG[index];
+
+	if (iblock)
+	    qentry = qtable[position] * qscale;
+	else
+	    qentry = 16 * qscale;
+
+	level = in[index];
+        coeff = (level * qentry) >> 3;
+        if (level < 0) {
+            coeff += (coeff & 1);
+	} else {
+            coeff -= (coeff & 1);
+	}
+
+	((int16 *)out)[position] = coeff;
+    }
+
+#ifdef BLEAH
+    for ( index = 0; index < 64; index++ )
+	fprintf(stdout, "DCT[%d] = %d\n", index, 
+		((int16 *)out)[index]);
+#endif
+}
+
+
+/*
+ * --------------------------------------------------------------
+ *
+ * mp_quant_zig_block --
+ *
+ * Quantizes and zigzags a block -- removing information
+ *
+ * Results: TRUE iff resulting 'out' is non-zero, FALSE if all
+ *	    zero
+ *
+ * Side effects: Modifies the out block.
+ *
+ * --------------------------------------------------------------
+ */
+boolean mp_quant_zig_block(Block in, FlatBlock out, int qscale, int iblock)
+{
+    register int i;
+    register int y, x;
+    register int16 temp;
+    register int qentry;
+    int start;
+    boolean nonZero = FALSE;
+
+    DBG_PRINT(("mp_quant_zig_block...\n"));
+    if (iblock) {
+	/*
+	 * the DC coefficient is handled specially -- it's not
+	 * sensitive to qscale, but everything else is
+	 */
+	temp = ((int16 *) in)[ZAG[0]];
+	qentry = qtable[ZAG[0]];
+	if (temp < 0) {
+	    temp = -temp;
+	    temp += qentry >> 1;
+	    temp /= qentry;
+	    temp = -temp;
+	} else {
+	    temp += qentry >> 1;
+	    temp /= qentry;
+	}
+	if ( temp != 0 )
+	    nonZero = TRUE;
+	out[0] = temp;
+	start = 1;
+    } else
+	start = 0;
+
+    for (i = start; i < DCTSIZE_SQ; i++) {
+	x = ZAG[i] % 8;
+	y = ZAG[i] / 8;
+	temp = in[y][x];
+	DBG_PRINT(("    in[%d][%d] = %d;  ", y, x, temp));
+
+	if (iblock)
+	    qentry = qtable[ZAG[i]] * qscale;
+	else
+	    qentry = 16 * qscale;
+
+	DBG_PRINT(("quantized with %d = ", qentry));
+
+	if (temp < 0) {
+	    temp = -temp;
+	    temp *= 8;
+	    temp += qentry >> 1;
+	    temp /= qentry;
+	    temp = -temp;
+	} else {
+	    temp *= 8;
+	    temp += qentry >> 1;
+	    temp /= qentry;
+	}
+	if ( temp != 0 )
+	    nonZero = TRUE;
+	out[i] = temp;
+	DBG_PRINT(("%d\n", temp));
+    }
+
+    return nonZero;
+}
+
+
+
+/*
+ * --------------------------------------------------------------
+ *
+ * mp_rle_huff_block --
+ *
+ * Given a FlatBlock, generates the Huffman bits
+ *
+ * Results: None.
+ *
+ * Side effects: Output bits changed
+ *
+ * --------------------------------------------------------------
+ */
+
+void	mp_rle_huff_block(FlatBlock in, BitBucket *out)
+{
+    register int i;
+    register int nzeros = 0;
+    register int16 cur;
+    register int16 acur;
+    register uint32 code;
+    register int nbits;
+
+    /*
+     * yes, Virginia, we start at 1.  The DC coefficient is handled
+     * specially, elsewhere.  Not here.
+     */
+    for (i = 1; i < DCTSIZE_SQ; i++) {
+	cur = in[i];
+	acur = ABS(cur);
+	if (cur) {
+	    if (nzeros < HUFF_MAXRUN && acur < huff_maxlevel[nzeros]) {
+	        /*
+		 * encode using the Huffman tables
+		 */
+
+		DBG_PRINT(("rle_huff %02d: Run %02d, Level %02d\n", i, nzeros, cur));
+		assert(cur);
+
+		code = (huff_table[nzeros])[acur];
+		nbits = (huff_bits[nzeros])[acur];
+
+		assert(nbits);
+
+		if (cur < 0)
+		    code |= 1;	/* the sign bit */
+		Bitio_Write(out, code, nbits);
+	    } else {
+		/*
+		 * encode using the escape code
+		 */
+		DBG_PRINT(("Escape\n"));
+		Bitio_Write(out, 0x1, 6);	/* ESCAPE */
+		DBG_PRINT(("Run Length\n"));
+		Bitio_Write(out, nzeros, 6);	/* Run-Length */
+
+		assert(cur != 0);
+
+		/*
+	         * this shouldn't happen, but the other
+	         * choice is to bomb out and dump core...
+	         */
+		if (cur < -255)
+		    cur = -255;
+		else if (cur > 255)
+		    cur = 255;
+
+		DBG_PRINT(("Level\n"));
+		if (acur < 128) {
+		    Bitio_Write(out, cur, 8);
+		} else {
+		    if (cur < 0) {
+			Bitio_Write(out, 0x8001 + cur + 255, 16);
+		    } else
+			Bitio_Write(out, cur, 16);
+		}
+	    }
+	    nzeros = 0;
+	} else
+	    nzeros++;
+    }
+    DBG_PRINT(("End of block\n"));
+    Bitio_Write(out, 0x2, 2);	/* end of block marker */
+}
+
+
+/*
+ * --------------------------------------------------------------
+ *
+ * mp_rle_huff_pblock --
+ *
+ * Given a FlatBlock, generates the Huffman bits for P DCT
+ *
+ * Results: None.
+ *
+ * Side effects: Output bits changed
+ *
+ * --------------------------------------------------------------
+ */
+
+void	mp_rle_huff_pblock(FlatBlock in, BitBucket *out)
+{
+    register int i;
+    register int nzeros = 0;
+    register int16 cur;
+    register int16 acur;
+    register uint32 code;
+    register int nbits;
+    boolean first_dct = TRUE;
+
+    /*
+     * yes, Virginia, we start at 0.
+     */
+    for (i = 0; i < DCTSIZE_SQ; i++) {
+	cur = in[i];
+	acur = ABS(cur);
+	if (cur) {
+	    if (nzeros < HUFF_MAXRUN && acur < huff_maxlevel[nzeros]) {
+	        /*
+		 * encode using the Huffman tables
+		 */
+
+		DBG_PRINT(("rle_huff %02d: Run %02d, Level %02d\n", i, nzeros, cur));
+		assert(cur);
+
+		if ( first_dct && (nzeros == 0) && (acur == 1) )
+		{
+		    /* actually, only needs = 0x2 */
+		    code = (cur == 1) ? 0x2 : 0x3;
+		    nbits = 2;
+		}
+		else
+		{
+		    code = (huff_table[nzeros])[acur];
+		    nbits = (huff_bits[nzeros])[acur];
+		}
+
+		assert(nbits);
+
+		if (cur < 0)
+		    code |= 1;	/* the sign bit */
+		Bitio_Write(out, code, nbits);
+		first_dct = FALSE;
+	    } else {
+		/*
+		 * encode using the escape code
+		 */
+		DBG_PRINT(("Escape\n"));
+		Bitio_Write(out, 0x1, 6);	/* ESCAPE */
+		DBG_PRINT(("Run Length\n"));
+		Bitio_Write(out, nzeros, 6);	/* Run-Length */
+
+		assert(cur != 0);
+
+		/*
+	         * this shouldn't happen, but the other
+	         * choice is to bomb out and dump core...
+	         */
+		if (cur < -255)
+		    cur = -255;
+		else if (cur > 255)
+		    cur = 255;
+
+		DBG_PRINT(("Level\n"));
+		if (acur < 128) {
+		    Bitio_Write(out, cur, 8);
+		} else {
+		    if (cur < 0) {
+			Bitio_Write(out, 0x8001 + cur + 255, 16);
+		    } else
+			Bitio_Write(out, cur, 16);
+		}
+
+		first_dct = FALSE;
+	    }
+	    nzeros = 0;
+	} else
+	    nzeros++;
+    }
+
+    /* actually, should REALLY return FALSE and not use this! */
+    if ( first_dct )	/* have to give a first_dct even if all 0's */
+    {
+	fprintf(stdout, "HUFF called with all-zero coefficients\n");
+	fprintf(stdout, "exiting...\n");
+	exit(1);
+    }
+
+    DBG_PRINT(("End of block\n"));
+    Bitio_Write(out, 0x2, 2);	/* end of block marker */
+}
diff --git a/converter/ppm/ppmtompeg/mpeg.c b/converter/ppm/ppmtompeg/mpeg.c
new file mode 100644
index 00000000..a934ed09
--- /dev/null
+++ b/converter/ppm/ppmtompeg/mpeg.c
@@ -0,0 +1,1717 @@
+/*===========================================================================*
+ * mpeg.c
+ *
+ *  Procedures to generate the MPEG sequence
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#define _BSD_SOURCE   /* Make sure strdup() is in string.h */
+
+#include "all.h"
+#include <time.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <string.h>
+#ifdef MIPS
+#include <sys/types.h>
+#endif
+#include <sys/stat.h>
+
+#include "ppm.h"
+#include "nstring.h"
+
+#include "mtypes.h"
+#include "frames.h"
+#include "motion_search.h"
+#include "prototypes.h"
+#include "parallel.h"
+#include "param.h"
+#include "readframe.h"
+#include "fsize.h"
+#include "mheaders.h"
+#include "rate.h"
+#include "input.h"
+#include "frametype.h"
+#include "mpeg.h"
+
+
+/*===========*
+ *  VERSION  *
+ *===========*/
+
+#define VERSION "1.5b"
+
+
+/*===========*
+ * CONSTANTS *
+ *===========*/
+
+#define FPS_30  0x5   /* from MPEG standard sect. 2.4.3.2 */
+#define ASPECT_1    0x1 /* aspect ratio, from MPEG standard sect. 2.4.3.2 */
+
+
+/*==================*
+ * STATIC VARIABLES *
+ *==================*/
+
+static unsigned int framesOutput;
+static int      realStart, realEnd;
+static int  currentGOP;
+static int      timeMask;
+static int      numI, numP, numB;
+static boolean  frameCountsUnknown;
+
+
+/*==================*
+ * GLOBAL VARIABLES *   
+ *==================*/
+
+/* important -- don't initialize anything here */
+/* must be re-initted anyway in GenMPEGStream */
+
+extern int  IOtime;
+extern boolean  resizeFrame;
+extern int outputWidth, outputHeight;
+int     gopSize = 100;  /* default */
+int32       tc_hrs, tc_min, tc_sec, tc_pict, tc_extra;
+int     totalFramesSent;
+int     yuvWidth, yuvHeight;
+int     realWidth, realHeight;
+char        currentPath[MAXPATHLEN];
+char        statFileName[256];
+char        bitRateFileName[256];
+time_t      timeStart, timeEnd;
+FILE       *statFile;
+FILE       *bitRateFile = NULL;
+char       *framePattern;
+int     framePatternLen;
+int     referenceFrame;
+int     frameRate = FPS_30;
+int     frameRateRounded = 30;
+boolean     frameRateInteger = TRUE;
+int     aspectRatio = ASPECT_1;
+extern char userDataFileName[];
+extern int mult_seq_headers;
+
+int32 bit_rate, buf_size;
+
+/*===============================*
+ * INTERNAL PROCEDURE prototypes *
+ *===============================*/
+
+static void ComputeDHMSTime _ANSI_ARGS_((int32 someTime, char *timeText));
+static void OpenBitRateFile _ANSI_ARGS_((void));
+static void CloseBitRateFile _ANSI_ARGS_((void));
+
+
+static void
+ShowRemainingTime(boolean const childProcess) {
+/*----------------------------------------------------------------------------
+   Print out an estimate of the time left to encode
+-----------------------------------------------------------------------------*/
+
+    if (childProcess) {
+        /* nothing */;
+    } else if ( numI + numP + numB == 0 ) {
+        /* no time left */
+    } else if ( timeMask != 0 ) {   
+        /* haven't encoded all types yet */
+    } else {
+        static int  lastTime = 0;
+        float   total;
+        time_t  nowTime;
+        float   secondsPerFrame;
+        
+        time(&nowTime);
+        secondsPerFrame = (nowTime-timeStart)/(float)framesOutput;
+        total = secondsPerFrame*(float)(numI+numP+numB);
+
+        if ((quietTime >= 0) && (!realQuiet) && (!frameCountsUnknown) &&
+            ((lastTime < (int)total) || ((lastTime-(int)total) >= quietTime) ||
+             (lastTime == 0) || (quietTime == 0))) {
+            if (total > 270.0)
+                pm_message("ESTIMATED TIME OF COMPLETION:  %d minutes",
+                           ((int)total+30)/60);
+            else
+                pm_message("ESTIMATED TIME OF COMPLETION:  %d seconds",
+                           (int)total);
+        }
+        lastTime = (int)total;
+    }
+}
+
+
+
+static void
+initTCTime(unsigned int const firstFrameNumber) {
+
+    unsigned int frameNumber;
+    
+    tc_hrs = 0; tc_min = 0; tc_sec = 0; tc_pict = 0; tc_extra = 0;
+    for (frameNumber = 0; frameNumber < firstFrameNumber; ++frameNumber)
+        IncrementTCTime();
+}
+
+
+
+/*===========================================================================*
+ *
+ * IncrementTCTime
+ *
+ *  increment the tc time by one second (and update min, hrs if necessary)
+ *  also increments totalFramesSent
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    totalFramesSent, tc_pict, tc_sec, tc_min, tc_hrs, tc_extra
+ *
+ *===========================================================================*/
+void
+IncrementTCTime() {
+    /* if fps = an integer, then tc_extra = 0 and is ignored
+
+       otherwise, it is the number of extra 1/1001 frames we've passed by
+
+       so far; for example, if fps = 24000/1001, then 24 frames = 24024/24000
+       seconds = 1 second + 24/24000 seconds = 1 + 1/1000 seconds; similary,
+       if fps = 30000/1001, then 30 frames = 30030/30000 = 1 + 1/1000 seconds
+       and if fps = 60000/1001, then 60 frames = 1 + 1/1000 seconds
+
+       if fps = 24000/1001, then 1/1000 seconds = 24/1001 frames
+       if fps = 30000/1001, then 1/1000 seconds = 30/1001 frames
+       if fps = 60000/1001, then 1/1000 seconds = 60/1001 frames     
+     */
+
+    totalFramesSent++;
+    tc_pict++;
+    if ( tc_pict >= frameRateRounded ) {
+        tc_pict = 0;
+        tc_sec++;
+        if ( tc_sec == 60 ) {
+            tc_sec = 0;
+            tc_min++;
+            if ( tc_min == 60 ) {
+                tc_min = 0;
+                tc_hrs++;
+            }
+        }
+        if ( ! frameRateInteger ) {
+            tc_extra += frameRateRounded;
+            if ( tc_extra >= 1001 ) {   /* a frame's worth */
+                tc_pict++;
+                tc_extra -= 1001;
+            }
+        }
+    }
+}
+
+
+
+static void
+initializeRateControl(bool const wantUnderflowWarning,
+                      bool const wantOverflowWarning) {
+/*----------------------------------------------------------------------------
+   Initialize rate control
+-----------------------------------------------------------------------------*/
+    int32 const bitstreamMode = getRateMode();
+
+    if (bitstreamMode == FIXED_RATE) {
+        initRateControl(wantUnderflowWarning, wantOverflowWarning);
+        /*
+          SetFrameRate();
+        */
+    }
+}
+    
+
+
+/*===========================================================================*
+ *
+ * SetReferenceFrameType
+ *
+ *  set the reference frame type to be original or decoded
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    referenceFrame
+ *
+ *===========================================================================*/
+void
+SetReferenceFrameType(const char * const type) {
+
+    if (strcmp(type, "ORIGINAL") == 0)
+        referenceFrame = ORIGINAL_FRAME;
+    else if ( strcmp(type, "DECODED") == 0 )
+        referenceFrame = DECODED_FRAME;
+    else
+        pm_error("INTERNAL ERROR: Illegal reference frame type: '%s'", type);
+}
+
+
+
+void
+SetBitRateFileName(fileName)
+    char *fileName;
+{
+    strcpy(bitRateFileName, fileName);
+}
+
+
+
+
+static void
+finishFrameOutput(MpegFrame * const frameP,
+                  BitBucket * const bbP,
+                  boolean     const separateFiles,
+                  int         const referenceFrame,
+                  boolean     const childProcess,
+                  boolean     const remoteIO) {
+
+    if ((referenceFrame == DECODED_FRAME) && 
+        childProcess && NonLocalRefFrame(frameP->id)) {
+        if (remoteIO)
+            SendDecodedFrame(frameP);
+        else
+            WriteDecodedFrame(frameP);
+            
+        NotifyDecodeServerReady(frameP->id);
+    }
+    
+    if (separateFiles) {
+        if (remoteIO)
+            SendRemoteFrame(frameP->id, bbP);
+        else {
+            Bitio_Flush(bbP);
+            Bitio_Close(bbP);
+        }
+    }
+}
+
+    
+
+
+static void
+outputIFrame(MpegFrame * const frameP,
+             BitBucket * const bb,
+             int         const realStart,
+             int         const realEnd,
+             MpegFrame * const pastRefFrameP,
+             boolean     const separateFiles) {
+      
+    /* only start a new GOP with I */
+    /* don't start GOP if only doing frames */
+    if ((!separateFiles) && (currentGOP >= gopSize)) {
+        boolean const closed = 
+            (totalFramesSent == frameP->id || pastRefFrameP == NULL);
+
+        static int num_gop = 0;
+    
+        /* first, check to see if closed GOP */
+    
+        /* new GOP */
+        if (num_gop != 0 && mult_seq_headers && 
+            num_gop % mult_seq_headers == 0) {
+            if (!realQuiet) {
+                fprintf(stdout, 
+                        "Creating new Sequence before GOP %d\n", num_gop);
+                fflush(stdout);
+            }
+      
+            Mhead_GenSequenceHeader(
+                bb, Fsize_x, Fsize_y,
+                /* pratio */    aspectRatio,
+                /* pict_rate */ frameRate, /* bit_rate */ bit_rate,
+                /* buf_size */  buf_size,  /* c_param_flag */ 1,
+                /* iq_matrix */ customQtable, 
+                /* niq_matrix */ customNIQtable,
+                /* ext_data */ NULL,  /* ext_data_size */ 0,
+                /* user_data */ NULL, /* user_data_size */ 0);
+        }
+    
+        if (!realQuiet)
+            pm_message("Creating new GOP (closed = %s) before frame %d\n",
+                       closed ? "YES" : "NO", frameP->id);
+    
+        ++num_gop;
+        Mhead_GenGOPHeader(bb,  /* drop_frame_flag */ 0,
+                           tc_hrs, tc_min, tc_sec, tc_pict,
+                           closed, /* broken_link */ 0,
+                           /* ext_data */ NULL, /* ext_data_size */ 0,
+                           /* user_data */ NULL, /* user_data_size */ 0);
+        currentGOP -= gopSize;
+        if (pastRefFrameP == NULL)
+            SetGOPStartTime(0);
+        else
+            SetGOPStartTime(pastRefFrameP->id+1);
+    }
+      
+    if ((frameP->id >= realStart) && (frameP->id <= realEnd))
+        GenIFrame(bb, frameP);
+      
+    numI--;
+    timeMask &= 0x6;
+      
+    currentGOP++;
+    IncrementTCTime();
+}
+
+
+
+static void
+outputPFrame(MpegFrame * const frameP,
+             BitBucket * const bbP,
+             int         const realStart,
+             int         const realEnd,
+             MpegFrame * const pastRefFrameP) {
+
+    if ((frameP->id >= realStart) && (frameP->id <= realEnd))
+        GenPFrame(bbP, frameP, pastRefFrameP);
+
+    numP--;
+    timeMask &= 0x5;
+    
+    currentGOP++;
+    IncrementTCTime();
+}
+
+
+
+static BitBucket *
+bitioNew(const char * const outputFileName,
+         unsigned int const frameNumber,
+         boolean      const remoteIO) {
+
+    BitBucket * bbP;
+
+    if (remoteIO)
+        bbP = Bitio_New(NULL);
+    else {
+        const char * fileName;
+
+        asprintfN(&fileName, "%s.frame.%d", outputFileName, frameNumber);
+
+        bbP = Bitio_New_Filename(fileName);
+
+        strfree(fileName);
+    }
+    return bbP;
+}
+
+
+
+static void
+getBFrame(int                  const frameNum,
+          struct inputSource * const inputSourceP,
+          MpegFrame *          const pastRefFrameP,
+          boolean              const childProcess,
+          boolean              const remoteIO,
+          MpegFrame **         const bFramePP,
+          int *                const IOtimeP,
+          unsigned int *       const framesReadP) {
+/*----------------------------------------------------------------------------
+   Get Frame 'frameNum', which is a B frame related to previous reference
+   frame 'pastRefFrameP'.  Return it as *bFramePP.
+
+   We have various ways of getting the frame, corresponding to the
+   multitude of modes in which Ppmtompeg works.
+-----------------------------------------------------------------------------*/
+    if (!inputSourceP->stdinUsed) {
+        time_t tempTimeStart, tempTimeEnd;
+        MpegFrame * bFrameP;
+        bool endOfStream;
+
+        bFrameP = Frame_New(frameNum, 'b');
+
+        time(&tempTimeStart);
+
+        ReadNthFrame(inputSourceP, frameNum, remoteIO, childProcess,
+                     separateConversion, slaveConversion, inputConversion,
+                     bFrameP, &endOfStream);
+
+        assert(!endOfStream);  /* Because it's not a stream */
+
+        time(&tempTimeEnd);
+        *IOtimeP += (tempTimeEnd-tempTimeStart);
+
+        ++(*framesReadP);
+        *bFramePP = bFrameP;
+    } else {
+        /* As the frame input is serial, we can't read the B frame now.
+           Rather, Caller has already read it and chained it to 
+           the previous reference frame.  So we get that copy now.
+        */
+        *bFramePP = pastRefFrameP->next;
+        pastRefFrameP->next = (*bFramePP)->next;  /* unlink from list */
+    }
+}
+
+
+
+static void
+processBFrames(MpegFrame *          const pastRefFrameP,
+               MpegFrame *          const futureRefFrameP,
+               int                  const realStart,
+               int                  const realEnd,
+               struct inputSource * const inputSourceP,
+               boolean              const remoteIo,
+               boolean              const childProcess,
+               int *                const IOtimeP,
+               BitBucket *          const wholeStreamBbP,
+               const char *         const outputFileName,
+               unsigned int *       const framesReadP,
+               unsigned int *       const framesOutputP,
+               int *                const currentGopP) {
+/*----------------------------------------------------------------------------
+   Process the B frames that go between 'pastRefFrameP' and
+   'futureRefFrame' in the movie (but go after 'futureRefFrameP' in the
+   MPEG stream, so reader doesn't have to read ahead).
+
+   Remember that a B frame is one which is described by data in the
+   MPEG stream that describes the frame with respect to a frame somewhere
+   before it, and a frame somewhere after it (i.e. reference frames).
+
+   But do only those B frames whose frame numbers are within the range
+   'realStart' through 'realEnd'.
+-----------------------------------------------------------------------------*/
+    boolean const separateFiles = (wholeStreamBbP == NULL);
+    unsigned int const firstBFrameNum = pastRefFrameP->id + 1;
+
+    int frameNum;
+
+    assert(pastRefFrameP != NULL);
+    assert(futureRefFrameP != NULL);
+    
+    for (frameNum = MAX(realStart, firstBFrameNum); 
+         frameNum < MIN(realEnd, futureRefFrameP->id); 
+         ++frameNum) {
+
+        MpegFrame * bFrame;
+        BitBucket * bbP;
+
+        getBFrame(frameNum, inputSourceP, pastRefFrameP, childProcess, 
+                  remoteIO,
+                  &bFrame, IOtimeP, framesReadP);
+
+        if (separateFiles)
+            bbP = bitioNew(outputFileName, bFrame->id, remoteIO);
+        else
+            bbP = wholeStreamBbP;
+
+        GenBFrame(bbP, bFrame, pastRefFrameP, futureRefFrameP);
+        ++(*framesOutputP);
+
+        if (separateFiles) {
+            if (remoteIO)
+                SendRemoteFrame(bFrame->id, bbP);
+            else {
+                Bitio_Flush(bbP);
+                Bitio_Close(bbP);
+            }
+        }
+
+        /* free this B frame right away */
+        Frame_Free(bFrame);
+
+        numB--;
+        timeMask &= 0x3;
+        ShowRemainingTime(childProcess);
+
+        ++(*currentGopP);
+        IncrementTCTime();
+    }
+}
+
+
+
+static void
+processRefFrame(MpegFrame *    const frameP, 
+                BitBucket *    const bb_arg,
+                int            const realStart,
+                int            const realEnd,
+                MpegFrame *    const pastRefFrameP,
+                boolean        const childProcess,
+                const char *   const outputFileName,
+                unsigned int * const framesReadP,
+                unsigned int * const framesOutputP) {
+/*----------------------------------------------------------------------------
+   Process an I or P frame.  Encode and output it.
+
+   But only if its frame number is within the range 'realStart'
+   through 'realEnd'.
+-----------------------------------------------------------------------------*/
+    if (frameP->id >= realStart && frameP->id <= realEnd) {
+        boolean separateFiles;
+        BitBucket * bb;
+  
+        separateFiles = (bb_arg == NULL);
+  
+        if ( separateFiles )
+            bb = bitioNew(outputFileName, frameP->id, remoteIO);
+        else
+            bb = bb_arg;
+  
+        /* first, output this reference frame */
+        switch (frameP->type) {
+        case TYPE_IFRAME:
+            outputIFrame(frameP, bb, realStart, realEnd, pastRefFrameP, 
+                         separateFiles);
+            break;
+        case TYPE_PFRAME:
+            outputPFrame(frameP, bb, realStart, realEnd, pastRefFrameP);
+            ShowRemainingTime(childProcess);
+            break;
+        default:
+            pm_error("INTERNAL ERROR: non-reference frame passed to "
+                     "ProcessRefFrame()");
+        }  
+        
+        ++(*framesOutputP);
+        
+        finishFrameOutput(frameP, bb, separateFiles, referenceFrame,
+                          childProcess, remoteIO);
+    }
+}
+
+
+
+static void
+countFrames(unsigned int const firstFrame,
+            unsigned int const lastFrame,
+            boolean      const stdinUsed,
+            int *        const numIP,
+            int *        const numPP,
+            int *        const numBP,
+            int *        const timeMaskP,
+            boolean *    const frameCountsUnknownP) {
+/*----------------------------------------------------------------------------
+  Count number of I, P, and B frames
+-----------------------------------------------------------------------------*/
+    unsigned int numI, numP, numB;
+    unsigned int timeMask;
+            
+    numI = 0; numP = 0; numB = 0;
+    timeMask = 0;
+    if (stdinUsed) {
+        numI = numP = numB = MAXINT/4;
+        *frameCountsUnknownP = TRUE;
+    } else {
+        unsigned int i;
+        for (i = firstFrame; i <= lastFrame; ++i) {
+            char const frameType = FType_Type(i);
+            switch(frameType) {
+            case 'i':        numI++;            timeMask |= 0x1;    break;
+            case 'p':        numP++;            timeMask |= 0x2;    break;
+            case 'b':        numB++;            timeMask |= 0x4;    break;
+            }
+        }
+        *frameCountsUnknownP = FALSE;
+    }
+
+    *numIP     = numI;
+    *numPP     = numP;
+    *numBP     = numB;
+    *timeMaskP = timeMask;
+    *frameCountsUnknownP = frameCountsUnknown;
+}
+
+
+
+static void
+readAndSaveFrame(struct inputSource * const inputSourceP,
+                 unsigned int         const frameNumber,
+                 char                 const frameType,
+                 const char *         const inputConversion,
+                 MpegFrame *          const pastRefFrameP,
+                 unsigned int *       const framesReadP,
+                 int *                const ioTimeP,
+                 bool *               const endOfStreamP) {
+/*----------------------------------------------------------------------------
+   Read the next frame from Standard Input and add it to the linked list
+   at *pastRefFrameP.  Assume it is Frame Number 'frameNumber' and is of
+   type 'frameType'.
+
+   Increment *framesReadP.
+   
+   Add the time it took to read it, in seconds, to *iotimeP.
+
+   Iff we can't read because we hit end of file, return
+   *endOfStreamP == TRUE and *framesReadP and *iotimeP untouched.
+-----------------------------------------------------------------------------*/
+    /* This really should be part of ReadNthFrame.  The frame should be chained
+       to the input object, not the past reference frame.
+    */
+       
+    MpegFrame * p;
+    MpegFrame * frameP;
+    time_t ioTimeStart, ioTimeEnd;
+    
+    time(&ioTimeStart);
+
+    frameP = Frame_New(frameNumber, frameType);
+    ReadFrame(frameP, inputSourceP, frameNumber, inputConversion,
+              endOfStreamP);
+
+    if (*endOfStreamP)
+        Frame_Free(frameP);
+    else {
+        ++(*framesReadP);
+    
+        time(&ioTimeEnd);
+        *ioTimeP += (ioTimeEnd - ioTimeStart);
+
+        /* Add the B frame to the end of the queue of B-frames 
+           for later encoding.
+        */
+        assert(pastRefFrameP != NULL);
+        
+        p = pastRefFrameP;
+        while (p->next != NULL)
+            p = p->next;
+        p->next = frameP;
+    }
+}
+
+
+
+static void
+doFirstFrameStuff(enum frameContext const context,
+                  const char *      const userDataFileName,
+                  BitBucket *       const bb,
+                  int               const fsize_x,
+                  int               const fsize_y,
+                  int               const aspectRatio,
+                  int               const frameRate,
+                  int32             const qtable[],
+                  int32             const niqtable[],
+                  unsigned int *    const inputFrameBitsP) {
+/*----------------------------------------------------------------------------
+   Do stuff we have to do after reading the first frame in a sequence
+   of frames requested of GenMPEGStream().
+-----------------------------------------------------------------------------*/
+    *inputFrameBitsP = 24*Fsize_x*Fsize_y;
+    SetBlocksPerSlice();
+          
+    if (context == CONTEXT_WHOLESTREAM) {
+        int32 const bitstreamMode = getRateMode();
+        char * userData;
+        unsigned int userDataSize;
+
+        assert(bb != NULL);
+
+        DBG_PRINT(("Generating sequence header\n"));
+        if (bitstreamMode == FIXED_RATE) {
+            bit_rate = getBitRate();
+            buf_size = getBufferSize();
+        } else {
+            bit_rate = -1;
+            buf_size = -1;
+        }
+        
+        if (strlen(userDataFileName) != 0) {
+            struct stat statbuf;
+            FILE *fp;
+          
+            stat(userDataFileName,&statbuf);
+            userDataSize = statbuf.st_size;
+            userData = malloc(userDataSize);
+            fp = fopen(userDataFileName,"rb");
+            if (fp == NULL) {
+                pm_message("Could not open userdata file '%s'.",
+                           userDataFileName);
+                userData = NULL;
+                userDataSize = 0;
+            } else {
+                size_t bytesRead;
+
+                bytesRead = fread(userData,1,userDataSize,fp);
+                if (bytesRead != userDataSize) {
+                    pm_message("Could not read %d bytes from "
+                               "userdata file '%s'.",
+                               userDataSize,userDataFileName);
+                    userData = NULL;
+                    userDataSize = 0;
+                }
+            }
+        } else { /* Put in our UserData Header */
+            const char * userDataString;
+            time_t now;
+                    
+            time(&now);
+            asprintfN(&userDataString,"MPEG stream encoded by UCB Encoder "
+                      "(mpeg_encode) v%s on %s.",
+                      VERSION, ctime(&now));
+            userData = strdup(userDataString);
+            userDataSize = strlen(userData);
+            strfree(userDataString);
+        }
+        Mhead_GenSequenceHeader(bb, Fsize_x, Fsize_y,
+                                /* pratio */ aspectRatio,
+                                /* pict_rate */ frameRate, 
+                                /* bit_rate */ bit_rate,
+                                /* buf_size */ buf_size,
+                                /*c_param_flag */ 1,
+                                /* iq_matrix */ qtable, 
+                                /* niq_matrix */ niqtable,
+                                /* ext_data */ NULL,
+                                /* ext_data_size */ 0,
+                                /* user_data */ (uint8*) userData,
+                                /* user_data_size */ userDataSize);
+    }
+}
+
+
+
+static void
+getPreviousFrame(unsigned int         const frameStart,
+                 int                  const referenceFrame,
+                 struct inputSource * const inputSourceP,
+                 boolean              const childProcess,
+                 const char *         const slaveConversion,
+                 const char *         const inputConversion,
+                 MpegFrame **         const framePP,
+                 unsigned int *       const framesReadP,
+                 int *                const ioTimeP) {
+
+    /* This needs to be modularized.  It shouldn't issue messages about
+       encoding GOPs and B frames, since it knows nothing about those.
+       It should work for Standard Input too, through a generic Standard
+       Input reader that buffers stuff for backward reading.
+    */
+
+    MpegFrame * frameP;
+    time_t ioTimeStart, ioTimeEnd;
+
+    /* can't find the previous frame interactively */
+    if (inputSourceP->stdinUsed)
+        pm_error("Cannot encode GOP from stdin when "
+                 "first frame is a B-frame.");
+
+    if (frameStart < 1)
+        pm_error("Cannot encode GOP when first frame is a B-frame "
+                 "and is not preceded by anything.");
+
+    /* need to load in previous frame; call it an I frame */
+    frameP = Frame_New(frameStart-1, 'i');
+
+    time(&ioTimeStart);
+
+    if ((referenceFrame == DECODED_FRAME) && childProcess) {
+        WaitForDecodedFrame(frameStart);
+
+        if (remoteIO)
+            GetRemoteDecodedRefFrame(frameP, frameStart - 1);
+        else
+            ReadDecodedRefFrame(frameP, frameStart - 1);
+    } else {
+        bool endOfStream;
+        ReadNthFrame(inputSourceP, frameStart - 1, remoteIO, childProcess,
+                     separateConversion, slaveConversion, inputConversion,
+                     frameP, &endOfStream);
+        assert(!endOfStream);  /* Because Stdin causes failure above */
+    }            
+    ++(*framesReadP);
+    
+    time(&ioTimeEnd);
+    *ioTimeP += (ioTimeEnd-ioTimeStart);
+
+    *framePP = frameP;
+}
+
+
+
+static void
+computeFrameRange(unsigned int         const frameStart,
+                  unsigned int         const frameEnd,
+                  enum frameContext    const context, 
+                  struct inputSource * const inputSourceP,
+                  unsigned int *       const firstFrameP,
+                  unsigned int *       const lastFrameP) {
+
+    switch (context) {
+    case CONTEXT_GOP:
+        *firstFrameP = frameStart;
+        *lastFrameP  = frameEnd;
+        break;
+    case CONTEXT_JUSTFRAMES: {
+        /* if first frame is P or B, need to read in P or I frame before it */
+        if (FType_Type(frameStart) != 'i') {
+            /* can't find the previous frame interactively */
+            if (inputSourceP->stdinUsed)
+                pm_error("Cannot encode frames from Standard Input "
+                         "when first frame is not an I-frame.");
+
+            *firstFrameP = FType_PastRef(frameStart);
+        } else
+            *firstFrameP = frameStart;
+
+        /* if last frame is B, need to read in P or I frame after it */
+        if ((FType_Type(frameEnd) == 'b') && 
+            (frameEnd != inputSourceP->numInputFiles-1)) {
+            /* can't find the next reference frame interactively */
+            if (inputSourceP->stdinUsed)
+                pm_error("Cannot encode frames from Standard Input "
+                         "when last frame is a B-frame.");
+            
+            *lastFrameP = FType_FutureRef(frameEnd);
+        } else
+            *lastFrameP = frameEnd;
+    }
+    break;
+    case CONTEXT_WHOLESTREAM:
+        *firstFrameP = frameStart;
+        *lastFrameP  = frameEnd;
+    }
+}
+
+
+
+static void
+getFrame(MpegFrame **         const framePP,
+         struct inputSource * const inputSourceP,
+         unsigned int         const frameNumber,
+         char                 const frameType,
+         unsigned int         const realStart,
+         unsigned int         const realEnd,
+         int                  const referenceFrame,
+         boolean              const childProcess,
+         boolean              const remoteIo,
+         boolean              const separateConversion,
+         const char *         const slaveConversion,
+         const char *         const inputConversion,
+         unsigned int *       const framesReadP,
+         int *                const ioTimeP) {
+/*----------------------------------------------------------------------------
+   Get frame with number 'frameNumber' as *frameP.
+
+   Increment *framesReadP.
+
+   Add to *ioTimeP the time in seconds we spent reading it.
+
+   Iff we fail to get the frame because the stream ends, return
+   *frameP == NULL, don't increment *framesReadP, and leave
+   *ioTimeP unchanged.
+-----------------------------------------------------------------------------*/
+    time_t ioTimeStart, ioTimeEnd;
+    MpegFrame * frameP;
+    bool endOfStream;
+    
+    time(&ioTimeStart);
+
+    frameP = Frame_New(frameNumber, frameType);
+            
+    if ((referenceFrame == DECODED_FRAME) &&
+        ((frameNumber < realStart) || (frameNumber > realEnd)) ) {
+        WaitForDecodedFrame(frameNumber);
+
+        if (remoteIo)
+            GetRemoteDecodedRefFrame(frameP, frameNumber);
+        else
+            ReadDecodedRefFrame(frameP, frameNumber);
+
+        /* I don't know what this block of code does, so I don't know
+           what endOfStream should be.  Here's a guess:
+        */
+        endOfStream = FALSE;
+    } else
+        ReadNthFrame(inputSourceP, frameNumber, remoteIO, childProcess,
+                     separateConversion, slaveConversion, inputConversion,
+                     frameP, &endOfStream);
+    
+    if (endOfStream) {
+        Frame_Free(frameP);
+        *framePP = NULL;
+    } else {
+        ++(*framesReadP);
+            
+        time(&ioTimeEnd);
+        *ioTimeP += (ioTimeEnd - ioTimeStart);
+
+        *framePP = frameP;
+    }
+}
+
+
+
+static void
+handleBitRate(unsigned int const realEnd,
+              unsigned int const numBits,
+              boolean      const childProcess,
+              boolean      const showBitRatePerFrame) {
+
+    extern void PrintItoIBitRate (int numBits, int frameNum);
+
+    if (FType_Type(realEnd) != 'i')
+        PrintItoIBitRate(numBits, realEnd+1);
+
+    if ((!childProcess) && showBitRatePerFrame)
+        CloseBitRateFile();
+}
+
+
+
+static void
+doAFrame(unsigned int         const frameNumber,
+         struct inputSource * const inputSourceP,
+         enum frameContext    const context, 
+         unsigned int         const frameStart, 
+         unsigned int         const frameEnd, 
+         unsigned int         const realStart,
+         unsigned int         const realEnd,
+         bool                 const childProcess,
+         const char *         const outputFileName,
+         MpegFrame *          const pastRefFrameP,
+         MpegFrame **         const newPastRefFramePP,
+         unsigned int *       const framesReadP,
+         unsigned int *       const framesOutputP,
+         bool *               const firstFrameDoneP,
+         BitBucket *          const bbP,
+         unsigned int *       const inputFrameBitsP,
+         bool *               const endOfStreamP) {
+/*----------------------------------------------------------------------------
+   *endOfStreamP returned means we were unable to do a frame because
+   the input stream has ended.  In that case, none of the other outputs
+   are valid.
+-----------------------------------------------------------------------------*/
+    char const frameType = FType_Type(frameNumber);
+    
+    *endOfStreamP = FALSE;  /* initial assumption */
+
+    if (frameType == 'b') {
+        /* We'll process this non-reference frame later.  If reading
+           from stdin, we read it now and save it.  Otherwise, we can
+           just read it later.
+        */
+        *newPastRefFramePP = pastRefFrameP;
+        if (inputSourceP->stdinUsed) 
+            readAndSaveFrame(inputSourceP,
+                             frameNumber, frameType, inputConversion,
+                             pastRefFrameP, framesReadP, &IOtime,
+                             endOfStreamP);
+    } else {
+        MpegFrame * frameP;
+        
+        getFrame(&frameP, inputSourceP, frameNumber, frameType,
+                 realStart, realEnd, referenceFrame, childProcess,
+                 remoteIO,
+                 separateConversion, slaveConversion, inputConversion,
+                 framesReadP, &IOtime);
+        
+        if (frameP) {
+            *endOfStreamP = FALSE;
+
+            if (!*firstFrameDoneP) {
+                doFirstFrameStuff(context, userDataFileName,
+                                  bbP, Fsize_x, Fsize_y, aspectRatio,
+                                  frameRate, qtable, niqtable, 
+                                  inputFrameBitsP);
+            
+                *firstFrameDoneP = TRUE;
+            }
+            processRefFrame(frameP, bbP, frameStart, frameEnd,
+                            pastRefFrameP, childProcess, outputFileName, 
+                            framesReadP, framesOutputP);
+                
+            if (pastRefFrameP) {
+                processBFrames(pastRefFrameP, frameP, realStart, realEnd,
+                               inputSourceP, remoteIO, childProcess, 
+                               &IOtime, bbP, outputFileName,
+                               framesReadP, framesOutputP, &currentGOP);
+            }
+            if (pastRefFrameP != NULL)
+                Frame_Free(pastRefFrameP);
+        
+            *newPastRefFramePP = frameP;
+        } else
+            *endOfStreamP = TRUE;
+    }
+}
+
+
+
+void
+GenMPEGStream(struct inputSource * const inputSourceP,
+              enum frameContext    const context, 
+              unsigned int         const frameStart, 
+              unsigned int         const frameEnd, 
+              int32                const qtable[], 
+              int32                const niqtable[], 
+              bool                 const childProcess,
+              FILE *               const ofP, 
+              const char *         const outputFileName,
+              bool                 const wantVbvUnderflowWarning,
+              bool                 const wantVbvOverflowWarning,
+              unsigned int *       const inputFrameBitsP,
+              unsigned int *       const totalBitsP) {
+/*----------------------------------------------------------------------------
+   Encode a bunch of frames into an MPEG sequence stream or a part thereof.
+
+   'context' tells what in addition to the frames themselves must go into
+   the stream:
+
+      CONTEXT_JUSTFRAMES:  Nothing but the indicated frames
+      CONTEXT_GOP:         GOP header/trailer stuff to make a single GOP
+                           that contains the indicated frames
+      CONTEXT_WHOLESTREAM: A whole stream consisting of the indicated
+                           frames -- a sequence of whole GOPS, with stream
+                           header/trailer stuff as well.
+
+   'frameStart' and 'frameEnd' are the numbers of the first and last
+   frames we are to encode, except that if the input source is a stream,
+   we stop where the stream ends if that is before 'frameEnd'.
+
+-----------------------------------------------------------------------------*/
+    BitBucket * bbP;
+    unsigned int frameNumber;
+    bool endOfStream;
+    bool firstFrameDone;
+    int numBits;
+    unsigned int firstFrame, lastFrame;
+    /* Frame numbers of the first and last frames we look at.  This
+       could be more than the the frames we actually encode because
+       we may need context (i.e. to encode a B frame, we need the subsequent
+       I or P frame).
+    */
+    unsigned int framesRead;
+        /* Number of frames we have read; for statistical purposes */
+    MpegFrame * pastRefFrameP;
+        /* The frame that will be the past reference frame for the next
+           B or P frame that we put into the stream
+        */
+    if (frameEnd + 1 > inputSourceP->numInputFiles)
+        pm_error("Last frame (number %u) is beyond the end of the stream "
+                 "(%u frames)", frameEnd, inputSourceP->numInputFiles);
+
+    if (context == CONTEXT_WHOLESTREAM &&
+        !inputSourceP->stdinUsed && 
+        FType_Type(inputSourceP->numInputFiles-1) == 'b')
+        pm_message("WARNING:  "
+                   "One or more B-frames at end will not be encoded.  "
+                   "See FORCE_ENCODE_LAST_FRAME parameter file statement.");
+
+    time(&timeStart);
+
+    framesRead = 0;
+
+    ResetIFrameStats();
+    ResetPFrameStats();
+    ResetBFrameStats();
+
+    Fsize_Reset();
+
+    framesOutput = 0;
+
+    if (childProcess && separateConversion)
+        SetFileType(slaveConversion);
+    else
+        SetFileType(inputConversion);
+
+    realStart = frameStart;
+    realEnd   = frameEnd;
+
+    computeFrameRange(frameStart, frameEnd, context, inputSourceP,
+                      &firstFrame, &lastFrame);
+
+    if (context == CONTEXT_GOP && FType_Type(frameStart) == 'b')
+        getPreviousFrame(frameStart, referenceFrame, inputSourceP,
+                         childProcess, slaveConversion, inputConversion,
+                         &pastRefFrameP, &framesRead, &IOtime);
+    else
+        pastRefFrameP = NULL;
+
+    countFrames(firstFrame, lastFrame, inputSourceP->stdinUsed,
+                &numI, &numP, &numB, &timeMask, &frameCountsUnknown);
+
+    if (showBitRatePerFrame)
+        OpenBitRateFile();  /* May modify showBitRatePerFrame */
+
+    if (context == CONTEXT_WHOLESTREAM)
+        bbP = Bitio_New(ofP);
+    else
+        bbP = NULL;
+
+    initTCTime(firstFrame);
+
+    totalFramesSent = firstFrame;
+    currentGOP = gopSize;        /* so first I-frame generates GOP Header */
+
+    initializeRateControl(wantVbvUnderflowWarning, wantVbvOverflowWarning);
+
+    firstFrameDone = FALSE;
+    for (frameNumber = firstFrame, endOfStream = FALSE;
+         frameNumber <= lastFrame && !endOfStream;
+         ++frameNumber) {
+
+        doAFrame(frameNumber, inputSourceP, context, 
+                 frameStart, frameEnd, realStart, realEnd,
+                 childProcess, outputFileName,
+                 pastRefFrameP, &pastRefFrameP,
+                 &framesRead, &framesOutput, &firstFrameDone, bbP,
+                 inputFrameBitsP, &endOfStream);
+    }
+    
+    if (pastRefFrameP != NULL)
+        Frame_Free(pastRefFrameP);
+    
+    /* SEQUENCE END CODE */
+    if (context == CONTEXT_WHOLESTREAM)
+        Mhead_GenSequenceEnder(bbP);
+    
+    if (context == CONTEXT_WHOLESTREAM)
+        numBits = bbP->cumulativeBits;
+    else {
+        /* What should the correct value be?  Most likely 1.  "numBits" is
+           used below, so we need to make sure it's properly initialized 
+           to somthing (anything).  
+        */
+        numBits = 1;
+    }
+
+    if (context != CONTEXT_JUSTFRAMES) {
+        Bitio_Flush(bbP);
+        bbP = NULL;
+        fclose(ofP);
+    }
+    handleBitRate(realEnd, numBits, childProcess, showBitRatePerFrame);
+
+    *totalBitsP  = numBits;
+}
+
+
+
+/*===========================================================================*
+ *
+ * SetStatFileName
+ *
+ *  set the statistics file name
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    statFileName
+ *
+ *===========================================================================*/
+void
+SetStatFileName(const char * const fileName) {
+    strcpy(statFileName, fileName);
+}
+
+
+/*===========================================================================*
+ *
+ * SetGOPSize
+ *
+ *  set the GOP size (frames per GOP)
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    gopSize
+ *
+ *===========================================================================*/
+void
+SetGOPSize(size)
+    int size;
+{
+    gopSize = size;
+}
+
+
+/*===========================================================================*
+ *
+ * PrintStartStats
+ *
+ *  print out the starting statistics (stuff from the param file)
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+PrintStartStats(time_t               const startTime, 
+                bool                 const specificFrames,
+                unsigned int         const firstFrame, 
+                unsigned int         const lastFrame,
+                struct inputSource * const inputSourceP) {
+
+    FILE *fpointer;
+    int i;
+
+    if (statFileName[0] == '\0') {
+        statFile = NULL;
+    } else {
+        statFile = fopen(statFileName, "a");    /* open for appending */
+        if (statFile == NULL) {
+            fprintf(stderr, "ERROR:  Could not open stat file:  %s\n",
+                    statFileName);
+            fprintf(stderr, "        Sending statistics to stdout only.\n");
+            fprintf(stderr, "\n\n");
+        } else if (! realQuiet) {
+            fprintf(stdout, "Appending statistics to file:  %s\n",
+                    statFileName);
+            fprintf(stdout, "\n\n");
+        }
+    }
+    
+    for (i = 0; i < 2; ++i) {
+        if ( ( i == 0 ) && (! realQuiet) ) {
+            fpointer = stdout;
+        } else if ( statFile != NULL ) {
+            fpointer = statFile;
+        } else {
+            continue;
+        }
+
+        fprintf(fpointer, "MPEG ENCODER STATS (%s)\n",VERSION);
+        fprintf(fpointer, "------------------------\n");
+        fprintf(fpointer, "TIME STARTED:  %s", ctime(&startTime));
+        if (getenv("HOST") != NULL)
+            fprintf(fpointer, "MACHINE:  %s\n", getenv("HOST"));
+        else
+            fprintf(fpointer, "MACHINE:  unknown\n");
+
+        if (inputSourceP->stdinUsed)
+            fprintf(fpointer, "INPUT:  stdin\n");
+        else {
+            const char * inputFileName;
+
+            fprintf(fpointer, "INPUT FROM FILES:\n");
+
+            GetNthInputFileName(inputSourceP, 0, &inputFileName);
+            fprintf(fpointer, "FIRST FILE:  %s/%s\n", 
+                    currentPath, inputFileName);
+            strfree(inputFileName);
+            GetNthInputFileName(inputSourceP, inputSourceP->numInputFiles-1, 
+                                &inputFileName);
+            fprintf(fpointer, "LAST FILE:  %s/%s\n", 
+                    currentPath, inputFileName);
+            strfree(inputFileName);
+        }    
+        fprintf(fpointer, "OUTPUT:  %s\n", outputFileName);
+
+        if (resizeFrame)
+            fprintf(fpointer, "RESIZED TO:  %dx%d\n",
+                    outputWidth, outputHeight);
+        fprintf(fpointer, "PATTERN:  %s\n", framePattern);
+        fprintf(fpointer, "GOP_SIZE:  %d\n", gopSize);
+        fprintf(fpointer, "SLICES PER FRAME:  %d\n", slicesPerFrame);
+        if (searchRangeP==searchRangeB)
+            fprintf(fpointer, "RANGE:  +/-%d\n", searchRangeP/2);
+        else fprintf(fpointer, "RANGES:  +/-%d %d\n", 
+                     searchRangeP/2,searchRangeB/2);
+        fprintf(fpointer, "PIXEL SEARCH:  %s\n", 
+                pixelFullSearch ? "FULL" : "HALF");
+        fprintf(fpointer, "PSEARCH:  %s\n", PSearchName());
+        fprintf(fpointer, "BSEARCH:  %s\n", BSearchName());
+        fprintf(fpointer, "QSCALE:  %d %d %d\n", qscaleI, 
+                GetPQScale(), GetBQScale());
+        if (specificsOn) 
+            fprintf(fpointer, "(Except as modified by Specifics file)\n");
+        if ( referenceFrame == DECODED_FRAME ) {
+            fprintf(fpointer, "REFERENCE FRAME:  DECODED\n");
+        } else if ( referenceFrame == ORIGINAL_FRAME ) {
+            fprintf(fpointer, "REFERENCE FRAME:  ORIGINAL\n");
+        } else
+            pm_error("Illegal referenceFrame!!!");
+
+        /*  For new Rate control parameters */
+        if (getRateMode() == FIXED_RATE) {
+            fprintf(fpointer, "PICTURE RATE:  %d\n", frameRateRounded);
+            if (getBitRate() != -1) {
+                fprintf(fpointer, "\nBIT RATE:  %d\n", getBitRate());
+            }
+            if (getBufferSize() != -1) {
+                fprintf(fpointer, "BUFFER SIZE:  %d\n", getBufferSize());
+            }
+        }
+    }
+    if (!realQuiet)
+        fprintf(stdout, "\n\n");
+}
+
+
+
+boolean
+NonLocalRefFrame(int const id) {
+/*----------------------------------------------------------------------------
+   Return TRUE if frame number 'id' might be referenced from a non-local
+   process.  This is a conservative estimate.  We return FALSE iff there
+   is no way based on the information we have that the frame could be
+   referenced by a non-local process.
+-----------------------------------------------------------------------------*/
+    boolean retval;
+
+    int const lastIPid = FType_PastRef(id);
+    
+    /* might be accessed by B-frame */
+    
+    if (lastIPid+1 < realStart)
+        retval = TRUE;
+    else {
+        unsigned int const nextIPid = FType_FutureRef(id);
+        
+        /* if B-frame is out of range, then current frame can be
+           ref'd by it 
+        */
+        
+        /* might be accessed by B-frame */
+        if (nextIPid > realEnd+1)
+            retval = TRUE;
+        
+        /* might be accessed by P-frame */
+        if ((nextIPid > realEnd) && (FType_Type(nextIPid) == 'p'))
+            retval = TRUE;
+    }
+    return retval;
+}
+
+
+ 
+/*===========================================================================*
+ *
+ * SetFrameRate
+ *
+ *  sets global frame rate variables.  value passed is MPEG frame rate code.
+ *
+ * RETURNS: TRUE or FALSE
+ *
+ * SIDE EFFECTS:    frameRateRounded, frameRateInteger
+ *
+ *===========================================================================*/
+void
+SetFrameRate()
+{
+    switch(frameRate) {
+    case 1:
+        frameRateRounded = 24;
+        frameRateInteger = FALSE;
+        break;
+    case 2:
+        frameRateRounded = 24;
+        frameRateInteger = TRUE;
+        break;
+    case 3:
+        frameRateRounded = 25;
+        frameRateInteger = TRUE;
+        break;
+    case 4:
+        frameRateRounded = 30;
+        frameRateInteger = FALSE;
+        break;
+    case 5:
+        frameRateRounded = 30;
+        frameRateInteger = TRUE;
+        break;
+    case 6:
+        frameRateRounded = 50;
+        frameRateInteger = TRUE;
+        break;
+    case 7:
+        frameRateRounded = 60;
+        frameRateInteger = FALSE;
+        break;
+    case 8:
+        frameRateRounded = 60;
+        frameRateInteger = TRUE;
+        break;
+    }
+    printf("frame rate(%d) set to %d\n", frameRate, frameRateRounded);
+}
+
+
+/*=====================*
+ * INTERNAL PROCEDURES *
+ *=====================*/
+
+/*===========================================================================*
+ *
+ * ComputeDHMSTime
+ *
+ *  turn some number of seconds (someTime) into a string which
+ *  summarizes that time according to scale (days, hours, minutes, or
+ *  seconds)
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+ComputeDHMSTime(someTime, timeText)
+    int32 someTime;
+    char *timeText;
+{
+    int     days, hours, mins, secs;
+
+    days = someTime / (24*60*60);
+    someTime -= days*24*60*60;
+    hours = someTime / (60*60);
+    someTime -= hours*60*60;
+    mins = someTime / 60;
+    secs = someTime - mins*60;
+
+    if ( days > 0 ) {
+        sprintf(timeText, "Total time:  %d days and %d hours", days, hours);
+    } else if ( hours > 0 ) {
+        sprintf(timeText, "Total time:  %d hours and %d minutes", hours, mins);
+    } else if ( mins > 0 ) {
+        sprintf(timeText, "Total time:  %d minutes and %d seconds", mins, secs);
+    } else {
+    sprintf(timeText, "Total time:  %d seconds", secs);
+    }
+}
+
+
+
+void
+ComputeGOPFrames(int            const whichGOP, 
+                 unsigned int * const firstFrameP, 
+                 unsigned int * const lastFrameP, 
+                 unsigned int   const numFrames) {
+/*----------------------------------------------------------------------------
+   Figure out which frames are in GOP number 'whichGOP'.
+-----------------------------------------------------------------------------*/
+    unsigned int passedB;
+    unsigned int currGOP;
+    unsigned int gopNum;
+    unsigned int frameNum;
+    unsigned int firstFrame, lastFrame;
+    bool foundGop;
+
+    /* calculate first, last frames of whichGOP GOP */
+
+    gopNum = 0;
+    frameNum = 0;
+    passedB = 0;
+    currGOP = 0;
+    foundGop = FALSE;
+
+    while (!foundGop) {
+        if (frameNum >= numFrames)
+            pm_error("There aren't that many GOPs!");
+
+        if (gopNum == whichGOP) {
+            foundGop = TRUE;
+            firstFrame = frameNum;
+        }           
+
+        /* go past one gop */
+        /* must go past at least one frame */
+        do {
+            currGOP += (1 + passedB);
+
+            ++frameNum;
+
+            passedB = 0;
+            while ((frameNum < numFrames) && (FType_Type(frameNum) == 'b')) {
+                ++frameNum;
+                ++passedB;
+            }
+        } while ((frameNum < numFrames) && 
+                 ((FType_Type(frameNum) != 'i') || (currGOP < gopSize)));
+
+        currGOP -= gopSize;
+
+        if (gopNum == whichGOP)
+            lastFrame = (frameNum - passedB - 1);
+
+        ++gopNum;
+    }
+    *firstFrameP = firstFrame;
+    *lastFrameP  = lastFrame;
+}
+
+
+
+static void
+doEndStats(FILE *       const fpointer,
+           time_t       const startTime,
+           time_t       const endTime,
+           unsigned int const inputFrameBits,
+           unsigned int const totalBits,
+           float        const totalCPU) {
+
+    int32 const diffTime = endTime - startTime;
+
+    char    timeText[256];
+
+    ComputeDHMSTime(diffTime, timeText);
+
+    fprintf(fpointer, "TIME COMPLETED:  %s", ctime(&endTime));
+    fprintf(fpointer, "%s\n\n", timeText);
+        
+    ShowIFrameSummary(inputFrameBits, totalBits, fpointer);
+    ShowPFrameSummary(inputFrameBits, totalBits, fpointer);
+    ShowBFrameSummary(inputFrameBits, totalBits, fpointer);
+
+    fprintf(fpointer, "---------------------------------------------\n");
+    fprintf(fpointer, "Total Compression:  %3d:1     (%9.4f bpp)\n",
+            framesOutput*inputFrameBits/totalBits,
+            24.0*(float)(totalBits)/(float)(framesOutput*inputFrameBits));
+    if (diffTime > 0) {
+        fprintf(fpointer, "Total Frames Per Sec Elapsed:  %f (%ld mps)\n",
+                (float)framesOutput/(float)diffTime,
+                (long)((float)framesOutput * 
+                       (float)inputFrameBits /
+                       (256.0*24.0*(float)diffTime)));
+    } else {
+        fprintf(fpointer, "Total Frames Per Sec Elapsed:  Infinite!\n");
+    }
+    if ( totalCPU == 0.0 ) {
+        fprintf(fpointer, "CPU Time:  NONE!\n");
+    } else {
+        fprintf(fpointer, "Total Frames Per Sec CPU    :  %f (%ld mps)\n",
+                (float)framesOutput/totalCPU,
+                (long)((float)framesOutput *
+                       (float)inputFrameBits/(256.0*24.0*totalCPU)));
+    }
+    fprintf(fpointer, "Total Output Bit Rate (%d fps):  %d bits/sec\n",
+            frameRateRounded, frameRateRounded*totalBits/framesOutput);
+    fprintf(fpointer, "MPEG file created in :  %s\n", outputFileName);
+    fprintf(fpointer, "\n\n");
+        
+    if ( computeMVHist ) {
+        ShowPMVHistogram(fpointer);
+        ShowBBMVHistogram(fpointer);
+        ShowBFMVHistogram(fpointer);
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ * PrintEndStats
+ *
+ *  print end statistics (summary, time information)
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+PrintEndStats(time_t       const startTime,
+              time_t       const endTime,
+              unsigned int const inputFrameBits, 
+              unsigned int const totalBits) {
+
+    float   totalCPU;
+
+    totalCPU = 0.0;
+    totalCPU += IFrameTotalTime();
+    totalCPU += PFrameTotalTime();
+    totalCPU += BFrameTotalTime();
+
+    if (!realQuiet) {
+        fprintf(stdout, "\n\n");
+        doEndStats(stdout, startTime, endTime, inputFrameBits,
+                   totalBits, totalCPU);
+    }
+    
+    if (statFile) {
+        doEndStats(statFile, startTime, endTime, inputFrameBits,
+                   totalBits, totalCPU);
+
+        fclose(statFile);
+    }
+}
+
+
+
+void
+ReadDecodedRefFrame(MpegFrame *  const frameP, 
+                    unsigned int const frameNumber) {
+
+    FILE    *fpointer;
+    char    fileName[256];
+    int width, height;
+    register int y;
+
+    width = Fsize_x;
+    height = Fsize_y;
+
+    sprintf(fileName, "%s.decoded.%u", outputFileName, frameNumber);
+    if (! realQuiet) {
+        fprintf(stdout, "reading %s\n", fileName);
+        fflush(stdout);
+    }
+
+    if ((fpointer = fopen(fileName, "rb")) == NULL) {
+        sleep(1);
+        if ((fpointer = fopen(fileName, "rb")) == NULL) {
+            fprintf(stderr, "Cannot open %s\n", fileName);
+            exit(1);
+        }}
+
+    Frame_AllocDecoded(frameP, TRUE);
+    
+    for ( y = 0; y < height; y++ ) {
+        size_t bytesRead;
+
+        bytesRead = fread(frameP->decoded_y[y], 1, width, fpointer);
+        if (bytesRead != width)
+            pm_error("Could not read enough bytes from '%s;", fileName);
+    }
+    
+    for (y = 0; y < (height >> 1); y++) {           /* U */
+        size_t const bytesToRead = width/2;
+        size_t bytesRead;
+
+        bytesRead = fread(frameP->decoded_cb[y], 1, bytesToRead, fpointer);
+        if (bytesRead != bytesToRead)
+            pm_message("Could not read enough bytes from '%s'", fileName);
+    }
+    
+    for (y = 0; y < (height >> 1); y++) {           /* V */
+        size_t const bytesToRead = width/2;
+        size_t bytesRead;
+        bytesRead = fread(frameP->decoded_cr[y], 1, bytesToRead, fpointer);
+        if (bytesRead != bytesToRead)
+            pm_message("Could not read enough bytes from '%s'", fileName);
+    }
+    fclose(fpointer);
+}
+
+
+
+static void
+OpenBitRateFile() {
+    bitRateFile = fopen(bitRateFileName, "w");
+    if ( bitRateFile == NULL ) {
+        pm_message("ERROR:  Could not open bit rate file:  '%s'", 
+                   bitRateFileName);
+        showBitRatePerFrame = FALSE;
+    }
+}
+
+
+
+static void
+CloseBitRateFile() {
+    fclose(bitRateFile);
+}
diff --git a/converter/ppm/ppmtompeg/mquant.c b/converter/ppm/ppmtompeg/mquant.c
new file mode 100644
index 00000000..1f8ca63a
--- /dev/null
+++ b/converter/ppm/ppmtompeg/mquant.c
@@ -0,0 +1,44 @@
+#include "mtypes.h"
+#include "mproto.h"
+
+static int qtable[][8] = {
+    { 8,16,19,22,26,27,29,34},
+    {16,16,22,24,27,29,34,37},
+    {19,22,26,27,29,34,34,38},
+    {22,22,26,27,29,34,37,40},
+    {22,26,27,29,32,35,40,48},
+    {26,27,29,32,35,40,48,58},
+    {26,27,29,34,38,46,56,69},
+    {27,29,35,38,46,56,69,83} };
+
+
+/*
+ *--------------------------------------------------------------
+ *
+ * mp_quant_block --
+ *
+ *	Quantizes a block -- removing information
+ *	It's safe for out == in.
+ *
+ * Results:
+ *	None.
+ *
+ * Side effects:
+ *	Modifies the out block.
+ *
+ *--------------------------------------------------------------
+ */
+void mp_quant_block(Block in, Block out) {
+    int i;
+
+    for(i=0;i<8;i++) {
+	out[i][0] = in[i][0] / qtable[i][0];
+	out[i][1] = in[i][1] / qtable[i][1];
+	out[i][2] = in[i][2] / qtable[i][2];
+	out[i][3] = in[i][3] / qtable[i][3];
+	out[i][4] = in[i][4] / qtable[i][4];
+	out[i][5] = in[i][5] / qtable[i][5];
+	out[i][6] = in[i][6] / qtable[i][6];
+	out[i][7] = in[i][7] / qtable[i][7];
+    }
+}
diff --git a/converter/ppm/ppmtompeg/nojpeg.c b/converter/ppm/ppmtompeg/nojpeg.c
new file mode 100644
index 00000000..38c05a9e
--- /dev/null
+++ b/converter/ppm/ppmtompeg/nojpeg.c
@@ -0,0 +1,61 @@
+/*===========================================================================*
+ * nojpeg.c								     *
+ *									     *
+ *	procedures to deal with JPEG files				     *
+ *									     *
+ * EXPORTED PROCEDURES:							     *
+ *	JMovie2JPEG							     *
+ *      ReadJPEG							     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "all.h"
+#include "mtypes.h"
+#include "frames.h"
+#include "prototypes.h"
+#include "param.h"
+#include "readframe.h"
+#include "fsize.h"
+#include "rgbtoycc.h"
+#include "jpeg.h"
+
+
+void
+JMovie2JPEG(const char * const infilename,
+            const char * const obase,
+            int          const start,
+            int          const end) {
+
+    pm_error("This program has not been built with the "
+             "ability to handle JPEG input files");
+}
+
+
+void
+ReadJPEG(MpegFrame * const mf,
+         FILE *      const fp) {
+
+    pm_error("This program has not been built with the "
+             "ability to handle JPEG input files");
+}
diff --git a/converter/ppm/ppmtompeg/noparallel.c b/converter/ppm/ppmtompeg/noparallel.c
new file mode 100644
index 00000000..016e3c44
--- /dev/null
+++ b/converter/ppm/ppmtompeg/noparallel.c
@@ -0,0 +1,229 @@
+/*===========================================================================*
+ *  noparallel.c
+ *
+ *  Would be procedures to make encoder to run in parallel -- except
+ *  this machine doesn't have sockets, so we can only run sequentially
+ *  so this file has dummy procedures which lets it compile
+ *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include <time.h>
+
+#include <pm.h>
+
+#include "all.h"
+#include "mtypes.h"
+#include "parallel.h"
+#include "frame.h"
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+
+int parallelTestFrames = 10;
+int parallelTimeChunks = 60;
+const char *IOhostName;
+int ioPortNumber;
+int combinePortNumber;
+int decodePortNumber;
+boolean niceProcesses = FALSE;
+boolean forceIalign = FALSE;
+int     machineNumber = -1;
+boolean remoteIO = FALSE;
+boolean separateConversion;
+time_t  IOtime = 0;
+
+
+/*=====================*
+ * EXPORTED PROCEDURES *
+ *=====================*/
+
+/*=================*
+ * IO SERVER STUFF *
+ *=================*/
+
+
+void
+IoServer(struct inputSource * const inputSourceP,
+         const char *         const parallelHostName, 
+         int                  const portNum) {
+
+    pm_error("This version of Ppmtompeg cannot run an I/O server because "
+             "it does not have socket capability.");
+}
+
+
+
+void
+SetIOConvert(boolean const separate) {
+    /* do nothing -- this may be called during non-parallel execution */
+}
+
+
+
+void
+SetParallelPerfect(boolean const val) {
+    /* do nothing -- this may be called during non-parallel execution */
+}
+
+
+void
+SetRemoteShell(const char * const shell) {
+    /* do nothing -- this may be called during non-parallel execution */
+}
+
+
+
+void
+NoteFrameDone(int const frameStart,
+              int const frameEnd) {
+    fprintf(stdout, 
+            "ERROR:  (NoteFrameDone) "
+            "This machine can NOT run parallel version\n");
+    exit(1);
+}
+
+
+
+/* SendRemoteFrame
+ */
+void
+SendRemoteFrame(int         const frameNumber,
+                BitBucket * const bb) {
+    fprintf(stdout, "ERROR:  (SendRemoteFrame) "
+            "This machine can NOT run parallel version\n");
+    exit(1);
+}
+
+
+
+/* GetRemoteFrame
+ */
+void
+GetRemoteFrame(MpegFrame * const frame,
+               int         const frameNumber) {
+
+    fprintf(stdout, "ERROR:  (GetRemoteFrame) "
+            "This machine can NOT run parallel version\n");
+    exit(1);
+}
+
+
+
+void
+WaitForOutputFile(int const number) {
+    fprintf(stdout, "ERROR:  (WaitForOutputFile) "
+            "This machine can NOT run parallel version\n");
+    exit(1);
+}
+
+
+
+/*=======================*
+ * PARALLEL SERVER STUFF *
+ *=======================*/
+
+
+void
+MasterServer(struct inputSource * const inputSourceP,
+             const char *         const paramFileName, 
+             const char *         const outputFileName) {
+
+    pm_error("This version of Ppmtompeg cannot run a master server because "
+             "it does not have socket capability.");
+}
+
+
+
+void
+CombineServer(int          const numFrames, 
+              const char * const masterHostName, 
+              int          const masterPortNum) {
+
+    pm_error("This version of Ppmtompeg cannot run combine server because "
+             "it does not have socket capability.");
+}
+
+
+
+void
+DecodeServer(int          const numInputFiles, 
+             const char * const decodeFileName, 
+             const char * const masterHostName, 
+             int          const masterPortNum) {
+
+    pm_error("This version of Ppmtompeg cannot run a decode server because "
+             "it does not have socket capability.");
+}
+
+
+
+void
+NotifyMasterDone(const char * const hostName, 
+                 int          const portNum, 
+                 int          const machineNumber, 
+                 unsigned int const seconds,
+                 boolean *    const moreWorkToDoP,
+                 int *        const frameStartP,
+                 int *        const frameEndP) {
+    pm_error("This version of Ppmtompeg cannot run parallel mode because "
+             "it does not have socket capability.");
+}
+
+
+
+void
+NotifyDecodeServerReady(int const id) {
+    pm_error("This version of Ppmtompeg cannot run parallel mode because "
+             "it does not have socket capability.");
+}
+
+
+
+void
+WaitForDecodedFrame(int const id) {
+    pm_error("This version of Ppmtompeg cannot run parallel mode because "
+             "it does not have socket capability.");
+}
+
+
+
+void
+SendDecodedFrame(MpegFrame * const frame) {
+    pm_error("This version of Ppmtompeg cannot run parallel mode because "
+             "it does not have socket capability.");
+}
+
+
+
+void
+GetRemoteDecodedRefFrame(MpegFrame * const frame,
+                         int         const frameNumber) {
+    pm_error("This version of Ppmtompeg cannot run parallel mode because "
+             "it does not have socket capability.");
+}
diff --git a/converter/ppm/ppmtompeg/opts.c b/converter/ppm/ppmtompeg/opts.c
new file mode 100644
index 00000000..c4d0c0b3
--- /dev/null
+++ b/converter/ppm/ppmtompeg/opts.c
@@ -0,0 +1,536 @@
+/*===========================================================================*
+ * opts.c								     *
+ *									     *
+ *      Special C code to handle TUNEing options                             *
+ *									     *
+ * EXPORTED PROCEDURES:							     *
+ *      Tune_Init                                                            *
+ *      CollectQuantStats                                                    *
+ *									     *
+ *===========================================================================*/
+
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ * 
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ * 
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include "opts.h"
+
+/*==============*
+ * EXTERNALS    *
+ *==============*/
+
+extern char    outputFileName[];
+extern boolean pureDCT;
+extern int32   qtable[], niqtable[];
+extern int     ZAG[];
+extern boolean printSNR, decodeRefFrames;
+
+void init_idctref _ANSI_ARGS_((void));
+void init_fdct _ANSI_ARGS_((void));
+
+
+/*===================*
+ * GLOBALS MADE HERE *
+ *===================*/
+
+boolean tuneingOn = FALSE;
+int block_bound = 128;
+boolean collect_quant = FALSE;
+int collect_quant_detailed = 0;
+FILE *collect_quant_fp;
+int kill_dim = FALSE;
+int kill_dim_break, kill_dim_end;
+float kill_dim_slope;
+int SearchCompareMode = DEFAULT_SEARCH;
+boolean squash_small_differences = FALSE;
+int SquashMaxLum, SquashMaxChr;
+float LocalDCTRateScale = 1.0, LocalDCTDistortScale = 1.0;
+boolean IntraPBAllowed = TRUE;
+boolean WriteDistortionNumbers = FALSE;
+int collect_distortion_detailed = 0;
+FILE *distortion_fp;
+FILE *fp_table_rate[31], *fp_table_dist[31];
+boolean DoLaplace = FALSE;
+double **L1, **L2, **Lambdas;
+int LaplaceNum, LaplaceCnum;
+boolean BSkipBlocks = TRUE;
+
+/* define this as it too much of a pain to find toupper on different arch'es */
+#define ASCII_TOUPPER(c) ((c>='a') && (c<='z')) ? c-'a'+'A' : c
+
+/*===============*
+ * Internals     *
+ *===============*/
+
+/*===========================================================================*
+ *
+ * SkipSpacesTabs
+ *
+ *	skip all spaces and tabs
+ *
+ * RETURNS:	point to next character not a space or tab
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static const char *
+SkipSpacesTabs(const char * const start) {
+
+    const char * p;
+
+    for (p = start; *p == ' ' || *p == '\t'; ++p);
+
+    return p;
+}
+
+
+
+/*===========================================================================*
+ *
+ * SetupCollectQuantStats
+ *
+ *     Setup variables to collect statistics on quantization values
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    sets collect_quant and collect_quant_fp
+ *
+ *===========================================================================*/
+static void 
+SetupCollectQuantStats(const char * const charPtr)
+{
+  char fname[256];
+  const char * cp;
+  cp = charPtr;
+  while ( (*cp != ' ') && (*cp != '\t') && (*cp != '\n')) {
+    cp++;
+  }
+
+  strncpy(fname, charPtr, cp-charPtr);
+  fname[cp-charPtr] = '\0';
+  collect_quant = TRUE;
+  if ((collect_quant_fp = fopen(fname,"w")) == NULL) {
+    fprintf(stderr, "Error opening %s for quant statistics\n", fname);
+    fprintf(stderr, "Using stdout (ick!)\n");
+    collect_quant_fp = stdout;
+  }
+
+  cp = SkipSpacesTabs(cp);
+  if (*cp != '\n') {
+    switch (*cp) {
+    case 'c':
+      collect_quant_detailed = 1;
+      break;
+    default:
+      fprintf(stderr, "Unknown TUNE parameter setting format %s\n", cp);
+    }}
+}
+
+
+
+
+/*===========================================================================*
+ *
+ * SetupKillDimAreas
+ *
+ *     Do a transform on small lum values
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    sets kill_dim, kill_dim_break, kill_dim_end
+ *
+ *===========================================================================*/
+static void 
+SetupKillDimAreas(const char * const charPtr)
+{
+  int items_scanned;
+
+  kill_dim = TRUE;
+  items_scanned = sscanf(charPtr, "%d %d %f", 
+			 &kill_dim_break, &kill_dim_end, &kill_dim_slope);
+  if (items_scanned != 3) {
+    kill_dim_slope = 0.25;
+    items_scanned = sscanf(charPtr, "%d %d", 
+			   &kill_dim_break, &kill_dim_end);
+    if (items_scanned != 2) {
+      /* Use defaults */
+      kill_dim_break = 20;
+      kill_dim_end   = 25;
+    }
+  }
+  /* check values */
+  if (kill_dim_break > kill_dim_end) {
+    fprintf(stderr, "TUNE parameter k: break > end is illegal.\n");
+    exit(-1);
+  }
+  if (kill_dim_slope < 0) {
+    fprintf(stderr, "TUNE parameter k: slope < 0 is illegal.\n");
+    exit(-1);
+  }
+}
+
+
+
+/*===========================================================================*
+ *
+ * SetupSquashSmall
+ *
+ *     Setup encoder to squash small changes in Y or Cr/Cb values
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    sets squash_max_differences SquashMaxLum SquashMaxChr 
+ *
+ *===========================================================================*/
+static void 
+SetupSquashSmall(const char * const charPtr)
+{
+  squash_small_differences = TRUE;
+
+  if (sscanf(charPtr, "%d %d", &SquashMaxLum, &SquashMaxChr) == 1) {
+    /* Only set one, do both */
+    SquashMaxChr = SquashMaxLum;
+  }
+}
+
+
+/*===========================================================================*
+ *
+ * SetupLocalDCT
+ *
+ *     Setup encoder to use DCT for rate-distortion estimat ein Psearches
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    sets SearchCompareMode and
+ *                        can change LocalDCTRateScale, LocalDCTDistortScale
+ *
+ *===========================================================================*/
+static void 
+SetupLocalDCT(const char * const charPtr)
+{
+  int num_scales=0;
+
+  SearchCompareMode = LOCAL_DCT;
+
+  /* Set scaling factors if present */
+  num_scales = sscanf(charPtr, "%f %f", &LocalDCTRateScale, &LocalDCTDistortScale);
+  if (num_scales == 1) {
+    fprintf(stderr, "Invalid number of scaling factors for local DCT\n");
+    fprintf(stderr, "Must specify Rate Scale and Distorion scale (both floats)\n");
+    fprintf(stderr, "Continuing with 1.0 1.0\n");
+    LocalDCTRateScale = 1.0;
+    LocalDCTDistortScale = 1.0;
+  }
+}
+
+
+/*===========================================================================*
+ *
+ * SetupLaplace
+ *
+ *     Setup encoder to find distrubution for I-frames, and use for -snr
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    sets DoLaplace, L1, L2, and Lambdas
+ *
+ *===========================================================================*/
+static void 
+SetupLaplace()
+{
+  int i;
+
+  DoLaplace = TRUE;
+  LaplaceNum = 0;
+  L1 = (double **)malloc(sizeof(double *)*3);
+  L2 = (double **)malloc(sizeof(double *)*3);
+  Lambdas = (double **)malloc(sizeof(double *)*3);
+  if (L1 == NULL || L2 == NULL || Lambdas == NULL) {
+    fprintf(stderr,"Out of memory!!!\n");
+    exit(1);
+  }
+  for (i = 0; i < 3; i++) {
+    L1[i] = (double *)calloc(64, sizeof(double));
+    L2[i] = (double *)calloc(64, sizeof(double));
+    Lambdas[i] = (double *)malloc(sizeof(double) * 64);
+    if (L1[i] == NULL || L2[i] == NULL || Lambdas[i] == NULL) {
+      fprintf(stderr,"Out of memory!!!\n");
+      exit(1);
+    }
+  }
+}
+
+static void
+SetupWriteDistortions(const char * const charPtr)
+{
+  char fname[256];
+  const char * cp;
+  int i;
+
+  WriteDistortionNumbers = TRUE;
+  cp = charPtr;
+  while ( (*cp != ' ') && (*cp != '\t') && (*cp != '\n')) {
+    cp++;
+  }
+
+  strncpy(fname, charPtr, cp-charPtr);
+  fname[cp-charPtr] = '\0';
+  collect_quant = TRUE;
+  if ((distortion_fp = fopen(fname,"w")) == NULL) {
+    fprintf(stderr, "Error opening %s for quant statistics\n", fname);
+    fprintf(stderr, "Using stdout (ick!)\n");
+    distortion_fp = stdout;
+  }
+
+  cp = SkipSpacesTabs(cp);
+  if (*cp != '\n') {
+    switch (*cp) {
+    case 'c':
+      collect_distortion_detailed = TRUE;
+      break;
+    case 't': {
+      char scratch[256];
+      collect_distortion_detailed = 2;
+      for (i = 1;  i < 32;  i++) {
+	sprintf(scratch, "%srate%d", fname, i);
+	fp_table_rate[i-1] = fopen(scratch, "w");
+	sprintf(scratch, "%sdist%d", fname, i);
+	fp_table_dist[i-1] = fopen(scratch, "w");
+	}}
+      break;
+    default:
+      fprintf(stderr, "Unknown TUNE parameter setting format %s\n", cp);
+    }}
+}  
+
+/*=====================*
+ * EXPORTED PROCEDURES *
+ *=====================*/
+
+void 
+CalcLambdas(void) {
+
+  int i,j,n;
+  double var;
+  
+  n = LaplaceNum;
+  for (i = 0;   i < 3;  i++) {
+    for (j = 0;  j < 64;  j++) {
+      var = (n*L1[i][j] + L2[i][j]*L2[i][j]) / (n*(n-1));
+      Lambdas[i][j] = sqrt(2.0) / sqrt(var);
+    }
+  }
+}
+
+
+/*===========================================================================*
+ *
+ * Mpost_UnQuantZigBlockLaplace
+ *
+ *	unquantize and zig-zag (decode) a single block, using the distrib to get vals
+ *      Iblocks only now
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+Mpost_UnQuantZigBlockLaplace(in, out, qscale, iblock)
+    FlatBlock in;
+    Block out;
+    int qscale;
+    boolean iblock;
+{
+    register int index;
+    int	    position;
+    register int	    qentry;
+    int	    level, coeff;
+    double low, high;
+    double mid,lam;
+
+    /* qtable[0] must be 8 */
+    out[0][0] = (int16)(in[0] * 8);
+    
+    for ( index = 1;  index < DCTSIZE_SQ;  index++ ) {
+      position = ZAG[index];
+      level = in[index];
+      
+      if (level == 0) {
+	((int16 *)out)[position] = 0;
+	continue;
+      }
+      qentry = qtable[position] * qscale;
+      coeff = (level*qentry)/8;
+      low = ((ABS(level)-.5)*qentry)/8;
+      high = ((ABS(level)+.5)*qentry)/8;
+      lam = Lambdas[LaplaceCnum][position];
+      mid = (1.0/lam) * log(0.5*(exp(-lam*low)+exp(-lam*high)));
+      mid = ABS(mid);
+      if (mid - floor(mid) > .4999) {
+	mid = ceil(mid);
+      } else {
+	mid = floor(mid);
+      }
+      if (level<0) {mid = -mid;}
+/*printf("(%2.1lf-%2.1lf): old: %d vs %d\n",low,high,coeff,(int) mid);*/
+      coeff = mid;
+      if ( (coeff & 1) == 0 ) {
+	if ( coeff < 0 ) {
+	  coeff++;
+	} else if ( coeff > 0 ) {
+	  coeff--;
+	}
+      }
+      ((int16 *)out)[position] = coeff;
+    }
+}
+
+int 
+mse(Block blk1, Block blk2)
+{
+  register int index, error, tmp;
+  int16 *bp1, *bp2;
+
+  bp1 = (int16 *)blk1;
+  bp2 = (int16 *)blk2;
+  error = 0;
+  for ( index = 0;  index < DCTSIZE_SQ;  index++ ) {
+    tmp = *bp1++ - *bp2++;
+    error += tmp*tmp;
+  }
+  return error;
+}
+
+
+
+
+/*===========================================================================*
+ *
+ * Tune_Init
+ *
+ *     Do any setup needed before coding stream
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:  varies
+ *
+ *===========================================================================*/
+void Tune_Init()
+{
+  int i;
+
+  /* Just check for each, and do whats needed */
+  if (collect_quant) {
+    if (!pureDCT) {
+      pureDCT = TRUE;
+      init_idctref();
+      init_fdct();
+    }
+    fprintf(collect_quant_fp, "# %s\n", outputFileName);
+    fprintf(collect_quant_fp, "#");
+    for (i=0; i<64; i++) 
+      fprintf(collect_quant_fp, " %d", qtable[i]);
+    fprintf(collect_quant_fp, "\n#");
+    for (i=0; i<64; i++) 
+      fprintf(collect_quant_fp, " %d", niqtable[i]);
+    fprintf(collect_quant_fp, "\n# %d %d %d\n\n", 
+	    GetIQScale(), GetPQScale(), GetBQScale());
+    
+  }
+
+  if (DoLaplace) {
+    if (!pureDCT) {
+      pureDCT = TRUE;
+      init_idctref();
+      init_fdct();
+    }
+    decodeRefFrames = TRUE;
+    printSNR = TRUE;
+  }
+    
+}
+
+/*===========================================================================*
+ *
+ * ParseTuneParam
+ *
+ *     Handle the strings following TUNE
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:  varies
+ *
+ *===========================================================================*/
+void ParseTuneParam(const char * const charPtr)
+{
+  switch (ASCII_TOUPPER(*charPtr)) {
+  case 'B': 
+    if (1 != sscanf(charPtr+2, "%d", &block_bound)) {
+      fprintf(stderr, "Invalid tuning parameter (b) in parameter file.\n");
+    }
+    break;
+  case 'C':
+    SetupCollectQuantStats(charPtr+2);
+    break;
+  case 'D':
+    SetupLocalDCT(SkipSpacesTabs(charPtr+1));
+    break;
+  case 'K':
+    SetupKillDimAreas(SkipSpacesTabs(charPtr+1));
+    break;
+  case 'L':
+    SetupLaplace();
+    break;
+  case 'N':
+    SearchCompareMode = NO_DC_SEARCH;
+    break;
+  case 'Q':
+    SearchCompareMode = DO_Mean_Squared_Distortion;
+    break;
+  case 'S':
+    SetupSquashSmall(SkipSpacesTabs(charPtr+1));
+    break;
+  case 'W':
+    SetupWriteDistortions(SkipSpacesTabs(charPtr+1));
+    break;
+  case 'U':
+    BSkipBlocks = FALSE;
+    break;
+  case 'Z':
+     IntraPBAllowed = FALSE;
+    break;
+  default:
+    fprintf(stderr, "Unknown tuning (%s) in parameter file.\n",charPtr);
+    break;
+  }
+}
+
+
diff --git a/converter/ppm/ppmtompeg/parallel.c b/converter/ppm/ppmtompeg/parallel.c
new file mode 100644
index 00000000..021e6d2b
--- /dev/null
+++ b/converter/ppm/ppmtompeg/parallel.c
@@ -0,0 +1,2278 @@
+/*===========================================================================*
+ * parallel.c              
+ *                         
+ *  Procedures to make encoder run in parallel   
+ *                             
+ *===========================================================================*/
+
+/* COPYRIGHT INFORMATION IS AT THE END OF THIS FILE */
+
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#define _XOPEN_SOURCE 500 /* Make sure stdio.h contains pclose() */
+/* _ALL_SOURCE is needed on AIX to make the C library include the 
+   socket services (e.g. define struct sockaddr) 
+
+   Note that AIX standards.h actually sets feature declaration macros such
+   as _XOPEN_SOURCE, unless they are already set.
+*/
+#define _ALL_SOURCE
+
+/* On AIX, pm_config.h includes standards.h, which expects to be included
+   after feature declaration macros such as _XOPEN_SOURCE.  So we include
+   pm_config.h as late as possible.
+*/
+
+
+#include <stdarg.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <netdb.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/times.h>
+
+#include "mallocvar.h"
+#include "nstring.h"
+
+#include "pm.h"
+
+#include "all.h"
+#include "param.h"
+#include "mpeg.h"
+#include "prototypes.h"
+#include "readframe.h"
+#include "fsize.h"
+#include "combine.h"
+#include "frames.h"
+#include "input.h"
+#include "psocket.h"
+#include "frametype.h"
+#include "gethostname.h"
+
+#include "parallel.h"
+
+
+struct childState {
+    boolean      finished;
+    unsigned int startFrame;
+    unsigned int numFrames;
+    unsigned int lastNumFrames;
+    unsigned int numSeconds;
+    float        fps;
+};
+
+
+struct scheduler {
+    /* This tracks the state of the subsystem that determines the assignments
+       for the children
+    */
+    unsigned int nextFrame;
+        /* The next frame that needs to be assigned to a child */
+    unsigned int numFramesInJob;
+        /* Total number of frames in the whole run of Ppmtompeg */
+    unsigned int numMachines;
+};
+
+
+
+#define MAX_IO_SERVERS  10
+#ifndef SOMAXCONN
+#define SOMAXCONN 5
+#endif
+
+/*==================*
+ * CONSTANTS        *
+ *==================*/
+
+#define TERMINATE_PID_SIGNAL    SIGTERM  /* signal used to terminate forked childs */
+#ifndef MAXARGS
+#define MAXARGS     1024   /* Max Number of arguments in safe_fork command */
+#endif
+
+/*==================*
+ * STATIC VARIABLES *
+ *==================*/
+
+static char rsh[256];
+static struct hostent *hostEntry = NULL;
+static boolean  *frameDone;
+static int  outputServerSocket;
+static int  decodeServerSocket;
+static boolean  parallelPerfect = FALSE;
+static  int current_max_forked_pid=0;
+
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+
+extern int yuvHeight, yuvWidth;
+extern char statFileName[256];
+extern FILE *statFile;
+extern boolean debugMachines;
+extern boolean debugSockets;
+int parallelTestFrames = 10;
+int parallelTimeChunks = 60;
+const char *IOhostName;
+int ioPortNumber;
+int decodePortNumber;
+boolean niceProcesses = FALSE;
+boolean forceIalign = FALSE;
+int     machineNumber = -1;
+boolean remoteIO = FALSE;
+bool separateConversion;
+    /* The I/O server will convert from the input format to the base format,
+       and the slave will convert from the base format to the YUV internal
+       format.  If false, the I/O server assumes the input format is the
+       base format and converts from the base format to the YUV internal
+       format; the slave does no conversion.
+    */
+time_t  IOtime = 0;
+extern char encoder_name[];
+int     ClientPid[MAX_MACHINES+4];
+
+
+/*=====================*
+ * INTERNAL PROCEDURES *
+ *=====================*/
+
+
+static void PM_GNU_PRINTF_ATTR(1,2)
+machineDebug(const char format[], ...) {
+
+    va_list args;
+
+    va_start(args, format);
+
+    if (debugMachines) {
+        const char * const hostname = GetHostName();
+        fprintf(stderr, "%s: ---", hostname);
+        strfree(hostname);
+        vfprintf(stderr, format, args);
+        fputc('\n', stderr);
+    }
+    va_end(args);
+}
+
+
+
+static void PM_GNU_PRINTF_ATTR(1,2)
+errorExit(const char format[], ...) {
+
+    const char * const hostname = GetHostName();
+
+    va_list args;
+
+    va_start(args, format);
+
+    fprintf(stderr, "%s: FATAL ERROR.  ", hostname);
+    strfree(hostname);
+    vfprintf(stderr, format, args);
+    fputc('\n', stderr);
+
+    exit(1);
+
+    va_end(args);
+}
+
+
+
+static void
+TransmitPortNum(const char * const hostName, 
+                int          const portNum, 
+                int          const newPortNum) {
+/*----------------------------------------------------------------------------
+   Transmit the port number 'newPortNum' to the master on port 'portNum'
+   of host 'hostName'.
+-----------------------------------------------------------------------------*/
+    int clientSocket;
+    const char * error;
+    
+    ConnectToSocket(hostName, portNum, &hostEntry, &clientSocket, &error);
+    
+    if (error)
+        errorExit("Can't connect in order to transmit port number.  %s",
+                  error);
+
+    WriteInt(clientSocket, newPortNum);
+    
+    close(clientSocket);
+}
+
+
+
+static void
+readYUVDecoded(int          const socketFd,
+               unsigned int const Fsize_x,
+               unsigned int const Fsize_y,
+               MpegFrame *  const frameP) {
+    
+    unsigned int y;
+    
+    for (y = 0; y < Fsize_y; ++y)         /* Y */
+        ReadBytes(socketFd, 
+                  (unsigned char *)frameP->decoded_y[y], Fsize_x);
+    
+    for (y = 0; y < (Fsize_y >> 1); ++y)  /* U */
+        ReadBytes(socketFd, 
+                  (unsigned char *)frameP->decoded_cb[y], (Fsize_x >> 1));
+    
+    for (y = 0; y < (Fsize_y >> 1); ++y)  /* V */
+        ReadBytes(socketFd, 
+                  (unsigned char *)frameP->decoded_cr[y], (Fsize_x >> 1));
+}
+
+
+
+static void
+writeYUVDecoded(int          const socketFd,
+                unsigned int const Fsize_x,
+                unsigned int const Fsize_y,
+                MpegFrame *  const frameP) {
+    
+    unsigned int y;
+    
+    for (y = 0; y < Fsize_y; ++y)         /* Y */
+        WriteBytes(socketFd, 
+                  (unsigned char *)frameP->decoded_y[y], Fsize_x);
+    
+    for (y = 0; y < (Fsize_y >> 1); ++y)  /* U */
+        WriteBytes(socketFd, 
+                   (unsigned char *)frameP->decoded_cb[y], (Fsize_x >> 1));
+    
+    for (y = 0; y < (Fsize_y >> 1); ++y)  /* V */
+        WriteBytes(socketFd, 
+                   (unsigned char *)frameP->decoded_cr[y], (Fsize_x >> 1));
+}
+
+
+
+static void
+writeYUVOrig(int          const socketFd,
+             unsigned int const Fsize_x,
+             unsigned int const Fsize_y,
+             MpegFrame *  const frameP) {
+    
+    unsigned int y;
+    
+    for (y = 0; y < Fsize_y; ++y)         /* Y */
+        WriteBytes(socketFd, 
+                  (unsigned char *)frameP->orig_y[y], Fsize_x);
+    
+    for (y = 0; y < (Fsize_y >> 1); ++y)  /* U */
+        WriteBytes(socketFd, 
+                   (unsigned char *)frameP->orig_cb[y], (Fsize_x >> 1));
+    
+    for (y = 0; y < (Fsize_y >> 1); ++y)  /* V */
+        WriteBytes(socketFd, 
+                   (unsigned char *)frameP->orig_cr[y], (Fsize_x >> 1));
+}
+
+
+
+static void
+readYUVOrig(int          const socketFd,
+            unsigned int const Fsize_x,
+            unsigned int const Fsize_y,
+            MpegFrame *  const frameP) {
+    
+    unsigned int y;
+    
+    for (y = 0; y < Fsize_y; ++y)         /* Y */
+        ReadBytes(socketFd, 
+                  (unsigned char *)frameP->orig_y[y], Fsize_x);
+    
+    for (y = 0; y < (Fsize_y >> 1); ++y)  /* U */
+        ReadBytes(socketFd, 
+                  (unsigned char *)frameP->orig_cb[y], (Fsize_x >> 1));
+    
+    for (y = 0; y < (Fsize_y >> 1); ++y)  /* V */
+        ReadBytes(socketFd, 
+                  (unsigned char *)frameP->orig_cr[y], (Fsize_x >> 1));
+}
+
+
+
+/*===========================================================================*
+ *
+ * EndIOServer
+ *
+ *  called by the master process -- tells the I/O server to commit
+ *  suicide
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+  EndIOServer()
+{
+  /* send signal to IO server:  -1 as frame number */
+  GetRemoteFrame(NULL, -1);
+}
+
+
+/*===========================================================================*
+ *
+ * NotifyDecodeServerReady
+ *
+ *  called by a slave to the Decode Server to tell it a decoded frame
+ *  is ready and waiting
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+NotifyDecodeServerReady(int const id) {
+
+    int   clientSocket;
+    time_t  tempTimeStart, tempTimeEnd;
+    const char * error;
+    
+    time(&tempTimeStart);
+    
+    ConnectToSocket(IOhostName, decodePortNumber, &hostEntry, &clientSocket,
+                    &error);
+    
+    if (error)
+        errorExit("CHILD: Can't connect to decode server to tell it a frame "
+                "is ready.  %s", error);
+    
+    WriteInt(clientSocket, id);
+    
+    close(clientSocket);
+    
+    time(&tempTimeEnd);
+    IOtime += (tempTimeEnd-tempTimeStart);
+}
+
+
+
+/*===========================================================================*
+ *
+ * WaitForDecodedFrame
+ *
+ *  blah blah blah
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+  WaitForDecodedFrame(id)
+int id;
+{
+  int const negativeTwo = -2;
+  int   clientSocket;
+  int     ready;
+  const char * error;
+
+  /* wait for a decoded frame */
+  if ( debugSockets ) {
+    fprintf(stdout, "WAITING FOR DECODED FRAME %d\n", id);
+  }
+
+  ConnectToSocket(IOhostName, decodePortNumber, &hostEntry, &clientSocket,
+                  &error);
+
+  if (error)
+      errorExit("CHILD: Can't connect to decode server "
+                "to get decoded frame.  %s",
+                error);
+
+  /* first, tell DecodeServer we're waiting for this frame */
+  WriteInt(clientSocket, negativeTwo);
+
+  WriteInt(clientSocket, id);
+
+  ReadInt(clientSocket, &ready);
+
+  if ( ! ready ) {
+    int     waitSocket;
+    int     waitPort;
+    int     otherSock;
+    const char * error;
+
+    /* it's not ready; set up a connection and wait for decode server */
+    CreateListeningSocket(&waitSocket, &waitPort, &error);
+    if (error)
+        errorExit("Unable to create socket on which to listen for "
+                  "decoded frame.  %s", error);
+
+    /* tell decode server where we are */
+    WriteInt(clientSocket, machineNumber);
+
+    WriteInt(clientSocket, waitPort);
+
+    close(clientSocket);
+
+    if ( debugSockets ) {
+      fprintf(stdout, "SLAVE:  WAITING ON SOCKET %d\n", waitPort);
+      fflush(stdout);
+    }
+
+    AcceptConnection(waitSocket, &otherSock, &error);
+    if (error)
+        errorExit("I/O SERVER: Failed to accept next connection.  %s", error);
+
+    /* should we verify this is decode server? */
+    /* for now, we won't */
+
+    close(otherSock);
+
+    close(waitSocket);
+  } else {
+    close(clientSocket);
+  }
+
+  if ( debugSockets ) {
+    fprintf(stdout, "YE-HA FRAME %d IS NOW READY\n", id);
+  }
+}
+
+
+/*===========================================================================*
+ *
+ * SendDecodedFrame
+ *
+ *  Send the frame to the decode server.
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+SendDecodedFrame(MpegFrame * const frameP) {
+/*----------------------------------------------------------------------------
+   Send frame *frameP to the decode server.
+-----------------------------------------------------------------------------*/
+    int const negativeTwo = -2;
+    
+    int clientSocket;
+    const char * error;
+    
+    /* send to IOServer */
+    ConnectToSocket(IOhostName, ioPortNumber, &hostEntry,
+                    &clientSocket, &error);
+    if (error)
+        errorExit("CHILD: Can't connect to decode server to "
+                  "give it a decoded frame.  %s", error);
+    
+    WriteInt(clientSocket, negativeTwo);
+    
+    WriteInt(clientSocket, frameP->id);
+
+    writeYUVDecoded(clientSocket, Fsize_x, Fsize_y, frameP);
+    
+    close(clientSocket);
+}
+
+
+/*===========================================================================*
+ *
+ * GetRemoteDecodedFrame
+ *
+ *  get the decoded frame from the decode server.
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:   
+ *
+ *===========================================================================*/
+void
+GetRemoteDecodedRefFrame(MpegFrame * const frameP, 
+                         int         const frameNumber) {
+/*----------------------------------------------------------------------------
+   Get decoded frame number 'frameNumber' *frameP from the decode server.
+-----------------------------------------------------------------------------*/
+  int const negativeThree = -3;
+  int clientSocket;
+  const char * error;
+
+  /* send to IOServer */
+  ConnectToSocket(IOhostName, ioPortNumber, &hostEntry,
+                  &clientSocket, &error);
+  if (error)
+      errorExit("CHILD: Can't connect to decode server "
+                "to get a decoded frame.  %s",
+                error);
+
+  /* ask IOServer for decoded frame */
+  WriteInt(clientSocket, negativeThree);
+
+  WriteInt(clientSocket, frameP->id);
+
+  readYUVDecoded(clientSocket, Fsize_x, Fsize_y, frameP);
+
+  close(clientSocket);
+}
+
+
+/*********
+  routines handling forks, execs, PIDs and signals
+  save, system-style forks
+  apian@ise.fhg.de
+  *******/
+
+
+/*===========================================================================*
+ *
+ * cleanup_fork
+ *
+ *  Kill all the children, to be used when we get killed
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:   kills other processes
+ *
+ *===========================================================================*/
+static void cleanup_fork( dummy )       /* try to kill all child processes */
+     int dummy;
+{
+  register int i;
+  for (i = 0;  i < current_max_forked_pid;  ++i ) {
+
+#ifdef DEBUG_FORK
+    fprintf(stderr, "cleanup_fork: killing PID %d\n", ClientPid[i]);
+#endif
+
+    if (kill(ClientPid[i], TERMINATE_PID_SIGNAL)) {
+      fprintf(stderr, "cleanup_fork: killed PID=%d failed (errno %d)\n", 
+          ClientPid[i], errno);
+    }
+  }
+}
+
+/*===========================================================================*
+ *
+ * safe_fork
+ *
+ *  fork a command
+ *
+ * RETURNS:     success/failure
+ *
+ * SIDE EFFECTS:   Fork the command, and save to PID so you can kil it later!
+ *
+ *===========================================================================*/
+static int safe_fork(command)       /* fork child process and remember its PID */
+     char *command;
+{
+  static int init=0;
+  char *argis[MAXARGS];
+  register int i=1;
+  
+  if (!(argis[0] = strtok(command, " \t"))) return(0); /* tokenize */
+  while ((argis[i] = strtok(NULL, " \t")) && i < MAXARGS) ++i;
+  argis[i] = NULL;
+  
+#ifdef DEBUG_FORK
+  {register int i=0; 
+   fprintf(stderr, "Command %s becomes:\n", command);
+   while(argis[i]) {fprintf(stderr, "--%s--\n", argis[i]); ++i;} }
+#endif
+  
+  if (!init) {          /* register clean-up routine */
+    signal (SIGQUIT, cleanup_fork);
+    signal (SIGTERM, cleanup_fork);
+    signal (SIGINT , cleanup_fork);
+    init=1;
+  }
+  
+  if (-1 == (ClientPid[current_max_forked_pid] = fork()) )  {
+    perror("safe_fork: fork failed ");
+    return(-1);
+  }
+  if( !ClientPid[current_max_forked_pid]) { /* we are in child process */
+    execvp(argis[0], argis );
+    perror("safe_fork child: exec failed ");
+    exit(1);
+  }
+#ifdef DEBUG_FORK
+  fprintf(stderr, "parallel: forked PID=%d\n", ClientPid[current_max_forked_pid]);
+#endif
+  current_max_forked_pid++;
+  return(0);
+}
+
+
+/*=====================*
+ * EXPORTED PROCEDURES *
+ *=====================*/
+
+            /*=================*
+             * IO SERVER STUFF *
+             *=================*/
+
+
+/*===========================================================================*
+ *
+ * SetIOConvert
+ *
+ *  sets the IO conversion to be separate or not.  If separate, then
+ *  some post-processing is done at slave end
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+SetIOConvert(bool const separate) {
+    separateConversion = separate;
+}
+
+
+/*===========================================================================*
+ *
+ * SetParallelPerfect
+ *
+ *  If this is called, then frames will be divided up completely, and
+ *  evenly (modulo rounding) between all the processors
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    Sets parallelPerfect ....
+ *
+ *===========================================================================*/
+void
+SetParallelPerfect(val)
+boolean val;
+{
+    parallelPerfect = val;
+}
+
+
+/*===========================================================================*
+ *
+ * SetRemoteShell
+ *
+ *  sets the remote shell program (usually rsh, but different on some
+ *  machines)
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+SetRemoteShell(const char * const shell) {
+    strcpy(rsh, shell);
+}
+
+
+static void
+decodedFrameToDisk(int const otherSock) {
+/*----------------------------------------------------------------------------
+  Get a decoded from from socket 'otherSock' and write it to disk.
+-----------------------------------------------------------------------------*/
+    int frameNumber;
+    MpegFrame * frameP;
+
+    ReadInt(otherSock, &frameNumber);
+    
+    if (debugSockets) {
+        fprintf(stdout, "INPUT SERVER:  GETTING DECODED FRAME %d\n", 
+                frameNumber);
+        fflush(stdout);
+    }
+
+    /* should read frame from socket, then write to disk */
+    frameP = Frame_New(frameNumber, 'i');
+    
+    Frame_AllocDecoded(frameP, TRUE);
+    
+    readYUVDecoded(otherSock, Fsize_x, Fsize_y, frameP);
+
+    /* now output to disk */
+    WriteDecodedFrame(frameP);
+
+    Frame_Free(frameP);
+}        
+
+
+
+static void
+decodedFrameFromDisk(int const otherSock) {
+
+    /* request for decoded frame from disk */
+            
+    int frameNumber;
+    MpegFrame * frameP;
+
+    ReadInt(otherSock, &frameNumber);
+    
+    if (debugSockets) {
+        fprintf(stdout, "INPUT SERVER:  READING DECODED FRAME %d "
+                "from DISK\n", frameNumber);
+        fflush(stdout);
+    }
+
+    /* should read frame from disk, then write to socket */
+    frameP = Frame_New(frameNumber, 'i');
+    
+    Frame_AllocDecoded(frameP, TRUE);
+    
+    ReadDecodedRefFrame(frameP, frameNumber);
+    
+    writeYUVDecoded(otherSock, Fsize_x, Fsize_y, frameP);
+    
+    Frame_Free(frameP);
+}        
+
+
+
+static void
+routeFromSocketToDisk(int              const otherSock,
+                      unsigned char ** const bigBufferP,
+                      unsigned int *   const bigBufferSizeP) {
+
+    /* routing output frame from socket to disk */
+
+    int frameNumber;
+    int numBytes;
+    unsigned char * bigBuffer;
+    unsigned int bigBufferSize;
+    const char * fileName;
+    FILE * filePtr;
+
+    bigBuffer     = *bigBufferP;
+    bigBufferSize = *bigBufferSizeP;
+
+    ReadInt(otherSock, &frameNumber);
+    ReadInt(otherSock, &numBytes);
+
+    /* Expand bigBuffer if necessary to fit this frame */
+    if (numBytes > bigBufferSize) {
+        bigBufferSize = numBytes;
+        if (bigBuffer != NULL)
+            free(bigBuffer);
+
+        MALLOCARRAY_NOFAIL(bigBuffer, bigBufferSize);
+    }
+    
+    /* now read in the bytes */
+    ReadBytes(otherSock, bigBuffer, numBytes);
+    
+    /* open file to output this stuff to */
+    asprintfN(&fileName, "%s.frame.%d", outputFileName, frameNumber);
+    filePtr = fopen(fileName, "wb");
+
+    if (filePtr == NULL)
+        errorExit("I/O SERVER: Could not open output file(3):  %s", fileName);
+
+    strfree(fileName);
+
+    /* now write the bytes here */
+    fwrite(bigBuffer, sizeof(char), numBytes, filePtr);
+    
+    fclose(filePtr);
+    
+    if (debugSockets) {
+        fprintf(stdout, "====I/O SERVER:  WROTE FRAME %d to disk\n",
+                frameNumber);
+        fflush(stdout);
+    }
+
+    *bigBufferP     = bigBuffer;
+    *bigBufferSizeP = bigBufferSize;
+}        
+
+
+
+static void
+readConvertWriteToSocket(struct inputSource * const inputSourceP,
+                         int                  const otherSock,
+                         int                  const frameNumber,
+                         bool *               const endOfStreamP) {
+/*----------------------------------------------------------------------------
+   Get the frame numbered 'frameNumber' from input source
+   *inputSourceP, apply format conversion User requested, and write
+   the "base format" result to socket 'otherSock'.
+-----------------------------------------------------------------------------*/
+    FILE * convertedFileP;
+    
+    convertedFileP = ReadIOConvert(inputSourceP, frameNumber);
+    if (convertedFileP) {
+        bool eof;
+        eof = FALSE;  /* initial value */
+        while (!eof) {
+            unsigned char buffer[1024];
+            unsigned int numBytes;
+            
+            numBytes = fread(buffer, 1, sizeof(buffer), convertedFileP);
+            
+            if (numBytes > 0) {
+                WriteInt(otherSock, numBytes);
+                WriteBytes(otherSock, buffer, numBytes);
+            } else
+                eof = TRUE;
+        }
+        
+        if (strcmp(ioConversion, "*") == 0 )
+            fclose(convertedFileP);
+        else
+            pclose(convertedFileP);
+        
+        *endOfStreamP = FALSE;
+    } else
+        *endOfStreamP = TRUE;
+}
+
+
+
+static void
+readWriteYuvToSocket(struct inputSource * const inputSourceP,
+                     int                  const otherSock,
+                     int                  const frameNumber,
+                     bool *               const endOfStreamP) {
+/*----------------------------------------------------------------------------
+   Read Frame number 'frameNumber' from the input source *inputSourceP,
+   assuming it is in base format, and write its contents in YUV format
+   to socket 'otherSock'.
+
+   Wait for acknowledgement that consumer has received it.
+-----------------------------------------------------------------------------*/
+    MpegFrame * frameP;
+
+    frameP = Frame_New(frameNumber, 'i');
+    
+    ReadFrame(frameP, inputSourceP, frameNumber, inputConversion,
+              endOfStreamP);
+    
+    if (!*endOfStreamP) {
+        writeYUVOrig(otherSock, Fsize_x, Fsize_y, frameP);
+        
+        {
+            /* Make sure we don't leave until other processor read
+               everything
+            */
+            int dummy;
+            ReadInt(otherSock, &dummy);
+            assert(dummy == 0);
+        }
+    }
+    Frame_Free(frameP);
+}
+
+
+
+static void
+readFrameWriteToSocket(struct inputSource * const inputSourceP,
+                       int                  const otherSock,
+                       int                  const frameNumber,
+                       bool *               const endOfStreamP) {
+/*----------------------------------------------------------------------------
+   Read Frame number 'frameNumber' from the input source *inputSourceP
+   and write it to socket 'otherSock'.
+-----------------------------------------------------------------------------*/
+    if (debugSockets) {
+        fprintf(stdout, "I/O SERVER GETTING FRAME %d\n", frameNumber);
+        fflush(stdout);
+    }
+
+    if (separateConversion)
+        readConvertWriteToSocket(inputSourceP, otherSock, frameNumber,
+                                 endOfStreamP);
+    else
+        readWriteYuvToSocket(inputSourceP, otherSock, frameNumber,
+                             endOfStreamP);
+
+    if (debugSockets) {
+        fprintf(stdout, "====I/O SERVER:  READ FRAME %d\n", frameNumber);
+    }
+}
+
+
+
+static void
+processNextConnection(int                  const serverSocket,
+                      struct inputSource * const inputSourceP,
+                      bool *               const doneP,
+                      unsigned char **     const bigBufferP,
+                      unsigned int *       const bigBufferSizeP) {
+
+    int          otherSock;
+    int          command;
+    const char * error;
+    
+    AcceptConnection(serverSocket, &otherSock, &error);
+    if (error)
+        errorExit("I/O SERVER: Failed to accept next connection.  %s", error);
+
+    ReadInt(otherSock, &command);
+
+    switch (command) {
+    case -1:
+        *doneP = TRUE;
+        break;
+    case -2:
+        decodedFrameToDisk(otherSock);
+        break;
+    case -3:
+        decodedFrameFromDisk(otherSock);
+        break;
+    case -4:
+        routeFromSocketToDisk(otherSock, bigBufferP, bigBufferSizeP);
+        break;
+    default: {
+        unsigned int const frameNumber = command;
+
+        bool endOfStream;
+
+        readFrameWriteToSocket(inputSourceP, otherSock, frameNumber,
+                               &endOfStream);
+
+        if (endOfStream) {
+            /* We don't do anything.  Closing the socket with having written
+               anything is our signal that there is no more input.
+
+               (Actually, Ppmtompeg cannot handle stream input in parallel
+               mode -- this code is just infrastructure so maybe it can some
+               day).
+            */
+        }
+    }
+    }
+    close(otherSock);
+}
+ 
+
+
+void
+IoServer(struct inputSource * const inputSourceP,
+         const char *         const parallelHostName, 
+         int                  const portNum) {
+/*----------------------------------------------------------------------------
+   Execute an I/O server.
+
+   An I/O server is the partner on the master machine of a child process
+   on a "remote" system.  "Remote" here doesn't just mean on another system.
+   It means on a system that isn't even in the same cluster -- specifically,
+   a system that doesn't have access to the same filesystem as the master.
+
+   The child process passes frame contents between it and the master via
+   the I/O server.
+-----------------------------------------------------------------------------*/
+    int       ioPortNum;
+    int       serverSocket;
+    boolean   done;
+    unsigned char   *bigBuffer;
+        /* A work buffer that we keep around permanently.  We increase
+           its size as needed, but never shrink it.
+        */
+    unsigned int bigBufferSize;
+        /* The current allocated size of bigBuffer[] */
+    const char * error;
+
+    bigBufferSize = 0;  /* Start with no buffer */
+    bigBuffer = NULL;
+    
+    /* once we get IO port num, should transmit it to parallel server */
+
+    CreateListeningSocket(&serverSocket, &ioPortNum, &error);
+    if (error)
+        errorExit("Unable to create socket on which to listen for "
+                  "reports from children.  %s", error);
+
+    if (debugSockets)
+        fprintf(stdout, "====I/O USING PORT %d\n", ioPortNum);
+
+    TransmitPortNum(parallelHostName, portNum, ioPortNum);
+
+    if (separateConversion)
+        SetFileType(ioConversion);  /* for reading */
+    else
+        SetFileType(inputConversion);
+
+    done = FALSE;  /* initial value */
+
+    while (!done)
+        processNextConnection(serverSocket, inputSourceP,
+                              &done, &bigBuffer, &bigBufferSize);
+
+    close(serverSocket);
+
+    if ( debugSockets ) {
+        fprintf(stdout, "====I/O SERVER:  Shutting Down\n");
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ * SendRemoteFrame
+ *
+ *  called by a slave to the I/O server; sends an encoded frame
+ *  to the server to be sent to disk
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+SendRemoteFrame(int const frameNumber, BitBucket * const bb) {
+
+    int const negativeFour = -4;
+    int clientSocket;
+    time_t  tempTimeStart, tempTimeEnd;
+    const char * error;
+
+    time(&tempTimeStart);
+
+    ConnectToSocket(IOhostName, ioPortNumber, &hostEntry,
+                    &clientSocket, &error);
+    if (error)
+        errorExit("CHILD: Can't connect to I/O server to deliver results.  %s",
+                  error);
+
+    WriteInt(clientSocket, negativeFour);
+
+    WriteInt(clientSocket, frameNumber);
+    
+    if (frameNumber != -1) {
+        /* send number of bytes */
+        
+        WriteInt(clientSocket, (bb->totalbits+7)>>3);
+    
+        /* now send the bytes themselves */
+        Bitio_WriteToSocket(bb, clientSocket);
+    }
+
+    close(clientSocket);
+
+    time(&tempTimeEnd);
+    IOtime += (tempTimeEnd-tempTimeStart);
+}
+
+
+
+void
+GetRemoteFrame(MpegFrame * const frameP, 
+               int         const frameNumber) {
+/*----------------------------------------------------------------------------
+   Get a frame from the I/O server.
+   
+   This is intended for use by a child.
+-----------------------------------------------------------------------------*/
+    int           clientSocket;
+    const char * error;
+
+    Fsize_Note(frameNumber, yuvWidth, yuvHeight);
+
+    if (debugSockets) {
+        fprintf(stdout, "MACHINE %s REQUESTING connection for FRAME %d\n",
+                getenv("HOST"), frameNumber);
+        fflush(stdout);
+    }
+
+    ConnectToSocket(IOhostName, ioPortNumber, &hostEntry,
+                    &clientSocket, &error);
+
+    if (error)
+        errorExit("CHILD: Can't connect to I/O server to get a frame.  %s", 
+                  error);
+
+    WriteInt(clientSocket, frameNumber);
+
+    if (frameNumber != -1) {
+        if (separateConversion) {
+            unsigned char buffer[1024];
+            /* This is by design the exact size of the data per message (except
+               the last message for a frame) the I/O server sends.
+            */
+            int numBytes;  /* Number of data bytes in message */
+            FILE * filePtr = pm_tmpfile();
+
+            /* read in stuff, write to file, perform local conversion */
+            do {
+                ReadInt(clientSocket, &numBytes);
+
+                if (numBytes > sizeof(buffer))
+                    errorExit("Invalid message received: numBytes = %d, "
+                              "which is greater than %d\n", 
+                              numBytes, sizeof(numBytes));
+                ReadBytes(clientSocket, buffer, numBytes);
+
+                fwrite(buffer, 1, numBytes, filePtr);
+            } while ( numBytes == sizeof(buffer) );
+            fflush(filePtr);
+            {
+                bool endOfStream;
+                rewind(filePtr);
+                /* I/O Server gave us base format.  Read it as an MpegFrame */
+                ReadFrameFile(frameP, filePtr, slaveConversion, &endOfStream);
+                assert(!endOfStream);
+            }
+            fclose(filePtr);
+        } else {
+            Frame_AllocYCC(frameP);
+
+            if (debugSockets) {
+                fprintf(stdout, "MACHINE %s allocated YCC FRAME %d\n",
+                        getenv("HOST"), frameNumber);
+                fflush(stdout);
+            }
+            /* I/O Server gave us internal YUV format.  Read it as MpegFrame */
+            readYUVOrig(clientSocket, yuvWidth, yuvHeight, frameP);
+        }
+    }
+
+    WriteInt(clientSocket, 0);
+
+    close(clientSocket);
+
+    if (debugSockets) {
+        fprintf(stdout, "MACHINE %s READ COMPLETELY FRAME %d\n",
+                getenv("HOST"), frameNumber);
+        fflush(stdout);
+    }
+}
+
+
+struct combineControl {
+    unsigned int numFrames;
+};
+
+
+
+
+static void
+getAndProcessACombineConnection(int const outputServerSocket) {
+    int          otherSock;
+    int          command;
+    const char * error;
+
+    AcceptConnection(outputServerSocket, &otherSock, &error);
+
+    if (error)
+        errorExit("COMBINE SERVER: "
+                  "Failed to accept next connection.  %s", error);
+    
+    ReadInt(otherSock, &command);
+    
+    if (command == -2) {
+        /* this is notification from non-remote process that a
+           frame is done.
+            */
+        int frameStart, frameEnd;
+
+        ReadInt(otherSock, &frameStart);
+        ReadInt(otherSock, &frameEnd);
+            
+        machineDebug("COMBINE_SERVER: Frames %d - %d done",
+                     frameStart, frameEnd);
+        {
+            unsigned int i;
+            for (i = frameStart; i <= frameEnd; ++i)
+                frameDone[i] = TRUE;
+        }
+    } else
+        errorExit("COMBINE SERVER: Unrecognized command %d received.",
+                  command);
+
+    close(otherSock);
+}
+
+
+
+#define READ_ATTEMPTS 5 /* number of times (seconds) to retry an input file */
+
+
+static void
+openInputFile(const char * const fileName,
+              FILE **      const inputFilePP) {
+
+    FILE * inputFileP;
+    unsigned int attempts;
+    
+    inputFileP = NULL;
+    attempts = 0;
+
+    while (!inputFileP && attempts < READ_ATTEMPTS) {
+        inputFileP = fopen(fileName, "rb");
+        if (inputFileP == NULL) {
+            pm_message("ERROR  Couldn't read frame file '%s' errno = %d (%s)"
+                       "attempt %d", 
+                       fileName, errno, strerror(errno), attempts);
+            sleep(1);
+        }
+        ++attempts;
+    }
+    if (inputFileP == NULL)
+        pm_error("Unable to open file '%s' after %d attempts.", 
+                 fileName, attempts);
+
+    *inputFilePP = inputFileP;
+}
+
+
+
+static void
+waitForOutputFile(void *        const inputHandle,
+                  unsigned int  const frameNumber,
+                  FILE **       const ifPP) {
+/*----------------------------------------------------------------------------
+   Keep handling output events until we get the specified frame number.
+   Open the file it's in and return the stream handle.
+-----------------------------------------------------------------------------*/
+    struct combineControl * const combineControlP = (struct combineControl *)
+        inputHandle;
+
+    if (frameNumber >= combineControlP->numFrames)
+        *ifPP = NULL;
+    else {
+        const char * fileName;
+
+        while (!frameDone[frameNumber]) {
+            machineDebug("COMBINE_SERVER: Waiting for frame %u done", 
+                         frameNumber);
+
+            getAndProcessACombineConnection(outputServerSocket);
+        }
+        machineDebug("COMBINE SERVER: Wait for frame %u over", frameNumber);
+
+        asprintfN(&fileName, "%s.frame.%u", outputFileName, frameNumber);
+
+        openInputFile(fileName, ifPP);
+
+        strfree(fileName);
+    }
+}
+
+
+
+static void
+unlinkFile(void *       const inputHandle,
+           unsigned int const frameNumber) {
+
+    if (!keepTempFiles) {
+        const char * fileName;
+
+        asprintfN(&fileName, "%s.frame.%u", outputFileName, frameNumber);
+
+        unlink(fileName);
+
+        strfree(fileName);
+    }
+}
+
+
+
+void
+CombineServer(int          const numFrames, 
+              const char * const masterHostName, 
+              int          const masterPortNum,
+              const char * const outputFileName) {
+/*----------------------------------------------------------------------------
+   Execute a combine server.
+
+   This handles combination of frames.
+-----------------------------------------------------------------------------*/
+  int    combinePortNum;
+  FILE * ofP;
+  const char * error;
+  struct combineControl combineControl;
+  
+  /* once we get Combine port num, should transmit it to parallel server */
+  
+  CreateListeningSocket(&outputServerSocket, &combinePortNum, &error);
+  if (error)
+      errorExit("Unable to create socket on which to listen.  %s", error);
+
+  machineDebug("COMBINE SERVER: LISTENING ON PORT %d", combinePortNum);
+  
+  TransmitPortNum(masterHostName, masterPortNum, combinePortNum);
+  
+  MALLOCARRAY_NOFAIL(frameDone, numFrames);
+  {
+      unsigned int i;
+      for (i = 0; i < numFrames; ++i)
+          frameDone[i] = FALSE;
+  }
+  ofP = pm_openw(outputFileName);
+  
+  combineControl.numFrames = numFrames;
+
+  FramesToMPEG(ofP, &combineControl, &waitForOutputFile, &unlinkFile);
+
+  machineDebug("COMBINE SERVER: Shutting down");
+  
+  /* tell Master server we are done */
+  TransmitPortNum(masterHostName, masterPortNum, combinePortNum);
+  
+  close(outputServerSocket);
+
+  fclose(ofP);
+}
+
+
+/*=====================*
+ * MASTER SERVER STUFF *
+ *=====================*/
+
+
+static void
+startCombineServer(const char * const encoderName,
+                   unsigned int const numMachines,
+                   const char * const masterHostName,
+                   int          const masterPortNum,
+                   unsigned int const numInputFiles,
+                   const char * const paramFileName,
+                   int          const masterSocket,
+                   int *        const combinePortNumP) {
+
+    char         command[1024];
+    int          otherSock;
+    const char * error;
+
+    snprintf(command, sizeof(command), 
+             "%s %s -max_machines %d -output_server %s %d %d %s",
+             encoderName, 
+             debugMachines ? "-debug_machines" : "",
+             numMachines, masterHostName, masterPortNum, 
+             numInputFiles, paramFileName);
+
+    machineDebug("MASTER: Starting combine server with shell command '%s'",
+                 command);
+
+    safe_fork(command);
+    
+    machineDebug("MASTER: Listening for connection back from "
+                 "new Combine server");
+
+    AcceptConnection(masterSocket, &otherSock, &error);
+    if (error)
+        errorExit("MASTER SERVER: "
+                  "Failed to accept next connection.  %s", error);
+
+    ReadInt(otherSock, combinePortNumP);
+    close(otherSock);
+
+    machineDebug("MASTER:  Combine port number = %d", *combinePortNumP);
+}
+
+
+
+static void
+startDecodeServer(const char * const encoderName,
+                  unsigned int const numMachines,
+                  const char * const masterHostName,
+                  int          const masterPortNum,
+                  unsigned int const numInputFiles,
+                  const char * const paramFileName,
+                  int          const masterSocket,
+                  int *        const decodePortNumP) {
+
+    char         command[1024];
+    int          otherSock;
+    const char * error;
+
+    snprintf(command, sizeof(command), 
+             "%s %s -max_machines %d -decode_server %s %d %d %s",
+             encoder_name, 
+             debugMachines ? "-debug_machines" : "",
+             numMachines, masterHostName, masterPortNum,
+             numInputFiles, paramFileName);
+
+    machineDebug("MASTER: Starting decode server with shell command '%s'",
+                 command);
+
+    safe_fork(command);
+
+    machineDebug("MASTER: Listening for connection back from "
+                 "new Decode server");
+
+    AcceptConnection(masterSocket, &otherSock, &error);
+    if (error)
+        errorExit("MASTER SERVER: "
+                  "Failed to accept connection back from the new "
+                  "decode server.  %s", error);
+
+    ReadInt(otherSock, decodePortNumP);
+    
+    close(otherSock);
+    
+    machineDebug("MASTER:  Decode port number = %d", *decodePortNumP);
+}
+
+
+
+static void
+startIoServer(const char *   const encoderName,
+              unsigned int   const numChildren,
+              const char *   const masterHostName,
+              int            const masterPortNum,
+              int            const masterSocket,
+              const char *   const paramFileName,
+              int *          const ioPortNumP) {
+              
+    char         command[1024];
+    int          otherSock;
+    const char * error;
+    
+    sprintf(command, "%s -max_machines %d -io_server %s %d %s",
+            encoderName, numChildren, masterHostName, masterPortNum,
+            paramFileName);
+
+    machineDebug("MASTER: Starting I/O server with remote shell command '%s'",
+                 command);
+
+    safe_fork(command);
+    
+    machineDebug("MASTER: Listening for connection back from "
+                 "new I/O server");
+
+    AcceptConnection(masterSocket, &otherSock, &error);
+    if (error)
+        errorExit("MASTER SERVER: "
+                  "Failed to accept connection back from the new "
+                  "I/O server.  %s", error);
+    
+    ReadInt(otherSock, ioPortNumP);
+    close(otherSock);
+    
+    machineDebug("MASTER:  I/O port number = %d", *ioPortNumP);
+}    
+    
+    
+
+static void
+extendToEndOfPattern(unsigned int * const nFramesP,
+                     unsigned int   const startFrame,
+                     unsigned int   const framePatternLen,
+                     unsigned int   const numFramesInStream) {
+
+    assert(framePatternLen >= 1);
+        
+    while (startFrame + *nFramesP < numFramesInStream &&
+           (startFrame + *nFramesP) % framePatternLen != 0)
+        ++(*nFramesP);
+}
+
+
+
+static void
+allocateInitialFrames(struct scheduler * const schedulerP,
+                      boolean            const parallelPerfect,
+                      boolean            const forceIalign,
+                      unsigned int       const framePatternLen,
+                      unsigned int       const parallelTestFrames,
+                      unsigned int       const childNum,
+                      unsigned int *     const startFrameP,
+                      unsigned int *     const nFramesP) {
+/*----------------------------------------------------------------------------
+   Choose which frames, to hand out to the new child numbered 'childNum'.
+-----------------------------------------------------------------------------*/
+    unsigned int const framesPerChild = 
+        MAX(1, ((schedulerP->numFramesInJob - schedulerP->nextFrame) /
+                (schedulerP->numMachines - childNum)));
+
+    unsigned int nFrames;
+
+    if (parallelPerfect)
+        nFrames = framesPerChild;
+    else {
+        assert(parallelTestFrames >= 1);
+
+        nFrames = MIN(parallelTestFrames, framesPerChild);
+    }
+    if (forceIalign)
+        extendToEndOfPattern(&nFrames, schedulerP->nextFrame,
+                             framePatternLen, schedulerP->numFramesInJob);
+
+    nFrames = MIN(nFrames, schedulerP->numFramesInJob - schedulerP->nextFrame);
+
+    *startFrameP = schedulerP->nextFrame;
+    *nFramesP = nFrames;
+    schedulerP->nextFrame += nFrames;
+}
+
+
+
+static float
+taperedGoalTime(struct childState const childState[],
+                unsigned int      const remainingFrameCount) {
+        
+    float        goalTime;
+    float        allChildrenFPS;
+    float        remainingJobTime;
+        /* How long we expect it to be before the whole movie is encoded*/
+    float        sum;
+    int          numMachinesToEstimate;
+    unsigned int childNum;
+    
+    /* frames left = lastFrameInStream - startFrame + 1 */
+    for (childNum = 0, sum = 0.0, numMachinesToEstimate = 0; 
+         childNum < numMachines; ++childNum) {
+        if (!childState[childNum].finished) {
+            if (childState[childNum].fps < 0.0 )
+                ++numMachinesToEstimate;
+            else
+                sum += childState[childNum].fps;
+        }
+    }
+    
+    allChildrenFPS = (float)numMachines *
+        (sum/(float)(numMachines-numMachinesToEstimate));
+    
+    remainingJobTime = (float)remainingFrameCount/allChildrenFPS;
+    
+    goalTime = MAX(5.0, remainingJobTime/2);
+
+    return goalTime;
+}
+
+
+
+static void
+allocateMoreFrames(struct scheduler * const schedulerP,
+                   unsigned int       const childNum,
+                   struct childState  const childState[],
+                   bool               const forceIalign,
+                   unsigned int       const framePatternLen,
+                   bool               const goalTimeSpecified,
+                   unsigned int       const goalTimeArg,
+                   unsigned int *     const startFrameP,
+                   unsigned int *     const nFramesP) {
+/*----------------------------------------------------------------------------
+   Decide which frames should be child 'childNum''s next assignment,
+   given the state/history of all children is childState[].
+
+   The lowest numbered frame which needs yet to be encoded is frame
+   number 'startFrame' and 'lastFrameInStream' is the highest.
+
+   The allocation always starts at the lowest numbered frame that
+   hasn't yet been allocated and is sequential.  We return as
+   *startFrameP the frame number of the first frame in the allocation
+   and as *nFramesP the number of frames.
+
+   If 'goalTimeSpecified' is true, we try to make the assignment take
+   'goalTimeArg' seconds.  If 'goalTimeSpecified' is not true, we choose
+   a goal time ourselves, which is based on how long we think it will
+   take for all the children to finish all the remaining frames.
+-----------------------------------------------------------------------------*/
+    float goalTime;
+        /* Number of seconds we want the assignment to take.  We size the
+           assignment to try to meet this goal.
+        */
+    unsigned int nFrames;
+    float avgFps;
+
+    if (!goalTimeSpecified) {
+        goalTime = taperedGoalTime(childState,
+                                   schedulerP->numFramesInJob - 
+                                   schedulerP->nextFrame);
+    
+        pm_message("MASTER: ASSIGNING %s %.2f seconds of work",
+                   machineName[childNum], goalTime);
+    } else
+        goalTime = goalTimeArg;
+    
+    if (childState[childNum].numSeconds != 0)
+        avgFps = (float)childState[childNum].numFrames / 
+            childState[childNum].numSeconds;
+    else
+        avgFps = 0.1;       /* arbitrary small value */
+
+    nFrames = MAX(1u, (unsigned int)(goalTime * avgFps + 0.5));
+    
+    nFrames = MIN(nFrames, 
+                  schedulerP->numFramesInJob - schedulerP->nextFrame);
+
+    if (forceIalign)
+        extendToEndOfPattern(&nFrames, schedulerP->nextFrame,
+                             framePatternLen, schedulerP->numFramesInJob);
+
+    *startFrameP = schedulerP->nextFrame;
+    *nFramesP = nFrames;
+    schedulerP->nextFrame += nFrames;
+}
+
+
+
+static void
+startChildren(struct scheduler *   const schedulerP,
+              const char *         const encoderName,
+              const char *         const masterHostName,
+              int                  const masterPortNum,
+              const char *         const paramFileName,
+              boolean              const parallelPerfect,
+              boolean              const forceIalign,
+              unsigned int         const framePatternLen,
+              unsigned int         const parallelTestFrames,
+              boolean              const beNice,
+              int                  const masterSocket,
+              int                  const combinePortNum,
+              int                  const decodePortNum,
+              int *                const ioPortNum,
+              unsigned int *       const numIoServersP,
+              struct childState ** const childStateP) {
+/*----------------------------------------------------------------------------
+   Start up the children.  Tell them to work for the master at
+   'masterHostName':'masterPortNum'.
+
+   Start I/O servers (as processes on this system) as required and return
+   the port numbers of the TCP ports on which they listen as
+   ioPortNum[] and the number of them as *numIoServersP.
+
+   Give each of the children some initial work to do.  This may be just
+   a small amount for timing purposes.
+
+   We access and manipulate the various global variables that represent
+   the state of the children, and the scheduler structure.
+-----------------------------------------------------------------------------*/
+    struct childState * childState;  /* malloc'ed */
+    unsigned int childNum;
+    unsigned int numIoServers;
+    unsigned int childrenLeftCurrentIoServer;
+        /* The number of additional children we can hook up to the
+           current I/O server before reaching our maximum children per
+           I/O server.  0 if there is no current I/O server.
+        */
+
+    MALLOCARRAY_NOFAIL(childState, schedulerP->numMachines);
+
+    childrenLeftCurrentIoServer = 0;  /* No current I/O server yet */
+    
+    numIoServers = 0;  /* None created yet */
+
+    for (childNum = 0; childNum < schedulerP->numMachines; ++childNum) {
+        char command[1024];
+        unsigned int startFrame;
+        unsigned int nFrames;
+
+        childState[childNum].fps        = -1.0;  /* illegal value as flag */
+        childState[childNum].numSeconds = 0;
+
+        allocateInitialFrames(schedulerP, parallelPerfect, forceIalign,
+                              framePatternLen, parallelTestFrames,
+                              childNum, &startFrame, &nFrames);
+
+        if (nFrames == 0) {
+            childState[childNum].finished = TRUE;
+            machineDebug("MASTER: No more frames; not starting child '%s'",
+                         machineName[childNum]);
+        } else {
+            childState[childNum].finished   = FALSE;
+        
+            if (remote[childNum]) {
+                if (childrenLeftCurrentIoServer == 0) {
+                    startIoServer(encoderName, schedulerP->numMachines, 
+                                  masterHostName, masterPortNum, masterSocket,
+                                  paramFileName, &ioPortNum[numIoServers++]);
+                    
+                    childrenLeftCurrentIoServer = SOMAXCONN;
+                }
+                --childrenLeftCurrentIoServer;
+            } 
+            snprintf(command, sizeof(command),
+                     "%s %s -l %s %s "
+                     "%s %s -child %s %d %d %d %d %d %d "
+                     "-frames %d %d %s",
+                     rsh,
+                     machineName[childNum], userName[childNum],
+                     beNice ? "nice" : "",
+                     executable[childNum],
+                     debugMachines ? "-debug_machines" : "",
+                     masterHostName, masterPortNum, 
+                     remote[childNum] ? ioPortNum[numIoServers-1] : 0,
+                     combinePortNum, decodePortNum, childNum,
+                     remote[childNum] ? 1 : 0,
+                     startFrame, startFrame + nFrames - 1,
+                     remote[childNum] ? 
+                         remoteParamFile[childNum] : paramFileName
+            );
+        
+            machineDebug("MASTER: Starting child server "
+                         "with shell command '%s'", command);
+
+            safe_fork(command);
+
+            machineDebug("MASTER: Frames %d-%d assigned to new child %s",
+                         startFrame, startFrame + nFrames - 1, 
+                         machineName[childNum]);
+        }
+        childState[childNum].startFrame = startFrame;
+        childState[childNum].lastNumFrames = nFrames;
+        childState[childNum].numFrames = childState[childNum].lastNumFrames;
+    }
+    *childStateP   = childState;
+    *numIoServersP = numIoServers;
+}
+
+
+
+static void
+noteFrameDone(const char * const combineHostName,
+              int          const combinePortNum,
+              unsigned int const frameStart, 
+              unsigned int const frameEnd) {
+/*----------------------------------------------------------------------------
+   Tell the Combine server that frames 'frameStart' through 'frameEnd'
+   are done.
+-----------------------------------------------------------------------------*/
+    int const negativeTwo = -2;
+    int clientSocket;
+    time_t  tempTimeStart, tempTimeEnd;
+    const char * error;
+    struct hostent * hostEntP;
+
+    time(&tempTimeStart);
+
+    hostEntP = NULL;
+
+    ConnectToSocket(combineHostName, combinePortNum, &hostEntP,
+                    &clientSocket, &error);
+    
+    if (error)
+        errorExit("MASTER: Can't connect to Combine server to tell it frames "
+                  "are done.  %s", error);
+
+    WriteInt(clientSocket, negativeTwo);
+
+    WriteInt(clientSocket, frameStart);
+
+    WriteInt(clientSocket, frameEnd);
+
+    close(clientSocket);
+
+    time(&tempTimeEnd);
+    IOtime += (tempTimeEnd-tempTimeStart);
+}
+
+
+
+static void
+feedTheChildren(struct scheduler * const schedulerP,
+                struct childState        childState[],
+                int                const masterSocket,
+                const char *       const combineHostName,
+                int                const combinePortNum,
+                bool               const forceIalign,
+                unsigned int       const framePatternLen,
+                bool               const goalTimeSpecified,
+                unsigned int       const goalTime) {
+/*----------------------------------------------------------------------------
+   Listen for children to tell us they have finished their assignments
+   and give them new assignments, until all the frames have been assigned
+   and all the children have finished.
+
+   As children finish assignments, inform the combine server at
+   'combineHostName':'combinePortNum' of such.
+
+   Note that the children got initial assigments when they were created.
+   So the first thing we do is wait for them to finish those.
+-----------------------------------------------------------------------------*/
+    unsigned int numFinished;
+        /* Number of child machines that have been excused because there
+           is no more work for them.
+        */
+    unsigned int framesDone;
+
+    numFinished = 0;
+    framesDone = 0;
+
+    while (numFinished != schedulerP->numMachines) {
+        int                 otherSock;
+        int                 childNum;
+        int                 seconds;
+        float               framesPerSecond;
+        struct childState * csP;
+        const char *        error;
+        unsigned int nextFrame;
+        unsigned int nFrames;
+
+        machineDebug("MASTER: Listening for a connection...");
+
+        AcceptConnection(masterSocket, &otherSock, &error);
+        if (error)
+            errorExit("MASTER SERVER: "
+                      "Failed to accept next connection.  %s", error);
+
+        ReadInt(otherSock, &childNum);
+        ReadInt(otherSock, &seconds);
+
+        csP = &childState[childNum];
+        
+        csP->numSeconds += seconds;
+        csP->fps = (float)csP->numFrames / (float)csP->numSeconds;
+
+        if (seconds != 0)
+            framesPerSecond = (float)csP->lastNumFrames / (float)seconds;
+        else
+            framesPerSecond = (float)csP->lastNumFrames * 2.0;
+
+        machineDebug("MASTER: Child %s FINISHED ASSIGNMENT.  "
+                     "%f frames per second", 
+                     machineName[childNum], framesPerSecond);
+
+        noteFrameDone(combineHostName, combinePortNum, csP->startFrame,
+                      csP->startFrame + csP->lastNumFrames - 1);
+
+        framesDone += csP->lastNumFrames;
+
+        allocateMoreFrames(schedulerP, childNum, childState,
+                           forceIalign, framePatternLen,
+                           goalTimeSpecified, goalTime,
+                           &nextFrame, &nFrames);
+
+        if (nFrames == 0) {
+            WriteInt(otherSock, -1);
+            WriteInt(otherSock, 0);
+
+            ++numFinished;
+
+            machineDebug("MASTER: NO MORE WORK FOR CHILD %s.  "
+                         "(%d of %d children now done)",
+                         machineName[childNum], numFinished, numMachines);
+        } else {
+            WriteInt(otherSock, nextFrame);
+            WriteInt(otherSock, nextFrame + nFrames - 1);
+
+            machineDebug("MASTER: Frames %d-%d assigned to child %s",
+                         nextFrame, nextFrame + nFrames - 1,
+                         machineName[childNum]);
+
+            csP->startFrame    = nextFrame;
+            csP->lastNumFrames = nFrames;
+            csP->numFrames    += csP->lastNumFrames;
+        }
+        close(otherSock);
+
+        machineDebug("MASTER: %d/%d DONE; %d ARE ASSIGNED",
+                     framesDone, schedulerP->numFramesInJob, 
+                     schedulerP->nextFrame - framesDone);
+    }
+}
+
+
+
+static void
+stopIoServers(const char * const hostName,
+              int          const ioPortNum[],
+              unsigned int const numIoServers) {
+
+    unsigned int childNum;
+
+    IOhostName = hostName;
+    for (childNum = 0; childNum < numIoServers; ++childNum) {
+        ioPortNumber = ioPortNum[childNum];
+        EndIOServer();
+    }
+}
+
+
+
+static void
+waitForCombineServerToTerminate(int const masterSocket) {
+
+    int otherSock;
+    const char * error;
+
+    machineDebug("MASTER SERVER: Waiting for combine server to terminate");
+
+    AcceptConnection(masterSocket, &otherSock, &error);
+    if (error)
+        errorExit("MASTER SERVER: "
+                  "Failed to accept connection expected from a "
+                  "terminating combine server.  %s", error);
+
+    {
+        int dummy;
+        ReadInt(otherSock, &dummy);
+    }
+    close(otherSock);
+}
+    
+
+
+static void
+printFinalStats(FILE *            const statfileP,
+                time_t            const startUpBegin,
+                time_t            const startUpEnd,
+                time_t            const shutDownBegin,
+                time_t            const shutDownEnd,
+                unsigned int      const numChildren,
+                struct childState const childState[],
+                unsigned int      const numFrames) {
+
+    unsigned int pass;
+    FILE * fileP;
+
+    for (pass = 0; pass < 2; ++pass) {
+        if (pass == 0)
+            fileP = stdout;
+        else
+            fileP = statfileP;
+
+        if (fileP) {
+            unsigned int childNum;
+            float totalFPS;
+
+            fprintf(fileP, "\n\n");
+            fprintf(fileP, "PARALLEL SUMMARY\n");
+            fprintf(fileP, "----------------\n");
+            fprintf(fileP, "\n");
+            fprintf(fileP, "START UP TIME:  %u seconds\n",
+                    (unsigned int)(startUpEnd - startUpBegin));
+            fprintf(fileP, "SHUT DOWN TIME:  %u seconds\n",
+                    (unsigned int)(shutDownEnd - shutDownBegin));
+            
+            fprintf(fileP, 
+                    "%14.14s %8.8s %8.8s %12.12s %9.9s\n",
+                    "MACHINE", "Frames", "Seconds", "Frames/Sec",
+                    "Self Time");
+
+            fprintf(fileP, 
+                    "%14.14s %8.8s %8.8s %12.12s %9.9s\n",
+                    "--------------", "--------", "--------", "------------",
+                    "---------");
+
+            totalFPS = 0.0;
+            for (childNum = 0; childNum < numChildren; ++childNum) {
+                float const localFPS = 
+                    (float)childState[childNum].numFrames /
+                    childState[childNum].numSeconds;
+                fprintf(fileP, "%14.14s %8u %8u %12.4f %8u\n",
+                        machineName[childNum], 
+                        childState[childNum].numFrames, 
+                        childState[childNum].numSeconds,
+                        localFPS, 
+                        (unsigned int)((float)numFrames/localFPS));
+                totalFPS += localFPS;
+            }
+
+            fprintf(fileP, 
+                    "%14.14s %8.8s %8.8s %12.12s %9.9s\n",
+                    "--------------", "--------", "--------", "------------",
+                    "---------");
+
+            fprintf(fileP, "%14s %8.8s %8u %12.4f\n", 
+                    "OPTIMAL", "", 
+                    (unsigned int)((float)numFrames/totalFPS),
+                    totalFPS);
+            
+            {
+                unsigned int const diffTime = shutDownEnd - startUpBegin;
+                
+                fprintf(fileP, "%14s %8.8s %8u %12.4f\n", 
+                        "ACTUAL", "", diffTime, 
+                        (float)numFrames / diffTime);
+            }
+            fprintf(fileP, "\n\n");
+        }
+    }
+}
+
+
+
+void
+MasterServer(struct inputSource * const inputSourceP,
+             const char *         const paramFileName, 
+             const char *         const outputFileName) {
+/*----------------------------------------------------------------------------
+   Execute the master server function.
+
+   Start all the other servers.
+-----------------------------------------------------------------------------*/
+    const char *hostName;
+    int       portNum;
+    int       masterSocket;
+        /* The file descriptor for the socket on which the master listens */
+    int ioPortNum[MAX_IO_SERVERS];
+    int       combinePortNum, decodePortNum;
+    struct childState * childState;  /* malloc'ed */
+    unsigned int numIoServers;
+    time_t  startUpBegin, startUpEnd;
+    time_t  shutDownBegin, shutDownEnd;
+    const char * error;
+    struct scheduler scheduler;
+
+    time(&startUpBegin);
+
+    scheduler.nextFrame = 0;
+    scheduler.numFramesInJob = inputSourceP->numInputFiles;
+    scheduler.numMachines = numMachines;
+
+    PrintStartStats(startUpBegin, FALSE, 0, 0, inputSourceP);
+
+    hostName = GetHostName();
+
+    hostEntry = gethostbyname(hostName);
+    if (hostEntry == NULL)
+        errorExit("Could not find host name '%s' in database", hostName);
+
+    CreateListeningSocket(&masterSocket, &portNum, &error);
+    if (error)
+        errorExit("Unable to create socket on which to listen.  %s", error);
+
+    if (debugSockets)
+        fprintf(stdout, "---MASTER USING PORT %d\n", portNum);
+
+    startCombineServer(encoder_name, numMachines, hostName, portNum,
+                       inputSourceP->numInputFiles, 
+                       paramFileName, masterSocket, 
+                       &combinePortNum);
+
+    if (referenceFrame == DECODED_FRAME)
+        startDecodeServer(encoder_name, numMachines, hostName, portNum,
+                          inputSourceP->numInputFiles, 
+                          paramFileName, masterSocket,
+                          &decodePortNum);
+
+    startChildren(&scheduler, encoder_name, hostName, portNum,
+                  paramFileName, parallelPerfect, forceIalign,
+                  framePatternLen, parallelTestFrames, 
+                  niceProcesses,
+                  masterSocket, combinePortNum, decodePortNum, 
+                  ioPortNum, &numIoServers,
+                  &childState);
+
+    time(&startUpEnd);
+
+    feedTheChildren(&scheduler, childState,
+                    masterSocket, hostName, combinePortNum,
+                    forceIalign, framePatternLen,
+                    parallelTimeChunks != -1, parallelTimeChunks);
+
+    assert(scheduler.nextFrame == scheduler.numFramesInJob);
+
+    time(&shutDownBegin);
+
+    stopIoServers(hostName, ioPortNum, numIoServers);
+
+    waitForCombineServerToTerminate(masterSocket);
+
+    close(masterSocket);
+
+    time(&shutDownEnd);
+
+    printFinalStats(statFile, startUpBegin, startUpEnd,
+                    shutDownBegin, shutDownEnd, numMachines,
+                    childState, inputSourceP->numInputFiles);
+
+    if (statFile)
+        fclose(statFile);
+
+    free(childState);
+    strfree(hostName);
+}
+
+
+
+void
+NotifyMasterDone(const char * const masterHostName, 
+                 int          const masterPortNum, 
+                 int          const childNum,
+                 unsigned int const seconds, 
+                 boolean *    const moreWorkToDoP,
+                 int *        const nextFrameStartP,
+                 int *        const nextFrameEndP) {
+/*----------------------------------------------------------------------------
+   Tell the master, at 'masterHostName':'masterPortNum' that child
+   number 'childNum' has finished its assignment, and the decoding
+   took 'seconds' wall clock seconds.  Get the next assignment, if
+   any, from the master.
+
+   If the master gives us a new assignment, return *moreWorkToDoP ==
+   TRUE and the frames the master wants us to do as *nextFrameStartP
+   and nextFrameEndP.  Otherwise (there is no more work for machine
+   'childNum' to do), return *moreWorkToDoP == FALSE.
+-----------------------------------------------------------------------------*/
+    int    clientSocket;
+    time_t tempTimeStart, tempTimeEnd;
+    const char * error;
+
+    machineDebug("CHILD: NOTIFYING MASTER Machine %d assignment complete", 
+                 childNum);
+
+    time(&tempTimeStart);
+    
+    ConnectToSocket(masterHostName, masterPortNum, &hostEntry,
+                    &clientSocket, &error);
+    if (error)
+        errorExit("CHILD: Can't connect to master to tell him we've finished "
+                  "our assignment.  %s", error);
+
+    WriteInt(clientSocket, childNum);
+    WriteInt(clientSocket, seconds);
+
+    ReadInt(clientSocket, nextFrameStartP);
+    ReadInt(clientSocket, nextFrameEndP);
+
+    *moreWorkToDoP = (*nextFrameStartP >= 0);
+
+    if (*moreWorkToDoP)
+        machineDebug("CHILD: Master says next assignment: start %d end %d",
+                     *nextFrameStartP, *nextFrameEndP);
+    else
+        machineDebug("CHILD: Master says no more work for us.");
+
+    close(clientSocket);
+
+    time(&tempTimeEnd);
+    IOtime += (tempTimeEnd-tempTimeStart);
+}
+
+
+
+void
+DecodeServer(int          const numInputFiles, 
+             const char * const decodeFileName, 
+             const char * const masterHostName, 
+             int          const masterPortNum) {
+/*----------------------------------------------------------------------------
+   Execute the decode server.
+
+   The decode server handles transfer of decoded frames to/from processes.
+
+   It is necessary only if referenceFrame == DECODED_FRAME.
+
+   Communicate to the master at hostname 'masterHostName':'masterPortNum'.
+
+-----------------------------------------------------------------------------*/
+    int     otherSock;
+    int     decodePortNum;
+    int     frameReady;
+    boolean *ready;
+    int     *waitMachine;
+    int     *waitPort;
+    int     *waitList;
+    int     slaveNumber;
+    int     slavePort;
+    int     waitPtr;
+    struct hostent *nullHost = NULL;
+    int     clientSocket;
+    const char * error;
+
+    /* should keep list of port numbers to notify when frames become ready */
+
+    ready = (boolean *) calloc(numInputFiles, sizeof(boolean));
+    waitMachine = (int *) calloc(numInputFiles, sizeof(int));
+    waitPort = (int *) malloc(numMachines*sizeof(int));
+    waitList = (int *) calloc(numMachines, sizeof(int));
+
+    CreateListeningSocket(&decodeServerSocket, &decodePortNum, &error);
+    if (error)
+        errorExit("Unable to create socket on which to listen.  %s", error);
+
+    machineDebug("DECODE SERVER LISTENING ON PORT %d", decodePortNum);
+
+    TransmitPortNum(masterHostName, masterPortNum, decodePortNum);
+
+    frameDone = (boolean *) malloc(numInputFiles*sizeof(boolean));
+    memset((char *)frameDone, 0, numInputFiles*sizeof(boolean));
+
+    /* wait for ready signals and requests */
+    while ( TRUE ) {
+        const char * error;
+
+        AcceptConnection(decodeServerSocket, &otherSock, &error);
+        if (error)
+            errorExit("DECODE SERVER: "
+                      "Failed to accept next connection.  %s", error);
+
+        ReadInt(otherSock, &frameReady);
+
+        if ( frameReady == -2 ) {
+            ReadInt(otherSock, &frameReady);
+
+            machineDebug("DECODE SERVER:  REQUEST FOR FRAME %d", frameReady);
+
+            /* now respond if it's ready yet */
+            WriteInt(otherSock, frameDone[frameReady]);
+
+            if ( ! frameDone[frameReady] ) {
+                /* read machine number, port number */
+                ReadInt(otherSock, &slaveNumber);
+                ReadInt(otherSock, &slavePort);
+
+                machineDebug("DECODE SERVER: WAITING:  SLAVE %d, PORT %d",
+                             slaveNumber, slavePort);
+
+                waitPort[slaveNumber] = slavePort;
+                if ( waitMachine[frameReady] == 0 ) {
+                    waitMachine[frameReady] = slaveNumber+1;
+                } else {
+                    /* someone already waiting for this frame */
+                    /* follow list of waiters to the end */
+                    waitPtr = waitMachine[frameReady]-1;
+                    while ( waitList[waitPtr] != 0 ) {
+                        waitPtr = waitList[waitPtr]-1;
+                    }
+
+                    waitList[waitPtr] = slaveNumber+1;
+                    waitList[slaveNumber] = 0;
+                }
+            }
+        } else {
+            frameDone[frameReady] = TRUE;
+            
+            machineDebug("DECODE SERVER:  FRAME %d READY", frameReady);
+
+            if ( waitMachine[frameReady] ) {
+                /* need to notify one or more machines it's ready */
+                waitPtr = waitMachine[frameReady]-1;
+                while ( waitPtr >= 0 ) {
+                    const char * error;
+                    ConnectToSocket(machineName[waitPtr], waitPort[waitPtr],
+                                    &nullHost,
+                                    &clientSocket, &error);
+                    if (error)
+                        errorExit("DECODE SERVER: "
+                                  "Can't connect to child machine.  %s", 
+                                  error);
+                    close(clientSocket);
+                    waitPtr = waitList[waitPtr]-1;
+                }
+            }
+        }
+
+        close(otherSock);
+    }
+    
+    machineDebug("DECODE SERVER:  Shutting down");
+
+    /* tell Master server we are done */
+    TransmitPortNum(masterHostName, masterPortNum, decodePortNum);
+
+    close(decodeServerSocket);
+}
+
+
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
diff --git a/converter/ppm/ppmtompeg/param.c b/converter/ppm/ppmtompeg/param.c
new file mode 100644
index 00000000..5ea69ab6
--- /dev/null
+++ b/converter/ppm/ppmtompeg/param.c
@@ -0,0 +1,1077 @@
+/*===========================================================================*
+ * param.c              
+ *                      
+ *  Procedures to read in parameter file  
+ *                                    
+ *===========================================================================*/
+
+/* COPYRIGHT INFORMATION IS AT THE END OF THIS FILE */
+
+#define _XOPEN_SOURCE 500
+    /* This makes sure popen() is in stdio.h.  In GNU libc 2.1.3, 
+     _POSIX_C_SOURCE = 2 is sufficient, but on AIX 4.3, the higher level
+     _XOPEN_SOURCE is required.  2000.09.09 
+
+     This also makes sure strdup() is in string.h.
+    */
+#define _BSD_SOURCE 1
+    /* Make sure string.h defines strncasecmp */
+
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "nstring.h"
+#include "mallocvar.h"
+#include "all.h"
+#include "mtypes.h"
+#include "mpeg.h"
+#include "motion_search.h"
+#include "prototypes.h"
+#include "parallel.h"
+#include "readframe.h"
+#include "fsize.h"
+#include "frames.h"
+#include "jpeg.h"
+#include "input.h"
+#include "frametype.h"
+#include "param.h"
+
+#include "rate.h"
+#include "opts.h"
+
+/*===========*
+ * CONSTANTS *
+ *===========*/
+
+#define INPUT_ENTRY_BLOCK_SIZE   128
+
+#define FIRST_OPTION           0
+#define OPTION_GOP             0
+#define OPTION_PATTERN         1
+#define OPTION_PIXEL           2
+#define OPTION_PQSCALE         3
+#define OPTION_OUTPUT          4
+#define OPTION_RANGE           5
+#define OPTION_PSEARCH_ALG     6
+#define OPTION_IQSCALE         7
+#define OPTION_INPUT_DIR       8
+#define OPTION_INPUT_CONVERT   9
+#define OPTION_INPUT          10
+#define OPTION_BQSCALE        11
+#define OPTION_BASE_FORMAT    12
+#define OPTION_SPF            13
+#define OPTION_BSEARCH_ALG    14
+#define OPTION_REF_FRAME      15
+#define LAST_OPTION           15
+
+/* put any non-required options after LAST_OPTION */
+#define OPTION_RESIZE	      16
+#define OPTION_IO_CONVERT     17
+#define OPTION_SLAVE_CONVERT  18
+#define OPTION_IQTABLE	      19
+#define OPTION_NIQTABLE	      20
+#define OPTION_FRAME_RATE     21
+#define OPTION_ASPECT_RATIO   22
+#define OPTION_YUV_SIZE	      23
+#define OPTION_SPECIFICS      24
+#define OPTION_DEFS_SPECIFICS 25
+#define OPTION_BUFFER_SIZE    26
+#define OPTION_BIT_RATE       27
+#define OPTION_USER_DATA      28
+#define OPTION_YUV_FORMAT     29
+#define OPTION_GAMMA          30
+#define OPTION_PARALLEL       31
+#define OPTION_FRAME_INPUT    32
+#define OPTION_GOP_INPUT      33
+
+#define NUM_OPTIONS           33
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+
+extern char currentPath[MAXPATHLEN];
+char	outputFileName[256];
+int	outputWidth, outputHeight;
+char inputConversion[1024];
+char ioConversion[1024];
+char slaveConversion[1024];
+char yuvConversion[256];
+char specificsFile[256],specificsDefines[1024]="";
+boolean GammaCorrection=FALSE;
+float   GammaValue;
+char userDataFileName[256]={0};
+boolean specificsOn = FALSE;
+char currentGOPPath[MAXPATHLEN];
+char currentFramePath[MAXPATHLEN];
+boolean keepTempFiles;
+
+static const char * const optionText[LAST_OPTION+1] = { 
+    "GOP_SIZE", "PATTERN", "PIXEL", "PQSCALE",
+    "OUTPUT", "RANGE", "PSEARCH_ALG", "IQSCALE", "INPUT_DIR",
+    "INPUT_CONVERT", "INPUT", "BQSCALE", "BASE_FILE_FORMAT",
+    "SLICES_PER_FRAME", "BSEARCH_ALG", "REFERENCE_FRAME"};
+static boolean optionSeen[NUM_OPTIONS+1];
+    /* optionSeen[x] means we have seen option x in the parameter file we've
+       been reading.
+    */
+
+int numMachines;
+char	machineName[MAX_MACHINES][256];
+char	userName[MAX_MACHINES][256];
+char	executable[MAX_MACHINES][1024];
+char	remoteParamFile[MAX_MACHINES][1024];
+boolean	remote[MAX_MACHINES];
+int mult_seq_headers = 0;  /* 0 for none, N for header/N GOPs */
+
+
+/*===========================================================================*
+ *
+ * SkipSpacesTabs
+ *
+ *	skip all spaces and tabs
+ *
+ * RETURNS:	point to next character not a space or tab
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static const char *
+SkipSpacesTabs(const char * const start) {
+
+    const char * p;
+
+    for (p = start; *p == ' ' || *p == '\t'; ++p);
+
+    return p;
+}
+
+
+
+/*===========================================================================*
+ *
+ * GetAspectRatio
+ *
+ * take a character string with the pixel aspect ratio
+ * and returns the correct aspect ratio code for use in the Sequence header
+ *
+ * RETURNS: aspect ratio code as per MPEG-I spec
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static int
+GetAspectRatio(const char * const p)
+{
+  float   ratio;
+  int	  ttRatio;
+  int     retval;
+
+  sscanf(p, "%f", &ratio);
+  ttRatio = (int)(0.5+ratio*10000.0);
+
+  if ( ttRatio == 10000 )	      retval = 1;
+  else if ( ttRatio ==  6735 )    retval = 2;
+  else if ( ttRatio ==  7031 )    retval = 3;
+  else if ( ttRatio ==  7615 )    retval = 4;
+  else if ( ttRatio ==  8055 )    retval = 5;
+  else if ( ttRatio ==  8437 )    retval = 6;
+  else if ( ttRatio ==  8935 )    retval = 7;
+  else if ( ttRatio ==  9157 )    retval = 8;
+  else if ( ttRatio ==  9815 )    retval = 9;
+  else if ( ttRatio == 10255 )    retval = 10;
+  else if ( ttRatio == 10695 )    retval = 11;
+  else if ( ttRatio == 10950 )    retval = 12;
+  else if ( ttRatio == 11575 )    retval = 13;
+  else if ( ttRatio == 12015 )    retval = 14;
+  else {
+    fprintf(stderr,"INVALID ASPECT RATIO: %s frames/sec\n", p);
+    exit(1);
+  }
+  return retval;
+}
+
+
+
+/*===========================================================================*
+ *
+ * ReadMachineNames
+ *
+ *	read a list of machine names for parallel execution
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    machine info updated
+ *
+ *===========================================================================*/
+static void
+ReadMachineNames(FILE * const fpointer)
+{
+  char    input[256];
+  const char *charPtr;
+
+  while ( (fgets(input, 256, fpointer) != NULL) &&
+	 (strncmp(input, "END_PARALLEL", 12) != 0) ) {
+    if ( input[0] == '#' || input[0] == '\n') {
+      continue;
+    }
+
+    if ( strncmp(input, "REMOTE", 6) == 0 ) {
+      charPtr = SkipSpacesTabs(&input[6]);
+      remote[numMachines] = TRUE;
+
+      sscanf(charPtr, "%s %s %s %s", machineName[numMachines],
+	     userName[numMachines], executable[numMachines],
+	     remoteParamFile[numMachines]);
+    } else {
+      remote[numMachines] = FALSE;
+
+      sscanf(input, "%s %s %s", machineName[numMachines],
+	     userName[numMachines], executable[numMachines]);
+    }
+
+    numMachines++;
+  }
+}
+
+
+/*===========================================================================*
+ *
+ * GetFrameRate
+ *
+ * take a character string with the input frame rate 
+ * and return the correct frame rate code for use in the Sequence header
+ *
+ * RETURNS: frame rate code as per MPEG-I spec
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static int
+GetFrameRate(const char * const p)
+{
+  float   rate;
+  int	  thouRate;
+  int     retval;
+
+  sscanf(p, "%f", &rate);
+  thouRate = (int)(0.5+1000.0*rate);
+
+  if ( thouRate == 23976 )	       retval = 1;
+  else if ( thouRate == 24000 )    retval = 2;
+  else if ( thouRate == 25000 )    retval = 3;
+  else if ( thouRate == 29970 )    retval = 4;
+  else if ( thouRate == 30000 )    retval = 5;
+  else if ( thouRate == 50000 )    retval = 6;
+  else if ( thouRate == 59940 )    retval = 7;
+  else if ( thouRate == 60000 )    retval = 8;
+  else {
+    fprintf(stderr,"INVALID FRAME RATE: %s frames/sec\n", p);
+    exit(1);
+  }
+  return retval;
+}
+
+
+
+static void
+mergeInputSource(struct inputSource * const baseSourceP,
+                 struct inputSource * const addedSourceP) {
+
+    unsigned int i;
+
+    baseSourceP->ifArraySize += addedSourceP->numInputFileEntries;
+    REALLOCARRAY_NOFAIL(baseSourceP->inputFileEntries, 
+                        baseSourceP->ifArraySize);
+    for (i = 0; i < addedSourceP->numInputFileEntries; ++i)
+        baseSourceP->inputFileEntries[baseSourceP->numInputFileEntries++] =
+            addedSourceP->inputFileEntries[i];
+
+    free(addedSourceP);
+    /* Note the space allocated for the *addedSourceP input file
+       entries themselves is still allocated, and used by 
+       *baseSourceP.
+    */
+}
+
+
+
+/* Forward declaration for recursively called function */
+static void
+ReadInputFileNames(FILE *               const fpointer, 
+                   const char *         const endInput,
+                   struct inputSource * const inputSourceP);
+
+static void
+expandBackTickLine(const char *         const input,
+                   struct inputSource * const inputSourceP) {
+
+    FILE *fp;
+    char cmd[300];
+    const char * start;
+    const char * end;
+    char cdcmd[110];
+
+    start = &input[1];
+    end = &input[strlen(input)-1];
+
+    while (*end != '`') {
+        end--;
+    }
+
+    end--;
+
+    if (optionSeen[OPTION_INPUT_DIR])
+        sprintf(cdcmd,"cd %s;",currentPath);
+    else
+        strcpy(cdcmd,"");
+
+    {
+        char tmp[300];
+        strncpy(tmp,start,end-start+1);
+        sprintf(cmd,"(%s %s)", cdcmd, tmp);
+    }
+
+    fp = popen(cmd, "r");
+    if (fp == NULL) {
+        pm_error("Unable to resolve backtick entry in input file list.  "
+                 "Could not open piped command: '%s'", cmd);
+    } else {
+        struct inputSource subInputSource;
+        ReadInputFileNames(fp, "HOPE-THIS_ISNT_A_FILENAME.xyz5555",
+                           &subInputSource);
+
+        mergeInputSource(inputSourceP, &subInputSource);
+    }
+}
+
+
+
+static void
+ReadInputFileNames(FILE *               const fpointer, 
+                   const char *         const endInput,
+                   struct inputSource * const inputSourceP) {
+/*----------------------------------------------------------------------------
+   Read a list of input file names from the parameter file.  Add 
+   the information to *inputSourceP.
+
+   If inputSourceP == NULL, read off the list, but ignore it.
+-----------------------------------------------------------------------------*/
+    char input[256];
+    bool endStatementRead;
+
+    /* read param file up through endInput statement.  Each line until
+       endInput is a file specification.
+    */
+    endStatementRead = FALSE;
+
+    while (!endStatementRead) {
+        char * rc;
+        rc = fgets(input, sizeof(input), fpointer);
+
+        if (feof(fpointer))
+            pm_error("End of file before section end statement '%s'",
+                     endInput);
+        else if (rc == NULL)
+            pm_error("Error reading file names from parameter file.");
+        else {
+            if (strncmp(input, endInput, strlen(endInput)) == 0)
+                endStatementRead = TRUE;
+            else if ((input[0] == '#') || (input[0] == '\n')) { 
+                /* It's a comment or blank line.  Ignore it */
+            } else if (input[0] == '`' ) {
+                expandBackTickLine(input, inputSourceP);
+            } else {
+                /* get rid of trailing whitespace including newline */
+                while (ISSPACE(input[strlen(input)-1]))
+                    input[strlen(input)-1] = '\0';
+                if (inputSourceP)
+                    AddInputFiles(inputSourceP, input);
+            }
+        }
+    }
+}
+
+
+
+static void
+initOptionSeen(void) {
+
+    unsigned int index;
+    
+    for (index = FIRST_OPTION; index < NUM_OPTIONS; ++index)
+        optionSeen[index] = FALSE;
+}
+
+
+
+static void
+verifyNoMissingEncodeFramesOption(void) {
+    if (!optionSeen[OPTION_GOP])
+        pm_error("GOP_SIZE option missing");
+    if (!optionSeen[OPTION_PATTERN])
+        pm_error("PATTERN option missing");
+    if (!optionSeen[OPTION_PIXEL])
+        pm_error("PIXEL option missing");
+    if (!optionSeen[OPTION_PQSCALE])
+        pm_error("PQSCALE option missing");
+    if (!optionSeen[OPTION_OUTPUT])
+        pm_error("OUTPUT option missing");
+    if (!optionSeen[OPTION_RANGE])
+        pm_error("RANGE option missing");
+    if (!optionSeen[OPTION_PSEARCH_ALG])
+        pm_error("PSEARCH_ALG option missing");
+    if (!optionSeen[OPTION_IQSCALE])
+        pm_error("IQSCALE option missing");
+    if (!optionSeen[OPTION_INPUT_DIR])
+        pm_error("INPUT_DIR option missing");
+    if (!optionSeen[OPTION_INPUT_CONVERT])
+        pm_error("INPUT_CONVERT option missing");
+    if (!optionSeen[OPTION_BQSCALE])
+        pm_error("BQSCALE option missing");
+    if (!optionSeen[OPTION_BASE_FORMAT])
+        pm_error("BASE_FILE_FORMAT option missing");
+    if (!optionSeen[OPTION_SPF])
+        pm_error("SLICES_PER_FRAME option missing");
+    if (!optionSeen[OPTION_BSEARCH_ALG])
+        pm_error("BSEARCH_ALG option missing");
+    if (!optionSeen[OPTION_REF_FRAME])
+        pm_error("REFERENCE_FRAME option missing");
+}
+
+
+
+static void
+verifyNoMissingCombineGopsOption(void) {
+
+    if (!optionSeen[OPTION_GOP_INPUT])
+        pm_error("GOP_INPUT option missing");
+    if (!optionSeen[OPTION_YUV_SIZE])
+        pm_error("YUV_SIZE option missing");
+    if (!optionSeen[OPTION_OUTPUT])
+        pm_error("OUTPUT option missing");
+}
+
+
+
+static void
+verifyNoMissingCombineFramesOption(void) {
+
+    if (!optionSeen[OPTION_GOP])
+        pm_error("GOP_SIZE option missing");
+    if (!optionSeen[OPTION_YUV_SIZE])
+        pm_error("YUV_SIZE option missing");
+    if (!optionSeen[OPTION_OUTPUT])
+        pm_error("OUTPUT option missing");
+}
+
+
+
+static void
+verifyNoMissingOption(int  const function) {
+/*----------------------------------------------------------------------------
+  Verify that the parameter file contains every option it is supposed to. 
+  Abort program if not.
+-----------------------------------------------------------------------------*/
+    switch(function) {
+    case ENCODE_FRAMES:
+        verifyNoMissingEncodeFramesOption();
+        break;
+    case COMBINE_GOPS:
+        verifyNoMissingCombineGopsOption();
+        break;
+    case COMBINE_FRAMES:
+        verifyNoMissingCombineFramesOption();
+        break;
+    default:
+        pm_error("Internal error - impossible value for 'function': %d",
+                 function);
+    }
+}
+
+
+
+static void
+processIqtable(FILE * const fpointer) {
+
+    unsigned int row;
+    unsigned int col;
+    char input[256];
+
+    for (row = 0; row < 8; ++row) {
+        const char * charPtr;
+
+        fgets(input, 256, fpointer);
+        charPtr = input;
+        if (8 != sscanf(charPtr,"%d %d %d %d %d %d %d %d",
+                        &qtable[row*8+0],  &qtable[row*8+1],
+                        &qtable[row*8+2],  &qtable[row*8+3],
+                        &qtable[row*8+4],  &qtable[row*8+5],
+                        &qtable[row*8+6],  &qtable[row*8+7])) {
+            pm_error("Line %d of IQTABLE doesn't have 8 elements!", 
+                     row);
+        }
+        for (col = 0; col < 8; ++col) {
+            if ((qtable[row*8+col]<1) || (qtable[row*8+col]>255)) {
+                pm_message(
+                    "Warning:  IQTable Element %1d,%1d (%d) "
+                    "corrected to 1-255.",
+                    row+1, col+1, qtable[row*8+col]);
+                qtable[row*8+col] = (qtable[row*8+col]<1)?1:255;
+            }
+        }
+    }
+            
+    if (qtable[0] != 8) {
+        pm_message("Warning:  IQTable Element 1,1 reset to 8, "
+                   "since it must be 8.");
+        qtable[0] = 8;
+    }
+    customQtable = qtable;
+}
+
+
+
+static void
+setInputSource(int                   const function,
+               struct inputSource ** const inputSourcePP,
+               struct inputSource *  const inputSourceP,
+               struct inputSource *  const gopInputSourceP,
+               struct inputSource *  const frameInputSourceP) {
+/*----------------------------------------------------------------------------
+   Given three the three input sources described by the parameter
+   file, 'inputSourceP', 'gopInputSourceP', and 'frameInputSourceP',
+   return as *inputSourcePP the appropriate one of them for the
+   function 'function', and destroy the other two.
+-----------------------------------------------------------------------------*/
+    switch (function) {
+    case ENCODE_FRAMES:
+        *inputSourcePP = inputSourceP;
+        DestroyInputSource(gopInputSourceP);
+        DestroyInputSource(frameInputSourceP);
+        break;
+    case COMBINE_GOPS:
+        *inputSourcePP = gopInputSourceP;
+        DestroyInputSource(inputSourceP);
+        DestroyInputSource(frameInputSourceP);
+        break;
+    case COMBINE_FRAMES:
+        *inputSourcePP = frameInputSourceP;
+        DestroyInputSource(inputSourceP);
+        DestroyInputSource(gopInputSourceP);
+        break;
+    default:
+      pm_error("INTERNAL ERROR: invalid 'function' %d", function);
+    }
+}
+
+
+
+/*=====================*
+ * EXPORTED PROCEDURES *
+ *=====================*/
+
+
+
+static void
+removeTrailingWhite(const char *  const rawLine,
+                    const char ** const editedLineP) {
+
+    char * buffer;
+    char * p;
+
+    buffer = strdup(rawLine);
+
+    if (!buffer)
+        pm_error("Unable to get memory to process parameter file");
+
+    p = buffer + strlen(buffer) - 1;  /* Point to last character */
+    
+    /* Position p to just before the trailing white space (might be one
+       character before beginning of string!)
+    */
+    while (p >= buffer && isspace(*p))
+        --p;
+    
+    ++p;  /* Move to first trailing whitespace character */
+    
+    *p = '\0';  /* Chop off all the trailing whitespace */
+
+    *editedLineP = buffer;
+}
+
+
+
+static void
+readNiqTable(FILE * const fpointer) {
+
+    unsigned int row;
+    for (row = 0; row < 8; ++row) {
+        char input[256];
+        unsigned int col;
+        fgets(input, sizeof(input), fpointer);
+        if (8 != sscanf(input, "%d %d %d %d %d %d %d %d",
+                        &niqtable[row*8+0],  &niqtable[row*8+1],
+                        &niqtable[row*8+2],  &niqtable[row*8+3],
+                        &niqtable[row*8+4],  &niqtable[row*8+5],
+                        &niqtable[row*8+6],  &niqtable[row*8+7])) {
+            pm_error("Line %d of NIQTABLE doesn't have 8 elements!", 
+                     row);
+        }
+        for ( col = 0; col < 8; col++ ) {
+            if ((niqtable[row*8+col]<1) || (niqtable[row*8+col]>255)) {
+                pm_message(
+                    "Warning:  NIQTable Element %1d,%1d (%d) "
+                    "corrected to 1-255.",
+                    row + 1, col + 1, niqtable[row * 8 + col]);
+                niqtable[row * 8 + col] = (niqtable[row*8+col] < 1) ? 1 : 255;
+            }
+        }
+    }
+
+    customNIQtable = niqtable;
+}
+
+
+
+static void
+processRanges(const char * const arg) {
+
+    int numRanges;
+    int a, b;
+
+    numRanges = sscanf(arg, "%d %d", &a, &b);
+
+    if (numRanges == 2)
+        SetSearchRange(a, b);
+    else if (sscanf(arg, "%d [%d]", &a, &b) == 2)
+        SetSearchRange(a, b);
+    else
+        SetSearchRange(a, a);
+}
+
+
+
+static void
+processParamLine(char const input[],
+                 FILE * const fpointer,
+                 bool * const yuvUsedP,
+                 struct inputSource * const inputSourceP,
+                 struct inputSource * const frameInputSourceP,
+                 struct inputSource * const gopInputSourceP,
+                 struct params * const paramP) {
+
+    switch(input[0]) {
+    case 'A':
+        if (STRNEQ(input, "ASPECT_RATIO", 12)) {
+            aspectRatio = GetAspectRatio(SkipSpacesTabs(&input[12]));
+            optionSeen[OPTION_ASPECT_RATIO] = TRUE;
+        }
+        break;
+        
+    case 'B':
+        if (STRNEQ(input, "BQSCALE", 7)) {
+            SetBQScale(atoi(SkipSpacesTabs(&input[7])));
+            optionSeen[OPTION_BQSCALE] = TRUE;
+        } else if (STRNEQ(input, "BASE_FILE_FORMAT", 16)) {
+            const char * arg = SkipSpacesTabs(&input[16]);
+            SetFileFormat(arg);
+            if (STRNEQ(arg, "YUV", 3) || STREQ(arg, "Y"))
+                *yuvUsedP = TRUE;
+            optionSeen[OPTION_BASE_FORMAT] = TRUE;
+        } else if (STRNEQ(input, "BSEARCH_ALG", 11)) {
+            SetBSearchAlg(SkipSpacesTabs(&input[11]));
+            optionSeen[OPTION_BSEARCH_ALG] = TRUE;
+        } else if (STRNEQ(input, "BIT_RATE", 8)) {
+            setBitRate(SkipSpacesTabs(&input[8]));
+            optionSeen[OPTION_BIT_RATE] = TRUE;
+        } else if (STRNEQ(input, "BUFFER_SIZE", 11)) {
+            setBufferSize(SkipSpacesTabs(&input[11]));
+            optionSeen[OPTION_BUFFER_SIZE] = TRUE;                  
+        }
+        break;
+
+    case 'C':
+        if (STRNEQ(input, "CDL_FILE", 8)) {
+            strcpy(specificsFile, SkipSpacesTabs(&input[8]));
+            specificsOn = TRUE;
+            optionSeen[OPTION_SPECIFICS] = TRUE;
+        } else if (STRNEQ(input, "CDL_DEFINES", 11)) {
+            strcpy(specificsDefines, SkipSpacesTabs(&input[11]));
+            optionSeen[OPTION_DEFS_SPECIFICS] = TRUE;
+        }
+        break;
+
+    case 'F':
+        if (STRNEQ(input, "FRAME_INPUT_DIR", 15)) {
+            const char * const arg = SkipSpacesTabs(&input[15]);
+            if (STRNCASEEQ(arg, "stdin", 5))
+                SetStdinInput(frameInputSourceP);
+
+            strcpy(currentFramePath, arg);
+        } else if (STRNEQ(input, "FRAME_INPUT", 11)) {
+            ReadInputFileNames(fpointer, "FRAME_END_INPUT", 
+                               frameInputSourceP->stdinUsed ? 
+                               NULL : frameInputSourceP);
+            optionSeen[OPTION_FRAME_INPUT] = TRUE;
+        } else if (STRNEQ(input, "FORCE_I_ALIGN", 13)) {
+            forceIalign = TRUE;
+        } else if (STRNEQ(input, "FORCE_ENCODE_LAST_FRAME", 23)) {
+            /* NO-OP.  We used to drop trailing B frames by default and you
+               needed this option to change the last frame to I so you could
+               encode all the frames.  Now we just do that all the time.  
+               Why wouldn't we?
+            */
+        } else if (STRNEQ(input, "FRAME_RATE", 10)) {
+            frameRate = GetFrameRate(SkipSpacesTabs(&input[10]));
+            frameRateRounded = (int) VidRateNum[frameRate];
+            if ((frameRate % 3) == 1)
+                frameRateInteger = FALSE;
+            optionSeen[OPTION_FRAME_RATE] = TRUE;
+        }
+        break;
+        
+    case 'G':
+        if (STRNEQ(input, "GOP_SIZE", 8)) {
+            SetGOPSize(atoi(SkipSpacesTabs(&input[8])));
+            optionSeen[OPTION_GOP] = TRUE;
+        } else if (STRNEQ(input, "GOP_INPUT_DIR", 13)) {
+            const char * const arg = SkipSpacesTabs(&input[13]);
+            if (STRNCASEEQ(arg, "stdin", 5))
+                SetStdinInput(gopInputSourceP);
+
+            strcpy(currentGOPPath, arg);
+        } else if (STRNEQ(input, "GOP_INPUT", 9)) {
+            ReadInputFileNames(fpointer, "GOP_END_INPUT", 
+                               gopInputSourceP->stdinUsed ? 
+                               NULL : gopInputSourceP);
+            optionSeen[OPTION_GOP_INPUT] = TRUE;
+        } else if (STRNEQ(input, "GAMMA", 5)) {
+            GammaCorrection = TRUE;
+            sscanf(SkipSpacesTabs(&input[5]), "%f", &GammaValue);
+            optionSeen[OPTION_GAMMA] = TRUE;
+        }
+        break;
+        
+    case 'I':
+        if (STRNEQ(input, "IQSCALE", 7)) {
+            SetIQScale(atoi(SkipSpacesTabs(&input[7])));
+            optionSeen[OPTION_IQSCALE] = TRUE;
+        } else if (STRNEQ(input, "INPUT_DIR", 9)) {
+            const char * const arg = SkipSpacesTabs(&input[9]);
+            if (STRNCASEEQ(arg, "stdin", 5))
+                SetStdinInput(inputSourceP);
+            strcpy(currentPath, arg);
+            optionSeen[OPTION_INPUT_DIR] = TRUE;
+        } else if (STRNEQ(input, "INPUT_CONVERT", 13)) {
+            strcpy(inputConversion, SkipSpacesTabs(&input[13]));
+            optionSeen[OPTION_INPUT_CONVERT] = TRUE;
+        } else if (STREQ(input, "INPUT")) {
+            ReadInputFileNames(fpointer, "END_INPUT", 
+                               inputSourceP->stdinUsed ?
+                               NULL : inputSourceP);
+            optionSeen[OPTION_INPUT] = TRUE;
+        } else if (STRNEQ(input, "IO_SERVER_CONVERT", 17)) {
+            strcpy(ioConversion, SkipSpacesTabs(&input[17]));
+            optionSeen[OPTION_IO_CONVERT] = TRUE;
+        } else if (STRNEQ(input, "IQTABLE", 7)) {
+            processIqtable(fpointer);
+
+            optionSeen[OPTION_IQTABLE] = TRUE;
+        }
+        break;
+
+    case 'K':
+        if (STRNEQ(input, "KEEP_TEMP_FILES", 15))
+            keepTempFiles = TRUE;
+        break;
+        
+    case 'N':
+      if (STRNEQ(input, "NIQTABLE", 8)) {
+          readNiqTable(fpointer);
+
+          optionSeen[OPTION_NIQTABLE] = TRUE;
+      }
+      break;
+
+    case 'O':
+        if (STRNEQ(input, "OUTPUT", 6)) {
+            const char * const arg = SkipSpacesTabs(&input[6]);
+            if ( whichGOP == -1 )
+                strcpy(outputFileName, arg);
+            else
+                sprintf(outputFileName, "%s.gop.%d", arg, whichGOP);
+            
+            optionSeen[OPTION_OUTPUT] = TRUE;
+        }
+        break;
+        
+    case 'P':
+        if (STRNEQ(input, "PATTERN", 7)) {
+            SetFramePattern(SkipSpacesTabs(&input[7]));
+            optionSeen[OPTION_PATTERN] = TRUE;
+        } else if (STRNEQ(input, "PIXEL", 5)) {
+            SetPixelSearch(SkipSpacesTabs(&input[5]));
+            optionSeen[OPTION_PIXEL] = TRUE;
+        } else if (STRNEQ(input, "PQSCALE", 7)) {
+            SetPQScale(atoi(SkipSpacesTabs(&input[7])));
+            optionSeen[OPTION_PQSCALE] = TRUE;
+        } else if (STRNEQ(input, "PSEARCH_ALG", 11)) {
+            SetPSearchAlg(SkipSpacesTabs(&input[11]));
+            optionSeen[OPTION_PSEARCH_ALG] = TRUE;
+        } else if (STRNEQ(input, "PARALLEL_TEST_FRAMES", 20)) {
+            SetParallelPerfect(FALSE);
+            parallelTestFrames = atoi(SkipSpacesTabs(&input[20]));
+        } else if (STRNEQ(input, "PARALLEL_TIME_CHUNKS", 20)) {
+            SetParallelPerfect(FALSE);
+            parallelTimeChunks = atoi(SkipSpacesTabs(&input[20]));
+        } else if (STRNEQ(input, "PARALLEL_CHUNK_TAPER", 20)) {
+            SetParallelPerfect(FALSE);
+            parallelTimeChunks = -1;
+        } else if (STRNEQ(input, "PARALLEL_PERFECT", 16)) {
+            SetParallelPerfect(TRUE);
+        } else if (STRNEQ(input, "PARALLEL", 8)) {
+            ReadMachineNames(fpointer);
+            optionSeen[OPTION_PARALLEL] = TRUE;
+        }
+        break;
+        
+    case 'R':
+        if (STRNEQ(input, "RANGE", 5)) {
+            processRanges(SkipSpacesTabs(&input[5]));
+            optionSeen[OPTION_RANGE] = TRUE;
+        } else if (STRNEQ(input, "REFERENCE_FRAME", 15)) {
+            SetReferenceFrameType(SkipSpacesTabs(&input[15]));
+            optionSeen[OPTION_REF_FRAME] = TRUE;
+        } else if (STRNEQ(input, "RSH", 3)) {
+            SetRemoteShell(SkipSpacesTabs(&input[3]));
+        } else if (STRNEQ(input, "RESIZE", 6)) {
+            const char * const arg = SkipSpacesTabs(&input[6]);
+            sscanf(arg, "%dx%d", &outputWidth, &outputHeight);
+            outputWidth &= ~(DCTSIZE * 2 - 1);
+            outputHeight &= ~(DCTSIZE * 2 - 1);
+            optionSeen[OPTION_RESIZE] = TRUE;
+        }
+        break;
+
+    case 'S':
+        if (STRNEQ(input, "SLICES_PER_FRAME", 16)) {
+            SetSlicesPerFrame(atoi(SkipSpacesTabs(&input[16])));
+            optionSeen[OPTION_SPF] = TRUE;
+        } else if (STRNEQ(input, "SLAVE_CONVERT", 13)) {
+            strcpy(slaveConversion, SkipSpacesTabs(&input[13]));
+            optionSeen[OPTION_SLAVE_CONVERT] = TRUE;
+        } else if (STRNEQ(input, "SPECIFICS_FILE", 14)) {
+            strcpy(specificsFile, SkipSpacesTabs(&input[14]));
+            specificsOn = TRUE;
+            optionSeen[OPTION_SPECIFICS] = TRUE;
+        } else if (STRNEQ(input, "SPECIFICS_DEFINES", 16)) {
+            strcpy(specificsDefines, SkipSpacesTabs(&input[17]));
+            optionSeen[OPTION_DEFS_SPECIFICS] = TRUE;
+        } else if (STRNEQ(input, "SEQUENCE_SIZE", 13)) {
+            mult_seq_headers = atoi(SkipSpacesTabs(&input[13]));
+        } else if (STRNEQ(input, "SIZE", 4)) {
+            const char * const arg = SkipSpacesTabs(&input[4]);
+            sscanf(arg, "%dx%d", &yuvWidth, &yuvHeight);
+            realWidth = yuvWidth;
+            realHeight = yuvHeight;
+            Fsize_Validate(&yuvWidth, &yuvHeight);
+            optionSeen[OPTION_YUV_SIZE] = TRUE;
+        }
+        break;
+
+    case 'T':
+        if (STRNEQ(input, "TUNE", 4)) {
+            tuneingOn = TRUE;
+            ParseTuneParam(SkipSpacesTabs(&input[4]));
+        }
+        break;
+
+    case 'U':
+        if (STRNEQ(input, "USER_DATA", 9)) {
+            strcpy(userDataFileName, SkipSpacesTabs(&input[9]));
+            optionSeen[OPTION_USER_DATA] = TRUE;
+        }
+        break;
+        
+    case 'W':
+        if (STRNEQ(input, "WARN_UNDERFLOW", 14))
+            paramP->warnUnderflow = TRUE;
+        if (STRNEQ(input, "WARN_OVERFLOW", 13))
+            paramP->warnOverflow = TRUE;
+        break;
+        
+    case 'Y':
+        if (STRNEQ(input, "YUV_SIZE", 8)) {
+            const char * const arg = SkipSpacesTabs(&input[8]);
+            sscanf(arg, "%dx%d", &yuvWidth, &yuvHeight);
+            realWidth = yuvWidth;
+            realHeight = yuvHeight;
+            Fsize_Validate(&yuvWidth, &yuvHeight);
+            optionSeen[OPTION_YUV_SIZE] = TRUE;
+        } else if (STRNEQ(input, "Y_SIZE", 6)) {
+            const char * const arg = SkipSpacesTabs(&input[6]);
+            sscanf(arg, "%dx%d", &yuvWidth, &yuvHeight);
+            realWidth = yuvWidth;
+            realHeight = yuvHeight;
+            Fsize_Validate(&yuvWidth, &yuvHeight);
+            optionSeen[OPTION_YUV_SIZE] = TRUE;
+        } else if (STRNEQ(input, "YUV_FORMAT", 10)) {
+            strcpy(yuvConversion,  SkipSpacesTabs(&input[10]));
+            optionSeen[OPTION_YUV_FORMAT] = TRUE;
+        }
+        break;
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ * ReadParamFile
+ *
+ *	read the parameter file
+ *	function is ENCODE_FRAMES, COMBINE_GOPS, or COMBINE_FRAMES, and
+ *	    will slightly modify the procedure's behavior as to what it
+ *	    is looking for in the parameter file
+ *
+ * SIDE EFFECTS:    sets parameters accordingly, as well as machine info for
+ *		    parallel execution and input file names
+ *
+ *===========================================================================*/
+void
+ReadParamFile(const char *    const fileName, 
+              int             const function,
+              struct params * const paramP) {
+
+  FILE *fpointer;
+  char    buffer[256];
+  bool yuvUsed;
+  struct inputSource * inputSourceP;
+      /* Contents of INPUT section */
+  struct inputSource * frameInputSourceP;
+      /* Contents of FRAME_INPUT section */
+  struct inputSource * gopInputSourceP;
+      /* Contents of GOP_INPUT section */
+
+  fpointer = fopen(fileName, "r");
+  if (fpointer == NULL)
+      pm_error("Error:  Cannot open parameter file:  %s", fileName);
+
+  CreateInputSource(&inputSourceP);
+  CreateInputSource(&frameInputSourceP);
+  CreateInputSource(&gopInputSourceP);
+
+  /* should set defaults */
+  numMachines = 0;
+  sprintf(currentPath, ".");
+  sprintf(currentGOPPath, ".");
+  sprintf(currentFramePath, ".");
+  SetRemoteShell("rsh");
+  keepTempFiles = FALSE;
+  paramP->warnOverflow = FALSE;
+  paramP->warnUnderflow = FALSE;
+
+  initOptionSeen();
+
+  yuvUsed = FALSE;  /* initial value */
+
+  while (fgets(buffer, 256, fpointer) != NULL) {
+      const char * input;
+
+      removeTrailingWhite(buffer, &input);
+
+      if (strlen(input) == 0) {
+          /* Ignore blank line */
+      } else if (input[0] == '#') {
+          /* Ignore comment */
+      } else
+          processParamLine(input, fpointer, &yuvUsed,
+                           inputSourceP, frameInputSourceP, gopInputSourceP,
+                           paramP);
+              /* May read additional lines from file */
+
+      strfree(input);
+  }
+
+  fclose(fpointer);
+
+  setInputSource(function, &paramP->inputSourceP,
+                 inputSourceP, gopInputSourceP, frameInputSourceP);
+
+  verifyNoMissingOption(function);
+
+  /* error checking */
+
+  if (!paramP->inputSourceP->stdinUsed &&
+      paramP->inputSourceP->numInputFiles == 0)
+      pm_error("You have not specified any input.  See the "
+               "INPUT_DIR, INPUT, GOP_INPUT_DIR, GOP_INPUT, "
+               "FRAME_INPUT_DIR, and FRAME_INPUT options");
+
+  if (yuvUsed) {
+      if (!optionSeen[OPTION_YUV_SIZE])
+          pm_error("YUV format used but YUV_SIZE not given");
+      
+      if (!optionSeen[OPTION_YUV_FORMAT]) {
+          strcpy (yuvConversion, "EYUV");
+          pm_message("WARNING:  YUV format not specified; "
+                     "defaulting to Berkeley YUV (EYUV)");
+      }
+  }
+
+  if (paramP->inputSourceP->stdinUsed && optionSeen[OPTION_PARALLEL] )
+      pm_error("stdin reading for parallel execution not enabled yet.");
+
+  if (optionSeen[OPTION_PARALLEL] && !optionSeen[OPTION_YUV_SIZE])
+      pm_error("Specify SIZE WxH for parallel encoding");
+
+  if (optionSeen[OPTION_IO_CONVERT] != optionSeen[OPTION_SLAVE_CONVERT])
+      pm_error("Must have either both IO_SERVER_CONVERT and SLAVE_CONVERT "
+               "or neither");
+      
+  if (optionSeen[OPTION_DEFS_SPECIFICS] && !optionSeen[OPTION_SPECIFICS])
+      pm_error("Does not make sense to define Specifics file options, "
+               "but no specifics file!");
+
+  SetIOConvert(optionSeen[OPTION_IO_CONVERT]);
+
+  SetResize(optionSeen[OPTION_RESIZE]);
+
+  if (function == ENCODE_FRAMES) {
+      SetFCode();
+
+      if (psearchAlg == PSEARCH_TWOLEVEL)
+          SetPixelSearch("HALF");
+  }
+}
+
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
diff --git a/converter/ppm/ppmtompeg/parse_huff.pl b/converter/ppm/ppmtompeg/parse_huff.pl
new file mode 100644
index 00000000..1fc6466c
--- /dev/null
+++ b/converter/ppm/ppmtompeg/parse_huff.pl
@@ -0,0 +1,198 @@
+# 
+# Copyright (c) 1993 The Regents of the University of California.
+# All rights reserved.
+# 
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose, without fee, and without written agreement is
+# hereby granted, provided that the above copyright notice and the following
+# two paragraphs appear in all copies of this software.
+# 
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# 
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+# 
+
+#  
+#  $Header: /n/picasso/users/dwallach/vid2/mpeg_encode/RCS/parse_huff.pl,v 1.3 1993/01/18 10:56:03 dwallach Exp $
+#  $Log: parse_huff.pl,v $
+# Revision 1.3  1993/01/18  10:56:03  dwallach
+# got RCS headers in huff.c and huff.h working
+#
+# Revision 1.3  1993/01/18  10:56:03  dwallach
+# got RCS headers in huff.c and huff.h working
+#
+# Revision 1.2  1993/01/18  10:17:29  dwallach
+# RCS headers installed, code indented uniformly
+#
+# Revision 1.2  1993/01/18  10:17:29  dwallach
+# RCS headers installed, code indented uniformly
+#
+#
+
+# this program's purpose in life is to parse the Huffman tables
+# and output C code which is awfully useful for translation
+
+# typical usage:
+# perl parse_huff.pl huffman.table
+# ---> generates huff.c and huff.h
+
+# source format:  # is a comment character
+# Otherwise, there are three tab-separated fields in a line:
+#    Run, Level, and VLC Code
+# Run and Level are integers, corresponding to the RLE coding.
+# The VLC code is what bits to generate, and is expected to be
+#    composed of 1, 0, space, and 's'.  Spaces are ignored, and
+#    s corresponds to the sign bit.  In the output of this program,
+#    We'll completely right-shift the data, with a 0 for the sign
+#    bit.  The encoder will make appropriate changes before outputing.
+
+
+open(HUFFC, "> huff.c") || die "Can't write huff.c: $!\n";
+open(HUFFH, "> huff.h") || die "Can't write huff.h: $!\n";
+
+sub encode {
+    local($run, $level, $vlc) = @_;
+    local($result) = 0;
+    local($tmp);
+    $vlc =~ s/\s//g;           # remove whitespace
+
+    local($bits) = length($vlc);
+
+    foreach (split(//, $vlc)) {
+	$_ = 0 if $_ eq 's';
+	$result = ($result << 1) + $_;
+    }
+
+    $tmp = sprintf("0x%x", $result);
+    eval "\$vlc$run[$level] = \$tmp";
+    eval "\$bits$run[$level] = \$bits";
+}
+
+while(<>) {
+    chop;
+    s/\s*#.*$//;       # remove comments
+    next if /^\s*$/;   # continue if the line is purely whitespace
+
+    ($run, $level, $vlc) = split(/\t/);
+    &encode($run, $level, $vlc);
+
+    #
+    # we have the +1's to insure the sizes of C arrays are correct
+    #
+    $maxlevel[$run] = $level+1 if $level >= $maxlevel[$run];
+    $maxlevel = $level+1 if $level >= $maxlevel;
+    $maxrun = $run+1 if $run >= $maxrun;
+}
+
+#
+# fix the entries that aren't defined
+#
+for($run = 0; $run < $maxrun; $run++) {
+    eval "\$vlc$run[0] = '0x0' if \$vlc$run[0] eq ''";
+    eval "\$bits$run[0] = '0' if \$bits$run[0] eq ''";
+}
+
+#
+# now, output some C code
+#
+
+printf HUFFC <<'EOF', $maxrun, join(", ", @maxlevel);
+/*
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /n/picasso/users/dwallach/vid2/mpeg_encode/RCS/parse_huff.pl,v 1.3 1993/01/18 10:56:03 dwallach Exp $
+ */
+
+/*  
+ *  THIS FILE IS MACHINE GENERATED!  DO NOT EDIT!
+ */
+#include "mtypes.h"
+#include "huff.h"
+
+int huff_maxlevel[%s] = { %s };
+
+EOF
+for($run = 0; $run < $maxrun; $run++) {
+    printf HUFFC <<EOF, eval "join(', ', \@vlc$run)", eval "join(', ', \@bits$run)";
+uint32 huff_table$run[$maxlevel[$run]] = { %s };
+int huff_bits$run[$maxlevel[$run]] = { %s };
+
+EOF
+}
+
+printf HUFFC "uint32 *huff_table[$maxrun] = { ";
+for($run = 0; $run < $maxrun; $run++) {
+    printf HUFFC "%shuff_table$run", ($run)?", ":"";
+}
+printf HUFFC " };\n";
+
+printf HUFFC "int *huff_bits[$maxrun] = { ";
+for($run = 0; $run < $maxrun; $run++) {
+    printf HUFFC "%shuff_bits$run", ($run)?", ":"";
+}
+printf HUFFC " };\n";
+close HUFFC;
+
+printf HUFFH <<'EOF', $maxrun, $maxlevel;
+/*
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /n/picasso/users/dwallach/vid2/mpeg_encode/RCS/parse_huff.pl,v 1.3 1993/01/18 10:56:03 dwallach Exp $
+ */
+
+/*  
+ *  THIS FILE IS MACHINE GENERATED!  DO NOT EDIT!
+ */
+#define HUFF_MAXRUN	%s
+#define HUFF_MAXLEVEL	%s
+
+extern int huff_maxlevel[];
+extern uint32 *huff_table[];
+extern int *huff_bits[];
+EOF
+
diff --git a/converter/ppm/ppmtompeg/pframe.c b/converter/ppm/ppmtompeg/pframe.c
new file mode 100644
index 00000000..e72fe5d6
--- /dev/null
+++ b/converter/ppm/ppmtompeg/pframe.c
@@ -0,0 +1,1072 @@
+/*===========================================================================*
+ * pframe.c                                  
+ *                                       
+ *  Procedures concerned with generation of P-frames             
+ *                                       
+ * EXPORTED PROCEDURES:                              
+ *  GenPFrame                                
+ *  ResetPFrameStats                             
+ *  ShowPFrameSummary                            
+ *  EstimateSecondsPerPFrame                         
+ *  ComputeHalfPixelData                             
+ *  SetPQScale                               
+ *  GetPQScale                               
+ *                                                                           
+ * NOTE:  when motion vectors are passed as arguments, they are passed as    
+ *        twice their value.  In other words, a motion vector of (3,4) will  
+ *        be passed as (6,8).  This allows half-pixel motion vectors to be   
+ *        passed as integers.  This is true throughout the program.          
+ *                                       
+ *===========================================================================*/
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include <assert.h>
+#include <sys/param.h>
+#include "pm.h"
+#include "pm_c_util.h"
+#include "all.h"
+#include "mtypes.h"
+#include "bitio.h"
+#include "frames.h"
+#include "motion_search.h"
+#include "prototypes.h"
+#include "block.h"
+#include "param.h"
+#include "mheaders.h"
+#include "fsize.h"
+#include "postdct.h"
+#include "mpeg.h"
+#include "parallel.h"
+#include "rate.h"
+#include "opts.h"
+#include "specifics.h"
+
+/*==================*
+ * STATIC VARIABLES *
+ *==================*/
+
+static int32    zeroDiff;
+static int      numPIBlocks = 0;
+static int      numPPBlocks = 0;
+static int      numPSkipped = 0;
+static int      numPIBits = 0;
+static int      numPPBits = 0;
+static int      numFrames = 0;
+static int      numFrameBits = 0;
+static int32    totalTime = 0;
+static int      qscaleP;
+static float    totalSNR = 0.0;
+static float    totalPSNR = 0.0;
+extern Block    **dct, **dctr, **dctb;
+extern dct_data_type   **dct_data;
+
+/*=====================*
+ * INTERNAL PROCEDURES *
+ *=====================*/
+
+static vector
+halfVector(vector const vector) {
+    struct vector half;
+
+    half.y = vector.y/2;
+    half.x = vector.x/2;
+
+    return half;
+}
+
+/*===========================================================================*
+ *
+ *  decide if (0,0) motion is better than the given motion vector
+ *
+ * RETURNS: TRUE if (0,0) is better, FALSE if (my,mx) is better
+ *
+ * SIDE EFFECTS:    none
+ *
+ * PRECONDITIONS:   The relevant block in 'current' is valid (it has not
+ *          been dct'd).  'zeroDiff' has already been computed
+ *          as the LumMotionError() with (0,0) motion
+ *
+ * NOTES:   This procedure follows the algorithm described on
+ *      page D-48 of the MPEG-1 specification
+ *
+ *===========================================================================*/
+static boolean
+ZeroMotionBetter(const LumBlock * const currentBlockP,
+                 MpegFrame *      const prev,
+                 int              const by,
+                 int              const bx,
+                 vector           const m) {
+
+    int bestDiff;
+    int CompareMode;
+
+    /* Junk needed to adapt for TUNEing */ 
+    CompareMode = SearchCompareMode;
+    SearchCompareMode = DEFAULT_SEARCH;
+    bestDiff = LumMotionError(currentBlockP, prev, by, bx, m, 0x7fffffff);
+    SearchCompareMode = CompareMode;
+
+    if ( zeroDiff < 256*3 ) {
+    if ( 2*bestDiff >= zeroDiff ) {
+        return TRUE;
+    }
+    } else {
+    if ( 11*bestDiff >= 10*zeroDiff ) {
+        return TRUE;
+    }
+    }
+    return FALSE;
+}
+
+
+/*===========================================================================*
+ *
+ *                USER-MODIFIABLE
+ *
+ * DoIntraCode
+ *
+ *  decide if intra coding is necessary
+ *
+ * RETURNS: TRUE if intra-block coding is better; FALSE if not
+ *
+ * SIDE EFFECTS:    none
+ *
+ * PRECONDITIONS:   The relevant block in 'current' is valid (it has not
+ *          been dct'd).
+ *
+ * NOTES:   This procedure follows the algorithm described on
+ *      page D-49 of the MPEG-1 specification
+ *
+ *===========================================================================*/
+static boolean
+DoIntraCode(const LumBlock * const currentBlockP,
+            MpegFrame *      const prev,
+            int              const by,
+            int              const bx,
+            vector           const motion) {
+
+    unsigned int y;
+    int32 sum = 0, vard = 0, varc = 0;
+    int32 currPixel, prevPixel;
+    LumBlock motionBlock;
+
+    ComputeMotionLumBlock(prev, by, bx, motion, &motionBlock);
+
+    for (y = 0; y < 16; ++y) {
+        unsigned int x;
+        for (x = 0; x < 16; ++x) {
+            currPixel = currentBlockP->l[y][x];
+            prevPixel = motionBlock.l[y][x];
+            
+            sum += currPixel;
+            varc += currPixel*currPixel;
+            
+            vard += SQR(currPixel - prevPixel);
+        }
+    }
+    
+    vard /= 256;     /* divide by 256; assumes mean is close to zero */
+    varc = (varc/256) - (sum/256) * (sum/256);
+
+    if (vard <= 64)
+        return FALSE;
+    else if (vard < varc)
+        return FALSE;
+    else
+        return TRUE;
+}
+
+
+
+/*===========================================================================*
+ *
+ *                USER-MODIFIABLE
+ *
+ * ZeroMotionSufficient
+ *
+ *  decide if zero motion is sufficient without DCT correction
+ *
+ * RETURNS: TRUE no DCT required; FALSE otherwise
+ *
+ * SIDE EFFECTS:    none
+ *
+ * PRECONDITIONS:   The relevant block in 'current' is raw YCC data
+ *
+ *===========================================================================*/
+static boolean
+ZeroMotionSufficient(const LumBlock * const currentBlockP,
+                     MpegFrame *      const prev,
+                     int              const by,
+                     int              const bx) {
+
+    LumBlock motionBlock;
+    int fy, fx;
+    unsigned int y;
+
+    fy = by * DCTSIZE;
+    fx = bx * DCTSIZE;
+    for (y = 0; y < 16; ++y) {
+        unsigned int x;
+        for (x = 0; x < 16; ++x) {
+            motionBlock.l[y][x] = prev->ref_y[fy+y][fx+x];
+        }
+    }
+
+    zeroDiff = LumBlockMAD(currentBlockP, &motionBlock, 0x7fffffff);
+
+    return (zeroDiff <= 256);
+}
+                 
+
+
+static void 
+computeCurrentBlock(MpegFrame * const current, 
+                    int         const y,
+                    int         const x,
+                    LumBlock *  const currentBlockP) {
+    int fy, fx;
+    int iy;
+
+    BLOCK_TO_FRAME_COORD(y, x, fy, fx);
+    for ( iy = 0; iy < 16; iy++ ) {
+        int ix;
+        for ( ix = 0; ix < 16; ix++ ) {
+            currentBlockP->l[iy][ix] = 
+                (int16)current->orig_y[fy+iy][fx+ix];
+        }
+    }
+}
+
+
+
+static void
+computeMotionVectors(bool             const specificsOn, 
+                     bool             const IntraPBAllowed,
+                     MpegFrame *      const current, 
+                     MpegFrame *      const prev,
+                     int              const mbAddress,
+                     BlockMV **       const infoP,
+                     int              const QScale, 
+                     const LumBlock * const currentBlockP,
+                     int              const y, 
+                     int              const x,
+                     bool *           const useMotionP, 
+                     vector *         const motionP) {
+
+    bool useCached;
+    BlockMV * info;
+
+    /* See if we have a cached answer */
+    if (specificsOn) {
+        SpecLookup(current->id, 2, mbAddress, &info, QScale);
+        if (info != (BlockMV*)NULL) 
+            useCached = TRUE;
+        else
+            useCached = FALSE;
+    } else
+        useCached = FALSE;
+
+    if (useCached) {
+        if (info->typ == TYP_SKIP) {
+            motionP->x = motionP->y = 0;
+            *useMotionP = TRUE;
+        } else {        /* assume P, since we're a P frame.... */
+            motionP->x = info->fx;
+            motionP->y = info->fy;
+            *useMotionP = TRUE;
+        }
+    } else {
+        /* see if we should use motion vectors, and if so, what those
+         * vectors should be
+         */
+        if (ZeroMotionSufficient(currentBlockP, prev, y, x)) {
+            motionP->x = 0;
+            motionP->y = 0;
+            *useMotionP = TRUE;
+        } else {
+            vector motion;
+            motion.y = motion.x = 0;  /* initial values */
+            PMotionSearch(currentBlockP, prev, y, x, &motion);
+            if (ZeroMotionBetter(currentBlockP, prev, y, x, motion)) {
+                motionP->y = 0;
+                motionP->x = 0;
+            } else
+                *motionP = motion;
+            if (IntraPBAllowed) 
+                *useMotionP = !DoIntraCode(currentBlockP, prev, y, x, motion);
+            else
+                *useMotionP = TRUE;
+        }
+    }
+    *infoP = info;
+}
+
+
+
+static void
+calculateForwardDcts(MpegFrame * const current, 
+                     int const y, int const x,
+                     Block ** const dct) {
+
+    /* calculate forward dct's */
+    if (collect_quant && (collect_quant_detailed & 1)) 
+        fprintf(collect_quant_fp, "l\n");
+
+    mp_fwd_dct_block2(current->y_blocks[y][x], dct[y][x]);
+    mp_fwd_dct_block2(current->y_blocks[y][x+1], dct[y][x+1]);
+    mp_fwd_dct_block2(current->y_blocks[y+1][x], dct[y+1][x]);
+    mp_fwd_dct_block2(current->y_blocks[y+1][x+1], dct[y+1][x+1]);
+
+    if (collect_quant && (collect_quant_detailed & 1)) 
+        fprintf(collect_quant_fp, "c\n");
+
+    mp_fwd_dct_block2(current->cb_blocks[y/2][x/2], dctb[y/2][x/2]);
+
+    mp_fwd_dct_block2(current->cr_blocks[y/2][x/2], dctr[y/2][x/2]);
+}
+
+
+
+static void
+computeMotionAndDct(int         const lastBlockY,
+                    int         const lastBlockX,
+                    bool        const specificsOn,
+                    bool        const IntraPBAllowed,
+                    MpegFrame * const current,
+                    MpegFrame * const prev,
+                    BlockMV **  const infoP,
+                    int         const QScale,
+                    int         const searchRangeP,
+                    Block **    const dct,
+                    int *       const numPBlocksP,
+                    int *       const numIBlocksP,
+                    int **      const pmvHistogram) {
+/*----------------------------------------------------------------------------
+   Loop through the frame finding motion/not and DCTing
+-----------------------------------------------------------------------------*/
+    int mbAddress;
+    int y;
+
+    mbAddress = 0;                        
+
+    for (y = 0; y < lastBlockY; y += 2) {
+        int x;
+        for (x = 0; x < lastBlockX; x += 2) {
+            LumBlock currentBlock;
+            vector motion;
+            bool useMotion;
+
+            computeCurrentBlock(current, y, x, &currentBlock);
+
+            computeMotionVectors(specificsOn,  IntraPBAllowed,
+                                 current, prev, mbAddress, infoP,
+                                 QScale, &currentBlock, y, x,
+                                 &useMotion, &motion);
+
+            dct_data[y][x].useMotion = useMotion;
+
+            if (useMotion) {
+                int pattern;
+
+                (*numPBlocksP)++;
+
+                pattern = 63;
+                ComputeDiffDCTs(current, prev, y, x, motion, &pattern);
+
+                assert(motion.x + searchRangeP + 1 >= 0);
+                assert(motion.y + searchRangeP + 1 >= 0);
+
+                if (computeMVHist) {
+                    assert(motion.x + searchRangeP + 1 <= 2*searchRangeP + 2);
+                    assert(motion.y + searchRangeP + 1 <= 2*searchRangeP + 2);
+                    ++pmvHistogram[motion.x + searchRangeP + 1]
+                        [motion.y + searchRangeP + 1];
+                }
+                /* Save specs for next loops */
+                dct_data[y][x].pattern  = pattern;
+                dct_data[y][x].fmotionX = motion.x;
+                dct_data[y][x].fmotionY = motion.y;
+            } else {
+                /* output I-block inside a P-frame */
+                ++*numIBlocksP;
+
+                calculateForwardDcts(current, y, x, dct);
+            }
+            ++mbAddress;
+        }
+    }
+}
+
+
+
+/*=====================*
+ * EXPORTED PROCEDURES *
+ *=====================*/
+
+/*===========================================================================*
+ *
+ * GenPFrame
+ *
+ *  generate a P-frame from previous frame, adding the result to the
+ *  given bit bucket
+ *
+ * RETURNS: frame appended to bb
+ *
+ *===========================================================================*/
+void
+GenPFrame(BitBucket * const bb,
+          MpegFrame * const current, 
+          MpegFrame * const prev) {
+
+    extern int **pmvHistogram;
+    FlatBlock fba[6], fb[6];
+    Block   dec[6];
+    int32 y_dc_pred, cr_dc_pred, cb_dc_pred;
+    int x, y;
+    vector motion;
+    vector oldMotion;
+    int offsetX, offsetY;
+    vector motionRem;
+    vector motionQuot;
+    int pattern;
+    int mbAddrInc = 1;
+    int numIBlocks = 0;
+    int numPBlocks = 0;
+    int numSkipped = 0;
+    int numIBits = 0;
+    int numPBits = 0;
+    int totalBits;
+    int totalFrameBits;
+    int32    startTime, endTime;
+    int lastBlockX, lastBlockY;
+    int lastX, lastY;
+    int mbAddress;
+    int slicePos;
+    register int index;
+    float   snr[3], psnr[3];
+    int QScale;
+    BlockMV *info;
+    int bitstreamMode, newQScale;
+    int rc_blockStart = 0;
+    boolean overflowChange = FALSE;
+    int     overflowValue  = 0;
+
+
+    oldMotion.x = oldMotion.y = 0;
+
+    if (collect_quant) {fprintf(collect_quant_fp, "# P\n");}
+    if (dct==NULL) AllocDctBlocks();
+    numFrames++;
+    totalFrameBits = bb->cumulativeBits;
+    startTime = time_elapsed();
+
+    DBG_PRINT(("Generating pframe\n"));
+
+    QScale = GetPQScale();
+    /*   bit allocation for rate control purposes */
+    bitstreamMode = getRateMode();
+    if (bitstreamMode == FIXED_RATE) {
+        targetRateControl(current);
+    }
+ 
+    Mhead_GenPictureHeader(bb, P_FRAME, current->id, fCodeP);
+    /* Check for Qscale change */  
+    if (specificsOn) {
+        /* Set a Qscale for this frame? */
+        newQScale = 
+            SpecLookup(current->id, 0, 0 /* junk */, &info /*junk*/, QScale);
+        if (newQScale != -1) {
+            QScale = newQScale;
+        }
+        /* Set for slice? */
+        newQScale = SpecLookup(current->id, 1, 1, &info /*junk*/, QScale);
+        if (newQScale != -1) {
+            QScale = newQScale;
+        }
+    }
+
+    DBG_PRINT(("Slice Header\n"));
+    Mhead_GenSliceHeader(bb, 1, QScale, NULL, 0);
+
+    if ( referenceFrame == DECODED_FRAME ) {
+        Frame_AllocDecoded(current, TRUE);
+    } else if ( printSNR ) {
+        Frame_AllocDecoded(current, FALSE);
+    }
+
+    /* don't do dct on blocks yet */
+    Frame_AllocBlocks(current);
+    BlockifyFrame(current);
+
+    /* for I-blocks */
+    y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
+
+    totalBits = bb->cumulativeBits;
+
+    if ( (! pixelFullSearch) && (! prev->halfComputed) ) {
+        ComputeHalfPixelData(prev);
+    }
+
+    lastBlockX = Fsize_x>>3;
+    lastBlockY = Fsize_y>>3;
+    lastX = lastBlockX-2;
+    lastY = lastBlockY-2;
+
+    computeMotionAndDct(lastBlockY, lastBlockX,
+                        specificsOn, IntraPBAllowed, current, prev,
+                        &info, QScale, searchRangeP, dct, 
+                        &numPBlocks, &numIBlocks, pmvHistogram);
+    
+    mbAddress = 0;
+    for (y = 0; y < lastBlockY; y += 2) {
+        for (x = 0; x < lastBlockX; x += 2) {
+            slicePos = (mbAddress % blocksPerSlice);
+
+            if ( (slicePos == 0) && (mbAddress != 0) ) {
+                if (specificsOn) {
+                    /* Make sure no slice Qscale change */
+                    newQScale = 
+                        SpecLookup(current->id, 1, mbAddress/blocksPerSlice,
+                                   &info /*junk*/, QScale);
+                    if (newQScale != -1) QScale = newQScale;
+                }
+
+                Mhead_GenSliceEnder(bb);
+                Mhead_GenSliceHeader(bb, 1+(y>>1), QScale, NULL, 0);
+
+                /* reset everything */
+                oldMotion.x = oldMotion.y = 0;
+                y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
+
+                mbAddrInc = 1+(x>>1);
+            }
+        
+            /*  Determine if new Qscale needed for Rate Control purposes  */
+            if (bitstreamMode == FIXED_RATE) {
+                rc_blockStart =  bb->cumulativeBits;
+                newQScale = needQScaleChange(qscaleP,
+                                             current->y_blocks[y][x],
+                                             current->y_blocks[y][x+1],
+                                             current->y_blocks[y+1][x],
+                                             current->y_blocks[y+1][x+1]);
+                if (newQScale > 0) {
+                    QScale = newQScale;
+                }
+            }
+        
+            /* Check for Qscale change */
+            if (specificsOn) {
+                newQScale = 
+                    SpecLookup(current->id, 2, mbAddress, &info, QScale);
+                if (newQScale != -1) {
+                    QScale = newQScale;
+                }
+            }
+
+            if (! dct_data[y][x].useMotion) {
+                GEN_I_BLOCK(P_FRAME, current, bb, mbAddrInc, QScale);
+                mbAddrInc = 1;
+
+                numIBits += (bb->cumulativeBits-totalBits);
+                totalBits = bb->cumulativeBits;
+
+                /* reset because intra-coded */
+                oldMotion.x = oldMotion.y = 0;
+
+                if ( decodeRefFrames ) {
+                    /* need to decode block we just encoded */
+                    Mpost_UnQuantZigBlock(fb[0], dec[0], QScale, TRUE);
+                    Mpost_UnQuantZigBlock(fb[1], dec[1], QScale, TRUE);
+                    Mpost_UnQuantZigBlock(fb[2], dec[2], QScale, TRUE);
+                    Mpost_UnQuantZigBlock(fb[3], dec[3], QScale, TRUE);
+                    Mpost_UnQuantZigBlock(fb[4], dec[4], QScale, TRUE);
+                    Mpost_UnQuantZigBlock(fb[5], dec[5], QScale, TRUE);
+
+                    /* now, reverse the DCT transform */
+                    for ( index = 0; index < 6; index++ ) {
+                        mpeg_jrevdct((int16 *)dec[index]);
+                    }
+
+                    /* now, unblockify */
+                    BlockToData(current->decoded_y, dec[0], y, x);
+                    BlockToData(current->decoded_y, dec[1], y, x+1);
+                    BlockToData(current->decoded_y, dec[2], y+1, x);
+                    BlockToData(current->decoded_y, dec[3], y+1, x+1);
+                    BlockToData(current->decoded_cb, dec[4], y>>1, x>>1);
+                    BlockToData(current->decoded_cr, dec[5], y>>1, x>>1);
+                }
+            } else {
+                int fCode = fCodeP;
+
+                /* reset because non-intra-coded */
+                y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
+
+                pattern = dct_data[y][x].pattern;
+                motion.x = dct_data[y][x].fmotionX;
+                motion.y = dct_data[y][x].fmotionY;
+
+#ifdef BLEAH
+                ComputeAndPrintPframeMAD(currentBlock, prev, y, x, motion, 
+                                         mbAddress);
+#endif
+
+                if ( pixelFullSearch ) { /* should be even */
+                    motion.y /= 2;
+                    motion.x /= 2;
+                }
+
+                /* transform the motion vector into the appropriate values */
+                offsetX = motion.x - oldMotion.x;
+                offsetY = motion.y - oldMotion.y;
+                /*  if ((offsetX+(8*x)) >= (Fsize_x-8)) log(10.0); */
+                encodeMotionVector(offsetX, offsetY, &motionQuot, &motionRem,
+                                   FORW_F, fCode);
+
+#ifdef BLEAH
+                if ( (motion.x != 0) || (motion.y != 0) ) {
+                    fprintf(stdout, "FRAME (y, x)  %d, %d (block %d)\n", 
+                            y, x, mbAddress);
+                    fprintf(stdout, "motion.x = %d, motion.y = %d\n", 
+                            motion.x, motion.y);
+                    fprintf(stdout, 
+                            "    mxq, mxr = %d, %d    myq, myr = %d, %d\n",
+                            motionQuot.x, motionRem.x,
+                            motionQuot.y, motionRem.y);
+                }
+#endif
+
+                oldMotion = motion;
+
+                if ( pixelFullSearch ) { /* reset for use with PMotionSearch */
+                    motion.y *= 2;
+                    motion.x *= 2;
+                }
+            calc_blocks:
+                /* create flat blocks and update pattern if necessary */
+                /* Note DoQuant references QScale, overflowChange,
+                   overflowValue, pattern, and the calc_blocks label */
+                DoQuant(0x20, dct[y][x], fba[0]);
+                DoQuant(0x10, dct[y][x+1], fba[1]);
+                DoQuant(0x08, dct[y+1][x], fba[2]);
+                DoQuant(0x04, dct[y+1][x+1], fba[3]);
+                DoQuant(0x02, dctb[y/2][x/2], fba[4]);
+                DoQuant(0x01, dctr[y/2][x/2], fba[5]);
+
+                if ( decodeRefFrames) {
+                    for ( index = 0; index < 6; index++ ) {
+                        if ( pattern & (1 << (5-index))) {
+                            Mpost_UnQuantZigBlock(fba[index], dec[index], 
+                                                  QScale, FALSE);
+                            mpeg_jrevdct((int16 *)dec[index]);
+                        } else {
+                            memset((char *)dec[index], 0, sizeof(Block));
+                        }
+                    }
+
+                    /* now add the motion block */
+                    AddMotionBlock(dec[0], prev->decoded_y, y, x, motion);
+                    AddMotionBlock(dec[1], prev->decoded_y, y, x+1, motion);
+                    AddMotionBlock(dec[2], prev->decoded_y, y+1, x, motion);
+                    AddMotionBlock(dec[3], prev->decoded_y, y+1, x+1, motion);
+                    AddMotionBlock(dec[4], prev->decoded_cb, y/2, x/2,
+                                   halfVector(motion));
+                    AddMotionBlock(dec[5], prev->decoded_cr, y/2, x/2, 
+                                   halfVector(motion));
+
+                    /* now, unblockify */
+                    BlockToData(current->decoded_y, dec[0], y, x);
+                    BlockToData(current->decoded_y, dec[1], y, x+1);
+                    BlockToData(current->decoded_y, dec[2], y+1, x);
+                    BlockToData(current->decoded_y, dec[3], y+1, x+1);
+                    BlockToData(current->decoded_cb, dec[4], y/2, x/2);
+                    BlockToData(current->decoded_cr, dec[5], y/2, x/2);
+                } 
+
+                if ((motion.x == 0) && (motion.y == 0)) {
+                    if ( pattern == 0 ) {
+                        /* can only skip if:
+                         *     1)  not the last block in frame
+                         *     2)  not the last block in slice
+                         *     3)  not the first block in slice
+                         */
+
+                        if ( ((y < lastY) || (x < lastX)) &&
+                             (slicePos+1 != blocksPerSlice) &&
+                             (slicePos != 0) ) {
+                            mbAddrInc++;    /* skipped macroblock */
+                            numSkipped++;
+                            numPBlocks--;
+                        } else {        /* first/last macroblock */
+                            Mhead_GenMBHeader(bb, 2 /* pict_code_type */, 
+                                              mbAddrInc /* addr_incr */,
+                                              QScale /* q_scale */,
+                                              fCode /* forw_f_code */, 
+                                              1 /* back_f_code */,
+                                              motionRem.x /* horiz_forw_r */, 
+                                              motionRem.y /* vert_forw_r */,
+                                              0 /* horiz_back_r */, 
+                                              0 /* vert_back_r */,
+                                              1 /* motion_forw */, 
+                                              motionQuot.x /* m_horiz_forw */,
+                                              motionQuot.y /* m_vert_forw */, 
+                                              0 /* motion_back */,
+                                              0 /* m_horiz_back */, 
+                                              0 /* m_vert_back */,
+                                              0 /* mb_pattern */, 
+                                              0 /* mb_intra */);
+                            mbAddrInc = 1;
+                        }
+                    } else {
+                        DBG_PRINT(("MB Header(%d,%d)\n", x, y));
+                        Mhead_GenMBHeader(bb, 2 /* pict_code_type */, 
+                                          mbAddrInc /* addr_incr */,
+                                          QScale /* q_scale */,
+                                          fCode /* forw_f_code */, 
+                                          1 /* back_f_code */,
+                                          0 /* horiz_forw_r */, 
+                                          0 /* vert_forw_r */,
+                                          0 /* horiz_back_r */, 
+                                          0 /* vert_back_r */,
+                                          0 /* motion_forw */, 
+                                          0 /* m_horiz_forw */,
+                                          0 /* m_vert_forw */, 
+                                          0 /* motion_back */,
+                                          0 /* m_horiz_back */, 
+                                          0 /* m_vert_back */,
+                                          pattern /* mb_pattern */, 
+                                          0 /* mb_intra */);
+                        mbAddrInc = 1;
+                    }
+                } else {
+                    /*      DBG_PRINT(("MB Header(%d,%d)\n", x, y));  */
+          
+                    Mhead_GenMBHeader(bb, 2 /* pict_code_type */, 
+                                      mbAddrInc /* addr_incr */,
+                                      QScale /* q_scale */,
+                                      fCode /* forw_f_code */, 
+                                      1 /* back_f_code */,
+                                      motionRem.x /* horiz_forw_r */, 
+                                      motionRem.y /* vert_forw_r */,
+                                      0 /* horiz_back_r */, 
+                                      0 /* vert_back_r */,
+                                      1 /* motion_forw */, 
+                                      motionQuot.x /* m_horiz_forw */,
+                                      motionQuot.y /* m_vert_forw */, 
+                                      0 /* motion_back */,
+                                      0 /* m_horiz_back */, 
+                                      0 /* m_vert_back */,
+                                      pattern /* mb_pattern */, 
+                                      0 /* mb_intra */);
+                    mbAddrInc = 1;
+                }
+
+                /* now output the difference */
+                {
+                    unsigned int x;
+                    for (x = 0; x < 6; ++x) {
+                        if (GET_ITH_BIT(pattern, 5-x))
+                            Mpost_RLEHuffPBlock(fba[x], bb);
+                    }
+                }
+                numPBits += (bb->cumulativeBits-totalBits);
+                totalBits = bb->cumulativeBits;
+            }
+
+            if (overflowChange) {
+                /* undo an overflow-caused Qscale change */
+                overflowChange = FALSE;
+                QScale -= overflowValue;
+                overflowValue = 0;
+            }
+
+            mbAddress++;
+            /*   Rate Control  */
+            if (bitstreamMode == FIXED_RATE) {
+                incMacroBlockBits( bb->cumulativeBits- rc_blockStart);
+                rc_blockStart = bb->cumulativeBits;
+                MB_RateOut(TYPE_PFRAME);
+            }
+        }
+    }
+
+    if ( printSNR ) {
+        BlockComputeSNR(current,snr,psnr);
+        totalSNR += snr[0];
+        totalPSNR += psnr[0];
+    }
+
+#ifdef BLEAHBLEAH
+    {
+        FILE *filePtr;
+
+        filePtr = fopen("PFRAME.yuv", "wb");
+
+        for ( y = 0; y < Fsize_y; y++ )
+        {
+            for ( x = 0; x < Fsize_x; x++ )
+                fprintf(filePtr, "%d ", current->decoded_y[y][x]);
+            fprintf(filePtr, "\n");
+        }
+
+        fclose(filePtr);
+    }
+#endif
+
+    Mhead_GenSliceEnder(bb);
+    /*   Rate Control */
+    if (bitstreamMode == FIXED_RATE) {
+        updateRateControl(TYPE_PFRAME);
+    }
+
+    /* UPDATE STATISTICS */
+    endTime = time_elapsed();
+    totalTime += (endTime-startTime);
+
+    if ( showBitRatePerFrame ) {
+        /* ASSUMES 30 FRAMES PER SECOND */
+        fprintf(bitRateFile, "%5d\t%8d\n", current->id,
+                30*(bb->cumulativeBits-totalFrameBits));
+    }
+
+    if ( frameSummary && (! realQuiet) ) {
+        fprintf(stdout, "FRAME %d (P):  I BLOCKS:  %d;  "
+                "P BLOCKS:  %d   SKIPPED:  %d  (%ld seconds)\n",
+                current->id, numIBlocks, numPBlocks, numSkipped, 
+                (long)(endTime-startTime)/TIME_RATE);
+        if ( printSNR ) {
+            fprintf(stdout, "FRAME %d:  SNR:  %.1f\t%.1f\t%.1f\t"
+                    "PSNR:  %.1f\t%.1f\t%.1f\n",
+                    current->id, snr[0], snr[1], snr[2],
+                    psnr[0], psnr[1], psnr[2]);
+        }
+    }
+
+    numFrameBits += (bb->cumulativeBits-totalFrameBits);
+    numPIBlocks += numIBlocks;
+    numPPBlocks += numPBlocks;
+    numPSkipped += numSkipped;
+    numPIBits += numIBits;
+    numPPBits += numPBits;
+}
+
+
+/*===========================================================================*
+ *
+ * ResetPFrameStats
+ *
+ *  reset the P-frame statistics
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+  ResetPFrameStats()
+{
+  numPIBlocks = 0;
+  numPPBlocks = 0;
+  numPSkipped = 0;
+  numPIBits = 0;
+  numPPBits = 0;
+  numFrames = 0;
+  numFrameBits = 0;
+  totalTime = 0;
+}
+
+
+/*===========================================================================*
+ *
+ * SetPQScale
+ *
+ *  set the P-frame Q-scale
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    qscaleP
+ *
+ *===========================================================================*/
+void
+  SetPQScale(qP)
+int qP;
+{
+  qscaleP = qP;
+}
+
+
+/*===========================================================================*
+ *
+ * GetPQScale
+ *
+ *  return the P-frame Q-scale
+ *
+ * RETURNS: the P-frame Q-scale
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+int
+  GetPQScale()
+{
+  return qscaleP;
+}
+
+
+float
+PFrameTotalTime(void) {
+    return (float)totalTime/(float)TIME_RATE;
+}
+
+
+
+void
+ShowPFrameSummary(unsigned int const inputFrameBits, 
+                  unsigned int const totalBits, 
+                  FILE *       const fpointer) {
+
+    if (numFrames > 0) {
+
+        fprintf(fpointer, "-------------------------\n");
+        fprintf(fpointer, "*****P FRAME SUMMARY*****\n");
+        fprintf(fpointer, "-------------------------\n");
+
+        if ( numPIBlocks != 0 ) {
+            fprintf(fpointer, "  I Blocks:  %5d     (%6d bits)     (%5d bpb)\n",
+                    numPIBlocks, numPIBits, numPIBits/numPIBlocks);
+        } else {
+            fprintf(fpointer, "  I Blocks:  %5d\n", 0);
+        }
+
+        if ( numPPBlocks != 0 ) {
+            fprintf(fpointer, "  P Blocks:  %5d     (%6d bits)     (%5d bpb)\n",
+                    numPPBlocks, numPPBits, numPPBits/numPPBlocks);
+        } else {
+            fprintf(fpointer, "  P Blocks:  %5d\n", 0);
+        }
+
+        fprintf(fpointer, "  Skipped:   %5d\n", numPSkipped);
+
+        fprintf(fpointer, "  Frames:    %5d     (%6d bits)     (%5d bpf)     (%2.1f%% of total)\n",
+                numFrames, numFrameBits, numFrameBits/numFrames,
+                100.0*(float)numFrameBits/(float)totalBits);
+        fprintf(fpointer, "  Compression:  %3d:1     (%9.4f bpp)\n",
+                numFrames*inputFrameBits/numFrameBits,
+                24.0*(float)numFrameBits/(float)(numFrames*inputFrameBits));
+        if ( printSNR )
+            fprintf(fpointer, "  Avg Y SNR/PSNR:  %.1f     %.1f\n",
+                    totalSNR/(float)numFrames, totalPSNR/(float)numFrames);
+        if ( totalTime == 0 ) {
+            fprintf(fpointer, "  Seconds:  NONE\n");
+        } else {
+            fprintf(fpointer, "  Seconds:  %9ld     (%9.4f fps)  (%9ld pps)  (%9ld mps)\n",
+                    (long)(totalTime/TIME_RATE),
+                    (float)((float)(TIME_RATE*numFrames)/(float)totalTime),
+                    (long)((float)TIME_RATE*(float)numFrames*(float)inputFrameBits/(24.0*(float)totalTime)),
+                    (long)((float)TIME_RATE*(float)numFrames*(float)inputFrameBits/(256.0*24.0*(float)totalTime)));
+        }
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ * EstimateSecondsPerPFrame
+ *
+ *  compute an estimate of the number of seconds required per P-frame
+ *
+ * RETURNS: the estimate, in seconds
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+float
+  EstimateSecondsPerPFrame()
+{
+  if ( numFrames == 0 ) {
+    return 10.0;
+  } else {
+    return (float)totalTime/((float)TIME_RATE*(float)numFrames);
+  }
+}
+
+
+/*===========================================================================*
+ *
+ * ComputeHalfPixelData
+ *
+ *  compute all half-pixel data required for half-pixel motion vector
+ *  search (luminance only)
+ *
+ * RETURNS: frame->halfX, ->halfY, and ->halfBoth modified
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+  ComputeHalfPixelData(frame)
+MpegFrame *frame;
+{
+  register int x, y;
+
+  /* we add 1 before dividing by 2 because .5 is supposed to be rounded up
+   * (see MPEG-1, page D-31)
+   */
+
+  if ( frame->halfX == NULL ) { /* need to allocate memory */
+    Frame_AllocHalf(frame);
+  }
+
+  /* compute halfX */
+  for ( y = 0; y < Fsize_y; y++ ) {
+    for ( x = 0; x < Fsize_x-1; x++ ) {
+      frame->halfX[y][x] = (frame->ref_y[y][x]+
+                frame->ref_y[y][x+1]+1)>>1;
+    }
+  }
+
+  /* compute halfY */
+  for ( y = 0; y < Fsize_y-1; y++ ) {
+    for ( x = 0; x < Fsize_x; x++ ) {
+      frame->halfY[y][x] = (frame->ref_y[y][x]+
+                frame->ref_y[y+1][x]+1)>>1;
+    }
+  }
+
+  /* compute halfBoth */
+  for ( y = 0; y < Fsize_y-1; y++ ) {
+    for ( x = 0; x < Fsize_x-1; x++ ) {
+      frame->halfBoth[y][x] = (frame->ref_y[y][x]+
+                   frame->ref_y[y][x+1]+
+                   frame->ref_y[y+1][x]+
+                   frame->ref_y[y+1][x+1]+2)>>2;
+    }
+  }
+
+  frame->halfComputed = TRUE;
+}
+
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
diff --git a/converter/ppm/ppmtompeg/postdct.c b/converter/ppm/ppmtompeg/postdct.c
new file mode 100644
index 00000000..56a23de9
--- /dev/null
+++ b/converter/ppm/ppmtompeg/postdct.c
@@ -0,0 +1,626 @@
+/*===========================================================================*
+ * postdct.c								     *
+ *									     *
+ *	Procedures concerned with MPEG post-DCT processing:		     *
+ *	    quantization and RLE Huffman encoding			     *
+ *									     *
+ * EXPORTED PROCEDURES:							     *
+ *	Mpost_QuantZigBlock						     *
+ *	Mpost_RLEHuffIBlock						     *
+ *	Mpost_RLEHuffPBlock						     *
+ *	Mpost_UnQuantZigBlock						     *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*
+ *  $Header: /n/picasso/project/mm/mpeg/mpeg_dist/mpeg_encode/RCS/postdct.c,v 1.12 1995/06/21 18:26:39 smoot Exp $
+ *  $Log: postdct.c,v $
+ * Revision 1.12  1995/06/21  18:26:39  smoot
+ * added length estimator for P-blocks
+ *
+ * Revision 1.11  1995/04/23  23:22:59  eyhung
+ * nothing changed
+ *
+ * Revision 1.10  1995/04/14  23:10:46  smoot
+ * Added overflow detection to MPOST_DCT so it will adjust Qscales (above)
+ *
+ * Revision 1.9  1995/02/15  23:15:32  smoot
+ * killed useless asserts
+ *
+ * Revision 1.8  1995/02/01  21:48:41  smoot
+ * assure out is set properly, short circuit 0 revquant
+ *
+ * Revision 1.7  1995/01/30  19:56:37  smoot
+ * Killed a <0 shift
+ *
+ * Revision 1.6  1995/01/25  23:07:33  smoot
+ * Better DBG_PRINTs, multiply/divide instead of shifts
+ *
+ * Revision 1.5  1995/01/19  23:09:10  eyhung
+ * Changed copyrights
+ *
+ * Revision 1.4  1995/01/16  08:17:08  eyhung
+ * added realQuiet
+ *
+ * Revision 1.3  1994/11/12  02:11:58  keving
+ * nothing
+ *
+ * Revision 1.2  1994/03/15  00:27:11  keving
+ * nothing
+ *
+ * Revision 1.2  1994/03/15  00:27:11  keving
+ * nothing
+ *
+ * Revision 1.1  1993/12/22  19:19:01  keving
+ * nothing
+ *
+ * Revision 1.11  1993/07/22  22:23:43  keving
+ * nothing
+ *
+ * Revision 1.10  1993/06/30  20:06:09  keving
+ * nothing
+ *
+ * Revision 1.9  1993/06/03  21:08:08  keving
+ * nothing
+ *
+ * Revision 1.8  1993/02/24  18:57:19  keving
+ * nothing
+ *
+ * Revision 1.7  1993/02/23  22:58:36  keving
+ * nothing
+ *
+ * Revision 1.6  1993/02/23  22:54:56  keving
+ * nothing
+ *
+ * Revision 1.5  1993/02/17  23:18:20  dwallach
+ * checkin prior to keving's joining the project
+ *
+ * Revision 1.4  1993/01/18  10:20:02  dwallach
+ * *** empty log message ***
+ *
+ * Revision 1.3  1993/01/18  10:17:29  dwallach
+ * RCS headers installed, code indented uniformly
+ *
+ * Revision 1.3  1993/01/18  10:17:29  dwallach
+ * RCS headers installed, code indented uniformly
+ *
+ */
+
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include <assert.h>
+#include "all.h"
+#include "mtypes.h"
+#include "bitio.h"
+#include "huff.h"
+#include "postdct.h"
+#include "opts.h"
+
+/*==================*
+ * STATIC VARIABLES *
+ *==================*/
+
+/* ZAG[i] is the natural-order position of the i'th element of zigzag order. */
+int ZAG[] = {
+    0, 1, 8, 16, 9, 2, 3, 10,
+    17, 24, 32, 25, 18, 11, 4, 5,
+    12, 19, 26, 33, 40, 48, 41, 34,
+    27, 20, 13, 6, 7, 14, 21, 28,
+    35, 42, 49, 56, 57, 50, 43, 36,
+    29, 22, 15, 23, 30, 37, 44, 51,
+    58, 59, 52, 45, 38, 31, 39, 46,
+    53, 60, 61, 54, 47, 55, 62, 63
+};
+
+/*
+ * possible optimization: reorder the qtable in the correct zigzag order, to
+ * reduce the number of necessary lookups
+ *
+ * this table comes from the MPEG draft, p. D-16, Fig. 2-D.15.
+ */
+int32 qtable[] = {
+    8, 16, 19, 22, 26, 27, 29, 34,
+    16, 16, 22, 24, 27, 29, 34, 37,
+    19, 22, 26, 27, 29, 34, 34, 38,
+    22, 22, 26, 27, 29, 34, 37, 40,
+    22, 26, 27, 29, 32, 35, 40, 48,
+    26, 27, 29, 32, 35, 40, 48, 58,
+    26, 27, 29, 34, 38, 46, 56, 69,
+    27, 29, 35, 38, 46, 56, 69, 83
+};
+
+int32 niqtable[] = {
+     16, 16, 16, 16, 16, 16, 16, 16,
+     16, 16, 16, 16, 16, 16, 16, 16,
+     16, 16, 16, 16, 16, 16, 16, 16,
+     16, 16, 16, 16, 16, 16, 16, 16,
+     16, 16, 16, 16, 16, 16, 16, 16,
+     16, 16, 16, 16, 16, 16, 16, 16,
+     16, 16, 16, 16, 16, 16, 16, 16,
+     16, 16, 16, 16, 16, 16, 16, 16
+};
+
+int32	*customQtable = NULL;
+int32	*customNIQtable = NULL;
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+
+extern boolean realQuiet;
+
+/*=====================*
+ * EXPORTED PROCEDURES *
+ *=====================*/
+
+/*===========================================================================*
+ *
+ * Mpost_UnQuantZigBlock
+ *
+ *	unquantize and zig-zag (decode) a single block
+ *	see section 2.4.4.1 of MPEG standard
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+Mpost_UnQuantZigBlock(in, out, qscale, iblock)
+    FlatBlock in;
+    Block out;
+    int qscale;
+    boolean iblock;
+{
+    register int index;
+    int	    start;
+    int	    position;
+    register int	    qentry;
+    int	    level, coeff;
+    
+    if ( iblock ) {
+	/* qtable[0] must be 8 */
+	out[0][0] = (int16)(in[0] * 8);
+
+	/* don't need to do anything fancy here, because we saved orig
+	    value, not encoded dc value */
+	start = 1;
+    } else {
+	start = 0;
+    }
+
+    for ( index = start;  index < DCTSIZE_SQ;  index++ ) {
+	position = ZAG[index];
+	level = in[index];
+
+	if (level == 0) {
+	  ((int16 *)out)[position] = 0;
+	  continue;
+	}
+
+
+	if ( iblock ) {
+	    qentry = qtable[position] * qscale;
+	    coeff = (level*qentry)/8;
+	    if ( (coeff & 1) == 0 ) {
+		if ( coeff < 0 ) {
+		    coeff++;
+		} else if ( coeff > 0 ) {
+		    coeff--;
+		}
+	    }
+	} else {
+	    qentry = niqtable[position] * qscale;
+	    if ( level == 0 ) {
+		coeff = 0;
+	    } else if ( level < 0 ) {
+		coeff = (((2*level)-1)*qentry) / 16;
+		if ( (coeff & 1) == 0 ) {
+		    coeff++;
+		}
+	    } else {
+		coeff = (((2*level)+1)*qentry) >> 4;
+		if ( (coeff & 1) == 0 ) {
+		    coeff--;
+		}
+	    }
+
+	    if ( coeff > 2047 ) {
+		coeff = 2047;
+	    } else if ( coeff < -2048 ) {
+		coeff = -2048;
+	    }
+        }
+
+	((int16 *)out)[position] = coeff;
+    }
+}
+
+
+/*===========================================================================*
+ *
+ * Mpost_QuantZigBlock
+ *
+ *	quantize and zigzags a block
+ *
+ * RETURNS:	MPOST_OVERFLOW if a generated value is outside |255|
+ *              MPOST_ZERO     if all coeffs are zero
+ *              MPOST_NON_ZERO otherwisw
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+int
+Mpost_QuantZigBlock(in, out, qscale, iblock)
+    Block in;
+    FlatBlock out;
+    register int qscale;
+    int iblock;
+{
+  register int i;
+  register int16 temp;
+  register int qentry;
+  register int position;
+  boolean nonZero = FALSE;
+  boolean overflow = FALSE;
+  
+  DBG_PRINT(("Mpost_QuantZigBlock...\n"));
+  if (iblock) {
+    /*
+     * the DC coefficient is handled specially -- it's not
+     * sensitive to qscale, but everything else is
+     */
+    temp = ((int16 *) in)[ZAG[0]];
+    qentry = qtable[ZAG[0]];
+    
+    if (temp < 0) {
+      temp = -temp;
+      temp += (qentry >> 1);
+      temp /= qentry;
+      temp = -temp;
+    } else {
+      temp += (qentry >> 1);
+      temp /= qentry;
+    }
+    if ( temp != 0 ) {
+      nonZero = TRUE;
+    }
+    out[0] = temp;
+    
+    for (i = 1; i < DCTSIZE_SQ; i++) {
+      position = ZAG[i];
+      temp = ((int16 *) in)[position];
+      qentry = qtable[position] * qscale;
+      
+      /* see 1993 MPEG doc, section D.6.3.4 */
+      if (temp < 0) {
+	temp = -temp;
+	temp = (temp << 3);	/* temp > 0 */
+	temp += (qentry >> 1);
+	temp /= qentry;
+	temp = -temp;
+      } else {
+	temp = (temp << 3);	/* temp > 0 */
+	temp += (qentry >> 1);
+	temp /= qentry;
+      }
+      
+      if ( temp != 0 ) {
+	nonZero = TRUE;
+	out[i] = temp;
+	if (temp < -255) {
+	  temp = -255;
+	  overflow = TRUE;
+	} else if (temp > 255) {
+	  temp = 255;
+	  overflow = TRUE;
+	}
+      } else out[i]=0;
+    }
+  } else {
+    for (i = 0; i < DCTSIZE_SQ; i++) {
+      position = ZAG[i];
+      temp = ((int16 *) in)[position];
+      
+      /* multiply by non-intra qtable */
+      qentry = qscale * niqtable[position];
+      
+      /* see 1993 MPEG doc, D.6.4.5 */
+      temp *= 8;
+      temp /= qentry;	    /* truncation toward 0 -- correct */
+      
+      if ( temp != 0 ) {
+	nonZero = TRUE;
+	out[i] = temp;
+	if (temp < -255) {
+	  temp = -255;
+	  overflow = TRUE;
+	} else if (temp > 255) {
+	  temp = 255;
+	  overflow = TRUE;
+	}
+	
+      } else out[i]=0;
+    }
+  }
+
+ if (overflow) return MPOST_OVERFLOW;
+ if (nonZero)  return MPOST_NON_ZERO;
+ return MPOST_ZERO;
+}
+
+
+
+/*===========================================================================*
+ *
+ * Mpost_RLEHuffIBlock
+ *
+ *	generate the huffman bits from an I-block
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+Mpost_RLEHuffIBlock(in, out)
+    FlatBlock in;
+    BitBucket *out;
+{
+    register int i;
+    register int nzeros = 0;
+    register int16 cur;
+    register int16 acur;
+    register uint32 code;
+    register int nbits;
+
+    /*
+     * yes, Virginia, we start at 1.  The DC coefficient is handled
+     * specially, elsewhere.  Not here.
+     */
+    for (i = 1; i < DCTSIZE_SQ; i++) {
+	cur = in[i];
+	acur = ABS(cur);
+	if (cur) {
+	    if ( (nzeros < HUFF_MAXRUN) && (acur < huff_maxlevel[nzeros])) {
+	        /*
+		 * encode using the Huffman tables
+		 */
+
+		DBG_PRINT(("rle_huff %02d.%02d: Run %02d, Level %4d\n", i,  ZAG[i], nzeros, cur));
+		code = (huff_table[nzeros])[acur];
+		nbits = (huff_bits[nzeros])[acur];
+
+		if (cur < 0) {
+		    code |= 1;	/* the sign bit */
+		}
+		Bitio_Write(out, code, nbits);
+	    } else {
+		/*
+		 * encode using the escape code
+		 */
+		DBG_PRINT(("Escape\n"));
+		Bitio_Write(out, 0x1, 6);	/* ESCAPE */
+		DBG_PRINT(("Run Length\n"));
+		Bitio_Write(out, nzeros, 6);	/* Run-Length */
+
+		/*
+	         * this shouldn't happen, but the other
+	         * choice is to bomb out and dump core...
+		 * Hmmm, seems to happen with small Qtable entries (1) -srs
+	         */
+		if (cur < -255) {
+		    cur = -255;
+		} else if (cur > 255) {
+		    cur = 255;
+		}
+
+		DBG_PRINT(("Level\n"));
+		if (acur < 128) {
+		    Bitio_Write(out, cur, 8);
+		} else {
+		    if (cur < 0) {
+			Bitio_Write(out, 0x8001 + cur + 255, 16);
+		    } else {
+			Bitio_Write(out, cur, 16);
+		    }
+		}
+	    }
+	    nzeros = 0;
+	} else {
+	    nzeros++;
+	}
+    }
+    DBG_PRINT(("End of block\n"));
+    Bitio_Write(out, 0x2, 2);	/* end of block marker */
+}
+
+
+/*===========================================================================*
+ *
+ * Mpost_RLEHuffPBlock
+ *
+ *	generate the huffman bits from an P-block
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+Mpost_RLEHuffPBlock(in, out)
+    FlatBlock in;
+    BitBucket *out;
+{
+    register int i;
+    register int nzeros = 0;
+    register int16 cur;
+    register int16 acur;
+    register uint32 code;
+    register int nbits;
+    boolean first_dct = TRUE;
+
+    /*
+     * yes, Virginia, we start at 0.
+     */
+    for (i = 0; i < DCTSIZE_SQ; i++) {
+	cur = in[i];
+	acur = ABS(cur);
+	if (cur) {
+	    if ((nzeros < HUFF_MAXRUN) && (acur < huff_maxlevel[nzeros])) {
+	        /*
+		 * encode using the Huffman tables
+		 */
+
+		DBG_PRINT(("rle_huff %02d.%02d: Run %02d, Level %4d\n", i, ZAG[i], nzeros, cur));
+		if ( first_dct && (nzeros == 0) && (acur == 1) ) {
+		    /* actually, only needs = 0x2 */
+		    code = (cur == 1) ? 0x2 : 0x3;
+		    nbits = 2;
+		} else {
+		    code = (huff_table[nzeros])[acur];
+		    nbits = (huff_bits[nzeros])[acur];
+		  }
+
+		assert(nbits);
+
+		if (cur < 0) {
+		    code |= 1;	/* the sign bit */
+		}
+		Bitio_Write(out, code, nbits);
+		first_dct = FALSE;
+	    } else {
+		/*
+		 * encode using the escape code
+		 */
+		DBG_PRINT(("Escape\n"));
+		Bitio_Write(out, 0x1, 6);	/* ESCAPE */
+		DBG_PRINT(("Run Length\n"));
+		Bitio_Write(out, nzeros, 6);	/* Run-Length */
+
+		/*
+	         * this shouldn't happen, but the other
+	         * choice is to bomb out and dump core...
+		 * Hmmm, seems to happen with small Qtable entries (1) -srs
+	         */
+		if (cur < -255) {
+		  cur = -255;
+		} else if (cur > 255) {
+		  cur = 255;
+		}
+
+		DBG_PRINT(("Level\n"));
+		if (acur < 128) {
+		    Bitio_Write(out, cur, 8);
+		} else {
+		    if (cur < 0) {
+			Bitio_Write(out, 0x8001 + cur + 255, 16);
+		    } else {
+			Bitio_Write(out, cur, 16);
+		    }
+		}
+
+		first_dct = FALSE;
+	    }
+	    nzeros = 0;
+	} else {
+	    nzeros++;
+	}
+    }
+
+    /* actually, should REALLY return FALSE and not use this! */
+
+    if ( first_dct ) {	/* have to give a first_dct even if all 0's */
+	fprintf(stderr, "HUFF called with all-zero coefficients\n");
+	fprintf(stderr, "exiting...\n");
+	exit(1);
+    }
+
+    DBG_PRINT(("End of block\n"));
+    Bitio_Write(out, 0x2, 2);	/* end of block marker */
+}
+
+
+/*===========================================================================*
+ *
+ * CalcRLEHuffLength
+ *
+ *	count the huffman bits for an P-block
+ *
+ * RETURNS:	number of bits
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+int
+CalcRLEHuffLength(in)
+    FlatBlock in;
+{
+  register int i;
+  register int nzeros = 0;
+  register int16 cur;
+  register int16 acur;
+  register int nbits;
+  register int countbits=0;
+  boolean first_dct = TRUE;
+  
+  for (i = 0; i < DCTSIZE_SQ; i++) {
+    cur = in[i];
+    acur = ABS(cur);
+    if (cur) {
+      if ((nzeros < HUFF_MAXRUN) && (acur < huff_maxlevel[nzeros])) {
+	/*
+	 * encode using the Huffman tables
+	 */
+
+	if ( first_dct && (nzeros == 0) && (acur == 1) ) {
+	  nbits = 2;
+	} else {
+	  nbits = (huff_bits[nzeros])[acur];
+	}
+	countbits += nbits;
+	first_dct = FALSE;
+      } else {
+	countbits += 12;	/* ESCAPE + runlength */
+
+	if (acur < 128) {
+	  countbits += 8;
+	} else {
+	  countbits += 16;
+	}
+
+	first_dct = FALSE;
+      }
+      nzeros = 0;
+    } else {
+      nzeros++;
+    }
+  }
+  
+  countbits += 2; /* end of block marker */
+  return countbits;
+}
diff --git a/converter/ppm/ppmtompeg/ppmtompeg.c b/converter/ppm/ppmtompeg/ppmtompeg.c
new file mode 100644
index 00000000..2296e2cb
--- /dev/null
+++ b/converter/ppm/ppmtompeg/ppmtompeg.c
@@ -0,0 +1,722 @@
+/*===========================================================================*
+ * main.c
+ *
+ * Main procedure
+ *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#define _BSD_SOURCE   /* Make sure strdup() is in string.h */
+
+#include <assert.h>
+#include <sys/utsname.h>
+
+#include "all.h"
+#include "mtypes.h"
+#include "mpeg.h"
+#include "motion_search.h"
+#include "prototypes.h"
+#include "param.h"
+#include "parallel.h"
+#include "readframe.h"
+#include "combine.h"
+#include "frames.h"
+#include "jpeg.h"
+#include "specifics.h"
+#include "opts.h"
+#include "frametype.h"
+#include "input.h"
+#include "gethostname.h"
+
+#include "pm_c_util.h"
+#include "ppm.h"
+#include "nstring.h"
+
+#include <time.h>
+
+int main _ANSI_ARGS_((int argc, char **argv));
+
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+
+boolean showBitRatePerFrame;
+boolean frameSummary;
+
+extern time_t IOtime;
+int whichGOP = -1;
+boolean ioServer = FALSE;
+boolean outputServer = FALSE;
+boolean decodeServer = FALSE;
+int quietTime = 0;
+boolean realQuiet = FALSE;
+boolean noFrameSummaryOption = FALSE;
+boolean debugSockets = FALSE;
+boolean debugMachines = FALSE;
+boolean bitRateInfoOption = FALSE;
+boolean computeMVHist = FALSE;
+int     baseFormat;
+extern  boolean specificsOn;
+extern  FrameSpecList *fsl;
+boolean pureDCT=FALSE;
+char    encoder_name[1024];
+const char * hostname;
+
+
+/*================================*
+ * External PROCEDURE prototypes  *
+ *================================*/
+
+void init_idctref _ANSI_ARGS_((void));
+void init_fdct _ANSI_ARGS_((void));
+
+
+struct cmdlineInfo {
+    bool         childProcess;
+    int          function;
+    const char * masterHostname;
+    int          masterPortNumber;
+    unsigned int outputFrames;
+    int          maxMachines;
+    const char * paramFileName;
+    bool         specificFrames;
+    unsigned int frameStart;
+    unsigned int frameEnd;
+};
+
+
+
+static void
+parseArgs(int     const argc,
+          char ** const argv,
+          struct cmdlineInfo * const cmdlineP) {
+
+    int idx;
+
+    if (argc-1 < 1)
+        pm_error("You must specify at least one argument: the parameter "
+                 "file name");
+
+    cmdlineP->function = ENCODE_FRAMES;
+    cmdlineP->childProcess = FALSE;  /* initial assumption */
+    cmdlineP->outputFrames = 0;
+    cmdlineP->maxMachines = MAXINT;
+    cmdlineP->specificFrames = FALSE;
+    
+    /* parse the arguments */
+    idx = 1;
+    while ( idx < argc-1 ) {
+        if ( argv[idx][0] != '-' )
+            pm_error("argument '%s', which must be an option because "
+                     "it is not the last argument, "
+                     "does not start with '-'", argv[idx]);
+
+        if ( strcmp(argv[idx], "-stat") == 0 ) {
+            if ( idx+1 < argc-1 ) {
+                SetStatFileName(argv[idx+1]);
+                idx += 2;
+            } else {
+                pm_error("Invalid -stat option");
+            }
+        } else if ( strcmp(argv[idx], "-gop") == 0 ) {
+            if ((cmdlineP->function != ENCODE_FRAMES) || 
+                (cmdlineP->specificFrames))
+                pm_error("Invalid -gop option");
+            
+            if ( idx+1 < argc-1 ) {
+                whichGOP = atoi(argv[idx+1]);
+                idx += 2;
+            } else {
+                pm_error("Invalid -gop option");
+            }
+        } else if ( strcmp(argv[idx], "-frames") == 0 ) {
+            if ( (cmdlineP->function != ENCODE_FRAMES) || (whichGOP != -1) ) {
+                pm_error("invalid -frames option");
+            }
+
+            if ( idx+2 < argc-1 ) {
+                int const frameStart = atoi(argv[idx+1]);
+                int const frameEnd = atoi(argv[idx+2]);
+
+                if (frameStart > frameEnd)
+                    pm_error("Start frame number %d is greater than end "
+                             "frame number %d", frameStart, frameEnd);
+                if (frameStart < 0)
+                    pm_error("Start frame number %d is less than zero",
+                             frameStart);
+
+                cmdlineP->specificFrames = TRUE;
+                cmdlineP->frameStart = frameStart;
+                cmdlineP->frameEnd   = frameEnd;
+                
+                idx += 3;
+            } else
+                pm_error("-frames needs to be followed by two values");
+        } else if (strcmp(argv[idx], "-combine_gops") == 0) {
+            if ((cmdlineP->function != ENCODE_FRAMES) || (whichGOP != -1) || 
+                (cmdlineP->specificFrames)) {
+                pm_error("Invalid -combine_gops option");
+            }
+
+            cmdlineP->function = COMBINE_GOPS;
+            idx++;
+        } else if (strcmp(argv[idx], "-combine_frames") == 0) {
+            if ((cmdlineP->function != ENCODE_FRAMES) || (whichGOP != -1) ||
+                (cmdlineP->specificFrames))
+                pm_error("Invalid -combine_frames option");
+
+            cmdlineP->function = COMBINE_FRAMES;
+            idx++;
+        } else if ( strcmp(argv[idx], "-child") == 0 ) {
+            if ( idx+7 < argc-1 ) {
+                int combinePortNumber;
+                    /* This used to be important information, when the child
+                       notified the combine server.  Now the master notifies
+                       the combine server after the child notifies the master
+                       it is done.  So this value is unused.
+                    */
+                cmdlineP->masterHostname = argv[idx+1];
+                cmdlineP->masterPortNumber = atoi(argv[idx+2]);
+                ioPortNumber = atoi(argv[idx+3]);
+                combinePortNumber = atoi(argv[idx+4]);
+                decodePortNumber = atoi(argv[idx+5]);
+                machineNumber = atoi(argv[idx+6]);
+                remoteIO = atoi(argv[idx+7]);
+
+                IOhostName = cmdlineP->masterHostname;
+            } else
+                pm_error("Not enough option values for -child option.  "
+                         "Need 7.");
+
+            cmdlineP->childProcess = TRUE;
+            idx += 8;
+        } else if ( strcmp(argv[idx], "-io_server") == 0 ) {
+            if ( idx+2 < argc-1 ) {
+                cmdlineP->masterHostname = argv[idx+1];
+                cmdlineP->masterPortNumber = atoi(argv[idx+2]);
+            } else {
+                pm_error("Invalid -io_server option");
+            }
+
+            ioServer = TRUE;
+            idx += 3;
+        } else if ( strcmp(argv[idx], "-output_server") == 0 ) {
+            if ( idx+3 < argc-1 ) {
+                cmdlineP->masterHostname = argv[idx+1];
+                cmdlineP->masterPortNumber = atoi(argv[idx+2]);
+                cmdlineP->outputFrames = atoi(argv[idx+3]);
+            } else {
+                pm_error("-output_server option requires 3 option values.  "
+                         "You specified %d", argc-1 - idx);
+            }
+
+            outputServer = TRUE;
+            idx += 4;
+        } else if ( strcmp(argv[idx], "-decode_server") == 0 ) {
+            if ( idx+3 < argc-1 ) {
+                cmdlineP->masterHostname = argv[idx+1];
+                cmdlineP->masterPortNumber = atoi(argv[idx+2]);
+                cmdlineP->outputFrames = atoi(argv[idx+3]);
+            } else {
+                pm_error("Invalid -decode_server option");
+            }
+
+            cmdlineP->function = COMBINE_FRAMES;
+            decodeServer = TRUE;
+            idx += 4;
+        } else if ( strcmp(argv[idx], "-nice") == 0 ) {
+            niceProcesses = TRUE;
+            idx++;
+        } else if ( strcmp(argv[idx], "-max_machines") == 0 ) {
+            if ( idx+1 < argc-1 ) {
+                cmdlineP->maxMachines = atoi(argv[idx+1]);
+            } else {
+                pm_error("Invalid -max_machines option");
+            }
+
+            idx += 2;
+        } else if ( strcmp(argv[idx], "-quiet") == 0 ) {
+            if ( idx+1 < argc-1 ) {
+                quietTime = atoi(argv[idx+1]);
+            } else {
+                pm_error("Invalid -quiet option");
+            }
+
+            idx += 2;
+        } else if ( strcmp(argv[idx], "-realquiet") == 0 ) {
+            realQuiet = TRUE;
+            idx++;
+        } else if (( strcmp(argv[idx], "-float_dct") == 0 ) ||
+                   ( strcmp(argv[idx], "-float-dct") == 0 )) {
+            pureDCT = TRUE;
+            init_idctref();
+            init_fdct();
+            idx++;
+        } else if ( strcmp(argv[idx], "-no_frame_summary") == 0 ) {
+            if ( idx < argc-1 ) {
+                noFrameSummaryOption = TRUE;
+            } else {
+                pm_error("Invalid -no_frame_summary option");
+            }
+
+            idx++;
+        } else if ( strcmp(argv[idx], "-snr") == 0 ) {
+            printSNR = TRUE;
+            idx++;
+        } else if ( strcmp(argv[idx], "-mse") == 0 ) {
+            printSNR =  printMSE = TRUE;
+            idx++;
+        } else if ( strcmp(argv[idx], "-debug_sockets") == 0 ) {
+            debugSockets = TRUE;
+            idx++;
+        } else if ( strcmp(argv[idx], "-debug_machines") == 0 ) {
+            debugMachines = TRUE;
+            idx++;
+        } else if ( strcmp(argv[idx], "-bit_rate_info") == 0 ) {
+            if ( idx+1 < argc-1 ) {
+                bitRateInfoOption = TRUE;
+                SetBitRateFileName(argv[idx+1]);
+                idx += 2;
+            } else {
+                pm_error("Invalid -bit_rate_info option");
+            }
+        } else if ( strcmp(argv[idx], "-mv_histogram") == 0 ) {
+            computeMVHist = TRUE;
+            idx++;
+        } else {
+            pm_error("Unrecognized option: '%s'", argv[idx]);
+        }
+    }
+
+    cmdlineP->paramFileName = argv[argc-1];
+}
+
+
+
+static void
+compileTests() {
+
+    /* There was code here (assert() calls) that verified that uint16
+       is 16 bits, etc.  It caused compiler warnings that said, "Of
+       course it is!"  (actually, "statement has no effect").  There
+       isn't enough chance that uint16, etc. are defined incorrectly
+       to warrant those asserts.  2000.05.07
+    */
+
+    if ( (-8 >> 3) != -1 ) {
+        fprintf(stderr, "ERROR:  Right shifts are NOT arithmetic!!!\n");
+        fprintf(stderr, "Change >> to multiplies by powers of 2\n");
+        exit(1);
+    }
+}
+
+
+
+static void
+announceJob(enum frameContext const context,
+            bool              const childProcess,
+            unsigned int      const frameStart,
+            unsigned int      const frameEnd,
+            const char *      const outputFileName) {
+
+    if (!realQuiet) {
+        const char * outputDest;
+        const char * combineDest;
+
+        if (context == CONTEXT_JUSTFRAMES)
+            asprintfN(&outputDest, "to individual frame files");
+        else
+            asprintfN(&outputDest, "to file '%s'", outputFileName);
+
+        if (childProcess)
+            combineDest = strdup("for delivery to combine server");
+        else
+            combineDest = strdup("");
+    
+        pm_message("%s:  ENCODING FRAMES %u-%u to %s %s",
+                   hostname, frameStart, frameEnd, outputDest, combineDest);
+
+        strfree(combineDest);
+        strfree(outputDest);
+    }
+}
+
+
+
+static void
+encodeSomeFrames(struct inputSource * const inputSourceP,
+                 boolean              const childProcess,
+                 enum frameContext    const context, 
+                 unsigned int         const frameStart,
+                 unsigned int         const frameEnd,
+                 int32                const qtable[],
+                 int32                const niqtable[],
+                 FILE *               const ofp,
+                 const char *         const outputFileName,
+                 bool                 const wantVbvUnderflowWarning,
+                 bool                 const wantVbvOverflowWarning,
+                 boolean              const printStats,
+                 unsigned int *       const encodeTimeP) {
+    
+    time_t framesTimeStart, framesTimeEnd;
+    unsigned int inputFrameBits;
+    unsigned int totalBits;
+
+    announceJob(context, childProcess, frameStart, frameEnd, outputFileName);
+
+    time(&framesTimeStart);
+    if (printStats)
+        PrintStartStats(framesTimeStart, context == CONTEXT_JUSTFRAMES,
+                        frameStart, frameEnd, inputSourceP);
+
+    GenMPEGStream(inputSourceP, context, frameStart, frameEnd,
+                  qtable, niqtable, childProcess, ofp, outputFileName, 
+                  wantVbvUnderflowWarning, wantVbvOverflowWarning,
+                  &inputFrameBits, &totalBits);
+
+    time(&framesTimeEnd);
+
+    *encodeTimeP = (unsigned int)(framesTimeEnd - framesTimeStart);
+
+    if (!realQuiet)
+        pm_message("%s:  COMPLETED FRAMES %u-%u (%u seconds)",
+                   hostname, frameStart, frameEnd, *encodeTimeP);
+
+    if (printStats)
+        PrintEndStats(framesTimeStart, framesTimeEnd, 
+                      inputFrameBits, totalBits);
+}
+
+
+
+
+static void
+encodeFrames(struct inputSource * const inputSourceP,
+             boolean              const childProcess,
+             const char *         const masterHostname,
+             int                  const masterPortNumber,
+             int                  const whichGOP,
+             bool                 const specificFrames,
+             unsigned int         const whichFrameStart,
+             unsigned int         const whichFrameEnd,
+             int32                const qtable[],
+             int32                const niqtable[],
+             FILE *               const ofp,
+             const char *         const outputFileName,
+             bool                 const wantVbvUnderflowWarning,
+             bool                 const wantVbvOverflowWarning) {
+/*----------------------------------------------------------------------------
+  Encode the stream.  If 'specificFrames' is true, then encode frames
+  'whichFrameStart' through 'whichFrameEnd' individually.  Otherwise,
+  encode the entire input stream as a complete MPEG stream.
+  
+  'childProcess' means to do it as a child process that is under the
+  supervision of a master process and is possibly doing only part of
+  a larger batch.
+  
+  (If we had proper modularity, we wouldn't care, but parallel operation
+  was glued on to this program after it was complete).
+  
+  One thing we don't do when running as a child process is print
+  statistics; our master will do that for the whole job.
+----------------------------------------------------------------------------*/
+    unsigned int frameStart, frameEnd;
+    enum frameContext context;
+    unsigned int      lastEncodeTime;
+        /* How long it took the encoder to do the last set of frames */
+    boolean           printStats;
+        /* We want the encoder to print start & end stats */
+
+    if (whichGOP != -1) {
+        /* He wants just one particular GOP from the middle of the movie. */
+        ComputeGOPFrames(whichGOP, &frameStart, &frameEnd, 
+                         inputSourceP->numInputFiles);
+        context = CONTEXT_GOP;
+    } else if (specificFrames) {
+        /* He wants some pure frames from the middle of the movie */
+        if (whichFrameStart > whichFrameEnd)
+            pm_error("You specified a starting frame number (%d) that is "
+                     "greater than the ending frame number (%d) "
+                     "you specified.", whichFrameStart, whichFrameEnd);
+        if (whichFrameEnd + 1 > inputSourceP->numInputFiles)
+            pm_error("You specified ending frame number %d, which is "
+                     "beyond the number of input files you supplied (%u)",
+                     whichFrameEnd, inputSourceP->numInputFiles);
+
+        frameStart = whichFrameStart;
+        frameEnd   = whichFrameEnd;
+        context = CONTEXT_JUSTFRAMES;
+    } else {
+        /* He wants the whole movie */
+        frameStart = 0;
+        frameEnd   = inputSourceP->numInputFiles - 1;
+        context = CONTEXT_WHOLESTREAM;
+    }
+    
+    printStats = !childProcess;
+    
+    encodeSomeFrames(inputSourceP, childProcess, context, frameStart, frameEnd,
+                     customQtable, customNIQtable,
+                     ofp, outputFileName, 
+                     wantVbvUnderflowWarning, wantVbvOverflowWarning,
+                     printStats,
+                     &lastEncodeTime);
+
+    if (childProcess) {
+        boolean moreWorkToDo;
+        
+        /* A child is not capable of generating GOP or stream headers */
+        assert(context == CONTEXT_JUSTFRAMES);
+        
+        moreWorkToDo = TRUE;  /* initial assumption */
+        while (moreWorkToDo) {
+            int nextFrameStart, nextFrameEnd;
+
+            NotifyMasterDone(masterHostname, masterPortNumber, machineNumber, 
+                             lastEncodeTime, &moreWorkToDo,
+                             &nextFrameStart, &nextFrameEnd);
+            if (moreWorkToDo)
+                encodeSomeFrames(inputSourceP, childProcess, 
+                                 CONTEXT_JUSTFRAMES, 
+                                 nextFrameStart, nextFrameEnd,
+                                 customQtable, customNIQtable,
+                                 NULL, outputFileName, 
+                                 wantVbvUnderflowWarning, 
+                                 wantVbvOverflowWarning,
+                                 FALSE,
+                                 &lastEncodeTime);
+        }
+        if (!realQuiet)
+            pm_message("%s: Child exiting.  Master has no more work.",
+                       hostname);
+    }
+}
+
+
+
+
+static void
+runMaster(struct inputSource * const inputSourceP,
+          const char *         const paramFileName,
+          const char *         const outputFileName) {
+
+    if (paramFileName[0] != '/' && paramFileName[0] != '~')
+        pm_error("For parallel mode, you must "
+                 "use an absolute path for parameter file.  "
+                 "You specified '%s'", paramFileName);
+    else
+        MasterServer(inputSourceP, paramFileName, outputFileName);
+}
+
+
+
+static void
+getUserFrameFile(void *       const handle,
+                 unsigned int const frameNumber,
+                 FILE **      const ifPP) {
+    
+    struct inputSource * const inputSourceP = (struct inputSource *) handle;
+
+    if (inputSourceP->stdinUsed)
+        pm_error("You cannot combine frames from Standard Input.");
+            /* Because Caller detects end of frames by EOF */
+    
+    if (frameNumber >= inputSourceP->numInputFiles)
+        *ifPP = NULL;
+    else {
+        const char * fileName;
+        const char * inputFileName;
+
+        GetNthInputFileName(inputSourceP, frameNumber, &inputFileName);
+        
+        asprintfN(&fileName, "%s/%s", currentFramePath, inputFileName);
+        
+        *ifPP = fopen(fileName, "rb");
+        if (*ifPP == NULL)
+            pm_error("Unable to open file '%s'.  Errno = %d (%s)",
+                     fileName, errno, strerror(errno));
+        
+        strfree(inputFileName);
+        strfree(fileName);
+    }
+}
+
+
+
+static void
+nullDisposeFile(void *       const handle,
+                unsigned int const frameNumber) {
+
+
+}
+
+
+
+static unsigned int
+framePoolSize(bool const sequentialInput) {
+/*----------------------------------------------------------------------------
+   Return the number of frames that our frame memory pool needs to have.
+
+   'sequentialInput' means we'll be reading from input that comes in frame
+   number order and we can't go back, so we'll have to have a bigger buffer
+   of frames than otherwise.
+-----------------------------------------------------------------------------*/
+    unsigned int numOfFrames;
+
+    numOfFrames = 0;  /* initial value */
+
+    if (sequentialInput) {
+        unsigned int idx;
+        unsigned int bcount;
+
+        for ( idx = 0, bcount = 0; idx < strlen(framePattern); idx++) {
+
+            /* counts the maximum number of B frames between two reference
+             * frames. 
+             */
+            
+            switch( framePattern[idx] ) {
+            case 'b': 
+                bcount++;
+                break;
+            case 'i':
+            case 'p':
+                if (bcount > numOfFrames)
+                    numOfFrames = bcount;
+                bcount = 0;
+                break;
+            }
+            
+            /* add 2 to hold the forward and past reference frames in addition
+             * to the maximum number of B's 
+             */
+        }
+        
+        numOfFrames += 2;
+
+    } else {
+        /* non-interactive, only 3 frames needed */
+        numOfFrames = 3;
+    }
+    return numOfFrames;
+}
+
+
+
+int
+main(int argc, char **argv) {
+    FILE *ofP;
+    time_t  initTimeStart;
+    struct cmdlineInfo cmdline;
+    struct params params;
+
+    ppm_init(&argc, argv);
+
+    strcpy(encoder_name, argv[0]);
+
+    compileTests();
+
+    time(&initTimeStart);
+
+    SetStatFileName("");
+
+    hostname = GetHostName();
+
+    parseArgs(argc, argv, &cmdline);
+
+    ReadParamFile(cmdline.paramFileName, cmdline.function, &params);
+
+    /* Jim Boucher's stuff:
+       if we are using a movie format then break up into frames
+    */
+    if ((!cmdline.childProcess) && (baseFormat == JMOVIE_FILE_TYPE))
+        JM2JPEG(params.inputSourceP);
+
+    if (printSNR || (referenceFrame == DECODED_FRAME))
+        decodeRefFrames = TRUE;
+
+    showBitRatePerFrame = (bitRateInfoOption && !cmdline.childProcess);
+    frameSummary = (!noFrameSummaryOption && !cmdline.childProcess);
+
+    numMachines = min(numMachines, cmdline.maxMachines);
+
+    Tune_Init();
+    Frame_Init(framePoolSize(params.inputSourceP->stdinUsed));
+
+    if (specificsOn) 
+        Specifics_Init();
+
+    ComputeFrameTable(params.inputSourceP->stdinUsed ? 
+                      0 : params.inputSourceP->numInputFiles);
+
+    if (ioServer) {
+        IoServer(params.inputSourceP, cmdline.masterHostname, 
+                 cmdline.masterPortNumber);
+        return 0;
+    } else if (outputServer) {
+        CombineServer(cmdline.outputFrames, 
+                      cmdline.masterHostname, cmdline.masterPortNumber,
+                      outputFileName);
+    } else if (decodeServer) {
+        DecodeServer(cmdline.outputFrames, outputFileName, 
+                     cmdline.masterHostname, cmdline.masterPortNumber);
+    } else {
+        if ((!cmdline.specificFrames) &&
+            ((numMachines == 0) || (cmdline.function != ENCODE_FRAMES)) ) {
+            ofP = fopen(outputFileName, "wb");
+            if (ofP == NULL)
+                pm_error("Could not open output file!");
+        } else
+            ofP = NULL;
+        
+        if (cmdline.function == ENCODE_FRAMES) {
+            if ((numMachines == 0) || (cmdline.specificFrames)) {
+                encodeFrames(params.inputSourceP,
+                             cmdline.childProcess, 
+                             cmdline.masterHostname, cmdline.masterPortNumber,
+                             whichGOP, cmdline.specificFrames,
+                             cmdline.frameStart, cmdline.frameEnd,
+                             customQtable, customNIQtable,
+                             ofP, outputFileName,
+                             params.warnUnderflow, params.warnOverflow);
+                
+            } else
+                runMaster(params.inputSourceP,
+                          cmdline.paramFileName, outputFileName);
+        } else if (cmdline.function == COMBINE_GOPS)
+            GOPsToMPEG(params.inputSourceP, outputFileName, ofP);
+        else if (cmdline.function == COMBINE_FRAMES)
+            FramesToMPEG(ofP, params.inputSourceP,
+                         &getUserFrameFile, &nullDisposeFile);
+    } 
+    Frame_Exit();
+        
+    strfree(hostname);
+
+    return 0;
+}
diff --git a/converter/ppm/ppmtompeg/psearch.c b/converter/ppm/ppmtompeg/psearch.c
new file mode 100644
index 00000000..aea1a29b
--- /dev/null
+++ b/converter/ppm/ppmtompeg/psearch.c
@@ -0,0 +1,989 @@
+/*===========================================================================*
+ * psearch.c                                     
+ *                                       
+ *  Procedures concerned with the P-frame motion search          
+ *                                       
+ *===========================================================================*/
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "all.h"
+#include "mtypes.h"
+#include "frames.h"
+#include "motion_search.h"
+#include "prototypes.h"
+#include "fsize.h"
+#include "param.h"
+
+
+/*==================*
+ * STATIC VARIABLES *
+ *==================*/
+
+/* none */
+
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+
+int **pmvHistogram = NULL;  /* histogram of P-frame motion vectors */
+int **bbmvHistogram = NULL; /* histogram of B-frame bkwd motion vectors */
+int **bfmvHistogram = NULL; /* histogram of B-frame fwd motion vectors */
+int pixelFullSearch;
+int searchRangeP,searchRangeB;
+/* The range, in half pixels in each direction, that we are to search
+       when detecting motion.  Specified by RANGE statement in parameter file.
+    */
+int psearchAlg;
+/* specified by parameter file. */
+
+/*===============================*
+ * INTERNAL PROCEDURE prototypes *
+ *===============================*/
+
+
+/*=====================*
+ * EXPORTED PROCEDURES *
+ *=====================*/
+
+/*===========================================================================*
+ *
+ *  Compute the best P-frame motion vector we can.  If it's better than
+ *  *motionP, update *motionP to it.
+ *
+ * PRECONDITIONS:   The relevant block in 'current' is valid (it has not
+ *          been dct'd).  Thus, the data in 'current' can be
+ *          accesed through y_blocks, cr_blocks, and cb_blocks.
+ *          This is not the case for the blocks in 'prev.'
+ *          Therefore, references into 'prev' should be done
+ *          through the struct items ref_y, ref_cr, ref_cb
+ *
+ * POSTCONDITIONS:  current, prev unchanged.
+ *          Some computation could be saved by requiring
+ *          the dct'd difference to be put into current's block
+ *          elements here, depending on the search technique.
+ *          However, it was decided that it mucks up the code
+ *          organization a little, and the saving in computation
+ *          would be relatively little (if any).
+ *
+ * NOTES:   the search procedure need not check the (0,0) motion vector
+ *      the calling procedure has a preference toward (0,0) and it
+ *      will check it itself
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+void
+PMotionSearch(const LumBlock * const currentBlockP, 
+              MpegFrame *      const prev, 
+              int              const by,
+              int              const bx, 
+              vector *         const motionP) {
+
+    /* CALL SEARCH PROCEDURE */
+
+    switch(psearchAlg) {
+    case PSEARCH_SUBSAMPLE:
+        PSubSampleSearch(currentBlockP, prev, by, bx, motionP, searchRangeP);
+        break;
+    case PSEARCH_EXHAUSTIVE:
+        PLocalSearch(currentBlockP, prev, by, bx, 
+                     motionP, INT_MAX, searchRangeP);
+        break;
+    case PSEARCH_LOGARITHMIC:
+        PLogarithmicSearch(currentBlockP, prev, by, bx, motionP, searchRangeP);
+        break;
+    case PSEARCH_TWOLEVEL:
+        PTwoLevelSearch(currentBlockP, prev, by, bx, 
+                        motionP, INT_MAX, searchRangeP);
+        break;
+    default:
+        pm_error("IMPOSSIBLE PSEARCH ALG:  %d", psearchAlg);
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ * SetPixelSearch
+ *
+ *  set the pixel search type (half or full)
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    pixelFullSearch
+ *
+ *===========================================================================*/
+void
+SetPixelSearch(const char * const searchType) {
+    if ( (strcmp(searchType, "FULL") == 0 ) || 
+         ( strcmp(searchType, "WHOLE") == 0 )) {
+        pixelFullSearch = TRUE;
+    } else if ( strcmp(searchType, "HALF") == 0 ) {
+        pixelFullSearch = FALSE;
+    } else {
+        fprintf(stderr, "ERROR:  Invalid pixel search type:  %s\n",
+                searchType);
+        exit(1);
+    }
+}
+
+
+/*===========================================================================*
+ *
+ * SetPSearchAlg
+ *
+ *  set the P-search algorithm
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    psearchAlg
+ *
+ *===========================================================================*/
+void
+SetPSearchAlg(const char * const alg)
+{
+    if ( strcmp(alg, "EXHAUSTIVE") == 0 ) {
+        psearchAlg = PSEARCH_EXHAUSTIVE;
+    } else if (strcmp(alg, "SUBSAMPLE") == 0 ) {
+        psearchAlg = PSEARCH_SUBSAMPLE;
+    } else if ( strcmp(alg, "LOGARITHMIC") == 0 ) {
+        psearchAlg = PSEARCH_LOGARITHMIC;
+    } else if ( strcmp(alg, "TWOLEVEL") == 0 ) {
+        psearchAlg = PSEARCH_TWOLEVEL;
+    } else {
+        fprintf(stderr, "ERROR:  Invalid psearch algorithm:  %s\n", alg);
+        exit(1);
+    }
+}
+
+
+/*===========================================================================*
+ *
+ * PSearchName
+ *
+ *  returns a string containing the name of the search algorithm
+ *
+ * RETURNS: pointer to the string
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+const char *
+PSearchName(void)
+{
+    const char *retval;
+
+    switch(psearchAlg) {
+    case PSEARCH_EXHAUSTIVE:
+        retval = "EXHAUSTIVE";break;
+    case PSEARCH_SUBSAMPLE:
+        retval = "SUBSAMPLE";break;
+    case PSEARCH_LOGARITHMIC:
+        retval = "LOGARITHMIC";break;
+    case PSEARCH_TWOLEVEL:
+        retval = "TWOLEVEL";break;
+    default:
+        fprintf(stderr, "ERROR:  Illegal PSEARCH ALG:  %d\n", psearchAlg);
+        exit(1);
+        break;
+    }
+    return retval;
+}
+
+
+/*===========================================================================*
+ *
+ * SetSearchRange
+ *
+ *  sets the range of the search to the given number of pixels,
+ *  allocate histogram storage
+ *
+ *===========================================================================*/
+void
+SetSearchRange(int const pixelsP, int const pixelsB) {
+
+    searchRangeP = 2*pixelsP;   /* +/- 'pixels' pixels */
+    searchRangeB = 2*pixelsB;
+
+    if ( computeMVHist ) {
+        int const max_search = max(searchRangeP, searchRangeB);
+
+        int index;
+    
+        pmvHistogram = (int **) malloc((2*searchRangeP+3)*sizeof(int *));
+        bbmvHistogram = (int **) malloc((2*searchRangeB+3)*sizeof(int *));
+        bfmvHistogram = (int **) malloc((2*searchRangeB+3)*sizeof(int *));
+        for ( index = 0; index < 2*max_search+3; index++ ) {
+            pmvHistogram[index] = 
+                (int *) calloc(2*searchRangeP+3, sizeof(int));
+            bbmvHistogram[index] = 
+                (int *) calloc(2*searchRangeB+3, sizeof(int));
+            bfmvHistogram[index] = 
+                (int *) calloc(2*searchRangeB+3, sizeof(int));
+        }
+    }
+}
+
+
+/*===========================================================================*
+ *
+ *              USER-MODIFIABLE
+ *
+ * MotionSearchPreComputation
+ *
+ *  do whatever you want here; this is called once per frame, directly
+ *  after reading
+ *
+ * RETURNS: whatever
+ *
+ * SIDE EFFECTS:    whatever
+ *
+ *===========================================================================*/
+void
+MotionSearchPreComputation(MpegFrame * const frameP) {
+    /* do nothing */
+}
+
+
+/*===========================================================================*
+ *
+ * PSubSampleSearch
+ *
+ *  uses the subsampling algorithm to compute the P-frame vector
+ *
+ * RETURNS: motion vector
+ *
+ * SIDE EFFECTS:    none
+ *
+ * REFERENCE:  Liu and Zaccarin:  New Fast Algorithms for the Estimation
+ *      of Block Motion Vectors, IEEE Transactions on Circuits
+ *      and Systems for Video Technology, Vol. 3, No. 2, 1993.
+ *
+ *===========================================================================*/
+int
+PSubSampleSearch(const LumBlock * const currentBlockP,
+                 MpegFrame *      const prev, 
+                 int              const by,
+                 int              const bx,
+                 vector *         const motionP,
+                 int              const searchRange) {
+    
+    int my, mx;
+    int bestBestDiff;
+    int stepSize;
+    int x;
+    int bestMY[4], bestMX[4], bestDiff[4];
+    int leftMY, leftMX;
+    int rightMY, rightMX;
+
+    stepSize = (pixelFullSearch ? 2 : 1);
+
+    COMPUTE_MOTION_BOUNDARY(by,bx,stepSize,leftMY,leftMX,rightMY,rightMX);
+
+    if ( searchRange < rightMY ) {
+        rightMY = searchRange;
+    }
+
+    if ( searchRange < rightMX ) {
+        rightMX = searchRange;
+    }
+
+    for ( x = 0; x < 4; x++ ) {
+        bestMY[x] = 0;
+        bestMX[x] = 0;
+        bestDiff[x] = INT_MAX;
+    }
+
+    /* do A pattern */
+    for (my = -searchRange; my < rightMY; my += 2*stepSize) {
+        if (my >= leftMY) {
+            for ( mx = -searchRange; mx < rightMX; mx += 2*stepSize ) {
+                if (mx >= leftMX) {
+                    int diff;
+                    vector m;
+                    m.y = my; m.x = mx;
+                    diff = LumMotionErrorA(currentBlockP, prev, by, bx, m,
+                                           bestDiff[0]);
+                    
+                    if (diff < bestDiff[0]) {
+                        bestMY[0] = my;
+                        bestMX[0] = mx;
+                        bestDiff[0] = diff;
+                    }
+                }
+            }
+        }
+    }
+
+    /* do B pattern */
+    for (my = stepSize-searchRange; my < rightMY; my += 2*stepSize) {
+        if (my >= leftMY) {
+            for (mx = -searchRange; mx < rightMX; mx += 2*stepSize) {
+                if (mx >= leftMX) {
+                    int diff;
+                    vector m;
+                    m.y = my; m.x = mx;
+                    diff = LumMotionErrorB(currentBlockP, prev, by, bx, m, 
+                                           bestDiff[1]);
+                    
+                    if (diff < bestDiff[1]) {
+                        bestMY[1] = my;
+                        bestMX[1] = mx;
+                        bestDiff[1] = diff;
+                    }
+                }
+            }
+        }
+    }
+
+    /* do C pattern */
+    for (my = stepSize-searchRange; my < rightMY; my += 2*stepSize) {
+        if (my >= leftMY) {
+            for ( mx = stepSize-searchRange; mx < rightMX; mx += 2*stepSize ) {
+                if (mx >= leftMX) {
+                    int diff;
+                    vector m;
+                    m.y = my; m.x = mx;
+                    diff = LumMotionErrorC(currentBlockP, prev, by, bx, m,
+                                           bestDiff[2]);
+                    
+                    if (diff < bestDiff[2]) {
+                        bestMY[2] = my;
+                        bestMX[2] = mx;
+                        bestDiff[2] = diff;
+                    }
+                }
+            }
+        }
+    }
+
+    /* do D pattern */
+    for (my = -searchRange; my < rightMY; my += 2*stepSize) {
+        if (my >= leftMY) {
+            for (mx = stepSize-searchRange; mx < rightMX; mx += 2*stepSize) {
+                if (mx >= leftMX) {
+                    int diff;
+                    vector m;
+                    m.y = my; m.x = mx;
+                    diff = LumMotionErrorD(currentBlockP, prev, by, bx, m,
+                                           bestDiff[3]);
+                    
+                    if (diff < bestDiff[3]) {
+                        bestMY[3] = my;
+                        bestMX[3] = mx;
+                        bestDiff[3] = diff;
+                    }
+                }
+            }
+        }
+    }
+
+    /* first check old motion */
+    if ((motionP->y >= leftMY) && (motionP->y < rightMY) &&
+        (motionP->x >= leftMX) && (motionP->x < rightMX)) {
+        bestBestDiff = LumMotionError(currentBlockP, prev, by, bx, 
+                                      *motionP, INT_MAX);
+    } else
+        bestBestDiff = INT_MAX;
+
+    /* look at Error of 4 different motion vectors */
+    for (x = 0; x < 4; ++x) {
+        vector m;
+        m.y = bestMY[x];
+        m.x = bestMX[x];
+        bestDiff[x] = LumMotionError(currentBlockP, prev, by, bx, m,
+                                     bestBestDiff);
+
+        if (bestDiff[x] < bestBestDiff) {
+            bestBestDiff = bestDiff[x];
+            *motionP     = m;
+        }
+    }
+    return bestBestDiff;
+}
+
+
+
+static void
+findBestSpaced(int              const minMY,
+               int              const minMX,
+               int              const maxMY,
+               int              const maxMX,
+               int              const spacing,
+               const LumBlock * const currentBlockP, 
+               MpegFrame *      const prev,
+               int              const by,
+               int              const bx,
+               int *            const bestDiffP, 
+               vector *         const centerP) {
+/*----------------------------------------------------------------------------
+   Examine every 'spacing'th half-pixel within the rectangle 
+   ('minBoundX', 'minBoundY', 'maxBoundX', 'maxBoundY'), 
+
+   If one of the half-pixels examined has a lower "LumMotionError" value
+   than *bestDiffP, update *bestDiffP to that value and update
+   *centerP to the location of that half-pixel.
+-----------------------------------------------------------------------------*/
+    int const minBoundY = MAX(minMY, centerP->y - spacing);
+    int const minBoundX = MAX(minMX, centerP->x - spacing);
+    int const maxBoundY = MIN(maxMY, centerP->y + spacing + 1);
+    int const maxBoundX = MIN(maxMX, centerP->x + spacing + 1);
+
+    int my;
+
+    for (my = minBoundY; my < maxBoundY; my += spacing) {
+        int mx;
+
+        for (mx = minBoundX; mx < maxBoundX; mx += spacing) {
+            int diff;
+            vector m;
+
+            m.y = my; m.x = mx;
+            
+            diff = LumMotionError(currentBlockP, prev, by, bx, m, *bestDiffP);
+            
+            if (diff < *bestDiffP) {
+                *centerP   = m;
+                *bestDiffP = diff;
+            }
+        }
+    }
+}
+
+
+
+/*===========================================================================*
+ *
+ * PLogarithmicSearch
+ *
+ *  uses logarithmic search to compute the P-frame vector
+ *
+ * RETURNS: motion vector
+ *
+ * SIDE EFFECTS:    none
+ *
+ * REFERENCE:  MPEG-I specification, pages 32-33
+ *
+ *===========================================================================*/
+int
+PLogarithmicSearch(const LumBlock * const currentBlockP,
+                   MpegFrame *      const prev, 
+                   int              const by,
+                   int              const bx, 
+                   vector *         const motionP,
+                   int              const searchRange) {
+
+    int const stepSize = (pixelFullSearch ? 2 : 1);
+
+    int minMY, minMX, maxMY, maxMX;
+    int spacing;  /* grid spacing */
+    vector motion;
+        /* Distance from (bx,by) (in half-pixels) of the block that is most
+           like the current block among those that we have examined so far.
+           (0,0) means we haven't examined any.
+        */
+    int bestDiff;
+        /* The difference between the current block and the block offset
+           'motion' from it.
+        */
+    
+    COMPUTE_MOTION_BOUNDARY(by, bx, stepSize, minMY, minMX, maxMY, maxMX);
+    minMX = max(minMX, - searchRange);
+    minMY = max(minMY, - searchRange);
+    maxMX = min(maxMX, + searchRange);
+    maxMY = min(maxMY, + searchRange);
+
+    /* Note: The clipping to 'searchRange' above may seem superfluous because
+       the basic algorithm would never want to look more than 'searchRange'
+       pixels away, but with rounding error, it can.
+    */
+
+    motion.x = motion.y = 0;
+    bestDiff = INT_MAX;
+
+    for (spacing = searchRange; spacing >= stepSize;) {
+        if (stepSize == 2) {  /* make sure spacing is even */
+            if (spacing == 2) 
+                spacing = 0;
+            else {
+                spacing = (spacing+1)/2;
+                if (spacing % 2 != 0) 
+                    --spacing;
+            }
+        } else {
+            if (spacing == 1) {
+                spacing = 0;
+            } else 
+                spacing = (spacing + 1) / 2;
+        }
+        if (spacing >= stepSize) 
+            findBestSpaced(minMY, minMX, maxMY, maxMX,
+                           spacing, currentBlockP, prev, by, bx,
+                           &bestDiff, &motion);
+    }
+
+    {
+        int diff;
+        /* check old motion -- see if it's better */
+        if ((motionP->y >= minMY) && (motionP->y < maxMY) &&
+            (motionP->x >= minMX) && (motionP->x < maxMX)) {
+            diff = LumMotionError(currentBlockP, prev, by, bx, 
+                                  *motionP, bestDiff);
+        } else 
+            diff = INT_MAX;
+        
+        if (bestDiff < diff)
+            *motionP = motion;
+        else 
+            bestDiff = diff;
+    }
+
+    return bestDiff;
+}
+
+
+
+/*===========================================================================*
+ *
+ * PLocalSearch
+ *
+ *  uses local exhaustive search to compute the P-frame vector
+ *
+ * RETURNS: motion vector
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+int
+PLocalSearch(const LumBlock * const currentBlockP,
+             MpegFrame *      const prev, 
+             int              const by,
+             int              const bx,
+             vector *         const motionP,
+             int              const bestSoFar,
+             int              const searchRange) {
+
+    int mx, my;
+    int bestDiff;
+    int stepSize;
+    int leftMY, leftMX;
+    int rightMY, rightMX;
+    int distance;
+    int tempRightMY, tempRightMX;
+
+    stepSize = (pixelFullSearch ? 2 : 1);
+
+    COMPUTE_MOTION_BOUNDARY(by,bx,stepSize,leftMY,leftMX,rightMY,rightMX);
+
+    /* try old motion vector first */
+    if (VALID_MOTION(*motionP)) {
+        bestDiff = LumMotionError(currentBlockP, prev, by, bx, 
+                                  *motionP, bestSoFar);
+
+        if (bestSoFar < bestDiff)
+            bestDiff = bestSoFar;
+    } else {
+        motionP->y = motionP->x = 0;
+        bestDiff = bestSoFar;
+    }
+
+    /* try a spiral pattern */    
+    for (distance = stepSize; distance <= searchRange; distance += stepSize) {
+        tempRightMY = MIN(distance, rightMY);
+        tempRightMX = MIN(distance, rightMX);
+
+        /* do top, bottom */
+        for (my = -distance; my < tempRightMY;
+             my += max(tempRightMY+distance-stepSize, stepSize)) {
+            if (my >= leftMY) {
+                for ( mx = -distance; mx < tempRightMX; mx += stepSize ) {
+                    if (mx >= leftMX) {
+                        int diff;
+                        vector m;
+                        
+                        m.y = my; m.x = mx;
+                        diff = LumMotionError(currentBlockP, prev, by, bx, m, 
+                                              bestDiff);
+                        
+                        if (diff < bestDiff) {
+                            *motionP = m;
+                            bestDiff = diff;
+                        }
+                    }
+                }
+            }
+        }
+
+        /* do left, right */
+        for (mx = -distance; mx < tempRightMX;
+             mx += max(tempRightMX+distance-stepSize, stepSize)) {
+
+            if (mx >= leftMX) {
+                for (my = -distance+stepSize; my < tempRightMY-stepSize;
+                     my += stepSize) {
+                    if (my >= leftMY) {
+                        int diff;
+                        vector m;
+
+                        m.y = my; m.x = mx;
+                        diff = LumMotionError(currentBlockP, prev, by, bx, m,
+                                              bestDiff);
+                        
+                        if (diff < bestDiff) {
+                            *motionP = m;
+                            bestDiff = diff;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return bestDiff;
+}
+
+
+/*===========================================================================*
+ *
+ * PTwoLevelSearch
+ *
+ *  uses two-level search to compute the P-frame vector
+ *  first does exhaustive full-pixel search, then looks at neighboring
+ *  half-pixel motion vectors
+ *
+ * RETURNS: motion vector
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+int
+PTwoLevelSearch(const LumBlock * const currentBlockP,
+                MpegFrame *      const prev, 
+                int              const by,
+                int              const bx, 
+                vector *         const motionP,
+                int              const bestSoFar,
+                int              const searchRange) {
+    int mx, my;
+    int loopInc;
+    int diff, bestDiff;
+    int leftMY, leftMX;
+    int rightMY, rightMX;
+    int distance;
+    int tempRightMY, tempRightMX;
+    int xOffset, yOffset;
+
+    /* exhaustive full-pixel search first */
+
+    COMPUTE_MOTION_BOUNDARY(by,bx,2,leftMY,leftMX,rightMY,rightMX);
+
+    rightMY--;
+    rightMX--;
+
+    /* convert vector into full-pixel vector */
+    if (motionP->y > 0) {
+        if ((motionP->y % 2) == 1) {
+            --motionP->y;
+        }
+    } else if (((-motionP->y) % 2) == 1)
+        ++motionP->y;
+
+    if (motionP->x > 0) {
+        if ((motionP->x % 2) == 1)
+            --motionP->x;
+    } else if ((-motionP->x % 2) == 1)
+        ++motionP->x;
+
+    /* try old motion vector first */
+    if (VALID_MOTION(*motionP)) {
+        bestDiff = LumMotionError(currentBlockP, prev, by, bx, 
+                                  *motionP, bestSoFar);
+
+        if ( bestSoFar < bestDiff ) {
+            bestDiff = bestSoFar;
+        }
+    } else {
+        motionP->y = motionP->x = 0;
+        bestDiff = bestSoFar;
+    }
+
+    ++rightMY;
+    ++rightMX;
+
+    /* try a spiral pattern */    
+    for ( distance = 2; distance <= searchRange; distance += 2 ) {
+        tempRightMY = MIN(distance, rightMY);
+        tempRightMX = MIN(distance, rightMX);
+
+        /* do top, bottom */
+        loopInc = max(tempRightMY + distance - 2, 2);
+        for (my = -distance; my < tempRightMY; my += loopInc) {
+            if (my >= leftMY) {
+                for (mx = -distance; mx < tempRightMX; mx += 2) {
+                    if (mx >= leftMX) {
+                        vector m;
+                        m.y = my; m.x = mx;
+                        diff = LumMotionError(currentBlockP, prev, by, bx, m, 
+                                              bestDiff);
+                        
+                        if (diff < bestDiff) {
+                            *motionP = m;
+                            bestDiff = diff;
+                        }
+                    }
+                }
+            }
+        }
+
+        /* do left, right */
+        loopInc = max(tempRightMX+distance-2, 2);
+        for (mx = -distance; mx < tempRightMX; mx += loopInc) {
+            if (mx >= leftMX) {
+                for ( my = -distance+2; my < tempRightMY-2; my += 2 ) {
+                    if (my >= leftMY) {
+                        int diff;
+                        vector m;
+                        m.y = my; m.x = mx;
+                        diff = LumMotionError(currentBlockP, prev, by, bx, m, 
+                                              bestDiff);
+                        
+                        if ( diff < bestDiff ) {
+                            *motionP = m;
+                            bestDiff = diff;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /* now look at neighboring half-pixels */
+    my = motionP->y;
+    mx = motionP->x;
+
+    --rightMY;
+    --rightMX;
+
+    for (yOffset = -1; yOffset <= 1; ++yOffset) {
+        for (xOffset = -1; xOffset <= 1; ++xOffset) {
+            if ((yOffset != 0) || (xOffset != 0)) {
+                vector m;
+                m.y = my+yOffset; m.x = mx+xOffset;
+                if (VALID_MOTION(m)) {
+                    int diff;
+                    diff = LumMotionError(currentBlockP, prev, by, bx,
+                                          m, bestDiff);
+                    if (diff < bestDiff) {
+                        *motionP = m;
+                        bestDiff = diff;
+                    }
+                }
+            }
+        }
+    }
+    return bestDiff;
+}
+
+
+
+void
+ShowPMVHistogram(fpointer)
+    FILE *fpointer;
+{
+    register int x, y;
+    int *columnTotals;
+    int rowTotal;
+
+    columnTotals = (int *) calloc(2*searchRangeP+3, sizeof(int));
+
+#ifdef COMPLETE_DISPLAY
+    fprintf(fpointer, "    ");
+    for ( y = 0; y < 2*searchRange+3; y++ ) {
+        fprintf(fpointer, "%3d ", y-searchRangeP-1);
+    }
+    fprintf(fpointer, "\n");
+#endif
+
+    for ( x = 0; x < 2*searchRangeP+3; x++ ) {
+#ifdef COMPLETE_DISPLAY
+        fprintf(fpointer, "%3d ", x-searchRangeP-1);
+#endif
+        rowTotal = 0;
+        for ( y = 0; y < 2*searchRangeP+3; y++ ) {
+            fprintf(fpointer, "%3d ", pmvHistogram[x][y]);
+            rowTotal += pmvHistogram[x][y];
+            columnTotals[y] += pmvHistogram[x][y];
+        }
+#ifdef COMPLETE_DISPLAY
+        fprintf(fpointer, "%4d\n", rowTotal);
+#else
+        fprintf(fpointer, "\n");
+#endif
+    }
+
+#ifdef COMPLETE_DISPLAY
+    fprintf(fpointer, "Tot ");
+    for ( y = 0; y < 2*searchRangeP+3; y++ ) {
+        fprintf(fpointer, "%3d ", columnTotals[y]);
+    }
+#endif
+    fprintf(fpointer, "\n");
+}
+
+
+void
+ShowBBMVHistogram(fpointer)
+    FILE *fpointer;
+{
+    register int x, y;
+    int *columnTotals;
+    int rowTotal;
+
+    fprintf(fpointer, "B-frame Backwards:\n");
+
+    columnTotals = (int *) calloc(2*searchRangeB+3, sizeof(int));
+
+#ifdef COMPLETE_DISPLAY
+    fprintf(fpointer, "    ");
+    for ( y = 0; y < 2*searchRangeB+3; y++ ) {
+        fprintf(fpointer, "%3d ", y-searchRangeB-1);
+    }
+    fprintf(fpointer, "\n");
+#endif
+
+    for ( x = 0; x < 2*searchRangeB+3; x++ ) {
+#ifdef COMPLETE_DISPLAY
+        fprintf(fpointer, "%3d ", x-searchRangeB-1);
+#endif
+        rowTotal = 0;
+        for ( y = 0; y < 2*searchRangeB+3; y++ ) {
+            fprintf(fpointer, "%3d ", bbmvHistogram[x][y]);
+            rowTotal += bbmvHistogram[x][y];
+            columnTotals[y] += bbmvHistogram[x][y];
+        }
+#ifdef COMPLETE_DISPLAY
+        fprintf(fpointer, "%4d\n", rowTotal);
+#else
+        fprintf(fpointer, "\n");
+#endif
+    }
+
+#ifdef COMPLETE_DISPLAY
+    fprintf(fpointer, "Tot ");
+    for ( y = 0; y < 2*searchRangeB+3; y++ ) {
+        fprintf(fpointer, "%3d ", columnTotals[y]);
+    }
+#endif
+    fprintf(fpointer, "\n");
+}
+
+
+void
+ShowBFMVHistogram(fpointer)
+    FILE *fpointer;
+{
+    register int x, y;
+    int *columnTotals;
+    int rowTotal;
+
+    fprintf(fpointer, "B-frame Forwards:\n");
+
+    columnTotals = (int *) calloc(2*searchRangeB+3, sizeof(int));
+
+#ifdef COMPLETE_DISPLAY
+    fprintf(fpointer, "    ");
+    for ( y = 0; y < 2*searchRangeB+3; y++ ) {
+        fprintf(fpointer, "%3d ", y-searchRangeB-1);
+    }
+    fprintf(fpointer, "\n");
+#endif
+
+    for ( x = 0; x < 2*searchRangeB+3; x++ ) {
+#ifdef COMPLETE_DISPLAY
+        fprintf(fpointer, "%3d ", x-searchRangeB-1);
+#endif
+        rowTotal = 0;
+        for ( y = 0; y < 2*searchRangeB+3; y++ ) {
+            fprintf(fpointer, "%3d ", bfmvHistogram[x][y]);
+            rowTotal += bfmvHistogram[x][y];
+            columnTotals[y] += bfmvHistogram[x][y];
+        }
+#ifdef COMPLETE_DISPLAY
+        fprintf(fpointer, "%4d\n", rowTotal);
+#else
+        fprintf(fpointer, "\n");
+#endif
+    }
+
+#ifdef COMPLETE_DISPLAY
+    fprintf(fpointer, "Tot ");
+    for ( y = 0; y < 2*searchRangeB+3; y++ ) {
+        fprintf(fpointer, "%3d ", columnTotals[y]);
+    }
+#endif
+    fprintf(fpointer, "\n");
+}
+
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /u/smoot/md/mpeg_encode/RCS/psearch.c,v 1.9 1995/01/19 23:09:12 eyhung Exp $
+ *  $Log: psearch.c,v $
+ * Revision 1.9  1995/01/19  23:09:12  eyhung
+ * Changed copyrights
+ *
+ * Revision 1.9  1995/01/19  23:09:12  eyhung
+ * Changed copyrights
+ *
+ * Revision 1.8  1994/12/07  00:40:36  smoot
+ * Added seperate P and B search ranges
+ *
+ * Revision 1.7  1994/11/12  02:09:45  eyhung
+ * full pixel bug
+ * fixed on lines 512 and 563
+ *
+ * Revision 1.6  1994/03/15  00:27:11  keving
+ * nothing
+ *
+ * Revision 1.5  1993/12/22  19:19:01  keving
+ * nothing
+ *
+ * Revision 1.4  1993/07/22  22:23:43  keving
+ * nothing
+ *
+ * Revision 1.3  1993/06/30  20:06:09  keving
+ * nothing
+ *
+ * Revision 1.2  1993/06/03  21:08:08  keving
+ * nothing
+ *
+ * Revision 1.1  1993/03/02  18:27:05  keving
+ * nothing
+ *
+ */
+
+
diff --git a/converter/ppm/ppmtompeg/psocket.c b/converter/ppm/ppmtompeg/psocket.c
new file mode 100644
index 00000000..707f1d84
--- /dev/null
+++ b/converter/ppm/ppmtompeg/psocket.c
@@ -0,0 +1,452 @@
+/*===========================================================================*
+                              psocket.c
+==============================================================================
+
+   low level communication facilities for Ppmtompeg parallel operation
+
+   By Bryan Henderson 2004.10.13.  Contributed to the public domain by
+   its author.
+
+============================================================================*/
+
+#define _XOPEN_SOURCE 500 /* Make sure stdio.h contains pclose() */
+/* _ALL_SOURCE is needed on AIX to make the C library include the 
+   socket services (e.g. define struct sockaddr) 
+
+   Note that AIX standards.h actually sets feature declaration macros such
+   as _XOPEN_SOURCE, unless they are already set.
+*/
+#define _ALL_SOURCE
+#define __EXTENSIONS__
+  /* __EXTENSIONS__ is for a broken Sun C library (uname SunOS kosh 5.8 
+     generic_108528-16 sun4u sparc).  When you define _XOPEN_SOURCE,
+     it's vnode.h and resource.h fail to define some data types that they
+     need (e.g. timestruct_t).  But with __EXTENSIONS__, they declare the
+     needed types anyway.  Our #include <sys/socket.h> causes the broken
+     header files to get included.
+  */
+
+/* On AIX, pm_config.h includes standards.h, which expects to be included
+   after feature declaration macros such as _XOPEN_SOURCE.  So we include
+   pm_config.h as late as possible.
+*/
+
+#include "pm_config.h" /* For POSIX_IS_IMPLIED */
+
+#ifdef POSIX_IS_IMPLIED
+/* The OpenBSD C library, at least, is broken in that when _XOPEN_SOURCE
+   is defined, its sys/socket.h refers to types "u_char", etc. but does
+   not define them.  But it is also one of the C libraries where
+   POSIX is implied so that we don't need to define _XOPEN_SOURCE in order
+   to get the POSIX routines such as pclose() defined.  So we circumvent
+   the problem by undefining _XOPEN_SOURCE:
+*/
+#undef _XOPEN_SOURCE
+#endif
+
+#include <stdarg.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "pm.h"
+#include "pm_c_util.h"
+#include "nstring.h"
+
+#include "gethostname.h"
+
+#include "psocket.h"
+
+
+/* We use type socklenx_t where we should use socklen_t from the C
+  library, but older systems don't have socklen_t.  And there doesn't
+  appear to be any way for the preprocessor to know whether it exists
+  or not.  On older systems with no socklen_t, a message length is a
+  signed integer, but on modern systems, socklen_t is an unsigned
+  integer.  Until we have some kind of build-time check for the existence
+  of socklen_t, we just use this socklenx_t, which is an unsigned
+  integer, and accept compiler warnings on older system.
+  -Bryan 2001.04.22.
+*/
+typedef unsigned int socklenx_t;
+
+#ifndef SOMAXCONN
+#define SOMAXCONN 5
+#endif
+
+
+
+static void PM_GNU_PRINTF_ATTR(1,2)
+errorExit(const char format[], ...) {
+
+    const char * const hostname = GetHostName();
+
+    va_list args;
+
+    va_start(args, format);
+
+    fprintf(stderr, "%s: FATAL ERROR.  ", hostname);
+    strfree(hostname);
+    vfprintf(stderr, format, args);
+    fputc('\n', stderr);
+
+    exit(1);
+
+    va_end(args);
+}
+
+
+
+static void
+unmarshallInt(unsigned char const buffer[],
+              int *         const valueP) {
+/*----------------------------------------------------------------------------
+  Interpret a number which is formatted for one of our network packets.
+
+  To wit, 32 bit big-endian pure binary.
+-----------------------------------------------------------------------------*/
+    union {
+        uint32_t value;
+        unsigned char bytes[4];
+    } converter;
+
+    memcpy(&converter.bytes, buffer, 4);
+
+    /* Note that contrary to what the C data types suggest, ntohl() is
+       a 32 bit converter, even if a C "long" is bigger than that.
+    */
+    *valueP = ntohl(converter.value);
+}
+
+
+
+static void
+safeRead(int             const fd, 
+         unsigned char * const buf, 
+         unsigned int    const nbyte) {
+/*----------------------------------------------------------------------------
+    Safely read from file 'fd'.  Keep reading until we get
+    'nbyte' bytes.
+-----------------------------------------------------------------------------*/
+    unsigned int numRead;
+
+    numRead = 0;  /* initial value */
+
+    while (numRead < nbyte) {
+        int const result = read(fd, &buf[numRead], nbyte-numRead);
+
+        if (result == -1)
+            errorExit("read (of %u bytes (total %u) ) returned "
+                      "errno %d (%s)",
+                      nbyte-numRead, nbyte, errno, strerror(errno));
+        else 
+            numRead += result;
+    }
+}
+
+
+
+void
+ReadBytes(int             const fd,
+          unsigned char * const buf,
+          unsigned int    const nbyte) {
+
+    safeRead(fd, buf, nbyte);
+}
+
+
+
+void
+ReadInt(int   const socketFd,
+        int * const valueP) {
+
+    unsigned char buffer[4];
+
+    safeRead(socketFd, buffer, sizeof(buffer));
+
+    unmarshallInt(buffer, valueP);
+}
+
+
+
+static void
+marshallInt(int              const value,
+            unsigned char (* const bufferP)[]) {
+/*----------------------------------------------------------------------------
+   Put the number 'value' into the buffer at *bufferP in the form required
+   for one of our network packets.
+
+   To wit, 32 bit big-endian pure binary.
+-----------------------------------------------------------------------------*/
+    union {
+        uint32_t value;
+        unsigned char bytes[4];
+    } converter;
+
+    unsigned char testbuffer[4];
+
+    /* Note that contrary to what the C data types suggest, htonl() is
+       a 32 bit converter, even if a C "long" is bigger than that.
+    */
+    converter.value = htonl(value);
+
+    (*bufferP)[0] = 7;
+    memcpy(testbuffer, &converter.bytes, 4);
+    memcpy(*bufferP, &converter.bytes, 4);
+}
+
+
+
+static void
+safeWrite(int             const fd, 
+          unsigned char * const buf, 
+          unsigned int    const nbyte) {
+/*----------------------------------------------------------------------------
+  Safely write to file 'fd'.  Keep writing until we write 'nbyte'
+  bytes.
+-----------------------------------------------------------------------------*/
+    unsigned int numWritten;
+
+    numWritten = 0;  /* initial value */
+
+    while (numWritten < nbyte) {
+        int const result = write(fd, &buf[numWritten], nbyte-numWritten);
+
+        if (result == -1) 
+            errorExit("write (of %u bytes (total %u) ) returned "
+                      "errno %d (%s)",
+                      nbyte-numWritten, nbyte, errno, strerror(errno));
+        numWritten += result;
+    }
+}
+
+
+
+void
+WriteBytes(int             const fd,
+           unsigned char * const buf,
+           unsigned int    const nbyte) {
+
+    safeWrite(fd, buf, nbyte);
+}
+
+
+
+void
+WriteInt(int const socketFd,
+         int const value) {
+
+    unsigned char buffer[4];
+
+    marshallInt(value, &buffer);
+
+    safeWrite(socketFd, buffer, sizeof(buffer));
+}
+
+
+
+void
+ConnectToSocket(const char *      const machineName, 
+                int               const portNum, 
+                struct hostent ** const hostEnt,
+                int *             const socketFdP,
+                const char **     const errorP) {
+/*----------------------------------------------------------------------------
+   Create a socket and connect it to the specified TCP endpoint.
+
+   That endpoint is fundamentally defined by 'machineName' and
+   'portNum', but *hostEnt is the address of a host entry that caches
+   the results of the host name lookup.  If *hostEnt is non-null, we
+   use it.  If *hostEnt is NULL, we look up the information and update
+   **hostEnt.
+-----------------------------------------------------------------------------*/
+    int rc;
+    
+    *errorP = NULL;  /* initial value */
+
+    if ((*hostEnt) == NULL) {
+        (*hostEnt) = gethostbyname(machineName);
+        if ((*hostEnt) == NULL)
+            asprintfN(errorP, "Couldn't get host by name (%s)", machineName);
+    }
+    if (!*errorP) {
+        rc = socket(AF_INET, SOCK_STREAM, 0);
+        if (rc < 0)
+            asprintfN(errorP, "socket() failed with errno %d (%s)", 
+                      errno, strerror(errno));
+        else {
+            int const socketFd = rc;
+            
+            int rc;
+            unsigned short tempShort;
+            struct sockaddr_in  nameEntry;
+            
+            nameEntry.sin_family = AF_INET;
+            memset((void *) nameEntry.sin_zero, 0, 8);
+            memcpy((void *) &(nameEntry.sin_addr.s_addr),
+                   (void *) (*hostEnt)->h_addr_list[0],
+                   (size_t) (*hostEnt)->h_length);
+            tempShort = portNum;
+            nameEntry.sin_port = htons(tempShort);
+            
+            rc = connect(socketFd, (struct sockaddr *) &nameEntry,
+                         sizeof(struct sockaddr));
+            
+            if (rc != 0)
+                asprintfN(errorP, 
+                          "connect() to host '%s', port %d failed with "
+                          "errno %d (%s)",
+                          machineName, portNum, errno, strerror(errno));
+            else {
+                *errorP = NULL;
+                *socketFdP = socketFd;
+            }
+            if (*errorP)
+                close(socketFd);
+        }
+    }
+}
+
+
+
+static bool
+portInUseErrno(int const testErrno) {
+/*----------------------------------------------------------------------------
+   Return TRUE iff 'testErrno' is what a bind() would return if one requestd
+   a port number that is unavailable (but other port numbers might be).
+-----------------------------------------------------------------------------*/
+    bool retval;
+
+    switch (testErrno) {
+    case EINVAL:
+    case EADDRINUSE:
+    case EADDRNOTAVAIL:
+        retval = TRUE;
+        break;
+    default:
+        retval = FALSE;
+    }
+    return retval;
+}
+
+
+
+static void
+bindToUnusedPort(int              const socketFd,
+                 unsigned short * const portNumP,
+                 const char **    const errorP) {
+    
+    bool foundPort;
+    unsigned short trialPortNum;
+
+    *errorP = NULL;  /* initial value */
+
+    for (foundPort = FALSE, trialPortNum = 2048; 
+         !foundPort && trialPortNum < 16384 && !*errorP; 
+         ++trialPortNum) {
+        
+        struct sockaddr_in nameEntry;
+        int rc;
+        
+        memset((char *) &nameEntry, 0, sizeof(nameEntry));
+        nameEntry.sin_family = AF_INET;
+        nameEntry.sin_port   = htons(trialPortNum);
+
+        rc = bind(socketFd, (struct sockaddr *) &nameEntry,
+                  sizeof(struct sockaddr));
+
+        if (rc == 0) {
+            foundPort = TRUE;
+            *portNumP = trialPortNum;
+        } else if (!portInUseErrno(errno))
+            asprintfN(errorP, "bind() of TCP port number %hu failed "
+                      "with errno %d (%s)", 
+                      trialPortNum, errno, strerror(errno));
+    }
+    
+    if (!*errorP && !foundPort)
+        asprintfN(errorP, "Unable to find a free port.  Every TCP port "
+                  "in the range 2048-16383 is in use");
+}
+
+
+
+void
+CreateListeningSocket(int *         const socketP,
+                      int *         const portNumP,
+                      const char ** const errorP) {
+/*----------------------------------------------------------------------------
+   Create a TCP socket and bind it to the first unused port number we
+   can find.
+
+   Return as *socketP a file handle for the socket (on which Caller can
+   listen()), and as *portNumP the TCP port number (to which Caller's
+   partner can connect).
+-----------------------------------------------------------------------------*/
+    int rc;
+    
+    rc = socket(AF_INET, SOCK_STREAM, 0);
+    if (rc < 0)
+        asprintfN(errorP,
+                  "Unable to create socket.  "
+                  "socket() failed with errno %d (%s)",
+                  errno, strerror(errno));
+    else {
+        int const socketFd = rc;
+
+        unsigned short portNum;
+
+        *socketP = socketFd;
+
+        bindToUnusedPort(socketFd, &portNum, errorP);
+        if (!*errorP) {
+            int rc;
+
+            *portNumP = portNum;
+
+            /* would really like to wait for 1+numMachines machines,
+              but this is max allowable, unfortunately
+            */
+            rc = listen(socketFd, SOMAXCONN);
+            if (rc != 0)
+                asprintfN(errorP, "Unable to listen on TCP socket.  "
+                          "listen() fails with errno %d (%s)", 
+                          errno, strerror(errno));
+        }
+        if (*errorP)
+            close(socketFd);
+    }
+}
+
+
+
+void
+AcceptConnection(int           const listenSocketFd,
+                 int *         const connectSocketFdP,
+                 const char ** const errorP) {
+
+    struct sockaddr otherSocket;
+    socklenx_t      otherSize;
+        /* This is an ugly dual-meaning variable.  As input to accept(),
+           it is the storage size of 'otherSocket'.  As output, it is the 
+           data length of 'otherSocket'.
+        */
+    int             rc;
+    
+    otherSize = sizeof(otherSocket);
+
+    rc = accept(listenSocketFd, &otherSocket, &otherSize);
+
+    if (rc < 0)
+        asprintfN(errorP, "accept() failed with errno %d (%s).  ",
+                  errno, strerror(errno));
+    else {
+        *connectSocketFdP = rc;
+        *errorP = NULL;
+    }
+}
diff --git a/converter/ppm/ppmtompeg/qtest.c b/converter/ppm/ppmtompeg/qtest.c
new file mode 100644
index 00000000..b3d26593
--- /dev/null
+++ b/converter/ppm/ppmtompeg/qtest.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /n/charlie-brown/project/mm/mpeg/mpeg_dist/mpeg_encode/RCS/qtest.c,v 1.5 1995/01/19 23:09:15 eyhung Exp $
+ *  $Log: qtest.c,v $
+ * Revision 1.5  1995/01/19  23:09:15  eyhung
+ * Changed copyrights
+ *
+ * Revision 1.4  1993/01/18  10:20:02  dwallach
+ * *** empty log message ***
+ *
+ * Revision 1.3  1993/01/18  10:17:29  dwallach
+ * RCS headers installed, code indented uniformly
+ *
+ * Revision 1.3  1993/01/18  10:17:29  dwallach
+ * RCS headers installed, code indented uniformly
+ *
+ */
+
+#include <stdio.h>
+#include "mtypes.h"
+#include "mproto.h"
+
+main()
+{
+    Block a;
+    FlatBlock b;
+    BitBucket *bb;
+    int i, j;
+
+    bb = new_bitbucket();
+
+    for (i = 0; i < 8; i++)
+	for (j = 0; j < 8; j++)
+	    a[i][j] = rand() % 100;
+    mp_quant_zig_block(a, b, 1, 1);
+    for (i = 0; i < 64; i++)
+	printf("%6d ", b[i]);
+    printf("\n");
+
+    mp_rle_huff_block(b, bb);	/* intuititve names, huh? */
+
+    printf("Huffman output is %d bits\n", bb->totalbits);
+}
diff --git a/converter/ppm/ppmtompeg/rate.c b/converter/ppm/ppmtompeg/rate.c
new file mode 100644
index 00000000..3940956c
--- /dev/null
+++ b/converter/ppm/ppmtompeg/rate.c
@@ -0,0 +1,986 @@
+/*============================================================================*
+ * rate.c								      *
+ *									      * 
+ *	Procedures concerned with rate control                                *
+ *									      *
+ * EXPORTED PROCEDURES:							      *
+ *      initRatecontrol()                                                     *
+ *      targetRateControl()                                                   *
+ *      updateRateControl()                                                   *
+ *      MB_RateOut()                                                          *
+ *      needQScaleChange()                                                    *
+ *      incNumBlocks()                                                        *
+ *      incQuant()                                                            *
+ *	incMacroBlockBits()                                                   *
+ *      setPictureRate()                                                      *
+ *      setBitRate()                                                          *
+ *      getBitRate()                                                          *
+ *      setBufferSize()                                                       *
+ *      getBufferSize()                                                       *
+ *                                                                            *
+ * NOTES:                                                                     *
+ *	Naming conventions follow those of MPEG-2 draft algorithm (chap. 10)  *
+ *============================================================================*/
+
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/times.h>
+
+#include "ppm.h"
+#include "nstring.h"
+
+#include "all.h"
+#include "mtypes.h"
+#include "bitio.h"
+#include "frames.h"
+#include "prototypes.h"
+#include "param.h"
+#include "mheaders.h"
+#include "fsize.h"
+#include "postdct.h"
+#include "mpeg.h"
+#include "parallel.h"
+#include "dct.h"
+#include "rate.h"
+
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+
+#define MAX_BIT_RATE 104857600		/* 18 digit number in units of 400 */
+#define MAX_BUFFER_SIZE 16760832        /* 10 digit number in units of 16k */
+#define DEFAULT_BUFFER_SIZE 327680      /* maximun for "constrained" bitstream */
+#define DEFAULT_VBV_FULLNESS 3          /* wait till 1/3 full */
+#define DEFAULT_PICT_RATE_CODE 5        /* code for 30 Frames/sec */
+#define DEFAULT_PICT_RATE 30            /* 30 frames per second */
+#define MAX_VBV_DELAY 32768             /* 16 digits */
+
+
+/*	  Variables from Parameter File */
+
+static int	RateControlMode = VARIABLE_RATE;
+static int32 buffer_size = DEFAULT_BUFFER_SIZE;
+static int32 bit_rate = -1;
+
+static bool wantVbvUnderflowWarning;
+static bool wantVbvOverflowWarning;
+
+/*   Variables for the VBV buffer defined in MPEG specs */
+static unsigned int VBV_remainingDelay; 
+    /* delay in units of 1/90000 seconds */
+static int32 VBV_buffer = 0;	  /* fullness of the theoretical VBV buffer */
+static int32 bufferFillRate = 0;    /* constant rate at which buffer filled */
+static int32 frameDelayIncrement = 0;	/* number of "delay" units/Frame */
+
+/*  Global complexity measure variables */
+static int Xi, Xp, Xb;  /*  Global complexity measure  */
+
+static int Si, Sp, Sb;  /*  Total # bits for last pict of type (Overhead?) */
+
+static float Qi, Qp, Qb; /* avg quantizaton for last picture of type  */
+     
+/*  Target bit allocations for each type of picture*/
+int Ti, Tp, Tb;
+
+int current_Tx;	/* allocation for current frame */
+
+/*  Count of number of pictures of each type remaining */
+int GOP_X;
+int GOP_I;
+int GOP_P;
+int GOP_B;
+
+int Nx = 0;
+int Ni = 0;
+int Np = 0;
+int Nb = 0;
+
+/*   Counters used while encoding frames   */
+
+int rc_numBlocks = 0;
+int rc_totalQuant = 0;
+int rc_bitsThisMB;
+int rc_totalMBBits;
+int rc_totalFrameBits;
+int rc_totalOverheadBits = 0;
+
+
+/*	Want to print out Macroblock info every Nth MB */
+int RC_MB_SAMPLE_RATE = 0;
+
+static float Ki = .7;
+static float Kp = 1;
+static float Kb = 1.4;
+static int rc_R;
+static int rc_G;
+
+/*   Rate Control variables   */
+
+/*   Virtual buffers for each frame type */
+static int d0_i;   /* Initial fullnesses */
+static int d0_p;
+static int d0_b;
+
+static int lastFrameVirtBuf;   /* fullness after last frame of this type */
+static int currentVirtBuf;     /* fullness during current encoding*/
+
+static int MB_cnt = -1;	       /* Number of MB's in picture */
+
+static int rc_Q;               /* reference quantization parameter */
+
+static int reactionParameter;  /*  Reaction parameter */
+
+/*	Adaptive Quantization variables */
+static int act_j;              /*  spatial activity measure */
+static float N_act;            /*  Normalized spacial activity */
+static int avg_act;	   /*  average activity value in last picture encoded */
+static int total_act_j;	       /*  Sum of activity values in current frame */
+
+static int var_sblk;	       /* sub-block activity */
+static int P_mean;	       /* Mean value of pixels in 8x8 sub-block */
+
+static int mquant;	       /* Raw Quantization value */
+static int Qscale;	       /* Clipped, truncated quantization value */
+
+
+
+/*  Output-related variables */
+#ifdef RC_STATS_FILE
+static FILE *RC_FILE;
+#endif
+
+static const char * const Frame_header1 = 
+"  Fm         #     Bit      GOP                    V                ";
+static const char * const Frame_header2 = 
+"   #  type   MBs   Alloc    left  Ni Np Nb  N_act  buff   Q_rc Qscale";
+static const char * const Frame_header3 = 
+"----     -  ----  ------ -------  -- -- --  -----  ------ ----   ----";
+static const char * const Frame_trailer1 = 
+"                      avg          virt     %    GOP      %     VBV";
+static const char * const Frame_trailer2 = 
+"    Sx    Qx      Xx  act N_act  buffer alloc    left  left     buf  delay";
+static const char * const Frame_trailer3 = 
+"------ --.-- -------  --- --.-- -------   --- -------   --- ------- ------";
+
+static const char * const MB_header1 = 
+"MB#  #bits  Q mqt     Dj  Q_j   actj  N_act  totbits b/MB %alloc %done";
+static const char * const MB_header2 = 
+"---  ----- -- --- ------  ---  -----  --.--   ------ ----    ---   ---";
+
+static char rc_buffer[101];
+
+/*	EXTERNAL Variables  */
+extern char *framePattern;
+extern int framePatternLen;
+
+
+/*===============================*
+ * INTERNAL PROCEDURE prototypes *
+ *===============================*/
+
+int initGOPRateControl _ANSI_ARGS_((void));
+int determineMBCount _ANSI_ARGS_((void));
+void checkBufferFullness _ANSI_ARGS_((int count));
+void checkSpatialActivity _ANSI_ARGS_((Block blk0, Block blk1, Block blk2, Block blk3));
+void incNumBlocks _ANSI_ARGS_((int num));
+void calculateVBVDelay _ANSI_ARGS_((int num));
+int BlockExperiments  _ANSI_ARGS_((int16 *OrigBlock, int16 *NewBlock, int control));
+     
+     
+
+static void
+analyzePattern(const char *  const framePattern,
+               int           const framePatternLen,
+               int *         const gop_xP,
+               int *         const gop_iP,
+               int *         const gop_pP,
+               int *         const gop_bP,
+               const char ** const errorP) {
+
+    unsigned int i;
+
+    /*  Initialize Pattern info */
+    *gop_xP = framePatternLen;    
+
+    for (i = 0, *gop_iP = 0, *gop_pP = 0, *gop_bP = 0, *errorP = NULL;
+         i < framePatternLen && !*errorP; 
+         ++i) {
+        switch(framePattern[i]) {
+        case 'i': ++*gop_iP; break;
+        case 'p': ++*gop_pP; break;
+        case 'b': ++*gop_bP; break;
+        default:
+            asprintfN(errorP, "Bad pattern - not composed of i, p, and b");
+        }
+    }
+    assert(*gop_xP == *gop_iP + *gop_pP + *gop_bP);
+}
+  
+
+
+/*===========================================================================*
+ *
+ * initRateControl
+ *
+ *	initialize the allocation parameters.
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:   many global variables 
+ *
+ * NOTES:  Get rid of the redundant pattern stuff!!
+ *===========================================================================*/
+int
+initRateControl(bool const wantUnderflowWarning,
+                bool const wantOverflowWarning) {
+    int result;
+    const char * error;
+
+    wantVbvUnderflowWarning = wantUnderflowWarning;
+    wantVbvOverflowWarning  = wantOverflowWarning;
+
+    DBG_PRINT(("Initializing Allocation Data\n"));
+  
+#ifdef RC_STATS_FILE
+    RC_FILE = fopen("RC_STATS_FILE", "w");
+    if ( RC_FILE  == NULL) {
+        DBG_PRINT(("Open of RC file failed, using stderr\n"));
+        RC_FILE = stderr;
+        fprintf(RC_FILE, "Open of RC file failed, using stderr\n");
+        fflush(RC_FILE);
+    }
+#endif
+
+    VBV_remainingDelay = 0;
+  
+    analyzePattern(framePattern, framePatternLen,
+                   &GOP_X, &GOP_I, &GOP_P, &GOP_B, &error);
+
+    if (error) {
+        pm_message("Unable to set up rate control.  Switching to variable.  "
+                   "%s", error);
+        strfree(error);
+        RateControlMode = VARIABLE_RATE;
+        return -1;
+    }
+
+
+    /* Initializing GOP bit allocation */	
+    rc_R = 0;
+    rc_G = (bit_rate * GOP_X/frameRateRounded);
+  
+    /*   Initialize the "global complexity measures" */
+    Xi = (160 * bit_rate/115);
+    Xp = (60 * bit_rate/115);
+    Xb = (42 * bit_rate/115);
+  
+    /*   Initialize MB counters */
+    rc_totalMBBits= rc_bitsThisMB= rc_totalFrameBits=rc_totalOverheadBits = 0;
+    rc_numBlocks = rc_totalQuant = 0;
+  
+    /*   init virtual buffers  */
+    reactionParameter = (2 * bit_rate / frameRateRounded);
+    d0_i = (10 * reactionParameter / 31);
+    d0_p = (Kp * d0_i);
+    d0_b = (Kb * d0_i);
+  
+    lastFrameVirtBuf = d0_i;	/*  start with I Frame */
+    rc_Q = lastFrameVirtBuf  * 31 / reactionParameter;
+  
+    /*   init spatial activity measures */
+    avg_act = 400;		/* Suggested initial value */
+    N_act = 1;
+  
+    mquant = rc_Q * N_act;
+  
+    frameDelayIncrement = (90000 / frameRateRounded);
+        /* num of "delay" units per frame */
+    bufferFillRate = bit_rate / frameRateRounded; 
+        /* VBV buf fills at constant rate */
+    VBV_buffer = buffer_size;
+    DBG_PRINT(("VBV- delay: %d, fill rate: %d, delay/Frame: %d units, "
+               "buffer size: %d\n",
+               VBV_remainginDelay, bufferFillRate, frameDelayIncrement, 
+               buffer_size));
+  
+    result = initGOPRateControl();
+  
+    return result;
+}
+
+/*===========================================================================*
+ *
+ * initGOPRateControl
+ *
+ *		(re)-initialize the RC for the a new Group of Pictures.
+ *	New bit allocation, but carry over complexity measures.
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:   many global variables 
+ *
+ *===========================================================================*/
+int
+initGOPRateControl()
+{
+    DBG_PRINT(("Initializing new GOP\n"));
+  
+    Nx = GOP_X;
+    Ni = GOP_I;
+    Np = GOP_P;
+    Nb = GOP_B;
+  
+    rc_R += rc_G;
+  
+    DBG_PRINT(("bufsize: %d, bitrate: %d, pictrate: %d, GOP bits: %d\n",
+               buffer_size, bit_rate, frameRateRounded, rc_R));
+    DBG_PRINT(("Xi: %d, Xp: %d, Xb: %d Nx: %d, Ni: %d, Np: %d, Nb: %d\n",
+               Xi, Xp, Xb, Nx,Ni,Np,Nb));
+    DBG_PRINT(("d0_i: %d, d0_p: %d, d0_b: %d, avg_act: %d, rc_Q: %d, "
+               "mquant: %d\n",
+               d0_i, d0_p, d0_b, avg_act, rc_Q, mquant));
+    return 1;
+}
+
+
+
+/*===========================================================================*
+ *
+ * targetRateControl
+ *
+ *      Determine the target allocation for given picture type, initiates
+ *  variables for rate control process.
+ *
+ * RETURNS:     nothing.
+ *
+ * SIDE EFFECTS:   many global variables
+ *
+ *===========================================================================*/
+void
+targetRateControl(MpegFrame * const frame) {
+
+    float temp1, minimumBits;
+    float tempX, tempY, tempZ;
+    int result;
+    int frameType;
+    const char *strPtr;
+  
+    minimumBits = (bit_rate / (8 * frameRateRounded));
+  
+    /*   Check if new GOP */
+    if (Nx == 0) {
+        initGOPRateControl();
+    }
+  
+    if (MB_cnt < 0) {MB_cnt = determineMBCount();}
+  
+    switch (frame->type) {
+    case TYPE_IFRAME:
+        frameType = 'I';
+    
+        tempX = ( (Np * Ki * Xp) / (Xi * Kp) );
+        tempY = ( (Nb * Ki * Xb) / (Xi*Kb) );
+        tempZ = Ni + tempX + tempY;
+        temp1 = (rc_R / tempZ);
+        result = (int) (temp1 > minimumBits ? temp1 :  minimumBits);
+        current_Tx = Ti = result;
+        lastFrameVirtBuf = d0_i;
+        break;
+    
+    case TYPE_PFRAME:
+        frameType = 'P';
+        tempX =  ( (Ni * Kp * Xi) / (Ki * Xp) );
+        tempY =  ( (Nb * Kp * Xb) / (Kb * Xp) );
+        tempZ = Np + tempX + tempY;
+        temp1 = (rc_R/ tempZ);
+        result = (int) (temp1 > minimumBits ? temp1 :  minimumBits);
+        current_Tx = Tp = result;
+        lastFrameVirtBuf = d0_p;
+        break;
+    
+    case TYPE_BFRAME:
+        frameType = 'B';
+        tempX =  ( (Ni * Kb * Xi) / (Ki * Xb) );
+        tempY =  ( (Np * Kb * Xp) / (Kp * Xb) );
+        tempZ = Nb + tempX + tempY;
+        temp1 = (rc_R/ tempZ);
+        result = (int) (temp1 > minimumBits ? temp1 :  minimumBits);
+        current_Tx = Tb = result;
+        lastFrameVirtBuf = d0_b;
+        break;
+    
+    default:
+        frameType = 'X';
+    }
+  
+    N_act = 1;
+    rc_Q = lastFrameVirtBuf  * 31 / reactionParameter;
+    mquant = rc_Q * N_act;
+    Qscale = (mquant > 31 ? 31 : mquant);
+    Qscale = (Qscale < 1 ? 1 : Qscale);
+  
+    /*   Print headers for Frame info */
+    strPtr = Frame_header1;
+    DBG_PRINT(("%s\n",strPtr));
+    strPtr = Frame_header2;
+    DBG_PRINT(("%s\n",strPtr));
+    strPtr = Frame_header3;
+    DBG_PRINT(("%s\n",strPtr));
+  
+    /*   Print Frame info */
+    sprintf(rc_buffer, "%4d     %1c  %4d  %6d %7d  "
+            "%2d %2d %2d   %2.2f  %6d %4d    %3d",
+            frame->id,frameType,MB_cnt,current_Tx,rc_R,Ni,Np,Nb, 
+            N_act, lastFrameVirtBuf, rc_Q, Qscale);
+  
+#ifdef RC_STATS_FILE
+    fprintf(RC_FILE,"%s\n", rc_buffer);
+    fflush(RC_FILE);
+#endif
+    DBG_PRINT(("%s\n",rc_buffer));
+  
+    /*  Print headers for Macroblock info */
+    if (RC_MB_SAMPLE_RATE) {
+        strPtr = MB_header1;
+        DBG_PRINT(("%s\n",strPtr));
+        strPtr = MB_header2;
+        DBG_PRINT(("%s\n",strPtr));
+    }
+}
+
+
+
+
+static void 
+updateVBVBuffer(int const frameBits) {
+/*----------------------------------------------------------------------------
+  Update the VBV buffer after each frame.  This theoretical buffer is
+  being filled at constant rate 'bufferFillRate' from an mpeg stream.
+  It is emptied as each frame is grabbed by the decoder.  Exception is
+  that the decoder will wait until the "delay" is over.
+
+  We mark the passing of one unit of time, in which 'frameBits' bits of
+  mpeg data were grabbed from the buffer by the decoder.
+-----------------------------------------------------------------------------*/
+    if (VBV_remainingDelay)
+        VBV_remainingDelay -= MIN(frameDelayIncrement, VBV_remainingDelay);
+    else
+        VBV_buffer -= frameBits;
+
+    VBV_buffer += bufferFillRate;
+    if (VBV_buffer < 0 && wantVbvUnderflowWarning)
+        pm_message("WARNING - VBV buffer underflow (%d)", VBV_buffer);
+    if (VBV_buffer > buffer_size && wantVbvOverflowWarning)
+        pm_message("WARNING - VBV buffer overflow (%d > %d)",
+                   VBV_buffer, buffer_size);
+}
+
+
+
+/*===========================================================================*
+ *
+ * updateRateControl
+ *
+ *      Update the statistics kept, after end of frame.  Resets
+ *  various global variables
+ *
+ * RETURNS:     nothing
+ *
+ * SIDE EFFECTS:   many global variables
+ *
+ *===========================================================================*/
+void
+updateRateControl(int const type) {
+    int totalBits, frameComplexity, pctAllocUsed, pctGOPUsed;
+    float avgQuant;
+    const char *strPtr;
+
+    totalBits = rc_totalFrameBits;
+    avgQuant = ((float) rc_totalQuant / (float) rc_numBlocks);
+    frameComplexity = totalBits * avgQuant;
+    pctAllocUsed = (totalBits *100 / current_Tx);
+    rc_R -= totalBits;
+    pctGOPUsed = (rc_R *100/ rc_G);
+  
+    avg_act = (total_act_j / MB_cnt);
+  
+    updateVBVBuffer(totalBits);
+  
+    switch (type) {
+    case TYPE_IFRAME:
+        Ti = current_Tx;
+        d0_i = currentVirtBuf;
+        Ni--;
+        Si = totalBits;
+        Qi = avgQuant;
+        Xi = frameComplexity;
+        break;
+    case TYPE_PFRAME:
+        Tp = current_Tx;
+        d0_p = currentVirtBuf;
+        Np--;
+        Sp = totalBits;
+        Qp = avgQuant;
+        Xp = frameComplexity;
+        break;
+    case TYPE_BFRAME:
+        Tb = current_Tx;
+        d0_b = currentVirtBuf;
+        Nb--;
+        Sb = totalBits;
+        Qb = avgQuant;
+        Xb = frameComplexity;
+        break;
+    }
+  
+  
+    /*  Print Frame info */
+    strPtr = Frame_trailer1;
+    DBG_PRINT(("%s\n",strPtr));
+    strPtr = Frame_trailer2;
+    DBG_PRINT(("%s\n",strPtr));
+    strPtr = Frame_trailer3;
+    DBG_PRINT(("%s\n",strPtr));
+  
+    sprintf(rc_buffer, "%6d  %2.2f  %6d  %3d  %2.2f %7d   "
+            "%3d %7d   %3d  %6d %6d",
+            totalBits, avgQuant, frameComplexity, avg_act, N_act, 
+            currentVirtBuf, pctAllocUsed, rc_R, pctGOPUsed, 
+            VBV_buffer, VBV_remainingDelay);
+#ifdef RC_STATS_FILE
+    fprintf(RC_FILE,"%s\n", rc_buffer);
+    fflush(RC_FILE);
+#endif
+    DBG_PRINT(("%s\n",rc_buffer));
+  
+    Nx--;
+    rc_totalMBBits= rc_bitsThisMB= rc_totalFrameBits=rc_totalOverheadBits = 0;
+    rc_numBlocks = rc_totalQuant = total_act_j = currentVirtBuf = 0;
+  
+    DBG_PRINT(("GOP now has %d bits remaining (%3d%%) for %d frames .. , "
+               "Ni= %d, Np= %d, Nb= %d\n", 
+               rc_R, (rc_R*100/rc_G), (Ni+Np+Nb), Ni, Np, Nb));
+  
+}
+
+
+/*===========================================================================*
+ *
+ * MB_RateOut
+ *
+ *      Prints out sampling of MB rate control data.  Every "nth" block
+ *	stats are printed, with "n" controled by global RC_MB_SAMPLE_RATE
+ *	(NB. "skipped" blocks do not go through this function and thus do not
+ *		show up in the sample )
+ *
+ * RETURNS:     nothing
+ *
+ * SIDE EFFECTS:   none
+ *
+ * NOTES:
+ *
+ *===========================================================================*/
+void
+  MB_RateOut(type)
+int type;
+{
+  int totalBits;
+  int pctUsed, pctDone;
+  int bitsThisMB;
+  int bitsPerMB;
+  
+  bitsThisMB = rc_bitsThisMB;
+  totalBits = rc_totalFrameBits;
+  bitsPerMB = (totalBits / rc_numBlocks); 
+  pctDone = (rc_numBlocks * 100/ MB_cnt); 
+  pctUsed = (totalBits *100/current_Tx);
+  
+  sprintf(rc_buffer, "%3d  %5d %2d %3d %6d  %3d %6d   %2.2f   %6d %4d    %3d   %3d\n",
+	  (rc_numBlocks - 1), bitsThisMB, Qscale, mquant, currentVirtBuf, 
+	  rc_Q, act_j, N_act, totalBits, bitsPerMB, pctUsed, pctDone);
+#ifdef RC_STATS_FILE
+  fprintf(RC_FILE, "%s", rc_buffer);
+  fflush(RC_FILE);
+#endif
+  
+  if ( (RC_MB_SAMPLE_RATE) && ((rc_numBlocks -1) % RC_MB_SAMPLE_RATE)) {
+    DBG_PRINT(("%s\n", rc_buffer));
+  } else {
+    return;
+  }
+}
+
+
+
+/*===========================================================================*
+ *
+ * incNumBlocks()
+ *
+ *
+ * RETURNS:   nothing
+ *
+ * SIDE EFFECTS:  rc_numBlocks
+ *
+ * NOTES:
+ *
+ *===========================================================================*/
+void incNumBlocks(num)
+     int num;
+{
+  rc_numBlocks += num;
+}
+
+
+/*===========================================================================*
+ *
+ * incMacroBlockBits()
+ *
+ *	Increments the number of Macro Block bits and the total of Frame
+ *  bits by the number passed.
+ *
+ * RETURNS:   nothing
+ *
+ * SIDE EFFECTS:  rc_totalMBBits
+ *
+ * NOTES:
+ *
+ *===========================================================================*/
+void incMacroBlockBits(num)
+     int num;
+{
+  rc_bitsThisMB = num;
+  rc_totalMBBits += num;
+  rc_totalFrameBits += num;
+}
+
+
+/*===========================================================================*
+ *
+ *   	needQScaleChange(current Q scale, 4 luminance blocks)
+ *
+ *
+ * RETURNS:     new Qscale
+ *
+ * SIDE EFFECTS:   
+ *
+ *===========================================================================*/
+int needQScaleChange(oldQScale, blk0, blk1, blk2, blk3)
+     int oldQScale;
+     Block blk0;
+     Block blk1;
+     Block blk2;
+     Block blk3;
+{
+  
+  /*   One more MacroBlock seen */
+  rc_numBlocks++;		/* this notes each block num in MB */
+  
+  checkBufferFullness(oldQScale);
+  
+  checkSpatialActivity(blk0, blk1, blk2, blk3);
+  
+  mquant = rc_Q * N_act;
+  Qscale = (mquant > 31 ? 31 : mquant);
+  Qscale = (Qscale < 1 ? 1 : Qscale);
+  rc_totalQuant += Qscale;
+  
+  if (oldQScale == Qscale)
+    return -1;
+  else
+    return Qscale;
+}
+
+
+/*===========================================================================*
+ *
+ * determineMBCount() 
+ *
+ *      Determines number of Macro Blocks in frame from the frame sizes
+ *	passed.
+ *
+ * RETURNS:     nothing
+ *
+ * SIDE EFFECTS:   sets the count passed
+ *
+ *===========================================================================*/
+int
+  determineMBCount ()
+{
+  int y,x;
+  
+  x = (Fsize_x +15)/16;
+  y = (Fsize_y +15)/16;
+  return  (x * y);
+}
+
+
+
+/*===========================================================================*
+ *
+ * void checkBufferFullness ()
+ *
+ *      Calculates the fullness of the virtual buffer for each
+ *  frame type.  Called before encoding each macro block.  Along
+ *  with the normalized spatial activity measure (N_act), it
+ *  determine the quantization factor for the next macroblock.
+ *
+ * RETURNS:     nothing
+ *
+ * SIDE EFFECTS:   the "currentVirtBuf" variable
+ *
+ * NOTES:
+ *
+ *===========================================================================*/
+void checkBufferFullness (oldQScale)
+     int oldQScale;
+{
+  int temp;
+  
+  temp = lastFrameVirtBuf + rc_totalFrameBits;
+  temp -=  (current_Tx * rc_numBlocks / MB_cnt);
+  currentVirtBuf = temp;
+  
+  rc_Q = (currentVirtBuf * 31 / reactionParameter);
+  return;
+}
+
+
+/*===========================================================================*
+ *
+ * void checkSpatialActivity()
+ *
+ *      Calcualtes the spatial activity for the four luminance blocks of the
+ *	macroblock.  Along with the normalized reference quantization parameter 
+ *  (rc_Q) , it determines the quantization factor for the next macroblock.
+ *
+ * RETURNS:     nothing
+ *
+ * SIDE EFFECTS:   the Adaptive quantization variables- act_j, N_act.
+ *
+ * NOTES:
+ *
+ *===========================================================================*/
+void checkSpatialActivity(blk0, blk1, blk2, blk3)
+     Block blk0;
+     Block blk1;
+     Block blk2;
+     Block blk3;
+{
+  int temp;
+  int16 *blkArray[4]; 
+  int16 *curBlock;
+  int16 *blk_ptr;
+  int var[4];
+  int i, j;
+  
+  
+  blkArray[0] = (int16 *) blk0;
+  blkArray[1] = (int16 *) blk1;
+  blkArray[2] = (int16 *) blk2;
+  blkArray[3] = (int16 *) blk3;
+  
+  
+  for (i =0; i < 4; i++) {	/* Compute the activity in each block */
+    curBlock = blkArray[i];
+    blk_ptr = curBlock;
+    P_mean = 0;
+    /*  Find the mean pixel value */
+    for (j=0; j < DCTSIZE_SQ; j ++) {
+      P_mean += *(blk_ptr++);
+      /*			P_mean += curBlock[j]; 
+				if (curBlock[j] != *(blk_ptr++)) {
+				printf("ARRAY ERROR: block %d\n", j);
+				}
+				*/
+    }
+    P_mean /= DCTSIZE_SQ;
+    
+    /*  Now find the variance  */
+    curBlock = blkArray[i];
+    blk_ptr = curBlock;
+    var[i] = 0;
+    for (j=0; j < DCTSIZE_SQ; j++) {
+#ifdef notdef
+      if (curBlock[j] != *(blk_ptr++)) {
+	printf("ARRAY ERROR: block %d\n", j);
+      }
+      temp = curBlock[j] - P_mean;
+#endif      
+      temp = *(blk_ptr++) - P_mean;
+      var[i] += (temp * temp);
+    }
+    var[i] /= DCTSIZE_SQ;
+  }
+  
+  /*  Choose the minimum variance from the 4 blocks and use as the activity */
+  var_sblk  = var[0];
+  for (i=1; i < 4; i++) {
+    var_sblk = (var_sblk < var[i] ? var_sblk : var[i]);
+  }
+  
+  
+  act_j = 1 + var_sblk;
+  total_act_j += act_j;
+  temp = (2 * act_j + avg_act);
+  N_act = ( (float) temp / (float) (act_j + 2*avg_act) );
+  
+  return;
+}
+
+
+
+
+/*============================================================================*
+ *
+ * getRateMode ()
+ *
+ *      Returns the rate mode- interpreted as either Fixed or Variable
+ *
+ * RETURNS:     integer
+ *
+ * SIDE EFFECTS:   none
+ *
+ *
+ *==========================================================================*/
+int getRateMode()
+{
+  return RateControlMode;
+}
+
+
+/*===========================================================================*
+ *
+ * setBitRate ()
+ *
+ *      Checks the string parsed from the parameter file.  Verifies
+ *  number and sets global values. MPEG standard specifies that bit rate
+ *	be rounded up to nearest 400 bits/sec.
+ *
+ * RETURNS:     nothing
+ *
+ * SIDE EFFECTS:   global variables
+ *
+ * NOTES:	Should this be in the 400-bit units used in sequence header?
+ *
+ *===========================================================================*/
+void setBitRate (const char * const charPtr)
+{
+  int rate, rnd;
+  
+  rate = atoi(charPtr);
+  if (rate > 0) {
+    RateControlMode = FIXED_RATE;
+  } else {
+    printf("Parameter File Error:  invalid BIT_RATE: \"%s\", defaults to Variable ratemode\n",
+	   charPtr);
+    RateControlMode = VARIABLE_RATE;
+    bit_rate = -1;
+  }
+  rnd = (rate % 400);
+  rate += (rnd ? 400 -rnd : 0); /* round UP to nearest 400 bps */
+  rate = (rate > MAX_BIT_RATE ? MAX_BIT_RATE : rate);
+  bit_rate = rate;
+  DBG_PRINT(("Bit rate is: %d\n", bit_rate));
+} 
+
+
+
+/*===========================================================================*
+ *
+ * getBitRate ()
+ *
+ *      Returns the bit rate read from the parameter file.  This is the
+ *  real rate in bits per second, not in 400 bit units as is written to
+ *  the sequence header.
+ *
+ * RETURNS:     int (-1 if Variable mode operation)
+ *
+ * SIDE EFFECTS:   none
+ *
+ *===========================================================================*/
+int getBitRate ()
+{
+  return bit_rate;
+}
+
+
+
+
+/*===========================================================================*
+ *
+ * setBufferSize ()
+ *
+ *      Checks the string parsed from the parameter file.  Verifies
+ *  number and sets global values.
+ *
+ * RETURNS:     nothing
+ *
+ * SIDE EFFECTS:   buffer_size global variable.
+ *
+ * NOTES:	The global is in bits, NOT the 16kb units used in sequence header
+ *
+ *===========================================================================*/
+void setBufferSize (const char * const charPtr)
+{
+  int size;
+  
+  size = atoi(charPtr);
+  size = (size > MAX_BUFFER_SIZE ? MAX_BUFFER_SIZE : size);
+  if (size > 0) {
+    size = (16*1024) * ((size + (16*1024 - 1)) / (16*1024));
+    buffer_size = size;
+  } else {
+    buffer_size = DEFAULT_BUFFER_SIZE;
+    printf("Parameter File Error:  invalid BUFFER_SIZE: \"%s\", defaults to : %d\n",
+	   charPtr, buffer_size);
+  }
+  DBG_PRINT(("Buffer size is: %d\n", buffer_size));
+}
+
+
+/*===========================================================================*
+ *
+ * getBufferSize ()
+ *
+ *      returns the buffer size read from the parameter file.  Size is
+ *  in bits- not in units of 16k as written to the sequence header.
+ *
+ * RETURNS:     int (or -1 if invalid)
+ *
+ * SIDE EFFECTS:   none
+ *
+ *===========================================================================*/
+int getBufferSize ()
+{
+  return buffer_size;
+}
+
+
+
diff --git a/converter/ppm/ppmtompeg/readframe.c b/converter/ppm/ppmtompeg/readframe.c
new file mode 100644
index 00000000..d1423c1f
--- /dev/null
+++ b/converter/ppm/ppmtompeg/readframe.c
@@ -0,0 +1,1016 @@
+/*===========================================================================*
+ * readframe.c                    
+ *                                
+ *  procedures to read in frames  
+ *                                
+ * EXPORTED PROCEDURES:           
+ *  ReadFrame                     
+ *  SetFileType                   
+ *  SetFileFormat                 
+ *                                
+ *===========================================================================*/
+
+/* COPYRIGHT INFORMATION IS AT THE END OF THIS FILE */
+
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#define _BSD_SOURCE   /* Make sure popen() is in stdio.h */
+#include "all.h"
+#include <time.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include "ppm.h"
+#include "nstring.h"
+
+#include "mtypes.h"
+#include "frames.h"
+#include "prototypes.h"
+#include "parallel.h"
+#include "param.h"
+#include "input.h"
+#include "fsize.h"
+#include "rgbtoycc.h"
+#include "jpeg.h"
+#include "opts.h"
+#include "readframe.h"
+
+
+/*==================*
+ * STATIC VARIABLES *
+ *==================*/
+
+static int  fileType = BASE_FILE_TYPE;
+struct YuvLine {
+    uint8   data[3072];
+    uint8   y[1024];
+    int8    cr[1024];
+    int8    cb[1024];
+};
+
+
+/*==================*
+ * Portability      *
+ *==================*/
+#ifdef __OS2__
+  #define popen _popen
+#endif
+   
+
+/*==================*
+ * Global VARIABLES *
+ *==================*/
+
+extern boolean GammaCorrection;
+extern float GammaValue;
+extern int outputWidth,outputHeight;
+boolean resizeFrame;
+const char *CurrFile;
+
+/*===============================*
+ * INTERNAL PROCEDURE prototypes *
+ *===============================*/
+
+static void ReadEYUV _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer,
+                 int width, int height));
+static void ReadAYUV _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer,
+                 int width, int height));
+static void SeparateLine _ANSI_ARGS_((FILE *fpointer, struct YuvLine *lineptr,
+                     int width));
+static void ReadY _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer,
+                 int width, int height));
+static void ReadSub4 _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer,
+                  int width, int height));
+static void DoGamma  _ANSI_ARGS_((MpegFrame *mf, int width, int height));
+
+static void DoKillDim _ANSI_ARGS_((MpegFrame *mf, int w, int h));
+
+#define safe_fread(ptr,sz,len,fileptr)                           \
+    if ((safe_read_count=fread(ptr,sz,len,fileptr))!=sz*len) {   \
+      fprintf(stderr,"Input file too small! (%s)\n",CurrFile);   \
+      exit(1);}                                                  \
+
+/*=====================*
+ * EXPORTED PROCEDURES *
+ *=====================*/
+
+
+
+void    
+SetResize(bool const set) {
+    resizeFrame = set;
+}
+
+
+
+static void
+ReadPNM(MpegFrame * const mpegFrameP,
+        FILE *      const fp) {
+/*----------------------------------------------------------------------------
+   Read a PPM file containing one movie frame.
+-----------------------------------------------------------------------------*/
+    int pnmCols, pnmRows;
+    xelval maxval;
+    xel ** xels;
+
+    xels = ppm_readppm(fp, &pnmCols, &pnmRows, &maxval);
+    ERRCHK(mpegFrameP, "ppm_readppm");
+
+    /*
+     * if this is the first frame read, set the global frame size
+     */
+    Fsize_Note(mpegFrameP->id, pnmCols, pnmRows);
+
+    PNMtoYUV(mpegFrameP, xels, Fsize_x, Fsize_y, maxval);
+    ppm_freearray(xels, pnmRows);
+}
+
+
+
+static void
+openFile(struct inputSource * const inputSourceP,
+         unsigned int         const frameNumber,
+         const char *         const conversion, 
+         FILE **              const ifPP) {
+
+    if (inputSourceP->stdinUsed) {
+        if (fileType == ANY_FILE_TYPE)
+            pm_error(
+                "ERROR : You cannot use a converter on frames when "
+                "you supply them as Standard Input.  Either specify "
+                "INPUT_CONVERTER * in the parameter file or supply the "
+                "frames in files by specifying a directory with "
+                "INPUT_DIRECTORY in the parameter file.");
+        
+        *ifPP = stdin;
+    } else {
+        const char * fileName;
+        const char * fullFileName;
+        
+        GetNthInputFileName(inputSourceP, frameNumber, &fileName);
+        
+        asprintfN(&fullFileName, "%s/%s", currentPath, fileName);
+        
+        CurrFile = fullFileName;
+        
+        if (fileType == ANY_FILE_TYPE) {
+            char command[1024];
+            const char * convertPtr;
+            char * commandPtr;
+            const char * charPtr;
+            
+            /* replace every occurrence of '*' with fullFileName */
+            convertPtr = conversion;
+            commandPtr = command;
+            while (*convertPtr != '\0') {
+                while ((*convertPtr != '\0') && (*convertPtr != '*')) {
+                    *commandPtr = *convertPtr;
+                    ++commandPtr;
+                    ++convertPtr;
+                }
+                
+                if (*convertPtr == '*') {
+                    /* copy fullFileName */
+                    charPtr = fullFileName;
+                    while (*charPtr != '\0') {
+                        *commandPtr = *charPtr;
+                        ++commandPtr;
+                        ++charPtr;
+                    }
+                    ++convertPtr;   /* go past '*' */
+                }
+            }
+            *commandPtr = '\0';
+            
+            *ifPP = popen(command, "r");
+            if (*ifPP == NULL) {
+                pm_message(
+                    "ERROR:  Couldn't execute input conversion command "
+                    "'%s'.  errno=%d (%s)",
+                    command, errno, strerror(errno));
+                if (ioServer)
+                    pm_error("IO SERVER:  EXITING!!!");
+                else
+                    pm_error("SLAVE EXITING!!!");
+            }
+        } else {
+            *ifPP = fopen(fullFileName, "rb");
+            if (*ifPP == NULL)
+                pm_error("Couldn't open input file '%s'", fullFileName);
+            
+            if (baseFormat == JMOVIE_FILE_TYPE)
+                unlink(fullFileName);
+        }
+        strfree(fullFileName);
+        strfree(fileName);
+    }
+}
+
+
+
+static void
+closeFile(struct inputSource * const inputSourceP,
+          FILE *               const ifP) {
+
+    if (!inputSourceP->stdinUsed) {
+        if (fileType == ANY_FILE_TYPE) {
+            int rc;
+            rc = pclose(ifP);
+            if (rc != 0)
+                pm_message("WARNING:  pclose() failed with errno %d (%s)",
+                           errno, strerror(errno));
+        } else
+            fclose(ifP);
+    }
+}
+
+
+
+static bool
+fileIsAtEnd(FILE * const ifP) {
+
+    int c;
+    bool eof;
+
+    c = getc(ifP);
+    if (c == EOF) {
+        if (feof(ifP)) 
+            eof = TRUE;
+        else
+            pm_error("File error on getc() to position to image");
+    } else {
+        int rc;
+
+        eof = FALSE;
+
+        rc = ungetc(c, ifP);
+        if (rc == EOF) 
+            pm_error("File error doing ungetc() to position to image.");
+    }
+    return eof;
+}
+
+
+
+void
+ReadFrameFile(MpegFrame *  const frameP,
+              FILE *       const ifP,
+              const char * const conversion,
+              bool *       const eofP) {
+/*----------------------------------------------------------------------------
+   Read a frame from the file 'ifP'.
+
+   Return *eofP == TRUE iff we encounter EOF before we can get the
+   frame.
+-----------------------------------------------------------------------------*/
+    MpegFrame   tempFrame;
+    MpegFrame * framePtr;
+
+    /* To make this code fit Netpbm properly, we should remove handling
+       of all types except PNM and use pm_nextimage() to handle sensing
+       of end of stream.
+    */
+
+    if (fileIsAtEnd(ifP))
+        *eofP = TRUE;
+    else {
+        *eofP = FALSE;
+
+        if (resizeFrame) {
+            tempFrame.inUse = FALSE;
+            tempFrame.orig_y = NULL;
+            tempFrame.y_blocks = NULL;
+            tempFrame.decoded_y = NULL;
+            tempFrame.halfX = NULL;
+            framePtr = &tempFrame;
+        } else
+            framePtr = frameP;
+
+        switch(baseFormat) {
+        case YUV_FILE_TYPE:
+
+            /* Encoder YUV */
+            if ((strncmp (yuvConversion, "EYUV", 4) == 0) ||
+                (strncmp (yuvConversion, "UCB", 3) == 0)) 
+
+                ReadEYUV(framePtr, ifP, realWidth, realHeight);
+
+            else
+                /* Abekas-type (interlaced) YUV */
+                ReadAYUV(framePtr, ifP, realWidth, realHeight);
+
+            break;
+        case Y_FILE_TYPE:
+            ReadY(framePtr, ifP, realWidth, realHeight);
+            break;
+        case PNM_FILE_TYPE:
+            ReadPNM(framePtr, ifP);
+            break;
+        case SUB4_FILE_TYPE:
+            ReadSub4(framePtr, ifP, yuvWidth, yuvHeight);
+            break;
+        case JPEG_FILE_TYPE:
+        case JMOVIE_FILE_TYPE:
+            ReadJPEG(framePtr, ifP);
+            break;
+        default:
+            break;
+        }
+
+        if (resizeFrame)
+            Frame_Resize(frameP, &tempFrame, Fsize_x, Fsize_y, 
+                         outputWidth, outputHeight);
+    
+        if (GammaCorrection)
+            DoGamma(frameP, Fsize_x, Fsize_y);
+
+        if (kill_dim)
+            DoKillDim(frameP, Fsize_x, Fsize_y);
+
+        MotionSearchPreComputation(frameP);
+    }
+}
+
+
+
+void
+ReadFrame(MpegFrame *          const frameP, 
+          struct inputSource * const inputSourceP,
+          unsigned int         const frameNumber,
+          const char *         const conversion,
+          bool *               const endOfStreamP) {
+/*----------------------------------------------------------------------------
+   Read the given frame, performing conversion as necessary.
+-----------------------------------------------------------------------------*/
+    FILE * ifP;
+
+    openFile(inputSourceP, frameNumber, conversion, &ifP);
+
+    ReadFrameFile(frameP, ifP, conversion, endOfStreamP);
+
+    if (*endOfStreamP && !inputSourceP->stdinUsed)
+        pm_error("Premature EOF on file containing Frame %u", frameNumber);
+
+    closeFile(inputSourceP, ifP);
+}
+
+
+
+/*===========================================================================*
+ *
+ * SetFileType
+ *
+ *  set the file type to be either a base type (no conversion), or
+ *  any type (conversion required)
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    fileType
+ *
+ *===========================================================================*/
+void
+SetFileType(const char * const conversion)
+{
+    if ( strcmp(conversion, "*") == 0 ) {
+    fileType = BASE_FILE_TYPE;
+    } else {
+    fileType = ANY_FILE_TYPE;
+    }
+}
+
+
+/*===========================================================================*
+ *
+ * SetFileFormat
+ *
+ *  set the file format (PNM, YUV, JPEG)
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    baseFormat
+ *
+ *===========================================================================*/
+void
+SetFileFormat(const char * const format)
+{
+    if ( strcmp(format, "PPM") == 0 ) {
+    baseFormat = PNM_FILE_TYPE;
+    } else if ( strcmp(format, "YUV") == 0 ) {
+    baseFormat = YUV_FILE_TYPE;
+    } else if ( strcmp(format, "Y") == 0 ) {
+    baseFormat = Y_FILE_TYPE;
+    } else if ( strcmp(format, "PNM") == 0 ) {
+    baseFormat = PNM_FILE_TYPE;
+    } else if (( strcmp(format, "JPEG") == 0 ) || ( strcmp(format, "JPG") == 0 )) {
+    baseFormat = JPEG_FILE_TYPE;
+    } else if ( strcmp(format, "JMOVIE") == 0 ) {
+    baseFormat = JMOVIE_FILE_TYPE;
+    } else if ( strcmp(format, "SUB4") == 0 ) {
+    baseFormat = SUB4_FILE_TYPE;
+    } else {
+    fprintf(stderr, "ERROR:  Invalid file format:  %s\n", format);
+    exit(1);
+    }
+}
+
+
+
+FILE *
+ReadIOConvert(struct inputSource * const inputSourceP,
+              unsigned int         const frameNumber) {
+/*----------------------------------------------------------------------------
+   Do conversion; return handle to the appropriate file.
+-----------------------------------------------------------------------------*/
+    FILE    *ifp;
+    char    command[1024];
+    const char * fullFileName;
+    char *convertPtr, *commandPtr;
+    const char * fileName;
+
+    GetNthInputFileName(inputSourceP, frameNumber, &fileName);
+
+    asprintfN(&fullFileName, "%s/%s", currentPath, fileName);
+
+    if ( strcmp(ioConversion, "*") == 0 ) {
+        char buff[1024];
+        ifp = fopen(fullFileName, "rb");
+        sprintf(buff,"fopen \"%s\"",fullFileName);
+        ERRCHK(ifp, buff);
+        return ifp;
+    }
+
+    /* replace every occurrence of '*' with fullFileName */
+    convertPtr = ioConversion;
+    commandPtr = command;
+    while ( *convertPtr != '\0' ) {
+        while ( (*convertPtr != '\0') && (*convertPtr != '*') ) {
+            *commandPtr = *convertPtr;
+            commandPtr++;
+            convertPtr++;
+        }
+
+        if ( *convertPtr == '*' ) {
+            /* copy fullFileName */
+            const char * charPtr;
+            charPtr = fullFileName;
+            while ( *charPtr != '\0' ) {
+                *commandPtr = *charPtr;
+                commandPtr++;
+                charPtr++;
+            }
+
+            convertPtr++;   /* go past '*' */
+        }
+    }
+    *commandPtr = '\0';
+
+    if ( (ifp = popen(command, "r")) == NULL ) {
+        fprintf(stderr, "ERROR:  "
+                "Couldn't execute input conversion command:\n");
+        fprintf(stderr, "\t%s\n", command);
+        fprintf(stderr, "errno = %d\n", errno);
+        if ( ioServer ) {
+            fprintf(stderr, "IO SERVER:  EXITING!!!\n");
+        } else {
+            fprintf(stderr, "SLAVE EXITING!!!\n");
+        }
+        exit(1);
+    }
+
+    strfree(fullFileName);
+    strfree(fileName);
+
+    return ifp;
+}
+
+
+
+/*===========================================================================*
+ *
+ * ReadEYUV
+ *
+ *  read a Encoder-YUV file (concatenated Y, U, and V)
+ *
+ * RETURNS: mf modified
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+ReadEYUV(mf, fpointer, width, height)
+    MpegFrame *mf;
+    FILE *fpointer;
+    int width;
+    int height;
+{
+    register int y;
+    uint8   junk[4096];
+    int     safe_read_count;
+
+    Fsize_Note(mf->id, width, height);
+
+    Frame_AllocYCC(mf);
+
+    for (y = 0; y < Fsize_y; y++) {         /* Y */
+    safe_fread(mf->orig_y[y], 1, Fsize_x, fpointer);
+
+    /* read the leftover stuff on the right side */
+    if ( width != Fsize_x ) {
+        safe_fread(junk, 1, width-Fsize_x, fpointer);
+    }
+    }
+
+    /* read the leftover stuff on the bottom */
+    for (y = Fsize_y; y < height; y++) {
+    safe_fread(junk, 1, width, fpointer);
+    }
+
+    for (y = 0; y < (Fsize_y >> 1); y++) {          /* U */
+    safe_fread(mf->orig_cb[y], 1, Fsize_x >> 1, fpointer);
+
+    /* read the leftover stuff on the right side */
+    if ( width != Fsize_x ) {
+        safe_fread(junk, 1, (width-Fsize_x)>>1, fpointer);
+    }
+    }
+
+    /* read the leftover stuff on the bottom */
+    for (y = (Fsize_y >> 1); y < (height >> 1); y++) {
+    safe_fread(junk, 1, width>>1, fpointer);
+    }
+
+    for (y = 0; y < (Fsize_y >> 1); y++) {          /* V */
+    safe_fread(mf->orig_cr[y], 1, Fsize_x >> 1, fpointer);
+
+    /* read the leftover stuff on the right side */
+    if ( width != Fsize_x ) {
+        safe_fread(junk, 1, (width-Fsize_x)>>1, fpointer);
+    }
+    }
+
+    /* ignore leftover stuff on the bottom */
+}
+
+/*===========================================================================*
+ *
+ * ReadAYUV
+ *
+ *  read an Abekas-YUV file
+ *
+ * RETURNS: mf modified
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+ReadAYUV(mf, fpointer, width, height)
+    MpegFrame *mf;
+    FILE *fpointer;
+    int width;
+    int height;
+{
+    register int x, y;
+    struct  YuvLine line1, line2;
+    uint8   junk[4096];
+    uint8    *cbptr, *crptr;
+    int     safe_read_count;
+
+    Fsize_Note(mf->id, width, height);
+
+    Frame_AllocYCC(mf);
+
+    for (y = 0; y < Fsize_y; y += 2) {
+    SeparateLine(fpointer, &line1, width);
+    SeparateLine(fpointer, &line2, width);
+
+    /* Copy the Y values for each line to the frame */
+    for (x = 0; x < Fsize_x; x++) {
+        mf->orig_y[y][x]   = line1.y[x];
+        mf->orig_y[y+1][x] = line2.y[x];
+    }
+
+    cbptr = &(mf->orig_cb[y>>1][0]);
+    crptr = &(mf->orig_cr[y>>1][0]);
+
+    /* One U and one V for each two pixels horizontal as well */
+    /* Toss the second line of Cr/Cb info, averaging was worse,
+       so just subsample */
+    for (x = 0; x < (Fsize_x >> 1); x ++) {
+        cbptr[x] =  line1.cb[x];
+        crptr[x] =  line1.cr[x];
+
+    }
+    }
+
+    /* read the leftover stuff on the bottom */
+    for (y = Fsize_y; y < height; y++) {
+    safe_fread(junk, 1, width<<1, fpointer);
+    }
+
+}
+
+/*===========================================================================*
+ *
+ * SeparateLine
+ *
+ *  Separates one line of pixels into Y, U, and V components
+ *
+ * RETURNS: lineptr modified
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+SeparateLine(fpointer, lineptr, width)
+    FILE *fpointer;
+    struct YuvLine *lineptr;
+    int width;
+{
+    uint8   junk[4096];
+    int8    *crptr, *cbptr;
+    uint8   *yptr;
+    int     num, length;
+    int     safe_read_count;
+
+
+    /* Sets the deinterlacing pattern */
+
+    /* shorthand for UYVY */
+    if (strncmp(yuvConversion, "ABEKAS", 6) == 0) {
+    strcpy(yuvConversion, "UYVY");
+
+    /* shorthand for YUYV */
+    } else if (strncmp(yuvConversion, "PHILLIPS", 8) == 0) {
+    strcpy(yuvConversion, "YUYV");
+    }
+
+    length = strlen (yuvConversion);
+
+    if ((length % 2) != 0) {
+    fprintf (stderr, "ERROR : YUV_FORMAT must represent two pixels, hence must be even in length.\n");
+    exit(1);
+    }
+
+    /* each line in 4:2:2 chroma format takes 2X bytes to represent X pixels.
+     * each line in 4:4:4 chroma format takes 3X bytes to represent X pixels.
+     * Therefore, half of the length of the YUV_FORMAT represents 1 pixel.
+     */
+    safe_fread(lineptr->data, 1, Fsize_x*(length>>1), fpointer);
+
+    /* read the leftover stuff on the right side */
+    if ( width != Fsize_x ) {
+    safe_fread(junk, 1, (width-Fsize_x)*(length>>1), fpointer);
+    }
+
+    crptr = &(lineptr->cr[0]);
+    cbptr = &(lineptr->cb[0]);
+    yptr = &(lineptr->y[0]);
+
+    for (num = 0; num < (Fsize_x*(length>>1)); num++) {
+    switch (yuvConversion[num % length]) {
+    case 'U':
+    case 'u':
+        *(cbptr++) = (lineptr->data[num]);
+        break;
+    case 'V':
+    case 'v':
+        *(crptr++) = (lineptr->data[num]);
+        break;
+    case 'Y':
+    case 'y':
+        *(yptr++) = (lineptr->data[num]);
+        break;
+    default:
+            fprintf(stderr, "ERROR: YUV_FORMAT must be one of the following:\n");
+            fprintf(stderr, "       ABEKAS\n");
+            fprintf(stderr, "       EYUV\n");
+            fprintf(stderr, "       PHILLIPS\n");
+            fprintf(stderr, "       UCB\n");
+        fprintf(stderr, "       or any even-length string consisting of the letters U, V, and Y.\n");
+            exit(1);
+        }
+    
+    }
+
+}
+
+
+/*===========================================================================*
+ *
+ * ReadY
+ *
+ *  read a Y file
+ *
+ * RETURNS: mf modified
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+ReadY(mf, fpointer, width, height)
+    MpegFrame *mf;
+    FILE *fpointer;
+    int width;
+    int height;
+{
+    register int y;
+    uint8   junk[4096];
+    int     safe_read_count;
+
+    Fsize_Note(mf->id, width, height);
+
+    Frame_AllocYCC(mf);
+
+    for (y = 0; y < Fsize_y; y++) {         /* Y */
+    safe_fread(mf->orig_y[y], 1, Fsize_x, fpointer);
+
+    /* read the leftover stuff on the right side */
+    if ( width != Fsize_x ) {
+        safe_fread(junk, 1, width-Fsize_x, fpointer);
+    }
+    }
+
+    /* read the leftover stuff on the bottom */
+    for (y = Fsize_y; y < height; y++) {
+    safe_fread(junk, 1, width, fpointer);
+    }
+    
+    for (y = 0 ; y < (Fsize_y >> 1); y++) {
+      memset(mf->orig_cb[y], 128, (Fsize_x>>1));
+      memset(mf->orig_cr[y], 128, (Fsize_x>>1));
+    }
+}
+
+
+/*===========================================================================*
+ *
+ * ReadSub4
+ *
+ *  read a YUV file (subsampled even further by 4:1 ratio)
+ *
+ * RETURNS: mf modified
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+ReadSub4(mf, fpointer, width, height)
+    MpegFrame *mf;
+    FILE *fpointer;
+    int width;
+    int height;
+{
+    register int y;
+    register int x;
+    uint8   buffer[1024];
+    int     safe_read_count;
+
+    Fsize_Note(mf->id, width, height);
+
+    Frame_AllocYCC(mf);
+
+    for (y = 0; y < (height>>1); y++) {         /* Y */
+    safe_fread(buffer, 1, width>>1, fpointer);
+    for ( x = 0; x < (width>>1); x++ ) {
+        mf->orig_y[2*y][2*x] = buffer[x];
+        mf->orig_y[2*y][2*x+1] = buffer[x];
+        mf->orig_y[2*y+1][2*x] = buffer[x];
+        mf->orig_y[2*y+1][2*x+1] = buffer[x];
+    }
+    }
+
+    for (y = 0; y < (height >> 2); y++) {           /* U */
+    safe_fread(buffer, 1, width>>2, fpointer);
+    for ( x = 0; x < (width>>2); x++ ) {
+        mf->orig_cb[2*y][2*x] = buffer[x];
+        mf->orig_cb[2*y][2*x+1] = buffer[x];
+        mf->orig_cb[2*y+1][2*x] = buffer[x];
+        mf->orig_cb[2*y+1][2*x+1] = buffer[x];
+    }
+    }
+
+    for (y = 0; y < (height >> 2); y++) {           /* V */
+    safe_fread(buffer, 1, width>>2, fpointer);
+    for ( x = 0; x < (width>>2); x++ ) {
+        mf->orig_cr[2*y][2*x] = buffer[x];
+        mf->orig_cr[2*y][2*x+1] = buffer[x];
+        mf->orig_cr[2*y+1][2*x] = buffer[x];
+        mf->orig_cr[2*y+1][2*x+1] = buffer[x];
+    }
+    }
+}
+
+
+/*=====================*
+ * INTERNAL PROCEDURES *
+ *=====================*/
+
+/*===========================================================================*
+ *
+ * DoGamma
+ *
+ *  Gamma Correct the Lum values
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    Raises Y values to power gamma.
+ *
+ *===========================================================================*/
+static void
+DoGamma(mf, w, h)
+MpegFrame *mf;
+int w,h;
+{
+  static int GammaVal[256];
+  static boolean init_done=FALSE;
+  int i,j;
+
+  if (!init_done) {
+    for(i=0; i<256; i++) 
+      GammaVal[i]=(unsigned char) (pow(((double) i)/255.0,GammaValue)*255.0+0.5);
+    init_done=TRUE;
+  }
+
+  for (i=0; i< h; i++) {  /* For each line */
+    for (j=0; j<w; j++) { /* For each Y value */
+      mf->orig_y[i][j] = GammaVal[mf->orig_y[i][j]];
+    }}
+}
+
+
+
+
+/*===========================================================================*
+ *
+ * DoKillDim
+ *
+ *  Applies an input filter to small Y values.
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    Changes Y values:
+ *
+ *  Output    |                 /
+              |                /
+              |               /
+              |              !
+              |             /
+              |            !
+              |           /
+              |          -
+              |        /
+              |      --
+              |     /
+              |   --
+              | /
+              ------------------------
+                        ^ kill_dim_break
+                             ^kill_dim_end
+              kill_dim_slope gives the slope (y = kill_dim_slope * x +0)
+              from 0 to kill_dim_break                      
+ *
+ *===========================================================================*/
+
+static void
+DoKillDim(mf, w, h)
+MpegFrame *mf;
+int w,h;
+{
+  static boolean init_done=FALSE;
+  static unsigned char mapper[256];
+  register int i,j;
+  double slope, intercept;
+
+  slope = (kill_dim_end - kill_dim_break*kill_dim_slope)*1.0 /
+    (kill_dim_end - kill_dim_break);
+  intercept = kill_dim_end * (1.0-slope);
+
+  if (!init_done) {
+    for(i=0; i<256; i++) {
+      if (i >= kill_dim_end) {
+        mapper[i] = (char) i;
+      } else if (i >= kill_dim_break) {
+        mapper[i] = (char) (slope*i + intercept);
+      } else { /* i <= kill_dim_break */
+        mapper[i] = (char) floor(i*kill_dim_slope + 0.49999);
+      }
+    }
+    init_done = TRUE;
+  }
+
+  for (i=0;  i < h;  i++) {  /* For each line */
+    for (j=0;   j < w;   j++) { /* For each Y value */
+      mf->orig_y[i][j] = mapper[mf->orig_y[i][j]];
+    }}
+}
+
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*  
+ *  $Header: /n/picasso/project/mpeg/mpeg_dist/mpeg_encode/RCS/readframe.c,v 1.27 1995/08/14 22:31:40 smoot Exp $
+ *  $Log: readframe.c,v $
+ *  Revision 1.27  1995/08/14 22:31:40  smoot
+ *  reads training info from PPms now (needed for piping reads)
+ *
+ *  Revision 1.26  1995/08/07 21:48:36  smoot
+ *  better error reporting, JPG == JPEG now
+ *
+ *  Revision 1.25  1995/06/12 20:30:12  smoot
+ *  added popen for OS2
+ *
+ * Revision 1.24  1995/06/08  20:34:36  smoot
+ * added "b"'s to fopen calls to make MSDOS happy
+ *
+ * Revision 1.23  1995/05/03  10:16:01  smoot
+ * minor compile bug with static f
+ *
+ * Revision 1.22  1995/05/02  22:00:12  smoot
+ * added TUNEing, setting near-black values to black
+ *
+ * Revision 1.21  1995/03/27  21:00:01  eyhung
+ * fixed bug with some long jpeg names
+ *
+ * Revision 1.20  1995/02/02  01:05:54  eyhung
+ * Fixed aAdded error checking for stdin
+ *
+ * Revision 1.19  1995/02/01  05:01:12  eyhung
+ * Removed troubleshooting printf
+ *
+ * Revision 1.18  1995/01/31  21:08:16  eyhung
+ * Improved YUV_FORMAT strings with better algorithm
+ *
+ * Revision 1.17  1995/01/27  23:34:09  eyhung
+ * Removed temporary JPEG files created by JMOVIE input
+ *
+ * Revision 1.16  1995/01/27  21:57:43  eyhung
+ * Added case for reading original JMOVIES
+ *
+ * Revision 1.14  1995/01/24  23:47:51  eyhung
+ * Confusion with Abekas format fixed : all other YUV revisions are wrong
+ *
+ * Revision 1.13  1995/01/20  00:02:30  smoot
+ * added gamma correction
+ *
+ * Revision 1.12  1995/01/19  23:09:21  eyhung
+ * Changed copyrights
+ *
+ * Revision 1.11  1995/01/17  22:23:07  aswan
+ * AbekasYUV chrominance implementation fixed
+ *
+ * Revision 1.10  1995/01/17  21:26:25  smoot
+ * Tore our average on Abekus/Phillips reconstruct
+ *
+ * Revision 1.9  1995/01/17  08:22:34  eyhung
+ * Debugging of ReadAYUV
+ *
+ * Revision 1.8  1995/01/16  13:18:24  eyhung
+ * Interlaced YUV format (e.g. Abekas) capability added (slightly buggy)
+ *
+ * Revision 1.7  1995/01/16  06:58:23  eyhung
+ * Added skeleton of ReadAYUV (for Abekas YUV files)
+ *
+ * Revision 1.6  1995/01/13  23:22:23  smoot
+ * Added ReadY, so we can make black&white movies (how artsy!)
+ *
+ * Revision 1.5  1994/12/16  00:20:40  smoot
+ * Now errors out on too small an input file
+ *
+ * Revision 1.4  1994/11/12  02:11:59  keving
+ * nothing
+ *
+ * Revision 1.3  1994/03/15  00:27:11  keving
+ * nothing
+ *
+ * Revision 1.2  1993/12/22  19:19:01  keving
+ * nothing
+ *
+ * Revision 1.1  1993/07/22  22:23:43  keving
+ * nothing
+ *
+ */
diff --git a/converter/ppm/ppmtompeg/rgbtoycc.c b/converter/ppm/ppmtompeg/rgbtoycc.c
new file mode 100644
index 00000000..766b8902
--- /dev/null
+++ b/converter/ppm/ppmtompeg/rgbtoycc.c
@@ -0,0 +1,204 @@
+/*===========================================================================*
+ * rgbtoycc.c                                    *
+ *                                       *
+ *  Procedures to convert from RGB space to YUV space            *
+ *                                       *
+ * EXPORTED PROCEDURES:                              *
+ *  PNMtoYUV                                 *
+ *  PPMtoYUV                                 *
+ *                                       *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "pnm.h"
+#include "all.h"
+#include "frame.h"
+#include "rgbtoycc.h"
+
+
+static float *mult299, *mult587, *mult114, *mult16874, *mult33126,
+    *mult5, *mult41869, *mult08131;  /* malloc'ed */
+    /* These are tables we use for fast arithmetic */
+static pixval table_maxval = 0;
+    /* The maxval used to compute the above arrays.  Zero means
+       the above arrays don't exist yet
+    */
+
+static void
+compute_mult_tables(const pixval maxval) {
+
+    /* For speed, we do the arithmetic with eight tables that reduce a
+       bunch of multiplications and divisions to a simple table lookup.
+       
+       Because a large maxval could require a significant amount of
+       table space, we allocate the space dynamically.
+
+       If we had to compute the tables for every frame, it wouldn't be 
+       fast at all, but since all the frames normally have the same
+       maxval, we only need to compute them once.  But just in case,
+       we check each frame to see if it has a different maxval and
+       recompute the tables if so.
+    */
+    
+    if (table_maxval != maxval) {
+        /* We need to compute or re-compute the multiplication tables */
+        if (table_maxval != 0) {
+            free(mult299); free(mult587); free(mult114); free(mult16874);
+            free(mult33126); free(mult5); free(mult41869); free(mult08131);  
+        } 
+        table_maxval = maxval;
+
+        mult299   = malloc((table_maxval+1)*sizeof(float));
+        mult587   = malloc((table_maxval+1)*sizeof(float));
+        mult114   = malloc((table_maxval+1)*sizeof(float));
+        mult16874 = malloc((table_maxval+1)*sizeof(float));
+        mult33126 = malloc((table_maxval+1)*sizeof(float));
+        mult5     = malloc((table_maxval+1)*sizeof(float));
+        mult41869 = malloc((table_maxval+1)*sizeof(float));
+        mult08131 = malloc((table_maxval+1)*sizeof(float));
+
+        if (mult299 == NULL || mult587 == NULL || mult114 == NULL ||
+            mult16874 == NULL || mult33126 == NULL || mult5 == NULL ||
+            mult41869 == NULL || mult08131 == NULL) 
+            pm_error("Unable to allocate storage for arithmetic tables.\n"
+                     "We need %d bytes, which is the maxval of the input "
+                     "image, plus 1,\n"
+                     "times the storage size of a floating point value.", 
+                     8 * (table_maxval+1)*sizeof(float));
+
+        {
+            int index;
+
+            for (index = 0; index <= table_maxval; index++ ) {
+                mult299[index]   = index*0.29900  * 255 / table_maxval; 
+                mult587[index]   = index*0.58700  * 255 / table_maxval;
+                mult114[index]   = index*0.11400  * 255 / table_maxval;
+                mult16874[index] = -0.16874*index * 255 / table_maxval;
+                mult33126[index] = -0.33126*index * 255 / table_maxval;
+                mult5[index]     = index*0.50000  * 255 / table_maxval;
+                mult41869[index] = -0.41869*index * 255 / table_maxval;
+                mult08131[index] = -0.08131*index * 255 / table_maxval;
+            }
+        }
+    }
+}
+
+
+/*=====================*
+ * EXPORTED PROCEDURES *
+ *=====================*/
+
+
+void
+PNMtoYUV(MpegFrame *  const frameP,
+         xel **       const xels,
+         unsigned int const cols,
+         unsigned int const rows,
+         xelval       const maxval) {
+/*----------------------------------------------------------------------------
+   Set the raster of the MPEG frame *frameP from the libnetpbm input
+   'xels'.  Note that the raster information in a MpegFrame is in YUV
+   form.
+-----------------------------------------------------------------------------*/
+    int x, y;
+    uint8 *dy0, *dy1;
+    uint8 *dcr, *dcb;
+    pixel *src0, *src1;
+
+    compute_mult_tables(maxval);  /* This sets up mult299[], etc. */
+
+    Frame_AllocYCC(frameP);
+
+    /*
+     * okay.  Now, convert everything into YCbCr space. (the specific
+     * numbers come from the JPEG source, jccolor.c) The conversion
+     * equations to be implemented are therefore
+     *
+     * Y  =  0.29900 * R + 0.58700 * G + 0.11400 * B
+     * Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B
+     * Cr =  0.50000 * R - 0.41869 * G - 0.08131 * B
+     *
+     * With Y, Cb, and Cr then normalized to the range 0 - 255.
+     */
+
+    for (y = 0; y < rows; y += 2) {
+        for (x = 0, src0 = xels[y], src1 = xels[y + 1],
+                 dy0 = frameP->orig_y[y], dy1 = frameP->orig_y[y + 1],
+                 dcr = frameP->orig_cr[y >> 1], dcb = frameP->orig_cb[y >> 1];
+             x < cols;
+             x += 2, dy0 += 2, dy1 += 2, dcr++,
+                 dcb++, src0 += 2, src1 += 2) {
+
+            *dy0 = (mult299[PPM_GETR(*src0)] +
+                    mult587[PPM_GETG(*src0)] +
+                    mult114[PPM_GETB(*src0)]);
+
+            *dy1 = (mult299[PPM_GETR(*src1)] +
+                    mult587[PPM_GETG(*src1)] +
+                    mult114[PPM_GETB(*src1)]);
+
+            dy0[1] = (mult299[PPM_GETR(src0[1])] +
+                      mult587[PPM_GETG(src0[1])] +
+                      mult114[PPM_GETB(src0[1])]);
+
+            dy1[1] = (mult299[PPM_GETR(src1[1])] +
+                      mult587[PPM_GETG(src1[1])] +
+                      mult114[PPM_GETB(src1[1])]);
+
+            *dcb = ((mult16874[PPM_GETR(*src0)] +
+                     mult33126[PPM_GETG(*src0)] +
+                     mult5[PPM_GETB(*src0)] +
+                     mult16874[PPM_GETR(*src1)] +
+                     mult33126[PPM_GETG(*src1)] +
+                     mult5[PPM_GETB(*src1)] +
+                     mult16874[PPM_GETR(src0[1])] +
+                     mult33126[PPM_GETG(src0[1])] +
+                     mult5[PPM_GETB(src0[1])] +
+                     mult16874[PPM_GETR(src1[1])] +
+                     mult33126[PPM_GETG(src1[1])] +
+                     mult5[PPM_GETB(src1[1])]) / 4) + 128;
+
+            *dcr = ((mult5[PPM_GETR(*src0)] +
+                     mult41869[PPM_GETG(*src0)] +
+                     mult08131[PPM_GETB(*src0)] +
+                     mult5[PPM_GETR(*src1)] +
+                     mult41869[PPM_GETG(*src1)] +
+                     mult08131[PPM_GETB(*src1)] +
+                     mult5[PPM_GETR(src0[1])] +
+                     mult41869[PPM_GETG(src0[1])] +
+                     mult08131[PPM_GETB(src0[1])] +
+                     mult5[PPM_GETR(src1[1])] +
+                     mult41869[PPM_GETG(src1[1])] +
+                     mult08131[PPM_GETB(src1[1])]) / 4) + 128;
+
+            DBG_PRINT(("%3d,%3d: (%3d,%3d,%3d) --> (%3d,%3d,%3d)\n", 
+                       x, y, 
+                       PPM_GETR(*src0), PPM_GETG(*src0), PPM_GETB(*src0), 
+                       *dy0, *dcb, *dcr));
+        }
+    }
+}
diff --git a/converter/ppm/ppmtompeg/specifics.c b/converter/ppm/ppmtompeg/specifics.c
new file mode 100644
index 00000000..c7bbfb5b
--- /dev/null
+++ b/converter/ppm/ppmtompeg/specifics.c
@@ -0,0 +1,688 @@
+/*===========================================================================*
+ * specifics.c								     *
+ *									     *
+ *	basic procedures to deal with the specifics file                     *
+ *									     *
+ * EXPORTED PROCEDURES:							     *
+ *	Specifics_Init							     *
+ *      Spec_Lookup                                                          *
+ *      SpecTypeLookup                                                       *
+ *									     *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "all.h"
+#include "mtypes.h"
+#include "frames.h"
+#include "frame.h"
+#include "fsize.h"
+#include "dct.h"
+#include "specifics.h"
+#include <stdio.h>
+#include <string.h>
+#include "prototypes.h"
+
+/*====================*
+ * System Information *
+ *====================*/
+
+#define CPP_LOC "/lib/cpp"
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+
+extern boolean specificsOn;
+extern char specificsFile[];
+extern char specificsDefines[];
+FrameSpecList *fsl;
+
+/*=====================*
+ * Internal procedures *
+ *=====================*/
+
+void Parse_Specifics_File _ANSI_ARGS_((FILE *fp));
+void Parse_Specifics_File_v1 _ANSI_ARGS_((FILE *fp));
+void Parse_Specifics_File_v2 _ANSI_ARGS_((FILE *fp));
+FrameSpecList *MakeFslEntry _ANSI_ARGS_((void));
+void AddSlc _ANSI_ARGS_((FrameSpecList *c,int snum, int qs));
+Block_Specifics *AddBs _ANSI_ARGS_((FrameSpecList *c,int bnum, 
+				    boolean rel, int qs));
+FrameSpecList *MakeFslEntry _ANSI_ARGS_((void));
+#define my_upper(c) (((c>='a') && (c<='z')) ? (c-'a'+'A') : c)
+#define CvtType(x) ReallyCvt(my_upper(x))
+#define ReallyCvt(x) (x=='I' ? 1 : (x=='P')?2: ((x=='B')?3:-1))
+#define SkipToSpace(lp) while ((*lp != ' ') && (*lp != '\n') && (*lp != '\0')) lp++
+#define EndString(lp)  ((*lp == '\n') || (*lp == '\0'))
+
+/*=============================================================
+ * SPEC FILE FORMAT (version 1):
+
+Specs files are processed with the c preprecoessor, so use C style comments
+and #defines if you wish.
+
+frames, blocks, and slices are numbered from 0.
+(sorry)
+
+In order by frame number, slice number, block number
+(if you skip slices it's fine).
+Can have specifics for any frame, block, or slice.
+Format:
+version N
+  Specify the version of the specifics file format (this is 1)
+frame N T M
+  Sets frame number N to type T and Qscale M
+  (type T is I,B,P,other, other means unspec.  I recomend - )
+slice M Q
+  Sets slice M (in frame N as defined by a previous frame command)
+  to qscale Q
+block M Q
+  Sets block M to qscale Q, in frame N previously specified.
+
+Unspecified frame types are set via the last I frame set, which is forced
+to act as the first I of the GOP.
+FORCE_ENCODE_LAST_FRAME overrides specifics on the final frame type.
+Note that Qscale changes in skipped blocks will be lost!
+
+Version 2:
+frames and slices are the same as above, but Q in blocks can be relative, i.e.
++N or -N.  Clipping to 1..31 is done but sequences like
+block 1 2
+block 2 -3
+block 3 +3
+
+has undefined results (as present block 3 would be Qscale 2).
+
+In addition motion vectors can be specified:
+block M Q skip
+  Says to skip the block  (not really an MV, but....)
+block M Q bi fx fy bx by
+  Sets block M to quality Q.  It will be a bidirectional block.
+  fx/fy is the forward (like a P frame) vector, bx/y is the back
+block M Q forw fx fy
+block M Q back bx by
+  Single directional.
+
+All vectors are specified in HALF PIXEL fixed point units, i.e.
+3.5 pixels is 7
+To specify a vector but not touch the q factor, set Q to 0
+
+*=============================================================*/
+
+
+/*=============*
+ * Local State *
+ *=============*/
+
+static char version = -1;
+
+/*================================================================
+ *
+ *   Specifics_Init
+ *
+ *   Cpp's and reads in the specifics file.  Creates fsl data structure.
+ *
+ *   Returns: nothing
+ * 
+ *   Modifies: fsl, file specificsFile".cpp"
+ *
+ *================================================================
+ */
+void Specifics_Init()
+{
+  char command[1100];
+  FILE *specificsFP;
+  
+  sprintf(command, "/bin/rm -f %s.cpp", specificsFile);
+  system(command);
+  sprintf(command, "%s -P %s %s %s.cpp",
+	  CPP_LOC, specificsDefines, specificsFile, specificsFile);
+  system(command);
+  strcat(specificsFile, ".cpp");
+  if ((specificsFP = fopen(specificsFile, "r")) == NULL) {
+    fprintf(stderr, "Error with specifics file, cannot open %s\n", specificsFile);
+    exit(1);
+  }
+  printf("Specifics file: %s\n", specificsFile);
+  Parse_Specifics_File(specificsFP);
+  sprintf(command, "/bin/rm -f %s.cpp", specificsFile);
+  system(command);
+
+}
+
+
+
+
+/*================================================================
+ *
+ *   Parse_Specifics_File
+ *
+ *   Read through the file passed in creating the fsl data structure
+ *   There is a primary routine, and helpers for the specific versions.
+ *
+ *   Returns: Nothing
+ *
+ *   Modifies: fsl
+ *
+ *================================================================
+ */
+void Parse_Specifics_File(fp)
+FILE *fp;
+{
+  char line[1024], *lp;
+  int vers;
+
+  while ((fgets(line, 1023, fp)) != NULL) {
+    lp = &line[0];
+    while ((*lp == ' ') || (*lp == '\t')) lp++;
+    if (( *lp == '#' ) || (*lp=='\n')) {
+      continue;
+    }
+
+    switch (my_upper(*lp)) {
+    case 'F': case 'S': case 'B':
+      fprintf(stderr, "Must specify version at beginning of specifics file\n");
+      exit(0);
+      break;
+    case 'V':
+      lp += 7;
+      if (1 != sscanf(lp, "%d", &vers)) {
+	fprintf(stderr," Improper version line in specs file: %s\n", line);
+      } else {
+	switch (vers) {
+	case 1:
+	  version = vers;
+	  Parse_Specifics_File_v1(fp);
+	  break;
+	case 2:
+	  version = vers;
+	  Parse_Specifics_File_v2(fp);
+	  break;
+	default:
+	  fprintf(stderr, "Improper version line in specs file: %s\n", line);
+	  fprintf(stderr, "\tSpecifics file will be IGNORED.\n");
+	  specificsOn = FALSE;
+	  return;
+	  break;
+	}}
+      break;
+    default:
+      fprintf(stderr, "Specifics file: What? *%s*\n", line);
+      break;
+    }}
+  
+}
+
+/* Version 1 */
+void Parse_Specifics_File_v1(fp)
+FILE *fp;
+{
+  char line[1024],*lp;
+  FrameSpecList *current, *new;
+  char typ; 
+  int fnum,snum, bnum, qs, newqs;
+  int num_scanned;
+
+  fsl = MakeFslEntry();
+  current = fsl;
+
+  while ((fgets(line,1023, fp)) != NULL) {
+    lp = &line[0];
+    while ((*lp == ' ') || (*lp == '\t')) lp++;
+    if (( *lp == '#' ) || (*lp=='\n')) {
+      continue;
+    }
+
+    switch (my_upper(*lp)) {
+    case 'F':
+      lp += 6;
+      sscanf(lp, "%d %c %d", &fnum, &typ, &qs);
+      if (current->framenum != -1) {
+	new=MakeFslEntry();
+	current->next = new;
+	current = new;
+      }
+      current->framenum = fnum;
+      current->frametype = CvtType(typ);
+      if (qs <= 0) qs = -1;
+      current->qscale = qs;
+      break;
+    case 'S':
+      lp += 6;
+      sscanf(lp, "%d %d", &snum, &newqs);
+      if (qs == newqs) break;
+      qs = newqs;
+      AddSlc(current, snum, qs);
+      break;
+    case 'B':
+      lp += 6;
+      num_scanned = sscanf(lp, "%d %d", &bnum, &newqs);
+      if (qs == newqs) break;
+      qs = newqs;
+      AddBs(current, bnum, FALSE, qs);
+      break;
+    case 'V':
+      fprintf(stderr, "Cannot specify version twice!  Taking first (%d)\n", version);
+      break;
+    default:
+      fprintf(stderr," What? *%s*\n", line);
+      break;
+    }}
+  
+}
+
+/* Version 2 */
+void Parse_Specifics_File_v2(fp)
+FILE *fp;
+{
+  char line[1024], *lp;
+  FrameSpecList *current, *new;
+  char typ;
+  int fnum, snum, bnum, qs, newqs;
+  int num_scanned, fx=0, fy=0, sx=0, sy=0;
+  char kind[100];
+  Block_Specifics *new_blk;
+  boolean relative;
+
+  fsl = MakeFslEntry();
+  current = fsl;
+
+  while ((fgets(line,1023,fp))!=NULL) {
+    lp = &line[0];
+    while ((*lp == ' ') || (*lp == '\t')) lp++;
+    if (( *lp == '#' ) || (*lp=='\n')) {
+      continue;
+    }
+
+    switch (my_upper(*lp)) {
+    case 'F':
+      lp += 6;
+      sscanf(lp,"%d %c %d", &fnum, &typ, &qs);
+      new = MakeFslEntry();
+      if (current->framenum != -1) {
+	current->next = new;
+	current = new;
+      }
+      current->framenum = fnum;
+      current->frametype = CvtType(typ);
+      if (qs <= 0) qs = -1;
+      current->qscale = qs;
+      break;
+    case 'S':
+      lp += 6;
+      sscanf(lp,"%d %d", &snum, &newqs);
+      if (qs == newqs) break;
+      qs = newqs;
+      AddSlc(current, snum, qs);
+      break;
+    case 'B':
+      lp += 6;
+      num_scanned = 0;
+      bnum = atoi(lp);
+      SkipToSpace(lp);
+      while ((*lp != '-') && (*lp != '+') &&
+	     ((*lp < '0') || (*lp > '9'))) lp++;
+      relative = ((*lp == '-') || (*lp == '+'));
+      newqs = atoi(lp);
+      SkipToSpace(lp);
+      if (EndString(lp)) {
+	num_scanned = 2;
+      } else {
+	num_scanned = 2+sscanf(lp, "%s %d %d %d %d", kind, &fx, &fy, &sx, &sy); 
+      }
+
+      qs = newqs;
+      new_blk = AddBs(current, bnum, relative, qs);
+      if (num_scanned > 2) {
+	BlockMV *tmp;
+	tmp = (BlockMV *) malloc(sizeof(BlockMV));
+	switch (num_scanned) {
+	case 7:
+	  tmp->typ = TYP_BOTH;
+	  tmp->fx = fx;
+	  tmp->fy = fy;
+	  tmp->bx = sx;
+	  tmp->by = sy;
+	  new_blk->mv = tmp;
+	  break;
+	case 3:
+	  tmp->typ = TYP_SKIP;
+	  new_blk->mv = tmp;
+	  break;
+	case 5:
+	  if (my_upper(kind[0]) == 'B') {
+	    tmp->typ = TYP_BACK;
+	    tmp->bx = fx;
+	    tmp->by = fy;
+	  } else {
+	    tmp->typ = TYP_FORW;
+	    tmp->fx = fx;
+	    tmp->fy = fy;
+	  }
+	  new_blk->mv = tmp;
+	  break;
+	default:
+	  fprintf(stderr,
+		  "Bug in specifics file!  Skipping short/long entry: %s\n",line);
+	  break;
+	}
+      } else {
+	new_blk->mv = (BlockMV *) NULL;
+      }
+
+      break;
+    case 'V':
+      fprintf(stderr,
+	      "Cannot specify version twice!  Taking first (%d).\n",
+	      version);
+      break;
+    default:
+      printf("What? *%s*\n",line);
+      break;
+    }}
+  
+}
+
+
+
+
+/*=================================================================
+ *
+ *     MakeFslEntry
+ *
+ *     Makes a single entry in for the fsl linked list (makes a frame)
+ *
+ *     Returns: the new entry
+ *
+ *     Modifies: nothing
+ *
+ *=================================================================
+ */
+FrameSpecList *MakeFslEntry()
+{
+  FrameSpecList *fslp;
+  fslp = (FrameSpecList *) malloc(sizeof(FrameSpecList));
+  fslp->framenum = -1;
+  fslp->slc = (Slice_Specifics *) NULL;
+  fslp->bs = (Block_Specifics *) NULL;
+  return fslp;
+}
+
+
+
+
+
+/*================================================================
+ *
+ *   AddSlc
+ *
+ *   Adds a slice to framespeclist c with values snum and qs
+ *
+ *   Returns: nothing
+ *
+ *   Modifies: fsl's structure
+ *
+ *================================================================
+ */
+void AddSlc(c, snum, qs)
+FrameSpecList *c;
+int snum,qs;
+{
+  Slice_Specifics *new;
+  static Slice_Specifics *last;
+
+  new = (Slice_Specifics *) malloc(sizeof(Slice_Specifics));
+  new->num = snum;
+  new->qscale = qs;
+  new->next = (Slice_Specifics *)NULL;
+  if (c->slc == (Slice_Specifics *)NULL) {
+    last = new;
+    c->slc = new;
+  } else {
+    last->next = new;
+    last = new;
+  }
+}
+
+
+
+
+
+/*================================================================
+ *
+ *   AddBs
+ *
+ *   Adds a sliceblock to framespeclist c with values bnum and qs
+ *
+ *   Returns: pointer to the new block spec
+ *
+ *   Modifies: fsl's structure
+ *
+ *================================================================
+ */
+Block_Specifics *AddBs(c,bnum,rel,qs)
+FrameSpecList *c;
+boolean rel;
+int bnum,qs;
+{
+  Block_Specifics *new;
+  static Block_Specifics *last;
+
+  new = (Block_Specifics *) malloc(sizeof(Block_Specifics));
+  new->num = bnum;
+  if (qs == 0) rel = TRUE;
+  new->relative = rel;
+  new->qscale = qs;
+  new->next = (Block_Specifics *)NULL;
+  new->mv = (BlockMV *) NULL;
+  if (c->bs == (Block_Specifics *)NULL) {
+    last = new;
+    c->bs = new;
+  } else {
+    last->next = new;
+    last = new;
+  }
+  return new;
+}
+
+
+
+
+
+
+/*================================================================
+ *
+ *  SpecLookup
+ *
+ *  Find out if there is any changes to be made for the qscale
+ *  at entry fn.num (which is of type typ).  Sets info to point to
+ *  motion vector info (if any), else NULL.
+ *
+ *  Returns: new qscale or -1
+ *
+ *  Modifies: *info (well, internal cache can change)
+ *
+ *================================================================
+ */
+
+int SpecLookup(fn,typ,num,info,start_qs)
+int fn,typ,num;
+BlockMV **info;
+int start_qs;
+{
+  static FrameSpecList *last = (FrameSpecList *) NULL;
+  Slice_Specifics *sptr=(Slice_Specifics *) NULL;
+  Block_Specifics *bptr=(Block_Specifics *) NULL;
+  FrameSpecList *tmp;
+  boolean found_it;
+  static int leftovers = 0;  /* Used in case of forced movement into 1..31 range */
+  
+  *info = (BlockMV * )NULL;
+  if (last == (FrameSpecList *) NULL){
+    /* No cache, try to find number fn */
+    tmp = fsl;
+    found_it = FALSE;
+    while (tmp != (FrameSpecList *) NULL) {
+      if (tmp->framenum == fn) {
+	found_it = TRUE;
+	break;
+      } else tmp = tmp->next;
+    }
+    if (!found_it) return -1;
+    last=tmp;
+  } else {
+    if (last->framenum != fn) { /* cache miss! */
+      /* first check if it is next */
+      if ((last->next != (FrameSpecList *) NULL) && 
+	  (last->next->framenum == fn)) {
+	last = last->next;
+      } else {
+	/* if not next, check from the start.
+	   (this allows people to put frames out of order,even
+	   though the spec doesnt allow it.) */
+	tmp = fsl;
+	found_it = FALSE;
+	while (tmp != (FrameSpecList *) NULL) {
+	  if (tmp->framenum==fn) {found_it = TRUE; break;}
+	  tmp = tmp->next;
+	}
+	if (!found_it) return -1;
+	last = tmp;
+      }
+    }
+  }
+  /* neither of these should ever be true, unless there is a bug above */
+  if (last == (FrameSpecList *) NULL) {
+    fprintf(stderr, "PROGRAMMER ERROR: last is null!\n");
+    return -1;
+  }
+  if (last->framenum!=fn) {
+    fprintf(stderr, "PROGRAMMER ERROR: last has wrong number!\n");
+    return -1; /* no data on it */
+  }
+  
+  switch(typ) {
+  case 0: /* Frame: num is ignored */
+    leftovers = 0;
+#ifdef BLEAH
+    printf("QSchange frame %d to %d\n", fn, last->qscale);
+#endif 
+    return last->qscale;
+    break;
+
+  case 1: /* Slice */
+    leftovers = 0;
+    /* So, any data on slices? */
+    if (last->slc == (Slice_Specifics *) NULL) return -1;
+    for (sptr = last->slc; sptr != (Slice_Specifics *) NULL; sptr = sptr->next) {
+      if (sptr->num == num) {
+#ifdef BLEAH
+	printf("QSchange Slice %d.%d to %d\n", fn, num, sptr->qscale);
+#endif
+	if (sptr->qscale == 0) return -1;
+	return sptr->qscale;
+      }
+    }
+    break;
+
+  case 2:  /* block */
+    /* So, any data on blocks? */
+    if (last->bs == (Block_Specifics *) NULL) {
+      return -1;
+    }
+    for (bptr=last->bs; bptr != (Block_Specifics *) NULL; bptr=bptr->next) {
+      if (bptr->num == num) {
+	int new_one;
+#ifdef BLEAH
+	printf("QSchange Block %d.%d to %d\n", fn, num, bptr->qscale);
+#endif
+	*info = bptr->mv;
+	if (bptr->relative) {
+	  if (bptr->qscale == 0) {
+	    /* Do nothing! */
+	    new_one = start_qs;
+	  } else {
+	    new_one = start_qs + bptr->qscale + leftovers;
+	    if (new_one < 1) {
+	      leftovers = new_one - 1;
+	      new_one = 1;
+	    } else if (new_one > 31) {
+	      leftovers = new_one - 31;
+	      new_one = 31;
+	    } else leftovers = 0;
+	  }}
+	else {
+	  new_one = bptr->qscale;
+	  leftovers = 0;
+	}
+	return new_one;
+      }
+    }
+    break;
+  default:
+    fprintf(stderr, "PROGRAMMER ERROR:  reached unreachable code in SpecLookup\n");
+    break;
+  }
+  /* no luck */
+  return -1;
+}
+     
+    
+/*================================================================
+ *
+ *  SpecTypeLookup
+ *
+ *  Find out if there is any changes to be made for the type of frame
+ *  at frame fn.
+ *
+ *  Returns: new type or -1 (unspecified)
+ *
+ *================================================================
+ */
+int SpecTypeLookup(fn)
+int fn;
+{
+  FrameSpecList *tmp;
+
+  /* try to find number fn */
+  tmp = fsl;
+  do {
+    if (tmp->framenum == fn) break;
+    else tmp = tmp->next;
+  } while (tmp != (FrameSpecList *) NULL);
+  if (tmp == (FrameSpecList *) NULL) {
+#ifdef BLEAH
+    printf("Frame %d type not specified\n", fn);
+#endif
+    return -1;
+  }
+#ifdef BLEAH
+  printf("Frame %d type set to %d\n", fn, tmp->frametype);
+#endif
+  return tmp->frametype;
+}
diff --git a/converter/ppm/ppmtompeg/subsample.c b/converter/ppm/ppmtompeg/subsample.c
new file mode 100644
index 00000000..5ec71814
--- /dev/null
+++ b/converter/ppm/ppmtompeg/subsample.c
@@ -0,0 +1,280 @@
+/*===========================================================================*
+ * subsample.c                                   *
+ *                                       *
+ *  Procedures concerned with subsampling                    *
+ *                                       *
+ * EXPORTED PROCEDURES:                              *
+ *  LumMotionErrorA                              *
+ *  LumMotionErrorB                              *
+ *  LumMotionErrorC                              *
+ *  LumMotionErrorD                              *
+ *                                       *
+ *===========================================================================*/
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*==============*
+ * HEADER FILES *
+ *==============*/
+
+#include "pm_c_util.h"
+#include "all.h"
+#include "mtypes.h"
+#include "frames.h"
+#include "bitio.h"
+#include "prototypes.h"
+
+
+
+static void
+computePrevFyFx(MpegFrame * const prevFrame,
+                int         const by,
+                int         const bx,
+                vector      const m,
+                uint8 ***   const prevP,
+                int *       const fyP,
+                int *       const fxP) {
+
+    boolean const xHalf = (ABS(m.x) % 2 == 1);
+    boolean const yHalf = (ABS(m.y) % 2 == 1);
+
+    MotionToFrameCoord(by, bx, m.y/2, m.x/2, fyP, fxP);
+
+    if (xHalf) {
+        if (m.x < 0)
+            --*fxP;
+
+        if (yHalf) {
+            if (m.y < 0)
+                --*fyP;
+        
+            *prevP = prevFrame->halfBoth;
+        } else
+            *prevP = prevFrame->halfX;
+    } else if (yHalf) {
+        if (m.y < 0)
+            --*fyP;
+        
+        *prevP = prevFrame->halfY;
+    } else
+        *prevP = prevFrame->ref_y;
+}
+
+
+
+static int32
+evenColDiff(const uint8 * const macross,
+            const int32 * const currentRow) {
+
+    return 0
+        + ABS(macross[ 0] - currentRow[ 0])
+        + ABS(macross[ 2] - currentRow[ 2])
+        + ABS(macross[ 4] - currentRow[ 4])
+        + ABS(macross[ 6] - currentRow[ 6])
+        + ABS(macross[ 8] - currentRow[ 8])
+        + ABS(macross[10] - currentRow[10])
+        + ABS(macross[12] - currentRow[12])
+        + ABS(macross[14] - currentRow[14]);
+}
+
+
+
+static int32
+oddColDiff(const uint8 * const macross,
+           const int32 * const currentRow) {
+
+    return 0
+        + ABS(macross[ 1] - currentRow[ 1])
+        + ABS(macross[ 3] - currentRow[ 3])
+        + ABS(macross[ 5] - currentRow[ 5])
+        + ABS(macross[ 7] - currentRow[ 7])
+        + ABS(macross[ 9] - currentRow[ 9])
+        + ABS(macross[11] - currentRow[11])
+        + ABS(macross[13] - currentRow[13])
+        + ABS(macross[15] - currentRow[15]);
+}
+
+
+
+/*===========================================================================*
+ *
+ * LumMotionErrorA
+ *
+ *  compute the motion error for the A subsampling pattern
+ *
+ * RETURNS: the error, or some number greater if it is worse
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+int32
+LumMotionErrorA(const LumBlock * const currentBlockP,
+                MpegFrame *      const prevFrame,
+                int              const by,
+                int              const bx,
+                vector           const m,
+                int32            const bestSoFar) {
+
+    int32 diff; /* max value of diff is 255*256 = 65280 */
+    uint8 ** prev;
+    int fy, fx;
+    unsigned int rowNumber;
+
+    computePrevFyFx(prevFrame, by, bx, m, &prev, &fy, &fx);
+
+    diff = 0;  /* initial value */
+
+    for (rowNumber = 0; rowNumber < 16; rowNumber +=2) {
+        uint8 *       const macross    = &(prev[fy + rowNumber][fx]);
+        const int32 * const currentRow = currentBlockP->l[rowNumber];
+
+        diff += evenColDiff(macross, currentRow);
+
+        if (diff > bestSoFar)
+            return diff;
+    }
+    return diff;
+}
+
+
+
+/*===========================================================================*
+ *
+ * LumMotionErrorB
+ *
+ *  compute the motion error for the B subsampling pattern
+ *
+ * RETURNS: the error, or some number greater if it is worse
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+int32
+LumMotionErrorB(const LumBlock * const currentBlockP,
+                MpegFrame *      const prevFrame,
+                int              const by,
+                int              const bx,
+                vector           const m,
+                int32            const bestSoFar) {
+
+    int32 diff;  /* max value of diff is 255*256 = 65280 */
+    uint8 **prev;
+    int fy, fx;
+    unsigned int rowNumber;
+
+    computePrevFyFx(prevFrame, by, bx, m, &prev, &fy, &fx);
+
+    diff = 0;  /* initial value */
+    
+    for (rowNumber = 0; rowNumber < 16; rowNumber +=2) {
+        uint8 *       const macross    = &(prev[fy + rowNumber][fx]);
+        const int32 * const currentRow = currentBlockP->l[rowNumber];
+
+        diff += oddColDiff(macross, currentRow);
+
+        if (diff > bestSoFar)
+            return diff;
+    }
+    return diff;
+}
+
+
+/*===========================================================================*
+ *
+ * LumMotionErrorC
+ *
+ *  compute the motion error for the C subsampling pattern
+ *
+ * RETURNS: the error, or some number greater if it is worse
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+int32
+LumMotionErrorC(const LumBlock * const currentBlockP,
+                MpegFrame *      const prevFrame,
+                int              const by,
+                int              const bx,
+                vector           const m,
+                int32            const bestSoFar) {
+
+    int32 diff;        /* max value of diff is 255*256 = 65280 */
+    uint8 **prev;
+    int fy, fx;
+    unsigned int rowNumber;
+
+    computePrevFyFx(prevFrame, by, bx, m, &prev, &fy, &fx);
+
+    diff = 0;  /* initial value */
+    
+    for (rowNumber = 1; rowNumber < 16; rowNumber +=2) {
+        uint8 *       const macross    = &(prev[fy + rowNumber][fx]);
+        const int32 * const currentRow = currentBlockP->l[rowNumber];
+
+        diff += evenColDiff(macross, currentRow);
+
+        if (diff > bestSoFar)
+            return diff;
+    }
+    return diff;
+}
+
+
+/*===========================================================================*
+ *
+ * LumMotionErrorD
+ *
+ *  compute the motion error for the D subsampling pattern
+ *
+ * RETURNS: the error, or some number greater if it is worse
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+int32
+LumMotionErrorD(const LumBlock * const currentBlockP,
+                MpegFrame *      const prevFrame,
+                int              const by,
+                int              const bx,
+                vector           const m,
+                int32            const bestSoFar) {
+
+    int32 diff;     /* max value of diff is 255*256 = 65280 */
+    uint8 ** prev;
+    int fy, fx;
+    unsigned int rowNumber;
+
+    computePrevFyFx(prevFrame, by, bx, m, &prev, &fy, &fx);
+
+    diff = 0;  /* initial value */
+
+    for (rowNumber = 1; rowNumber < 16; rowNumber +=2) {
+        uint8 *       const macross    = &(prev[fy + rowNumber][fx]);
+        const int32 * const currentRow = currentBlockP->l[rowNumber];
+
+        diff += oddColDiff(macross, currentRow);
+
+        if (diff > bestSoFar)
+            return diff;
+    }
+    return diff;
+}
diff --git a/converter/ppm/ppmtompeg/tst/README b/converter/ppm/ppmtompeg/tst/README
new file mode 100644
index 00000000..4e35f6ba
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/README
@@ -0,0 +1,30 @@
+The test in this directory is derived from that in the Berkeley mpeg
+package, but we have trimmed it down for the purposes of the Netpbm
+package to save space.
+
+First of all, the Berkeley package had Berkeley YUV files for sample input
+(in the 'ts' directory).  But we converted them to JPEG to save a great 
+deal of space (even when the package is gzipped).
+
+We modified the ts.param file to work with the JPEG files and updated the
+expected results file to correspond to the JPEG input (the expected results
+are different after the JPEG conversion because JPEG conversion is lossy).
+
+We kept some of the other parameter files from the Berkeley package in
+case someone can get some use out of them, but did not update them to
+use the JPEG files.  You'll have to do that yourself.  And we removed
+the expected results files for them, since you can't generate those
+results with the inputs we have supplied.
+
+Note that JPEG input doesn't really exercise the most standard function
+of ppmtompeg.  As its name suggests, it's main purpose is to take PPM
+frames as input.  You can use jpegtoppm to create PPM input and then
+modify the parameter files if you want to test that.  We have not, however
+supplied an expected results file for that.
+
+The .mpg files are what ppmtojpeg output as the mpeg movie when we
+ran it on the jpeg files in the 'ts' directory.
+
+The .stat files are what ppmtojpeg output when we used the -stat
+option in generating the expected results.  As part of your test, use
+the -stat option and compare yours to the expected results.
diff --git a/converter/ppm/ppmtompeg/tst/gop.param b/converter/ppm/ppmtompeg/tst/gop.param
new file mode 100644
index 00000000..96900a3d
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/gop.param
@@ -0,0 +1,30 @@
+# test suite parameter file
+
+PATTERN		IBPBIBPBPB
+OUTPUT		/tmp/ts.mpg
+
+YUV_SIZE	352x240
+
+BASE_FILE_FORMAT	YUV
+INPUT_CONVERT	*
+GOP_SIZE	10
+SLICES_PER_FRAME  1
+
+INPUT_DIR	./tst/ts
+
+INPUT
+stennis.*.yuv	[30-39]
+stennis.*.yuv	[30-39]
+END_INPUT
+
+PIXEL		HALF
+RANGE		8
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	SIMPLE
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+REFERENCE_FRAME	ORIGINAL
diff --git a/converter/ppm/ppmtompeg/tst/par3.param b/converter/ppm/ppmtompeg/tst/par3.param
new file mode 100644
index 00000000..6ee6586e
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/par3.param
@@ -0,0 +1,43 @@
+# speed test parameter file
+
+PATTERN		IBBPBBPBBPBBPBB
+
+OUTPUT		/n/picasso/users/keving/encode/output/flowgard.mpg
+GOP_SIZE	30
+SLICES_PER_FRAME	15
+
+BASE_FILE_FORMAT	YUV
+YUV_SIZE	352x240
+
+INPUT_CONVERT	*
+
+INPUT_DIR	/n/picasso/users/keving/encode/input/flowg
+
+INPUT
+sflowg.*.yuv	[0-39]
+END_INPUT
+
+# quality parameters
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+# motion vector search parameters
+
+PIXEL		HALF
+
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+REFERENCE_FRAME	ORIGINAL
+
+PARALLEL_TEST_FRAMES	3
+PARALLEL_TIME_CHUNKS	30
+
+PARALLEL
+bugs-bunny	keving	~keving/encode/bin/sun/mpeg_encode
+linus		keving	~keving/encode/bin/sun/mpeg_encode
+END_PARALLEL
diff --git a/converter/ppm/ppmtompeg/tst/short.param b/converter/ppm/ppmtompeg/tst/short.param
new file mode 100644
index 00000000..9189e5d6
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/short.param
@@ -0,0 +1,31 @@
+# test suite parameter file
+
+PATTERN		IBBBPBBB
+OUTPUT		/tmp/ts.mpg
+
+YUV_SIZE	352x240
+
+BASE_FILE_FORMAT	YUV
+INPUT_CONVERT	*
+GOP_SIZE	30
+SLICES_PER_FRAME  1
+
+INPUT_DIR	../test/ts
+
+INPUT
+stennis.*.yuv	[30-37]
+END_INPUT
+
+PIXEL		HALF
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+REFERENCE_FRAME	ORIGINAL
+
+# FORCE_ENCODE_LAST_FRAME
diff --git a/converter/ppm/ppmtompeg/tst/test_all b/converter/ppm/ppmtompeg/tst/test_all
new file mode 100755
index 00000000..67b56c9c
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/test_all
@@ -0,0 +1,19 @@
+#!/bin/csh -f
+cd ..
+echo "First we encode three mpegs... (note requires 5MB on /tmp)"
+rm -f /tmp/ts{,2,d}.{mpg,stat}
+./mpeg_encode -stat /tmp/ts.stat ./tst/ts.param
+./mpeg_encode -stat /tmp/ts2.stat ./tst/ts2.param
+./mpeg_encode -stat /tmp/tsd.stat ./tst/tsd.param
+
+cd tst
+
+echo "Test one - tst/ts.param"
+csh diffscript /tmp/ts.stat ts.stat /tmp/ts.mpg ts.mpg
+
+echo "Test two - tst/ts2.param (different pattern)"
+csh diffscript /tmp/ts2.stat ts2.stat /tmp/ts2.mpg ts2.mpg
+
+echo "Test three - tst/tsd.param (uses decoded frames)"
+csh diffscript /tmp/tsd.stat tsd.stat /tmp/tsd.mpg tsd.mpg
+
diff --git a/converter/ppm/ppmtompeg/tst/ts.mpg b/converter/ppm/ppmtompeg/tst/ts.mpg
new file mode 100644
index 00000000..2bc6ae6e
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/ts.mpg
Binary files differdiff --git a/converter/ppm/ppmtompeg/tst/ts.param b/converter/ppm/ppmtompeg/tst/ts.param
new file mode 100644
index 00000000..23e1092c
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/ts.param
@@ -0,0 +1,29 @@
+# test suite parameter file
+
+PATTERN		IBBPBBPBBP
+OUTPUT		/tmp/ts.mpg
+
+BASE_FILE_FORMAT JPEG
+INPUT_CONVERT	*
+GOP_SIZE	30
+SLICES_PER_FRAME  1
+
+INPUT_DIR	./tst/ts
+
+INPUT
+stennis.*.jpg	[30-39]
+END_INPUT
+
+PIXEL		HALF
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+REFERENCE_FRAME	ORIGINAL
+# Default string has the date in it, bad for tests!
+USER_DATA  /dev/null
diff --git a/converter/ppm/ppmtompeg/tst/ts.stat b/converter/ppm/ppmtompeg/tst/ts.stat
new file mode 100644
index 00000000..e13be8a3
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/ts.stat
@@ -0,0 +1,52 @@
+MPEG ENCODER STATS (1.5b)
+------------------------
+TIME STARTED:  Thu Mar 30 19:50:43 2000
+MACHINE:  unknown
+FIRST FILE:  ./tst/ts/stennis.30.jpg
+LAST FILE:  ./tst/ts/stennis.39.jpg
+PATTERN:  ibbpbbpbbp
+GOP_SIZE:  30
+SLICES PER FRAME:  1
+RANGE:  +/-10
+PIXEL SEARCH:  HALF
+PSEARCH:  LOGARITHMIC
+BSEARCH:  CROSS2
+QSCALE:  8 10 25
+REFERENCE FRAME:  ORIGINAL
+TIME COMPLETED:  Thu Mar 30 19:50:50 2000
+Total time:  7 seconds
+
+-------------------------
+*****I FRAME SUMMARY*****
+-------------------------
+  Blocks:      330     (105385 bits)     (  319 bpb)
+  Frames:        1     (105488 bits)     (105488 bpf)     (32.2% of total)
+  Compression:   19:1     (   1.2487 bpp)
+  Seconds:          0     (   7.6923 fps)  (   649846 pps)  (     2538 mps)
+-------------------------
+*****P FRAME SUMMARY*****
+-------------------------
+  I Blocks:    110     ( 27261 bits)     (  247 bpb)
+  P Blocks:    872     (147211 bits)     (  168 bpb)
+  Skipped:       8
+  Frames:        3     (174816 bits)     (58272 bpf)     (53.3% of total)
+  Compression:   34:1     (   0.6898 bpp)
+  Seconds:          0     (   3.2967 fps)  (   278505 pps)  (     1087 mps)
+-------------------------
+*****B FRAME SUMMARY*****
+-------------------------
+  I Blocks:      1     (   156 bits)     (  156 bpb)
+  B Blocks:   1979     ( 46497 bits)     (   23 bpb)
+  B types:     227     (  21 bpb) forw    484 (  16 bpb) back    1268 (  26 bpb) bi
+  Skipped:       0
+  Frames:        6     ( 47328 bits)     ( 7888 bpf)     (14.4% of total)
+  Compression:  257:1     (   0.0934 bpp)
+  Seconds:          5     (   1.1952 fps)  (   100972 pps)  (      394 mps)
+---------------------------------------------
+Total Compression:   61:1     (   0.3880 bpp)
+Total Frames Per Second:  1.428571 (471 mps)
+CPU Time:  1.650165 fps     (544 mps)
+Total Output Bit Rate (30 fps):  983472 bits/sec
+MPEG file created in :  /tmp/ts.mpg
+
+
diff --git a/converter/ppm/ppmtompeg/tst/ts/stennis.30.jpg b/converter/ppm/ppmtompeg/tst/ts/stennis.30.jpg
new file mode 100644
index 00000000..f70e014e
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/ts/stennis.30.jpg
Binary files differdiff --git a/converter/ppm/ppmtompeg/tst/ts/stennis.31.jpg b/converter/ppm/ppmtompeg/tst/ts/stennis.31.jpg
new file mode 100644
index 00000000..cc88a285
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/ts/stennis.31.jpg
Binary files differdiff --git a/converter/ppm/ppmtompeg/tst/ts/stennis.32.jpg b/converter/ppm/ppmtompeg/tst/ts/stennis.32.jpg
new file mode 100644
index 00000000..221e22c9
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/ts/stennis.32.jpg
Binary files differdiff --git a/converter/ppm/ppmtompeg/tst/ts/stennis.33.jpg b/converter/ppm/ppmtompeg/tst/ts/stennis.33.jpg
new file mode 100644
index 00000000..c702a620
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/ts/stennis.33.jpg
Binary files differdiff --git a/converter/ppm/ppmtompeg/tst/ts/stennis.34.jpg b/converter/ppm/ppmtompeg/tst/ts/stennis.34.jpg
new file mode 100644
index 00000000..47c86806
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/ts/stennis.34.jpg
Binary files differdiff --git a/converter/ppm/ppmtompeg/tst/ts/stennis.35.jpg b/converter/ppm/ppmtompeg/tst/ts/stennis.35.jpg
new file mode 100644
index 00000000..ed21c16b
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/ts/stennis.35.jpg
Binary files differdiff --git a/converter/ppm/ppmtompeg/tst/ts/stennis.36.jpg b/converter/ppm/ppmtompeg/tst/ts/stennis.36.jpg
new file mode 100644
index 00000000..6fb7506b
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/ts/stennis.36.jpg
Binary files differdiff --git a/converter/ppm/ppmtompeg/tst/ts/stennis.37.jpg b/converter/ppm/ppmtompeg/tst/ts/stennis.37.jpg
new file mode 100644
index 00000000..561bd3b2
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/ts/stennis.37.jpg
Binary files differdiff --git a/converter/ppm/ppmtompeg/tst/ts/stennis.38.jpg b/converter/ppm/ppmtompeg/tst/ts/stennis.38.jpg
new file mode 100644
index 00000000..25ba097e
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/ts/stennis.38.jpg
Binary files differdiff --git a/converter/ppm/ppmtompeg/tst/ts/stennis.39.jpg b/converter/ppm/ppmtompeg/tst/ts/stennis.39.jpg
new file mode 100644
index 00000000..02b15aff
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/ts/stennis.39.jpg
Binary files differdiff --git a/converter/ppm/ppmtompeg/tst/ts2.param b/converter/ppm/ppmtompeg/tst/ts2.param
new file mode 100644
index 00000000..f72ba150
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/ts2.param
@@ -0,0 +1,33 @@
+# test suite parameter file
+
+PATTERN		IBBPBBPBB
+
+OUTPUT		/tmp/ts2.mpg
+
+YUV_SIZE	352x240
+
+BASE_FILE_FORMAT	YUV
+YUV_FORMAT	UCB
+INPUT_CONVERT	*
+GOP_SIZE	30
+SLICES_PER_FRAME  1
+
+INPUT_DIR	./tst/ts
+
+INPUT
+stennis.*.yuv	[30-39]
+END_INPUT
+
+PIXEL		HALF
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+REFERENCE_FRAME	ORIGINAL
+# Default string has the date in it, bad for tests!
+USER_DATA  /dev/null
diff --git a/converter/ppm/ppmtompeg/tst/ts2.stat b/converter/ppm/ppmtompeg/tst/ts2.stat
new file mode 100644
index 00000000..5a14ef79
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/ts2.stat
@@ -0,0 +1,52 @@
+MPEG ENCODER STATS (1.5)
+------------------------
+TIME STARTED:  Mon Jun 26 14:22:56 1995
+MACHINE:  odie.CS.Berkeley.EDU
+FIRST FILE:  ./tst/ts/stennis.30.yuv
+LAST FILE:  ./tst/ts/stennis.39.yuv
+PATTERN:  ibbpbbpbb
+GOP_SIZE:  30
+SLICES PER FRAME:  1
+RANGE:  +/-10
+FULL SEARCH:  0
+PSEARCH:  LOGARITHMIC
+BSEARCH:  CROSS2
+QSCALE:  8 10 25
+REFERENCE FRAME:  ORIGINAL
+TIME COMPLETED:  Mon Jun 26 14:23:11 1995
+Total time:  15 seconds
+
+-------------------------
+*****I FRAME SUMMARY*****
+-------------------------
+  Blocks:      660     (171792 bits)     (  260 bpb)
+  Frames:        2     (172008 bits)     (86004 bpf)     (60.0% of total)
+  Compression:   23:1     (   1.0180 bpp)
+  Seconds:          0     (   2.9851 fps)  (   252179 pps)  (      985 mps)
+-------------------------
+*****P FRAME SUMMARY*****
+-------------------------
+  I Blocks:     54     ( 13161 bits)     (  243 bpb)
+  P Blocks:    598     ( 69956 bits)     (  116 bpb)
+  Skipped:       8
+  Frames:        2     ( 83344 bits)     (41672 bpf)     (29.1% of total)
+  Compression:   48:1     (   0.4933 bpp)
+  Seconds:          1     (   1.2821 fps)  (   108307 pps)  (      423 mps)
+-------------------------
+*****B FRAME SUMMARY*****
+-------------------------
+  I Blocks:      5     (   391 bits)     (   78 bpb)
+  B Blocks:   1733     ( 29897 bits)     (   17 bpb)
+  B types:     250     (  11 bpb) forw    483 (  12 bpb) back    1000 (  20 bpb) bi
+  Skipped:     491
+  Frames:        6     ( 30960 bits)     ( 5160 bpf)     (10.8% of total)
+  Compression:  392:1     (   0.0611 bpp)
+  Seconds:         11     (   0.5029 fps)  (    42487 pps)  (      165 mps)
+---------------------------------------------
+Total Compression:   70:1     (   0.3392 bpp)
+Total Frames Per Second:  0.666667 (220 mps)
+CPU Time:  0.706215 fps     (233 mps)
+Total Output Bit Rate (30 fps):  859608 bits/sec
+MPEG file created in :  /tmp/ts2.mpg
+
+
diff --git a/converter/ppm/ppmtompeg/tst/ts3.param b/converter/ppm/ppmtompeg/tst/ts3.param
new file mode 100644
index 00000000..5f7b9efa
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/ts3.param
@@ -0,0 +1,32 @@
+# test suite parameter file
+
+PATTERN		IBPB
+OUTPUT		/tmp/ts.mpg
+
+YUV_SIZE	352x240
+
+BASE_FILE_FORMAT	YUV
+YUV_FORMAT	UCB
+INPUT_CONVERT	*
+GOP_SIZE	3
+SLICES_PER_FRAME  1
+
+INPUT_DIR	./tst/ts
+
+INPUT
+stennis.*.yuv	[30-39]
+END_INPUT
+
+PIXEL		HALF
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+REFERENCE_FRAME	ORIGINAL
+# Default string has the date in it, bad for tests!
+USER_DATA  /dev/null
diff --git a/converter/ppm/ppmtompeg/tst/ts4.param b/converter/ppm/ppmtompeg/tst/ts4.param
new file mode 100644
index 00000000..c8ba161c
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/ts4.param
@@ -0,0 +1,56 @@
+# test suite parameter file
+
+PATTERN		IBBBPBBBBP
+OUTPUT		/tmp/ts.mpg
+
+YUV_SIZE	352x240
+
+BASE_FILE_FORMAT	YUV
+YUV_FORMAT	UCB
+INPUT_CONVERT	*
+GOP_SIZE	30
+SLICES_PER_FRAME  1
+
+INPUT_DIR	./tst/ts
+
+INPUT
+stennis.*.yuv	[30-39]
+END_INPUT
+
+PIXEL		HALF
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+FRAME_RATE	25.000
+
+ASPECT_RATIO	1.0
+
+REFERENCE_FRAME	ORIGINAL
+
+IQTABLE
+	8	16	19	22	26	27	29	34
+	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
+
+NIQTABLE
+	8	16	19	22	26	27	29	34
+	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
+# Default string has the date in it, bad for tests!
+USER_DATA  /dev/null
diff --git a/converter/ppm/ppmtompeg/tst/tsd.param b/converter/ppm/ppmtompeg/tst/tsd.param
new file mode 100644
index 00000000..330a7a2a
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/tsd.param
@@ -0,0 +1,32 @@
+# test suite parameter file
+
+PATTERN		IBBBPBBBBP
+OUTPUT		/tmp/tsd.mpg
+
+YUV_SIZE	352x240
+
+BASE_FILE_FORMAT	YUV
+YUV_FORMAT	UCB
+INPUT_CONVERT	*
+GOP_SIZE	30
+SLICES_PER_FRAME  1
+
+INPUT_DIR	./tst/ts
+
+INPUT
+stennis.*.yuv	[30-39]
+END_INPUT
+
+PIXEL		HALF
+RANGE		10
+
+PSEARCH_ALG	LOGARITHMIC
+BSEARCH_ALG	CROSS2
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+REFERENCE_FRAME	DECODED
+# Default string has the date in it, bad for tests!
+USER_DATA  /dev/null
diff --git a/converter/ppm/ppmtompeg/tst/tsd.stat b/converter/ppm/ppmtompeg/tst/tsd.stat
new file mode 100644
index 00000000..b130e089
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/tsd.stat
@@ -0,0 +1,52 @@
+MPEG ENCODER STATS (1.5b)
+------------------------
+TIME STARTED:  Tue Aug 15 12:31:11 1995
+MACHINE:  odie.CS.Berkeley.EDU
+FIRST FILE:  ./tst/ts/stennis.30.yuv
+LAST FILE:  ./tst/ts/stennis.39.yuv
+PATTERN:  ibbbpbbbbp
+GOP_SIZE:  30
+SLICES PER FRAME:  1
+RANGE:  +/-10
+PIXEL SEARCH:  HALF
+PSEARCH:  LOGARITHMIC
+BSEARCH:  CROSS2
+QSCALE:  8 10 25
+REFERENCE FRAME:  DECODED
+TIME COMPLETED:  Tue Aug 15 12:31:31 1995
+Total time:  20 seconds
+
+-------------------------
+*****I FRAME SUMMARY*****
+-------------------------
+  Blocks:      330     ( 94083 bits)     (  285 bpb)
+  Frames:        1     ( 94192 bits)     (94192 bpf)     (37.0% of total)
+  Compression:   21:1     (   1.1150 bpp)
+  Seconds:          0     (   2.4390 fps)  (   206048 pps)  (      804 mps)
+-------------------------
+*****P FRAME SUMMARY*****
+-------------------------
+  I Blocks:     97     ( 20894 bits)     (  215 bpb)
+  P Blocks:    560     ( 83390 bits)     (  148 bpb)
+  Skipped:       3
+  Frames:        2     (104512 bits)     (52256 bpf)     (41.1% of total)
+  Compression:   38:1     (   0.6186 bpp)
+  Seconds:          1     (   1.0811 fps)  (    91329 pps)  (      356 mps)
+-------------------------
+*****B FRAME SUMMARY*****
+-------------------------
+  I Blocks:      4     (   588 bits)     (  147 bpb)
+  B Blocks:   2306     ( 54124 bits)     (   23 bpb)
+  B types:     283     (  14 bpb) forw    419 (  16 bpb) back    1604 (  26 bpb) bi
+  Skipped:       0
+  Frames:        7     ( 55504 bits)     ( 7929 bpf)     (21.8% of total)
+  Compression:  255:1     (   0.0939 bpp)
+  Seconds:         16     (   0.4182 fps)  (    35326 pps)  (      137 mps)
+---------------------------------------------
+Total Compression:   79:1     (   0.3011 bpp)
+Total Frames Per Second:  0.500000 (165 mps)
+CPU Time:  0.526316 fps     (173 mps)
+Total Output Bit Rate (30 fps):  763200 bits/sec
+MPEG file created in :  /tmp/tsd.mpg
+
+
diff --git a/converter/ppm/ppmtompeg/tst/tstl.param b/converter/ppm/ppmtompeg/tst/tstl.param
new file mode 100644
index 00000000..2b9c1718
--- /dev/null
+++ b/converter/ppm/ppmtompeg/tst/tstl.param
@@ -0,0 +1,31 @@
+# test suite parameter file
+
+PATTERN		IBBBPBBBBP
+OUTPUT		/tmp/ts.mpg
+
+YUV_SIZE	352x240
+
+BASE_FILE_FORMAT	YUV
+INPUT_CONVERT	*
+GOP_SIZE	30
+SLICES_PER_FRAME  1
+
+INPUT_DIR	../test/ts
+
+INPUT
+stennis.*.yuv	[30-39]
+END_INPUT
+
+PIXEL		HALF
+RANGE		10
+
+PSEARCH_ALG	TWOLEVEL
+BSEARCH_ALG	CROSS2
+
+IQSCALE		8
+PQSCALE		10
+BQSCALE		25
+
+REFERENCE_FRAME	ORIGINAL
+# Default string has the date in it, bad for tests!
+USER_DATA  /dev/null