Frame Acquire Effect -- A Custom UWP Video Effect

This is  the most simple operating of my UWP video effects, called the Frame Acquire Effect. It is meant to be used to get one frame and write that to a pointer memory allocation. The memory allocation is handled by the calling program. 

When the effect is added to the MediaCapture's chain, the MediaCapture returns a valid VideoEffect object. Properties can be written to this object to change inner settings while the effect is running. A frame can be acquired by writing a valid "FarPointer" (as an IntPtr via Marshal.AllocHGlobal( Frame Size In Bytes )) property to that returned VideoEffect object. 

The Frame Acquire Effect uses the pointer once to send pixel bytes, and then resets its inner pointer back to zero. This can then be repeated whenever someone wants a frame. The effect does not change the actual pointer.  

After the pointer is written to the effect's properties, you want to wait the width of a frame in time using the async call task.delay(x) before reading it, to give the hardware time to trap the next incoming frame and write its bytes to memory.  

Using video encoding properties (expressed here as asp), the time width in milliseconds for delay routine can be expressed as 1000 * CSng(asp.FrameRate.Denominator) / CSng(asp.FrameRate.Numerator) -- making 1/30 into 33.33 for instance.  

So here is the code for that: 

public sealed class FrameAcquireEffect : IBasicVideoEffect
    {
        private IntPtr farPointer;
        private CanvasDevice canvasDevice;

        public bool TimeIndependent { get { return true; } }

        public MediaMemoryTypes SupportedMemoryTypes { get { return MediaMemoryTypes.Gpu; } }

        public bool IsReadOnly { get { return true; } }

        public IReadOnlyList<VideoEncodingProperties> SupportedEncodingProperties
        {
            get
            {
                var encodingProperties = new VideoEncodingProperties();
                encodingProperties.Subtype = "ARGB32";
                return new List<VideoEncodingProperties>() { encodingProperties };
            }
        }

        public void SetEncodingProperties(VideoEncodingProperties encodingProperties, IDirect3DDevice device)
        {
            canvasDevice = CanvasDevice.CreateFromDirect3D11Device(device);
        }

        public void SetProperties(IPropertySet configuration)
        {

            if (configuration.TryGetValue("FarPointer", out object brb3))
            {
                farPointer = (IntPtr)brb3;
            }
            else
            {
                farPointer = IntPtr.Zero;
            }
        }

        public void DiscardQueuedFrames()
        {
        }

        public void Close(MediaEffectClosedReason reason)
        {
        }

        public void ProcessFrame(ProcessVideoFrameContext context)
        {
            using (CanvasBitmap inputBitmap = CanvasBitmap.CreateFromDirect3D11Surface(canvasDevice, context.InputFrame.Direct3DSurface))
            {
                if (farPointer != IntPtr.Zero)
                {
                    byte[] bt2 = inputBitmap.GetPixelBytes();
                    Marshal.Copy(bt2, 0, farPointer, bt2.Length);
                    farPointer = IntPtr.Zero;
                }
            }
        }
    }

I put this as the first effect in the chain, and use it to get raw video frames when effects are running, when I need to do stuff. Maybe compare some area of the screen with a logo bitmap, and "count stuff" to see if that logo is showing. Even when the screen is darkened and blurred by effects. 

Note about code listing. When copied the right arrow (<) and left arrow (>) may not show up properly, and instead be represented by the string literals (&lt;) and (&gt;) respectively. Replace those four character literals with the correct arrow in that case. 

Disclaimer: This is free for personal use only. Place of origin, California, US.