Take Snapshots of Videos with WPF
With WPF’s Imaging-Classes you can take snapshots of any Visual. The snapshot can be saved in any common Image-Format, like e.g. JPG. Let’s take a look at a pretty short example, that shows how easy this can be done. The example takes snapshots of a Video.
The following Window contains a MediaElement and a Button. The MediaElement plays the Video thomasOnBoard.wmv. The Button defines an Eventhandler for the Click-Event. It takes a snapshot of the video, when you click it.
<Window x:Class="SnapShots.Window1"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/...
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300"
ResizeMode="NoResize">
<StackPanel>
<MediaElement x:Name="media" Height="200" Stretch="Fill">
<MediaElement.Triggers>
<EventTrigger RoutedEvent="MediaElement.Loaded">
<BeginStoryboard>
<Storyboard>
<MediaTimeline
Source="thomasOnBoard.wmv"
RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</MediaElement.Triggers>
</MediaElement>
<Button Click="Button_Click" Content="Snapshot"/>
</StackPanel>
</Window>
Let’s look at the Eventhandler of the Button. An instance of the RenderTargetBitmap-class is created with some parameters about image-size, dots per inch (dpi) and Pixelformat. The Render-Method gets the MediaElement as a parameter, so MediaElements visual appearance is stored in the RenderTargetBitmap in memory. With a JpegBitmapEncoder and a FileStream the Image is written as a JPG to disk. That’s it.
void Button_Click(object sender, RoutedEventArgs e)
{
Size dpi = new Size(96,96);
RenderTargetBitmap bmp =
new RenderTargetBitmap(300, 200,
dpi.Width, dpi.Height, PixelFormats.Pbgra32);
bmp.Render(media);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bmp));
string filename = Guid.NewGuid().ToString()+".jpg";
FileStream fs = new FileStream(filename,FileMode.Create);
encoder.Save(fs);
fs.Close();
Process.Start(filename);
}
Instead of taking the picture in the Button_Click eventhandler, you could create a Timer and take an Image every 0.1s. That allows you to extract an image-sequence of your videos. As it works for any Visual, and everything that’s on the screen in a WPF-Application is a visual, there are many things you can do with it. You could create a snapshot of an Image drawn to an inkCanvas, upload it to a webserver to display it on a webpage etc.
Comments (17)
Thomas,
Nice, very nice!
Cheers,
Karl
Hi Karl,
thanks. :-)
Thomas
Hi in silverlight Process.Start(filename)
Can u please spacify in which library it is?
Hi,
Its really nice n smart work,else I did it using Directshow by writting long long code.
By inspiring your work,
Do you have any idea about how we can get all frames of given video files using your approch ?
I am looking for some replacement of ISamplegrabber of Directshow, in which I can get all frames one by one from file and I do have event after each frame arrive so I can put my processing logic in between.
Can we do similer in WPF ?
Any kind of hint, link..will be gr8 help for me.
thnx.
Hello,
Thanks for this post, it’s really great and useful.
I have a question, can I do this streaming (extracting these snapshots) while I’m recording the video ? I mean I need it at run time .. recording a video and every frame recorded is converted to still image to process on it without the need to wait till the end of the rec ordering ?
Thanks in advance.
nice but pls tell me how to decompress an image in wpf(.bmp) or(.jpg)
Hi Sridhar,
please look at the BitmapDecoder-class.
Thomas
nicely explained. But is it possible to make the snapshot’s width and height similar to it’s natural video width and height (which we get from mediaelement)?
Great example, but I need to get an image from a video when the video is NOT playing. Is that possible and can you show me how to do that?
Hi URW,
I haven’t tested that case to get an image without showing the video. I think somehow it should be possible, but currently I don’t have the (spare)time to look for a solution for that case.
Thanks for your reply Thomas. I found a way to do it, using ffmpeg but I am stilling hoping to find a way to get that picture within wpf, so we don;t have to install another executable and don’t run into licensing issues. If I find a way, would you like me to let you know?
Loooking at your name, I believe you understand the following
Schoenes Wochenende
Tschuess
Ute
Hi Thomas,
Thanks for the example. I have a question: is it possible to take a snapshot of the video with the size being the video’s resolution? For example, if the video’s resolution is 1920×1080, I want to take the video snapshot at 1920×1080 resolution, NOT at the size of the mediaelement.
I have tried passing 1920 and 1080 to “RenderTargetBitmap”, but it still gives me 300×200 snapshot with the rest area being white
Thanks
Hi Terence,
yes, that should be possible. Did you get it working now?
Cheers,
Thomas
thanks :)
You’re welcome Ali.
Hi, i just bumped on this good solution but my problem is, the screenshot is not according to the original video size (width and height).
Is there any way to fix this? Ive been fiddling around with some settings but still cant get it work.
Thank you.
Hi Zahk, yes, the screenshot is in the size of the mediaplayer/mediaelement. I think if you want to get the raw size of the video, you have to take another approach and extract the frame directly from that file. Here are some ideas: https://stackoverflow.com/questions/35380868/extract-frames-from-video-c-sharp/35382071