Click here to Skip to main content
15,879,095 members
Articles / Multimedia / DirectX
Article

Extracting still pictures from movie files, with C#

Rate me:
Please Sign up or sign in to vote.
4.81/5 (42 votes)
23 Feb 20054 min read 593.4K   23.8K   113   160
Sample application to extract still pictures from most movie file formats.

Sample Image

Introduction

Pressing the "Print Screen" key while playing a movie file in Windows Media Player will not allow you to save the current frame. The sample application will save frames to JPEG files. It can extract frames from most movie file formats including *.wm? (Windows Media Player), *.avi, *.mpeg, *.mov (QuickTime), and *.dat (DivX). Commercial and shareware applications that provide this functionality exist but the code that I will show will let you build your own application that fits your exact needs.

Background

Pressing the "Print Screen" key while playing a movie file in Windows Media Player will not allow you to save the current frame. So I started to look for a simple way to grab a frame from movie files playing in the most common media applications (e.g., Windows Media Player, QuickTime, or DivX Player). It turned out to be more complicated than I originally thought. Hence, I decided to write up a sample application and submit it to CodeProject since I have used their resources quite often; it was a way to thank the people behind this site.

Microsoft approach to this problem would be using DirectShow but there is no managed equivalent of it. By digging in the DirectX documentation, I discovered the MediaDet class that is used in some VB samples. It is not the ideal solution but it is good enough for many situations. By wrapping the qedit.dll from the DirectShow Developer Runtime (which is included in the Extras of the DirectX SDK) in a managed assembly, I could make calls to MediaDetClass::WriteBitmapBits method that saves a frame from a movie file to a bitmap file.

Using the code

As already mentioned, the workhorse of the application is the WriteBitmapBits method of the class MediaDetClass. In order to be able to access this method, you need to add a reference (from Visual Studio menu, Project/Add Reference if you are using Visual Studio, or use tlbimp from the .NET Framework tools) to the qedit.dll. In the code for this application, I have included the managed assembly (named interop.dexterlib.dll which was created using VS).

To declare an object of the MediaDetClass, you'll see code like:

C#
MediaDetClass md = new MediaDetClass();
md.Filename = "sample.mov";
md.CurrentStream = 0;
string fBitmapName = "sample" + ".bmp" ;
md.WriteBitmapBits( 0, 320, 240, fBitmapName );

After having called WriteBitmapBits, the MediaDetClass object is, as the DirectShow documentation says, in bitmap grab mode. The important thing to know about this is that you need to create a new MediaDetClass instance anytime you need to load a new movie (it is a little as if the properties of this class are "read only").

I have set the property CurrentStream to 0 and it was working with all the samples I have tried. Moreover, it seems that you can only write to a bitmap file. So in order to save disk space, I have added code to convert the bitmap file to a JPEG one. You have to remember that, even with our 100 Gig hard disks, you can chew up the gigabytes pretty quickly if you want to save a frame every 0.1 second on a 30 minutes movie.

Points of Interest

The "Save" button saves the current frame to a JPEG file in the "tmp" subdirectory. The "Scan" button loops through the whole movie and saves a frame every second (or 0.1 second).

The MediaDetClass as imported with Visual Studio is not a Windows control, its base class is System.Object, and it seems that after calling the method WriteBitmapBits, a handle to the bitmap file just created stays open. Therefore, the application, sometimes, complains that a file is already being used. I have just increased a variable counter to avoid most of these situations; an alternative solution would have been to wrap the MediaDetClass a second time in a more sophisticated implementation.

As mentioned, this is not an ideal solution. DirectShow is not going to appear in a managed version (as opposed to the rest of the DirectX API). I imagine it is for performance reasons. But as this application shows, an interop version will do the job; as they say "It Just Works!", which is fine for many situations.

I have included a file ("build.cmd" ) with the command line needed to compile the application in a shell window where the C# compiler must be found on the path.

Limitations and known issues

The application extracts a frame every second, by default. Under the Options menu, you can choose to extract a frame every one tenth of a second. This is only taken in consideration when you press the "Scan" button.

The application only saves a bitmap with the resolution 320 x 240. And they are saved in the "tmp" subdirectory (that will be created when you run the application).

The application is meant to extract pictures from movie files and is a poor application for viewing movies. The creation of new instances of the MediaDetClass type makes this restriction unavoidable.

I have created a thread to be able to keep track of the progress so far (which is displayed on a static label) when scanning a whole movie. The thread only updates the label.

The length of the movie is immediately overwritten when opening a second movie with the current position.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
You can read my blog entries at:
http://wwww.informikon.com/blog/

Comments and Discussions

 
General"COMException (0x8007007A):" Pin
adeel221-Jul-05 9:27
adeel221-Jul-05 9:27 
GeneralRe: "COMException (0x8007007A):" Pin
daniel04923-Jul-05 3:39
daniel04923-Jul-05 3:39 
GeneralRe: "COMException (0x8007007A):" Pin
adeel22-Aug-05 4:12
adeel22-Aug-05 4:12 
Generalthe license Pin
EmailSolidale27-Jun-05 5:11
EmailSolidale27-Jun-05 5:11 
GeneralRe: the license Pin
daniel04928-Jun-05 3:22
daniel04928-Jun-05 3:22 
GeneralRe: the license Pin
EmailSolidale28-Jun-05 4:00
EmailSolidale28-Jun-05 4:00 
GeneralRe: the license Pin
lgs.lsg28-Jun-05 23:23
lgs.lsg28-Jun-05 23:23 
GeneralQuestion Pin
Rene Pally11-May-05 10:12
Rene Pally11-May-05 10:12 
Hi, nice article, could you give me an example of code to capture images from video for example at the 5 second?

Excellent
GeneralRe: Question Pin
daniel04912-May-05 2:57
daniel04912-May-05 2:57 
GeneralRe: Question Pin
Rene Pally12-May-05 5:01
Rene Pally12-May-05 5:01 
GeneralCatastrophic failure Pin
xreven13-Apr-05 17:31
xreven13-Apr-05 17:31 
GeneralRe: Catastrophic failure Pin
daniel04915-Apr-05 10:23
daniel04915-Apr-05 10:23 
GeneralRe: Catastrophic failure Pin
EmailSolidale8-Sep-05 23:43
EmailSolidale8-Sep-05 23:43 
GeneralVideo dimensions Pin
lello928-Apr-05 4:35
lello928-Apr-05 4:35 
GeneralRe: Video dimensions Pin
daniel0499-Apr-05 13:44
daniel0499-Apr-05 13:44 
GeneralRe: Video dimensions Pin
10-Apr-05 11:15
suss10-Apr-05 11:15 
GeneralRe: Video dimensions Pin
lgs.lsg16-Apr-05 16:19
lgs.lsg16-Apr-05 16:19 
GeneralDexterLib Pin
Rene Pally4-Apr-05 10:12
Rene Pally4-Apr-05 10:12 
GeneralRe: DexterLib Pin
daniel0495-Apr-05 7:44
daniel0495-Apr-05 7:44 
GeneralRe: DexterLib Pin
Rene Pally5-Apr-05 12:21
Rene Pally5-Apr-05 12:21 
GeneralRe: DexterLib Pin
lgs.lsg16-Apr-05 15:05
lgs.lsg16-Apr-05 15:05 
GeneralProblem With Mov Files Pin
GNULinux3-Apr-05 20:35
GNULinux3-Apr-05 20:35 
GeneralConverting to vb.net Pin
msali30-Mar-05 19:06
msali30-Mar-05 19:06 
GeneralRe: Converting to vb.net Pin
daniel04931-Mar-05 3:36
daniel04931-Mar-05 3:36 
GeneralException HRESULT 0x80040200 Pin
leilanecris27-Mar-05 15:54
leilanecris27-Mar-05 15:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.