DCSIMG
WPF Raw Video - Essential WPF

WPF Raw Video

In my last post I showed how to access the WPF's BitmapSource underlying WIC image, and I promised to explain my code, and also to post an Image stream (Video) code based on my solution.

In this post I will quickly talk about the unique CompositionTarget class, and I will show how to render a Raw Video using its Rendered event.

Download the code from here (FYI - I refractor the code from the last post and fixed several bugs).

I will start by reminding one of the disadvantages of my WICBitmap solution: "Sometimes the Lock/Copy fail. I think that it because I'm trying to lock the buffer while it is in use by the render thread (use the TryLock method instead of Lock, and try again and again if fails. The second or third lock should succeed)"

When I first encountered this symptom, I have searched in the Image class for an OnRender method or event. One such that will be raised after the image renders the BitmapSource. Unfortunately, I didn't find one. Searching for the word Rendered in the MSDN, I have found the WPF CompositionTarget class. Surprisingly, The CompositionTarget class has a Rendered event. It is written that the Rendered event fires a moment before WPF sends the visual tree to milcore for rendering. This is a great opportunity for manipulating my video buffer.

Here is the code for the Rendered event:

        public Window1()
        {
            InitializeComponent();

            CompositionTarget.Rendering += CompositionTarget_Rendering;
        }
        void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            if (_isPlaying)
            {
                NextFrame();
            }
        }
        private void NextFrame()
        {
            // Randomize a new buffer with random pixels
            _random.NextBytes(_managedBuffer); // replace this code by copying the next video frame
            // Copy the new buffer into the unmanaged memory.
            Marshal.Copy(_managedBuffer, 0, _unmanagedBuffer, _managedBuffer.Length);
            WICBitmapLock wicBitmapLock;
            // Retrieve the low level WIC buffer of the BitmapSource.
            int errorCode;
            if (_wicBitmap.TryLock(LockFlags.ReadWrite, out wicBitmapLock, out errorCode))
            {
                // Copy the new randomized buffer into the unmanaged memory.
                // It is also possible to work directly on the WIC buffer.
                if (wicBitmapLock.Pixels.CopyFrom(_unmanagedBuffer, (uint)_managedBuffer.Length))
                {
                    // Enforce Image instance to render itself.
                    image.InvalidateVisual();
                }
                else
                {
                    Debug.WriteLine("Failed to copy buffer. Drop frame.");
                }
                // The dispose method releases the lock.
                // WHY VALUE TYPES HAVE NO CONSTRUCTORS? :-)
                wicBitmapLock.Dispose();
            }
            else
            {
                Debug.WriteLine("Failed to lock buffer. Drop frame.");
            }
        }

 

image  image image

 

As you can see, instead of manipulating the WIC image using a timer or other mechanism, I'm using the Rendered event which is the best place for placing this code. This ensures that the image is fully rendered, and provides best performance.

Running this code in my Duo Core2 laptop, using a 32bit color depth with resolution of 800x600, ends up with 37fps with randomize, and with 70fps without randomize.

It is getting too late (have to work tomorrow), so I promise to explain my solution in the next post.

Download the code from here.

Published Monday, October 01, 2007 12:46 AM by Tomer Shamam

Comments

# re: WPF Raw Video

Wednesday, December 19, 2007 9:49 AM by nick bridger

Wow, this is excellent stuff! I work with image processing and was very keen to make use of the power of WPF for fast imagae display etc, but was disapointed there was no "official" way to access the pixel data. So this goes a long way to providing what I need - thanks!

One question though, is it possible to Lock two bitmaps at the same time? For example, to use one image as the source and another as the dest of a processing function? When I try the second Lock always fails; if I swap the locks around, it alwasy the 2nd that fails.

# re: WPF Raw Video

Wednesday, December 19, 2007 10:29 AM by Tomer Shamam

Please read my other post about "WPF Official Image Interop", you will find it more usefull. I provided a better official solution for accessing pixels. Also I have used this solution for my Video example and compared these two methods (see the link to the code in the relevant post).

Leave a Comment

(required) 
(required) 
(optional)
(required) 

Enter the numbers above:
Powered by Community Server (Commercial Edition), by Telligent Systems