Click here to Skip to main content
Email Password   helpLost your password?

Introduction

This is an article for everyone who does not want to spend hours messing around with the AVIFile functions, if he only wants to read or change a simple AVI video. I have wrapped the most important AVIFile functions into three easy to use C# classes that can handle the following tasks:

These features cover the common use cases like creating a video from a couple of images and a wave sound, extracting the sound track from a video, cutting out short clips, or grabbing a single picture from a movie.

This article has got two sections:

How to use the library - A walk through the demo application

The Explore tab

The Explore tab lets you explore an AVI file, and offers simple tasks that don't need editable streams:

At the top of the form, you can choose the AVI file you want to explore. text.avi from the test data folder is pre-selected. On the left side, you can display header information about the video and the wave sound stream (if available). Also, you can see image frames from the video in a PictureBox:

The images are read by a VideoStream object. GetFrameOpen prepares the stream for decompressing frames, GetFrameClose releases the resources used to decompress the frame, and GetBitmap decompresses a frame and converts it to a System.Drawing.Bitmap.

AviManager aviManager = new AviManager(txtAviFileName.Text, true);
VideoStream aviStream = aviManager.GetVideoStream();
aviStream.GetFrameOpen();
picFrame.Image = 
  aviStream.GetBitmap(Convert.ToInt32(numPosition.Value));
aviStream.GetFrameClose();
aviManager.Close();

In the middle of the demo form, you can work with whole streams:

Decompress removes the compression from a video stream. It creates a new file and video stream, decompresses each frame from the old stream, and writes it into the new stream. The result is a large new .avi file with the same video but no compression.

Compress changes the compression of the video, or applies compression to an uncompressed video. It does the same as Uncompress, but compresses the new stream. These two functions use the same method CopyFile:

private void CopyFile(String newName, bool compress){
    //open compressed file

    AviManager aviManager = 
        new AviManager(txtAviFileName.Text, true);
    VideoStream aviStream = aviManager.GetVideoStream();
    //create un-/re-compressed file

    AviManager newManager = 
        aviStream.DecompressToNewFile(newName, compress);

    //close compressed file

    aviManager.Close();
    //save and close un-/re-compressed file

    newManager.Close();
}

Whenever an instance of VideoStream creates a compressed stream, it asks you for a codec and settings:

Extract Bitmaps splits the video into many separate bitmap files:

VideoStream stream = aviManager.GetVideoStream();
stream.GetFrameOpen();

String path = @"..\..\testdata\";
for(int n=0; n<stream.CountFrames; n++){
    stream.ExportBitmap(n, path+n.ToString()+".bmp");
}

stream.GetFrameClose();

Of course, you can save the images in any format. ExportBitmap is just a shortcut for these three lines:

Bitmap bmp = stream.GetBitmap(position);
bmp.Save(FileName);
bmp.Dispose();

Extract Video copies the whole video stream into a new AVI file. You can use it to get rid of all the other streams like MIDI, text and Wave sound.

The lower box deals with Wave sound. Extract Sound copies the whole sound stream into a Wave file. This is not a big task, it requires only four lines of code:

AviManager aviManager = 
    new AviManager(txtAviFileName.Text, true);
AudioStream audioStream = aviManager.GetWaveStream();
audioStream.ExportStream( @"..\..\testdata\sound.wav" );
aviManager.Close();

Extract a few Seconds lets you copy video and sound between second X and second Y. First, a CopyForm dialog lets you enter X and Y, then these parts are cut out of the video and sound streams:

AviManager aviManager = new AviManager(txtAviFileName.Text, true);
VideoStream aviStream = aviManager.GetVideoStream();
CopyForm dialog = new CopyForm(0,
  aviStream.CountFrames / aviStream.FrameRate);
if (dialog.ShowDialog() == DialogResult.OK) {
  int startSecond = dialog.Start;
  int stopSecond = dialog.Stop;

  AviManager newFile = aviManager.CopyTo(
    "..\\..\\testdata\\video.avi", startSecond, stopSecond);
  newFile.Close();
}
aviManager.Close();

Add Sound lets you choose a .wav file, and adds it to the video. You can use this feature to add a sound track to a silent video, for example, re-add the sound to a video extracted with Extract Video. Adding sound is a simple task of three lines:

String fileName = GetFileName("Sounds (*.wav)|*.wav");
if(fileName != null){
    AviManager aviManager = 
        new AviManager(txtAviFileName.Text, true);
    aviManager.AddAudioStream(fileName);
    aviManager.Close();
}

The last set of functions is about creating new video streams. Enter a list of image files in the box and animate them:

Create uncompressed builds a new video from the images, and saves it without any compression. Create and Compress does the same, except that it displays the compression settings dialog and compresses the images. Both methods create a new file, and pass a sample bitmap to AddVideoStream. The sample bitmap is used to set the format of the new stream. Then, all the images from the list are added to the video.

//load the first image

Bitmap bitmap = (Bitmap)Image.FromFile(txtFileNames.Lines[0]);
//create a new AVI file

AviManager aviManager = 
    new AviManager(@"..\..\testdata\new.avi", false);
//add a new video stream and one frame to the new file

VideoStream aviStream = 
    aviManager.AddVideoStream(true, 2, bitmap);

Bitmap bitmap;
int count = 0;
for(int n=1; n<txtFileNames.Lines.Length; n++){
    if(txtFileNames.Lines[n].Trim().Length > 0){
        bitmap = 
           (Bitmap)Bitmap.FromFile(txtFileNames.Lines[n]);
        aviStream.AddFrame(bitmap);
        bitmap.Dispose();
        count++;
    }
}
aviManager.Close();

Add Frames appends the images to the existing video stream. To an uncompressed video stream, we could append frames by simply opening the stream and adding frames as usual. But a compressed stream cannot be re-compressed. AVIStreamWrite - used by AddFrame - would not return any error; but anyway, it would add the new frames uncompressed and produce nothing but strangely colored pixel storms. To add frames to a compressed stream, the existing frames must be decompressed and added to a new compressed stream. Then the additional frames can be added to that stream:

//open file

Bitmap bmp = (Bitmap)Image.FromFile(txtFileNames.Lines[0]);
AviManager aviManager = 
    new AviManager(txtAviFileName.Text, true);
VideoStream aviStream = aviManager.GetVideoStream();

//streams cannot be edited - copy to a new file

AviManager newManager = aviStream.DecompressToNewFile(
                        @"..\..\testdata\temp.avi", true);
aviStream = newManager.GetOpenStream(0);

//add images

Bitmap bitmap;
for(int n=0; n<txtFileNames.Lines.Length; n++){
    if(txtFileNames.Lines[n].Trim().Length > 0){
        bitmap = 
            (Bitmap)Bitmap.FromFile(txtFileNames.Lines[n]);
        aviStream.AddFrame(bitmap);
        bitmap.Dispose();
    }
}

aviManager.Close(); //close old file

newManager.Close(); //save and close new file


//delete old file, replace with new file

System.IO.File.Delete(txtAviFileName.Text);
System.IO.File.Move(@"..\..\testdata\temp.avi", 
                            txtAviFileName.Text);

Now that you know how to use the AVIFile wrapper classes, let's have a look at the background.

The Edit tab

The Edit tab demonstrates tasks for editable AVI streams, like pasting frames at any position in the stream, or changing the frame rate:

When you have chosen a file to edit, an editable stream is created from the video stream, and the editor buttons become enabled. A normal video stream is locked; for inserting and deleting frames, you need an editable stream:

AviManager file = new AviManager(fileName, true);
VideoStream stream = file.GetVideoStream();
EditableVideoStream editableStream = 
           new EditableVideoStream(stream);
file.Close();

On the left side, you can copy or cut frame sequences, and paste them at another position in the same stream:

Copying frames from one stream, and pasting them into another or the same stream, is only two lines of code:

//copy frames

IntPtr copiedData = editableStream.Copy(start, length);

//insert frames

editableStream.Paste(copiedData, 0, position, length);

There is no other method for deleting frames than just cut and forget them:

//cut and paste frames

IntPtr copiedData = editableStream.Cut(start, length);
editableStream.Paste(copiedData, 0, position, length);

//delete frames == cut without paste

IntPtr deletedData = editableStream.Cut(start, length);

In the middle of the dialog, you can insert frames from image files anywhere in the stream, and change the frame rate to make the video play back slower or faster:

We can paste only streams, not bitmaps, so the bitmaps from the list are written into a temporary AVI file and then pasted as a stream:

//create temporary video file

String tempFileName = System.IO.Path.GetTempFileName() + ".avi";
AviManager tempFile = new AviManager(tempFileName, false);

//write the new frames into the temporary video stream

Bitmap bitmap = 
  (Bitmap)Image.FromFile(txtNewFrameFileName.Lines[0].Trim());
tempFile.AddVideoStream(false, 1, bitmap);
VideoStream stream = tempFile.GetVideoStream();

for (int n=1; n<txtNewFrameFileName.Lines.Length; n++) {
   if (txtNewFrameFileName.Lines[n].Trim().Length > 0) {
       stream.AddFrame(
         (Bitmap)Image.FromFile(txtNewFrameFileName.Lines[n]));
   }
}

//paste the video into the editable stream

editableStream.Paste(stream, 0,
   (int)numPastePositionBitmap.Value, stream.CountFrames);

Do you find your video too slow, or too fast? Tell the player application to play more/less frames per second:

Avi.AVISTREAMINFO info = editableStream.StreamInfo;
info.dwRate = (int)(numFrameRate.Value * 10000);
info.dwScale = 10000;
editableStream.SetInfo(info);

The last box is not for editing, it is only a preview player. You should preview your editable stream before saving it to an AVI file.

A preview player is easy to implement, you only need a PictureBox and the video stream you want to play. A label displaying the current frame index can be helpful, too. A start button, a stop button, and there you are:

private void btnPlay_Click(object sender, EventArgs e) {
    player = new AviPlayer(editableStream, 
                pictureboxPreview, labelFrameIndex);
    player.Stopped += new System.EventHandler(player_Stopped);
    player.Start();
    SetPreviewButtonsState();
}

private void player_Stopped(object sender, EventArgs e) {
        btnPlay.Invoke(
           new SimpleDelegate(SetPreviewButtonsState));
}

private void SetPreviewButtonsState() {
        btnPlay.Enabled = ! player.IsRunning;
        btnStop.Enabled = player.IsRunning;
}

private void btnStop_Click(object sender, EventArgs e) {
        player.Stop();
}

How it works

AviManger manages the streams in an AVI file. The constructor takes the name of the file and opens it. Close closes all opened streams and the file itself. You can add new streams with AddVideoStream and AddAudioStream. New video streams are empty, Wave streams can only be created from Wave files. After you have created an empty video stream, use the methods of VideoStream to fill it. But what actually happens when you add a stream?

Create a video stream

There are two methods for creating a new video stream: create from a sample bitmap, or create from explicit format information. Both methods do the same, they pass their parameter on to VideoStream and add the new stream to the internal list of opened streams, to close them before closing the file:

public VideoStream AddVideoStream(
    bool isCompressed, //display the compression dialog,

     // create a compressed stream

    int frameRate, //frames per second

    int frameSize, //size of one frame in bytes

    int width, int height, PixelFormat format //format of 

                                              //the bitmaps

    ){

    VideoStream stream = new VideoStream(
        aviFile,
        isCompressed,
        frameRate,
        frameSize,
        width, height, format);

    streams.Add(stream);
    return stream;
}

public VideoStream AddVideoStream(
    bool isCompressed, //display the compression dialog,

      // create a compressed stream

    int frameRate, //frames per second

    Bitmap firstFrame //get the format from this image

      // and add it to the new stream

    ){

    VideoStream stream = new VideoStream(
        aviFile,
        isCompressed,
        frameRate,
        firstFrame);

    streams.Add(stream);
    return stream;
}

Then, VideoStream uses the format data to create a new stream. It calls AVIFileCreateStream and, if writeCompressed says so, AVIMakeCompressedStream:

public VideoStream(
    int aviFile, //pointer to the file object

    bool writeCompressed, //true: create compressed stream

    int frameRate, //frames per second

    ...
    ){

    //store format information

    //...


    //create the stream

    CreateStream();
}

private void CreateStream(){
    //fill stream information

    Avi.AVISTREAMINFO strhdr = new Avi.AVISTREAMINFO();
    strhdr.fccType = Avi.mmioStringToFOURCC("vids", 0);
    strhdr.fccHandler = Avi.mmioStringToFOURCC("CVID", 0);
    strhdr.dwScale = 1;
    strhdr.dwRate = frameRate;
    strhdr.dwSuggestedBufferSize = frameSize;
    strhdr.dwQuality = -1; //default

    strhdr.rcFrame.bottom = (uint)height;
    strhdr.rcFrame.right = (uint)width;
    strhdr.szName = new UInt16[64];

    //create the stream

    int result = Avi.AVIFileCreateStream(aviFile, 
                          out aviStream, ref strhdr);

    if(writeCompressed){
        //create a compressed stream from 

        //the uncompressed stream

        CreateCompressedStream();
    }else{
        //apply the format to the uncompressed stream

        SetFormat(aviStream);
    }
}

private void CreateCompressedStream(){
    Avi.AVICOMPRESSOPTIONS_CLASS options = 
             new Avi.AVICOMPRESSOPTIONS_CLASS();
    options.fccType = (uint)Avi.streamtypeVIDEO;
    options.lpParms = IntPtr.Zero;
    options.lpFormat = IntPtr.Zero;

    //display the compression options dialog

    Avi.AVISaveOptions(
      IntPtr.Zero,
      Avi.ICMF_CHOOSE_KEYFRAME | Avi.ICMF_CHOOSE_DATARATE,
      1, ref aviStream, ref options);

    //get a compressed stream

    Avi.AVICOMPRESSOPTIONS structOptions = 
                            options.ToStruct();
    int result = Avi.AVIMakeCompressedStream(
        out compressedStream,
        aviStream,
        ref structOptions, 0);

    //format the compressed stream

    SetFormat(compressedStream);
}

AVICOMPRESSOPTIONS_CLASS is the AVICOMPRESSOPTIONS structure as a class. Using classes instead of structures is the easiest way to deal with pointers to pointers. If you don't know what I'm talking about, you probably have never used AVISaveOptions or AVISaveV in .NET. Take a look at the original declaration:

BOOL AVISaveOptions(
  HWND hwnd,
  UINT uiFlags,
  int nStreams,
  PAVISTREAM * ppavi,
  LPAVICOMPRESSOPTIONS * plpOptions
);

LPAVICOMPRESSOPTIONS is a pointer to a pointer to an AVICOMPRESSOPTIONS structure. In C#, structures are passed by value. If you pass a structure by ref, a pointer to the structure is passed. Instances of classes are always passed to methods as pointers. So a class-parameter by ref means a pointer to a pointer to the object. The C# declarations of AVISaveOptions and AVICOMPRESSOPTIONS are:

[DllImport("avifil32.dll")]
public static extern bool AVISaveOptions(
    IntPtr hwnd,
    UInt32 uiFlags,
    Int32 nStreams,
    ref IntPtr ppavi,
    ref AVICOMPRESSOPTIONS_CLASS plpOptions
    );

[StructLayout(LayoutKind.Sequential, Pack=1)]
    public struct AVICOMPRESSOPTIONS {
    public UInt32   fccType;
    public UInt32   fccHandler;
    public UInt32   dwKeyFrameEvery;
    public UInt32   dwQuality;
    public UInt32   dwBytesPerSecond;
    public UInt32   dwFlags;
    public IntPtr   lpFormat;
    public UInt32   cbFormat;
    public IntPtr   lpParms;
    public UInt32   cbParms;
    public UInt32   dwInterleaveEvery;
}

[StructLayout(LayoutKind.Sequential, Pack=1)]
public class AVICOMPRESSOPTIONS_CLASS {
    public UInt32   fccType;
    public UInt32   fccHandler;
    public UInt32   dwKeyFrameEvery;
    public UInt32   dwQuality;
    public UInt32   dwBytesPerSecond;
    public UInt32   dwFlags;
    public IntPtr   lpFormat;
    public UInt32   cbFormat;
    public IntPtr   lpParms;
    public UInt32   cbParms;
    public UInt32   dwInterleaveEvery;

    public AVICOMPRESSOPTIONS ToStruct(){
        AVICOMPRESSOPTIONS returnVar = new AVICOMPRESSOPTIONS();
        returnVar.fccType = this.fccType;
        returnVar.fccHandler = this.fccHandler;
        returnVar.dwKeyFrameEvery = this.dwKeyFrameEvery;
        returnVar.dwQuality = this.dwQuality;
        returnVar.dwBytesPerSecond = this.dwBytesPerSecond;
        returnVar.dwFlags = this.dwFlags;
        returnVar.lpFormat = this.lpFormat;
        returnVar.cbFormat = this.cbFormat;
        returnVar.lpParms = this.lpParms;
        returnVar.cbParms = this.cbParms;
        returnVar.dwInterleaveEvery = this.dwInterleaveEvery;
        return returnVar;
    }
}

With this workaround, we are able to call AVISaveOptions and (later on) AVISaveV in C#. Now, the new stream can be filled with image frames using AddFrame:

public void AddFrame(Bitmap bmp){
    bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);

    //lock the memory block

    BitmapData bmpDat = bmp.LockBits(
        new Rectangle(
        0,0, bmp.Width, bmp.Height),
        ImageLockMode.ReadOnly, bmp.PixelFormat);

    //add the bitmap to the (un-)compressed stream

    int result = Avi.AVIStreamWrite(
        writeCompressed ? compressedStream : aviStream,
        countFrames, 1,
        bmpDat.Scan0,
        (Int32)(bmpDat.Stride * bmpDat.Height),
        0, 0, 0);

    //unlock the memory block

    bmp.UnlockBits(bmpDat);

    //count the frames, so that we don't have to

    //call AVIStreamLength for every new frame

    countFrames++;
}

Now, we are able to fill an empty stream with images. But what can we do to add frames to an existing stream? Well, first, we have to open the stream with the third constructor.

Re-compress a video stream

public VideoStream(int aviFile, IntPtr aviStream){

    this.aviFile = aviFile;
    this.aviStream = aviStream;

    //read the stream's format

    Avi.BITMAPINFOHEADER bih = new Avi.BITMAPINFOHEADER();
    int size = Marshal.SizeOf(bih);
    Avi.AVIStreamReadFormat(aviStream, 0, ref bih, ref size);
    Avi.AVISTREAMINFO streamInfo = GetStreamInfo(aviStream);

    //store the important format values

    this.frameRate = streamInfo.dwRate / streamInfo.dwScale;
    this.width = (int)streamInfo.rcFrame.right;
    this.height = (int)streamInfo.rcFrame.bottom;
    this.frameSize = bih.biSizeImage;
    this.countBitsPerPixel = bih.biBitCount;

    //get the count of frames that are already there

    int firstFrame = Avi.AVIStreamStart(aviStream.ToInt32());
    countFrames = 
       firstFrame + Avi.AVIStreamLength(aviStream.ToInt32());
}

If you are sure the video stream is not compressed, you can call AddFrame now. Otherwise, you have to decompress the existing frames, and recompress them into a new stream:

public AviManager DecompressToNewFile(String fileName, 
                                        bool recompress){
    //create a new AVI file

    AviManager newFile = new AviManager(fileName, false);

    //create a video stream in the new file

    this.GetFrameOpen();
    Bitmap frame = GetBitmap(0);
    VideoStream newStream = 
        newFile.AddVideoStream(recompress, frameRate, frame);

    //decompress each frame and add it to the new stream

    for(int n=1; n<countFrames; n++){
        frame = GetBitmap(n);
        newStream.AddFrame(frame);
    }

    this.GetFrameClose();

    return newFile;
}

DecompressToNewFile creates a writeable copy of the stream in a new file. You can add frames to this new stream, close the new AviManager to save it, and then add the sound stream from the old file to complete the copy. Adding frames to a video is not easy, but this way it works.

Separate a stream

Sometimes, you might have a video file with sound, but you only need the silent video, or only the sound. It is not necessary to copy each frame, you can open the stream as usual and export it with AVISaveV. This works with all kinds of streams, only the compression options are different:

public override void ExportStream(String fileName){
    Avi.AVICOMPRESSOPTIONS_CLASS opts = 
                new Avi.AVICOMPRESSOPTIONS_CLASS();

    //for video streams

    opts.fccType = (UInt32)Avi.mmioStringToFOURCC("vids", 0);
    opts.fccHandler = (UInt32)Avi.mmioStringToFOURCC("CVID", 0);

    //for audio streams

    //opts.fccType = (UInt32)Avi.mmioStringToFOURCC("auds", 0);

    //opts.fccHandler = (UInt32)Avi.mmioStringToFOURCC("CAUD", 0);


    //export the stream

    Avi.AVISaveV(fileName, 0, 0, 1, ref aviStream, ref opts);
}

Import sound from a Wave file

Now, we are able to build a video from bitmaps, and extract sound from it. And how does the sound get into the file? We could use AVISaveV again, to combine the video and audio streams in a new file - but we don't have to. The easiest way to add a new audio stream is to open the Wave file as an AVI file with only one stream, and then copy that stream:

public void AddAudioStream(String waveFileName){
    //open the wave file

    AviManager audioManager = 
        new AviManager(waveFileName, true);
    //get the wave sound as an audio stream...

    AudioStream newStream = audioManager.GetWaveStream();
    //...and add it to the file

    AddAudioStream(newStream);
    audioManager.Close();
}

public void AddAudioStream(AudioStream newStream){
    Avi.AVISTREAMINFO streamInfo = new Avi.AVISTREAMINFO();
    Avi.PCMWAVEFORMAT streamFormat = new Avi.PCMWAVEFORMAT();
    int streamLength = 0;

    //read header info, format and length, 

    //and get a pointer to the wave data

    IntPtr waveData = newStream.GetStreamData(
        ref streamInfo,
        ref streamFormat,
        ref streamLength);

    //create new stream

    IntPtr aviStream;
    Avi.AVIFileCreateStream(aviFile, out aviStream, 
                                      ref streamInfo);

    //add format new stream

    Avi.AVIStreamSetFormat(
        aviStream, 0,
        ref streamFormat,
        Marshal.SizeOf(streamFormat));

    //copy the raw wave data into the new stream

    Avi.AVIStreamWrite(
        aviStream, 0,
        streamLength,
        waveData,
        streamLength,
        Avi.AVIIF_KEYFRAME, 0, 0);

    Avi.AVIStreamRelease(aviStream);
}

Copy a clip from video and sound

I have added this method, because many people asked me how this could be done. To copy a part of the video stream from second X to second Y, the indices of the first and last frames have to be calculated from the frame rate and second. For the Wave stream, we must calculate the byte offsets from samples per second, bits per sample, and the requested seconds. The rest is only copy and paste:

public AviManager CopyTo(String newFileName,
    int startAtSecond, int stopAtSecond) {
    AviManager newFile = new AviManager(newFileName, false);

    try {
        //copy video stream


        VideoStream videoStream = GetVideoStream();

        int startFrameIndex = 
             videoStream.FrameRate * startAtSecond;
        int stopFrameIndex = 
             videoStream.FrameRate * stopAtSecond;

        videoStream.GetFrameOpen();
        Bitmap bmp = videoStream.GetBitmap(startFrameIndex);

        VideoStream newStream = newFile.AddVideoStream(
             false,
             videoStream.FrameRate,
             bmp);

        for (int n = startFrameIndex + 1; 
                     n <= stopFrameIndex; n++) {
            bmp = videoStream.GetBitmap(n);
            newStream.AddFrame(bmp);
        }
        videoStream.GetFrameClose();

        //copy audio stream


        AudioStream waveStream = GetWaveStream();

        Avi.AVISTREAMINFO streamInfo = 
                         new Avi.AVISTREAMINFO();
        Avi.PCMWAVEFORMAT streamFormat = 
                         new Avi.PCMWAVEFORMAT();
        int streamLength = 0;
        IntPtr ptrRawData = waveStream.GetStreamData(
            ref streamInfo,
            ref streamFormat,
            ref streamLength);

        int startByteIndex = waveStream.CountSamplesPerSecond
               * startAtSecond
               * waveStream.CountBitsPerSample / 8;

        int stopByteIndex = waveStream.CountSamplesPerSecond
               * stopAtSecond
               * waveStream.CountBitsPerSample / 8;

        ptrRawData = 
          new IntPtr(ptrRawData.ToInt32() + startByteIndex);

        byte[] rawData = 
          new byte[stopByteIndex - startByteIndex];
        Marshal.Copy(ptrRawData, rawData, 0, rawData.Length);

        streamInfo.dwLength = rawData.Length;
        streamInfo.dwStart = 0;

        IntPtr unmanagedRawData = 
              Marshal.AllocHGlobal(rawData.Length);
        Marshal.Copy(rawData, 0, unmanagedRawData, 
                                     rawData.Length);

        newFile.AddAudioStream(unmanagedRawData,
              streamInfo,
              streamFormat,
              rawData.Length);

    } catch (Exception ex) {
        newFile.Close();
        throw ex;
    }

    return newFile;
}

If you are still interested in AVI videos, download the wrapper library and the demo application. Finally, I dare to say: have fun with AVIFile!

Known issues

Adding frames to an existing stream does not work with all video codecs and/or bitmaps. You might get a StackOverflowException or broken frames. If you find out why this happens, please let me know.

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralMilliseconds per Frame
Alexander Müller
13:37 8 Feb '10  
Hi,

at first: Thanks! I started writing nearly the same wrapper until I found out you already did it.
I am using this wrapper to extract frames which I convert to OpenGL textures and I synchronize
repaint events using the number of milliseconds per frame... I've added this to my wrapper before
I found yours and find it really useful. You might want to add it as well.

Here is (the really simple) patch:

Add this to Avi.cs:

[DllImport("avifil32.dll")]
public static extern int AVIStreamSampleToTime(
int pavi,
int lastFrame
);

Go to the constructor of VideoStream with the signature public VideoStream(int aviFile, IntPtr aviStream) and add following line to the end of the constructor:
this.millisecondsPerFrame = Avi.AVIStreamSampleToTime(aviStream.ToInt32(), this.countFrames) / this.countFrames;

Last but not least, add a nice property, e.g.:
/// <summary>milliseconds per frame</summary>
/// <remarks>Added by A. Müller</remarks>
protected int millisecondsPerFrame = 0;
public int MillisecondsPerFrame
{
get { return millisecondsPerFrame; }
}

Wink
GeneralIssue with 8bpp bitmaps
BogdanJankowski
15:33 25 Jan '10  
Hi Corinna. Thanks a lot for this very useful library. Great Job!

I have a question regarding 8bpp bitmap (gray-scale images) files. When I try extract set of 8bpp into AVI file then AVI file is very poor quality ( pink, green, etc. colors...) It's not similar to separates bitmaps Wink

Is it way to avoid that?

Thanks in advance.
Bogdan
GeneralRe: Issue with 8bpp bitmaps
BogdanJankowski
1:06 27 Jan '10  
I am sorry for the confusion. The behavior which I have experienced was caused by lack of needed codecs. Now everything works fine.

Regards,
Bogdan
QuestionExcept the one given sample I can't open any avi file
Member 786670
0:27 19 Jan '10  
Madam ,
I'm using ur code for my research purpose and the problem is its not opening other avi files except the one u gave (test.avi). How can we analyse another avi video. This avi is being played by the windows media player and all other players.
Venu
GeneralCode works. But on Win7 64Bit I have problems.
Nasenbaaer
0:25 13 Jan '10  
Hi

Regarding to use:
http://www.codeproject.com/Messages/2400581/Re-video-compressor-preselected-no-video-compresso.aspx[^]

I have the error:
Exception in AVIMakeCompressedStream: -2147205007

in function:
Private Sub CreateCompressedStream(ByVal options As Avi.AVICOMPRESSOPTIONS)

can you advise?
GeneralError - Flipped frames
wpiatkowski
8:04 19 Dec '09  
I create video from two different images. These two images makes about 200 frames in one image. The code is:

private void CreateAndSaveAviFromBitmap(List<Frame> frames,string path,string fileName, double duration)
{
if (frames == null || frames.Count == 0)
{
return;
}
AviManager aviManager = new AviManager(path + @"\" + fileName, false);
double frameRate = 4;
double maxFrames = frameRate * duration;
VideoStream aviStream = aviManager.AddVideoStream(false, frameRate, frames[0].Bitmap);
var currentFrameNr = 0;
double frameMultiplication = maxFrames / frames.Count;
//Bitmap bmp;
foreach (var frame in frames)
{
++currentFrameNr;

for (int i = 0; i < frameMultiplication; ++i)
{
// bmp = frame.Bitmap;
aviStream.AddFrame(frame.Bitmap);
// bmp.Dispose();
}

}
aviManager.Close();
}


There is a problem with created video. Each following frame is flipped verticaly from previous one. Why is that? How can I avoid this issue ?
GeneralProblem with frame rate
Pinnacle Rob
12:47 8 Dec '09  
This is a fantastic library and demo program. Thank you. Just what I was looking for to do some home cooked video editing. However -
When I try to copy a movie from my digital camera with a frame rate of 29.724518456389 the result has a different rate. The problem is with the GetRateAndScale routine in VideoStream.cs which tries to make an integer for the Rate. There are many ways to fix it. I just capped the scale at 1000000. Bob
GeneralImportant To Note : Codecs
Jason Gross
8:30 29 Nov '09  
It's important to note that codecs play an important part of this code working. The operating system that the code is working against needs the appropriate codecs your AVI is using (if you plan on opening/reading from existing AVIs).
Generalfabulous - This code really rocks
Nasenbaaer
7:03 3 Nov '09  
Hi.

I think this was one of the best projects for me here in The Code Project.

Thanks for sharing.

Regards
Timo
GeneralAbout videoStream framerate
joelihn
22:24 22 Oct '09  
Excelent article. This source code help me to finish my developement.

But i have a question about the videoStream framerate,i found it`s not accurately.Because just use Thread.Sleep(millisecondsPerFrame),ignore the cost of the code in the for circle before Thread.Sleep().I make a test, implement the code cost 30-50ms, therefore, i use Thread.Sleep(millisecondsPerFrame-time cost by the code),but when i set framerate larger then 25,it still not accurately.So, i want to konw how to make it accurately.Thanks.
GeneralChange aspect ratio
sunonsea
7:26 21 Oct '09  
Hello
Is it possible create an avi from bmp but with a differnt aspect ratio??
Thanks
GeneralRe: Change aspect ratio
Corinna John
9:45 21 Oct '09  
All frames must have the same aspect ratio. But some codecs allow patch frames which contain only the part of the image that is actually changed.

This statement is false.

GeneralCannot add frames
MarqW
0:26 19 Oct '09  
Even in your demo application, I cannot add frames-

Exception in Paste: -2147205018
at AviFile.EditableVideoStream.Paste(IntPtr sourceStream, Int32 copyPosition, Int32 pastePosition, Int32 length) in C:\Temp\ScreenCap\aviFileWrapperDemo_src\AviFile\EditableVideoStream.cs:line 102
at AviFile.EditableVideoStream.Paste(VideoStream sourceStream, Int32 copyPosition, Int32 pastePosition, Int32 length) in C:\Temp\ScreenCap\aviFileWrapperDemo_src\AviFile\EditableVideoStream.cs:line 89
at AviDemo.EditControl.btnAddFrame_Click(Object sender, EventArgs e) in C:\Temp\ScreenCap\aviFileWrapperDemo_src\AviDemo\EditControl.cs:line 144


Literally ran the demo project, clicked the Edit tab, "Edit Selected File" button, Insert Frames->Browse button, "Add Frame" button.

Any ideas? Thanks
GeneralIt can't read above 2GB.[Avifil32.dll] limitation?
KangWooSauk
20:34 14 Oct '09  
Hi Corinna!

I'm making the RAW-AVI to YV12 converter with your source code.
But, I found, your source code can't read above 2GB.
(My source file is 160Giga bytes, 1920x1080 resolution,
uncompressed raw data and 12 minute of running time)
I'm thinking, this is limitation of AVIFIL32.DLL.

I'd like to hear your advice.
GeneralRe: It can't read above 2GB.[Avifil32.dll] limitation?
Corinna John
22:45 14 Oct '09  
It is a limitation of AVI 1.0 in general. The file format would allow sizes up to 4 GB, but AVIFIL32 won't read more than 2 GB.

This statement is false.

GeneralRe: Thanks for your response!
KangWooSauk
7:25 15 Oct '09  
This limitation is regret...
But, I'll search another solution.

Thanks.
Questioncannot open AVI files
iena.damsky
7:55 27 Sep '09  
Hi Corinna!

Great job on the lib, not only it wll be able to save me alot of time to write something similar, but it also helped me understand bettr how the avi format works.

every AVI file I've downloaded from the internet seems to kill the app in the AVIStreamGetFrameOpen step.
is it beacuse they ae prbably AVI 2.0?
if so, do you have a recommendation as to what to do with it?
I need to open AVI files so I will be able to use the data inside them (I'm trying to implement the video snapcut algorithm) and meanwhile your video stream calss seems to be the best way to do so.

thanks,

Irena
AnswerRe: cannot open AVI files
Corinna John
4:22 29 Sep '09  
Hi Irena!
Sadly, VfW cannot handle AVI 2.0 files. Cry

This statement is false.

GeneralHow to use AVIFileReadData method
MarkDRatc
18:49 23 Aug '09  
I really appreciate the work done on the AviFile library. It does not include the translation into C# of the AVIFileReadData method. I have an AVI file with a SUBJECT within the INFO chunk, which is the ISBJ FourCC code. I want to retrieve this information from the AVI file, but I don't know exactly how to do it.

The Windows SDK doc indicates the method as:

STDAPI AVIFileReadData(
PAVIFILE pfile,
DWORD ckid,
LPVOID lpData,
LONG * lpcbData
);

I think the C# translation should be:

[DllImport("avifil32.dll")]
public static extern int AVIFileReadData(
int pfile,
int ckid,
IntPtr lpData,
out int lpcbData
);

The code that I am trying to use is this:

Avi.AVIFileInit();
int aviFile = 0;
int result;

result = Avi.AVIFileOpen(ref aviFile, "Cap0.avi", Avi.OF_READWRITE, 0);
if (result == 0)
{
int fourCCInfo = Avi.mmioFOURCC('I', 'S', 'B', 'J');
IntPtr dataPtr = Marshal.AllocHGlobal(256);
int dataSize;
result = Avi.AVIFileReadData(aviFile, fourCCInfo, dataPtr, out dataSize);
if (result == 0)
{
... retrieve the buffer and get the data

}
}

The call to open the file is successful. I know that the INFO chunk is in the file and the subchunk of ISBJ is there as well, since I can view this with a RIFF viewer utility. The call to AVIFileReadData fails, however, with an HRESULT value of -2147205005

Please help!!

Thanks,

Mark

MarkDRatc
South Carolina, USA

Generalerror opening AVI fles
Lawrence Botley
4:53 15 Aug '09  
Hi,

I have tried quite a few avi files and i always get an exception on the GetFrameOpen() call

Is there any way the library can open a dvd for editing?

thanks very much!

Lawrence

Within the twentieth century, an ultraintelligent machine will be built and that it will be the last invention that man need make.

I.J. Good

QuestionProblem with low FPS Movies
saharon10
23:09 11 Aug '09  
I want to compress images to a movie with 3 FPS.
But when I do that, I get a movie with the right length but only one image is shown.
I get this issue when I go under 5 fps.
Anyone has an idea what the problem is and how can I fix it?
GeneralToo much code?
OChecker
6:16 4 Aug '09  
Hey guys,

just a little question:
There´s the Convert-function from a frame into a bitmap with the following code:

int dib = Avi.AVIStreamGetFrame(getFrameObject, firstFrame + position);
//Copy the bitmap header into a managed struct
Avi.BITMAPINFOHEADER bih = new Avi.BITMAPINFOHEADER();
bih = (Avi.BITMAPINFOHEADER)Marshal.PtrToStructure(new IntPtr(dib), bih.GetType());


Can´t the BitmapInfoHeader given in 'Avi.AVIStreamGetFrameOpen(StreamPointer, ref bih)' also do this job? The focus is actually on getFrameObject as the result, but I thought, the second parameter could be useful to. Is it?
QuestionAVI Image issues
Douglas White
9:35 3 Aug '09  
Hi,

I am using your code to read frames from an AVI movie file. However, the image quality I am getting out is really bad, and I need the images to be representations of the original data stream. Instead of getting the original movie, when I was using your code I get a weird multicolored image which vaguely resembles the original. Any ideas?
Generalmerging avi with MP3
abrar from uet lahore
5:12 29 Jul '09  
Is it possible to merge AVI with mp3?

abrar

GeneralRe: merging avi with MP3
Corinna John
6:27 29 Jul '09  
It is possible with AVI 2.0 and an MPEG codec, i.e. XVid.

This statement is false.


Last Updated 4 Jan 2006 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010