
Imports System
Imports System.Threading

Imports AForge
Imports AForge.Video
Imports AForge.Video.DirectShow

Public Class Camera : Implements IDisposable

    Private WithEvents device As VideoCaptureDevice
    Public Property FrameSize As Size
    Private frameReady As ManualResetEvent
    Private frame As Bitmap

    Public Sub New(ByVal device As VideoCaptureDevice)
        Me.device = device
        Me.FrameSize = Me.getFrameSizes().First()
    End Sub

    Public Sub New(ByVal moniker As String)
        Me.device = New VideoCaptureDevice(moniker)
        Me.FrameSize = Me.getFrameSizes().First()

        '-- Planet13
        'Hier wird keine Einstellung getroffen aus Performancegründen!
        'Die Defaultauflösung und Framerate ist am schnellsten!
        'Me.device.DesiredFrameSize = Me.FrameSize
        'Me.device.DesiredFrameRate = framerate
    End Sub

    Public Sub New(ByVal moniker As String, framesize As Size, framerate As Integer)
        Me.device = New VideoCaptureDevice(moniker)
        Me.FrameSize = framesize

        '-- Planet13
        'Hier wird keine Einstellung getroffen aus Performancegründen!
        'Die Defaultauflösung und framerate ist am schnellsten!
        'Me.device.DesiredFrameSize = Me.FrameSize
        'Me.device.DesiredFrameRate = framerate
    End Sub

    Public Sub start()
        Me.device.Start()
    End Sub

    Public Sub [stop]()
        Me.device.SignalToStop()
        Me.device.WaitForStop()
        If Me.frameReady IsNot Nothing Then Me.frameReady.Close()
        RemoveHandler Me.device.NewFrame, AddressOf Me.newFrame
    End Sub

    Public Function getDevice() As VideoCaptureDevice
        Return Me.device
    End Function

    Public Function getFrame() As Bitmap
        Dim b As Bitmap = Nothing
        If Me.device.IsRunning Then
            Me.frameReady = New ManualResetEvent(False)

            AddHandler Me.device.NewFrame, AddressOf Me.newFrame

            If Me.frameReady.WaitOne(8000) Then
                b = Me.frame
            End If

            RemoveHandler Me.device.NewFrame, AddressOf Me.newFrame

        End If
        Return b
    End Function

    Private Sub newFrame(ByVal sender As Object, ByVal eventArgs As NewFrameEventArgs)
        Me.frame = eventArgs.Frame.Clone()
        Me.frameReady.Set()
    End Sub

    Public Function GetInfo() As String
        Dim s As String = ""
        For Each vc As VideoCapabilities In Me.device.VideoCapabilities
            s &= vc.FrameSize.Width & "x" & vc.FrameSize.Height & " @" & vc.FrameRate & "fps" & vbCrLf
        Next
        Return s
    End Function

    Public Function getFrameSizes() As Size()
        Dim videoCapabilities() As VideoCapabilities = Me.device.VideoCapabilities
        Dim frameSizes(videoCapabilities.Length - 1) As Size

        For i As Integer = 0 To videoCapabilities.Length - 1
            frameSizes(i) = videoCapabilities(i).FrameSize
        Next

        Return frameSizes
    End Function

    Public Shared Function getDevices() As Dictionary(Of String, String)
        Dim d As New Dictionary(Of String, String)
        Dim videoDevices As New FilterInfoCollection(FilterCategory.VideoInputDevice)
        For Each fi As FilterInfo In videoDevices
            d.Add(fi.MonikerString, fi.Name)
        Next
        Return d
    End Function

    Protected Overrides Sub Finalize()
        Try
            Me.Dispose()
        Finally
            MyBase.Finalize()
        End Try
    End Sub

#Region "IDisposable Support"
    Private disposedValue As Boolean ' So ermitteln Sie überflüssige Aufrufe

    ' IDisposable
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' TODO: Verwalteten Zustand löschen (verwaltete Objekte).
                Me.stop()
            End If
            ' TODO: Nicht verwaltete Ressourcen (nicht verwaltete Objekte) freigeben und Finalize() unten überschreiben.
            ' TODO: Große Felder auf NULL festlegen.
        End If
        Me.disposedValue = True
    End Sub

    ' TODO: Finalize() nur überschreiben, wenn Dispose(ByVal disposing As Boolean) oben über Code zum Freigeben von nicht verwalteten Ressourcen verfügt.
    'Protected Overrides Sub Finalize()
    '    ' Ändern Sie diesen Code nicht. Fügen Sie oben in Dispose(ByVal disposing As Boolean) Bereinigungscode ein.
    '    Dispose(False)
    '    MyBase.Finalize()
    'End Sub

    ' Dieser Code wird von Visual Basic hinzugefügt, um das Dispose-Muster richtig zu implementieren.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Ändern Sie diesen Code nicht. Fügen Sie oben in Dispose(ByVal disposing As Boolean) Bereinigungscode ein.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

End Class
