Hi all, I recently bought a webcam C200 (logitech) for use with the mini2440. I modified the example from v4l2 website (capture.c) to save images. My problem is that when the program is run on the mini2440, the maximal resolution allowed by the driver is 176*144. If the program is run on my PC it's 640*480. I think the problem is from usb1.1 on 2440 and usb2 on my PC. Am i correct? Has someone be able (with a UVC camera) to work with resolution higher than 176*144 ? If yes, which model? Thanks,
Webcam and maximal resolution using v4l2
up :) has nobody be able to capture images greater than 176*144 with a usb webcam on mini2440 ? Thanks for help.
Could you please send me the code? I'm trying to understand how to work on those pictures, without results. I tried to save the output directly on a file, but then the file was not usable by other programs. It would be very useful for me! Please! Thank you, bye!
yes i can but i need an email or something to send to. Do you want the YUV or MJPEG code? Because of the usb1.1 on the mini2440 i dropped my YUV capture project and moved to MJPEG (which is more complicated).
You can send the code to this address: gorillarapito@yahoo.it Thank you very much! I'm not sure on which of the two I need... Could you send me both? What I need is mainly: to understand how to use the output of capture.c; after that I will try to process the images read from the webcam directly (and eventually saving to file after processing). The reason is that I'm studying a bit of computer vision and I want to try some (very) simple things directly on my webcam. Thank you again! :)
Hi! I read some paragraphs of the V4L2 specification guide and I solved my problem! I could save one frame in a BMP file! I succeeded in my goal! I don't need your code anymore... However I thank you for your availability! And I hope you will succeed in your purpose, too! Bye bye!
Hi Berello, I'm trying to get a capture in YUV format from web cam without success. I need to show the frame on LCD 3.5" using framebuffer. In this case I need the image to be in RGB565 format. Could you help me ? Thanks
I'm sorry but I cannot help you. I know almost nothing about codecs: I solved my problem because there were instructions (and a description of the codecs I needed) in this PDF: http://v4l2spec.bytesex.org/v4l2spec/v4l2.pdf At first impact, that file doesn't seem very friendly; but reading it from the first page, you understand the fundamentals of V4L2 and then you can jump to the subject of your interest. It will be easier than you think. Probably, there you can find a description of every codec supported by V4L2, maybe your RGB565 too. However I suppose that my code to save a "grey scale" bitmap could be useful for you; with a few changes you can convert it to a colour bitmap (which I suppose similar to the codec you're looking for). I'll send you the code in a next message or eventually by e-mail. Don't ask me anything about the code, except about the function "process_image", which is the only part I wrote. The rest of the code has been taken from: http://v4l2spec.bytesex.org/v4l2spec/capture.c and I cannot tell you anything about it. However in the PDF I mentioned before, you can find explanations for everything in that code. About my code (process_image function): I read in the PDF I mentioned before about the structure of YUYV (which is very very similar to YUV) and I learned that it has one grey scale byte (Y), followed by one blue channel byte (U), then one grey scale byte (Y again) and finally one red channel byte (V). The 2 grey scale bytes are 2 different pixels. The 2 colours (blue and red) refer to both pixels and are the same for both pixels. What I do in my code is: copying all the Y bytes (and ignoring all U and V bytes). It is done in lines 130-133 (it's a loop, just after the line "char *bmp_data = ..."): as you can see, through "(2 * tmp)" I take only even bytes (passing over odd bytes, which are U and V bytes), which is only the grey scale part of my image. If you are interested in colours, too, you can change my code, making it consider U and V bytes too (and you can compute the green channel, knowing that the grey channel contains R+G+B... Probably GREEN = (3*Y-(U+V)), but I'm not sure about the "3", just read the PDF). The rest of the code in "process_image" is just the creation of the header of the bitmap (which, as I suppose, is not of your interest) and its writing in a file. Now I'll send you the code! I hope it will be helpful and useful!
/* * V4L2 video capture example * * This program can be used and distributed without restrictions. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <getopt.h> /* getopt_long() */ #include <fcntl.h> /* low-level i/o */ #include <unistd.h> #include <errno.h> #include <malloc.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/time.h> #include <sys/mman.h> #include <sys/ioctl.h> #include <asm/types.h> /* for videodev2.h */ #include <linux/videodev2.h> #define CLEAR(x) memset (&(x), 0, sizeof (x)) #define WIDTH 640 #define HEIGHT 480 typedef enum { IO_METHOD_READ, IO_METHOD_MMAP, IO_METHOD_USERPTR, } io_method; struct buffer { void * start; size_t length; }; static char * dev_name = NULL; static io_method io = IO_METHOD_MMAP; static int fd = -1; struct buffer * buffers = NULL; static unsigned int n_buffers = 0; static void errno_exit (const char * s) { fprintf (stderr, "%s error %d, %s\n", s, errno, strerror (errno)); exit (EXIT_FAILURE); } static int xioctl (int fd, int request, void * arg) { int r; do r = ioctl (fd, request, arg); while (-1 == r && EINTR == errno); return r; } static void process_image (const void * p) { int tmp; short int tmp_short; char *yuyv_img = (char *) p; char *bmp_fileheader = malloc(sizeof(char) * 14); /* "BM" */ *(bmp_fileheader) = 'B'; *(bmp_fileheader + 1) = 'M'; /* Dimensione del file */ tmp = 14 + 40 + 256 * 4 + WIDTH * HEIGHT; memcpy((bmp_fileheader+2), &tmp, 4); /* 0 */ tmp = 0; memcpy((bmp_fileheader+6), &tmp, 4); /* Offset mappa */ tmp = 14 + 40 + 256 * 4; memcpy((bmp_fileheader+10), &tmp, 4); char *bmp_infoheader = malloc(sizeof(char) * 40); /* 40 */ tmp = 40; memcpy(bmp_infoheader, &tmp, 4); /* Larghezza */ tmp = WIDTH; memcpy(bmp_infoheader + 4, &tmp, 4); /* Altezza */ tmp = -HEIGHT; memcpy(bmp_infoheader + 8, &tmp, 4); /* 1 */ tmp_short = 1; memcpy(bmp_infoheader + 12, &tmp_short, 2); /* bpp */ tmp_short = 8; memcpy(bmp_infoheader + 14, &tmp_short, 2); /* 0 = nessuna compressione */ tmp = 0; memcpy(bmp_infoheader + 16, &tmp, 4); /* 0 se non c'è compressione */ memcpy(bmp_infoheader + 20, &tmp, 4); /* 0 = pixel/m orizzontali del dispositivo non specificati */ memcpy(bmp_infoheader + 24, &tmp, 4); /* 0 = pixel/m verticali del dispositivo non specificati */ memcpy(bmp_infoheader + 28, &tmp, 4); /* 0 = usa tutte le corrispondenze della tavolozza */ memcpy(bmp_infoheader + 32, &tmp, 4); /* 0 = usa tutti i colori della tavolozza */ memcpy(bmp_infoheader + 36, &tmp, 4); char *bmp_colortable = malloc(256 * 4 * sizeof(char)); for (tmp = 0; tmp < 256; tmp++) { *(bmp_colortable + 4 * tmp) = tmp; *(bmp_colortable + 4 * tmp + 1) = tmp; *(bmp_colortable + 4 * tmp + 2) = tmp; *(bmp_colortable + 4 * tmp + 3) = 0; } char *bmp_data = malloc(WIDTH * HEIGHT * sizeof(char)); for (tmp = 0; tmp < (WIDTH * HEIGHT * sizeof(char)); tmp++) { *(bmp_data + tmp) = *(yuyv_img + (2 * tmp)); } printf("NO\n"); FILE *filebmp = fopen("Webcam.bmp", "w"); for (tmp = 0; tmp < 14; tmp++) { putc(*(bmp_fileheader + tmp), filebmp); } for (tmp = 0; tmp < 40; tmp++) { putc(*(bmp_infoheader + tmp), filebmp); } for (tmp = 0; tmp < (256 * 4 * sizeof(char)); tmp++) { putc(*(bmp_colortable + tmp), filebmp); } for (tmp = 0; tmp < (WIDTH * HEIGHT * sizeof(char)); tmp++) { putc(*(bmp_data + tmp), filebmp); } fflush(filebmp); fclose(filebmp); free(bmp_fileheader); free(bmp_infoheader); free(bmp_colortable); free(bmp_data); fputc ('.', stdout); fflush (stdout); } static int read_frame (void) { struct v4l2_buffer buf; unsigned int i; switch (io) { case IO_METHOD_READ: if (-1 == read (fd, buffers[0].start, buffers[0].length)) { switch (errno) { case EAGAIN: return 0; case EIO: /* Could ignore EIO, see spec. */ /* fall through */ default: errno_exit ("read"); } } process_image (buffers[0].start); break; case IO_METHOD_MMAP: CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) { switch (errno) { case EAGAIN: return 0; case EIO: /* Could ignore EIO, see spec. */ /* fall through */ default: errno_exit ("VIDIOC_DQBUF"); } } assert (buf.index < n_buffers); process_image (buffers[buf.index].start); if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) errno_exit ("VIDIOC_QBUF"); break; case IO_METHOD_USERPTR: CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_USERPTR; if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) { switch (errno) { case EAGAIN: return 0; case EIO: /* Could ignore EIO, see spec. */ /* fall through */ default: errno_exit ("VIDIOC_DQBUF"); } } for (i = 0; i < n_buffers; ++i) if (buf.m.userptr == (unsigned long) buffers[i].start && buf.length == buffers[i].length) break; assert (i < n_buffers); process_image ((void *) buf.m.userptr); if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) errno_exit ("VIDIOC_QBUF"); break; } return 1; } static void mainloop (void) { unsigned int count; count = 1; while (count-- > 0) { for (;;) { fd_set fds; struct timeval tv; int r; FD_ZERO (&fds); FD_SET (fd, &fds); /* Timeout. */ tv.tv_sec = 2; tv.tv_usec = 0; r = select (fd + 1, &fds, NULL, NULL, &tv); if (-1 == r) { if (EINTR == errno) continue; errno_exit ("select"); } if (0 == r) { fprintf (stderr, "select timeout\n"); exit (EXIT_FAILURE); } if (read_frame ()) break; /* EAGAIN - continue select loop. */ } } } static void stop_capturing (void) { enum v4l2_buf_type type; switch (io) { case IO_METHOD_READ: /* Nothing to do. */ break; case IO_METHOD_MMAP: case IO_METHOD_USERPTR: type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &type)) errno_exit ("VIDIOC_STREAMOFF"); break; } } static void start_capturing (void) { unsigned int i; enum v4l2_buf_type type; switch (io) { case IO_METHOD_READ: /* Nothing to do. */ break; case IO_METHOD_MMAP: for (i = 0; i < n_buffers; ++i) { struct v4l2_buffer buf; CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) errno_exit ("VIDIOC_QBUF"); } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl (fd, VIDIOC_STREAMON, &type)) errno_exit ("VIDIOC_STREAMON"); break; case IO_METHOD_USERPTR: for (i = 0; i < n_buffers; ++i) { struct v4l2_buffer buf; CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_USERPTR; buf.index = i; buf.m.userptr = (unsigned long) buffers[i].start; buf.length = buffers[i].length; if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) errno_exit ("VIDIOC_QBUF"); } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl (fd, VIDIOC_STREAMON, &type)) errno_exit ("VIDIOC_STREAMON"); break; } } static void uninit_device (void) { unsigned int i; switch (io) { case IO_METHOD_READ: free (buffers[0].start); break; case IO_METHOD_MMAP: for (i = 0; i < n_buffers; ++i) if (-1 == munmap (buffers[i].start, buffers[i].length)) errno_exit ("munmap"); break; case IO_METHOD_USERPTR: for (i = 0; i < n_buffers;...stripped-down
static void uninit_device (void) { unsigned int i; switch (io) { case IO_METHOD_READ: free (buffers[0].start); break; case IO_METHOD_MMAP: for (i = 0; i < n_buffers; ++i) if (-1 == munmap (buffers[i].start, buffers[i].length)) errno_exit ("munmap"); break; case IO_METHOD_USERPTR: for (i = 0; i < n_buffers; ++i) free (buffers[i].start); break; } free (buffers); } static void init_read (unsigned int buffer_size) { buffers = calloc (1, sizeof (*buffers)); if (!buffers) { fprintf (stderr, "Out of memory\n"); exit (EXIT_FAILURE); } buffers[0].length = buffer_size; buffers[0].start = malloc (buffer_size); if (!buffers[0].start) { fprintf (stderr, "Out of memory\n"); exit (EXIT_FAILURE); } } static void init_mmap (void) { struct v4l2_requestbuffers req; CLEAR (req); req.count = 4; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) { if (EINVAL == errno) { fprintf (stderr, "%s does not support " "memory mapping\n", dev_name); exit (EXIT_FAILURE); } else { errno_exit ("VIDIOC_REQBUFS"); } } if (req.count < 2) { fprintf (stderr, "Insufficient buffer memory on %s\n", dev_name); exit (EXIT_FAILURE); } buffers = calloc (req.count, sizeof (*buffers)); if (!buffers) { fprintf (stderr, "Out of memory\n"); exit (EXIT_FAILURE); } for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { struct v4l2_buffer buf; CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = n_buffers; if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &buf)) errno_exit ("VIDIOC_QUERYBUF"); buffers[n_buffers].length = buf.length; buffers[n_buffers].start = mmap (NULL /* start anywhere */, buf.length, PROT_READ | PROT_WRITE /* required */, MAP_SHARED /* recommended */, fd, buf.m.offset); if (MAP_FAILED == buffers[n_buffers].start) errno_exit ("mmap"); } } static void init_userp (unsigned int buffer_size) { struct v4l2_requestbuffers req; unsigned int page_size; page_size = getpagesize (); buffer_size = (buffer_size + page_size - 1) & ~(page_size - 1); CLEAR (req); req.count = 4; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_USERPTR; if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) { if (EINVAL == errno) { fprintf (stderr, "%s does not support " "user pointer i/o\n", dev_name); exit (EXIT_FAILURE); } else { errno_exit ("VIDIOC_REQBUFS"); } } buffers = calloc (4, sizeof (*buffers)); if (!buffers) { fprintf (stderr, "Out of memory\n"); exit (EXIT_FAILURE); } for (n_buffers = 0; n_buffers < 4; ++n_buffers) { buffers[n_buffers].length = buffer_size; buffers[n_buffers].start = memalign (/* boundary */ page_size, buffer_size); if (!buffers[n_buffers].start) { fprintf (stderr, "Out of memory\n"); exit (EXIT_FAILURE); } } } static void init_device (void) { struct v4l2_capability cap; struct v4l2_cropcap cropcap; struct v4l2_crop crop; struct v4l2_format fmt; unsigned int min; if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap)) { if (EINVAL == errno) { fprintf (stderr, "%s is no V4L2 device\n", dev_name); exit (EXIT_FAILURE); } else { errno_exit ("VIDIOC_QUERYCAP"); } } if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { fprintf (stderr, "%s is no video capture device\n", dev_name); exit (EXIT_FAILURE); } switch (io) { case IO_METHOD_READ: if (!(cap.capabilities & V4L2_CAP_READWRITE)) { fprintf (stderr, "%s does not support read i/o\n", dev_name); exit (EXIT_FAILURE); } break; case IO_METHOD_MMAP: case IO_METHOD_USERPTR: if (!(cap.capabilities & V4L2_CAP_STREAMING)) { fprintf (stderr, "%s does not support streaming i/o\n", dev_name); exit (EXIT_FAILURE); } break; } /* Select video input, video standard and tune here. */ CLEAR (cropcap); cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) { crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; crop.c = cropcap.defrect; /* reset to default */ if (-1 == xioctl (fd, VIDIOC_S_CROP, &crop)) { switch (errno) { case EINVAL: /* Cropping not supported. */ break; default: /* Errors ignored. */ break; } } } else { /* Errors ignored. */ } CLEAR (fmt); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = WIDTH; fmt.fmt.pix.height = HEIGHT; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt)) errno_exit ("VIDIOC_S_FMT"); /* Note VIDIOC_S_FMT may change width and height. */ /* Buggy driver paranoia. */ min = fmt.fmt.pix.width * 2; if (fmt.fmt.pix.bytesperline < min) fmt.fmt.pix.bytesperline = min; min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; if (fmt.fmt.pix.sizeimage < min) fmt.fmt.pix.sizeimage = min; switch (io) { case IO_METHOD_READ: init_read (fmt.fmt.pix.sizeimage); break; case IO_METHOD_MMAP: init_mmap (); break; case IO_METHOD_USERPTR: init_userp (fmt.fmt.pix.sizeimage); break; } } static void close_device (void) { if (-1 == close (fd)) errno_exit ("close"); fd = -1; } static void open_device (void) { struct stat st; if (-1 == stat (dev_name, &st)) { fprintf (stderr, "Cannot identify '%s': %d, %s\n", dev_name, errno, strerror (errno)); exit (EXIT_FAILURE); } if (!S_ISCHR (st.st_mode)) { fprintf (stderr, "%s is no device\n", dev_name); exit (EXIT_FAILURE); } fd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0); if (-1 == fd) { fprintf (stderr, "Cannot open '%s': %d, %s\n", dev_name, errno, strerror (errno)); exit (EXIT_FAILURE); } } static void usage (FILE * fp, int argc, char ** argv) { fprintf (fp, "Usage: %s [options]\n\n" "Options:\n" "-d | --device name Video device name [/dev/video]\n" "-h | --help Print this message\n" "-m | --mmap Use memory mapped buffers\n" "-r | --read Use read() calls\n" "-u | --userp Use application allocated buffers\n" "", argv[0]); } static const char short_options [] = "d:hmru"; static const struct option long_options [] = { { "device", required_argument, NULL, 'd' }, { "help", no_argument, NULL, 'h' }, { "mmap", no_argument, NULL, 'm' }, { "read", no_argument, NULL, 'r' }, { "userp", no_argument, NULL, 'u' }, { 0, 0, 0, 0 } }; int main (int argc, char ** ...stripped-down
Nothing, I cannot send you the code here. If you send me your e-mail address, I'll send it to you. Otherwise try to put together the code I sent here with this other: http://v4l2spec.bytesex.org/v4l2spec/capture.c ... If you don't want to send your e-mail address here, where everybody can read it, you can send it to my e-mail address (which I posted previously). Bye, Berello
Ok, I saw that the third and last part of the code is very short, for this reason I'm sending it here (overall for who, in the future, will need the whole code). You can ask me the code by e-mail, this way it will be easier to save it on your computer (no collages needed! :-P ). int main (int argc, char ** argv) { dev_name = "/dev/video"; for (;;) { int index; int c; c = getopt_long (argc, argv, short_options, long_options, &index); if (-1 == c) break; switch (c) { case 0: /* getopt_long() flag */ break; case 'd': dev_name = optarg; break; case 'h': usage (stdout, argc, argv); exit (EXIT_SUCCESS); case 'm': io = IO_METHOD_MMAP; break; case 'r': io = IO_METHOD_READ; break; case 'u': io = IO_METHOD_USERPTR; break; default: usage (stderr, argc, argv); exit (EXIT_FAILURE); } } open_device (); init_device (); start_capturing (); mainloop (); stop_capturing (); uninit_device (); close_device (); exit (EXIT_SUCCESS); return 0; }
Hi, I run your code and I only get a bad frame. I opened the bmp image on PC machine and it only shows a lot of black and white horizontal lines. I changed your process_image function and I get 100 captures but all are the same. Did you open your bmp image on PC machine and look fine ? P.S. I sent you a mail. Thanks
Hi Neyna, I'm trying to get a capture with resolution 176x144 but it's automatically reset to 320x240 and the image type is JPG. Do you know why it's dropped ? The best type of capture what I want to get is RGB565 but I'm also glad with YUV or BMP, just compressed no. The resolution is not significant for me, 176x144 it's ok. Could you send me your code ? Thanks
I've got the same problem with my logitech webcam: Enable to set frame size upper 176x144. So when I'm doing lsusb command I've got : Bus 001 Device 003: ID 046d:080f Logitech, Inc. Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub In arm processor specification is written 1.1 too. With another webcam, I can take mutch sizer image but in jpeg format: ID 0ac8:307b Z-Star Microelectronics Corp. USB 1.1 WebCam
I'm using Logitech C270 and I ran into the same problem. I'm using the fswebcam program and with kernel 3.2.9 I was able to get YUYV with resolution 1280x960 but with kernel 3.5.7 only that pity 176x144 and the palette color channels are also wrong. The fswebcam application was using old kernel headers with a static file videodev2.h included in the sources. I fixed that to use the recent kernel headers but it still does not work properly.