MFormats SDK: simple video recorder

MFormats SDK will receive and capture each frame that arrives from a video source. In this article we will discuss MFWriter object, which is responsible for recording to disk and streaming to network. The article explains how to configure MFWriter object and write a simple video capture app.


This is MFWriter class:


MFWriterClass m_objWriter = new MFWriterClass();


The capture configuration has a tree structure: for each of the available container formats there is a set of supported video and audio codecs. So once you select a file format, you will need to update the list of codecs.


This is how you can get the full list of available capture formats:


int nCount;
m_objWriter.WriterOptionGetCount(eMFWriterOption.eMFWO_Format, out nCount); // get number of capturing formats (eMFWriterOption.eMFWO_Format)
for (int i = 0; i  nCount; i++)
{
	string myName, longName;
	m_objWriter.WriterOptionGetByIndex(eMFWriterOption.eMFWO_Format, i, out myName, out longName); // get short (ID) and long names of capturing format
	formatcombo.Items.Add(longName); // add a format name into combobox's list
}


If we select any of the ComboBox items we should set the capturing format:


IMFProps props;
m_objWriter.WriterOptionSetByIndex(eMFWriterOption.eMFWO_Format, formatcombo.SelectedIndex, out props);
Marshal.ReleaseComObject(props); // props object will not be used in this sample so we can release it from memory


And refresh the list of available audio and video codecs:


int nCount;
m_objWriter.WriterOptionGetCount(eMFWriterOption.eMFWO_VideoCodec, out nCount); // get number of capturing formats (eMFWriterOption.eMFWO_VideoCodec)
for (int i = 0; i  nCount; i++)
{
	string myName, longName;
	m_objWriter.WriterOptionGetByIndex(eMFWriterOption.eMFWO_VideoCodec, i, out myName, out longName); // get short (ID) and long names of video codec
	videocodec.Items.Add(longName); // add a video codec name to a list
}


Repeat the same process for audio codecs:


m_objWriter.WriterOptionGetCount(eMFWriterOption.eMFWO_AudioCodec, out nCount); // get number of audio codecs (eMFWriterOption.eMFWO_AudioCodec)
audiocodec.Items.Clear();
for (int i = 0; i  nCount; i++)
{
	string myName, longName;
	m_objWriter.WriterOptionGetByIndex(eMFWriterOption.eMFWO_AudioCodec, i, out myName, out longName); // get short (ID) and long names of audio codec
	audiocodec.Items.Add(longName); // add a video codec name to a list
}


All actions with containers and codecs are similar. To set a video codec by selected index we should call:


IMFProps props;
m_objWriter.WriterOptionSetByIndex(eMFWriterOption.eMFWO_VideoCodec, videocodec.SelectedIndex, out props);
Marshal.ReleaseComObject(props);


For an audio codec:


IMFProps props;
m_objWriter.WriterOptionSetByIndex(eMFWriterOption.eMFWO_AudioCodec, audiocodec.SelectedIndex, out props);
Marshal.ReleaseComObject(props);


To get the full configuration for capturing, call WriterGet method:


string tPath, options;
m_objWriter.WriterGet(out tPath, out options);
config.Text = options; // to show the configuration in user control


Here is an example of MFWriter configuration:


format='mp4' play_while_rec='true' video::codec='mpeg4' audio::codec='aac'


Before starting capturing to file, you should specify the destination for recording and configuration:


m_objWriter.WriterSet(outputFileName, 1, "format='mp4' play_while_rec='true' video::codec='mpeg4' audio::codec='aac'");


Now MFWriter object is open and ready to receive frames. To encode a frame from your source you should put the frame into MFWriter object:

m_objWriter.ReceiverFramePut(pFrame, -1, "");


where pFrame is the frame that is received from source.


Generally, the process of receiving and capturing a frame looks like this:


MFFrame pFrame = null;
try
{
	m_objLive.SourceFrameGet(-1, out pFrame, "");
	//Send the frame to the preview
	m_objPreview.ReceiverFramePut(pFrame, -1, "");
	// capture the frame
	if (rec) // rec here indicates whether capturing is started or not
	m_objWriter.ReceiverFramePut(pFrame, -1, "");
	//Release frame from memory
	Marshal.ReleaseComObject(pFrame);
}
catch { }


To stop capturing we should close MFWriter object with WriterClose method:


m_objWriter.WriterClose();


That's it. Enjoy your captured content! More sample code is available in the Writer sample.