giovedì 30 maggio 2013

How TO: C# internal WEB CAM r2

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.

Nessun commento: