July 20, 2013

Creating an AVI file from bitmaps using Delphi

It is quite easy to create an AVI file from a number of individual bitmaps. The AVI file maybe compressed on the fly using any installed codec. An example application would be creating a video from computer generated images such as 3D view or discrete bitmaps such as those generated from a Mandelbrot fractal zoom in. Each zoom step produces a new bitmap. Taking all bitmap into an AVI makes a nice movie showing the zoom into the fractal deep space!

Windows has two API to handle AVI files: an old API named “Video For Windows” (VfW) and a new API named “DirectShow”. The old API is the easiest to use for the task.

A guy named Gopalakrishna Palemat wrote a Visual Studio C++ application to demonstrate that use of VfW API. I have ported his code to Delphi. I have slightly updated his code to fix shortcomings and make it “the Delphi way”.

The original article can be found at http://gopalakrishna.palem.in/createmovie.html
My Delphi source code can be found at http://www.overbyte.be/eng/blog_source_Code.html

I will speak only about my source code from now.

All the AVI creation code has been moved into a component named “TAviFromBitmaps”. This class handle everything required with VfW API to create an AVI movie, compressed or not. You just has to create an instance of the class and call his AppendNewFrame method to add a bitmap at the end of the already added bitmaps. The result is an AVI file.

As a simple sample, I wrote a procedure which generate an AVI file made of 25 bitmaps generated on the fly. Each bitmap contain the text “Delphi rocks!” and the number of the frame. This is for simple demo. As I said above, you could as well produce bitmap with a 3D scene viewed from a moving point of view, or a zoom into a Mandelbrot fractal.

procedure TCAviFileForm.GenerateAvi
var
    I          : Integer;
    Y          : Integer;
    H          : Integer;
    BackBitmap : Graphics.TBitMap;
    Avi        : TAviFromBitmaps;
begin
    BackBitmap             := Graphics.TBitMap.Create;
    BackBitmap.Width       := 320;
    BackBitmap.Height      := 240;
    BackBitmap.PixelFormat := TPixelFormat.pf32bit;

    Avi := TAviFromBitmaps.CreateAviFile(
                nil, 'output.avi',
                //MKFOURCC('x', 'v', 'i', 'd'),// XVID (MPEG-4) compression
                MKFOURCC('D', 'I', 'B', ' '),  // No compression
                2, 1);                         // 2 frames per second
    // First, add a blank frame
    Avi.AppendNewFrame(BackBitmap.Handle);
    // Then add frames with text
    BackBitmap.Canvas.Font.Size := 20;
    H := (BackBitmap.Canvas.TextHeight('I') * 15) div 10;
    Y := (BackBitmap.Height div 2) - H;
    BackBitmap.Canvas.TextOut(10, Y, 'Delphi rocks!');
    Y := (BackBitmap.Height div 2);
    for I := 1 to 25 do begin
        BackBitmap.Canvas.TextOut(10, Y, IntToStr(I));
        Avi.AppendNewFrame(BackBitmap.Handle);
    end;
    // Finally, add two blank frame
    // (MediaPlayer doesn't show the last two frames)
    BackBitmap.Canvas.FillRect(Rect(0, 0,
                                     BackBitmap.Width, BackBitmap.Height));
    Avi.AppendNewFrame(BackBitmap.Handle);
    Avi.AppendNewFrame(BackBitmap.Handle);

    FreeAndNil(Avi);
    FreeAndNil(BackBitmap);
end;


Compression of the AVI is very important. Without compression, your AVI file will be quickly very large. VfW API is able to compress with about any algorithm. It is enough to install a “codec” into Windows. I like the XVID codec because it produces MPEG-4 video with high quality and high compression. Xvid is an open-source research project focusing on video compression and is a collaborative development effort (http://www.xvid.org). All code is released under the terms of GNU GPL license.

To use XVID compressor, download the setup from http://www.xvid.org and install it. Microsoft Media Player is able to decode XVID compressed movie without installing xvid software because the result is a standard MPEG-4 file.

Each codec is identified by a four character code name “FourCC”. VfW API has a function to transform those four characters codes into an integer value suitable for the rest of the API. This is why you see “MKFOURCC(‘x’, ‘v’, ‘I’, ‘d’)” in the above code.

Of course compression comes with a price: image quality is not the same as the original. So in some applications, you may want to avoid compression. This is done by selecting a compressor of type “MKFOURCC(‘D’, ‘I’, ‘B’, ‘ ’)” (Fourth character is a space).


Download source code from: http://www.overbyte.be/eng/blog_source_code.html
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be

6 comments:

Oleksandr said...

Hi there,

Does it possible to compress output AVI-file with xDiv codec by restoring them from resources (not installed!)?

nola speaker said...

Have you considered porting this to Delphi FMX for Android/iOS? You would be doing the Delphi community an even greater service if you did that!

François Piette said...

Not possible to port that specific code to Android/iOS because it makes use of VFW Windows API (VFW stands for Video For Windows).

David Rodriguez said...

Hello, Why it does not work in my computer the compression?

It can not generate the file when I used

MKFOURCC('x', 'v', 'i', 'd'), // XVID (MP4) compression


I had windows 8.1

Thanks a lot,

David Rodriguez said...

Hello, Why it does not work in my computer the compression?

It can not generate the file when I used

MKFOURCC('x', 'v', 'i', 'd'), // XVID (MP4) compression


I had windows 8.1

Thanks a lot,

Paul said...

I was able to implement this very efficient library to convert my security/critter cam snapshots (10/min) to daily videos for easy review using VLC.

Very Cool!

Thanks Francois!