static int init_v4l2(struct vdIn *vd) { int i; int ret = 0; if((vd->fd = OPEN_VIDEO(vd->videodevice, O_RDWR)) == -1) { perror("ERROR opening V4L interface"); DBG("errno: %d", errno); return -1; } memset(&vd->cap, 0, sizeof(struct v4l2_capability)); ret = xioctl(vd->fd, VIDIOC_QUERYCAP, &vd->cap); if(ret < 0) { fprintf(stderr, "Error opening device %s: unable to query device.\n", vd->videodevice); goto fatal; } if((vd->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { fprintf(stderr, "Error opening device %s: video capture not supported.\n", vd->videodevice); goto fatal;; } if(vd->grabmethod) { if(!(vd->cap.capabilities & V4L2_CAP_STREAMING)) { fprintf(stderr, "%s does not support streaming i/o\n", vd->videodevice); goto fatal; } } else { if(!(vd->cap.capabilities & V4L2_CAP_READWRITE)) { fprintf(stderr, "%s does not support read i/o\n", vd->videodevice); goto fatal; } } if (vd->vstd != V4L2_STD_UNKNOWN) { if (ioctl(vd->fd, VIDIOC_S_STD, &vd->vstd) == -1) { fprintf(stderr, "Can't set video standard: %s\n",strerror(errno)); goto fatal; } } /* * set format in */ memset(&vd->fmt, 0, sizeof(struct v4l2_format)); vd->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vd->fmt.fmt.pix.width = vd->width; vd->fmt.fmt.pix.height = vd->height; vd->fmt.fmt.pix.pixelformat = vd->formatIn; vd->fmt.fmt.pix.field = V4L2_FIELD_ANY; ret = xioctl(vd->fd, VIDIOC_S_FMT, &vd->fmt); if(ret < 0) { fprintf(stderr, "Unable to set format: %d res: %dx%d\n", vd->formatIn, vd->width, vd->height); goto fatal; } if((vd->fmt.fmt.pix.width != vd->width) || (vd->fmt.fmt.pix.height != vd->height)) { fprintf(stderr, "i: The format asked unavailable, so the width %d height %d \n", vd->fmt.fmt.pix.width, vd->fmt.fmt.pix.height); vd->width = vd->fmt.fmt.pix.width; vd->height = vd->fmt.fmt.pix.height; /* * look the format is not part of the deal ??? */ if(vd->formatIn != vd->fmt.fmt.pix.pixelformat) { if(vd->formatIn == V4L2_PIX_FMT_MJPEG) { fprintf(stderr, "The input device does not supports MJPEG mode\n" "You may also try the YUV mode (-yuv option), \n" "or the you can set another supported formats using the -fourcc argument.\n" "Note: streaming using uncompressed formats will require much more CPU power on your server\n"); goto fatal; } else if(vd->formatIn == V4L2_PIX_FMT_YUYV) { fprintf(stderr, "The input device does not supports YUV format\n"); goto fatal; } else if (vd->formatIn == V4L2_PIX_FMT_RGB565) { fprintf(stderr, "The input device does not supports RGB565 format\n"); goto fatal; } } else { vd->formatIn = vd->fmt.fmt.pix.pixelformat; } } /* * set framerate */ if (vd->fps != -1) { struct v4l2_streamparm *setfps; setfps = (struct v4l2_streamparm *) calloc(1, sizeof(struct v4l2_streamparm)); memset(setfps, 0, sizeof(struct v4l2_streamparm)); setfps->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* * first query streaming parameters to determine that the FPS selection is supported */ ret = xioctl(vd->fd, VIDIOC_G_PARM, setfps); if (ret == 0) { if (setfps->parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { memset(setfps, 0, sizeof(struct v4l2_streamparm)); setfps->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; setfps->parm.capture.timeperframe.numerator = 1; setfps->parm.capture.timeperframe.denominator = vd->fps==-1?255:vd->fps; // if no default fps set set it to maximum ret = xioctl(vd->fd, VIDIOC_S_PARM, setfps); if (ret) { perror("Unable to set the FPS\n"); } else { if (vd->fps != setfps->parm.capture.timeperframe.denominator) { IPRINT("FPS coerced ......: from %d to %d\n", vd->fps, setfps->parm.capture.timeperframe.denominator); } // if we selecting lower FPS than the allowed then we will use software framedropping if (vd->fps < setfps->parm.capture.timeperframe.denominator) { vd->soft_framedrop = 1; vd->frame_period_time = 1000/vd->fps; // calcualate frame period time in ms IPRINT("Frame period time ......: %ld ms\n", vd->frame_period_time); // set FPS to maximum in order to minimize the lagging memset(setfps, 0, sizeof(struct v4l2_streamparm)); setfps->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; setfps->parm.capture.timeperframe.numerator = 1; setfps->parm.capture.timeperframe.denominator = 255; ret = xioctl(vd->fd, VIDIOC_S_PARM, setfps); if (ret) { perror("Unable to set the FPS\n"); } } } } else { perror("Setting FPS on the capture device is not supported, fallback to software framedropping\n"); vd->soft_framedrop = 1; vd->frame_period_time = 1000/vd->fps; // calcualate frame period time in ms IPRINT("Frame period time ......: %ld ms\n", vd->frame_period_time); } } else { perror("Unable to query that the FPS change is supported\n"); } } /* * request buffers */ memset(&vd->rb, 0, sizeof(struct v4l2_requestbuffers)); vd->rb.count = NB_BUFFER; vd->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vd->rb.memory = V4L2_MEMORY_MMAP; ret = xioctl(vd->fd, VIDIOC_REQBUFS, &vd->rb); if(ret < 0) { perror("Unable to allocate buffers"); goto fatal; } /* * map the buffers */ for(i = 0; i < NB_BUFFER; i++) { memset(&vd->buf, 0, sizeof(struct v4l2_buffer)); vd->buf.index = i; vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vd->buf.memory = V4L2_MEMORY_MMAP; ret = xioctl(vd->fd, VIDIOC_QUERYBUF, &vd->buf); if(ret < 0) { perror("Unable to query buffer"); goto fatal; } if(debug) fprintf(stderr, "length: %u offset: %u\n", vd->buf.length, vd->buf.m.offset); vd->mem[i] = mmap(0 /* start anywhere */ , vd->buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, vd->fd, vd->buf.m.offset); if(vd->mem[i] == MAP_FAILED) { perror("Unable to map buffer"); goto fatal; } if(debug) fprintf(stderr, "Buffer mapped at address %p.\n", vd->mem[i]); } /* * Queue the buffers. */ for(i = 0; i < NB_BUFFER; ++i) { memset(&vd->buf, 0, sizeof(struct v4l2_buffer)); vd->buf.index = i; vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vd->buf.memory = V4L2_MEMORY_MMAP; ret = xioctl(vd->fd, VIDIOC_QBUF, &vd->buf); if(ret < 0) { perror("Unable to queue buffer"); goto fatal;; } } return 0; fatal: return -1; }
static int init_v4l2(struct vdIn *vd) { int i; int ret = 0; if((vd->fd = OPEN_VIDEO(vd->videodevice, O_RDWR)) == -1) { perror("ERROR opening V4L interface"); DBG("errno: %d", errno); return -1; } memset(&vd->cap, 0, sizeof(struct v4l2_capability)); ret = xioctl(vd->fd, VIDIOC_QUERYCAP, &vd->cap); if(ret < 0) { fprintf(stderr, "Error opening device %s: unable to query device.\n", vd->videodevice); goto fatal; } if((vd->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { fprintf(stderr, "Error opening device %s: video capture not supported.\n", vd->videodevice); goto fatal;; } if(vd->grabmethod) { if(!(vd->cap.capabilities & V4L2_CAP_STREAMING)) { fprintf(stderr, "%s does not support streaming i/o\n", vd->videodevice); goto fatal; } } else { if(!(vd->cap.capabilities & V4L2_CAP_READWRITE)) { fprintf(stderr, "%s does not support read i/o\n", vd->videodevice); goto fatal; } } /* * set format in */ memset(&vd->fmt, 0, sizeof(struct v4l2_format)); vd->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vd->fmt.fmt.pix.width = vd->width; vd->fmt.fmt.pix.height = vd->height; vd->fmt.fmt.pix.pixelformat = vd->formatIn; vd->fmt.fmt.pix.field = V4L2_FIELD_ANY; ret = xioctl(vd->fd, VIDIOC_S_FMT, &vd->fmt); if(ret < 0) { fprintf(stderr, "Unable to set format: %d res: %dx%d\n", vd->formatIn, vd->width, vd->height); goto fatal; } if((vd->fmt.fmt.pix.width != vd->width) || (vd->fmt.fmt.pix.height != vd->height)) { fprintf(stderr, "i: The format asked unavailable, so the width %d height %d \n", vd->fmt.fmt.pix.width, vd->fmt.fmt.pix.height); vd->width = vd->fmt.fmt.pix.width; vd->height = vd->fmt.fmt.pix.height; /* * look the format is not part of the deal ??? */ if(vd->formatIn != vd->fmt.fmt.pix.pixelformat) { if(vd->formatIn == V4L2_PIX_FMT_MJPEG) { fprintf(stderr, "The inpout device does not supports MJPEG mode\nYou may also try the YUV mode (-yuv option), but it requires a much more CPU power\n"); goto fatal; } else if(vd->formatIn == V4L2_PIX_FMT_YUYV) { fprintf(stderr, "The input device does not supports YUV mode\n"); goto fatal; } } else { vd->formatIn = vd->fmt.fmt.pix.pixelformat; } } /* * set framerate */ struct v4l2_streamparm *setfps; setfps = (struct v4l2_streamparm *) calloc(1, sizeof(struct v4l2_streamparm)); memset(setfps, 0, sizeof(struct v4l2_streamparm)); setfps->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; setfps->parm.capture.timeperframe.numerator = 1; setfps->parm.capture.timeperframe.denominator = vd->fps; ret = xioctl(vd->fd, VIDIOC_S_PARM, setfps); /* * request buffers */ memset(&vd->rb, 0, sizeof(struct v4l2_requestbuffers)); vd->rb.count = NB_BUFFER; vd->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vd->rb.memory = V4L2_MEMORY_MMAP; ret = xioctl(vd->fd, VIDIOC_REQBUFS, &vd->rb); if(ret < 0) { perror("Unable to allocate buffers"); goto fatal; } /* * map the buffers */ for(i = 0; i < NB_BUFFER; i++) { memset(&vd->buf, 0, sizeof(struct v4l2_buffer)); vd->buf.index = i; vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vd->buf.memory = V4L2_MEMORY_MMAP; ret = xioctl(vd->fd, VIDIOC_QUERYBUF, &vd->buf); if(ret < 0) { perror("Unable to query buffer"); goto fatal; } if(debug) fprintf(stderr, "length: %u offset: %u\n", vd->buf.length, vd->buf.m.offset); vd->mem[i] = mmap(0 /* start anywhere */ , vd->buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, vd->fd, vd->buf.m.offset); if(vd->mem[i] == MAP_FAILED) { perror("Unable to map buffer"); goto fatal; } if(debug) fprintf(stderr, "Buffer mapped at address %p.\n", vd->mem[i]); } /* * Queue the buffers. */ for(i = 0; i < NB_BUFFER; ++i) { memset(&vd->buf, 0, sizeof(struct v4l2_buffer)); vd->buf.index = i; vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vd->buf.memory = V4L2_MEMORY_MMAP; ret = xioctl(vd->fd, VIDIOC_QBUF, &vd->buf); if(ret < 0) { perror("Unable to queue buffer"); goto fatal;; } } return 0; fatal: return -1; }
int init_v4l2(struct video_device *vd) { int i; struct v4l2_streamparm setfps; if ((vd->fd = OPEN_VIDEO(vd->device_filename, O_RDWR)) == -1) { log_itf(LOG_ERROR, "Error opening V4L2 interface on %s. errno %d", vd->device_filename, errno); } memset(&vd->cap, 0, sizeof(struct v4l2_capability)); if (xioctl(vd->fd, VIDIOC_QUERYCAP, &vd->cap) < 0) { log_itf(LOG_ERROR, "Error opening device %s: unable to query device.", vd->device_filename); return -1; } if ((vd->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { log_itf(LOG_ERROR, "Error opening device %s: video capture not supported.", vd->device_filename); return -1; } if (vd->use_streaming) { if (!(vd->cap.capabilities & V4L2_CAP_STREAMING)) { log_itf(LOG_ERROR, "%s does not support streaming I/O", vd->device_filename); return -1; } } else { if (!(vd->cap.capabilities & V4L2_CAP_READWRITE)) { log_itf(LOG_ERROR, "%s does not support read I/O", vd->device_filename); return -1; } } vd->streaming_state = STREAMING_OFF; // set format in memset(&vd->fmt, 0, sizeof(struct v4l2_format)); vd->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vd->fmt.fmt.pix.width = vd->width; vd->fmt.fmt.pix.height = vd->height; vd->fmt.fmt.pix.pixelformat = vd->format_in; vd->fmt.fmt.pix.field = V4L2_FIELD_ANY; if (xioctl(vd->fd, VIDIOC_S_FMT, &vd->fmt) < 0) { log_itf(LOG_WARNING, "Unable to set format %d, res %dx%d, device %s. Trying fallback.", vd->format_in, vd->width, vd->height, vd->device_filename); // Try the fallback format vd->format_in = UVC_FALLBACK_FORMAT; vd->fmt.fmt.pix.pixelformat = vd->format_in; if (xioctl(vd->fd, VIDIOC_S_FMT, &vd->fmt) < 0) { log_itf(LOG_ERROR, "Unable to set fallback format %d, res %dx%d, device %s.", vd->format_in, vd->width, vd->height, vd->device_filename); return -1; } } if ((vd->fmt.fmt.pix.width != vd->width) || (vd->fmt.fmt.pix.height != vd->height)) { log_itf(LOG_WARNING, "The format asked unavailable, so the width %d height %d on device %s.", vd->fmt.fmt.pix.width, vd->fmt.fmt.pix.height, vd->device_filename); vd->width = vd->fmt.fmt.pix.width; vd->height = vd->fmt.fmt.pix.height; // look the format is not part of the deal ??? if (vd->format_in != vd->fmt.fmt.pix.pixelformat) { if (vd->format_in == V4L2_PIX_FMT_MJPEG) { log_itf(LOG_ERROR, "The input device %s does not supports MJPEG mode.\nYou may also try the YUV mode, but it requires a much more CPU power.", vd->device_filename); return -1; } else if (vd->format_in == V4L2_PIX_FMT_YUYV) { log_itf(LOG_ERROR, "The input device %s does not supports YUV mode.", vd->device_filename); return -1; } } else { vd->format_in = vd->fmt.fmt.pix.pixelformat; } } // set framerate memset(&setfps, 0, sizeof(struct v4l2_streamparm)); setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; setfps.parm.capture.timeperframe.numerator = 1; setfps.parm.capture.timeperframe.denominator = vd->fps; if (xioctl(vd->fd, VIDIOC_S_PARM, &setfps) < 0) { log_itf(LOG_ERROR, "Unable to set FPS to %d on device %s.", vd->fps, vd->device_filename); return -1; } // request buffers memset(&vd->rb, 0, sizeof(struct v4l2_requestbuffers)); vd->rb.count = NB_BUFFER; vd->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vd->rb.memory = V4L2_MEMORY_MMAP; if (xioctl(vd->fd, VIDIOC_REQBUFS, &vd->rb) < 0) { log_itf(LOG_ERROR, "Unable to allocate buffers for device %s.", vd->device_filename); return -1; } // map the buffers for(i = 0; i < NB_BUFFER; i++) { memset(&vd->buf, 0, sizeof(struct v4l2_buffer)); vd->buf.index = i; vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vd->buf.memory = V4L2_MEMORY_MMAP; if (xioctl(vd->fd, VIDIOC_QUERYBUF, &vd->buf)) { log_itf(LOG_ERROR, "Unable to query buffer on device %s.", vd->device_filename); return -1; } vd->mem[i] = mmap(0 /* start anywhere */ , vd->buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, vd->fd, vd->buf.m.offset); if (vd->mem[i] == MAP_FAILED) { log_itf(LOG_ERROR, "Unable to map buffer on device %s.", vd->device_filename); return -1; } DBG("Buffer mapped at address %p for device %s.", vd->mem[i], vd->device_filename); } // Queue the buffers. for(i = 0; i < NB_BUFFER; ++i) { memset(&vd->buf, 0, sizeof(struct v4l2_buffer)); vd->buf.index = i; vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vd->buf.memory = V4L2_MEMORY_MMAP; if (xioctl(vd->fd, VIDIOC_QBUF, &vd->buf) < 0) { log_itf(LOG_ERROR, "Unable to query buffer on device %s.", vd->device_filename); return -1; } } if (video_enable(vd)) { log_itf(LOG_ERROR, "Unable to enable video for device %s.", vd->device_filename); return -1; } return 0; }