I am trying to understand how to use V4L2 and am writing my own camera driver in C. I have followed this tutorial mostly to get a feel for how V4L2 works, and have copied most of the code to implement my own here, I am however stuck at trying to get USB webcams working, I have got this code to work with the laptop's integrated webcam, just not external USB ones (Logitech c270 - works in OpenCV). Any help would be much appreciated.
The source code camera.c
is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
/* #include <SDL/SDL.h> */
/* #include <SDL/SDL_image.h> */
static int webcam_open(const char *webcam_dev)
{
int fd;
struct v4l2_capability cap;
fd = open(webcam_dev, O_RDWR);
if (fd < 0) {
perror("open");
exit(1);
}
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
perror("VIDIOC_QUERYCAP");
exit(1);
}
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
fprintf(stderr, "Device cannot handle single-planar video capture.n");
exit(1);
}
return fd;
}
static void *webcam_setup(int fd)
{
struct v4l2_format format;
struct v4l2_requestbuffers bufrequest;
struct v4l2_buffer bufferinfo;
void *buffer_start;
/* configure video format */
memset(&format, 0, sizeof(format));
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
format.fmt.pix.width = 800;
format.fmt.pix.height = 600;
format.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
format.fmt.pix.field = V4L2_FIELD_NONE;
if (ioctl(fd, VIDIOC_S_FMT, &format) < 0) {
perror("VIDIOC_S_FMT");
exit(1);
}
/* configure buffers */
memset(&bufrequest, 0, sizeof(bufrequest));
bufrequest.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufrequest.memory = V4L2_MEMORY_MMAP;
bufrequest.count = 1;
if (ioctl(fd, VIDIOC_REQBUFS, &bufrequest) < 0) {
perror("VIDIOC_REQBUFS");
exit(1);
}
/* allocate buffer */
memset(&bufferinfo, 0, sizeof(bufferinfo));
bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufferinfo.memory = V4L2_MEMORY_MMAP;
bufferinfo.index = 0;
if (ioctl(fd, VIDIOC_QUERYBUF, &bufferinfo) < 0) {
perror("VIDIOC_QUERYBUF");
exit(1);
}
// allocate memory map
buffer_start = mmap(
NULL,
bufferinfo.length,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
bufferinfo.m.offset
);
if (buffer_start == MAP_FAILED) {
perror("mmap");
exit(1);
}
memset(buffer_start, 0, bufferinfo.length);
return buffer_start;
}
static void webcam_stream(int fd, void *buffer_start)
{
int retval;
int buffer_type;
struct v4l2_buffer bufferinfo;
/* setup buffer info */
memset(&bufferinfo, 0, sizeof(bufferinfo));
bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufferinfo.memory = V4L2_MEMORY_MMAP;
bufferinfo.index = 0; /* queueing buffer index 0. */
/* queue buffer */
if (ioctl(fd, VIDIOC_QBUF, &bufferinfo) < 0){
perror("VIDIOC_QBUF");
exit(1);
}
/* activate streaming */
buffer_type = bufferinfo.type;
if (ioctl(fd, VIDIOC_STREAMON, &buffer_type) < 0){
perror("VIDIOC_STREAMON");
exit(1);
}
/* dequeue buffer */
if (ioctl(fd, VIDIOC_DQBUF, &bufferinfo) < 0){
perror("VIDIOC_QBUF");
exit(1);
}
/* printf("Length: %dnAddress: %pn", bufferinfo.length, buffer_start); */
/* printf("Image Length: %dn", bufferinfo.bytesused); */
/* save frame to file */
int jpgfile;
if ((jpgfile = open("test.jpg", O_WRONLY | O_CREAT)) < 0){
perror("open");
exit(1);
}
retval = write(jpgfile, buffer_start, bufferinfo.bytesused);
if (retval < 0) {
perror("write");
exit(1);
}
retval = close(jpgfile);
if (retval < 0) {
perror("close");
exit(1);
}
/* deactivate streaming */
if (ioctl(fd, VIDIOC_STREAMOFF, &buffer_type) < 0){
perror("VIDIOC_STREAMOFF");
exit(1);
}
}
int main()
{
int fd;
void *buffer_start;
// setup
fd = webcam_open("/dev/video0");
buffer_start = webcam_setup(fd);
webcam_stream(fd, buffer_start);
close(fd);
return 0;
}
To compile this code, simply run:
gcc camera.c -o camera
Note: I believe you may need V4L2 installed.
Aucun commentaire:
Enregistrer un commentaire