videocapture raspicam raspberry c++ linux raspberry-pi v4l2 raspberry-pi2

c++ - raspicam - raspberry pi camera streaming python



¿Es posible obtener buenos FPS usando la cámara Raspberry Pi v4l2 en c++? (2)

He estado observando los diversos métodos de uso de la picamera y no soy un experto, pero parece que la configuración predeterminada de la cámara es lo que te frena. Hay muchos modos e interruptores. No sé si están expuestos a través de ioctls o cómo todavía, recién comencé. Pero tuve que usar un programa llamado v4l-ctl para preparar las cosas para el modo que quería. Una mirada profunda a esa fuente y el levantamiento de algunos códigos deberían permitirle alcanzar la grandeza. Ah, y dudo que la llamada selectiva sea un problema, simplemente está esperando el descriptor que tarda en hacerse legible. Dependiendo del modo, etc. puede haber una espera obligatoria para la exposición automática, etc. Editar: Quise decir "una configuración predeterminada" ya que ha cambiado un poco. También hay reglas no codificadas en el controlador.

Intento transmitir video en una Raspberry Pi usando el controlador oficial V4L2 con la cámara Raspberry Pi, desde C ++ en raspbian (versión 2015-02), y tengo problemas de FPS bajos.

Actualmente solo estoy creando una ventana y copiando el búfer a la pantalla (que tarda unos 30 ms) mientras que la select() tarda unos 140 ms (para un total de 5-6 fps). También traté de dormir durante 100 ms y disminuye el tiempo de select() en una cantidad similar (lo que da como resultado el mismo fps). La carga de la CPU es de aproximadamente 5-15%.

También traté de cambiar el controlador fps de la consola (o system() ) pero solo funciona hacia abajo (por ejemplo, si configuro los fps del controlador a 1 fps, obtendré 1 fps pero si lo configuro a 90 fps aún obtendré 5 6 fps, aunque el controlador confirma configurarlo a 90 fps). Además, al consultar los modos FPS para la resolución utilizada, obtengo 90 fps.

Incluí las partes del código relacionadas con V4L2 (código omitido entre las diferentes partes):

////////////////// // Open device ////////////////// mFD = open(mDevName, O_RDWR | O_NONBLOCK, 0); if (mFD == -1) ErrnoExit("Open device failed"); ////////////////// // Setup format ////////////////// struct v4l2_format fmt; memset(&fmt, 0, sizeof(fmt)); fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; Xioctl(VIDIOC_G_FMT, &fmt); mImgWidth = fmt.fmt.pix.width; mImgHeight = fmt.fmt.pix.height; cout << "width=" << mImgWidth << " height=" << mImgHeight << "/nbytesperline=" << fmt.fmt.pix.bytesperline << " sizeimage=" << fmt.fmt.pix.sizeimage << "/n"; // For some reason querying the format always sets pixelformat to JPEG // no matter the input, so set it back to YUYV fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; if (Xioctl(VIDIOC_S_FMT, &fmt) == -1) { cout << "Set video format failed : " << strerror(errno) << "/n"; } ////////////////// // Setup streaming ////////////////// struct v4l2_requestbuffers req; memset(&req, 0, sizeof(req)); req.count = 20; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; if (-1 == Xioctl(VIDIOC_REQBUFS, &req)) { ErrnoExit("Reqbufs"); } if (req.count < 2) throw "Not enough buffer memory !"; mNBuffers = req.count; mBuffers = new CBuffer[mNBuffers]; if (!mBuffers) throw "Out of memory !"; for (unsigned int i = 0; i < mNBuffers; i++) { struct v4l2_buffer buf; memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; if (-1 == Xioctl(VIDIOC_QUERYBUF, &buf)) ErrnoExit("Querybuf"); mBuffers[i].mLength = buf.length; mBuffers[i].pStart = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, mFD, buf.m.offset); if (mBuffers[i].pStart == MAP_FAILED) ErrnoExit("mmap"); } ////////////////// // Start streaming ////////////////// unsigned int i; enum v4l2_buf_type type; struct v4l2_buffer buf; for (i = 0; i < mNBuffers; i++) { memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; if (-1 == Xioctl(VIDIOC_QBUF, &buf)) ErrnoExit("QBUF"); } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1==Xioctl(VIDIOC_STREAMON, &type)) ErrnoExit("STREAMON");

Y las dos últimas partes en el ciclo principal:

////////////////// // Get frame ////////////////// FD_ZERO(&fds); FD_SET(mFD, &fds); tv.tv_sec = 3; tv.tv_usec = 0; struct timespec t0, t1; clock_gettime(CLOCK_REALTIME, &t0); // This line takes about 140ms which I don''t get r = select(mFD + 1, &fds, NULL, NULL, &tv); clock_gettime(CLOCK_REALTIME, &t1); cout << "select time : " << ((float)(t1.tv_sec - t0.tv_sec))*1000.0f + ((float)(t1.tv_nsec - t0.tv_nsec))/1000000.0f << "/n"; if (-1 == r) { if (EINTR == errno) continue; ErrnoExit("select"); } if (r == 0) throw "Select timeout/n"; // Read the frame //~ struct v4l2_buffer buf; memset(&mCurBuf, 0, sizeof(mCurBuf)); mCurBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; mCurBuf.memory = V4L2_MEMORY_MMAP; // DQBUF about 2ms if (-1 == Xioctl(VIDIOC_DQBUF, &mCurBuf)) { if (errno == EAGAIN) continue; ErrnoExit("DQBUF"); } clock_gettime(CLOCK_REALTIME, &mCaptureTime); // Manage frame in mBuffers[buf.index] mCurBufIndex = mCurBuf.index; break; } ////////////////// // Release frame ////////////////// if (-1 == Xioctl(VIDIOC_QBUF, &mCurBuf)) ErrnoExit("VIDIOC_QBUF during mainloop");


El formato de pixel importa. Encontré el problema similar de baja fps, y pasé algún tiempo probando usando mi programa en Go y C ++ usando la API V4L2. Lo que encontré es que Rpi Cam Module tiene buena aceleración con H.264 / MJPG pixelformat. Puedo obtener fácilmente 60 fps a 640 * 480, lo mismo que formatos no comprimidos como YUYV / RGB. Sin embargo, JPEG funciona muy lento. Solo puedo obtener 4fps incluso a 320 * 240. Y también encontré que la corriente es mayor (> 700 mA) con JPEG en comparación con 500 mA con H.264 / MJPG.