MFormats SDK: simple live source

Working with live sources in MFormats SDK is as easy as file playback. This post explains how to receive video from live sources. Video playout is covered in a separate post.


Receiving frames from devices is very similar to reading from files: you need to receive a frame from the device and send it to preview. Input devices are handled by the MFLiveClass. For preview we will use the same MFPreviewClass (like in the simple playout scenario).


MFPreviewClass m_objPreview = new MFPreviewClass();
MFLiveClass m_objLive = new MFLiveClass();


We will be receiving frames in a separate thread to make sure that our GUI is isolated (you can do the same for file playback). Here we will use BackgroundWorker object:


BackgroundWorker m_bgWorker = new BackgroundWorker();
m_bgWorker.WorkerSupportsCancellation = true;
m_bgWorker.WorkerReportsProgress = true;


To initialize the preview:


//Configure preview
m_objPreview.PreviewWindowSet("", panelPreview.Handle.ToInt32());
m_objPreview.PreviewEnable("", 1, 1); // enable audio and video preview


There may be many devices on your machine so there's a way to get a list of all of the available devices:


int vCount;
m_objLive.DeviceGetCount(eMFDeviceType.eMFDT_Video, out vCount); // get a number of available devices
if (vCount > 0)
{
	for (int i = 0; i  vCount; i++)
	{
	string strName;
	int _pbBusy;
	m_objLive.DeviceGetByIndex(eMFDeviceType.eMFDT_Video, i, out strName, out _pbBusy); // get a video device
	comboBoxV.Items.Add(strName); // add device's name into combobox list
	}
	comboBoxV.SelectedIndex = 0; // to set the 1st available device
}


As you know, all devices support several source video formats. To work with formats we need to use IMFFormat interface and its methods. To be able to select the required format we need to enumerate all of the available video formats:


int fCount;
string name;
M_VID_PROPS vidProps;
m_objLive.FormatVideoGetCount(eMFormatType.eMFT_Input, out fCount);
if (fCount > 0)
{
	for (int i = 0; i  fCount; i++)
	{
	m_objLive.FormatVideoGetByIndex(eMFormatType.eMFT_Input, i, out vidProps, out name);
	comboBoxVF.Items.Add(name); // add the format into combobox list
	}
	// Get current video format
	int nCurrent = 0;
	try
	{
	string strName;
	M_VID_PROPS _vidProps;
	m_objLive.FormatVideoGet(eMFormatType.eMFT_Input, out _vidProps, out nCurrent, out strName);
	}
	catch { }
	// Select current video format
	comboBoxVF.SelectedIndex = nCurrent;
}


Professional devices have different inputs: here's how we can get the list of available inputs. Inputs are represented as properties of the MFLiveClass object:


string strCurrent;
int nSel = -1;
int lCount;
string _pOptions, _pHelp;
m_objLive.PropsGet("line-in", out strCurrent); // get current input line
// get number of input lines
m_objLive.PropsOptionGetCount("line-in", out lCount);
if (lCount > 0)
{
	for (int i = 0; i  lCount; i++)
	{
	m_objLive.PropsOptionGetByIndex("line-in", i, out _pOptions, out _pHelp);
	comboBoxVL.Items.Add(_pHelp); // add a line into combobox list
	if (strCurrent == _pOptions)
		nSel = i; // compare indexes to get a current line
	}
	if (nSel >= 0)
	comboBoxVL.SelectedIndex = nSel; // select a current line
}


So, now we have a list of the available devices, and for each device we have the list of inputs and available video formats. Lets choose a device to work with:


m_objLive.DeviceSet(eMFDeviceType.eMFDT_Video, comboBoxV.SelectedIndex, ""); // select a device by selected index of combobox
// here we should get available input lines and video formats
m_objLive.PropsOptionSetByIndex("line-in", comboBoxVL.SelectedIndex); // set input line
M_VID_PROPS vidProps;
string name;
m_objLive.FormatVideoGetByIndex(eMFormatType.eMFT_Input, comboBoxVF.SelectedIndex, out vidProps, out name); // get a selected video format
m_objLive.FormatVideoSet(eMFormatType.eMFT_Input, vidProps); // set this format for the device


Now we are ready to start receiving the live video. Here we need go back to our BackgroundWorker object and configure it to get frames from the source and send them to preview:


private void bw_DoWork(object sender, DoWorkEventArgs e)
{
	BackgroundWorker worker = sender as BackgroundWorker;
	while (!worker.CancellationPending)
	{
	MFFrame pFrame = null;
	try
	{
		m_objLive.SourceFrameGet(-1, out pFrame, ""); // get a frame from source
		//Send frame to the preview
		m_objPreview.ReceiverFramePut(pFrame, -1, "");
		//Release frame from memory- DO NOT FORGOT TO DO THIS !!!
		Marshal.ReleaseComObject(pFrame);
	}
	catch { }
	}
}


Now, to start playback we need to connect this method with BackgroundWorker and start it:


// Start worker if not started yet
if (!m_bgWorker.IsBusy)
	m_bgWorker.RunWorkerAsync();


To close your device all you need is this:


m_bgWorker.CancelAsync(); // to stop a thread
m_objLive.DeviceClose(); // to close a device


As you can see, "victory loves preparation": most of the code is for device configuration. The rest is very simple.


You will also find this code in our Live input preview sample.