Differenze tra le versioni di "Catturare un'immagine con una webcam mediante le funzioni esterne del API di libv4l2"
Da Gambas-it.org - Wikipedia.
(14 versioni intermedie di uno stesso utente non sono mostrate) | |||
Riga 3: | Riga 3: | ||
La libreria ''libv4l2'', che qui ci interessa, mette a disposizione l'API ''v4l2'' per i dispositivi ''v4l2''. | La libreria ''libv4l2'', che qui ci interessa, mette a disposizione l'API ''v4l2'' per i dispositivi ''v4l2''. | ||
− | Per poter fruire delle risorse fornite dalla libreria ''v4l2'' è necessario richiamare nell'applicazione Gambas la | + | Per poter fruire delle risorse fornite dalla libreria ''v4l2'' è necessario richiamare nell'applicazione Gambas la libreria condivisa: "''libv4l2.so.0.0.0'' ". |
− | Mostriamo di seguito un possibile codice per la cattura di un'immagine attraverso una webcam. L'immagine sarà salvata in un file formato ''ppm'': | + | Mostriamo di seguito un possibile codice per la cattura di un'immagine attraverso una webcam. |
− | + | ||
− | + | L'esempio funziona solo su sistemi a 64bit. | |
− | + | ||
− | + | L'immagine sarà salvata in un file formato ''ppm'': | |
Public Struct BUFFER | Public Struct BUFFER | ||
start As Pointer | start As Pointer | ||
Riga 16: | Riga 16: | ||
End Struct | End Struct | ||
− | + | Library "<FONT Color=blue>libv4l2:0.0.0</font>" | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | Library "libv4l2:0.0.0" | ||
Public Struct v4l2_requestbuffers | Public Struct v4l2_requestbuffers | ||
Riga 32: | Riga 26: | ||
Private Enum V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, V4L2_BUF_TYPE_VIDEO_OUTPUT, V4L2_BUF_TYPE_VIDEO_OVERLAY, | Private Enum V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, V4L2_BUF_TYPE_VIDEO_OUTPUT, V4L2_BUF_TYPE_VIDEO_OVERLAY, | ||
− | V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_BUF_TYPE_VBI_OUTPUT, V4L2_BUF_TYPE_SLICED_VBI_CAPTURE, V4L2_BUF_TYPE_SLICED_VBI_OUTPUT | + | V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_BUF_TYPE_VBI_OUTPUT, V4L2_BUF_TYPE_SLICED_VBI_CAPTURE, |
− | + | V4L2_BUF_TYPE_SLICED_VBI_OUTPUT | |
Private Enum V4L2_MEMORY_MMAP = 1, V4L2_MEMORY_USERPTR, V4L2_MEMORY_OVERLAY, V4L2_MEMORY_DMABUF | Private Enum V4L2_MEMORY_MMAP = 1, V4L2_MEMORY_USERPTR, V4L2_MEMORY_OVERLAY, V4L2_MEMORY_DMABUF | ||
− | |||
Private Const V4L2_PIX_FMT_RGB24 As Integer = 859981650 | Private Const V4L2_PIX_FMT_RGB24 As Integer = 859981650 | ||
Private Const V4L2_FIELD_INTERLACED As Integer = 4 | Private Const V4L2_FIELD_INTERLACED As Integer = 4 | ||
Riga 70: | Riga 63: | ||
− | Library "libc:6" | + | Library "<FONT Color=red>libc:6</font>" |
+ | Public Struct timeval | ||
+ | tv_sec As Long | ||
+ | tv_usec As Long | ||
+ | End Struct | ||
+ | |||
+ | Private Enum O_RDONLY = 0, O_WRONLY, O_RDWR, O_NONBLOCK = &2000 | ||
+ | Private Enum PROT_NONE = 0, PROT_READ, PROT_WRITE | ||
+ | Private Const MAP_SHARED As Integer = 1 | ||
+ | |||
<FONT Color=gray>' ''int select (int __nfds, fd_set *__restrict __readfds, fd_set *__restrict __writefds, fd_set *__restrict __exceptfds, struct timeval *__restrict __timeout)'' | <FONT Color=gray>' ''int select (int __nfds, fd_set *__restrict __readfds, fd_set *__restrict __writefds, fd_set *__restrict __exceptfds, struct timeval *__restrict __timeout)'' | ||
' ''Blocks the calling process until there is activity on any of the specified sets of file descriptors, or until the timeout period has expired.''</font> | ' ''Blocks the calling process until there is activity on any of the specified sets of file descriptors, or until the timeout period has expired.''</font> | ||
Private Extern select_C(nfds As Integer, readfds As Pointer, writefds As Pointer, exceptfds As Pointer, timeout As Timeval) As Integer Exec "select" | Private Extern select_C(nfds As Integer, readfds As Pointer, writefds As Pointer, exceptfds As Pointer, timeout As Timeval) As Integer Exec "select" | ||
− | + | ||
− | |||
− | |||
− | |||
− | + | '''Public''' Sub Main() | |
− | + | ||
− | + | Dim dispositivo, file_ppm As String | |
− | Dim dispositivo | ||
− | |||
Dim fd, r, n_buff, i, offset As Integer | Dim fd, r, n_buff, i, offset As Integer | ||
Dim width, height, index, byte_usati, pix As Integer | Dim width, height, index, byte_usati, pix As Integer | ||
Riga 94: | Riga 91: | ||
Dim fex As File | Dim fex As File | ||
− | + | <FONT Color=gray>' ''Impostare il dispositivo video adeguato:''</font> | |
− | + | dispositivo = "/dev/video0" | |
− | + | file_ppm = "/tmp/immago.ppm" <FONT Color=gray>' ''Il percorso ove sarà salvato il file immagine ppm creato''</font> | |
− | + | ||
− | + | Write "\e[31mAttendere......\e[0m" | |
+ | Flush | ||
+ | |||
+ | fd = v4l2_open(dispositivo, O_RDWR Or O_NONBLOCK, 0) | ||
+ | If fd < 0 Then Error.Raise("Impossibile aprire il file-device !") | ||
− | + | p = Alloc(SizeOf(gb.Byte), 208) | |
− | + | st = Memory p For Read Write | |
− | + | Write #st, V4L2_BUF_TYPE_VIDEO_CAPTURE As Integer | |
− | + | Seek #st, 8 | |
− | + | Write #st, 640 As Integer | |
− | + | Write #st, 480 As Integer | |
− | + | Write #st, V4L2_PIX_FMT_RGB24 As Integer | |
− | + | Write #st, V4L2_FIELD_INTERLACED As Integer | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | Repeat | |
− | + | r = v4l2_ioctl_pointer(fd, VIDIOC_S_FMT, p) | |
− | + | Until r > -1 | |
− | + | If r = -1 Then Error.Raise("Errore !") | |
− | + | Seek #st, 8 | |
− | + | Read #st, width | |
− | + | Read #st, height | |
− | + | Read #st, pix | |
− | + | If pix <> V4L2_PIX_FMT_RGB24 Then Error.Raise("Libv4l non accetta il formato RGB24.\nImpossibile procedere !") | |
− | + | If (width <> 640) Or (height <> 480) Then Print "Attenzione: il dispositivo imposterà l'immagine alle dimensioni";; width; "x"; height | |
− | + | st.Close | |
− | + | <FONT Color=gray>' ''Dealloca l'area di memoria precedentemente riservata e si assicura che il Puntatore non punti ad un indirizzo rilevante:''</font> | |
− | + | Free(p) | |
− | + | p = 0 | |
− | + | ||
− | + | With reqbuf | |
− | + | .count = 2 | |
− | + | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE | |
− | + | .memory_ = V4L2_MEMORY_MMAP | |
− | + | End With | |
− | + | ||
− | + | Repeat | |
− | + | r = v4l2_ioctl_request(fd, VIDIOC_REQBUFS, reqbuf) | |
− | + | Until r > -1 | |
− | + | If r = -1 Then Error.Raise("Errore !") | |
− | + | ||
− | + | p = Alloc(SizeOf(gb.Byte), 88) | |
− | + | st = Memory p For Read Write | |
− | + | For n_buff = 0 To reqbuf.count - 1 | |
− | + | Seek #st, 0 | |
− | + | Write #st, n_buff As Integer | |
− | + | Write #st, V4L2_BUF_TYPE_VIDEO_CAPTURE As Integer | |
− | + | Seek #st, 60 | |
− | + | Write #st, V4L2_MEMORY_MMAP As Integer | |
− | + | Repeat | |
− | + | r = v4l2_ioctl_pointer(fd, VIDIOC_QUERYBUF, p) | |
− | + | Until r > -1 | |
− | + | If r = -1 Then Error.Raise("Errore !") | |
− | + | Seek #st, 72 | |
− | + | With buffers[n_buff] = New BUFFER | |
− | + | Read #st, i | |
− | + | .length = i | |
+ | End With | ||
+ | Seek #st, 64 | ||
+ | Read #st, offset | ||
+ | buffers[n_buff].start = v4l2_mmap(Null, i, PROT_READ Or PROT_WRITE, MAP_SHARED, fd, offset) | ||
+ | If IsNull(buffers[n_buff].start) Then Error.Raise("Errore: puntatore nullo !") | ||
+ | Next | ||
+ | st.Close | ||
+ | <FONT Color=gray>' ''Dealloca l'area di memoria precedentemente riservata e si assicura che il Puntatore non punti ad un indirizzo rilevante:''</font> | ||
+ | Free(p) | ||
+ | p = 0 | ||
+ | |||
+ | p = Alloc(SizeOf(gb.Byte), 88) | ||
+ | st = Memory p For Write | ||
+ | For i = 0 To n_buff - 1 | ||
+ | Seek #st, 0 | ||
+ | Write #st, i As Integer | ||
+ | Write #st, V4L2_BUF_TYPE_VIDEO_CAPTURE As Integer | ||
+ | Seek #st, 60 | ||
+ | Write #st, V4L2_MEMORY_MMAP As Integer | ||
+ | Repeat | ||
+ | r = v4l2_ioctl_pointer(fd, VIDIOC_QBUF, p) | ||
+ | Until r > -1 | ||
+ | If r = -1 Then Error.Raise("Errore !") | ||
+ | Next | ||
+ | st.Close | ||
+ | <FONT Color=gray>' ''Dealloca l'area di memoria precedentemente riservata e si assicura che il Puntatore non punti ad un indirizzo rilevante:''</font> | ||
+ | Free(p) | ||
+ | p = 0 | ||
+ | |||
+ | i = V4L2_BUF_TYPE_VIDEO_CAPTURE | ||
+ | Repeat | ||
+ | r = v4l2_ioctl_pointer(fd, VIDIOC_STREAMON, VarPtr(i)) | ||
+ | Until r > -1 | ||
+ | If r = -1 Then Error.Raise("Errore !") | ||
+ | |||
+ | Repeat | ||
+ | tv.tv_sec = 1 | ||
+ | r = select_C(fd + 1, Null, Null, Null, tv) | ||
+ | Until r > -1 | ||
+ | If r = -1 Then Error.Raise("Errore !") | ||
+ | |||
+ | p = Alloc(SizeOf(gb.Byte), 88) | ||
+ | st = Memory p For Read Write | ||
+ | Seek #st, 4 | ||
+ | Write #st, V4L2_BUF_TYPE_VIDEO_CAPTURE As Integer | ||
+ | Seek #st, 60 | ||
+ | Write #st, V4L2_MEMORY_MMAP As Integer | ||
+ | Repeat | ||
+ | r = v4l2_ioctl_pointer(fd, VIDIOC_DQBUF, p) | ||
+ | Until r > -1 | ||
+ | If r = -1 Then Error.Raise("Errore !") | ||
+ | Seek #st, 8 | ||
+ | Read #st, byte_usati | ||
<FONT Color=gray>' ''Scrive il file immagine .ppm:''</font> | <FONT Color=gray>' ''Scrive il file immagine .ppm:''</font> | ||
− | + | File.Save(file_ppm, "P6\x0A" & CStr(width) & Chr(32) & CStr(height) & " 255\x0A") | |
− | + | fex = open file_ppm For Write | |
− | + | If IsNull(fex) Then Error.Raise("Impossibile aprire in scrittura il file immagine !") | |
− | + | Seek #st, 0 | |
− | + | Read #st, index | |
− | + | st.Close | |
− | + | <FONT Color=gray>' ''Dealloca l'area di memoria precedentemente riservata e si assicura che il Puntatore non punti ad un indirizzo rilevante:''</font> | |
− | + | Free(p) | |
− | + | p = 0 | |
− | + | ||
− | + | p = buffers[index].start | |
− | + | If p == 0 Then Error.Raise("Errore !") | |
− | + | Seek #fex, 15 | |
− | + | For i = 1 To byte_usati | |
+ | Write #fex, Byte@(p) As Byte | ||
+ | p = p + 1 | ||
+ | Next | ||
+ | fex.Close | ||
<FONT Color=gray>' ''In chiusura:''</font> | <FONT Color=gray>' ''In chiusura:''</font> | ||
− | + | i = V4L2_BUF_TYPE_VIDEO_CAPTURE | |
− | + | Repeat | |
− | + | r = v4l2_ioctl_pointer(fd, VIDIOC_STREAMON, VarPtr(i)) | |
− | + | Until r > -1 | |
− | + | If r = -1 Then Error.Raise("Errore !") | |
− | + | For i = 0 To n_buff - 1 | |
− | + | v4l2_munmap(buffers[i].start, buffers[i].length) | |
− | + | Next | |
− | + | v4l2_close(fd) | |
− | |||
− | |||
− | |||
+ | Write "\rImmagine acquisita !" | ||
+ | |||
'''End''' | '''End''' | ||
− | |||
Riga 247: | Riga 250: | ||
=Riferimenti= | =Riferimenti= | ||
* http://linuxtv.org/downloads/v4l-dvb-apis/index.html | * http://linuxtv.org/downloads/v4l-dvb-apis/index.html | ||
+ | * http://www.exploits.org/v4l/ |
Versione delle 11:44, 12 apr 2023
La risorsa libv4l è una raccolta di librerie per la gestione dei dispositivi video4linux2 evitando che si debba scrivere del codice separato, nella stessa classe, per i diversi dispositivi. libv4l è composta da tre librerie differenti: libv4lconvert, libv4l1 e libv4l2.
La libreria libv4l2, che qui ci interessa, mette a disposizione l'API v4l2 per i dispositivi v4l2.
Per poter fruire delle risorse fornite dalla libreria v4l2 è necessario richiamare nell'applicazione Gambas la libreria condivisa: "libv4l2.so.0.0.0 ".
Mostriamo di seguito un possibile codice per la cattura di un'immagine attraverso una webcam.
L'esempio funziona solo su sistemi a 64bit.
L'immagine sarà salvata in un file formato ppm:
Public Struct BUFFER start As Pointer length As Integer End Struct Library "libv4l2:0.0.0" Public Struct v4l2_requestbuffers count As Integer type As Integer memory_ As Integer reserved[2] As Integer End Struct Private Enum V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, V4L2_BUF_TYPE_VIDEO_OUTPUT, V4L2_BUF_TYPE_VIDEO_OVERLAY, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_BUF_TYPE_VBI_OUTPUT, V4L2_BUF_TYPE_SLICED_VBI_CAPTURE, V4L2_BUF_TYPE_SLICED_VBI_OUTPUT Private Enum V4L2_MEMORY_MMAP = 1, V4L2_MEMORY_USERPTR, V4L2_MEMORY_OVERLAY, V4L2_MEMORY_DMABUF Private Const V4L2_PIX_FMT_RGB24 As Integer = 859981650 Private Const V4L2_FIELD_INTERLACED As Integer = 4 Private Const VIDIOC_S_FMT As Long = 3234878981 Private Const VIDIOC_REQBUFS As Long = 3222558216 Private Const VIDIOC_QUERYBUF As Long = 3227014665 Private Const VIDIOC_QBUF As Long = 3227014671 Private Const VIDIOC_STREAMON As Long = 1074026002 Private Const VIDIOC_DQBUF As Long = 3227014673 ' int v4l2_open(const char *file, int oflag, ...) ' Open a V4L2 device. Private Extern v4l2_open(fl As String, oflag As Integer, alterum As Integer) As Integer ' int v4l2_ioctl(int fd, unsigned long int request, ...) ' Program a V4L2 device. Private Extern v4l2_ioctl_pointer(fd As Integer, request As Long, arg As Pointer) As Integer Exec "v4l2_ioctl" ' int v4l2_ioctl(int fd, unsigned long int request, ...) ' Program a V4L2 device. Private Extern v4l2_ioctl_request(fd As Integer, request As Long, arg As V4l2_requestbuffers) As Integer Exec "v4l2_ioctl" ' void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, int64_t offset) ' Map device memory into application address space. Private Extern v4l2_mmap(startP As Pointer, lengthI As Integer, prot As Integer, flags As Integer, fdI As Integer, offsetL As Long) As Pointer ' int v4l2_munmap(void *start, size_t length) ' Unmap device memory. Private Extern v4l2_munmap(startP As Pointer, lengthI As Integer) As Integer ' int v4l2_close(int fd) ' Close a V4L2 device. Private Extern v4l2_close(fd As Integer) Library "libc:6" Public Struct timeval tv_sec As Long tv_usec As Long End Struct Private Enum O_RDONLY = 0, O_WRONLY, O_RDWR, O_NONBLOCK = &2000 Private Enum PROT_NONE = 0, PROT_READ, PROT_WRITE Private Const MAP_SHARED As Integer = 1 ' int select (int __nfds, fd_set *__restrict __readfds, fd_set *__restrict __writefds, fd_set *__restrict __exceptfds, struct timeval *__restrict __timeout) ' Blocks the calling process until there is activity on any of the specified sets of file descriptors, or until the timeout period has expired. Private Extern select_C(nfds As Integer, readfds As Pointer, writefds As Pointer, exceptfds As Pointer, timeout As Timeval) As Integer Exec "select" Public Sub Main() Dim dispositivo, file_ppm As String Dim fd, r, n_buff, i, offset As Integer Dim width, height, index, byte_usati, pix As Integer Dim reqbuf As New V4l2_requestbuffers Dim p As Pointer Dim st As Stream Dim buffers As New BUFFER[2] Dim tv As New Timeval Dim fex As File ' Impostare il dispositivo video adeguato: dispositivo = "/dev/video0" file_ppm = "/tmp/immago.ppm" ' Il percorso ove sarà salvato il file immagine ppm creato Write "\e[31mAttendere......\e[0m" Flush fd = v4l2_open(dispositivo, O_RDWR Or O_NONBLOCK, 0) If fd < 0 Then Error.Raise("Impossibile aprire il file-device !") p = Alloc(SizeOf(gb.Byte), 208) st = Memory p For Read Write Write #st, V4L2_BUF_TYPE_VIDEO_CAPTURE As Integer Seek #st, 8 Write #st, 640 As Integer Write #st, 480 As Integer Write #st, V4L2_PIX_FMT_RGB24 As Integer Write #st, V4L2_FIELD_INTERLACED As Integer Repeat r = v4l2_ioctl_pointer(fd, VIDIOC_S_FMT, p) Until r > -1 If r = -1 Then Error.Raise("Errore !") Seek #st, 8 Read #st, width Read #st, height Read #st, pix If pix <> V4L2_PIX_FMT_RGB24 Then Error.Raise("Libv4l non accetta il formato RGB24.\nImpossibile procedere !") If (width <> 640) Or (height <> 480) Then Print "Attenzione: il dispositivo imposterà l'immagine alle dimensioni";; width; "x"; height st.Close ' Dealloca l'area di memoria precedentemente riservata e si assicura che il Puntatore non punti ad un indirizzo rilevante: Free(p) p = 0 With reqbuf .count = 2 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE .memory_ = V4L2_MEMORY_MMAP End With Repeat r = v4l2_ioctl_request(fd, VIDIOC_REQBUFS, reqbuf) Until r > -1 If r = -1 Then Error.Raise("Errore !") p = Alloc(SizeOf(gb.Byte), 88) st = Memory p For Read Write For n_buff = 0 To reqbuf.count - 1 Seek #st, 0 Write #st, n_buff As Integer Write #st, V4L2_BUF_TYPE_VIDEO_CAPTURE As Integer Seek #st, 60 Write #st, V4L2_MEMORY_MMAP As Integer Repeat r = v4l2_ioctl_pointer(fd, VIDIOC_QUERYBUF, p) Until r > -1 If r = -1 Then Error.Raise("Errore !") Seek #st, 72 With buffers[n_buff] = New BUFFER Read #st, i .length = i End With Seek #st, 64 Read #st, offset buffers[n_buff].start = v4l2_mmap(Null, i, PROT_READ Or PROT_WRITE, MAP_SHARED, fd, offset) If IsNull(buffers[n_buff].start) Then Error.Raise("Errore: puntatore nullo !") Next st.Close ' Dealloca l'area di memoria precedentemente riservata e si assicura che il Puntatore non punti ad un indirizzo rilevante: Free(p) p = 0 p = Alloc(SizeOf(gb.Byte), 88) st = Memory p For Write For i = 0 To n_buff - 1 Seek #st, 0 Write #st, i As Integer Write #st, V4L2_BUF_TYPE_VIDEO_CAPTURE As Integer Seek #st, 60 Write #st, V4L2_MEMORY_MMAP As Integer Repeat r = v4l2_ioctl_pointer(fd, VIDIOC_QBUF, p) Until r > -1 If r = -1 Then Error.Raise("Errore !") Next st.Close ' Dealloca l'area di memoria precedentemente riservata e si assicura che il Puntatore non punti ad un indirizzo rilevante: Free(p) p = 0 i = V4L2_BUF_TYPE_VIDEO_CAPTURE Repeat r = v4l2_ioctl_pointer(fd, VIDIOC_STREAMON, VarPtr(i)) Until r > -1 If r = -1 Then Error.Raise("Errore !") Repeat tv.tv_sec = 1 r = select_C(fd + 1, Null, Null, Null, tv) Until r > -1 If r = -1 Then Error.Raise("Errore !") p = Alloc(SizeOf(gb.Byte), 88) st = Memory p For Read Write Seek #st, 4 Write #st, V4L2_BUF_TYPE_VIDEO_CAPTURE As Integer Seek #st, 60 Write #st, V4L2_MEMORY_MMAP As Integer Repeat r = v4l2_ioctl_pointer(fd, VIDIOC_DQBUF, p) Until r > -1 If r = -1 Then Error.Raise("Errore !") Seek #st, 8 Read #st, byte_usati ' Scrive il file immagine .ppm: File.Save(file_ppm, "P6\x0A" & CStr(width) & Chr(32) & CStr(height) & " 255\x0A") fex = open file_ppm For Write If IsNull(fex) Then Error.Raise("Impossibile aprire in scrittura il file immagine !") Seek #st, 0 Read #st, index st.Close ' Dealloca l'area di memoria precedentemente riservata e si assicura che il Puntatore non punti ad un indirizzo rilevante: Free(p) p = 0 p = buffers[index].start If p == 0 Then Error.Raise("Errore !") Seek #fex, 15 For i = 1 To byte_usati Write #fex, Byte@(p) As Byte p = p + 1 Next fex.Close ' In chiusura: i = V4L2_BUF_TYPE_VIDEO_CAPTURE Repeat r = v4l2_ioctl_pointer(fd, VIDIOC_STREAMON, VarPtr(i)) Until r > -1 If r = -1 Then Error.Raise("Errore !") For i = 0 To n_buff - 1 v4l2_munmap(buffers[i].start, buffers[i].length) Next v4l2_close(fd) Write "\rImmagine acquisita !" End