Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Drawing
Imports System.Linq
Imports System.Text
Imports System.Windows.Forms
Imports System.Math

Imports Emgu.CV.UI
Imports Emgu.CV
Imports Emgu.CV.Structure
Imports Emgu.CV.CvEnum

Imports DirectShowLib
Imports System.Runtime.InteropServices

Public Class frmVideo
 
    Delegate Sub DelegateVideoStart()
    Public Sub subVideoStart() Handles Me.Load
        Try
            If Me.InvokeRequired Then
                Dim newDelegate As New DelegateVideoStart(AddressOf subVideoStart)
                Me.Invoke(newDelegate, New Object() {})
            Else
                If Not boolVideoStarted Then
                    Me.Visible = boolEnableFaceRecognition Or boolEnableVideo
                    strStatusDriving = "Starting Video  "
                    subPopulateCameraList()
                    If (mnuVidSelectComboBox.Items.Item(intVideoSource) Is Nothing) Then intVideoSource = 0
                    If (mnuVidSelectComboBox.Items.Item(intVideoSource) IsNot Nothing) Then
                        mnuVidSelectComboBox.SelectedIndex = intVideoSource
                        subConfigureMenu()
                        If Not boolTrained Then boolTrained = modFaceRecognition.ftnFaceRecognitionLoad()
                        If boolTrained And boolEnableFaceRecognition Then
                            message_bar1.Text = "Training Data loaded"
                        ElseIf boolEnableFaceRecognition Then
                            message_bar1.Text = "No training data found, please train program using Train menu option"
                        End If
                        If boolEnableFaceRecognition Or boolEnableVideo Then
                            subInitializeCapture()
                        Else
                            subStopCapture()
                        End If
                        boolVideoStarted = True
                    ElseIf (mnuVidSelectComboBox.Items.Item(intVideoSource) Is Nothing) Then
                        message_bar1.Text = "Please select a camera"
                    End If
                End If
            End If
        Catch ex As Exception
            message_bar1.Text = "Please select a camera"
            frmDebug.subWriteLogs(" EXCEPTION in subVideoStart :  " & ex.ToString)
        End Try
    End Sub


    Sub exitToolStripMenuItem_Click() Handles exitToolStripMenuItem4.Click
        Me.Close()
    End Sub

    Sub subVideoExit() Handles Me.FormClosing
        Try
            boolEnableFaceRecognition = False
            boolEnableVideo = False
            frmGotABotTop.mnuFaceRecognition.Checked = False
            frmGotABotTop.mnuVideo.Checked = False
            subStopCapture()
            boolVideoStarted = False
        Catch ex As Exception
            frmDebug.subWriteLogs(" EXCEPTION in subVideoExit :  " & ex.ToString)
        End Try
    End Sub

  
    Private Sub mnuVidSelectComboBox_Click(sender As Object, e As EventArgs) Handles mnuVidSelectComboBox.Click
        Try
            mnuVidSelectComboBox.Items.Clear()
            subPopulateCameraList()
        Catch ex As Exception
            frmDebug.subWriteLogs(" EXCEPTION in mnuVidSelectComboBox_Click :  " & ex.ToString)
        End Try
    End Sub

    Private Sub VidSelectComboBox1_Change(sender As System.Object, e As System.EventArgs) Handles mnuVidSelectComboBox.TextChanged
        Try
            If mnuVidSelectComboBox.Focused And (boolEnableFaceRecognition Or boolEnableVideo) Then
                intVideoSource = Val(mnuVidSelectComboBox.SelectedIndex)
                mnuVidSelectComboBox.Text = "Video Device : " & mnuVidSelectComboBox.Items.Item(intVideoSource).ToString
                message_bar1.Text = "Video Device : " & mnuVidSelectComboBox.Items.Item(intVideoSource).ToString
                boolSettingsChanged = True
                subInitializeCapture()
                Me.mnuCamera.HideDropDown()
            End If
        Catch ex As Exception
            frmDebug.subWriteLogs(" EXCEPTION in VidSelectComboBox1_Change :  " & ex.ToString)
        End Try
    End Sub


    Private Sub mnuResolutionSelectComboBox_Click(sender As Object, e As EventArgs) Handles mnuResolutionSelectComboBox.TextChanged
        Try
            If mnuResolutionSelectComboBox.Focused Then
                Dim intResolutionSelected As Integer = Val(mnuResolutionSelectComboBox.SelectedIndex)
                If mnuResolutionSelectComboBox.Items.Item(intResolutionSelected) IsNot Nothing Then
                    Dim strResolution As String = mnuResolutionSelectComboBox.Items.Item(intResolutionSelected)
                    Dim strParsedText As String() = strResolution.Split("x"c)
                    ticCameraResolution.X = Convert.ToInt16(strParsedText(0))
                    ticCameraResolution.Y = Convert.ToInt16(strParsedText(1))
                    subInitializeCapture()
                    boolSettingsChanged = True
                    subConfigureMenu()
                    mnuCamera.ShowDropDown()
                End If
            End If
        Catch ex As Exception
            frmDebug.subWriteLogs(" EXCEPTION in mnuResolutionSelectComboBox_Click :  " & ex.ToString)
        End Try
    End Sub

    Sub subPopulateCameraList()
        Try
            'Dim ListCamerasData As New List(Of KeyValuePair(Of Integer, String))()    'Find systems cameras with DirectShow.Net dll 
            Dim _SystemCameras As DsDevice() = DsDevice.GetDevicesOfCat(DirectShowLib.FilterCategory.VideoInputDevice)
            Dim _DeviceIndex As Integer = 0
            For Each _Camera As DirectShowLib.DsDevice In _SystemCameras
                mnuVidSelectComboBox.Items.Add(New KeyValuePair(Of Integer, String)(_DeviceIndex, _Camera.Name))
                _DeviceIndex += 1
            Next
            Dim listAvailableResolutions As List(Of String) = ftnGetAllAvailableResolution(_SystemCameras(intVideoSource))
            mnuResolutionSelectComboBox.Items.Clear()
            For Each strResolution As String In listAvailableResolutions
                mnuResolutionSelectComboBox.Items.Add(strResolution)
            Next

        Catch ex As Exception
            frmDebug.subWriteLogs(" EXCEPTION in subPopulateCameraList :  " & ex.ToString)
        End Try
    End Sub


    Sub subInitializeCapture()
        Try
            subStopCapture()
            If boolEnableFaceRecognition Or boolEnableVideo And (mnuVidSelectComboBox.Items.Item(intVideoSource) IsNot Nothing) Then
                grabber = New Capture(intVideoSource)
                subWait(25)
                grabber.QueryFrame()
                subWait(25)
                grabber.SetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FRAME_HEIGHT, ticCameraResolution.Y) ' 
                subWait(25)
                grabber.SetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FRAME_WIDTH, ticCameraResolution.X) ' 
                subWait(25)
                grabber.QueryFrame()
                AddHandler Application.Idle, AddressOf FrameGrabber
            ElseIf (mnuVidSelectComboBox.Items.Item(intVideoSource) Is Nothing) Then
                message_bar1.Text = "Please select a camera"
            End If
        Catch ex As Exception
            frmDebug.subWriteLogs(" EXCEPTION in subInitializeCapture :  " & ex.ToString)
        End Try
    End Sub

    Private Sub subStopCapture()
        RemoveHandler Application.Idle, AddressOf FrameGrabber
        subWait(100)
        If grabber IsNot Nothing Then grabber.Dispose()
    End Sub

    Private grabber As Capture
    Dim boolFrameGrabberIsBusy As Boolean = False
    Sub FrameGrabber(sender As Object, e As EventArgs)
        Try
            If boolEnableVideo And boolVideoStarted And Not boolFrameGrabberIsBusy Then
                boolFrameGrabberIsBusy = True
                Dim currentFrame As Image(Of Bgr, [Byte]) = grabber.QueryFrame()    'Get the current frame from capture device
                If boolEnableFaceRecognition And currentFrame IsNot Nothing Then subFaceRecognition(currentFrame)
                Me.picVideo.Image = currentFrame.ToBitmap()

                boolFrameGrabberIsBusy = False
            End If
        Catch ex As Exception
            subInitializeCapture()
            boolFrameGrabberIsBusy = False
            frmDebug.subWriteLogs(" EXCEPTION in FrameGrabber :  " & ex.ToString)
        End Try
    End Sub


 

    Private Sub FieldOfViewToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles mnuFOV.Click
        Try
            Dim strCameraFOV As String
            Dim sngDiagonalFOV As Single = Sqrt(sngCameraFOV ^ 2 + (sngCameraFOV * ticCameraResolution.Y / ticCameraResolution.X) ^ 2)
            strCameraFOV = InputBox("Enter Camera Diagonal Field Of View ", "Camera FOV", Str(sngDiagonalFOV))
            If strCameraFOV <> "" And IsNumeric(strCameraFOV) Then
                sngCameraFOV = Convert.ToSingle(strCameraFOV) * ticCameraResolution.X / Sqrt(ticCameraResolution.X ^ 2 + ticCameraResolution.Y ^ 2)
            End If
            boolSettingsChanged = True
            subConfigureMenu()
            mnuCamera.ShowDropDown()
        Catch ex As Exception
            frmDebug.subWriteLogs(" EXCEPTION in FieldOfViewToolStripMenuItem_Click :  " & ex.ToString)
        End Try
    End Sub



    Private Sub mnuEnableFaceRecognition_Click(sender As Object, e As EventArgs) Handles mnuEnableFaceRecognition.Click
        Try
            boolEnableFaceRecognition = Not boolEnableFaceRecognition
            mnuEnableFaceRecognition.Checked = boolEnableFaceRecognition
        Catch ex As Exception
            frmDebug.subWriteLogs(" EXCEPTION in mnuEnableFaceRecognition_Click :  " & ex.ToString)
        End Try
    End Sub


    Private Sub mnuTrainPhoto_Click(sender As Object, e As EventArgs) Handles mnuTrainPhoto.Click
        strPersonName = LCase(InputBox("What is the person's name ", "Name", strPersonName))
        subTrainPhoto()
    End Sub


    Private Sub mnuTrainWebcam_Click(sender As Object, e As EventArgs) Handles mnuTrainWebcam.Click
        strPersonName = LCase(InputBox("What is the person's name ", "Name", strPersonName))
        subTrainWebcam()
    End Sub

    Function ftnGetAllAvailableResolution(ByVal vidDev As DsDevice) As List(Of String)
        Try
            Dim hr As Integer, bitCount As Integer = 0
            Dim sourceFilter As IBaseFilter = Nothing
            Dim m_FilterGraph2 = TryCast(New FilterGraph(), IFilterGraph2)
            hr = m_FilterGraph2.AddSourceFilterForMoniker(vidDev.Mon, Nothing, vidDev.Name, sourceFilter)
            Dim pRaw2 = DsFindPin.ByCategory(sourceFilter, PinCategory.Capture, 0)
            Dim AvailableResolutions = New List(Of String)()
            Dim v As VideoInfoHeader = New VideoInfoHeader()
            Dim mediaTypeEnum As IEnumMediaTypes
            Dim mediaTypes As AMMediaType() = New AMMediaType(0) {}
            hr = pRaw2.EnumMediaTypes(mediaTypeEnum)
            Dim fetched As IntPtr = IntPtr.Zero
            hr = mediaTypeEnum.[Next](1, mediaTypes, fetched)
            'While fetched IsNot Nothing AndAlso mediaTypes(0) IsNot Nothing
            While mediaTypes(0) IsNot Nothing
                Marshal.PtrToStructure(mediaTypes(0).formatPtr, v)
                If v.BmiHeader.Size <> 0 AndAlso v.BmiHeader.BitCount <> 0 Then
                    If v.BmiHeader.BitCount > bitCount Then
                        AvailableResolutions.Clear()
                        bitCount = v.BmiHeader.BitCount
                    ElseIf v.BmiHeader.BitCount = bitCount Then
                        AvailableResolutions.Add(v.BmiHeader.Width & "x" & v.BmiHeader.Height)
                    Else
                        Dim a As Integer = 3
                    End If
                End If
                hr = mediaTypeEnum.[Next](1, mediaTypes, fetched)
            End While

            Return AvailableResolutions
        Catch ex As Exception
            frmDebug.subWriteLogs(" EXCEPTION in ftnGetAllAvailableResolution :  " & ex.ToString)
            Return New List(Of String)()
        End Try
    End Function

    Private Sub mnuCameraOffsetDegrees_Click(sender As Object, e As EventArgs) Handles mnuCameraOffsetDegrees.Click
        Try
            Dim strCameraOffset As String = InputBox("Enter Camera Offset in degrees ", "Camera Offset", Str(sngCameraOffsetDegrees))
            If strCameraOffset <> "" And IsNumeric(strCameraOffset) Then
                sngCameraOffsetDegrees = Convert.ToSingle(strCameraOffset)
            End If
            boolSettingsChanged = True
            subConfigureMenu()
            mnuCamera.ShowDropDown()
        Catch ex As Exception
            frmDebug.subWriteLogs(" EXCEPTION in mnuCameraOffsetDegrees_Click :  " & ex.ToString)
        End Try
    End Sub

    Private Sub subConfigureMenu()
        Try
            mnuVidSelectComboBox.Text = mnuVidSelectComboBox.Items.Item(intVideoSource).ToString
            mnuResolutionSelectComboBox.Text = Str(ticCameraResolution.X) & "x" & Str(ticCameraResolution.Y)
            mnuFOV.Text = "Camera FOV                 (" & FormatNumber(sngCameraFOV * Sqrt(ticCameraResolution.X ^ 2 + ticCameraResolution.Y ^ 2) / ticCameraResolution.X, 1) & ")"
            mnuCameraOffsetDegrees.Text = "Camera Offset Degrees   (" & sngCameraOffsetDegrees & ")"
        Catch ex As Exception
            frmDebug.subWriteLogs(" EXCEPTION in subConfigureMenu :  " & ex.ToString)
        End Try
    End Sub


End Class