Luigi Di Biasi


XP Programming Style
Sondaggio
Argomento Spider e WebCrawler

Interessante
Non interessante

Enumerare le periferiche video - DirectShow.NET

DirectShow.NET
"by SourceForge "

L'intendo di questa serie di post è quello di descrivere l'utilizzo della libreria DirectShow.NET in modo da poter accedere alle periferiche video senza dover programmare in C++. Chiaramente, usando DirectShow, ci poniamo come obbiettivo quello di superare le limitazioni della libreria avicap32.dll e quindi, di avere pieno controllo sulle nostre 'care' schede di acquisione.

La conoscenza di COM, di alcune strutture e di alcuni oggetti è comunque necessaria infatti anche se il linguaggio di programmazione sarà VB.net ( e quindi C# ) useremo una classe (DirectShow.NET) che farà da Wrap tra .NET e Win32. Cambierà solo il linguaggio ma la struttura degli esempi rimarrà la stessa di quelli visti nei post della sezione C++. (Per cui è necessaria comunque una panoramica su http://msdn.microsoft.com/en-us/library/dd375454(VS.85).aspx )

In realtà l'obbiettivo (finale) che cercheremo di raggiungere è più complesso...
Scriveremo una classe che ci semplifichi le operazioni base quale l'enumerazione, l'avvio del flusso, lo snapshot e altre piccole operazioni che altrimenti richiederebbero molte linee di codice. (da riscrivere ogni volta per ogni nuovo programma.. ma noi siamo furbi e ci creiamo la piccola DLL)

La classe, come detto, sarà un WRAP del WRAP  (perdonatemi l'abuso)... scarichiamo quindi directShow.NET da sourceforge, creiamo il nostro progetto Libreria DLL, aggiungiamo un riferimento alla DLL scaricata e siamo pronti per cominciare...

ENUMERAZIONE
L'enumerazione delle periferiche (a/v) della macchina avviene tramite COM e precisamente tramite il devices enumerator. 

Un piccolo appunto prima di continuare... quando si parla di enumerazione hardware l'oggetto utilizzato per rappresentare un apparato è il Moniker. E' bene fare riferimento a MSDN per capire la natura di questo oggetto. Per il momento vediamo il moniker come un oggetto che può assumere più forme ( può essere bindato su piu' interfacce).

Per usare COM all'interno di una classe .NET è necessario importare i namespaces:

Imports System.Runtime.InteropServices.ComTypes
Imports System.Runtime.InteropServices

Come detto vogliamo scrivere una classe che ci semplifichi le operazioni di base, prima fra tutte l'enumerazione delle periferiche nuda e cruda. Per fare questo abbiamo la necessità di interrogare il DeviceEnumerator, inseriamo quindi anche il riferimento al namespace 

Imports DirectShowLib

L'enumeratore ci restituirà una lista di Moniker... ma noi vogliamo anche una descrizione più umana (precisamente il nome riportato in Sistema->Periferiche di Imaging) e quindi siamo costretti a scrivere due funzioni.. una per recuperare la lista dei moniker e una per bindare i moniker ritornati in un oggetto detto PropertyBag (contenitore di proprietà) da cui leggere poi il nome umano della periferica.

Personalmente ho battezzato la classe che sto per scrivere Base_VideoUtilty con l'intendo di estenderla in Complex_VideoUtility in un futuro non precisato.. ma un nome vale l'altro...


Public Class Base_VideoUtilty

    ' Ritorna la lista delle periferiche di acquisizione disponibili come un dizionario Intero,Moniker ( per indicizzare le periferiche ) 
    Public Function Get_ListOfVideoAcquireHardware() As Dictionary(Of Integer, IMoniker)

        ' Enumeratore di Moniker di tipo VideoInputDevice
        Dim classEnum As IEnumMoniker = Nothing
        ' La lista che conterrà i moniker. Un Moniker è un oggetto che può essere bindato
        ' su un'interfaccia. 
        Dim moniker As IMoniker() = New IMoniker(0) {}
        ' L'enumeratore di Devices.. questo oggetto può enumerare i devices presenti nella macchina
        Dim devEnum As ICreateDevEnum = CType(New CreateDevEnum, ICreateDevEnum)

        Dim hr As Integer = 0
        ' Filtra tutti i video devices presenti nella macchina
        hr = devEnum.CreateClassEnumerator(FilterCategory.VideoInputDevice, classEnum, 0)
         If hr <> 0 Then
            Throw New Exception("return code from COM: " & hr)
        End If
        Marshal.ReleaseComObject(devEnum)

        ' Scorre la lista dei devices disponibili
        Dim MList As ArrayList = New ArrayList
        Dim EndOfMoniker As Integer
        While True
            EndOfMoniker = classEnum.Next(moniker.Length, moniker, IntPtr.Zero)
            If EndOfMoniker = 1 Then
                Exit While
            End If
            MList.Add(moniker(0))
        End While

        ' Genera la lista da ritornare
        Dim toReturn As Dictionary(Of Integer, IMoniker) = New Dictionary(Of Integer, IMoniker)
        Dim it As IMoniker
        Dim k As Integer = 0
        For Each it In MList
            toReturn.Add(k, it)
            k += 1
        Next it

        MList.Clear() : MList = Nothing
        it = Nothing

        ' Puliamo un pò la memoria

        Marshal.ReleaseComObject(classEnum)
        GC.Collect()

        Return toReturn

    End Function

    ' Ritorna la descrizione UMANA delle periferiche di acquisizone disponibili.
    ' Richiede come parametro una lista di IMoniker. Utilizza l'intefaccia IPropertyBag
    Public Function Get_FriendlyListOfVideoAcquireHardware(ByRef IMonikerList As Dictionary(Of Integer, IMoniker)) As Dictionary(Of Integer, String)

        Dim IProp As IPropertyBag = Nothing
        Dim toReturn As Dictionary(Of Integer, String) = New Dictionary(Of Integer, String)

        ' Le proprietà che intendiamo leggere
        Dim FName As String = Nothing

        Dim it As KeyValuePair(Of Integer, IMoniker)
        For Each it In IMonikerList
            it.Value.BindToStorage(Nothing, Nothing, GetType(IPropertyBag).GUID, IProp)
           ' Legge il nome UMANO della periferica!!! 
   IProp.Read("FriendlyName", FName, Nothing)
            toReturn.Add(it.Key, FName)
        Next it

        Marshal.ReleaseComObject(IProp)

        Return toReturn

    End Function

End Class


Se abbiamo una cam installata possiamo provare la bontà del codice in una form 

' Istanziamo la nostra classe

Dim myB As Base_VideoUtilty = New Base_VideoUtilty()
       
        ' Leggiamo la lista delle periferiche e ne estraiamo il nome umano
 Dim t As Dictionary(Of Integer, String) = myB.Get_FriendlyListOfVideoAcquireHardware(myB.Get_ListOfVideoAcquireHardware())

' scorriamo la lista delle periferiche e la aggiungiamo ad una listbox
        Dim j As KeyValuePair(Of Integer, String)
        For Each j In t
            listaPeriferiche.Items.Add(j.Key & " " & j.Value)
        Next j

Nel prossimo post vedremo come scrivere una funzione che prenda il flusso video e lo avvii in un oggetto dotato di handle (una form, una picture box , una textbox o qualsiasi oggetto generato dalla api CreateWindowEx)

Vai al prossimo post >> 

giovedì, 11 giu 2009 Ore. 22.37
Statistiche
  • Views Home Page: 25.882
  • Views Posts: 49.736
  • Views Gallerie: 0
  • n° Posts: 41
  • n° Commenti: 33
Archivio Posts
Anno 2012

Anno 2011

Anno 2010

Anno 2009

Anno 2008
Copyright © 2002-2007 - Blogs 2.0
dotNetHell.it | Home Page Blogs
ASP.NET 2.0 Windows 2003