Generating video frame captures in WPF
I was using windows media center the other night on my new media center pc (ok, its an old pc, but a new install of media center), and I really liked how it goes about creating thumbnail snapshots of the videos. Vista also does this, and I thought that I'd like to try and do something similar in WPF to generate snapshots of videos stored in my p2pDlib project. After reading a few texts and also after a little googling, this had a fairly simple solution after mucking around with some not-quite-right
information that I found.
To do this, create a WPF application, and then use the media player object combined with RenderTargetBitmap, DrawingVisual and CrawingContext objects. The application I build had an image control on the main canvas, and in the Window_Loaded event would execute the following code:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
MediaPlayer player = new MediaPlayer();
player.MediaOpened += new EventHandler(player_MediaOpened);
player.Open(new Uri(@"D:\My Videos\Trailer Park Boys - S06E04 - Where In The Fuck Is Oscar Goldman.avi"));
player.Position = TimeSpan.FromSeconds(15);
player.Play();
}This code instantiates a new media player object, assigns an event handler for when the media is opened, opens a video file, positions the video 15 seconds in, and then starts play of the video.
The trick that I found to this was in having to handle the loaded event and that you apparently need to call the play method. Otherwise, you'll just get a black screen capture.
The event handler then contains the following code;
void player_MediaOpened(object sender, EventArgs e)
{
MediaPlayer player = sender as MediaPlayer;
player.Pause();
RenderTargetBitmap rtb = new RenderTargetBitmap((int)image1.Width, (int)image1.Height, 1 / 200, 1 / 200, PixelFormats.Pbgra32);
DrawingVisual dv = new DrawingVisual();
DrawingContext dc = dv.RenderOpen();
dc.DrawVideo(player, new Rect(0, 0, image1.Width, image1.Height));
dc.Close();
rtb.Render(dv);
image1.Source = BitmapFrame.Create(rtb);
}
This method retrieves the media player and then pauses the video. I'm assuming that since this method is called once the video is loaded and play begins, that we are at the specified frame. Again, I found that this is the only way to get the video to the appropriate frame.
RenderTargetBitmap is then used to make a snapshot of the media player control (it can be used to do this for any WPF control). The object is setup to be the same size as the image on the form, but you obviously make this any size that you desire.
The next trick is in creating a DrawingVisual object, which is used to get a DrawingContext object which is used to actually render the bitmap by calling it's DrawVideo method. The DrawingContext object is then closed, and the Render method called passing in the DrawingVisual object which renders the content of the media play frame to the RenderTargetBitmap. The last thing to do is then to create a BitmapFrame object from the RenderTargetBitmap object and assign that to the image on the form.
As an example of this, here is a snapshot of the window: