Here is the code that converts a window to a bitmap and then generates a frame from the bitmap that is converted to one of the standard formats and is sent to the output SDI:
factory = new MFFactoryClass();
renderer = new MFRendererClass();
renderer.DeviceSet(eMFDeviceType.eMFDT_Video, 0, "");
The above can be defined somewhere in your code. To work with the renderer, please refer to the existing samples of MFormats SDK, e.g. Sample File Playback C# or Initialization of a device for output.
The below code is a part of your main thread of frame processing (again, refer to MFormats SDK samples to get the idea):
Initialize the bitmap object, clear its memory and render the content into the bitmap:
int width = (int)ActualWidth;
int height = (int)ActualHeight;
RenderTargetBitmap targetBitmap = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
targetBitmap.Clear();
targetBitmap.Render(this);
For RGBA we use 4 bits. stride - the amount of memory for a single horizontal line of the resulting frame, bufferSize - total memory size of the frame:
int stride = 4 * width;
int bufferSize = stride * height;
Allocate some memory for a video buffer and copy the bitmap data to the allocated memory:
IntPtr bufferPtr = Marshal.AllocHGlobal(bufferSize);
targetBitmap.CopyPixels(new Int32Rect(0, 0, width, height), bufferPtr, bufferSize, stride);
Start the frame generation from the memory. Define the AV parameters (negative height is used to to handle upside-down frames in ARGB32 colourspace):
M_AV_PROPS props = new M_AV_PROPS();
props.vidProps.dblRate = 25.0;
props.vidProps.fccType = eMFCC.eMFCC_ARGB32;
props.vidProps.nWidth = width;
props.vidProps.nHeight = -height;
props.vidProps.nRowBytes = stride;
The actual method to generate a frame from the allocated memory:
factory.MFFrameCreateFromMem(ref props, bufferPtr.ToInt64(), 0, 0, out MFFrame frame, "");
To process the SDI output, the frame should have some time data (10.000.000 is a standard constant for time units calculation):
M_TIME time = new M_TIME();
time.rtStartTime = 0;
time.rtEndTime = (long)(10000000 / props.vidProps.dblRate);
frame.MFTimeSet(ref time);
Now, it's time to convert the frame, send the frame to the SDI output:
M_AV_PROPS convertedProps = new M_AV_PROPS();
convertedProps.vidProps.eVideoFormat = eMVideoFormat.eMVF_HD1080_60p;
int rest = 0;
do
{
MFFrame convertedFrame = null;
frame.MFConvert(ref convertedProps, out convertedFrame, out rest, "", "");
if (convertedFrame != null)
{
//Send frame to the preview
_myPreview.ReceiverFramePut(convertedFrame, -1, "");
Marshal.ReleaseComObject(convertedFrame);
Console.WriteLine(rest.ToString());
}
} while (rest > 0);
Marshal.ReleaseComObject(frame);
Marshal.ZeroFreeGlobalAllocAnsi(bufferPtr);
As a result, the following frame will be created and sent to the output: