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.
There are two approaches to reading frames:
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.
'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
//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).
'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
//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); } }
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.
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.
'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
//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.
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.
'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
//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.
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.
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; }
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
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.
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
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.