첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
728x90
반응형
728x170

TestProject.zip
다운로드

▶ CameraControl.cs

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

using DirectShowLib;

namespace TestProject
{
    /// <summary>
    /// 카메라 컨트롤
    /// </summary>
    [Guid("43878F19-1E0E-42d2-B72B-88A94418A302")]
    [ComVisible(true)]
    public partial class CameraControl : UserControl
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// WM_GRAPHNOTIFY
        /// </summary>
        private int WM_GRAPHNOTIFY = Convert.ToInt32("0X8000", 16) + 1;

        /// <summary>
        /// 비디오 윈도우
        /// </summary>
        private IVideoWindow vidoeWindow = null;

        /// <summary>
        /// 미디어 컨트롤
        /// </summary>
        private IMediaControl mediaControl = null;

        /// <summary>
        /// 미디어 이벤트 확장
        /// </summary>
        private IMediaEventEx mediaEventEx = null;

        /// <summary>
        /// 그래프 빌더
        /// </summary>
        private IGraphBuilder graphBuilder = null;

        /// <summary>
        /// 캡처 그래프 빌더 2
        /// </summary>
        private ICaptureGraphBuilder2 captureGraphBuilder2 = null;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - CameraControl()

        /// <summary>
        /// 생성자
        /// </summary>
        public CameraControl()
        {
            InitializeComponent();

            Load += UserControl_Load;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Protected
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 윈도우 프로시저 처리하기 - WndProc(message)

        /// <summary>
        /// 윈도우 프로시저 처리하기
        /// </summary>
        /// <param name="message">메시지</param>
        protected override void WndProc(ref Message message)
        {
            if(message.Msg == WM_GRAPHNOTIFY)
            {
                HandleGraphEvent();
            }

            if(this.vidoeWindow != null)
            {
                this.vidoeWindow.NotifyOwnerMessage
                (
                    message.HWnd            ,
                    message.Msg             ,
                    message.WParam.ToInt32(),
                    message.LParam.ToInt32()
                );
            }

            base.WndProc(ref message);
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Private
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 사용자 컨트롤 로드시 처리하기 - UserControl_Load(sender, e)

        /// <summary>
        /// 사용자컨트롤 로드시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void UserControl_Load(object sender, EventArgs e)
        {
            Resize += UserControl_Resize;
        }

        #endregion
        #region 사용자 컨트롤 크기 변경시 처리하기 - Control_Resize(sender, e)

        /// <summary>
        /// 사용자 컨트롤 크기 변경시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void UserControl_Resize(object sender, EventArgs e)
        {
            if(this.vidoeWindow != null)
            {
                this.vidoeWindow.SetWindowPosition(0, 0, Width, ClientSize.Height);
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Function

        #region 인터페이스 설정하기 - SetInterfaces()

        /// <summary>
        /// 인터페이스 설정하기
        /// </summary>
        private void SetInterfaces()
        {
            this.graphBuilder         = (IGraphBuilder)(new FilterGraph());
            this.captureGraphBuilder2 = (ICaptureGraphBuilder2)(new CaptureGraphBuilder2());
            this.mediaControl         = (IMediaControl)this.graphBuilder;
            this.vidoeWindow          = (IVideoWindow)this.graphBuilder;
            this.mediaEventEx         = (IMediaEventEx)this.graphBuilder;

            int resultHandle = this.mediaEventEx.SetNotifyWindow(Handle, WM_GRAPHNOTIFY, IntPtr.Zero);

            DsError.ThrowExceptionForHR(resultHandle);
        }

        #endregion
        #region 캡처 디바이스 찾기 - FindCaptureDevice()

        /// <summary>
        /// 캡처 디바이스 찾기
        /// </summary>
        /// <returns>베이스 필터 인터페이스</returns>
        private IBaseFilter FindCaptureDevice()
        {
            UCOMIEnumMoniker ucomIEnumMoniker  = null;
            UCOMIMoniker[]   uconIMonikerArray = new UCOMIMoniker[1];
            object           source            = null;
            ICreateDevEnum   createDevEnum     = (ICreateDevEnum)(new CreateDevEnum());
            int              resultHandle      = createDevEnum.CreateClassEnumerator(FilterCategory.VideoInputDevice, out ucomIEnumMoniker, CDef.None);

            DsError.ThrowExceptionForHR(resultHandle);

            Marshal.ReleaseComObject(createDevEnum);

            if(ucomIEnumMoniker == null)
            {
                throw new ApplicationException
                (
                     "No video capture device was detected.\\r\\n\\r\\n" +
                     "This sample requires a video capture device, such as a USB WebCam,\\r\\n" +
                     "to be installed and working properly. The sample will now close."
                );
            }

            int none = 0;
            
            if(ucomIEnumMoniker.Next(uconIMonikerArray.Length, uconIMonikerArray, out none) == 0)
            {
                Guid guid = typeof(IBaseFilter).GUID;

                uconIMonikerArray[0].BindToObject(null, null, ref guid, out source);
            }
            else
            {
                throw new ApplicationException("Unable to access video capture device!");
            }

            Marshal.ReleaseComObject(uconIMonikerArray[0]);

            Marshal.ReleaseComObject(ucomIEnumMoniker);

            return (IBaseFilter)source;
        }

        #endregion
        #region 비디오 윈도우 셋업하기 - SetupVideoWindow()

        /// <summary>
        /// 비디오 윈도우 셋업하기
        /// </summary>
        private void SetupVideoWindow()
        {
            int resultHandle = 0;

            resultHandle = this.vidoeWindow.put_Owner(Handle);

            DsError.ThrowExceptionForHR(resultHandle);

            resultHandle = this.vidoeWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren);

            DsError.ThrowExceptionForHR(resultHandle);

            UserControl_Resize(this, null);

            resultHandle = this.vidoeWindow.put_Visible(OABool.True);

            DsError.ThrowExceptionForHR(resultHandle);
        }

        #endregion
        #region 비디오 캡처하기 - CaptureVideo()

        /// <summary>
        /// 비디오 캡처하기
        /// </summary>
        public void CaptureVideo()
        {
            int resultHandle = 0;

            IBaseFilter sourceBaseFilter = null;

            try
            {
                SetInterfaces();

                resultHandle = this.captureGraphBuilder2.SetFiltergraph(this.graphBuilder);

                DsError.ThrowExceptionForHR(resultHandle);

                sourceBaseFilter = FindCaptureDevice();

                resultHandle = this.graphBuilder.AddFilter(sourceBaseFilter, "WebCamControl Video");

                DsError.ThrowExceptionForHR(resultHandle);
                
                resultHandle = this.captureGraphBuilder2.RenderStream
                (
                    PinCategory.Preview,
                    MediaType.Video,
                    sourceBaseFilter,
                    null,
                    null
                );

                Debug.WriteLine(DsError.GetErrorText(resultHandle));

                DsError.ThrowExceptionForHR(resultHandle);

                Marshal.ReleaseComObject(sourceBaseFilter);

                SetupVideoWindow();

                resultHandle = this.mediaControl.Run();

                DsError.ThrowExceptionForHR(resultHandle);
            }
            catch(Exception exception)
            {
                MessageBox.Show("An unrecoverable error has occurred.\r\n" + exception.ToString());
            }
        }

        #endregion
        #region 그래프 이벤트 처리하기 - HandleGraphEvent()

        /// <summary>
        /// 그래프 이벤트 처리하기
        /// </summary>
        private void HandleGraphEvent()
        {
            int       resultHandle    = 0;
            EventCode eventCode       = 0;
            int       eventParameter1 = 0;
            int       eventParameter2 = 0;

            while(this.mediaEventEx != null && this.mediaEventEx.GetEvent(out eventCode, out eventParameter1, out eventParameter2, 0) == 0)
            {
                resultHandle = this.mediaEventEx.FreeEventParams(eventCode, eventParameter1, eventParameter2);

                DsError.ThrowExceptionForHR(resultHandle);
            }
        }       

        #endregion
        #region 인터페이스 해제하기 - ReleaseInterfaces()

        /// <summary>
        /// 인터페이스 해제하기
        /// </summary>
        public void ReleaseInterfaces()
        {
            if(this.mediaControl != null)
            {
                this.mediaControl.StopWhenReady();
            }
            
            if(this.mediaEventEx != null)
            {
                this.mediaEventEx.SetNotifyWindow(IntPtr.Zero, WM_GRAPHNOTIFY, IntPtr.Zero);
            }
            
            if(this.vidoeWindow != null)
            {
                this.vidoeWindow.put_Visible(OABool.False);

                this.vidoeWindow.put_Owner(IntPtr.Zero);
            }
            
            Marshal.ReleaseComObject(this.mediaControl);

            this.mediaControl = null;

            Marshal.ReleaseComObject(this.mediaEventEx);

            this.mediaEventEx = null;

            Marshal.ReleaseComObject(this.vidoeWindow);

            this.vidoeWindow = null;

            Marshal.ReleaseComObject(this.graphBuilder);

            this.graphBuilder = null;

            Marshal.ReleaseComObject(this.captureGraphBuilder2);

            this.captureGraphBuilder2 = null;
        }

        #endregion
    }
}

 

728x90

 

▶ MainForm.cs

using System;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 메인 폼
    /// </summary>
    public partial class MainForm : Form
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainForm()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainForm()
        {
            InitializeComponent();
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Private
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 재생 버튼 클릭시 처리하기 - playButton_Click(sender, e)

        /// <summary>
        /// 재생 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void playButton_Click(object sender, EventArgs e)
        {
            if(this.playButton.Text == "캡처 시작")
            {
                this.playButton.Text = "캡처 종료";

                this.xWebCamControl.CaptureVideo();
            }
            else
            {
                this.playButton.Text = "캡처 시작";

                this.xWebCamControl.ReleaseInterfaces();
            }
        }

        #endregion
    }
}

※ 윈도우즈 7에서만 실행된다.

728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요