How to render video from raw frames in WPF?

I have a special video camera (using the GigEVision protocol), which I control using the provided library. I can subscribe to the received frame event, and then access the frame data through IntPtr.

In my old WinForms application, I could visualize the frame by creating a Bitmap object from the data and setting it to the PictureBox, or by passing the PictureBox handle to a function in the library that will draw directly in the area.

What is the best and fastest way to do this in WPF? The camcorder runs from 30 to 100 frames per second.

edit (1):

Since the event received by the frame is not in the user interface thread, it must work through the threads.

edit (2):

I found a solution using WriteableBitmap:

void camera_FrameReceived(IntPtr info, IntPtr frame) 
{
    if (VideoImageControlToUpdate == null)
    {
        throw new NullReferenceException("VideoImageControlToUpdate must be set before frames can be processed");
    }

    int width, height, size;
    unsafe
    {
        BITMAPINFOHEADER* b = (BITMAPINFOHEADER*)info;

        width = b->biWidth;
        height = b->biHeight;
        size = (int)b->biSizeImage;
    }
    if (height < 0) height = -height;

        //Warp space-time
        VideoImageControlToUpdate.Dispatcher.Invoke((Action)delegate {
        try
        {
            if (VideoImageControlToUpdateSource == null)
            {
                VideoImageControlToUpdateSource =
                    new WriteableBitmap(width, height, 96, 96, PixelFormats.Gray8, BitmapPalettes.Gray256);
            }
            else if (VideoImageControlToUpdateSource.PixelHeight != height ||
                     VideoImageControlToUpdateSource.PixelWidth != width)
            {
                VideoImageControlToUpdateSource =
                    new WriteableBitmap(width, height, 96, 96, PixelFormats.Gray8, BitmapPalettes.Gray256);
            }

            VideoImageControlToUpdateSource.Lock();

            VideoImageControlToUpdateSource.WritePixels(
                new Int32Rect(0, 0, width, height),
                frame,
                size,
                width);

            VideoImageControlToUpdateSource.AddDirtyRect(new System.Windows.Int32Rect(0, 0, width, height));
            VideoImageControlToUpdateSource.Unlock();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    });
}

The above example VideoImageControlToUpdateis a WPF image control.

For more speed, I find the VideoRendererElement found on codeplex is faster.

+1
source share
1 answer

Best way: WriteableBitmap.WritePixels (..., source IntPtr, ...)

The fastest way: Use WIC and all operations in IntPtr unmanaged memory. But why bother using WPF in this case? Consider using DirectX overlay if this performance is required.

0
source

All Articles