- Start Visual Studio .NET.
- Choose File->New->Project... from the menu.
- In the New Project dialog box, choose either "Visual C# Projects" or "Visual Basic Projects" in the Projects Type List, and choose "Windows Application " in the Templates List.
- Type the project name as "Multimedia Frame Extractor" in the Project Name field, and then choose OK. If desired, type a new location for your project or select a directory using the Browse button, and then choose OK.
- In the "Solution Explorer" window, right-click on the "References" folder, and select "Add Reference..." from the context menu. In the "Add Reference" dialog box, select the ".NET" tab and select Leadtools.Multimedia and click OK. If this dll does not appear under the .NET tab, you will need select the Browse tab and add it from the "<LEADTOOLS_INSTALLDIR>\Bin\DotNet\Win32 " folder, by selecting the following DLL:
- Leadtools.Multimedia.dll
- Next, we need to add the using/import directive for this DLL to our Form's source file. Switch Form1 to code view (right-click Form1 in the solution explorer then select View Code) and add the following lines at the beginning of the file:
[Visual Basic]
Imports Leadtools.Multimedia
[C#]using Leadtools.Multimedia;
- While still in code view, declare the following private variables for use later:
[Visual Basic]
Private _sourceFile As String Private _targetPath As String
[C#]private string _sourceFile; private string _targetPath;
- Next, we need to add an instance of the ConvertCtrl to the form. Make sure Form1 is in design view. Go to the toolbox (View->Toolbox) and drag and drop a ConvertCtrl control on the form. NOTE: If you do not have ConvertCtrl in your toolbox, select Tools->Choose Toolbox Items from the menu. Click Browse and then select Leadtools.Multimedia.dll from "<LEADTOOLS_INSTALLDIR>\Bin\DotNet\Win32" and then click Open and then click OK. After adding it to the form, set the following properties on the convert control:
Property Value Name _convertctrl Anchor Top, Bottom, Left, Right BackColor Black - Go to the toolbox (View->Toolbox) and drag and drop a ProgressBar control on the form (below the convert control) and set the following properties:
Property Value Name _progress Anchor Bottom, Left, Right Step 1 - Next, we will add a text control and browse button for the source video file selection. Go to the toolbox (View->Toolbox) and drag and drop a Text control and a Button control to the form (below the progress bar) and set the following properties:
Property Value Name _textSrcFile Anchor Bottom, Left, Right ReadOnly True BackColor ControlLightLight Name _buttonBrowseSrc Text Source... Anchor Bottom, Right - Next, we will add another text control and browse button to select the output folder for extracted frames. Go to the toolbox (View->Toolbox) and drag and drop a Text control and a Button control to the bottom of the form and set the following properties:
Property Value Name _textTargetPath Anchor Bottom, Left, Right ReadOnly True BackColor ControlLightLight Name _buttonBrowseTarget Text ... Anchor Bottom, Right - Now, we need one final button to start the conversion/frames extraction work. Go to the toolbox (View->Toolbox) and drag and drop a Button control to the bottom of the form and set the following properties:
Property Value Name _buttonConvert Text Extract Anchor Bottom, Right - While still in design view, select the properties for the form and add an event handler to the Form1 Load event. Code this event handler as follows:
[Visual Basic]
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load _sourceFile = "<LEADTOOLS_INSTALLDIR>\Media\DaDa_DVD_MPEG2.mpg" _targetPath = Path.Combine(Directory.GetCurrentDirectory(), "Frames") If (Not Directory.Exists(_targetPath)) Then Directory.CreateDirectory(_targetPath) End If _textSrcFile.Text = _sourceFile _textTargetPath.Text = _targetPath End Sub
[C#]private void Form1_Load(object sender, System.EventArgs e) { _sourceFile = @"<LEADTOOLS_INSTALLDIR>\Media\DaDa_DVD_MPEG2.mpg"; _targetPath = Path.Combine(Directory.GetCurrentDirectory(), "Frames"); if (!Directory.Exists(_targetPath)) Directory.CreateDirectory(_targetPath); _textSrcFile.Text = _sourceFile; _textTargetPath.Text = _targetPath; }
- Also, add an event handler to the _convertctrl Progress event and code it as follows:
[Visual Basic]
Private Sub _convertctrl_Progress(ByVal sender As System.Object, ByVal e As ProgressEventArgs) Handles _convertctrl.Progress _progress.Value = CInt((_progress.Maximum * e.percent / 100)) End Sub
[C#]private void _convertctrl_Progress(object sender, ProgressEventArgs e) { _progress.Value = (int)(_progress.Maximum * e.percent / 100); }
- Now, add an event handler to the _convertctrl Complete event to let us know when the conversion/extraction process is completed. Code this event handler as follows:
[Visual Basic]
Private Sub _convertctrl_Complete(ByVal sender As System.Object, ByVal e As EventArgs) Handles _convertctrl.Complete MessageBox.Show("Frame Extraction Complete") _buttonBrowseSrc.Enabled = True _buttonBrowseTarget.Enabled = True _buttonConvert.Enabled = True End Sub
[C#]private void _convertctrl_Complete(object sender, EventArgs e) { MessageBox.Show("Frame Extraction Complete"); _buttonBrowseSrc.Enabled = true; _buttonBrowseTarget.Enabled = true; _buttonConvert.Enabled = true; }
- Add an event handler to the _buttonBrowseSrc Click event to select the source video file for processing. Code this event handler as follows:
[Visual Basic]
Private Sub _buttonBrowseSrc_Click(ByVal sender As Object, ByVal e As EventArgs) Handles _buttonBrowseSrc.Click Dim ofn As OpenFileDialog = New OpenFileDialog() ofn.FileName = _sourceFile ofn.FilterIndex = 0 If _textSrcFile.Text <> String.Empty Then ofn.InitialDirectory = Path.GetDirectoryName(_textSrcFile.Text) Else ofn.InitialDirectory = Directory.GetCurrentDirectory() End If ofn.Multiselect = False ofn.Title = "Select Source Video" ofn.CheckFileExists = True ofn.Filter = "MPEG2 Video Files (*.mpg)|*.mpg|All files (*.*)|*.*" If ofn.ShowDialog() = DialogResult.OK Then _textSrcFile.Text = ofn.FileName _sourceFile = _textSrcFile.Text End If End Sub
[C#]private void _buttonBrowseSrc_Click(object sender, EventArgs e) { OpenFileDialog ofn = new OpenFileDialog(); ofn.FileName = _sourceFile; ofn.FilterIndex = 0; if (_textSrcFile.Text != string.Empty) ofn.InitialDirectory = Path.GetDirectoryName(_textSrcFile.Text); else ofn.InitialDirectory = Directory.GetCurrentDirectory(); ofn.Multiselect = false; ofn.Title = "Select Source Video"; ofn.CheckFileExists = true; ofn.Filter = "MPEG2 Video Files (*.mpg)|*.mpg|All files (*.*)|*.*"; if (ofn.ShowDialog() == DialogResult.OK) { _textSrcFile.Text = ofn.FileName; _sourceFile = _textSrcFile.Text; } }
- Next, add an event handler to the _buttonBrowseTarget Click event to handle browsing for the output path where the extracted video frames will be saved. Code this event handler as follows:
[Visual Basic]
Private Sub _buttonBrowseTarget_Click(ByVal sender As Object, ByVal e As EventArgs) Handles _buttonBrowseTarget.Click Dim fbd As FolderBrowserDialog = New FolderBrowserDialog() fbd.SelectedPath = _targetPath fbd.ShowNewFolderButton = True fbd.Description = "Frames Output Folder" fbd.RootFolder = Environment.SpecialFolder.MyComputer If fbd.ShowDialog() = DialogResult.OK Then _targetPath = fbd.SelectedPath _textTargetPath.Text = _targetPath End If End Sub
[C#]private void _buttonBrowseTarget_Click(object sender, EventArgs e) { FolderBrowserDialog fbd = new FolderBrowserDialog(); fbd.SelectedPath = _targetPath; fbd.ShowNewFolderButton = true; fbd.Description = "Frames Output Folder"; fbd.RootFolder = Environment.SpecialFolder.MyComputer; if (fbd.ShowDialog() == DialogResult.OK) { _targetPath = fbd.SelectedPath; _textTargetPath.Text = _targetPath; } }
- Finally, add an event handler to the _buttonConvert Click event to perform the conversion/extraction. Code this event handler as follows:
[Visual Basic]
Private Sub _buttonConvert_Click(ByVal sender As Object, ByVal e As EventArgs) Handles _buttonConvert.Click Try ExtractFrames() _buttonBrowseSrc.Enabled = False _buttonBrowseTarget.Enabled = False _buttonConvert.Enabled = False Catch ex As Exception MessageBox.Show(Me, ex.Message) End Try End Sub
[C#]private void _buttonConvert_Click(object sender, EventArgs e) { try { ExtractFrames(); _buttonBrowseSrc.Enabled = false; _buttonBrowseTarget.Enabled = false; _buttonConvert.Enabled = false; } catch (Exception ex) { MessageBox.Show(this, ex.Message); } }
- Now, with all the forms elements and events setup out of the way, we can write the code behind the ExtractFrames method. This is where the real work of starting the conversion, looping through all the sample frames and extracting them to bitmap files is done. Add the following methods and code as follows:
[Visual Basic]
Public Sub ExtractFrames() ' input file and output files Dim sampleFileName As String ' This example demonstrates how to use SampleTarget and MediaSample ' objects to directly access sample frames from a conversion graph. Try ' set the source and target files _convertctrl.SourceFile = _sourceFile ' set the preview _convertctrl.Preview = True ' create a new sample target Dim st As SampleTarget = New SampleTarget() ' set the target media type for the video stream Dim mtTarget As MediaType = New MediaType() mtTarget.Type = Leadtools.Multimedia.Constants.MEDIATYPE_Video mtTarget.SubType = Leadtools.Multimedia.Constants.MEDIASUBTYPE_RGB24 ' set the sample target's accepted media type st.SetAcceptedMediaType(mtTarget) ' assign the sample target to the capture control _convertctrl.TargetObject = st _convertctrl.TargetFormat = TargetFormatType.StillImage ' run the convert _convertctrl.StartConvert() Dim msFrame As MediaSample = st.GetSample(1000) Dim sampleStart, sampleStop As Long Do While Not msFrame Is Nothing ' get the sample target's connected media type Dim mtSample As MediaType = st.GetConnectedMediaType() ' get the sample times msFrame.GetTime(sampleStart, sampleStop) ' create the file name for this frame bitmap sampleFileName = String.Format("{0}\Frame_{1}-{2}.bmp", _targetPath, sampleStart, sampleStop) ' create the bitmap for this frame WriteSampleBitmap(sampleFileName, msFrame, mtSample) ' mtCopy); Try ' create a media sample using the captured sample from above msFrame = st.GetSample(1000) Catch cex As COMException ' if we have reached the end of stream we are finished If cex.ErrorCode = CInt(ErrorCode.VFW_E_SAMPLE_REJECTED_EOS) OrElse cex.ErrorCode = CInt(ErrorCode.VFW_E_WRONG_STATE) Then Exit Do ElseIf cex.ErrorCode = CInt(ErrorCode.VFW_E_TIMEOUT) Then Continue Do Else Throw cex End If End Try Loop Catch e1 As Exception ' fail! End Try End Sub Private Function WriteSampleBitmap(ByVal outFile As String, ByVal ms As MediaSample, ByVal mt As MediaType) As Bitmap ' get the video information Dim vih As VideoInfoHeader = mt.GetVideoFormatData() ' create a bitmap to hold the sample and copy it Dim bmp As Bitmap = New Bitmap(vih.bmiHeader.biWidth, vih.bmiHeader.biHeight, FormatFromBitCount(vih.bmiHeader.biBitCount)) Dim bmpData As BitmapData = bmp.LockBits(New Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat) Marshal.Copy(ms.Buffer, 0, bmpData.Scan0, GetBitmapSize(bmp, vih.bmiHeader.biBitCount)) bmp.UnlockBits(bmpData) ' flip the upside down buffer bmp.RotateFlip(RotateFlipType.Rotate180FlipX) ' save the image bmp.Save(outFile, ImageFormat.Bmp) Return bmp End Function Private Function FormatFromBitCount(ByVal bitCount As Integer) As PixelFormat Select Case bitCount Case 8 Return PixelFormat.Format8bppIndexed Case 16 Return PixelFormat.Format16bppRgb555 Case 32 Return PixelFormat.Format32bppRgb Case 48 Return PixelFormat.Format48bppRgb Case 24 Return PixelFormat.Format24bppRgb End Select Throw New Exception("Unrecognized bit count") End Function Private Function GetBitmapSize(ByVal bmp As Bitmap, ByVal bitCount As Integer) As Integer Dim pixelSize As Integer = CInt(Math.Log(CDbl(bitCount))) Return (bmp.Width * pixelSize + pixelSize And (Not 3)) * bmp.Height End Function Private Function GetBitmapScanRowSize(ByVal bmpSize As Integer, ByVal stride As Integer, ByVal width As Integer) As Integer Return CInt(bmpSize / (stride / width)) End Function
[C#]public void ExtractFrames() { // input file and output files string sampleFileName; // This example demonstrates how to use SampleTarget and MediaSample // objects to directly access sample frames from a conversion graph. try { // set the source and target files _convertctrl.SourceFile = _sourceFile; // set the preview _convertctrl.Preview = true; // create a new sample target SampleTarget st = new SampleTarget(); // set the target media type for the video stream MediaType mtTarget = new MediaType(); mtTarget.Type = Constants.MEDIATYPE_Video; mtTarget.SubType = Constants.MEDIASUBTYPE_RGB24; // set the sample target's accepted media type st.SetAcceptedMediaType(mtTarget); // assign the sample target to the capture control _convertctrl.TargetObject = st; _convertctrl.TargetFormat = TargetFormatType.StillImage; // run the convert _convertctrl.StartConvert(); MediaSample msFrame = st.GetSample(1000); long sampleStart, sampleStop; while (msFrame != null) { // get the sample target's connected media type MediaType mtSample = st.GetConnectedMediaType(); // get the sample times msFrame.GetTime(out sampleStart, out sampleStop); // create the file name for this frame bitmap sampleFileName = string.Format("{0}\\Frame_{1}-{2}.bmp", _targetPath, sampleStart, sampleStop); // create the bitmap for this frame WriteSampleBitmap(sampleFileName, msFrame, mtSample); // mtCopy); try { // create a media sample using the captured sample from above msFrame = st.GetSample(1000); } catch (COMException cex) { // if we have reached the end of stream we are finished if (cex.ErrorCode == (int)ErrorCode.VFW_E_SAMPLE_REJECTED_EOS || cex.ErrorCode == (int)ErrorCode.VFW_E_WRONG_STATE) break; else if (cex.ErrorCode == (int)ErrorCode.VFW_E_TIMEOUT) continue; else throw cex; } } } catch (Exception) { // fail! } } private Bitmap WriteSampleBitmap(string outFile, MediaSample ms, MediaType mt) { // get the video information VideoInfoHeader vih = mt.GetVideoFormatData(); // create a bitmap to hold the sample and copy it Bitmap bmp = new Bitmap(vih.bmiHeader.biWidth, vih.bmiHeader.biHeight, FormatFromBitCount(vih.bmiHeader.biBitCount)); BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat); Marshal.Copy(ms.Buffer, 0, bmpData.Scan0, GetBitmapSize(bmp, vih.bmiHeader.biBitCount)); bmp.UnlockBits(bmpData); // flip the upside down buffer bmp.RotateFlip(RotateFlipType.Rotate180FlipX); // save the image bmp.Save(outFile, ImageFormat.Bmp); return bmp; } private PixelFormat FormatFromBitCount(int bitCount) { switch (bitCount) { case 8: return PixelFormat.Format8bppIndexed; case 16: return PixelFormat.Format16bppRgb555; case 32: return PixelFormat.Format32bppRgb; case 48: return PixelFormat.Format48bppRgb; case 24: return PixelFormat.Format24bppRgb; } throw new Exception("Unrecognized bit count"); } private int GetBitmapSize(Bitmap bmp, int bitCount) { int pixelSize = (int)Math.Log((double)bitCount); return (bmp.Width * pixelSize + pixelSize & ~3) * bmp.Height; } private int GetBitmapScanRowSize(int bmpSize, int stride, int width) { return bmpSize / (stride / width); }
- Now you are ready to Build, and Run the program to test it. Use the Source... button to browse for the source video file and then select the target output folder for frames by using the [...] browse button. Next click the Extract button to perform the conversion/extraction and then open the output folder to view the extracted bitmap files.