Ho capito, se devo dirti la verità sono un po confuso, perchè è la prima volta che affronto questo tipo di linguaggi, ho iniziato a capire qualcosa col c++ e mi son dovuto trasportare di fretta sul c#..
Questa è una classe che mi serve (scopiazzata dal file di esempio delle directshow.net, ma lì veniva inglobata direttamente dentro un form) per catturare l'immagine da una webcam.
Come parametri fornisco l'handle del controllo (esempio panel.handle) e un indice che corrisponde alla webcam rilevata da dsdevice.
Allora io per adesso ce l'ho così:
File webcam.cs (file di classe separato)
codice:
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Runtime.InteropServices.ComTypes;
using DirectShowLib;
namespace Jarvis
{
internal class webcam: IDisposable
{
public void Dispose()
{
GC.SuppressFinalize(this);
CloseInterfaces();
}
~webcam()
{
CloseInterfaces();
}
public string DeviceName, DevicePath;
// Application-defined message to notify app of filtergraph events
public const int WM_GRAPHNOTIFY = 0x8000 + 1;
IVideoWindow videoWindow = null;
IMediaControl mediaControl = null;
IMediaEventEx mediaEventEx = null;
IGraphBuilder graphBuilder = null;
ICaptureGraphBuilder2 captureGraphBuilder = null;
DsROTEntry rot = null;
public void CaptureVideo(IntPtr customhandle, int index_device)
{
int hr = 0;
IBaseFilter sourceFilter = null;
try
{
// Get DirectShow interfaces
GetInterfaces();
// Attach the filter graph to the capture graph
hr = this.captureGraphBuilder.SetFiltergraph(this.graphBuilder);
DsError.ThrowExceptionForHR(hr);
// Use the system device enumerator and class enumerator to find
// a video capture/preview device, such as a desktop USB video camera.
sourceFilter = FindCaptureDevice(index_device);
// Add Capture filter to our graph.
hr = this.graphBuilder.AddFilter(sourceFilter, "Video Capture");
DsError.ThrowExceptionForHR(hr);
// Render the preview pin on the video capture filter
// Use this instead of this.graphBuilder.RenderFile
hr = this.captureGraphBuilder.RenderStream(PinCategory.Preview, MediaType.Video, sourceFilter, null, null);
DsError.ThrowExceptionForHR(hr);
// Now that the filter has been added to the graph and we have
// rendered its stream, we can release this reference to the filter.
//
// Set video window style and position
SetupVideoWindow(customhandle);
// Add our graph to the running object table, which will allow
// the GraphEdit application to "spy" on our graph
rot = new DsROTEntry(this.graphBuilder);
// Start previewing video data
hr = this.mediaControl.Run();
DsError.ThrowExceptionForHR(hr);
}
catch
{
MessageBox.Show("An unrecoverable error has occurred.");
}
}
private void GetInterfaces()
{
// An exception is thrown if cast fail
this.graphBuilder = (IGraphBuilder)new FilterGraph();
this.captureGraphBuilder = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
this.mediaControl = (IMediaControl)this.graphBuilder;
this.videoWindow = (IVideoWindow)this.graphBuilder;
this.mediaEventEx = (IMediaEventEx)this.graphBuilder;
}
private IBaseFilter FindCaptureDevice(int index_device)
{
DsDevice[] devices;
object source;
// Get all video input devices
devices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
// Take the first device
DsDevice device = (DsDevice)devices[index_device];
DeviceName = device.Name;
DevicePath = device.DevicePath;
// Bind Moniker to a filter object
Guid iid = typeof(IBaseFilter).GUID;
device.Mon.BindToObject(null, null, ref iid, out source);
// An exception is thrown if cast fail
return (IBaseFilter)source;
}
public void SetupVideoWindow(IntPtr customhandle)
{
int hr = 0;
// Set the video window to be a child of the main window
hr = this.videoWindow.put_Owner(customhandle);
DsError.ThrowExceptionForHR(hr);
hr = this.videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren);
DsError.ThrowExceptionForHR(hr);
// Resize the video preview window to match owner window size
if (this.videoWindow != null)
{
this.videoWindow.SetWindowPosition(0, 0, 200, 200);
}
// Make the video window visible, now that it is properly positioned
hr = this.videoWindow.put_Visible(OABool.True);
DsError.ThrowExceptionForHR(hr);
}
public void CloseInterfaces()
{
// Stop previewing data
if (this.mediaControl != null)
this.mediaControl.StopWhenReady();
// Stop receiving events
if (this.mediaEventEx != null)
this.mediaEventEx.SetNotifyWindow(IntPtr.Zero, WM_GRAPHNOTIFY, IntPtr.Zero);
// Relinquish ownership (IMPORTANT!) of the video window.
// Failing to call put_Owner can lead to assert failures within
// the video renderer, as it still assumes that it has a valid
// parent window.
if (this.videoWindow != null)
{
this.videoWindow.put_Visible(OABool.False);
this.videoWindow.put_Owner(IntPtr.Zero);
}
// Remove filter graph from the running object table
if (rot != null)
{
rot.Dispose();
}
//aggiunto da me
//Marshal.ReleaseComObject(sourceFilter);
}
}
}
Per adesso se mi date una mano a capire, che cosa ho combinato.. vi direi grazie mille!!
Dubbi:
- Cosa mi cambia tra indicare private, public o internal prima del nomeclasse? Solitamente non metto mai nulla lascio solo "class nomeclasse { .. "
- In questo modo ovviamente per distruggere l'oggetto, chiamo "Dispose()" all'interno del dispose del form, in modo che quando chiude il form mi distrugge anche le risorse della classe, volendo potrei comunque metterlo sull'evento "onClosing" del form.
- Ci sono sicuramente parti superflue di codice, perché dall'esempio ho cercato di eliminare parti del codice per semplificare questa classe..
Questa è la versione originale dell'esempio da cui ho copiato