Luigi Di Biasi


XP Programming Style
Sondaggio
Argomento Spider e WebCrawler

Interessante
Non interessante

Visualizzare il flusso video ( e gestire la periferica )

Gestione della periferica 

La classe Base_VideoAcquireHardware

Nel post precedente siamo riusciti ad enumerare le periferiche video ed a crearci una lista indicizzata in cui ad ogni intero corrisponde un moniker. Le periferiche disponibili, quindi, saranno numerate da 0 in poi.

Adesso vogliamo crearci un oggetto che ci permetta di avviare e bloccare ( successivamente aggiungeremo metodi nuovi) il flusso video. Questo oggetto dovrà nascondere tutte le operazioni necessarie per la gestione della periferica e fornire solo i metodi che in realtà ci interessano, tra cui:

- Inizializzazione dell'hardware , StartVideo, StopVideo e DistruzioneHardware ( per rilasciarlo alle altre applicazioni ).

Come destinazione del flusso utilizzeremo un qualsiasi oggetto dotato di handle ( in realtà deve essere un oggetto di tipo Window (picturebox, form, etc..).

Classe Base_VideoAcquireHardware - Panoramica

Personalmente ho battezzato la classe Base_VideoAcquireHardware ma come sempre un nome vale l'altro.. In linea generale questa classe conterrà un riferimento al Moniker, un riferimento all'indice, gli oggetti DirectShow necessari per collegarsi alla periferica e alcuni metodi...

 - Costruttore new([arg]...): Inizializza l'hardware e gli oggetti DirectShow necessari.

- StartVideoOnHandle([arg]...) : Avvia la visualizzazione del flusso nell'oggetto che gli passeremo come parametro... Questa funzione può essere richiamata solo 1 volta finchè non viene richiamata la StopVideo...

- StopVideo():  Blocca momentaneamente il flusso..

- Dispose() : Distrugge gli oggetti DirectShow,libera la periferica e finalizza la classe.

- ResizeWindowOnHandle([arg]...) : Questa funzione và richiamata dal programma che utilizza la nostra classe. Quando si ridimensiona una picturebox,un form, o comunque l'oggetto dove stiamo visualizzando il video è necessario richiamarla per informare DirectShow e ridimensionare così anche la dimensione del video. (se avremo tempo cercheremo di far rilevare in automatico, alla classe, il resize dell'oggetto di destinazione)

Vediamo quindi come è definita la nostra classe:

Classe Base_VideoAcquireHardware - Implementazione VB.NET

 Public Class Base_VideoAcquireHardware

            ' Indice e riferimento all'oggetto COM che identifica l'hardware video
            Private DeviceID As Integer
            Private
Ref_Moniker As IMoniker
            Private DeviceDescription As String

            ' Oggetti DirectSHOW per l'utilizzo dell'hardware
            Private MyGraphBuilder As IGraphBuilder
            Private MyCaptureGraphBuilder As ICaptureGraphBuilder2
            Private MyWinDevice As IVideoWindow
            Private MyMediaControl As IMediaControl

            ' Oggetto IBaseFilter recuperato tramite il moniker. (Il moniker verrà bindato su questa classe per usarne i metodi)
            Private MyHardware As IBaseFilter

            ' Variabile per capire se è già rendered una periferica
            Private IsRender As Boolean = False
            Private
IsDisposed As Boolean = False

            'Il costruttore si occupa di inizializzare gli oggetti COM necessari.
            Public Sub New(ByVal HardwareIndex As Integer, ByRef HardwareMoniker As IMoniker)

                Dim ErrH As Integer

                ' Riferimenti BASE
                DeviceID = HardwareIndex
                Ref_Moniker = HardwareMoniker

                'Legge la descrizione
                Dim IProp As IPropertyBag = Nothing
                HardwareMoniker.BindToStorage(Nothing, Nothing, GetType(IPropertyBag).GUID, IProp)
                IProp.Read("FriendlyName", DeviceDescription, Nothing)

                ' Genera gli oggetti COM necessari per il funzionamento di DirectShow. Binda il Moniker
                ' in oggetto IBaseFilter. (Filtro di cui è possibile effettuare l'attach sul grafo Dshow)
                Dim source As Object = Nothing
                HardwareMoniker.BindToObject(Nothing, Nothing, GetType(IBaseFilter).GUID, source)
                MyHardware = CType(source, IBaseFilter)

                MyGraphBuilder = CType(New FilterGraph, IGraphBuilder)
                MyMediaControl = CType(MyGraphBuilder, IMediaControl)
                MyCaptureGraphBuilder = CType(New CaptureGraphBuilder2, ICaptureGraphBuilder2)
                MyWinDevice = CType(MyGraphBuilder, IVideoWindow)

                ' A questo punto l'oggetto è pronto per utilizzare la periferica video
                ' Effettua gli attach richiesti sul grafo
                ErrH = MyCaptureGraphBuilder.SetFiltergraph(MyGraphBuilder)
                DsError.ThrowExceptionForHR(ErrH)
                ErrH = MyGraphBuilder.AddFilter(MyHardware, "VideoAcquire_" & HardwareIndex)
                DsError.ThrowExceptionForHR(ErrH)

                ' Libera la memoria
                Marshal.ReleaseComObject(IProp)

            End Sub

 


            ' Questa funzione avvia il flusso video su un handle di finestra.
            ' I parametri 2 e 3 permettono di definire da dove acquisisire ( da quale PIN) e il tipo di MEDIA
            Public Sub StartVideoOnHandle(ByRef __dstHandle As System.IntPtr, ByVal PinType As DsGuid, ByVal MediaT As DsGuid)

                Dim ErrH As Integer
                If Me.IsDisposed Then
                    Throw New Exception("Questo oggetto è stato eliminato. E' necessario istanziare un nuovo oggetto.")
                End If
                If Not IsRender Then
                    ErrH = MyCaptureGraphBuilder.RenderStream(PinType, MediaT, MyHardware, Nothing, Nothing)
                    DsError.ThrowExceptionForHR(ErrH)
                    Marshal.ReleaseComObject(MyHardware)
                    IsRender = True
                End If

                ErrH = MyMediaControl.Run()
                DsError.ThrowExceptionForHR(ErrH)
                ErrH = MyWinDevice.put_Owner(__dstHandle)
                DsError.ThrowExceptionForHR(ErrH)
                ErrH = MyWinDevice.put_WindowStyle(WindowStyle.Child Or WindowStyle.ClipChildren)
                DsError.ThrowExceptionForHR(ErrH)
                ErrH = MyWinDevice.put_Visible(OABool.True)
                DsError.ThrowExceptionForHR(ErrH)

            End Sub

            ' Questa funzione andrebbe richiamata ogni qual volta viene effettuato un resize
            ' dell'oggetto puntato dall'handle.
            Public Sub ResizeVideoOnHandle(ByRef __dstHandle As System.IntPtr, ByVal Width As Integer, ByVal Height As Integer)
                If Me.IsDisposed Then
                    Throw New Exception("Questo oggetto è stato eliminato. E' necessario istanziare un nuovo oggetto.")
                End If
                If Not IsNothing(__dstHandle) Then
                    MyWinDevice.SetWindowPosition(0, 0, Width, Height)
                End If
            End Sub

            ' Questa funzione blocca il flusso video
            Public Sub StopVideo()
                If Me.IsDisposed Then
                    Throw New Exception("Questo oggetto è stato eliminato. E' necessario istanziare un nuovo oggetto.")
                End If
                Dim errh As Integer = MyMediaControl.Pause()
                DsError.ThrowExceptionForHR(errh)
            End Sub


            ' Questa funzione dealloca l'oggetto
            Public Sub Dispose()
                If Me.IsDisposed Then
                    Throw New Exception("Questo oggetto è stato eliminato. E' necessario istanziare un nuovo oggetto.")
                End If
                MyMediaControl.Stop()
                Finalize()
                IsDisposed = True
            End Sub


            ' Pulitura e rilascio degli oggetti COM
            Protected Overrides Sub Finalize()

                Marshal.ReleaseComObject(MyGraphBuilder)
                Marshal.ReleaseComObject(MyCaptureGraphBuilder)
                Marshal.ReleaseComObject(MyWinDevice)
                Marshal.ReleaseComObject(MyHardware)
                Marshal.ReleaseComObject(Ref_Moniker)
                MyBase.Finalize()
            End Sub
        End Class

    End Class

Per completezza, (e per velocizzare l'utilizzo del nostro wrap) dobbiamo aggiungere un ulteriore metodo alla classe  Base_VideoUtilty vista nel post precedente.

Il metodo Create_VideoAcquireHardware(Integer) accetterà l'indice della periferica che vogliamo usare e ritornerà la classe Base_VideoAcquireHardware associata a quest'ultima.

  ' Questa funzione ritorna un oggetto di tipo Base_VideoAcquireHardware che implementa
        ' alcune semplici operazioni.
        Public Function Create_VideoAcquireHardware(ByVal HardwareIndex As Integer) As Base_VideoAcquireHardware
            Try
                Dim toReturn As Base_VideoAcquireHardware = Nothing
                Dim MyMon As Dictionary(Of Integer, IMoniker) = Get_ListOfVideoAcquireHardware()
                If MyMon.ContainsKey(HardwareIndex) Then
                    toReturn = New Base_VideoAcquireHardware(HardwareIndex, CType(MyMon(HardwareIndex), IMoniker))
                Else
                    Throw New Exception("Indice periferica non valido.")
                End If
                Return
toReturn
            Catch
                Throw New Exception("Cannot create VideoAcquireHardware. (bad index?) Check : " & Err.Description)
            End Try
        End Function

Il codice riportato in questo post è completo facendo copia e incolla può essere tranquillamente compilato.

Nel prossimo post vedremo un esempio di utilizzo con il link per il download della classe compilata.

venerdì, 12 giu 2009 Ore. 19.23
Statistiche
  • Views Home Page: 27.346
  • Views Posts: 51.296
  • 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