Luigi Di Biasi


XP Programming Style
Sondaggio
Argomento Spider e WebCrawler

Interessante
Non interessante

[t] Salvare il flusso video su HD

Il mio blog si è trasferito all'indirizzo http://www.luigidibiasi.it
Salvataggio del flusso su HD

















L'obbiettivo di questo post è quello di descrivere le modifiche da apportare al metodo StartVideoOnHandle([arg]...) della  Base_VideoAcquireHardware per aggiungere la funzionalità di salvataggio del flusso video su hard-disk durante la visualizzazione del preview. 

Per il momento il formato utilizzato sarà AVI (dunque file abbastanza grandi) poiché di norma il filtro necessario per salvare in questo formato è sempre disponibile sui sistemi windows. Successivamente implementeremo lo snapshot di un singolo frame ed infine l'utilizzo di filtri di compressione. 

Il metodo StartVideoOnHandle
Questo metodo era stato scritto in modo da avviare l'anteprima del flusso in una finestra passata tramite il proprio handle. Tuttavia, c'era un errore di fondo poiché la firma del metodo richiedeva il PIN da dove acquisire il flusso e dunque era possibile avviare la preview anche dal PIN di cattura. Ciò poteva darci problemi se dovevamo acquisire e salvare su file. Inoltre, è presente un altro parametro che dovrebbe essere eliminato (il mediatype) poiché permette di specificare il tipo di media che la classe dovrà gestire. E' possibile infatti passare MediaType.AUDIO mandando in crash la classe (che è scritta per acquisire video) ma, per il momento, lo lasciamo lì magari con uno sguardo al futuro, se tenteremo di modificare la classe per permette di acquisire sia Audio che Video

Ora, ci proponiamo di ottimizzare il metodo in modo che permetta sia la visualizzazione dell'anteprima che la cattura del flusso. ( l'anteprima verrà generata utilizzando il PIN di PREVIEW, la cattura il pin CAPTURE, entrambi gestiti automaticamente dalla classe)

La nuova firma del metodo sarà definita come:

Public Sub StartVideoOnHandle(ByRef __dstHandle As System.IntPtr, ByVal MediaT As DsGuid, Optional ByVal MustSave As Boolean = False, Optional ByVal FilePath As String = Nothing, Optional byval showPreview as boolean=true)

Le modifiche sostanziali sono le seguenti:
- Non è più possibile specificare il PIN di origine.
- E' possibile modificare il comportamento di una istanza Base_VideoAcquireFlagHardware tramite il flag MustSave.  Se true allora la classe salverà il flusso in filePath. Se false il salvataggio non verrà eseguito. Inoltre, sarà possibile nascondere l'anteprima durante il salvataggio tramite il flag showPreview.

 Il nuovo metodo utilizzerà un filtro in più che verrà aggiunto al filtro dei grafi: AviMUX. Questo filtro si occuperà del salvataggio su disco. (il flusso dal PIN CAPTURE verrà convogliato nel MUX che lo salverà su disco)

Pertanto definiamo due nuove variabili globali:

  ' Oggetto per il salvataggio su file
   Private pMux As IBaseFilter
   Private isRender as boolean=false    ' spiegata in seguito

Poi, modifichiamo il corpo del metodo come segue:

' Questa funzione avvia il flusso video su un handle di finestra.
' I parametri 2 e 3 permettono di definire da dove acquisisire e cosa

Public Sub StartVideoOnHandle(ByRef __dstHandle As System.IntPtr, ByVal MediaT As DsGuid, Optional ByVal MustSaveAs Boolean = FalseOptional ByVal FilePath As String = Nothing, Optional byval showPreview as boolean=true)

                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

' Qui controlla se è stato effettuato il flush su disco. In caso positivo inizia a scrivere da ZERO il file
' quindi se si esegue il flush è opportuno rinominare il file già acquisito pena la sovrascrittura.
                If IsFlushed Then
                        IsFlushed = False
                        MyMediaControl.Run()
                        Exit Sub
                 End If

                    ' Deve anche salvare il flusso?
                    If MustSave Then

                      ' Avvia l'acquisizione ->  notare il mediasubtype  e il PIN specificati 

                      ErrH = MyCaptureGraphBuilder.SetOutputFileName(MediaSubType.Avi, FilePath, pMux, Nothing)
                      DsError.ThrowExceptionForHR(ErrH)
                      ErrH = MyCaptureGraphBuilder.RenderStream(PinCategory.Capture, MediaT, MyHardware, Nothing, pMux)
                      DsError.ThrowExceptionForHR(ErrH)

                    End If

                    '  Prepara il flusso di preview
                    ErrH = MyCaptureGraphBuilder.RenderStream(PinCategory.Preview, MediaT, MyHardware, Nothing, Nothing)
                    DsError.ThrowExceptionForHR(ErrH)

                    ' Avvia il grafo. 
                    ErrH = MyMediaControl.Run()
                    DsError.ThrowExceptionForHR(ErrH)

            ' Controlla se mostrare o meno la finestra di preview.

                    If Not ShowPreview Then 'la nasconde
                        ErrH = MyWinDevice.put_AutoShow(OABool.False)
                        DsError.ThrowExceptionForHR(ErrH)
                        ErrH = MyWinDevice.put_Visible(OABool.False)
                        DsError.ThrowExceptionForHR(ErrH)
                    Else 'invia il preview sull'handle passato in argomento
                        ' Manda il flusso sul __dstHandle e si salva il riferimento x usi successivi
                        ErrH = MyWinDevice.put_Owner(__dstHandle)
                        __currentVideoHandler = __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 If

                    Marshal.ReleaseComObject(MyHardware)
                    IsRender = True
                Else  ' se il grafo è in pausa lo riavvia soltanto
                    MyMediaControl.Run()
                End If

            End Sub

La scrittura su disco avviene quando il grafo viene fermato ovvero quando si richiama MyMediaControl.Stop 
Ridefiniamo quindi la funzione StopVideo aggiungendo un parametro che permetta di specificare se vogliamo
scrivere su disco oppure bloccare temporaneamente l'acquisizione

            Public Sub StopVideo(Optional ByVal Flush As Boolean = False)
                If Me.IsDisposed Then
                    Throw New Exception("Questo oggetto è stato eliminato. E' necessario istanziare un nuovo oggetto.")
                End If

                Dim errh As Integer
                If Not Flush Then                   ' se non è richiesto il flush viene bloccata l'acquisizione ma ripartirà scrivendo 
    ' sul file senza sovrascriverlo.
                    errh = MyMediaControl.Pause()
                    DsError.ThrowExceptionForHR(errh)
                Else
                    errh = MyMediaControl.Stop()   ' se effettuiamo il flush quando ripartirà l'acquisizione sovrascriverà il file
                    DsError.ThrowExceptionForHR(errh)
                    IsRender = False
                    IsFlushed = True
                End If
            End Sub

Una dll per testare queste nuove modifiche è disponibile qui. Purtroppo non l'ho testata a fondo quindi se sono presenti bug (sempre presenti) vi prego di segnalarmeli.
martedì, 01 giu 2010 Ore. 16.12
Statistiche
  • Views Home Page: 25.612
  • Views Posts: 49.433
  • 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