This documentation is for the old version. Go to the latest Graphics Mill docs

Reading Video Files Frame by Frame

The main feature of Media Processor Add-on is to read video files in different formats frame by frame. Reading video this way you can display it on the screen, save certain frames to separate files and convert the file to AVI format using AVI Processor Add-on for Graphics Mill.

Creating the Reader

There are two approaches to reading frames:

  • Random access when you specify the number of the desired frame and load only it.
  • Sequential access when you load all frames one after another.

No matter which approach you are going to use, you should start with opening the file with a reader. To create a reader, use the MediaFormatManager.CreateFormatReader method or create the reader of the required type explicitly:

If you use the MediaFormatManager class for creating the reader, the actual type of the reader will be detected automatically.

Visual Basic
'Create a reader using the class factory
Private Sub CreateReader(ByVal fileName As String)
    Try
        reader = MediaFormatManager.CreateFormatReader(fileName)
    Catch ex As System.Exception
        MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, _
            MessageBoxIcon.Error)
    End Try
End Sub
C#
//Create a reader using the class factory
private void CreateReader(String fileName)
{
    try
    {
        reader = MediaFormatManager.CreateFormatReader(fileName);
    }
    catch(System.Exception ex)
    {
        MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK,
            MessageBoxIcon.Error);
    }

}

And the following sample shows how to open a reader of a specific type (in this case, WMReader).

Visual Basic
'Create a specific reader (Windows Media)
Private Sub CreateWMReader(ByVal fileName As String)
    Try
        reader = New WMReader(fileName)
    Catch ex As System.Exception
        MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, _
            MessageBoxIcon.Error)
    End Try
End Sub
C#
//Create a specific reader (Windows Media)
private void CreateWMReader(String fileName)
{
    try
    {
        reader = new WMReader(fileName);
    }
    catch(System.Exception ex)
    {
        MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK,
            MessageBoxIcon.Error);
    }

}
Note

When you open a file for reading, no data is actually loaded from it. The data is loaded only on demand, that is, when you get the image from the frame. This way Media Processor Add-on is memory-friendly.

However when the file is opened, it becomes locked by the application. No other application can remove or modify this file. That is why it is highly recommended to close or dispose the reader object as soon as possible.

Accessing Frames

Random Access

Each reader represents a frame collection, and once you have created it, you can access frames. One of the ways to do it is to load single specific frames. Remember though that not all file formats support this kind of reading by default because not all of them contain a seek index. The seek index assigns a unique (for the opened file) number to each frame and allows addressing frames with these numbers. If the index is absent, frames can be read only one after another.

To check, if the required file contains the seek index and, therefore, supports random access to frames, use the IsFrameSeekable property. If the file does not support this way of reading frames, you may create the index as it is described in the File Indexing for Random Access section below.

If the file you are working with supports random access, you can get a specific frame by its number using the LoadFrame(Int32) method. The total number of frames in the reader is stored in the FrameCount property.

Visual Basic
'Process a random frame
Private Sub ProcessFrame(ByVal idx As Int32)
    If idx = 0 Then
        Return
    End If
    'Check if the frame exists at all
    If idx < 0 Or idx >= reader.FrameCount Then
        MessageBox.Show("Incorrect index value. Cannot open specified frame.", _
            "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        Return
    End If
    Dim frame As IFrame = reader.LoadFrame(idx)
    'Do something with the frame
    '...
End Sub
C#
//Process a random frame
private void ProcessFrame(Int32 idx)
{
    if (idx == 0)
        return;
    //Check if the frame exists at all
    else if (idx < 0 || idx >= reader.FrameCount)
    {
        MessageBox.Show("Incorrect index value. Cannot open specified frame.",
            "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return;
    }
    //Load the frame
    IFrame frame = reader.LoadFrame(idx);
    //Do something with the frame
    //...
}

The LoadFrame(Int32) method also allows iterating through the files sequentially, using the for loop.

Sequential Access

Another way to access frames is to load them sequentially, one by one. As it is mentioned above, the reader is a collection of frames, so you can go through them with the foreach statement.

Visual Basic
'Process frames one by one
Private Sub ProcessFrames()
    Try
        For Each frame As IFrame In reader
            'Do something with the frame
            '...
        Next
    Catch ex As System.Exception
        MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, _
            MessageBoxIcon.Error)
    End Try
End Sub
C#
//Process frames one by one
private void ProcessFrames()
{
    try 
    {
        foreach (IFrame frame in reader)
        {
            //Do something with the frame
            //...
        }
    }
    catch (System.Exception ex)
    {
        MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK,
            MessageBoxIcon.Error);
    }
}

Sequential access is supported for files of all formats by default.

File Indexing for Random Access

If the file you are working with is an ASF file that does not support random access to frames, you can try to create an index for it. It can be done with the help of the AsfIndexer class.

The AsfIndexer class provides two Index methods, and both of them can be used for creating ASF file indices. One of them takes a file name as a parameter and overwrites the existing file with its indexed version. If the operation of index creation fails, the original file is left unchanged. If you want to keep an original file, use the second method. It takes two file names: one for the source file, and another for the indexed copy. If the operation of index creation fails, the copy is deleted.

C#
string inputFilename = @"C:\chicken.wmv";
string outputFilename = @"C:\chicken-indexed.wmv";
try
{
    //Create the reader
    IFormatReader reader = MediaFormatManager.CreateFormatReader(inputFilename);

    //Check if the file is indexed
    if (!reader.IsFrameSeekable)
    {
        AsfIndexer indexer = new AsfIndexer();
        //Create an indexed copy
        indexer.Index(inputFilename, outputFilename);
    }
    else 
        Console.WriteLine("The file is already indexed.");
}
catch(System.Exception e)
{
    Console.WriteLine("Error: '{0}'", e);
    throw;
}
Visual Basic
Dim inputFilename As String = "C:\chicken.wmv"
Dim outputFilename As String = "C:\chicken-indexed.wmv"
Try
    'Create the reader
    Dim reader As IFormatReader = MediaFormatManager.CreateFormatReader _
    (inputFilename)
    'Check if the file is indexed
    If Not reader.IsFrameSeekable Then
        Dim indexer As New AsfIndexer
        'Create an indexed copy
        indexer.Index(inputFilename, outputFilename)
    Else
        Console.WriteLine("The file is already indexed.")
    End If
Catch ex As Exception
    Console.WriteLine("Error: '{0}'", ex)
    Throw
End Try

Working With Frame Content

Media Processor Add-on provides three types of frame objects, one for each reader:

They all inherit from the base Frame class.

After reading a frame in the way that is most convenient for you, you can process its content. For example, you can load an image stored in the frame using the GetBitmap(Bitmap) method. This method returns a Bitmap object. Now, you can do whatever you want with that image—save it as a file, process it, or simply display on the screen.

Visual Basic
Private Sub GetFrameImage(ByVal frame As IFrame, ByVal fileName As String)
    Dim image As Aurigma.GraphicsMill.Bitmap = New Aurigma.GraphicsMill.Bitmap
    Try
        'Get the bitmap
        frame.GetBitmap(image)
        'Save the bitmap to file
        image.Save(fileName)
    Catch ex As System.Exception
        MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, _
         MessageBoxIcon.Error)
    End Try
End Sub
C#
private void GetFrameImage(IFrame frame, String fileName)
{
    Aurigma.GraphicsMill.Bitmap image = new Aurigma.GraphicsMill.Bitmap();
    try
    {
        //Get the bitmap
        frame.GetBitmap(image);
        //Save the bitmap to file
        image.Save(fileName);
    }
    catch (System.Exception ex)
    {
        MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK,
            MessageBoxIcon.Error);
    }
}

If you need to get a resized copy of the image in the frame, use the GetThumbnail(Bitmap, Int32, Int32) method. Calling this method is a faster way of getting a thumbnail than using a combination of GetBitmap(Bitmap) and Resize.

See Also

Samples

Reference

Manual