This article covers one of the possible implementations of the scenario when it's needed to record content from two or more screens into one video.
Both MFormats and MPlatform implement this scenario using the same approach. We create as many MFLiveClass / MLiveClass instances as many monitors we want to capture in one video. For simplicity, in this article we will consider an example with two monitors that are located horizontally to each other.
MFormats implementation
If your application is based on MFormats SDK, it's needed to create empty frames via MFFactoryClass instance through MFFrameCreateFromMem() method. The created frame resolution should be enough for overlaying all the frames as we desire. For example, if we want to record two Full-HD screens which are located side by side without any gaps and frame squeezing, we need to create 3840×1080 pixels frames.
// Creating the empty frame for further overlaying:
MFFactoryClass m_objFactory = new MFFactoryClass();
M_AV_PROPS frameProps = new M_AV_PROPS();
frameProps.vidProps.eVideoFormat = eMVideoFormat.eMVF_Custom;
frameProps.vidProps.fccType = eMFCC.eMFCC_ARGB32;
frameProps.vidProps.dblRate = 60.0;
frameProps.vidProps.nWidth = 3840;
frameProps.vidProps.nHeight = 1080;
m_objFactory.MFFrameCreateFromMem(ref frameProps, 0, 0, 0, out MFFrame createdFrame, "solid_color='black'");
Thereafter, we grab the frames from the sources and overlay them on the created empty frames. When the result frame is ready, the only thing left is to put the frame into MFWriterClass / MWriterClass instance. Since the result frame has a nonstandard resolution, it's needed to disable any conversions or to define a custom one to prevent any frame squeezing.
// Overlaying frames from lives on the created frame:
createdFrame.MFOverlay(frameFormLive1, null, 0, 0, 1, "", "ch1");
createdFrame.MFOverlay(frameFormLive2, null, 1920, 0, 1, "", "ch2");
So that, the result scheme for MFormats SDK based app looks like this:
MPlatform implementation
If your application is based on MPlatform SDK, the idea is the same. But although MPlatform SDK has a similar method (FrameOverlay()), we would like to recommend using MMixer for overlaying two pictures because this approach is much easier, and it keeps the code much more maintainable. MMixer will generate the empty frames in the same way as it's done by MFFactoryClass in MFormats SDK.
// Defining MMixer output format:
M_AV_PROPS frameProps = new M_AV_PROPS();
frameProps.vidProps.eVideoFormat = eMVideoFormat.eMVF_Custom;
frameProps.vidProps.fccType = eMFCC.eMFCC_ARGB32;
frameProps.vidProps.dblRate = 60.0;
frameProps.vidProps.nWidth = 3840;
frameProps.vidProps.nHeight = 1080;
m_objMixer.FormatVideoSet(eMFormatType.eMFT_Convert, ref frameProps.vidProps);
m_objMixer.ObjectStart(null);
// Configuring MLives:
m_objMLive_1.DeviceSet("video", "Medialooks DXGI/DX11 ScreenCapture", "");
m_objMLive_1.PropsSet("device::capture.screen_index", "1");
m_objMLive_1.ObjectStart(null);
m_objMLive_2.DeviceSet("video", "Medialooks DXGI/DX11 ScreenCapture", "");
m_objMLive_2.PropsSet("device::capture.screen_index", "0");
m_objMLive_2.ObjectStart(null);
// Configuring MMixer:
m_objMixer.StreamsAdd("Screen_1", m_objMLive_1, "", "", out _, 0.0d);
m_objMixer.StreamsAdd("Screen_2", m_objMLive_2, "", "", out _, 0.0d);
m_objMixer.ElementsGetByIndex(0, out MElement root);
(root as IMElements).ElementsAdd("", "video", "stream_id=Screen_1 pos=top-left h=1 w=0.5 x=0 y=0 show=1", out _, 0.0d);
(root as IMElements).ElementsAdd("", "video", "stream_id=Screen_2 pos=top-left h=1 w=0.5 x=0.5 y=0 show=1", out _, 0.0d);
And the result scheme for MPlatform SDK based app looks like this: