views:

372

answers:

2

Is there a way to capture each WPF MediaElement frame? Like an event that fires at each rendered frame and allows me to access it. If MediaElement does not provide such functionality, how could it be implemented or what other control could I use? On a side note, is there such a control or method that would allow for off-screen fast rendering of media clips with frame capture? (so I could process frames as fast as possible)

A: 

There is no built-in WPF way:

  • MediaElement does not have this ability.
  • BitmapDecoder has the API to request this but using BitmapDecoder to extract frames from arbitrary media is not implemented: It can only extract frames from a few animated bitmap formats like .gif.

I was able to get frame images from .mpg, .wmv, .mov, .flv, .avi and other movie formats using DirectShow. I constructed a filter graph using DirectShow's COM graph builder interfaces. The resulting filter graph decoded the movie and connected it to a custom renderer filter written in C#. My custom filter received the frame data and converted it into BitmapSource objects for display using BitmapSource.Create.

The DirectShow solution performed quite well, and the managed to unmanaged transition was no big deal, but it took a while to figure out the details of the DirectShow graph building.

Ray Burns
+1  A: 

Try out my WPF MediaKit project. Allows you to do pretty much anything in WPF with Media. Try out the MediaDetector.cs, it allows you to extract out frames from any time in the media. It's a little buggy as I've never put a lot of time in it, but should work for what you need.

Jeremiah Morrill
+1 It's nice, but I'm not sure how stable it would be in getting each frame. I could get a frame from a timer firing based on the number of the media's frames per second , but I'm guessing it'll still be prone to rounding errors and variations in time it takes to capture and return the frame...
luvieere
I would modify the MediaUriPlayer.cs file to add the SampleGrabber filter to the graph to receive each sample. You can see how to do this by looking at the VideoCapturePlayer.cs as it receives each sample. Code for converting the passed IntPtr to a Bitmap is in the MediaDetector.cs. So in short, I believe my project has all the code you would need, but theres some copy/paste refactoring to do :)
Jeremiah Morrill