Differenze tra le versioni di "Catturare un'immagine con una webcam mediante le funzioni esterne del API di libv4l2"

Da Gambas-it.org - Wikipedia.
Riga 2: Riga 2:
  
 
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''.
 
+
<BR>Per poter fruire delle risorse fornite dalla libreria ''v4l2'' è necessario richiamare nell'applicazione Gambas la libreria condivisa: "''libv4l2.so.0.0.0'' ".
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.
 
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'':
 
L'immagine sarà salvata in un file formato ''ppm'':
  Public Struct BUFFER
+
  Public Struct Buffer
 
   start As Pointer
 
   start As Pointer
 
   length As Integer
 
   length As Integer
 
  End Struct
 
  End Struct
 
   
 
   
  Library "<FONT Color=blue>libv4l2:0.0.0</font>"
+
 +
  Library "<FONT Color=red>libc:6</font>"
 +
 +
Public Struct timeval
 +
  tv_sec As Long
 +
  tv_usec As Long
 +
End Struct
 
   
 
   
 
  Public Struct v4l2_requestbuffers
 
  Public Struct v4l2_requestbuffers
Riga 22: Riga 24:
 
   type As Integer
 
   type As Integer
 
   memory_ As Integer
 
   memory_ As Integer
   reserved[2] As Integer
+
  capabilities As Integer
 +
  flags As Byte
 +
   reserved[3] As Byte
 
  End Struct
 
  End Struct
 
   
 
   
 +
Public Struct v4l2_timecode
 +
  type As Integer
 +
  flags As Integer
 +
  frames As Byte
 +
  seconds As Byte
 +
  minutes As Byte
 +
  hours As Byte
 +
  userbits[4] As Byte
 +
End Struct
 +
 +
Public Struct v4l2_buffer
 +
  index As Integer
 +
  type As Integer
 +
  bytesused As Integer
 +
  flags As Integer
 +
  field As Integer
 +
  timestamp As Struct Timeval
 +
  timecode As Struct V4l2_timecode
 +
  sequence As Integer
 +
  memory_ As Integer
 +
  m As Long
 +
  length As Integer
 +
  reserved2 As Integer
 +
  request_fd As Integer
 +
End Struct
 +
 +
Private Enum O_RDONLY = 0, O_WRONLY, O_RDWR, O_NONBLOCK = &2000
 +
Private Enum PROT_NONE = 0, PROT_READ, PROT_WRITE
 
  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_VBI_CAPTURE, V4L2_BUF_TYPE_VBI_OUTPUT, V4L2_BUF_TYPE_SLICED_VBI_CAPTURE,
               V4L2_BUF_TYPE_SLICED_VBI_OUTPUT
+
               V4L2_BUF_TYPE_SLICED_VBI_OUTPUT, V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
 +
              V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, V4L2_BUF_TYPE_SDR_CAPTURE, V4L2_BUF_TYPE_SDR_OUTPUT,
 +
              V4L2_BUF_TYPE_META_CAPTURE, V4L2_BUF_TYPE_META_OUTPUT
 +
Private Enum V4L2_FIELD_ANY, V4L2_FIELD_NONE, V4L2_FIELD_TOP, V4L2_FIELD_BOTTOM, V4L2_FIELD_INTERLACED,
 +
              V4L2_FIELD_SEQ_TB, V4L2_FIELD_SEQ_BT, V4L2_FIELD_ALTERNATE, V4L2_FIELD_INTERLACED_TB,
 +
              V4L2_FIELD_INTERLACED_BT
 
  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 VIDIOC_S_FMT As Long = 3234878981
 
  Private Const VIDIOC_S_FMT As Long = 3234878981
 
  Private Const VIDIOC_REQBUFS As Long = 3222558216
 
  Private Const VIDIOC_REQBUFS As Long = 3222558216
Riga 36: Riga 72:
 
  Private Const VIDIOC_QBUF As Long = 3227014671
 
  Private Const VIDIOC_QBUF As Long = 3227014671
 
  Private Const VIDIOC_STREAMON As Long = 1074026002
 
  Private Const VIDIOC_STREAMON As Long = 1074026002
 +
Private Const VIDIOC_STREAMOFF As Long = 1074026003
 
  Private Const VIDIOC_DQBUF As Long = 3227014673
 
  Private Const VIDIOC_DQBUF As Long = 3227014673
 +
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)''
 +
' ''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"
 +
 +
 
 +
Library "<FONT Color=blue>libv4l2:0.0.0</font>"
 
   
 
   
 
  <FONT Color=gray>' ''int v4l2_open(const char *file, int oflag, ...)''
 
  <FONT Color=gray>' ''int v4l2_open(const char *file, int oflag, ...)''
Riga 45: Riga 90:
 
  ' ''Program a V4L2 device.''</font>
 
  ' ''Program a V4L2 device.''</font>
 
  Private Extern v4l2_ioctl_pointer(fd As Integer, request As Long, arg As Pointer) As Integer Exec "v4l2_ioctl"
 
  Private Extern v4l2_ioctl_pointer(fd As Integer, request As Long, arg As Pointer) As Integer Exec "v4l2_ioctl"
 +
 +
<FONT Color=gray>' ''int v4l2_ioctl(int fd, unsigned long int request, ...)''
 +
' ''Program a V4L2 device.''</font>
 +
Private Extern v4l2_ioctl_buffer(fd As Integer, request As Long, arg As V4l2_buffer) As Integer Exec "v4l2_ioctl"
 
   
 
   
 
  <FONT Color=gray>' ''int v4l2_ioctl(int fd, unsigned long int request, ...)''
 
  <FONT Color=gray>' ''int v4l2_ioctl(int fd, unsigned long int request, ...)''
Riga 52: Riga 101:
 
  <FONT Color=gray>' ''void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, int64_t offset)''
 
  <FONT Color=gray>' ''void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, int64_t offset)''
 
  ' ''Map device memory into application address space.''</font>
 
  ' ''Map device memory into application address space.''</font>
  Private Extern v4l2_mmap(startP As Pointer, lengthI As Integer, prot As Integer, flags As Integer, fdI As Integer, offsetL As Long) As Pointer
+
  Private Extern v4l2_mmap(start As Pointer, lengthI As Integer, prot As Integer, flags As Integer, fd As Integer, offset As Long) As Pointer
 
   
 
   
 
  <FONT Color=gray>' ''int v4l2_munmap(void *start, size_t length)''
 
  <FONT Color=gray>' ''int v4l2_munmap(void *start, size_t length)''
Riga 63: Riga 112:
 
   
 
   
 
   
 
   
  Library "<FONT Color=red>libc:6</font>"
+
  Public Sub Main()
 +
 +
  Dim buf As New V4l2_buffer
 +
  Dim req As New V4l2_requestbuffers
 +
  Dim buffers As Buffer[]
 +
  Dim tv As New Timeval
 +
  Dim fout As File
 +
  Dim fmt, p As Pointer
 +
  Dim st As Stream
 +
  Dim fd, r, width, height, pix, type As Integer
 +
  Dim ppm As String
 +
 +
  Write "\e[31m\e[5mAcquisizione immagini...\e[0m"
 +
  Flush
 +
 +
  fd = v4l2_open("/dev/video0", O_RDWR Or O_NONBLOCK, 0)
 +
 +
  fmt = Alloc(SizeOf(gb.Byte), 208)
 +
  st = Memory fmt 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, fmt)
 +
    If r = -1 Then Error.Raise("Errore !")
 +
  Until r > -1
 +
  Seek #st, 8
 +
  Read #st, width
 +
  Read #st, height
 +
  Read #st, pix
 +
  If (width <> 640) Or (height <> 480) Then Print "Attenzione: il dispositivo imposterà l'immagine alle dimensioni";; width; "x"; height
 +
  If pix <> V4L2_PIX_FMT_RGB24 Then Error.Raise("Libv4l non accetta il formato RGB24.\nImpossibile procedere !")
 +
  st.Close
 +
  Free(fmt)
 +
 +
  With req
 +
    .count = 1
 +
    .type = V4L2_BUF_TYPE_VIDEO_CAPTURE
 +
    .memory_ = V4L2_MEMORY_MMAP
 +
  End With
 +
  Repeat
 +
    r = v4l2_ioctl_request(fd, VIDIOC_REQBUFS, req)
 +
    If r = -1 Then Error.Raise("Errore !")
 +
  Until r > -1
 +
 +
  buffers = New Buffer[req.count]
 +
 +
  For n_buffers As Integer = 0 To req.count - 1
 +
    With buf
 +
      .index = n_buffers
 +
      .type = V4L2_BUF_TYPE_VIDEO_CAPTURE
 +
      .memory_ = V4L2_MEMORY_MMAP
 +
    End With
 +
    Repeat
 +
      r = v4l2_ioctl_buffer(fd, VIDIOC_QUERYBUF, buf)
 +
      If r = -1 Then Error.Raise("Errore !")
 +
    Until r > -1
 +
    With buffers[n_buffers] = New Buffer
 +
      .length = buf.length
 +
      .start = v4l2_mmap(Null, buf.length, PROT_READ Or PROT_WRITE, MAP_SHARED, fd, buf.m)
 +
    End With
 +
  Next
 +
 +
  For i As Integer = 0 To n_buffers - 1
 +
    With buf
 +
      .index = i
 +
      .type = V4L2_BUF_TYPE_VIDEO_CAPTURE
 +
      .memory_ = V4L2_MEMORY_MMAP
 +
    End With
 +
    Repeat
 +
      r = v4l2_ioctl_buffer(fd, VIDIOC_QBUF, buf)
 +
      If r = -1 Then Error.Raise("Errore !")
 +
    Until r > -1
 +
  Next
 +
  type = V4L2_BUF_TYPE_VIDEO_CAPTURE
 +
  Repeat
 +
    r = v4l2_ioctl_pointer(fd, VIDIOC_STREAMON, VarPtr(type))
 +
    If r = -1 Then Error.Raise("Errore !")
 +
  Until r > -1
 +
  Repeat
 +
    tv.tv_sec = 1
 +
    r = select_C(fd + 1, Null, Null, Null, tv)
 +
    If r = -1 Then Error.Raise("Errore !")
 +
  Until r > -1
 +
  buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE
 +
  buf.memory_ = V4L2_MEMORY_MMAP
 +
  Repeat
 +
    r = v4l2_ioctl_buffer(fd, VIDIOC_DQBUF, buf)
 +
    If r = -1 Then Error.Raise("Errore !")
 +
  Until r > -1
 
   
 
   
  Public Struct timeval
+
  ppm = "/tmp/V4L" &/ Format(Now, "dd-mm-yyyy_hh:nn:ss") & ".ppm"
  tv_sec As Long
+
  <FONT Color=gray>' ''Scrive i dati d'intestazione del file immagine PPM:''</font>
   tv_usec As Long
+
   File.Save(ppm, "P6\x0A" & CStr(width) & Chr(32) & CStr(height) & " 255\x0A")
End Struct
 
 
   
 
   
Private Enum O_RDONLY = 0, O_WRONLY, O_RDWR, O_NONBLOCK = &2000
+
  fout = Open ppm For Write Append
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)''
 
' ''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"
 
 
 
 
   
 
   
Public Sub Main()
+
  p = buffers[buf.index].start
 
+
  If p == 0 Then Error.Raise("Errore !")
  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
 
 
 
<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)
+
<FONT Color=gray>' ''Aggiunge i dati immagine al file PPM:''</font>
  If fd < 0 Then Error.Raise("Impossibile aprire il file-device !")
+
  Write #fout, p, buf.bytesused    <FONT Color=gray>'</font> <SUP>&#091;[[#Note|nota 1]]&#093;</sup>
     
 
  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
+
  fout.Close
    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 di memoria:''</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 di memoria:''</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 di memoria:''</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>
 
  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
+
  <FONT Color=gray>' ''Va in chiusura:''</font>
  Read #st, index
+
  i = V4L2_BUF_TYPE_VIDEO_CAPTURE
  st.Close
+
  Repeat
  <FONT Color=gray>' ''Dealloca l'area di memoria precedentemente riservata e si assicura che il Puntatore non punti ad un indirizzo rilevante di memoria:''</font>
+
    r = v4l2_ioctl_pointer(fd, VIDIOC_STREAMOFF, VarPtr(i))
  Free(p)
+
    If r = -1 Then Error.Raise("Errore !")
  p = 0
+
  Until r > -1
 
 
  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>
+
  For i = 0 To n_buffers - 1
  i = V4L2_BUF_TYPE_VIDEO_CAPTURE
+
    v4l2_munmap(buffers[i].start, buffers[i].length)
  Repeat
+
  Next
    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_close(fd)
    v4l2_munmap(buffers[i].start, buffers[i].length)
 
  Next
 
  v4l2_close(fd)
 
 
   
 
   
  Write "\rImmagine acquisita !"
+
  Write "\rAcquisite n. " & t & " immagini !"
 
   
 
   
 
  End
 
  End
 +
 +
 +
 +
=Note=
 +
[1] Per questo uso del Puntatore con ''WRITE'' vedere: https://www.gambas-it.org/wiki/index.php/Write#Scrivere_in_un_file_i_dati_contenuti_in_un.27area_di_memoria_puntata_da_un_Puntatore
  
  

Versione delle 09:05, 20 lug 2024

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'immagine sarà salvata in un file formato ppm:

Public Struct Buffer
  start As Pointer
  length As Integer
End Struct


Library "libc:6"

Public Struct timeval
  tv_sec As Long
  tv_usec As Long
End Struct

Public Struct v4l2_requestbuffers
  count As Integer
  type As Integer
  memory_ As Integer
  capabilities As Integer
  flags As Byte
  reserved[3] As Byte
End Struct

Public Struct v4l2_timecode
  type As Integer
  flags As Integer
  frames As Byte
  seconds As Byte
  minutes As Byte
  hours As Byte
  userbits[4] As Byte
End Struct

Public Struct v4l2_buffer
  index As Integer
  type As Integer
  bytesused As Integer
  flags As Integer
  field As Integer
  timestamp As Struct Timeval
  timecode As Struct V4l2_timecode
  sequence As Integer
  memory_ As Integer
  m As Long
  length As Integer
  reserved2 As Integer
  request_fd As Integer
End Struct

Private Enum O_RDONLY = 0, O_WRONLY, O_RDWR, O_NONBLOCK = &2000
Private Enum PROT_NONE = 0, PROT_READ, PROT_WRITE
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_VIDEO_OUTPUT_OVERLAY, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
             V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, V4L2_BUF_TYPE_SDR_CAPTURE, V4L2_BUF_TYPE_SDR_OUTPUT,
             V4L2_BUF_TYPE_META_CAPTURE, V4L2_BUF_TYPE_META_OUTPUT
Private Enum V4L2_FIELD_ANY, V4L2_FIELD_NONE, V4L2_FIELD_TOP, V4L2_FIELD_BOTTOM, V4L2_FIELD_INTERLACED,
             V4L2_FIELD_SEQ_TB, V4L2_FIELD_SEQ_BT, V4L2_FIELD_ALTERNATE, V4L2_FIELD_INTERLACED_TB,
             V4L2_FIELD_INTERLACED_BT
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 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_STREAMOFF As Long = 1074026003
Private Const VIDIOC_DQBUF As Long = 3227014673
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"

 
Library "libv4l2:0.0.0"

' 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_buffer(fd As Integer, request As Long, arg As V4l2_buffer) 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(start As Pointer, lengthI As Integer, prot As Integer, flags As Integer, fd As Integer, offset 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)


Public Sub Main()

  Dim buf As New V4l2_buffer
  Dim req As New V4l2_requestbuffers
  Dim buffers As Buffer[]
  Dim tv As New Timeval
  Dim fout As File
  Dim fmt, p As Pointer
  Dim st As Stream
  Dim fd, r, width, height, pix, type As Integer
  Dim ppm As String

  Write "\e[31m\e[5mAcquisizione immagini...\e[0m"
  Flush

  fd = v4l2_open("/dev/video0", O_RDWR Or O_NONBLOCK, 0)

  fmt = Alloc(SizeOf(gb.Byte), 208)
  st = Memory fmt 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, fmt)
    If r = -1 Then Error.Raise("Errore !")
  Until r > -1
  Seek #st, 8
  Read #st, width
  Read #st, height
  Read #st, pix
  If (width <> 640) Or (height <> 480) Then Print "Attenzione: il dispositivo imposterà l'immagine alle dimensioni";; width; "x"; height
  If pix <> V4L2_PIX_FMT_RGB24 Then Error.Raise("Libv4l non accetta il formato RGB24.\nImpossibile procedere !")
  st.Close
  Free(fmt)

  With req
    .count = 1
    .type = V4L2_BUF_TYPE_VIDEO_CAPTURE
    .memory_ = V4L2_MEMORY_MMAP
  End With 
  Repeat
    r = v4l2_ioctl_request(fd, VIDIOC_REQBUFS, req)
    If r = -1 Then Error.Raise("Errore !")
  Until r > -1

  buffers = New Buffer[req.count]

  For n_buffers As Integer = 0 To req.count - 1
    With buf
      .index = n_buffers
      .type = V4L2_BUF_TYPE_VIDEO_CAPTURE
      .memory_ = V4L2_MEMORY_MMAP
    End With 
    Repeat
      r = v4l2_ioctl_buffer(fd, VIDIOC_QUERYBUF, buf)
      If r = -1 Then Error.Raise("Errore !")
    Until r > -1
    With buffers[n_buffers] = New Buffer
      .length = buf.length
      .start = v4l2_mmap(Null, buf.length, PROT_READ Or PROT_WRITE, MAP_SHARED, fd, buf.m)
    End With
  Next

  For i As Integer = 0 To n_buffers - 1
    With buf
      .index = i
      .type = V4L2_BUF_TYPE_VIDEO_CAPTURE
      .memory_ = V4L2_MEMORY_MMAP
    End With 
    Repeat
      r = v4l2_ioctl_buffer(fd, VIDIOC_QBUF, buf)
      If r = -1 Then Error.Raise("Errore !")
    Until r > -1
  Next
  type = V4L2_BUF_TYPE_VIDEO_CAPTURE
  Repeat
    r = v4l2_ioctl_pointer(fd, VIDIOC_STREAMON, VarPtr(type))
    If r = -1 Then Error.Raise("Errore !")
  Until r > -1
  Repeat
    tv.tv_sec = 1
    r = select_C(fd + 1, Null, Null, Null, tv)
    If r = -1 Then Error.Raise("Errore !")
  Until r > -1
  buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE
  buf.memory_ = V4L2_MEMORY_MMAP
  Repeat
    r = v4l2_ioctl_buffer(fd, VIDIOC_DQBUF, buf)
    If r = -1 Then Error.Raise("Errore !")
  Until r > -1

  ppm = "/tmp/V4L" &/ Format(Now, "dd-mm-yyyy_hh:nn:ss") & ".ppm"
' Scrive i dati d'intestazione del file immagine PPM:
  File.Save(ppm, "P6\x0A" & CStr(width) & Chr(32) & CStr(height) & " 255\x0A")

  fout = Open ppm For Write Append 

  p = buffers[buf.index].start
  If p == 0 Then Error.Raise("Errore !")

' Aggiunge i dati immagine al file PPM:
  Write #fout, p, buf.bytesused    ' [nota 1]

  fout.Close


' Va in chiusura:
  i = V4L2_BUF_TYPE_VIDEO_CAPTURE
  Repeat
    r = v4l2_ioctl_pointer(fd, VIDIOC_STREAMOFF, VarPtr(i))
    If r = -1 Then Error.Raise("Errore !")
  Until r > -1

  For i = 0 To n_buffers - 1
    v4l2_munmap(buffers[i].start, buffers[i].length)
  Next

  v4l2_close(fd)

  Write "\rAcquisite n. " & t & " immagini !"

End


Note

[1] Per questo uso del Puntatore con WRITE vedere: https://www.gambas-it.org/wiki/index.php/Write#Scrivere_in_un_file_i_dati_contenuti_in_un.27area_di_memoria_puntata_da_un_Puntatore


Riferimenti