JPEG to MPEG conversion howto


Table of Contents
1. Abstract
2. About this document
3. About the author
4. MPEG tools
5. Dependencies
5.1. libavifile
5.2. libsdl
5.3. nasm
5.4. jpeg-mmx
5.5. movtar
5.6. fontconfig
5.7. Compiling MJPEG tools itself
6. Encoding the JPEGS into the MPEG
7. Conclusion

1. Abstract

Some time ago, I went to a conference and was keen enough to setup a webcam to take a picture every couple of seconds. I then had 27,000 JPEG images, which I wanted to turn into a simple MPEG movie. This document details the process I went through to make this happen.


2. About this document

The version of this howto which you are currently reading is an update of the original version. I updated the document about a year after initially going through the process. This version reflects a few small changes in the open source projects which I used to perform the conversion, and some error corrections from the original version of this document.

Since the original version of this article, I have updated my machine from a pretty vanilla Redhat 7.1 box to a Debian unstable machine, for those who care about such things. Where things have changed from my experience about a year ago, I'll let you know.

I'm also a little surprised about the amount of email I have received about the original version of this document — obviously lots of people are trying to solve this kind of problem. I also get a lot of email from people using Microsoft Windows™ and wanting to perform a similar conversion. Unfortunately, as someone who doesn't use Windows very much, I cannot recommend a way of doing this sort of processing on that platform, although it is possible that MJPEG tools could be compiled for Windows™ — I just haven't tried. I would recommend Google as a way of finding something to help you out.


3. About the author

Michael has been working in the image processing field for several years, including a couple of years managing and developing large image databases for an Australian government department. He currently works for TOWER Software, who manufacture a world leading EDMS and Records Management package named TRIM. Michael is also the developer of Panda, an open source PDF generation API, as well as a bunch of other Open Source code.

Michael has a website at http://www.stillhq.com, and may be emailed at mikal@stillhq.com


4. MPEG tools

When I went searching for something to convert my many JPEG files to a MPEG moving, I quickly came across the MJPEG tools project. The URL for this project is http://mjpeg.sourceforge.net. MJPEG tools is very powerful, but there are lots of dependencies, which we should talk about first. There are also a few build and install problems with some of these dependencies which need to be resolved along the way, which I have also documented here. The updated version of this article was written with version 1.6.1 beta.


5. Dependencies

Let's work through the various MJPEG tools dependencies one by one, and discuss what needs to be done to get them installed on your machine.


5.1. libavifile

This library can be found at http://avifile.sourceforge.net. It is needed by MJPEG tools to be able to handle AVI files. The version I used was 0.7.37. It follows the standard autotools install process:

./configure
make
make install

For Debian, just use apt-get install libavifile0.7-dev.


5.2. libsdl

"Simple DirectMedia Layer is a cross-platform multimedia library designed to provide fast access to the graphics framebuffer and audio device. It is used by MPEG playback software, emulators, and many popular games, including the award winning Linux port of "Civilization: Call To Power." Simple DirectMedia Layer supports Linux, Win32, BeOS, MacOS, Solaris, IRIX, and FreeBSD." -- http://www.libsdl.org/index.php

libsdl can be found at http://www.libsdl.org, and is needed for some of the MJPEG playback routines. I used version 1.2.5. Again, installing is done by simply:

./configure
make
make install

For Debian, just do a apt-get install libsdl-dev.


5.3. nasm

The NASM web page can be found at http://nasm.sourceforge.net/. An explanation of where NASM came from can be found in the documentation:

 

The Netwide Assembler grew out of an idea on comp.lang.asm.x86 (or possibly alt.lang.asm - I forget which), which was essentially that there didn't seem to be a good free x86-series assembler around, and that maybe someone ought to write one.

  • a86 is good, but not free, and in particular you don't get any 32-bit capability until you pay. It's DOS only, too.

  • gas is free, and ports over DOS and Unix, but it's not very good, since it's designed to be a back end to gcc, which always feeds it correct code. So its error checking is minimal. Also, its syntax is horrible, from the point of view of anyone trying to actually write anything in it. Plus you can't write 16-bit code in it (properly).

  • as86 is Minix- and Linux-specific, and (my version at least) doesn't seem to have much (or any) documentation.

  • MASM isn't very good, and it's expensive, and it runs only under DOS.

  • TASM is better, but still strives for MASM compatibility, which means millions of directives and tons of red tape. And its syntax is essentially MASM's, with the contradictions and quirks that entails (although it sorts out some of those by means of Ideal mode). It's expensive too. And it's DOS-only.

So here, for your coding pleasure, is NASM. At present it's still in prototype stage - we don't promise that it can outperform any of these assemblers. But please, please send us bug reports, fixes, helpful information, and anything else you can get your hands on (and thanks to the many people who've done this already! You all know who you are), and we'll improve it out of all recognition. Again.

 
--http://home.attbi.com/~fbkotler/nasmdoc1.html#section-1.1 

I downloaded 0.98.36 when I wrote the updated version of this article.

Install it by doing the autotools thing once more. Note that the make install step is still broken (it didn't work for the first version of the article a year ago either), and that I had to do this to get it to install:

mkdir bin
mkdir man
mkdir man/man1
make install
cp bin/nasm /usr/local/bin/
cp man/man1/n* /usr/local/man/man1/

This seems to be because it is trying to install everything in the the current working directory, instead of the system wide install location. You should also note that apt-get install nasm on a Debian machine does exactly what is expected of it, and packages exactly the version which was available from the NASM website.


5.4. jpeg-mmx

We'll also need the MJPEG people's MMX JPEG library, which was at version 0.1.4 at the time of writing this article. I believe the difference between the standard JPEG library and the MMX JPEG library is that the MMX version is optimized for MMX processors, and wont run on processors without MMX. The standard libjpeg also seems to be an option here, although my machine have MMX, so I didn't try it. I downloaded version 0.1.4, and did the autotools thing.

For some reason they have disabled the install make target, possibly because they're worried about clobbering the standard libjpeg install. This reason doesn't really work though, as the library files have different names from those used in libjpeg. I did:

[root@localhost jpeg-mmx-0.1.4]# make install
Make install has been disabled
If you really want to install libjpeg-mmx, please use make install_real
[root@localhost jpeg-mmx-0.1.4]# make install_real 
/usr/bin/install -c -m 644 jconfig.h /usr/local/include/jconfig.h
/usr/bin/install -c -m 644 ./jpeglib.h /usr/local/include/jpeglib.h
/usr/bin/install -c -m 644 ./jmorecfg.h /usr/local/include/jmorecfg.h
/usr/bin/install -c -m 644 ./jerror.h /usr/local/include/jerror.h
/usr/bin/install -c -m 644 ./jinclude.h /usr/local/include/jinclude.h
/usr/bin/install -c -m 644 libjpeg-mmx.a /usr/local/lib/libjpeg-mmx.a
[root@localhost jpeg-mmx-0.1.4]# 

And annoyingly, I also had to manually copy a file:

cp jpegint.h /usr/local/include/

TODO: Debian package?


5.5. movtar

movtar is actually written by the MJPEG people. You can download it from http://download.sourceforge.net/mjpeg/. I used the 1.3.0 release, which hasn't changed since I wrote this article a year ago. The install was autotooled once more. I am sure by now I don't have to explain how to do that...

TODO: Debian package


5.6. fontconfig

Since I first wrote this article, MJPEG tools appears to have added a dependency on the fontconfig library from www.fontconfig.org. I installed version 2.2.1. Annoyingly, the autotools configuration for MJPEG tools didn't detect that fontconfig was missing, it just failed to compile.

TODO: Debian package


5.7. Compiling MJPEG tools itself

I downloaded version 1.6.1 from the SourceForge website. Yet again, the install process was based off the autotools.

Then we can go ahead and make the project:

./configure
make
make install

For those who are interested, my build configuration at the end of the configure script looked like:

 MJPEG tools 1.6.1 build configuration :

    - X86 Optimizations:
      - MMX/3DNow!/SSE enabled      : true
      - cmov support enabled        : true

****************************************************************************
* NOTE:                                                                    *
*   The resultant binaries will ***NOT*** run on a K6 or Pentium CPU       *
****************************************************************************
    - video4linux recording/playback: true
    - software MJPEG playback       : true
    - movtar playback/recording     : true
    - Quicktime playback/recording  : false
    - AVI MJPEG playback/recording  : true (always)
    - libDV (digital video) support : false  
    - AVIFILE divx encoding support : true
    - Gtk+ support for glav         : true
    - glibc support for >2GB files  : true

This time around, because I am using a newer version of GCC, I had to apply the following patch:

diff -urN mjpegtools-1.6.1/mplex/multplex.cc mjpegtools-1.6.1-hacked2/mplex/multplex.cc
--- mjpegtools-1.6.1/mplex/multplex.cc    2002-04-30 00:36:00.000000000 +1000
+++ mjpegtools-1.6.1-hacked2/mplex/multplex.cc    2003-07-25 09:05:40.000000000 +1000
@@ -3,6 +3,7 @@
 #include <math.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <assert.h>
 
 #include <mjpeg_types.h>
 #include <mjpeg_logging.h>
diff -urN mjpegtools-1.6.1/mplex/stillsstream.cc mjpegtools-1.6.1-hacked2/mplex/stillsstream.cc
--- mjpegtools-1.6.1/mplex/stillsstream.cc    2002-04-18 14:32:02.000000000 +1000
+++ mjpegtools-1.6.1-hacked2/mplex/stillsstream.cc    2003-07-25 09:07:55.000000000 +1000
@@ -22,6 +22,7 @@

 
 #include <format_codes.h>
+#include <assert.h>
 
 #include "stillsstream.hh"
 #include "interact.hh"
diff -urN mjpegtools-1.6.1/mplex/systems.cc mjpegtools-1.6.1-hacked2/mplex/systems.cc
--- mjpegtools-1.6.1/mplex/systems.cc    2002-04-30 00:36:01.000000000 +1000
+++ mjpegtools-1.6.1-hacked2/mplex/systems.cc    2003-07-25 09:07:19.000000000 +1000
@@ -4,6 +4,7 @@
 #include <string.h>
 #include <sys/param.h>
 #include <sys/stat.h>
+#include <assert.h>
 #include "systems.hh"
 #include "mplexconsts.hh"
 
diff -urN mjpegtools-1.6.1/yuvdenoise/Makefile.am mjpegtools-1.6.1-hacked2/yuvdenoise/Makefile.am
--- mjpegtools-1.6.1/yuvdenoise/Makefile.am    2002-03-25 07:52:57.000000000 +1100
+++ mjpegtools-1.6.1-hacked2/yuvdenoise/Makefile.am    2003-07-25 09:20:06.000000000 +1000
@@ -3,7 +3,9 @@
 EXTRA_DIST = .cvsignore
 MAINTAINERCLEANFILES = Makefile.in
 INCLUDES = -I $(top_srcdir)/utils -I $(top_srcdir)
-AM_CFLAGS = -funroll-all-loops -finline-functions -ffast-math -frerun-cse-after-loop -frerun-loop-opt -fexpensive-optimizations -fmove-all-movables -Werror
+
+# Mikal: Turned off -Werror because of ASM changes in GCC
+AM_CFLAGS = -funroll-all-loops -finline-functions -ffast-math -frerun-cse-after-loop -frerun-loop-opt -fexpensive-optimizations -fmove-all-movables
 
 bin_PROGRAMS       = yuvdenoise
 yuvdenoise_SOURCES = main.c deinterlace.c deinterlace.h denoise.c denoise.h motion.c motion.h global.h
diff -urN mjpegtools-1.6.1/yuvdenoise/Makefile.in mjpegtools-1.6.1-hacked2/yuvdenoise/Makefile.in
--- mjpegtools-1.6.1/yuvdenoise/Makefile.in    2002-12-09 23:58:03.000000000 +1100
+++ mjpegtools-1.6.1-hacked2/yuvdenoise/Makefile.in    2003-07-25 09:21:36.000000000 +1000
@@ -134,7 +134,9 @@
 EXTRA_DIST = .cvsignore
 MAINTAINERCLEANFILES = Makefile.in
 INCLUDES = -I $(top_srcdir)/utils -I $(top_srcdir)
-AM_CFLAGS = -funroll-all-loops -finline-functions -ffast-math -frerun-cse-after-loop -frerun-loop-opt -fexpensive-optimizations -fmove-all-movables -Werror
+
+# Mikal: Removed -Werror because of GCC asm changes
+AM_CFLAGS = -funroll-all-loops -finline-functions -ffast-math -frerun-cse-after-loop -frerun-loop-opt -fexpensive-optimizations -fmove-all-movables
 
 bin_PROGRAMS = yuvdenoise
 yuvdenoise_SOURCES = main.c deinterlace.c deinterlace.h denoise.c denoise.h motion.c motion.h global.h

Code: mjpegtools.patch

TODO: Debian package


6. Encoding the JPEGS into the MPEG

Finally, we can use MJPEG tools to convert the JPEGs into a MPEG stream.

When I originally wrote this article, I recommended that people use the following command line, which is what I had found recommended on the web, and what worked for me:

jpeg2yuv -f 25 -j frame-%05d.jpg -I p | mpeg2enc -o mpegfile.m1v

It turns out that the recommended command line is much more like:

ls *.ppm | xargs -n1 cat | ppmtoy4m | mpeg2enc -o mpegfile.m1v

It should be noted that this command line requires that the input images be PPM files instead of JPEG files however. We can get around this by using convert to change the format of the images:

for item in `ls *.jpg`
do
  convert $item $item.ppm
done

Note that the conversion is also quite slow, I walked away and came back later.


7. Conclusion

In this document I have discussed how to install MJPEG tools and it's dependancies, and then discussed how to convert a bunch of JPEGs to PPM files, and then a single MPEG movie. I hope you have found this document of some use. Feel free to send me email if you have more questions, although I don't gaurantee to personally answer then many hundreds of emails I receive each day.