Skip to content

Instantly share code, notes, and snippets.

@cebe
Created December 6, 2015 03:09
Show Gist options
  • Save cebe/386a89b273d0389b86a9 to your computer and use it in GitHub Desktop.
Save cebe/386a89b273d0389b86a9 to your computer and use it in GitHub Desktop.
Compile it with: clang -o utox -g -Wall -Wshadow -std=gnu99 ./bug.c `pkg-config --libs --cflags libv4lconvert` -fsanitize=address
static int utox_v4l_fd = -1;
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <unistd.h>
#include <locale.h>
#include <dlfcn.h>
#include <errno.h>
#define debug(...) printf(__VA_ARGS__)
#include <linux/videodev2.h>
#include <libv4l2.h>
#include <libv4lconvert.h>
#define CLEAR(x) memset(&(x), 0, sizeof(x))
int v4l_init(char *dev_name);
int main() {
return v4l_init("/dev/video0");
}
static int xioctl(int fh, unsigned long request, void *arg)
{
int r;
do {
r = ioctl(fh, request, arg);
} while (-1 == r && EINTR == errno);
return r;
}
static struct v4lconvert_data *v4lconvert_data;
static struct v4l2_format fmt, dest_fmt = {
//.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
.fmt = {
.pix = {
.pixelformat = V4L2_PIX_FMT_YUV420,
//.field = V4L2_FIELD_NONE,
},
},
};
int v4l_init(char *dev_name) {
utox_v4l_fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
if (-1 == utox_v4l_fd) {
debug("Cannot open '%s': %d, %s\n", dev_name, errno, strerror(errno));
return 0;
}
struct v4l2_capability cap;
struct v4l2_cropcap cropcap;
struct v4l2_crop crop;
unsigned int min;
if (-1 == xioctl(utox_v4l_fd, VIDIOC_QUERYCAP, &cap)) {
if (EINVAL == errno) {
debug("%s is no V4L2 device\n", dev_name);
} else {
debug("VIDIOC_QUERYCAP error %d, %s\n", errno, strerror(errno));
}
return 0;
}
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
debug("%s is no video capture device\n", dev_name);
return 0;
}
if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
debug("%s does not support streaming i/o\n", dev_name);
return 0;
}
/* Select video input, video standard and tune here. */
CLEAR(cropcap);
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (0 == xioctl(utox_v4l_fd, VIDIOC_CROPCAP, &cropcap)) {
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
crop.c = cropcap.defrect; /* reset to default */
if (-1 == xioctl(utox_v4l_fd, VIDIOC_S_CROP, &crop)) {
switch (errno) {
case EINVAL:
/* Cropping not supported. */
break;
default:
/* Errors ignored. */
break;
}
}
} else {
/* Errors ignored. */
}
v4lconvert_data = v4lconvert_create(utox_v4l_fd);
CLEAR(fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl(utox_v4l_fd, VIDIOC_G_FMT, &fmt)) {
debug("VIDIOC_S_FMT error %d, %s\n", errno, strerror(errno));
return 0;
}
/*if(fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV) {
debug("Unsupported video format: %u %u %u %u\n", fmt.fmt.pix.width, fmt.fmt.pix.height, fmt.fmt.pix.pixelformat, fmt.fmt.pix.field);
}*/
int video_width = fmt.fmt.pix.width;
int video_height = fmt.fmt.pix.height;
dest_fmt.fmt.pix.width = fmt.fmt.pix.width;
dest_fmt.fmt.pix.height = fmt.fmt.pix.height;
debug("Video size: %u %u\n", video_width, video_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;
/* part 3*/
//uint32_t buffer_size = fmt.fmt.pix.sizeimage;
struct v4l2_requestbuffers req;
CLEAR(req);
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;//V4L2_MEMORY_USERPTR;
if (-1 == xioctl(utox_v4l_fd, VIDIOC_REQBUFS, &req)) {
if (EINVAL == errno) {
debug("%s does not support x i/o\n", dev_name);
} else {
debug("VIDIOC_REQBUFS error %d, %s\n", errno, strerror(errno));
}
return 0;
}
debug("success\n");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment