Programar em C para conecção USB (libusb-1.0)

Iniciado por edjin, 04 de Março de 2016, 16:06

tópico anterior - próximo tópico

edjin

Bom dia a todos, estive lendo sobre a libusb-1.0 para linux, e gostaria de escrever um simples programa com linguagem C que, quando executado pelo terminal devolvesse um arquivo de fotografia em qualquer formato na pasta corrente a partir de uma webcam (já listei bus, drivers, endereços de endpoint entre outros) não entendi como proceder com essa comunicação.

obrigado.


irtigor

Pra isso existe a API V4L2. Dependendo do que realmente deseja pode compensar usar algo como o opencv, no lugar de usar V4L2 diretamente.

edjin

Ótima diga amigo irtigor, estarei enviando resultado dos testes na programação. Obrigado.

edjin

Boa tarde a todos, fiz alguns testes com esse código sem sucesso, o tamanho do arquivo continua em 0 bytes, provavelmente alguma configuração mal feita nas structs... pois o arquivo compilado roda normal, e na compilação o gcc não retorna nenhuma mensagem de warning (?)

Comando utilizado para compilação.
gcc -o <nome-do-programa> -Wall -g -O2 <nome-arquivo.c>

Sei que a maioria do pessoal conhece bem o gcc, mas pra quem ainda não observou o man, aqui algumas dicas)

Observações para linha de comando:

"-Wall" todas as mensagens de erro e warming do compilador gcc.
"-g"        gera símbolos para depuração com gdb.
"-O2"     nível 2 de otimização do código na compilação.

segue abaixo código testado:

#include <errno.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>

uint8_t *buffer;

static int xioctl(int fd, int request, void *arg)
{
int r;

do r = ioctl (fd, request, arg);
while (-1 == r && EINTR == errno);
return r;
}

int print_caps(int fd)
{
struct v4l2_capability caps = {};

if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &caps))
{
perror("Querying Capabilities");
return 1;
}

printf( "Driver Caps:\n"
"  Driver: \"%s\"\n"
"  Card: \"%s\"\n"
"  Bus: \"%s\"\n"
"  Version: %d.%d\n"
"  Capabilities: %08x\n",
caps.driver,
caps.card,
caps.bus_info,
(caps.version>>16)&&0xff,
(caps.version>>24)&&0xff,
caps.capabilities);

struct v4l2_cropcap cropcap = {0};
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

if (-1 == xioctl (fd, VIDIOC_CROPCAP, &cropcap))
{
perror("Querying Cropping Capabilities");
return 1;
}

printf( "\nCamera Cropping:\n"
"  Bounds: %dx%d+%d+%d\n"
"  Default: %dx%d+%d+%d\n"
"  Aspect: %d/%d\n",
cropcap.bounds.width, cropcap.bounds.height, cropcap.bounds.left, cropcap.bounds.top,
cropcap.defrect.width, cropcap.defrect.height, cropcap.defrect.left, cropcap.defrect.top,
cropcap.pixelaspect.numerator, cropcap.pixelaspect.denominator);

int support_grbg10 = 0;

struct v4l2_fmtdesc fmtdesc = {0};
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
       
char fourcc[5] = {0};
char c, e;
       
printf("\n  FMT : CE Desc\n--------------------\n");

while (0 == xioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc))
{
strncpy(fourcc, (char *)&fmtdesc.pixelformat, 4);

if (fmtdesc.pixelformat == V4L2_PIX_FMT_SGRBG10)
support_grbg10 = 1;
                   
c = fmtdesc.flags & 1? 'C' : ' ';
e = fmtdesc.flags & 2? 'E' : ' ';
               
printf("  %s: %c%c %s\n", fourcc, c, e, fmtdesc.description);
fmtdesc.index++;
}

/*
if (!support_grbg10)
{
printf("Doesn't support GRBG10.\n");
return 1;
}
*/

struct v4l2_format fmt = {0};
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/*
fmt.fmt.pix.width = 752;
fmt.fmt.pix.height = 480;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SGRBG10;
fmt.fmt.pix.field = V4L2_FIELD_NONE;
*/
fmt.fmt.pix.width = 640;
fmt.fmt.pix.height = 480;
//fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
//fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_GREY;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
fmt.fmt.pix.field = V4L2_FIELD_NONE;

if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
{
perror("Setting Pixel Format");
return 1;
}

strncpy(fourcc, (char *)&fmt.fmt.pix.pixelformat, 4);
printf( "Selected Camera Mode:\n"
"  Width: %d\n"
"  Height: %d\n"
"  PixFmt: %s\n"
"  Field: %d\n",
fmt.fmt.pix.width,
fmt.fmt.pix.height,
fourcc,
fmt.fmt.pix.field);

return 0;
}

int init_mmap(int fd)
{
    struct v4l2_requestbuffers req = {0};
    req.count = 1;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;

    if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req))
    {
        perror("Requesting Buffer");
        return 1;
    }

    struct v4l2_buffer buf = {0};
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = 0;
    if(-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
    {
        perror("Querying Buffer");
        return 1;
    }

    buffer = mmap (NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
    printf("Length: %d\nAddress: %p\n", buf.length, buffer);
    printf("Image Length: %d\n", buf.bytesused);

    return 0;
}

int capture_image(int fd)
{
    struct v4l2_buffer buf = {0};
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = 0;
   
    if(-1 == xioctl(fd, VIDIOC_QBUF, &buf))
    {
        perror("Query Buffer");
        return 1;
    }

    if(-1 == xioctl(fd, VIDIOC_STREAMON, &buf.type))
    {
        perror("Start Capture");
        return 1;
    }

    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(fd, &fds);
    struct timeval tv = {0};
    tv.tv_sec = 2;

   
    int r = select(fd+1, &fds, NULL, NULL, &tv);
    if(-1 == r)
    {
        perror("Waiting for Frame");
        return 1;
    }

    if(-1 == xioctl(fd, VIDIOC_DQBUF, &buf))
    {
        perror("Retrieving Frame");
        return 1;
    }

    //int outfd = open("out.img", O_RDWR);
    int outfd = open("out.jpeg", O_RDWR);
    write(outfd, buffer, buf.bytesused);
    close(outfd);
   
    if(-1 == xioctl(fd, VIDIOC_STREAMOFF, &buf.type))
    {
        perror("OFF Capture");
        return 1;
    }

    return 0;
}

int main()
{
int fd;

fd = open("/dev/video0", O_RDWR);
if (fd == -1) {
perror("Opening video device");
return 1;
}

if(print_caps(fd))
return 1;
           
if(init_mmap(fd))
return 1;
           
if(capture_image(fd))
return 1;

close(fd);
       
return 0;
}





Desde já agradeço, aguardando perguntas e respostas dos leitores.
Abraço.