Windows Develop Bookmark and Share   
 index > Windows Forms General > Loop capture image and generic error occured in GDI+
 

Loop capture image and generic error occured in GDI+

I've application to capture video of image and grab the still image. It runs well untill I put loop to regrab the still images many times automatically.. and the error (generic error occured GDI+) happend.
For your information, I also run different code of application that have similar function which to capture the image repeatedly that I found from internet. However, it give the same error message.
I think maybe I've to setup something in the configuration but I still blur about it. I'm using C# Express edition. Could anybody help me please...

shuhada  Wednesday, December 20, 2006 2:36 AM

Hi shuhada,

A little more information would be useful.

1) What are you using to capture the video VFW? DirectShow? something else?

2) What method are you using to capture the image from the video stream, and what format is it in?

3) Can you provide any code? Especially for your image capture loop.

Regards

GavH  Wednesday, December 20, 2006 1:27 PM

Thanks for your respond GavH,

I'm use DirectShow to capture the image. I got the original source code from here:

http://www.codeproject.com/cs/media/directshownet.asp?df=100&forumid=4377

I modified little bit to get only two functions: get the video and grab image. The image is in JPEG.

This is the code:

/// <summary> handler for toolbar button clicks. </summary>

private void toolBar_ButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e)

{

if( e.Button == toolBarBtnGrab )

do // this is the loop that i did

{

Thread.Sleep(2000);

a++;

Prepare4Grab();

textBox1.Text = a.ToString();

}

while (a < 5);

}

void Prepare4Grab()

{

int hr;

int size = videoInfoHeader.BmiHeader.ImageSize; //image info

savedArray = new byte[size + 64000]; // buffer for bitmap data

captured = false;

hr = sampGrabber.SetCallback(this, 1);

}

/// <summary> capture event, triggered by buffer callback. </summary>

void OnCaptureDone()

{

try

{

toolBarBtnGrab.Enabled = true;

int hr;

if( sampGrabber == null )

return;

hr = sampGrabber.SetCallback( null, 0 );

int w = videoInfoHeader.BmiHeader.Width;

int h = videoInfoHeader.BmiHeader.Height;

int stride = w * 3;

GCHandle handle = GCHandle.Alloc(savedArray, GCHandleType.Pinned);

int scan0 = (int)handle.AddrOfPinnedObject();

scan0 += (h - 1) * stride;

Bitmap b = new Bitmap(w, h, -stride, PixelFormat.Format24bppRgb, (IntPtr)scan0);

handle.Free();

savedArray = null;

Image old = pictureBox.Image;

pictureBox.Image = b;

//b.Dispose();

//toolBarBtnSave.Enabled = true;

pictureBox.Image.Save("1stImage.Jpeg", ImageFormat.Jpeg);

}

catch (Exception ee)

{

MessageBox.Show(this, "Could not grab picture\r\n" + ee.Message, "DirectShow.NET", MessageBoxButtons.OK, MessageBoxIcon.Stop);

}

}

bool StartupVideo( UCOMIMoniker mon )

{

int hr;

try {

if( ! CreateCaptureDevice( mon ) )

return false;

if( ! GetInterfaces() )

return false;

if( ! SetupGraph() )

return false;

if( ! SetupVideoWindow() )

return false;

#if DEBUG

DsROT.AddGraphToRot(graphBuilder, out rotCookie); // graphBuilder capGraph

#endif

hr = mediaCtrl.Run();

if( hr < 0 )

Marshal.ThrowExceptionForHR( hr );

return true;

}

catch( Exception ee )

{

MessageBox.Show( this, "Could not start video stream\r\n" + ee.Message, "DirectShow.NET", MessageBoxButtons.OK, MessageBoxIcon.Stop );

return false;

}

}

// <summary> make the video preview window to show in videoPanel. </summary>///

bool SetupVideoWindow()

{

int hr;

try {

// Set the video window to be a child of the main window

hr = videoWin.put_Owner( videoPanel.Handle );

if( hr < 0 )

Marshal.ThrowExceptionForHR( hr );

// Set video window style

hr = videoWin.put_WindowStyle( WS_CHILD | WS_CLIPCHILDREN );

if( hr < 0 )

Marshal.ThrowExceptionForHR( hr );

// Use helper function to position video window in client rect of owner window

ResizeVideoWindow();

// Make the video window visible, now that it is properly positioned

hr = videoWin.put_Visible( DsHlp.OATRUE );

if( hr < 0 )

Marshal.ThrowExceptionForHR( hr );

hr = mediaEvt.SetNotifyWindow(this.Handle, WM_GRAPHNOTIFY, IntPtr.Zero);

if (hr < 0)

Marshal.ThrowExceptionForHR(hr);

return true;

}

catch( Exception ee )

{

MessageBox.Show( this, "Could not setup video window\r\n" + ee.Message, "DirectShow.NET", MessageBoxButtons.OK, MessageBoxIcon.Stop );

return false;

}

}

/// <summary> build the capture graph for grabber. </summary>

bool SetupGraph()

{

int hr;

try {

hr = capGraph.SetFiltergraph(graphBuilder);

if (hr < 0)

Marshal.ThrowExceptionForHR(hr);

hr = graphBuilder.AddFilter(capFilter, "Ds.NET Video Capture Device");

if (hr < 0)

Marshal.ThrowExceptionForHR(hr);

//DsUtils.ShowCapPinDialog( capGraph, capFilter, this.Handle );//box property

AMMediaType media = new AMMediaType();

media.majorType = MediaType.Video;

media.subType = MediaSubType.RGB24;

media.formatType = FormatType.VideoInfo; // ???

hr = sampGrabber.SetMediaType( media );

if( hr < 0 )

Marshal.ThrowExceptionForHR( hr );

hr = graphBuilder.AddFilter( baseGrabFlt, "Ds.NET Grabber" );

if( hr < 0 )

Marshal.ThrowExceptionForHR( hr );

Guid cat = PinCategory.Preview;

Guid med = MediaType.Video;

hr = capGraph.RenderStream( ref cat, ref med, capFilter, null, null ); // baseGrabFlt

if( hr < 0 )

Marshal.ThrowExceptionForHR( hr );

cat = PinCategory.Capture;

med = MediaType.Video;

hr = capGraph.RenderStream( ref cat, ref med, capFilter, null, baseGrabFlt ); // baseGrabFlt

if( hr < 0 )

Marshal.ThrowExceptionForHR( hr );

media = new AMMediaType();

hr = sampGrabber.GetConnectedMediaType( media );

if( hr < 0 )

Marshal.ThrowExceptionForHR( hr );

if( (media.formatType != FormatType.VideoInfo) || (media.formatPtr == IntPtr.Zero) )

throw new NotSupportedException( "Unknown Grabber Media Format" );

videoInfoHeader = (VideoInfoHeader) Marshal.PtrToStructure( media.formatPtr, typeof(VideoInfoHeader) );

Marshal.FreeCoTaskMem( media.formatPtr ); media.formatPtr = IntPtr.Zero;

hr = sampGrabber.SetBufferSamples( false );

if( hr == 0 )

hr = sampGrabber.SetOneShot( false );

if( hr == 0 )

hr = sampGrabber.SetCallback( null, 0 );

if( hr < 0 )

Marshal.ThrowExceptionForHR( hr );

return true;

}

catch( Exception ee )

{

MessageBox.Show( this, "Could not setup graph\r\n" + ee.Message, "DirectShow.NET", MessageBoxButtons.OK, MessageBoxIcon.Stop );

return false;

}

}

/// <summary> create the used COM components and get the interfaces. </summary>

bool GetInterfaces()

{

Type comType = null;

object comObj = null;

try {

comType = Type.GetTypeFromCLSID(Clsid.FilterGraph);

if (comType == null)

throw new NotImplementedException(@"DirectShow FilterGraph not installed/registered!");

comObj = Activator.CreateInstance(comType);

graphBuilder = (IGraphBuilder)comObj; comObj = null;

Guid clsid = Clsid.CaptureGraphBuilder2;

Guid riid = typeof(ICaptureGraphBuilder2).GUID;

comObj = DsBugWO.CreateDsInstance( ref clsid, ref riid );

capGraph = (ICaptureGraphBuilder2) comObj; comObj = null;

comType = Type.GetTypeFromCLSID( Clsid.SampleGrabber );

if( comType == null )

throw new NotImplementedException( @"DirectShow SampleGrabber not installed/registered!" );

comObj = Activator.CreateInstance( comType );

sampGrabber = (ISampleGrabber) comObj; comObj = null;

mediaCtrl = (IMediaControl) graphBuilder;

videoWin = (IVideoWindow) graphBuilder;

mediaEvt = (IMediaEventEx) graphBuilder;

baseGrabFlt = (IBaseFilter) sampGrabber;

return true;

}

catch( Exception ee )

{

MessageBox.Show( this, "Could not get interfaces\r\n" + ee.Message, "DirectShow.NET", MessageBoxButtons.OK, MessageBoxIcon.Stop );

return false;

}

finally

{

if( comObj != null )

Marshal.ReleaseComObject( comObj ); comObj = null;

}

}

/// <summary> create the user selected capture device. </summary>

bool CreateCaptureDevice(UCOMIMoniker mon )

{

object capObj = null;

try {

Guid gbf = typeof( IBaseFilter ).GUID;

mon.BindToObject( null, null, ref gbf, out capObj );

capFilter = (IBaseFilter) capObj; capObj = null;

return true;

}

catch( Exception ee )

{

MessageBox.Show( this, "Could not create capture device\r\n" + ee.Message, "DirectShow.NET", MessageBoxButtons.OK, MessageBoxIcon.Stop );

return false;

}

finally

{

if( capObj != null )

Marshal.ReleaseComObject( capObj ); capObj = null;

}

}

/// <summary> do cleanup and release DirectShow. </summary>

void CloseInterfaces()

{

int hr;

try {

#if DEBUG

if( rotCookie != 0 )

DsROT.RemoveGraphFromRot( ref rotCookie );

#endif

if( mediaCtrl != null )

{

hr = mediaCtrl.Stop();

mediaCtrl = null;

}

if( mediaEvt != null )

{

hr = mediaEvt.SetNotifyWindow( IntPtr.Zero, WM_GRAPHNOTIFY, IntPtr.Zero );

mediaEvt = null;

}

if( videoWin != null )

{

hr = videoWin.put_Visible( DsHlp.OAFALSE );

hr = videoWin.put_Owner( IntPtr.Zero );

videoWin = null;

}

baseGrabFlt = null;

if( sampGrabber != null )

Marshal.ReleaseComObject( sampGrabber ); sampGrabber = null;

if( capGraph != null )

Marshal.ReleaseComObject( capGraph ); capGraph = null;

if( graphBuilder != null )

Marshal.ReleaseComObject( graphBuilder ); graphBuilder = null;

if( capFilter != null )

Marshal.ReleaseComObject( capFilter ); capFilter = null;

if( capDevices != null )

{

foreach( DsDevice d in capDevices )

d.Dispose();

capDevices = null;

}

}

catch( Exception )

{}

}

/// <summary> resize preview video window to fill client area. </summary>

void ResizeVideoWindow()

{

if( videoWin != null )

{

Rectangle rc = videoPanel.ClientRectangle;

videoWin.SetWindowPosition( 0, 0, rc.Right, rc.Bottom );

}

}

/// <summary> override window fn to handle graph events. </summary> //// the error refer to this part

protected override void WndProc(ref Message m)

{

if (m.Msg == WM_GRAPHNOTIFY)

{

if (mediaEvt != null)

OnGraphNotify();

return;

}

base.WndProc(ref m);

}

/// <summary> graph event (WM_GRAPHNOTIFY) handler. </summary>

void OnGraphNotify()

{

DsEvCode code;

int p1, p2, hr = 0;

do

{

hr = mediaEvt.GetEvent( out code, out p1, out p2, 0 );

if( hr < 0 )

break;

hr = mediaEvt.FreeEventParams( code, p1, p2 );

}

while( hr == 0 );

}

/// <summary> sample callback, NOT USED. </summary>

int ISampleGrabberCB.SampleCB(double SampleTime, IMediaSample pSample)

{

Trace.WriteLine("!!CB: ISampleGrabberCB.SampleCB");

return 0;

}

/// <summary> buffer callback, COULD BE FROM FOREIGN THREAD. </summary>

int ISampleGrabberCB.BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)

{

if ((captured == true) || (savedArray == null))

{

Trace.WriteLine("!!CB: ISampleGrabberCB.BufferCB");

return 0;

}

captured = true;

bufferedSize = BufferLen;

Trace.WriteLine("!!CB: ISampleGrabberCB.BufferCB !GRAB! size = " + BufferLen.ToString());

if ((pBuffer != IntPtr.Zero) && (BufferLen > 1000) && (BufferLen <= savedArray.Length))

Marshal.Copy(pBuffer, savedArray, 0, BufferLen);

else

Trace.WriteLine(" !!!GRAB! failed ");

this.BeginInvoke(new CaptureDone(this.OnCaptureDone));

return 0;

}

shuhada  Friday, December 22, 2006 5:28 AM
Hi,

This could be the solution. Try releasing the resources of the bitmap you are using in the OnCaptureComplete() method, and to do this correctly you should pass a new bitmap to your picturebox, not 'b' otherwise you are just creating a reference.

So I would modify the method as follows and see if it helps:

void OnCaptureDone()

{

try

{

toolBarBtnGrab.Enabled = true;

int hr;

if (sampGrabber == null)

return;

hr = sampGrabber.SetCallback(null, 0);

int w = videoInfoHeader.BmiHeader.Width;

int h = videoInfoHeader.BmiHeader.Height;

int stride = w * 3;

GCHandle handle = GCHandle.Alloc(savedArray, GCHandleType.Pinned);

int scan0 = (int)handle.AddrOfPinnedObject();

scan0 += (h - 1) * stride;

Bitmap b = new Bitmap(w, h, -stride, PixelFormat.Format24bppRgb, (IntPtr)scan0);

handle.Free();

savedArray = null;

//Create a new Image here, else you are cross referencing the

//image to be assigned to the picture box in the next step.

Image old = new Bitmap(pictureBox.Image);

pictureBox.Image.Dispose();

//----------------------------------------------------------

//we need to dispoase of the Bitmap correctly. To achieve this

//assign a new Bitmap to the picturebox based on the existing one

//we do this otherwise we only recieve a reference, and disposing

//b under this case would not be a good idea

pictureBox.Image = new Bitmap(b);

b.Dispose();

//toolBarBtnSave.Enabled = true;

//this could cause problems also if this method is called repeatedly

//and the file handle has not yet been released or we are attempting to

//dispose an image that we are also attempting to save

//you may have to throttle the capture, or use differing

//file names such as by adding a timestamp

pictureBox.Image.Save(DateTime.Now.ToString() + ".Jpeg", ImageFormat.Jpeg);

//----------------------------------------------------------

}

See if any of those suggestions help.

If not shout back, I have some code I can dig out and offer you. With regard to my expereinces with the SampleGrabber, I had problems with certain video formats, DV and possible MPEG2, and used the VMR as a capture source instead. The VMR provides a very handy GetCurrentImage method.

The VMR simply replaces the VideoRenderer in your graph, so the image you retrieve is not from the stream but from the end point, if you dont wish to modify the buffer, to edit the stream, then SampleGrabber is not required and is infact not the best way to capture screens as it is constantly waiting for your callback method to complete, so has a performance hit, and as I stated compatibility problems, although an improved compatibility SampleGrabber was provided with the SDK examples as source code.

You should consider reducing the operations in the callback method (OnCaptureComplete) to simply retrieving the Bitmap and sending it on in an event to be processed, as overalll video performance can be effected by the speed of this method.

Regards
GavH  Friday, December 22, 2006 11:59 AM

Hi,

Thanks for your respond. I've try the code that you give, but it gives error.

"Could not grab picture. Object reference not an instance of an object"

For your information, this error will come even if I did not put the loop in the code. I still blur about this and really hope you could help. Thanks for willing to help.

shuhada  Saturday, December 23, 2006 8:19 AM

Try changing Image old = new Bitmap(pictureBox.Image);

to:

if(pictureBox.Image != null)
Image old = new Bitmap(pictureBox.Image);

That is most likely the soure of the 'Object reference not set' Exception, as on the first run through pictureBox wont have an image assigned.

Regards.

GavH  Saturday, December 23, 2006 9:13 AM

It still give the same error. I mean, after I click capture button, the same error will come out.

shuhada

shuhada  Saturday, December 23, 2006 1:49 PM
Hi can you email me your project to : gav @ pinnacle-software-solutions . com

I am sure the problem is minimal, I can see nothing as such wrong with your code, however if I can compile the project I will have a much better chance of locating the error.

Regards


GavH  Saturday, December 23, 2006 2:35 PM

Hi,

I've already sent. Pleaseinform me if my email has not been successfully sent. Thank you.

shuhada  Saturday, December 23, 2006 3:17 PM
Hi shuhada,

In your MainForm.cs make the following changes. Note I will also send this back to you by email as it is a little complicated. I have added notes, but the major changes are the use of the SampleGrabber buffer, and due to that the removal of the SampleGrabber callback. I also rewrote the buffer to bmp routine.

Regards



using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics;
using System.Threading;

using DShowNET;
using DShowNET.Device;


namespace grab1
{

/// <summary> Summary description for MainForm. </summary>
public class MainForm : System.Windows.Forms.Form
{
//private System.Windows.Forms.Splitter splitter1;
private System.Windows.Forms.ToolBar toolBar;
private System.Windows.Forms.Panel videoPanel;
private System.Windows.Forms.Panel stillPanel;
private System.Windows.Forms.PictureBox pictureBox;
private System.Windows.Forms.ToolBarButton toolBarBtnGrab;
private System.Windows.Forms.ImageList imgListToolBar;
private System.ComponentModel.IContainer components;
private TextBox textBox1;
public static int i;
public static int a = 0;

//_________________GavH edit_____________________________
//we use this event to signal an image has been captured
public delegate void BitmapCaptureReady(Bitmap bmp); //delegate for capture complete event
public event BitmapCaptureReady CaptureComplete; //the capture complete event
//________________End Edit_______________________________


public MainForm()
{
// Required for Windows Form Designer support
InitializeComponent();

//________________GavH Edit________________________________________________
//we need to add an event handler for our new BitmapCaptureReady event
this.CaptureComplete += new BitmapCaptureReady(MainForm_CaptureComplete);
}

/// <summary>
/// Handle the bitmap capture complete event
/// </summary>
/// <param name="bmp"></param>
void MainForm_CaptureComplete(Bitmap bmp)
{
pictureBox.Image = bmp;

//toolBarBtnSave.Enabled = true;
//pictureBox.Image.Save("1stImage.Jpeg", ImageFormat.Jpeg);
}

//________________End Edit__________________________________________________

/// <summary> Clean up any resources being used. </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
CloseInterfaces();

if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.toolBar = new System.Windows.Forms.ToolBar();
this.toolBarBtnGrab = new System.Windows.Forms.ToolBarButton();
this.imgListToolBar = new System.Windows.Forms.ImageList(this.components);
this.videoPanel = new System.Windows.Forms.Panel();
this.stillPanel = new System.Windows.Forms.Panel();
this.pictureBox = new System.Windows.Forms.PictureBox();
this.textBox1 = new System.Windows.Forms.TextBox();
this.stillPanel.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureBox)).BeginInit();
this.SuspendLayout();
//
// toolBar
//
this.toolBar.Buttons.AddRange(new System.Windows.Forms.ToolBarButton[] {
this.toolBarBtnGrab});
this.toolBar.Cursor = System.Windows.Forms.Cursors.Hand;
this.toolBar.DropDownArrows = true;
this.toolBar.Location = new System.Drawing.Point(0, 0);
this.toolBar.Name = "toolBar";
this.toolBar.ShowToolTips = true;
this.toolBar.Size = new System.Drawing.Size(689, 42);
this.toolBar.TabIndex = 0;
this.toolBar.ButtonClick += new System.Windows.Forms.ToolBarButtonClickEventHandler(this.toolBar_ButtonClick);
//
// toolBarBtnGrab
//
this.toolBarBtnGrab.Name = "toolBarBtnGrab";
this.toolBarBtnGrab.Text = "Click Here";
//
// imgListToolBar
//
this.imgListToolBar.ColorDepth = System.Windows.Forms.ColorDepth.Depth8Bit;
this.imgListToolBar.ImageSize = new System.Drawing.Size(16, 16);
this.imgListToolBar.TransparentColor = System.Drawing.Color.Transparent;
//
// videoPanel
//
this.videoPanel.BackColor = System.Drawing.Color.Black;
this.videoPanel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.videoPanel.Dock = System.Windows.Forms.DockStyle.Left;
this.videoPanel.Location = new System.Drawing.Point(0, 42);
this.videoPanel.Name = "videoPanel";
this.videoPanel.Size = new System.Drawing.Size(353, 283);
this.videoPanel.TabIndex = 1;
this.videoPanel.Resize += new System.EventHandler(this.videoPanel_Resize);
//
// stillPanel
//
this.stillPanel.AutoScroll = true;
this.stillPanel.AutoScrollMargin = new System.Drawing.Size(8, 8);
this.stillPanel.AutoScrollMinSize = new System.Drawing.Size(32, 32);
this.stillPanel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.stillPanel.Controls.Add(this.textBox1);
this.stillPanel.Controls.Add(this.pictureBox);
this.stillPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.stillPanel.Location = new System.Drawing.Point(353, 42);
this.stillPanel.Name = "stillPanel";
this.stillPanel.Size = new System.Drawing.Size(336, 283);
this.stillPanel.TabIndex = 3;
//
// pictureBox
//
this.pictureBox.Location = new System.Drawing.Point(52, 13);
this.pictureBox.Name = "pictureBox";
this.pictureBox.Size = new System.Drawing.Size(240, 232);
this.pictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.pictureBox.TabIndex = 0;
this.pictureBox.TabStop = false;
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(9, 252);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(95, 20);
this.textBox1.TabIndex = 1;
//
// MainForm
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(689, 325);
this.Controls.Add(this.stillPanel);
this.Controls.Add(this.videoPanel);
this.Controls.Add(this.toolBar);
this.Name = "MainForm";
this.Text = "Agent Base Recognition System";
this.Activated += new System.EventHandler(this.MainForm_Activated);
this.Closing += new System.ComponentModel.CancelEventHandler(this.MainForm_Closing);
this.stillPanel.ResumeLayout(false);
this.stillPanel.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureBox)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{


Application.Run(new MainForm());
}

private void MainForm_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
this.Hide();
CloseInterfaces();
}

/// <summary> detect first form appearance, start grabber. </summary>
private void MainForm_Activated(object sender, System.EventArgs e)
{
if( firstActive )
return;
firstActive = true;


if( ! DsUtils.IsCorrectDirectXVersion() )
{
MessageBox.Show( this, "DirectX 8.1 NOT installed!", "DirectShow.NET", MessageBoxButtons.OK, MessageBoxIcon.Stop );
this.Close(); return;
}

if (!DsDev.GetDevicesOfCat(FilterCategory.VideoInputDevice, out capDevices))
{
MessageBox.Show(this, "No video capture devices found!", "DirectShow.NET", MessageBoxButtons.OK, MessageBoxIcon.Stop);
this.Close(); return;
}

DsDevice dev = null;
if (capDevices.Count == 1)
dev = capDevices[0] as DsDevice;
else
{
DeviceSelector selector = new DeviceSelector( capDevices );

selector.ShowDialog( this );
dev = selector.SelectedDevice;
}

if( dev == null )
{
this.Close(); return;
}

if( ! StartupVideo( dev.Mon ) )
this.Close();
}

private void videoPanel_Resize(object sender, System.EventArgs e)
{
ResizeVideoWindow();
}


/// <summary> handler for toolbar button clicks. </summary>
private void toolBar_ButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e)
{
if (e.Button == toolBarBtnGrab)

do
{
//Thread.Sleep(2000);
a++;
//______GavH Edit ----------------//
//no longer required
//SampleGrabber is set to handle its own buffer
//Prepare4Grab();
this.CaptureImage();
textBox1.Text = a.ToString();
}
while (a < 5);
}

/*________________GavH Edit __________________________
* We dont need this method,we are no longer using the SmapleGrabber
* in callback mode, it is handling its own buffer
void Prepare4Grab()


{
int hr;

int size = videoInfoHeader.BmiHeader.ImageSize; //image info
savedArray = new byte[size + 64000]; // buffer for bitmap data
captured = false;
hr = sampGrabber.SetCallback(this, 1);
}

/// <summary> capture event, triggered by buffer callback. </summary>
void OnCaptureDone()
{
try
{

toolBarBtnGrab.Enabled = true;
int hr;
if( sampGrabber == null )
return;
hr = sampGrabber.SetCallback( null, 0 );

int w = videoInfoHeader.BmiHeader.Width;
int h = videoInfoHeader.BmiHeader.Height;
int stride = w * 3;

GCHandle handle = GCHandle.Alloc(savedArray, GCHandleType.Pinned);
int scan0 = (int)handle.AddrOfPinnedObject();
scan0 += (h - 1) * stride;
Bitmap b = new Bitmap(w, h, -stride, PixelFormat.Format24bppRgb, (IntPtr)scan0);
handle.Free();
savedArray = null;

//Image old = pictureBox.Image;
pictureBox.Image = new Bitmap(b);

//b.Dispose();

//toolBarBtnSave.Enabled = true;
//pictureBox.Image.Save("1stImage.Jpeg", ImageFormat.Jpeg);

}
catch (Exception ee)
{
MessageBox.Show(this, "Could not grab picture\r\n" + ee.Message, "DirectShow.NET", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}

}
*/



/// <summary>
/// This method grabs the current buffer from the SampleGrabber and converts
/// it into an appropriate BMP, fast.
///
/// it then calls the CaptureComplete Event passing with it the new BMP
/// </summary>
public void CaptureImage()
{
int size = 0;
int hr = 0;
IntPtr pBuffer = IntPtr.Zero;
IntPtr hBmp = IntPtr.Zero;
byte[] buffer;
Bitmap bmp = null;
AMMediaType mt = null;

try
{
//get the size of the buffer
hr = sampGrabber.GetCurrentBuffer(ref size, IntPtr.Zero);
if (hr < 0) throw new Exception("Could not retrieve sample buffer");

//allocate buffer - get data - copy buffer
//we are making the same call as above although the first
//call was just to get the buffer size
pBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(byte)) * size);
hr = sampGrabber.GetCurrentBuffer(ref size, pBuffer);
if (hr < 0) throw new Exception("Could not retrieve sample buffer");

buffer = new byte[size];
Marshal.Copy(pBuffer, buffer, 0, size);
Marshal.FreeHGlobal(pBuffer);
pBuffer = IntPtr.Zero;

//we need to know the mediatype so we can work with the buffer
mt = new AMMediaType();
hr = sampGrabber.GetConnectedMediaType(mt);
if (hr < 0) throw new NotSupportedException("Sample Grabber Media Type Issue");

//Examine the format block
//obtain a VideoInfoHeader
VideoInfoHeader Vih = new VideoInfoHeader();

if ((mt.formatType == FormatType.VideoInfo) &&
(mt.formatSize >= Marshal.SizeOf(Vih)) &&
(mt.formatPtr != IntPtr.Zero))
{
Vih = (VideoInfoHeader)Marshal.PtrToStructure(mt.formatPtr, typeof(VideoInfoHeader));
}
else
{
// Wrong format. Free the format block and return an error.
if (mt.formatSize != 0)
{
Marshal.FreeCoTaskMem(mt.formatPtr);
mt.formatSize = 0;
mt.formatPtr = IntPtr.Zero;
}
if (mt.unkPtr != IntPtr.Zero)
{
Marshal.Release(mt.unkPtr);
mt.unkPtr = IntPtr.Zero;
}
mt = null;
throw new NotSupportedException("Invalid media type.");
}


//this can be performed faster using win32 interop
//however this is the 'prefered' method



//instantiate bmp of correct size according to bitmapinfoheader
bmp = new Bitmap(Vih.BmiHeader.Width, Vih.BmiHeader.Height);
BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

//Copy buffer to BitmapData
Marshal.Copy(buffer, 0, bd.Scan0, buffer.Length);

bmp.UnlockBits(bd); //unlock Bitmap which will now be upsidedown

//correct the orientation
bmp.RotateFlip(RotateFlipType.Rotate180FlipX);

//fire the event with the bmp
CaptureComplete(new Bitmap(bmp));
bmp.Dispose();
}
catch (Exception ex)
{
throw ex;
}
finally
{
//clean up anything we have not already dealt with
if (mt != null)
{
if (mt.formatSize != 0)
{
Marshal.FreeCoTaskMem(mt.formatPtr);
mt.formatSize = 0;
mt.formatPtr = IntPtr.Zero;
}
if (mt.unkPtr != IntPtr.Zero)
{
Marshal.Release(mt.unkPtr);
mt.unkPtr = IntPtr.Zero;
}
mt = null;
}
if (pBuffer != IntPtr.Zero) Marshal.FreeHGlobal(pBuffer); pBuffer = IntPtr.Zero;
if (hBmp != IntPtr.Zero) hBmp = IntPtr.Zero;
GC.Collect();
}
}


//_________________End Edit_________________________________


bool StartupVideo( UCOMIMoniker mon )
{
int hr;
try {
if( ! CreateCaptureDevice( mon ) )
return false;

if( ! GetInterfaces() )
return false;

if( ! SetupGraph() )
return false;

if( ! SetupVideoWindow() )
return false;

#if DEBUG
DsROT.AddGraphToRot(graphBuilder, out rotCookie); // graphBuilder capGraph
#endif

hr = mediaCtrl.Run();
if( hr < 0 )
Marshal.ThrowExceptionForHR( hr );
return true;
}
catch( Exception ee )
{
MessageBox.Show( this, "Could not start video stream\r\n" + ee.Message, "DirectShow.NET", MessageBoxButtons.OK, MessageBoxIcon.Stop );
return false;
}
}

// <summary> make the video preview window to show in videoPanel. </summary>///
bool SetupVideoWindow()
{
int hr;
try {
// Set the video window to be a child of the main window
hr = videoWin.put_Owner( videoPanel.Handle );
if( hr < 0 )
Marshal.ThrowExceptionForHR( hr );

// Set video window style
hr = videoWin.put_WindowStyle( WS_CHILD | WS_CLIPCHILDREN );
if( hr < 0 )
Marshal.ThrowExceptionForHR( hr );

// Use helper function to position video window in client rect of owner window
ResizeVideoWindow();

// Make the video window visible, now that it is properly positioned
hr = videoWin.put_Visible( DsHlp.OATRUE );
if( hr < 0 )
Marshal.ThrowExceptionForHR( hr );

hr = mediaEvt.SetNotifyWindow(this.Handle, WM_GRAPHNOTIFY, IntPtr.Zero);
if (hr < 0)
Marshal.ThrowExceptionForHR(hr);
return true;
}
catch( Exception ee )
{
MessageBox.Show( this, "Could not setup video window\r\n" + ee.Message, "DirectShow.NET", MessageBoxButtons.OK, MessageBoxIcon.Stop );
return false;
}
}


/// <summary> build the capture graph for grabber. </summary>
bool SetupGraph()
{
int hr;
try {
hr = capGraph.SetFiltergraph(graphBuilder);
if (hr < 0)
Marshal.ThrowExceptionForHR(hr);

hr = graphBuilder.AddFilter(capFilter, "Ds.NET Video Capture Device");
if (hr < 0)
Marshal.ThrowExceptionForHR(hr);

//DsUtils.ShowCapPinDialog( capGraph, capFilter, this.Handle );//box property

AMMediaType media = new AMMediaType();
media.majorType = MediaType.Video;
media.subType = MediaSubType.RGB24;
media.formatType = FormatType.VideoInfo; // ???
hr = sampGrabber.SetMediaType( media );
if( hr < 0 )
Marshal.ThrowExceptionForHR( hr );

hr = graphBuilder.AddFilter( baseGrabFlt, "Ds.NET Grabber" );
if( hr < 0 )
Marshal.ThrowExceptionForHR( hr );

Guid cat = PinCategory.Preview;
Guid med = MediaType.Video;
hr = capGraph.RenderStream( ref cat, ref med, capFilter, null, null ); // baseGrabFlt
if( hr < 0 )
Marshal.ThrowExceptionForHR( hr );

cat = PinCategory.Capture;
med = MediaType.Video;
hr = capGraph.RenderStream( ref cat, ref med, capFilter, null, baseGrabFlt ); // baseGrabFlt
if( hr < 0 )
Marshal.ThrowExceptionForHR( hr );

media = new AMMediaType();
hr = sampGrabber.GetConnectedMediaType( media );
if( hr < 0 )
Marshal.ThrowExceptionForHR( hr );
if( (media.formatType != FormatType.VideoInfo) || (media.formatPtr == IntPtr.Zero) )
throw new NotSupportedException( "Unknown Grabber Media Format" );

videoInfoHeader = (VideoInfoHeader) Marshal.PtrToStructure( media.formatPtr, typeof(VideoInfoHeader) );
Marshal.FreeCoTaskMem( media.formatPtr ); media.formatPtr = IntPtr.Zero;


//-----------------GavH Edit---------------------//
/*
hr = sampGrabber.SetBufferSamples( false );
if( hr == 0 )
hr = sampGrabber.SetOneShot( false );
if( hr == 0 )
hr = sampGrabber.SetCallback( null, 0 );
if( hr < 0 )
Marshal.ThrowExceptionForHR( hr );
*/

//setup sample grabber to maintain samples buffer
//we can call the buffer when we want a capture
//instead of using the callback.

hr = sampGrabber.SetBufferSamples(true);
if (hr < 0) throw new NotSupportedException("Sample Grabber Buffer");
hr = sampGrabber.SetOneShot(false);
if (hr < 0) throw new NotSupportedException("Sample Grabber compatibility problems");



//----------------Edit Finished -----------------//

return true;
}
catch( Exception ee )
{
MessageBox.Show( this, "Could not setup graph\r\n" + ee.Message, "DirectShow.NET", MessageBoxButtons.OK, MessageBoxIcon.Stop );
return false;
}
}


/// <summary> create the used COM components and get the interfaces. </summary>
bool GetInterfaces()
{
Type comType = null;
object comObj = null;
try {
comType = Type.GetTypeFromCLSID(Clsid.FilterGraph);
if (comType == null)
throw new NotImplementedException(@"DirectShow FilterGraph not installed/registered!");
comObj = Activator.CreateInstance(comType);
graphBuilder = (IGraphBuilder)comObj; comObj = null;


Guid clsid = Clsid.CaptureGraphBuilder2;
Guid riid = typeof(ICaptureGraphBuilder2).GUID;
comObj = DsBugWO.CreateDsInstance( ref clsid, ref riid );
capGraph = (ICaptureGraphBuilder2) comObj; comObj = null;


comType = Type.GetTypeFromCLSID( Clsid.SampleGrabber );
if( comType == null )
throw new NotImplementedException( @"DirectShow SampleGrabber not installed/registered!" );
comObj = Activator.CreateInstance( comType );
sampGrabber = (ISampleGrabber) comObj; comObj = null;


mediaCtrl = (IMediaControl) graphBuilder;
videoWin = (IVideoWindow) graphBuilder;
mediaEvt = (IMediaEventEx) graphBuilder;
baseGrabFlt = (IBaseFilter) sampGrabber;
return true;
}
catch( Exception ee )
{
MessageBox.Show( this, "Could not get interfaces\r\n" + ee.Message, "DirectShow.NET", MessageBoxButtons.OK, MessageBoxIcon.Stop );
return false;
}
finally
{
if( comObj != null )
Marshal.ReleaseComObject( comObj ); comObj = null;
}
}

/// <summary> create the user selected capture device. </summary>
bool CreateCaptureDevice(UCOMIMoniker mon )
{
object capObj = null;
try {
Guid gbf = typeof( IBaseFilter ).GUID;
mon.BindToObject( null, null, ref gbf, out capObj );
capFilter = (IBaseFilter) capObj; capObj = null;
return true;
}
catch( Exception ee )
{
MessageBox.Show( this, "Could not create capture device\r\n" + ee.Message, "DirectShow.NET", MessageBoxButtons.OK, MessageBoxIcon.Stop );
return false;
}
finally
{
if( capObj != null )
Marshal.ReleaseComObject( capObj ); capObj = null;
}

}



/// <summary> do cleanup and release DirectShow. </summary>
void CloseInterfaces()
{
int hr;
try {
#if DEBUG
if( rotCookie != 0 )
DsROT.RemoveGraphFromRot( ref rotCookie );
#endif

if( mediaCtrl != null )
{
hr = mediaCtrl.Stop();
mediaCtrl = null;
}

if( mediaEvt != null )
{
hr = mediaEvt.SetNotifyWindow( IntPtr.Zero, WM_GRAPHNOTIFY, IntPtr.Zero );
mediaEvt = null;
}

if( videoWin != null )
{
hr = videoWin.put_Visible( DsHlp.OAFALSE );
hr = videoWin.put_Owner( IntPtr.Zero );
videoWin = null;
}

baseGrabFlt = null;
if( sampGrabber != null )
Marshal.ReleaseComObject( sampGrabber ); sampGrabber = null;

if( capGraph != null )
Marshal.ReleaseComObject( capGraph ); capGraph = null;

if( graphBuilder != null )
Marshal.ReleaseComObject( graphBuilder ); graphBuilder = null;

if( capFilter != null )
Marshal.ReleaseComObject( capFilter ); capFilter = null;

if( capDevices != null )
{
foreach( DsDevice d in capDevices )
d.Dispose();
capDevices = null;
}
}
catch( Exception )
{}
}

/// <summary> resize preview video window to fill client area. </summary>
void ResizeVideoWindow()
{
if( videoWin != null )
{
Rectangle rc = videoPanel.ClientRectangle;
videoWin.SetWindowPosition( 0, 0, rc.Right, rc.Bottom );
}
}

/// <summary> override window fn to handle graph events. </summary>
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_GRAPHNOTIFY)
{
if (mediaEvt != null)
OnGraphNotify();
return;
}
base.WndProc(ref m);
}

/// <summary> graph event (WM_GRAPHNOTIFY) handler. </summary>
void OnGraphNotify()
{
DsEvCode code;
int p1, p2, hr = 0;
do
{
hr = mediaEvt.GetEvent( out code, out p1, out p2, 0 );
if( hr < 0 )
break;
hr = mediaEvt.FreeEventParams( code, p1, p2 );

}
while( hr == 0 );
}

/*--------------GavH Edit__________________________//
/// <summary> sample callback, NOT USED. </summary>
int ISampleGrabberCB.SampleCB(double SampleTime, IMediaSample pSample)
{
Trace.WriteLine("!!CB: ISampleGrabberCB.SampleCB");
return 0;
}

/// <summary> buffer callback, COULD BE FROM FOREIGN THREAD. </summary>
int ISampleGrabberCB.BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)
{
if ((captured == true) || (savedArray == null))
{
Trace.WriteLine("!!CB: ISampleGrabberCB.BufferCB");
return 0;
}

captured = true;
bufferedSize = BufferLen;
Trace.WriteLine("!!CB: ISampleGrabberCB.BufferCB !GRAB! size = " + BufferLen.ToString());
if ((pBuffer != IntPtr.Zero) && (BufferLen > 1000) && (BufferLen <= savedArray.Length))
Marshal.Copy(pBuffer, savedArray, 0, BufferLen);
else
Trace.WriteLine(" !!!GRAB! failed ");
this.BeginInvoke(new CaptureDone(this.OnCaptureDone));
return 0;
}
*/
//_______________________End Edit________________________________


/// <summary> flag to detect first Form appearance </summary>
private bool firstActive;

/// <summary> base filter of the actually used video devices. </summary>
private IBaseFilter capFilter;

/// <summary> graph builder interface. </summary>
private IGraphBuilder graphBuilder;

/// <summary> capture graph builder interface. </summary>
private ICaptureGraphBuilder2 capGraph;
private ISampleGrabber sampGrabber;

/// <summary> control interface. </summary>
private IMediaControl mediaCtrl;

/// <summary> event interface. </summary>
private IMediaEventEx mediaEvt;

/// <summary> video window interface. </summary>
private IVideoWindow videoWin;

/// <summary> grabber filter interface. </summary>
private IBaseFilter baseGrabFlt;

/// <summary> structure describing the bitmap to grab. </summary>
private VideoInfoHeader videoInfoHeader;
private bool captured = true;
private int bufferedSize;

/// <summary> buffer for bitmap data. </summary>
private byte[] savedArray;

/// <summary> list of installed video devices. </summary>
private ArrayList capDevices;

private const int WM_GRAPHNOTIFY = 0x00008001; // message from graph

private const int WS_CHILD = 0x40000000; // attributes for video window
private const int WS_CLIPCHILDREN = 0x02000000;
private const int WS_CLIPSIBLINGS = 0x04000000;

/// <summary> event when callback has finished (ISampleGrabberCB.BufferCB). </summary>
private delegate void CaptureDone();

#if DEBUG
private int rotCookie = 0;
#endif
}

internal enum PlayState
{
Init, Stopped, Paused, Running
}

}

GavH  Saturday, December 23, 2006 5:47 PM

Hi GavH,

Thanks for help me alot. I run the code that you give. Yes, th error does not come out. However, the result (means the capturing still image) just appear at the last of looping. It not appear during the looping process. During the loop process it not give any result.

shuhada  Sunday, December 24, 2006 12:23 AM

Hi Shuhada,

If you change the CaptureComplete event handler to the following so that it saves each image under a seperate file name, by (tick) you will be ableto see how fast the system is creating the images, very fast indeed.

/// <summary>

/// Handle the bitmap capture complete event

/// </summary>

/// <param name="bmp"></param>

void MainForm_CaptureComplete(Bitmap bmp)

{

pictureBox.Image = bmp;

//toolBarBtnSave.Enabled = true;

pictureBox.Image.Save("h:\\" + DateTime.Now.Ticks.ToString() + "test.Jpeg", ImageFormat.Jpeg);

}

The reason you do not see any change until after the last of the loop has completed is because you are doing all of your processing in the UI thread. When your Grab method runs, it processes through that loop so intensley that it does not do anything else, The best result would be achieved by processing on a different thread, however you can fix your problem by adding Application.DoEvents() to you loop.

/// <summary> handler for toolbar button clicks. </summary>

private void toolBar_ButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e)

{

if (e.Button == toolBarBtnGrab)

do

{

//Thread.Sleep(2000);

a++;

//______GavH Edit ----------------//

//no longer required

//SampleGrabber is set to handle its own buffer

//Prepare4Grab();

this.CaptureImage();

textBox1.Text = a.ToString();

Application.DoEvents();

}

while (a < 150);

}

This is not the best method of doing this. A better way would be to use a timer that calls the capture method at a set interval, say every 10th of a second.

Regards

GavH  Sunday, December 24, 2006 9:17 AM

Hi GavH,

Thanks alot.. Finally, the program can loop.However I not use timer for delay as u suggest. I was use sleep. And it works. However there are two major problem comes after that.

(1) The loop only works for the first click of capture. After the first round loop complete and I click to capture again, it just capture once and not repeat the loop. I wonder why.

(2)For your information, i'll use the image for futher process of filtering. And it going well. But it gives problem when I want to call file from outside. It gives error message: "Object reference not set to an instance of an object".

And the error refer to this code:

catch (Exception ex)

{

throw ex;

}

And this code under CaptureImage() method. I'll send to you my new code for your reference.

Thankyou for your time.

shuhada  Monday, December 25, 2006 9:29 AM

I'm using the Blas5's code from http://www.codeproject.com/directx/CapSample1.asp

I'm using D-Link's web cam. I splited the windows (AddCam, MW and CW) and accessing through a Menu. Its all works fine for first time. but Whenever I try to access MW form (of your sample) its not rendering.

I tried to access again this code ->
CaptureInformation.Camera = Dispositivos.VideoInputDevices(cboCamaras.SelectedIndex)
this is throwing exception (this time hr is < 0).

What I want is to set once my camera and keep calling capture window to n times (open & close) to capture frames.

Hopefully GavH help me to come out of this error...

VishalR  Thursday, December 28, 2006 5:13 AM
Hi Shuhada,

To fix your loop problem you must change the way the loop is counted, try the following:

/// <summary> handler for toolbar button clicks. </summary>
private void toolBar_ButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e)
{
if (e.Button == toolBarBtnGrab)

do
{
Thread.Sleep(500);
a++;
this.CaptureImage();
textBox1.Text = a.ToString();
Application.DoEvents();
}
while (a %10 != 0); //use modulus, always stops on factors of 10
}

As for your other problem with accessing the bitmap, can you please provide instructions as to how I can recreate the exception.

Regards
GavH  Thursday, December 28, 2006 11:12 AM
Hi VishalR,

Your problem most likely relates to objects not being correctly disposed, for example it is possible that you are trying to restablish a connection to a capture device that has never been closed. Most capture devices only have one output stream, and attempting to connect multiple times will produce errors.

Underlying DirectShow is a lot of COM interop, and those COM objects need to be explicitly destroyed.

When you say that you are opening and closing the capture window to capture frames, this does not sound like a good way of capturing frames, however it is possible that I misunderstand you.

Do you simply want to capture occasional frames with no interest in displaying the video?

Regards




GavH  Thursday, December 28, 2006 11:28 AM

Thanks for Reply...
I'm sending sample of my project to you through Email.
Its works fine first time with form MW and successfully capturing Image and sending back that image to form2. But Problem occurs when second time I press the Button1 on form2.
Debuger showing me error on line number 1463 of Capture.cs
this time hr value is -2147024809 and my camera is still on.
Hopefully u can help me to come out of this. Thanks in advance...

-VishalR

VishalR  Saturday, December 30, 2006 2:11 PM

Hi GavH,

Thanks for your respond. I can see now that my 1st question (from previous problem) is my silly mistake. Sorry for that. However, I still confuse and blur about the second problem. Can you please explain detail about what did you mean by "recreate the exception"? Thanks.

shuhada  Tuesday, January 02, 2007 3:03 PM

You can use google to search for other answers

Custom Search

More Threads

• MeasureString Disagrees with MouseEventArgs.X
• ShowWindow and Internet Explorer
• Hard Drives
• Cloning retuns null
• ListBox Double click on selected item C#
• RichTextBox & WM_PASTE
• DrawToBitmap on hidden controls
• ListViewItemSorter stops working after introducing groups?
• Populating controls from a ListView
• SelectedRow in DataGridView