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 6: Riga 6:
 
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'immagine sarà salvata in un file formato ''ppm'':
+
L'immagine sarà salvata in un file immagine di formato "PPM":
 
  Public Struct Buffer
 
  Public Struct Buffer
 
   start As Pointer
 
   start As Pointer

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 immagine di 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