Il tipo di approccio che ti suggerisco ti consente di catturare immagini da una webcam,
ovviamente caricarle su un Form o una PictureBox, mostrare lo stream video proveniente dalla
webcam e ottenere informazioni sulle capacità del driver di cattura video e mostrare le finestre di
dialogo per l'impostazione del formato, dimensioni e origine della cattura.
Il tutto viene realizzato con un paio di API e qualche struttura (UDT).
La prima cosa da fare è creare una Capture-Window.
Una volta connessa al driver di cattura video, potrai inviarle dei messaggi ottenendo i risultati descritti
sopra. Quindi le funzioni API di cui hai bisogno sono principalmente due:
capCreateCaptureWindow per creare la capture window e
SendMessage per inviarle i messaggi
ecco le dichiarazioni di queste due funzioni:
codice:
Private Declare Function capCreateCaptureWindow Lib "avicap32" Alias "capCreateCaptureWindowA" (ByVal lpszWindowName As String, ByVal dwStyle As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hWnd As Long, ByVal nID As Long) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
in più: le dichiarazioni di due costanti per definire lo stile della Capture Window:
codice:
Const WS_CHILD = &H40000000 ' figlia
Const WS_VISIBLE = &H10000000 ' visibile
altre funzioni API e alcune costanti che utilizzerai:
codice:
Private Declare Function DestroyWindow Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function SetWindowPos Lib "user32" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
' Per SetWindowPos
Const SWP_NOZORDER = &H4
Const SWP_NOMOVE = &H2
' Messagi per capture driver
Const WM_USER = &H400
Const WM_CAP_START = WM_USER
Const WM_CAP_DRIVER_CONNECT = WM_CAP_START Or 10
Const WM_CAP_DRIVER_DISCONNECT = WM_CAP_START Or 11
Const WM_CAP_GET_STATUS = WM_CAP_START Or 54 ' stato del driver
Const WM_CAP_DRIVER_GET_CAPS = WM_CAP_START + 14 ' capabilities del driver
Const WM_CAP_GRAB_FRAME = WM_CAP_START + 60 ' per cattura frame
Const WM_CAP_GRAB_FRAME_NOSTOP = WM_CAP_START + 61 ' " " "
Const WM_CAP_EDIT_COPY = WM_CAP_START + 30 ' copia frame su clipboard
Const WM_CAP_SET_OVERLAY = WM_CAP_START + 51 ' per abilitare/disabilitare overlay
Const WM_CAP_SET_PREVIEW = WM_CAP_START + 50 ' per abilitare/disabilitare modo preview
Const WM_CAP_SET_PREVIEWRATE = WM_CAP_START + 52 ' per settare il preview rate
Const WM_CAP_DLG_VIDEOFORMAT = WM_CAP_START + 41 ' per dialog formati video
Const WM_CAP_DLG_VIDEOSOURCE = WM_CAP_START + 42 ' per dialog origine acquisizione
Const WM_CAP_DLG_VIDEODISPLAY = WM_CAP_START + 43 '
Const WM_CAP_DLG_VIDEOCOMPRESSION = WM_CAP_START + 46 ' per dialog compressioni video
Const WM_CAP_GET_VIDEOFORMAT = WM_CAP_START + 44
Const WM_CAP_SET_VIDEOFORMAT = WM_CAP_START + 45
DestroyWindow per "ditruggere" la Capture Window una volta che non ne avrai più bisogno (magari alla chiusura
dell'applicazione) e SetWindowPos per definire posizione e dimensioni della CaptureWindow.
Le costanti il cui identificatore comincia per "WM_" rappresentano i messaggi che puoi inviare alla Capture Window.
Ora vediamo un paio di strutture utili:
codice:
' Status del driver di cattura video
Private Type CAPSTATUS
uiImageWidth As Long ' width
uiImageHeight As Long ' height
fLiveWindow As Long ' Live window flag. Vale True se la CaptureWindow sta mostrando video usando il metodo Preview
fOverlayWindow As Long ' Overlay window flag. Vale True se la CaptureWindow sta mostrando video usando l'hardware overlay
fScale As Long
ptScrollx As Long
ptScrolly As Long
fUsingDefaultPalette As Long
fAudioHardware As Long
fCapFileExists As Long
dwCurrentVideoFrame As Long
dwCurrentVideoFramesDropped As Long
dwCurrentWaveSamples As Long
dwCurrentTimeElapsedMS As Long
hPalCurrent As Long ' handle della pallette corrente
fCapturingNow As Long
dwReturn As Long
wNumVideoAllocated As Long
wNumAudioAllocated As Long
End Type
' Capabilities del driver di cattura video
Private Type CAPDRIVERCAPS
wDeviceIndex As Long
fHasOverlay As Long
fHasDlgVideoSource As Long
fHasDlgVideoFormat As Long
fHasDlgVideoDisplay As Long
fCaptureInitialized As Long
fDriverSuppliesPalettes As Long
hVideoIn As Long
hVideoOut As Long
hVideoExtIn As Long
hVideoExtOut As Long
End Type
Ed ecco, finalmente, come creare la tua Capture Window:
codice:
hWndCapture = capCreateCaptureWindow("CaptureWindow Name", WS_CHILD Or WS_VISIBLE, 0, 0, 320, 240, Picture1.hWnd, 0)
Il primo argomento è una stringa contenente il nome che vuoi assegnare alla Window:
Puoi scegliere il nome che preferisci. Il secondo argomento definisce lo stile: una finestra figlia visibile.
Fai un tentativo e osserva cosa succede omettendo WS_CHILD... la finestra non è più "figlia" !!!
I quattro argomenti successivi indicano posizione e dimensioni della finestra espresse in pixels,
segue l'handle della Window su cui verrà mostrata l'immagine o lo stream proveniente dalla webcam.
A questo argomento ho passatol'hwnd di una PictureBox. Per quanto riguarda l'ultimo argomento...
non ho la più pallida idea di quale sia il suo significato o scopo :-)
A questo punto hai la tua Capture Window e puoi iniziare ad usarla.
Prima però devi tenere presente che questa verrà creata indipendentemente dal fatto che sul sistema in uso
sia o meno installata e collegata una webcam.
Il passo successivo, la connessione al driver di cattura video, ti permetterà anche di verificare ciò.
codice:
' Verifica la connessione al del capture driver
If (SendMessage(hWndCapture, WM_CAP_DRIVER_CONNECT, 0, 0) = 0) Then
MsgBox "Assicurarsi che il dispositivo di cattura video sia collegato correttamente ed, eventualmente installare nuovamente il driver.", vbCritical, "Impossibile connettersi al driver di cattura video"
Exit Sub
End If
Come vedi viene inviato alla Capture Window un messaggio WM_CAP_DRIVER_CONNECT per connettersi al driver di cattura.
Se questa restituisce 0 significa che ha fallito, quindi la webcam non è collegata o addirittura non è installata.
codice:
Dim CapStat As CAPSTATUS
' Richiesta dello stato del capture driver
SendMessage hWndCapture, WM_CAP_GET_STATUS, Len(CapStat), CapStat
Con questa chiamata a SendMessage, popoliamo una struttura CAPSTATUS con le informazioni sullo stato del driver
di cattura video. Possiamo quindi utilizzare queste informazioni per ridimensionare la PictureBox adattandola alle
dimensioni della cattura:
codice:
' Resize della PictureBox
With Me.Picture1
.Width = ScaleX(CapStat.uiImageWidth, vbPixels, vbTwips)
.Height = ScaleY(CapStat.uiImageHeight, vbPixels, vbTwips)
End With
Affinchè la Capture Window venga utilizzata bene occorre, anche per essa, impostarne le dimensioni:
codice:
' Impostazione delle dimensioni della Capture Window
SetWindowPos hWndCapture, 0, 0, 0, CapStat.uiImageWidth, CapStat.uiImageHeight, SWP_NOZORDER + SWP_NOMOVE
Fino a qui:
1) abbiamo la Capture Window,
2) ne abbiamo impostato le dimensioni adattandole a quelle della cattura,
3) abbiamo fatto lo stesso con le dimensioni della PictureBox.
Procediamo:
Richiediamo informazioni sulle capacità del driver di cattura video. Queste ci permetteranno di determinare
se possiamo catturare solo immagini fisse o uno stream (oltre ad altre utili informazioni):
codice:
Dim CapDrvCaps As CAPDRIVERCAPS
' Richiesta delle capacità del capture driver
SendMessage hWndCapture, WM_CAP_DRIVER_GET_CAPS, Len(CapDrvCaps), CapDrvCaps
Gli elementi fHasDlgVideoSource e fHasDlgVideoFormat
del tipo CAPDRIVERCAPS restituiscono valori booleani che indicano rispettivamente
se il driver supporta la finestra di dialogo per la selezione dell'origine di cattura (fHasDlgVideoSource) e
se supporta la finestra di dialogo per la selezione del formato (dimensioni) di cattura (HasDlgVideoFormat).
Esempio:
codice:
If CapDrvCaps.fHasDlgVideoSource Then
MsgBox "Il driver consente la selezione dell'origine della cattura.", vbInformation
Else
MsgBox "Il driver non consente la selezione dell'origine della cattura.", vbExclamation
End If
quindi mostrare le dialog inviando i rispettivi messaggi
(WM_CAP_DLG_VIDEOFORMAT, WM_CAP_DLG_VIDEOSOURCE, WM_CAP_DLG_VIDEODISPLAY, WM_CAP_DLG_VIDEOCOMPRESSION):
codice:
' Mostra la dialog per la selezione del formato video
SendMessage hWndCapture, WM_CAP_DLG_VIDEOFORMAT, 0, 0
Ora vediamo se il driver consente di abilitare il modo Preview che ci permette di mostrare lo stream video
nella nostra PictureBox:
codice:
' Se è possibile modo overlay...
If CapDrvCaps.fHasOverlay Then
' ...abilita l'overlay (1 = attiva; 0 = disattiva)
SendMessage hWndCapture, WM_CAP_SET_OVERLAY, 1, 0
Else
' Setta il PreviewRate (a 120 ms) e lo abilita
SendMessage hWndCapture, WM_CAP_SET_PREVIEWRATE, 120, 0
' setta il modo Preview (1 = attiva; 0 = disattiva)
SendMessage hWndCapture, WM_CAP_SET_PREVIEW, 1, 0
End If
Se è possibile viene settato il PreviewRate a 129 millisecondi (ovviamente puoi scegliere tu l'intervallo)
e viene abilitato il modo Preview. Da questo momento in poi, sulla PictureBox verrà mostrato lo stream catturato
dalla webcam.
Se il driver non lo consente, si abilita il modo Overlay e un'unica immagine catturata dalla WebCam verrà visualizzata
sulla PictureBox. In entrambi i casi, comunque, puoi catturare fotogrammi (anche durante lo streaming).
Anche la cattura dei frames è possibile grazie a SendMessage. Basta inviare alla capture window un messaggio
WM_CAP_GRAB_FRAME_NOSTOP per catturare il frame dal buffer senza bloccare lo streaming e, successivamente,
un messaggio WM_CAP_EDIT_COPY per copiare il frame nella Clipboard. Il passo successivo consisterà nel caricare
l'immagine direttamente dalla Clipboard. Volendo si potrebbe preparare una funzioncina di questo tipo:
codice:
Function CaptureFrame() As IPictureDisp
' Restituisce l'immagine catturata dalla webcam
SendMessage hWndCapture, WM_CAP_GRAB_FRAME_NOSTOP, 0, 0 ' cattura frame dal buffer
SendMessage hWndCapture, WM_CAP_EDIT_COPY, 0, 0 ' lo copia sulla clipboard
Set CaptureFrame = Clipboard.GetData() ' restituisce l'immagine contenuta nella clipboard
End Function
e richiamarla così:
codice:
Set Picture2.Picture = CaptureFrame()
per mostrare la cattura in un'altra PictureBox (Picture2).
Ok, abbiamo quasi concluso. Ricordati che, alla fine del lavoro, devi liberare le risorse disconnettendoti
dal driver di cattura video e distruggendo la Capture Window:
codice:
Private Sub Form_Unload(Cancel As Integer)
SendMessage hWndCapture, WM_CAP_SET_PREVIEW, 0, 0 ' disabilita modo preview
SendMessage hWndCapture, WM_CAP_DRIVER_DISCONNECT, 0, 0 ' disconnette dal capture driver
DestroyWindow hWndCapture ' libera risorse
End Sub
Ora è propio tutto.
Buon divertimento.
Simo