Medialooks Knowledge Base Support Center

Contact Us

WPF preview

Preview process

Both MPlatform and MFormats SDK previews are based on Direct3D. But by design it requires a handle of a control to draw video on - you use PreviewWindowSet method for this.

When you work with WPF, controls don't have handles, so the approach to get video preview with MPreview (or MFPreview in MFormats SDK) is different.

The following description is common for both MFormats and MPlatform SDKs and followed with comments if something is different:

1. You create an MFPreview (MPreview for MPlatform SDK) object:

_myPreview = new MFPreviewClass();

2. You specify "wpf_preview" mode for MFPreview with:

_myPreview.PropsSet("wpf_preview", "true");

3. Enable preview

_myPreview.PreviewEnable("", 1, 1);

4. Use OnEventSafe for MFPreview object:

_myPreview.OnEventSafe += _myPreview_OnEventSafe;

5. Create a D3DImage object:

private D3DImage previewSource;
previewSource = new D3DImage();

6. Start playback of your source.

The moment you a frame is sent to preview in MFormats SDK with:

_myPreview.ReceiverFramePut(sourceFrame, -1, "");

or after you call 

_myPreview.ObjectStart(myPlaylist);

and frames start to reach MPreview object, a "wpf_nextframe" event is raised. Note please that previewImage in the following code is an Image control on your WPF window.

private IntPtr _mSavedPointer; // required to update image context
private void _myPreview_OnEventSafe(string bsChannelId, string bsEventName, string bsEventParam, object pEventObject)
        {
            if (bsEventName == "wpf_nextframe")
            {
                IntPtr pEventObjectPtr = Marshal.GetIUnknownForObject(pEventObject);
                if (pEventObjectPtr != _mSavedPointer)
                {
                    if (_mSavedPointer != IntPtr.Zero)
                        Marshal.Release(_mSavedPointer);

                    _mSavedPointer = pEventObjectPtr;
                    previewSource.Lock();
                    previewSource.SetBackBuffer(D3DResourceType.IDirect3DSurface9, IntPtr.Zero);
                    previewSource.SetBackBuffer(D3DResourceType.IDirect3DSurface9, _mSavedPointer);
                    previewSource.Unlock();
                    previewImage.Source = previewSource;                }

                if (pEventObjectPtr != IntPtr.Zero)
                    Marshal.Release(pEventObjectPtr);

                previewSource.Lock();
                previewSource.AddDirtyRect(new Int32Rect(0, 0, _previewSource.PixelWidth, _previewSource.PixelHeight));
                previewSource.Unlock();
            }
            Marshal.ReleaseComObject(pEventObject);
        }

WPF-related preview properties

There are several properties for WPF preview for MPreview and MFPreview objects.

You can find them in system registry for MPlatform SDK:

HKEY_CURRENT_USER\SOFTWARE\Medialooks\MPlatform\MPreview

And for MFormats SDK:

HKEY_CURRENT_USER\SOFTWARE\Medialooks\MFormats\MFPreview

Or specify them with the PropsSet method of IMProps (MPlatform) or IMFProps (MFormats) interfaces.

The properties are:

"wpf_preview" 

It just enables WPF preview mode. So if "wpf_preview" = true then MPreview object has a possibility to use OnEvent that you use in your code now and sends a pointer to 3D Surface.

"wpf_preview.downscale"

By default, as a result, you have a full-frame sized D3DImage in the event. Because this is processed by DirectX there is no much effect on CPU usage. But still, there is a possibility to reduce size. 

For example, if your preview panel is 300x200, why do you need to feed it with 1920x1080 image? For this purpose, there is "wpf_preview.downscale" property. With "1" as value, result D3DImage is like it lost each other row (so the horizontal quality is the same, but vertical is reduced 2 times).

With "2" it cuts each other vertical and horizontal lines. So, as a result, the output 3D surface is 4 times smaller than the original one. 

It leads to lower CPU usage for drawing the image. But it is useful only for small preview panels.

"wpf_preview.update"

The property sets a number of frames before a context is updated - so a blank frame is returned. As a result, you have a "flickering" preview. By default, it is set to 30 so once per 30 frames there is such an artifact.

We set it to "30" by default because with our investigations the problem may appear at random. But it looks like it depends on the overall performance of a video card so it may work fine with "0" - no flickering at all should be in this case.

Possible issues

In MPlatform WPF Preview does not restart after close/start of the source object. How to solve?

When you close MLive object the matched MPreview keeps referring to its initial source. So you have to close the preview object with

myPreview.ObjectClose();

together with its source object and then start them together again with

mySource.ObjectStart(null); 
myPreview.ObjectStart(null);