La prima versione mi è piaciuta ma onestamente non mi ha soddisfatto, perchè il sorgente era strettamente legato al form, oggi con un filo di calma in più ( giocandomi la pausa ) sono riuscito a migliorare il tutto e il gioco sta nel come gestire le cose.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace CameraCapture.Objects
{
public class HandledObject
{
public int width;
public int height;
public Size clientSize;
public IntPtr handle;
}
}
Questo primo oggetto mi serve come tramite per la gestiione dell'Handle... quasi mi sembra di tornare ai fasti delle API a 32bit.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CameraCapture.Objects
{
public enum PlayState
{
Stopped,
Paused,
Running,
Init
}
}
Questo è rimasto invariato.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DirectShowLib;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace CameraCapture.Objects
{
public class DirectShowWrapper
{
public int D = Convert.ToInt32("0X8000", 16);
public int WM_GRAPHNOTIFY = 0;
public IVideoWindow VideoWindow = null;
public IMediaControl MediaControl = null;
public IMediaEventEx MediaEventEx = null;
public IGraphBuilder GraphBuilder = null;
public ICaptureGraphBuilder2 CaptureGraphBuilder = null;
public DsROTEntry rot = null;
private PlayState CurrentState = PlayState.Stopped;
public DirectShowWrapper()
{
WM_GRAPHNOTIFY = D + 1;
}
public void GetInterfaces(HandledObject f)
{
int hr = 0;
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);
hr = this.MediaEventEx.SetNotifyWindow(f.handle,
WM_GRAPHNOTIFY,
IntPtr.Zero);
}
public void CaptureVideo(HandledObject f)
{
int hr = 0;
IBaseFilter sourceFilter = null;
try
{
GetInterfaces(f);
hr = this.CaptureGraphBuilder.SetFiltergraph(this.GraphBuilder);
sourceFilter = FindCaptureDevice();
hr = this.GraphBuilder.AddFilter(sourceFilter, "Video Capture");
hr = this.CaptureGraphBuilder.RenderStream(PinCategory.Preview,
MediaType.Video,
sourceFilter,
null, null);
Marshal.ReleaseComObject(sourceFilter);
SetupVideoWindow(f);
rot = new DsROTEntry(this.GraphBuilder);
hr = this.MediaControl.Run();
this.CurrentState = PlayState.Running;
}
catch (Exception ex)
{
}
}
public void SetupVideoWindow(HandledObject f)
{
int hr = 0;
hr = VideoWindow.put_Owner(f.handle);
hr = VideoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren);
ResizeVideoWindow(f);
hr = VideoWindow.put_Visible(OABool.True);
}
public void closeinterfaces()
{
if (this.MediaControl != null)
{
this.MediaControl.StopWhenReady();
}
this.CurrentState = PlayState.Stopped;
if (this.MediaEventEx != null)
{
this.MediaEventEx.SetNotifyWindow(IntPtr.Zero,
WM_GRAPHNOTIFY,
IntPtr.Zero);
}
if (this.VideoWindow != null)
{
this.VideoWindow.put_Visible(OABool.False);
this.VideoWindow.put_Owner(IntPtr.Zero);
}
if (rot != null)
{
rot.Dispose();
rot = null;
}
Marshal.ReleaseComObject(this.MediaControl);
Marshal.ReleaseComObject(this.MediaEventEx);
Marshal.ReleaseComObject(this.VideoWindow);
Marshal.ReleaseComObject(this.GraphBuilder);
Marshal.ReleaseComObject(this.CaptureGraphBuilder);
this.MediaControl = null;
this.MediaEventEx = null;
this.VideoWindow = null;
this.CaptureGraphBuilder = null;
this.GraphBuilder = null;
}
public void HandleGraphEvent()
{
int hr = 0;
EventCode evCode;
int evParam1;
int evParam2;
if (MediaEventEx == null)
{
return;
}
while (MediaEventEx.GetEvent(out evCode, out evParam1, out evParam2, 0) == 0)
{
hr = MediaEventEx.FreeEventParams(evCode, evParam1, evParam2);
}
}
public IBaseFilter FindCaptureDevice()
{
int hr = 0;
IEnumMoniker IclassEnum;
System.Runtime.InteropServices.UCOMIEnumMoniker classEnum;
IMoniker[] moniker = new IMoniker[1];
Object source = null;
ICreateDevEnum devEnum = (ICreateDevEnum)(new CreateDevEnum());
hr = devEnum.CreateClassEnumerator(FilterCategory.VideoInputDevice,
out classEnum, 0);
IclassEnum = (IEnumMoniker)(classEnum);
Marshal.ReleaseComObject(devEnum);
if (classEnum == null)
{
throw new ApplicationException("No device video on board.");
}
if (IclassEnum.Next(moniker.Length, moniker, IntPtr.Zero) == 0)
{
Guid iid = typeof(IBaseFilter).GUID;
moniker[0].BindToObject(null, null, iid, out source);
}
else
{
throw new ApplicationException("Unable to access video capture device!");
}
Marshal.ReleaseComObject(moniker[0]);
Marshal.ReleaseComObject(classEnum);
return (IBaseFilter)(source);
}
public void ChangePreviewState(bool showVideo)
{
int hr = 0;
if (this.MediaControl == null)
{
return;
}
if (showVideo == true)
{
if (this.CurrentState != PlayState.Running)
{
hr = this.MediaControl.Run();
this.CurrentState = PlayState.Running;
}
}
else
{
hr = this.MediaControl.StopWhenReady();
this.CurrentState = PlayState.Stopped;
}
}
public void ResizeVideoWindow(HandledObject ho)
{
if (VideoWindow != null)
{
VideoWindow.SetWindowPosition(0, 0, ho.width, ho.clientSize.Height);
}
}
}
}
Questo è l'oggetto che sostituisce e wrappa tutte le attività lasciando libero e snello il form.
Il motivo è semplice, in questo modo posso aggiungere una picturebox o qualsiasi altro oggetto per cui sussistano dimensioni e handle, mapparlo nell'oggetto di scambio, e gestire così la camera.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using DirectShowLib;
using System.Windows.Forms;
using CameraCapture.Objects;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace CameraCapture
{
public partial class frmMain : Form
{
DirectShowWrapper dsw = new DirectShowWrapper();
HandledObject ho = new HandledObject();
public frmMain()
{
InitializeComponent();
ho.height = this.Height;
ho.width = this.Width;
ho.handle = this.Handle;
ho.clientSize = this.ClientSize;
dsw.CaptureVideo(ho);
}
protected void WndProc(Message m)
{
if (m.Msg == dsw.WM_GRAPHNOTIFY)
{
dsw.HandleGraphEvent();
}
if (dsw.VideoWindow != null)
{
dsw.VideoWindow.NotifyOwnerMessage(
m.HWnd,
m.Msg,
(int)m.WParam,
(int)m.LParam);
}
else
{
base.WndProc(ref m);
}
}
private void frmMain_Resize(object sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Minimized)
dsw.ChangePreviewState(false);
if (this.WindowState == FormWindowState.Normal)
dsw.ChangePreviewState(true);
ho.height = this.Height;
ho.width = this.Width;
ho.handle = this.Handle;
ho.clientSize = this.ClientSize;
dsw.ResizeVideoWindow(ho);
}
public void frmMain_FormClosed(object sender, FormClosedEventArgs e)
{
dsw.closeinterfaces();
}
}
}
Orbene questo è quanto rimane del form ...ora la situazione è sicuramente molto più gestibile e pulita.