Recently, I went to a conference and was keen enough to setup a webcam. Now I have 27,000 JPEG images, which I want to turn into a simple MPEG movie. This document details the process I went through to make this happen...

    This was all done on a pretty vanilla Redhat 7.1 box, for those who care about such things.

    MPEG tools

    The project I found which did the conversion is called MJPEG tools. The URL for this project is There were lots of dependancies, which we should talk about first...



    This library can be found at It is needed by MJPEG tools to be able to handle AVI files. The version I used was 0.7-0.7.15. It follows the standard autotools install process:

    make install


    "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." --

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

    make install


    NASM is an assembler, and the authors are none to modest. The web page is and to quote from that page:

    "This is NASM - the famous Netwide Assembler. Back at SourceForge and in intensive development!"

    It can't be that famous, I've never heard of it before.

    An explaination 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.


    Install it by doing the autotools thing once more. Note that the make install step is broken, 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/


    We'll also need the MJPEG people's MMX JPEG library. I am not sure how this differs from the standard JPEG library, which also seems to be an option here... I downloaded version 0.1.4, and did the autotools thing.

    For some reason they have disabled make install. 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/


    movtar is actaully written by the MJPEG people. You can download it from I used the 1.3.0 release. The install was auttooled once more. I am sure by now I don't have to explain how to do that...

    Compiling MJPEG tools itself

    I downloaded version 1.6.0 from the sourceforge website. Yet again, the install process was:

    This wouldn't make out of the box:

    g++ -g -O2 -o .libs/divxdec divxdec.o lav_common.o -Wl,-rpath -Wl,/usr/local/lib  
    -L/root/mjpegtools-1.6.0/utils -lmjpegutils -L/usr/local/lib 
    /usr/local/lib/ -lz -L/usr/X11R6/lib -lSM -lICE -lXxf86dga -lXxf86vm 
    -lXi -lXft -lXv -lXext -lX11 -lpthread -lnsl -ldl -lm ./.libs/ -L/usr/lib 
    /usr/lib/ -lmovtar -L/root/mjpegtools-1.6.0/../jpeg-mmx-0.1.4 
    ./.libs/ ./.libs/ -ljpeg-mmx -Wl,--rpath -Wl,/usr/local/lib
    ./.libs/ undefined reference to `SDL_Quit'
    ./.libs/ undefined reference to `SDL_WM_SetCaption'
    ./.libs/ undefined reference to `SDL_CreateYUVOverlay'
    ./.libs/ undefined reference to `SDL_LockYUVOverlay'
    ./.libs/ undefined reference to `SDL_EventState'
    ./.libs/ undefined reference to `SDL_UnlockSurface'
    ./.libs/ undefined reference to `SDL_LockSurface'
    ./.libs/ undefined reference to `SDL_DisplayYUVOverlay'
    ./.libs/ undefined reference to `SDL_UpdateRect'
    ./.libs/ undefined reference to `SDL_Init'
    ./.libs/ undefined reference to `SDL_GetError'
    ./.libs/ undefined reference to `SDL_UnlockYUVOverlay'
    ./.libs/ undefined reference to `SDL_FreeYUVOverlay'
    ./.libs/ undefined reference to `SDL_SetVideoMode'
    collect2: ld returned 1 exit status

    Until I had applied this patch.

    Then we can go ahead and make the project:

    make install

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

     MJPEG tools 1.6.0 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

    Encoding the JPEGS into the MPEG

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

    "You can use jpeg2yuv to create a yuv stream from separate JPEG images. This stream is sent to stdout, so that it can either be saved into a file, encoded directly to a mpeg video using mpeg2enc or used for anything else."

    "Saving an yuv stream can be done like this: jpeg2yuv -f 25 -j image%05d.jpg > result.yuv"

    "Creates the file result.yuv containing the yuv video data with 25 FPS. The -f option is used to set the frame rate. Note that image%05d.jpg means that the jpeg files are named image00000.jpg, image00001.jpg and so on. (05 means five digits, 04 means four digits, etc.)"

    "If you want to encode a mpeg video directly from jpeg images without saving a separate video file type: jpeg2yuv -f 25 -j image%05d.jpg | mpeg2enc -o mpegfile.m1v" --

    Note that this documentation is wrong, and you also need to include an interlacing option...

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

    The frames also have to count from 00000 in this example. I used the following little script to convert to the required naming format:

    for item in `find . -type f`
      mv $item frame-`printf "%05d" $count`.jpg
      count=$(( $count + 1 ))

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

posted at: 07:00 | path: /jpeg2mpeg | permanent link to this entry