#include #include #include #include #include #include #include #include #include #ifndef V4L2_PIX_FMT_VYUY #define V4L2_PIX_FMT_VYUY v4l2_fourcc('V','Y','U','Y') /* 16 YUV 4:2:2 */ #endif struct image { unsigned int width; unsigned int height; unsigned int bytes_per_line; unsigned int size; void *buf; }; static void perror_exit(const char *str) { perror(str); exit(EXIT_FAILURE); } static unsigned char clip(int value) { if (value < 0) value = 0; else if (value > 255) value = 255; return value; } static void yuv422_to_rgb(unsigned char *src, unsigned char *dst, unsigned int nr_pixels) { unsigned int i; int y1, y2, u, v; for (i = 0; i < nr_pixels; i += 2) { /* Input format is Cr(i)Y(i + 1)Cb(i)Y(i) */ y2 = *src++; v = *src++; y1 = *src++; u = *src++; y1 -= 16; u -= 128; v -= 128; y2 -= 16; *dst++ = clip(( 298 * y1 + 409 * v + 128) >> 8); *dst++ = clip(( 298 * y1 - 100 * u - 208 * v + 128) >> 8); *dst++ = clip(( 298 * y1 + 516 * u + 128) >> 8); *dst++ = clip(( 298 * y2 + 409 * v + 128) >> 8); *dst++ = clip(( 298 * y2 - 100 * u - 208 * v + 128) >> 8); *dst++ = clip(( 298 * y2 + 516 * u + 128) >> 8); } } static void dump_frame(int fd, const struct image *image) { unsigned char *line_rgb; unsigned char *line_yuv; unsigned char *p; unsigned int nlines = image->height; unsigned int nbytes; ssize_t ret; char ppm_header[256]; line_rgb = malloc(image->width * 3); line_yuv = image->buf; sprintf(ppm_header, "P6\n%u %u 255\n", image->width, image->height); for (nbytes = strlen(ppm_header), p = ppm_header; nbytes; p += ret, nbytes -= ret) { ret = write(fd, p, nbytes); if (ret < 0) perror_exit("write error"); } while (nlines--) { yuv422_to_rgb(line_yuv, line_rgb, image->width); for (nbytes = image->width * 3, p = line_rgb; nbytes; p += ret, nbytes -= ret) { ret = write(fd, p, nbytes); if (ret < 0) perror_exit("write error"); } line_yuv += image->bytes_per_line; } free(line_rgb); } static void grab_frame(int fd, struct image *image) { unsigned int nbytes = image->size; ssize_t ret; while (nbytes > 0) { ret = read(fd, image->buf, nbytes); if (ret < 0) perror_exit("read error"); nbytes -= ret; } } static void init_videodev(int fd, struct image *image) { struct v4l2_capability cap; struct v4l2_format fmt; if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) perror_exit("VIDIOC_QUERYCAP failed"); if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { fprintf(stderr, "No video capture capability present\n"); exit(EXIT_FAILURE); } if (!(cap.capabilities & V4L2_CAP_READWRITE)) { fprintf(stderr, "read() interface not supported by driver\n"); exit(EXIT_FAILURE); } /* Select video format */ memset(&fmt, 0, sizeof(fmt)); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = 320; fmt.fmt.pix.height = 240; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_VYUY; if (ioctl(fd, VIDIOC_S_FMT, &fmt)) perror_exit("VIDIOC_S_FMT failed"); image->width = fmt.fmt.pix.width; image->height = fmt.fmt.pix.height; image->bytes_per_line = fmt.fmt.pix.bytesperline; image->size = fmt.fmt.pix.sizeimage; image->buf = malloc(image->size); if (!image->buf) { fprintf(stderr, "Out of memory\n"); exit(EXIT_FAILURE); } } static void show_usage(const char *progname) { fprintf(stderr, "Usage: %s [-d videodev] [-o outfile]\n\n", progname); fprintf(stderr, "If no options are given, one frame is grabbed from\n" "/dev/video0 and written to stdout in PPM format.\n"); } int main(int argc, char **argv) { struct image image; char *input_name = "/dev/video0"; char *output_name = NULL; int infd, outfd; while (1) { int c; c = getopt(argc, argv, "d:ho:"); if (c == -1) break; switch (c) { case 'd': input_name = strdup(optarg); break; case 'o': output_name = strdup(optarg); break; case 'h': case '?': show_usage(argv[0]); return EXIT_FAILURE; default: abort(); } } infd = open(input_name, O_RDONLY); if (infd < 0) { perror("Failed to open video device"); return EXIT_FAILURE; } outfd = STDOUT_FILENO; if (output_name) { outfd = open(output_name, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (outfd < 0) { perror("Failed to open output file"); return EXIT_FAILURE; } } init_videodev(infd, &image); grab_frame(infd, &image); dump_frame(outfd, &image); return EXIT_SUCCESS; }