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 8: Riga 8:
 
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.
  
Funziona solo su sistemi a 64bit.
+
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'':

Versione delle 12:56, 6 lug 2015

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 seguente libreria dinamica 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:

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

Public Struct BUFFER
  start As Pointer
  length As Integer
End Struct

Public Struct timeval
  tv_sec As Long
  tv_usec As Long
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"

' 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 As String
 Dim 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
 
  dispositivo = "/dev/video0"
  file_ppm = "/tmp/immago.ppm"   ' Il percorso ove sarà salvato il file immagine ppm creato
  
  fd = v4l2_open(dispositivo, O_RDWR Or O_NONBLOCK, 0)
  If fd < 0 Then Error.Raise("Impossibile aprire il file-device !")
     
  p = Alloc(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

  Do
    r = v4l2_ioctl_pointer(fd, VIDIOC_S_FMT, p)
  Loop 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
  Free(p)

  With reqbuf
    .count = 2
    .type = V4L2_BUF_TYPE_VIDEO_CAPTURE
    .memory_ = V4L2_MEMORY_MMAP
  End With

       
  Do
    r = v4l2_ioctl_request(fd, VIDIOC_REQBUFS, reqbuf)
  Loop Until r > -1
  If r = -1 Then Error.Raise("Errore !")


  p = Alloc(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

    Do
      r = v4l2_ioctl_pointer(fd, VIDIOC_QUERYBUF, p)
    Loop 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
  Free(p)

  
  p = Alloc(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
    Do
      r = v4l2_ioctl_pointer(fd, VIDIOC_QBUF, p)
    Loop Until r > -1
    If r = -1 Then Error.Raise("Errore !")
  Next
  st.Close
  Free(p)

  i = V4L2_BUF_TYPE_VIDEO_CAPTURE
  Do
    r = v4l2_ioctl_pointer(fd, VIDIOC_STREAMON, VarPtr(i))
  Loop Until r > -1
  If r = -1 Then Error.Raise("Errore !")

       
  Do
    tv.tv_sec = 1
    r = select_C(fd + 1, Null, Null, Null, tv)
  Loop Until r > -1
  If r = -1 Then Error.Raise("Errore !")

  p = Alloc(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
  Do
    r = v4l2_ioctl_pointer(fd, VIDIOC_DQBUF, p)
  Loop 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
  Free(p)
  
  p = buffers[index].start
  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
  Do
    r = v4l2_ioctl_pointer(fd, VIDIOC_STREAMON, VarPtr(i))
  Loop 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)
 
End



Riferimenti