How do i selecte/choose wich frame/image to save to hard disk ?

EDN Admin

Well-known member
Joined
Aug 7, 2010
Messages
12,794
Location
In the Machine
Im using this class wich i didnt create just using it to extract images from a video file to the hard disk.
In this case it will save all the frames from the video to the hard disk. For example in this case it will be 2255 files/images on the hard disk. Each image is like a frame.

<pre class="prettyprint using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using DirectShowLib;
using System.Collections.Generic;
using Extracting_Frames;
using System.Windows.Forms;

namespace Polkan.DataSource
{
internal class WmvAdapter : ISampleGrabberCB, IDisposable
{
#region Fields_Properties_and_Events
bool dis = false;
int count = 0;
const string fileName = @"d:histogramValues.dat";
private IFilterGraph2 _filterGraph;
private IMediaControl _mediaCtrl;
private IMediaEvent _mediaEvent;
private int _width;
private int _height;
private readonly string _outFolder;
private int _frameId;
//better use a custom EventHandler that passes the results of the action to the subscriber.
public delegate void EventHandler(object sender, EventArgs e);
public event EventHandler StatusChanged;

public delegate void FrameCountEventHandler(object sender, FrameCountEventArgs e);
public event FrameCountEventHandler FrameCountAvailable;

public delegate void ProgressEventHandler(object sender, ProgressEventArgs e);
public event ProgressEventHandler ProgressChanged;

private IMediaSeeking _mSeek;
private long _duration = 0;
private long _avgFrameTime = 0;

//just save the averages to a List (not to fs)
public List<double> AveragesList { get; set; }

public List<long> histogramValuesList;

public bool Secondpass { get; set; }

public List<int> FramesToSave { get; set; }
StreamWriter w;

#endregion

#region Constructors and Destructors

public WmvAdapter(string file, string outFolder)
{
_outFolder = outFolder;
try
{
SetupGraph(file);
}
catch
{
Dispose();
MessageBox.Show("A codec is required to load this video file. Please use http://www.headbands.com/gspot/ or search the web for the correct codec");
}
}

~WmvAdapter()
{
CloseInterfaces();
}

#endregion

public void Dispose()
{
CloseInterfaces();
}

public void Start()
{
if (this.Secondpass)
{
w = new StreamWriter(@"d:NumbersTest.txt");
}
EstimateFrameCount();
int hr = _mediaCtrl.Run();
WaitUntilDone();
DsError.ThrowExceptionForHR(hr);

}

public void WaitUntilDone()
{
int hr;
const int eAbort = unchecked((int)0x80004004);

do
{

System.Windows.Forms.Application.DoEvents();
EventCode evCode;
if (dis == true)
{
return;
}

hr = _mediaEvent.WaitForCompletion(100, out evCode);

}while (hr == eAbort);

DsError.ThrowExceptionForHR(hr);
OnStatusChanged();
}

//Edit: added events
protected virtual void OnStatusChanged()
{
if (StatusChanged != null)
StatusChanged(this, new EventArgs());
}

protected virtual void OnFrameCountAvailable(long frameCount)
{
if (FrameCountAvailable != null)
FrameCountAvailable(this, new FrameCountEventArgs() { FrameCount = frameCount });
}

protected virtual void OnProgressChanged(int frameID)
{
if (ProgressChanged != null)
ProgressChanged(this, new ProgressEventArgs() { FrameID = frameID });
}

/// <summary> build the capture graph for grabber. </summary>
private void SetupGraph(string file)
{
ISampleGrabber sampGrabber = null;
IBaseFilter capFilter = null;
IBaseFilter nullrenderer = null;

_filterGraph = (IFilterGraph2)new FilterGraph();
_mediaCtrl = (IMediaControl)_filterGraph;
_mediaEvent = (IMediaEvent)_filterGraph;

_mSeek = (IMediaSeeking)_filterGraph;

var mediaFilt = (IMediaFilter)_filterGraph;

try
{
// Add the video source
int hr = _filterGraph.AddSourceFilter(file, "Ds.NET FileFilter", out capFilter);
DsError.ThrowExceptionForHR(hr);

// Get the SampleGrabber interface
sampGrabber = new SampleGrabber() as ISampleGrabber;
var baseGrabFlt = sampGrabber as IBaseFilter;

ConfigureSampleGrabber(sampGrabber);

// Add the frame grabber to the graph
hr = _filterGraph.AddFilter(baseGrabFlt, "Ds.NET Grabber");
DsError.ThrowExceptionForHR(hr);

// ---------------------------------
// Connect the file filter to the sample grabber

// Hopefully this will be the video pin, we could check by reading its mediatype
IPin iPinOut = DsFindPin.ByDirection(capFilter, PinDirection.Output, 0);

// Get the input pin from the sample grabber
IPin iPinIn = DsFindPin.ByDirection(baseGrabFlt, PinDirection.Input, 0);

hr = _filterGraph.Connect(iPinOut, iPinIn);
DsError.ThrowExceptionForHR(hr);

// Add the null renderer to the graph
nullrenderer = new NullRenderer() as IBaseFilter;
hr = _filterGraph.AddFilter(nullrenderer, "Null renderer");
DsError.ThrowExceptionForHR(hr);

// ---------------------------------
// Connect the sample grabber to the null renderer

iPinOut = DsFindPin.ByDirection(baseGrabFlt, PinDirection.Output, 0);
iPinIn = DsFindPin.ByDirection(nullrenderer, PinDirection.Input, 0);

hr = _filterGraph.Connect(iPinOut, iPinIn);
DsError.ThrowExceptionForHR(hr);

// Turn off the clock. This causes the frames to be sent
// thru the graph as fast as possible
hr = mediaFilt.SetSyncSource(null);
DsError.ThrowExceptionForHR(hr);

// Read and cache the image sizes
SaveSizeInfo(sampGrabber);

//Edit: get the duration
hr = _mSeek.GetDuration(out _duration);
DsError.ThrowExceptionForHR(hr);
}
finally
{
if (capFilter != null)
{
Marshal.ReleaseComObject(capFilter);
}
if (sampGrabber != null)
{
Marshal.ReleaseComObject(sampGrabber);
}
if (nullrenderer != null)
{
Marshal.ReleaseComObject(nullrenderer);
}
GC.Collect();
}
}

private void EstimateFrameCount()
{
try
{
//1sec / averageFrameTime
double fr = 10000000.0 / _avgFrameTime;
double frameCount = fr * (_duration / 10000000.0);
OnFrameCountAvailable((long)frameCount);

}
catch
{

}
}

public double framesCounts()
{
double fr = 10000000.0 / _avgFrameTime;
double frameCount = fr * (_duration / 10000000.0);
return frameCount;
}

private void SaveSizeInfo(ISampleGrabber sampGrabber)
{
// Get the media type from the SampleGrabber
var media = new AMMediaType();
int hr = sampGrabber.GetConnectedMediaType(media);
DsError.ThrowExceptionForHR(hr);

if ((media.formatType != FormatType.VideoInfo) || (media.formatPtr == IntPtr.Zero))
{
throw new NotSupportedException("Unknown Grabber Media Format");
}

// Grab the size info
var videoInfoHeader = (VideoInfoHeader)Marshal.PtrToStructure(media.formatPtr, typeof(VideoInfoHeader));
_width = videoInfoHeader.BmiHeader.Width;
_height = videoInfoHeader.BmiHeader.Height;
//Edit: get framerate
_avgFrameTime = videoInfoHeader.AvgTimePerFrame;

DsUtils.FreeAMMediaType(media);
GC.Collect();
}

private void ConfigureSampleGrabber(ISampleGrabber sampGrabber)
{
var media = new AMMediaType
{
majorType = MediaType.Video,
subType = MediaSubType.RGB24,
formatType = FormatType.VideoInfo
};
int hr = sampGrabber.SetMediaType(media);
DsError.ThrowExceptionForHR(hr);

DsUtils.FreeAMMediaType(media);
GC.Collect();
hr = sampGrabber.SetCallback(this, 1);
DsError.ThrowExceptionForHR(hr);
}

private void CloseInterfaces()
{
try
{
if (_mediaCtrl != null)
{
_mediaCtrl.Stop();
_mediaCtrl = null;
dis = true;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}

if (_filterGraph != null)
{
Marshal.ReleaseComObject(_filterGraph);
_filterGraph = null;
}
GC.Collect();
}
int ISampleGrabberCB.SampleCB(double sampleTime, IMediaSample pSample)
{
Marshal.ReleaseComObject(pSample);
return 0;
}

int ISampleGrabberCB.BufferCB(double sampleTime, IntPtr pBuffer, int bufferLen)
{

if (Form1.ExtractAutomatic == true)
{
using (var bitmap = new Bitmap(_width, _height, _width * 3, PixelFormat.Format24bppRgb, pBuffer))
{
if (this.Secondpass)
{

}
else
{
//this is the changed part
using (Bitmap original_bmp = new Bitmap(_width, _height, _width * 3, PixelFormat.Format24bppRgb, pBuffer))
{
if (_frameId > 0)
{

long[] HistogramsValues = Form1.GetHistogram(original_bmp);
if (histogramValuesList == null)
histogramValuesList = new List<long>(256);
histogramValuesList.AddRange(HistogramsValues);
using (BinaryWriter binWriter =
new BinaryWriter(File.Open(fileName, FileMode.Create)))
{
for (int i = 0; i < histogramValuesList.Count; i++)
{

binWriter.Write(histogramValuesList[(int)i]);


}
binWriter.Close();
}

}


using (Bitmap resized_bmp = ResizeBitmap(bitmap, 100, 100))
{

resized_bmp.RotateFlip(RotateFlipType.Rotate180FlipX);
resized_bmp.Save(Path.Combine(_outFolder, _frameId.ToString("D6") + ".bmp"), ImageFormat.Bmp);



}

}
}


_frameId++;

//let only report each 100 frames for performance
if (_frameId % 100 == 0)
OnProgressChanged(_frameId);
}
}
public static Bitmap ResizeBitmap(Bitmap b, int nWidth, int nHeight)
{
Bitmap result = new Bitmap(nWidth, nHeight);
using (Graphics g = Graphics.FromImage((Image)result))
g.DrawImage(b, 0, 0, nWidth, nHeight);
return result;
}
public class FrameCountEventArgs
{
public long FrameCount { get; set; }
}

public class ProgressEventArgs
{
public int FrameID { get; set; }
}
}[/code]
So now when it will save the bitmap/s to the hard disk it will save all of them.
But lets say i want in Form1 to save only part of the frames for example i want to save only frame number 1345 so on my hard disk there will be only one file name: 001345.bmp wich will show as an image the frame number 1345.
Or maybe i want to save only ten frames somewhere from the video so it will scan/loop over all the frames but will Save to the hard disk only specific frames.

This is how im using it in Form1 i have a button click:

<pre class="prettyprint private void button8_Click(object sender, EventArgs e)
{
HistogramGraphs1 = new Lightnings_Extractor.Histogram_Graphs();
viewToolStripMenuItem.Enabled = false;
fileToolStripMenuItem.Enabled = false;
button2.Enabled = false;
label14.Visible = false;
label15.Visible = false;
label21.Visible = false;
label22.Visible = false;
label24.Visible = false;
label25.Visible = false;

ExtractAutomatic = true;
automaticDone = true;
manualDone = false;
DirectoryInfo info = new DirectoryInfo(_videoFile);
string dirName = info.Name;
automaticModeDirectory = dirName + "_Automatic";
subDirectoryName = _outputDir + "\" + automaticModeDirectory;
if (secondPass == true)
{
Start(true);
}
Start(false);
}[/code]
Then the Start fucntion:

<pre class="prettyprint private void Start(bool secondpass)
{
setpicture(-1);
if (Directory.Exists(_outputDir) && secondpass == false)
{
}
else
{
Directory.CreateDirectory(_outputDir);
}
if (ExtractAutomatic == true)
{
string subDirectory_Automatic_Name = _outputDir + "\" + automaticModeDirectory;
Directory.CreateDirectory(subDirectory_Automatic_Name);
f = new WmvAdapter(_videoFile,
Path.Combine(subDirectory_Automatic_Name));
}
else
{
string subDirectory_Manual_Name;
if (Directory.Exists(subDirectoryName))
{
subDirectory_Manual_Name = subDirectoryName;
f = new WmvAdapter(_videoFile,
Path.Combine(subDirectory_Manual_Name));
}
else
{
subDirectory_Manual_Name = _outputDir + "\" + averagesListTextFileDirectory + "_Manual";
Directory.CreateDirectory(subDirectory_Manual_Name);
f = new WmvAdapter(_videoFile,
Path.Combine(subDirectory_Manual_Name));
}
// f = new WmvAdapter(_videoFile,
//Path.Combine(subDirectoryName));
}

button1.Enabled = false;
f.Secondpass = secondpass;
f.FramesToSave = _fts;
f.FrameCountAvailable += new WmvAdapter.FrameCountEventHandler(f_FrameCountAvailable);
f.StatusChanged += new WmvAdapter.EventHandler(f_StatusChanged);
f.ProgressChanged += new WmvAdapter.ProgressEventHandler(f_ProgressChanged);

this.Text = "Processing Please Wait...";
label5.ForeColor = Color.Green;
label5.Text = "Processing Please Wait";
button8.Enabled = false;
button5.Enabled = false;
label5.Visible = true;
pictureBox1.Image = Lightnings_Extractor.Properties.Resources.Weather_Michmoret;
Hrs = 0; //number of hours
Min = 0; //number of Minutes
Sec = 0; //number of Sec
timeElapsed = 0;
label10.Text = "00:00:00";
label11.Visible = false;
label12.Visible = false;
label9.Visible = false;
label8.Visible = false;
this.button1.Enabled = false;
myTrackPanelss1.trackBar1.Enabled = false;
this.checkBox2.Enabled = false;
this.checkBox1.Enabled = false;
numericUpDown1.Enabled = false;
timer1.Start();
//this.Enabled = false;
label2.Text = "";
label1.Visible = true;
label2.Visible = true;
label3.Visible = true;
label4.Visible = true;
f.Start();
}

private void setpicture(int indx)
{
if (_fi == null)
{
pictureBox1.Image = Lightnings_Extractor.Properties.Resources.Weather_Michmoret;
button5.Enabled = false;
label5.Visible = true;
}
else
{
if (indx >= 0 && indx <= myTrackPanelss1.trackBar1.Maximum && _fi.Length > indx)
{
try
{
label19.ForeColor = Color.Red;
fileToolStripMenuItem.Enabled = true;
label19.Visible = false;
label20.Visible = false;
label14.Visible = true;
label15.Visible = true;
label8.Visible = true;
label9.Visible = true;
// try use a bool flag
myTrackPanelss1.trackBar1.Enabled = true;
using (FileStream fs = new FileStream(_fi[indx].FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
this.label8.Visible = true;
this.label9.Visible = true;
this.label9.Text = _fi[indx].Name;
Image img = null;
Bitmap bmp = null;
Image imgOLd = null;

try
{
// label5.Visible = false; // to make that the label5 "process done" in green will wait like 5 seconds and then will disapear ! using a timer !

img = Image.FromStream(fs);
bmp = new Bitmap(img);

imgOLd = this.pictureBox1.Image;
this.pictureBox1.Image = bmp;
if (imgOLd != null)
imgOLd.Dispose();

img.Dispose();
img = null;
}
catch
{
if (img != null)
img.Dispose();
if (bmp != null)
bmp.Dispose();
if (imgOLd != null)
imgOLd.Dispose();
}
}
}
catch
{
button1.Enabled = false;
label1.Visible = false;
label2.Visible = false;
label3.Visible = false;
label4.Visible = false;
label11.Visible = false;
label12.Visible = false;
checkBox2.Enabled = false;
label19.Visible = true;
label19.ForeColor = Color.Green;
label19.Text = "The Selected Directory Is Access Denied";
label20.Visible = true;
label20.ForeColor = Color.Green;
label20.Text = "Please Set A Different Directory";
fileToolStripMenuItem.Enabled = false;
label14.Visible = false;
label15.Visible = false;
label8.Visible = false;
label9.Visible = false;
myTrackPanelss1.trackBar1.Enabled = false;
timer2.Stop();
return;
}
}
else
{
Image imgOLd = this.pictureBox1.Image;
//this.pictureBox1.Image = null;

if (imgOLd != null)
{
imgOLd.Dispose();
imgOLd = null;
}

Application.DoEvents();
}
}
}[/code]
And the <span style="font-size:small <span style="font-size:small f_StatusChanged event in Form1 too:

<pre class="prettyprint void f_StatusChanged(object sender, EventArgs e)
{
if (InvokeRequired)
{
this.Invoke(new del2(f_StatusChanged), new object[] { null, e });
return;
}
else
{
WmvAdapter f = (WmvAdapter)sender;
averages = f.AveragesList;
bool secondPass = f.Secondpass;
if (automaticDone == true || manualDone == true)
{

//free the resources
f.Dispose();

this.progressBar1.Value = this.progressBar1.Maximum;

if (!secondPass)
{
//do the second pass processing
if (manualDone == true)
{
averages = f.AveragesList;
//DoCheckResults(_outputDir, averages);
w = new StreamWriter(_outputDir + "\" + averagesListTextFileDirectory + "\" + averagesListTextFile + ".txt", false, Encoding.ASCII);
w.WriteLine("DANNY VIDEO META DATArnFORMAT VERSION:1.00rnSOURCE: " + "<" + averagesListTextFile + " + "rnDATA: ");

for (int i = 0; i < averages.Count; i++)
{
w.WriteLine(averages);
}
w.WriteLine("DATA");
w.Close();
this.progressBar1.Value = 0;
Start(true);
}
if (automaticDone == true)
{

//averages = f.AveragesList;
//DoCheckResults(_outputDir, averagesTest);
if (averagesListTextFileDirectory.Contains("_Automatic"))
{
w = new StreamWriter(_outputDir + "\" + averagesListTextFileDirectory + "\" + averagesListTextFile + ".txt", false, Encoding.ASCII);
}
else
{
w = new StreamWriter(_outputDir + "\" + averagesListTextFileDirectory + "_Automatic" + "\" + averagesListTextFile + ".txt", false, Encoding.ASCII);
}
w.WriteLine("DANNY VIDEO META DATArnFORMAT VERSION:1.00rnSOURCE: " + "<" + averagesListTextFile + " + "rnDATA: ");

for (int i = 0; i < averagesOriginal.Count; i++) // to make this variable as averagesOriginal and change fix the rest errors to averages1000
{
w.WriteLine(averagesOriginal);
}
w.WriteLine("DATA");
w.Close();

WriteHistograms();

this.progressBar1.Value = 0;
Start(true);
}
}
else
{
viewToolStripMenuItem.Enabled = true;
fileToolStripMenuItem.Enabled = true;
button2.Enabled = true;
label14.Visible = true;
label15.Visible = true;
label21.Visible = true;
button8.Enabled = true;
this.Text = "Process Done";
label5.ForeColor = Color.Green;
label5.Text = "Process Done";
label5.Visible = true;
manualDone = true;
timer4.Start();
numericUpDown1.Enabled = false;
this.checkBox1.Checked = false;
this.button1.Enabled = false;
myTrackPanelss1.trackBar1.Enabled = true;
myTrackPanelss1.trackBar1.Select();
//this.checkBox2.Enabled = true;
this.checkBox1.Enabled = true;
//this.Enabled = true;
timer1.Stop();
this.progressBar1.Value = 0;
this.progressBar1.Enabled = false;

this.label2.Visible = false;
this.label4.Visible = false;
if (Directory.Exists(subDirectoryName))
{
trackbarCounter = 0;
_fi = new DirectoryInfo(subDirectoryName).GetFiles("*.bmp");
fiAutomatic = _fi;
list_of_histograms = Histograms;
//tt = list_of_histograms[0];
histogramGraphsToolStripMenuItem.Enabled = true;
if (_fi.Length > 0)
{
myTrackPanelss1.trackBar1.Maximum = _fi.Length - 1;
label22.Visible = true;
label22.Text = _fi[myTrackPanelss1.trackBar1.Value].Name; // To check out of index bound since _fi length is 0.
if (myTrackPanelss1.trackBar1.Maximum > 0)
{
setpicture(0);
//myTrackPanelss1.trackBar1.Scroll += new EventHandler(trackBar1_Scroll);
}
}
}
label11.Visible = true;
//label12.Text = f.FramesToSave.Count().ToString(); //f.FramesToSave.Count.ToString();
label12.Visible = true;
_fi = new DirectoryInfo(subDirectoryName).GetFiles("*.bmp");
if (_fi.Length > 0)
{
label15.Text = _fi.Length.ToString();
}
}
}
if (ExtractAutomatic == false || manualDone == false)
{
this.progressBar1.Value = this.progressBar1.Maximum;

if (!secondPass)
{
Start(true);
}
else
{
viewToolStripMenuItem.Enabled = true;
fileToolStripMenuItem.Enabled = true; // Also to change the modes viewing in all paramters when its "Done" if i started the automatic mode
// when it was on manual viewing so when its "Done" it should be on automatic viewing and if i started manual mode and it was on viewing automatic mode
// so to switch to manual mode when its "Done".
button2.Enabled = true;
label14.Visible = true;
label15.Visible = true;
label21.Visible = true;
label22.Visible = true;
DirectoryInfo info = new DirectoryInfo(_videoFile);
string dirName = info.Name;
automaticModeDirectory = dirName + "_Automatic";
AutomaticsubDirectoryName = _outputDir + "\" + automaticModeDirectory;
fiAutomatic = new DirectoryInfo(AutomaticsubDirectoryName).GetFiles("*.bmp");
//label22.Text = fiAutomatic[myTrackPanelss1.trackBar1.Value].Name; to check it now !!!
button8.Enabled = true;
button5.Enabled = true;
this.Text = "Process Done";
label5.ForeColor = Color.Green;
label5.Text = "Process Done";
label5.Visible = true;
automaticDone = true;
timer4.Start();
numericUpDown1.Enabled = false;
this.checkBox1.Checked = false;
this.button1.Enabled = false;
myTrackPanelss1.trackBar1.Enabled = true;
myTrackPanelss1.trackBar1.Select();
//this.checkBox2.Enabled = true;
this.checkBox1.Enabled = true;
//this.Enabled = true;
timer1.Stop();
this.progressBar1.Value = 0;
this.progressBar1.Enabled = false;

this.label2.Visible = false;
this.label4.Visible = false;
if (Directory.Exists(subDirectoryName))
{
trackbarCounter = 0; // _fi isnt right should bne here maybe _auromatic FileINfo[]
// then to check also why when clicking automatic process button it dosent show process in green.
// and to set the current trackBar.Maximum value it dosent good now !
_fi = new DirectoryInfo(subDirectoryName).GetFiles("*.bmp");
myTrackPanelss1.trackBar1.Maximum = list_of_histograms.Count() - 1;

if (myTrackPanelss1.trackBar1.Maximum > 0)
{
setpicture(0);
//myTrackPanelss1.trackBar1.Scroll += new EventHandler(trackBar1_Scroll);
}
}
label11.Visible = true;
//label12.Text = f.FramesToSave.ToString(); //f.FramesToSave.Count.ToString();
//label12.Text = f.FramesToSave.Count().ToString(); //f.FramesToSave.Count.ToString();
label12.Visible = false;
_fi = new DirectoryInfo(subDirectoryName).GetFiles("*.bmp");
label15.Text = _fi.Length.ToString();
}
}
}
}[/code]
And the ProgressChanged event in Form1:

<pre class="prettyprint void f_ProgressChanged(object sender, ProgressEventArgs e)
{
if (InvokeRequired)
{
this.Invoke(new del1(f_ProgressChanged), new object[] { null, e });
return;
}
else
{
if (e.FrameID < this.progressBar1.Maximum)
this.progressBar1.Value = e.FrameID;
this.label2.Text = e.FrameID.ToString();
}
}

void f_FrameCountAvailable(object sender, FrameCountEventArgs e)
{
if (InvokeRequired)
{
this.Invoke(new del3(f_FrameCountAvailable), new object[] { null, e });
return;
}
else
{
this.progressBar1.Maximum = (int)e.FrameCount;
this.label1.Visible = true;
this.label3.Text = e.FrameCount.ToString();
this.progressBar1.Enabled = true;
}
}[/code]
But i dont want to save all the images/frames from the video file only some specific ones.
In the new class im using i have a variable resized_bmp original_bmp and also _frmaeId but i couldnt find where and how do i tell the class wich frames/images to save.
Thanks. <hr class="sig danieli

View the full article
 
Back
Top