📄 video2.c
字号:
for (b = 0; b < s->req.count; b++) { struct v4l2_buffer buf; memset(&buf, 0, sizeof(struct v4l2_buffer)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = b; if (xioctl(s->fd, VIDIOC_QUERYBUF, &buf) == -1) { motion_log(LOG_ERR, 0, "Error querying buffer %i", b); motion_log(LOG_ERR, 0, "VIDIOC_QUERYBUF: %s", strerror(errno)); free(s->buffers); return (-1); } s->buffers[b].size = buf.length; s->buffers[b].ptr = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, s->fd, buf.m.offset); if (s->buffers[b].ptr == MAP_FAILED) { motion_log(LOG_ERR, 0, "Error mapping buffer %i", b); motion_log(LOG_ERR, 0, "mmap: %s", strerror(errno)); free(s->buffers); return (-1); } motion_log(LOG_DEBUG, 0, "%i length=%d", b, buf.length); } s->map = -1; for (b = 0; b < s->req.count; b++) { memset(&s->buf, 0, sizeof(struct v4l2_buffer)); s->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; s->buf.memory = V4L2_MEMORY_MMAP; s->buf.index = b; if (xioctl(s->fd, VIDIOC_QBUF, &s->buf) == -1) { motion_log(LOG_ERR, 0, "VIDIOC_QBUF: %s", strerror(errno)); return (-1); } } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (xioctl(s->fd, VIDIOC_STREAMON, &type) == -1) { motion_log(LOG_ERR, 0, "Error starting stream."); motion_log(LOG_ERR, 0, "VIDIOC_STREAMON: %s", strerror(errno)); return (-1); } return (0);}static int v4l2_scan_controls(src_v4l2_t * s){ int count, i; struct v4l2_queryctrl queryctrl; memset(&queryctrl, 0, sizeof(struct v4l2_queryctrl)); for (i = 0, count = 0; queried_ctrls[i]; i++) { queryctrl.id = queried_ctrls[i]; if (xioctl(s->fd, VIDIOC_QUERYCTRL, &queryctrl)) continue; count++; s->ctrl_flags |= 1 << i; } if (count) { struct v4l2_queryctrl *ctrl = s->controls = calloc(count, sizeof(struct v4l2_queryctrl)); if (!ctrl) { motion_log(LOG_ERR, 0, "%s: Insufficient buffer memory.", __FUNCTION__); return (-1); } for (i = 0; queried_ctrls[i]; i++) { if (s->ctrl_flags & (1 << i)) { struct v4l2_control control; queryctrl.id = queried_ctrls[i]; if (xioctl(s->fd, VIDIOC_QUERYCTRL, &queryctrl)) continue; memcpy(ctrl, &queryctrl, sizeof(struct v4l2_queryctrl)); motion_log(LOG_INFO, 0, "found control 0x%08x, \"%s\", range %d,%d %s", ctrl->id, ctrl->name, ctrl->minimum, ctrl->maximum, ctrl->flags & V4L2_CTRL_FLAG_DISABLED ? "!DISABLED!" : ""); memset (&control, 0, sizeof (control)); control.id = queried_ctrls[i]; xioctl(s->fd, VIDIOC_G_CTRL, &control); motion_log(LOG_INFO, 0, "\t\"%s\", default %d, current %d", ctrl->name, ctrl->default_value, control.value); ctrl++; } } } return 0;}static int v4l2_set_control(src_v4l2_t * s, u32 cid, int value){ int i, count; if (!s->controls) return -1; for (i = 0, count = 0; queried_ctrls[i]; i++) { if (s->ctrl_flags & (1 << i)) { if (cid == queried_ctrls[i]) { struct v4l2_queryctrl *ctrl = s->controls + count; struct v4l2_control control; int ret; memset (&control, 0, sizeof (control)); control.id = queried_ctrls[i]; switch (ctrl->type) { case V4L2_CTRL_TYPE_INTEGER: value = control.value = (value * (ctrl->maximum - ctrl->minimum) / 256) + ctrl->minimum; ret = xioctl(s->fd, VIDIOC_S_CTRL, &control); break; case V4L2_CTRL_TYPE_BOOLEAN: value = control.value = value ? 1 : 0; ret = xioctl(s->fd, VIDIOC_S_CTRL, &control); break; default: motion_log(LOG_ERR, 0, "%s: control type not supported yet"); return -1; } if (debug_level > 5) motion_log(LOG_INFO, 0, "setting control \"%s\" to %d (ret %d %s) %s", ctrl->name, value, ret, ret ? strerror(errno) : "", ctrl->flags & V4L2_CTRL_FLAG_DISABLED ? "Control is DISABLED!" : ""); return 0; } count++; } } return -1;}static void v4l2_picture_controls(struct context *cnt, struct video_dev *viddev){ src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private; if (cnt->conf.contrast && cnt->conf.contrast != viddev->contrast) { viddev->contrast = cnt->conf.contrast; v4l2_set_control(s, V4L2_CID_CONTRAST, viddev->contrast); } if (cnt->conf.saturation && cnt->conf.saturation != viddev->saturation) { viddev->saturation = cnt->conf.saturation; v4l2_set_control(s, V4L2_CID_SATURATION, viddev->saturation); } if (cnt->conf.hue && cnt->conf.hue != viddev->hue) { viddev->hue = cnt->conf.hue; v4l2_set_control(s, V4L2_CID_HUE, viddev->hue); } if (cnt->conf.autobright) { if (vid_do_autobright(cnt, viddev)) { if (v4l2_set_control(s, V4L2_CID_BRIGHTNESS, viddev->brightness)) v4l2_set_control(s, V4L2_CID_GAIN, viddev->brightness); } } else { if (cnt->conf.brightness && cnt->conf.brightness != viddev->brightness) { viddev->brightness = cnt->conf.brightness; if (v4l2_set_control(s, V4L2_CID_BRIGHTNESS, viddev->brightness)) v4l2_set_control(s, V4L2_CID_GAIN, viddev->brightness); } }}/* public functions */unsigned char *v4l2_start(struct context *cnt, struct video_dev *viddev, int width, int height, int input, int norm, unsigned long freq, int tuner_number){ src_v4l2_t *s; /* Allocate memory for the state structure. */ if (!(s = calloc(sizeof(src_v4l2_t), 1))) { motion_log(LOG_ERR, 0, "%s: Out of memory.", __FUNCTION__); goto err; } viddev->v4l2_private = s; s->fd = viddev->fd; s->fps = cnt->conf.frame_limit; s->pframe = -1; if (v4l2_get_capability(s)) { goto err; } if (v4l2_select_input(s, input, norm, freq, tuner_number)) { goto err; } if (v4l2_set_pix_format(cnt ,s, &width, &height)) { goto err; } if (v4l2_scan_controls(s)) { goto err; }#if 0 v4l2_set_fps(s);#endif if (v4l2_set_mmap(s)) { goto err; } viddev->size_map = 0; viddev->v4l_buffers[0] = NULL; viddev->v4l_maxbuffer = 1; viddev->v4l_curbuffer = 0; viddev->v4l_fmt = VIDEO_PALETTE_YUV420P; viddev->v4l_bufsize = (width * height * 3) / 2; /* Update width and height with supported values from camera driver */ viddev->width = width; viddev->height = height; return (void *) 1; err: if (s) free(s); viddev->v4l2_private = NULL; viddev->v4l2 = 0; return NULL;}void v4l2_set_input(struct context *cnt, struct video_dev *viddev, unsigned char *map, int width, int height, struct config *conf){ int i; int input = conf->input; int norm = conf->norm; int skip = conf->roundrobin_skip; unsigned long freq = conf->frequency; int tuner_number = conf->tuner_number; if (input != viddev->input || width != viddev->width || height != viddev->height || freq != viddev->freq || tuner_number != viddev->tuner_number) { struct timeval switchTime; v4l2_select_input((src_v4l2_t *) viddev->v4l2_private, input, norm, freq, tuner_number); gettimeofday(&switchTime, NULL); v4l2_picture_controls(cnt, viddev); viddev->input = input; viddev->width = width; viddev->height = height; viddev->freq = freq; viddev->tuner_number = tuner_number; /* Skip all frames captured before switchtime, capture 1 after switchtime */ { src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private; unsigned int counter = 0; if (debug_level > 5) motion_log(LOG_DEBUG, 0, "set_input_skip_frame switch_time=%ld:%ld", switchTime.tv_sec, switchTime.tv_usec); /* Avoid hang using the number of mmap buffers */ while(counter < s->req.count) { counter++; if (v4l2_next(cnt, viddev, map, width, height)) break; if (s->buf.timestamp.tv_sec > switchTime.tv_sec || (s->buf.timestamp.tv_sec == switchTime.tv_sec && s->buf.timestamp.tv_usec > switchTime.tv_usec)) break; if (debug_level > 5) motion_log(LOG_DEBUG, 0, "got frame before switch timestamp=%ld:%ld", s->buf.timestamp.tv_sec, s->buf.timestamp.tv_usec); } } /* skip a few frames if needed */ for (i = 1; i < skip; i++) v4l2_next(cnt, viddev, map, width, height); } else { /* No round robin - we only adjust picture controls */ v4l2_picture_controls(cnt, viddev); }}int v4l2_next(struct context *cnt, struct video_dev *viddev, unsigned char *map, int width, int height){ sigset_t set, old; src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private; if (viddev->v4l_fmt != VIDEO_PALETTE_YUV420P) { return V4L_FATAL_ERROR; } /* Block signals during IOCTL */ sigemptyset(&set); sigaddset(&set, SIGCHLD); sigaddset(&set, SIGALRM); sigaddset(&set, SIGUSR1); sigaddset(&set, SIGTERM); sigaddset(&set, SIGHUP); pthread_sigmask(SIG_BLOCK, &set, &old); if (s->pframe >= 0) { if (xioctl(s->fd, VIDIOC_QBUF, &s->buf) == -1) { motion_log(LOG_ERR, 0, "%s: VIDIOC_QBUF: %s", __FUNCTION__, strerror(errno)); return (-1); } } memset(&s->buf, 0, sizeof(struct v4l2_buffer)); s->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; s->buf.memory = V4L2_MEMORY_MMAP; if (xioctl(s->fd, VIDIOC_DQBUF, &s->buf) == -1) { /* some drivers return EIO when there is no signal, driver might dequeue an (empty) buffer despite returning an error, or even stop capturing. */ if ( errno == EIO ){ s->pframe++; if ((u32)s->pframe >= s->req.count) s->pframe=0; s->buf.index = s->pframe; motion_log(LOG_ERR, 0, "%s: VIDIOC_DQBUF: EIO (s->pframe %d)", __FUNCTION__,s->pframe); return (1); } motion_log(LOG_ERR, 0, "%s: VIDIOC_DQBUF: %s", __FUNCTION__, strerror(errno)); return (-1); } s->pframe = s->buf.index; s->buffers[s->buf.index].used = s->buf.bytesused; s->buffers[s->buf.index].content_length = s->buf.bytesused; pthread_sigmask(SIG_UNBLOCK, &old, NULL); /*undo the signal blocking */ { netcam_buff *the_buffer = &s->buffers[s->buf.index]; switch (s->fmt.fmt.pix.pixelformat) { case V4L2_PIX_FMT_RGB24: conv_rgb24toyuv420p(map, (unsigned char *) the_buffer->ptr, width, height); return 0; case V4L2_PIX_FMT_UYVY: conv_uyvyto420p(map, (unsigned char *) the_buffer->ptr, (unsigned)width, (unsigned)height); return 0; case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YUV422P: conv_yuv422to420p(map, (unsigned char *) the_buffer->ptr, width, height); return 0; case V4L2_PIX_FMT_YUV420: memcpy(map, the_buffer->ptr, viddev->v4l_bufsize); return 0; case V4L2_PIX_FMT_MJPEG:#ifdef MJPEGT mjpegtoyuv420p(map, (unsigned char *) the_buffer->ptr, width, height, s->buffers[s->buf.index].content_length); return 0;#endif case V4L2_PIX_FMT_JPEG: return conv_jpeg2yuv420(cnt, map, the_buffer, width, height); case V4L2_PIX_FMT_SBGGR8: /* bayer */ bayer2rgb24(cnt->imgs.common_buffer, (unsigned char *) the_buffer->ptr, width, height); conv_rgb24toyuv420p(map, cnt->imgs.common_buffer, width, height); return 0; case V4L2_PIX_FMT_SN9C10X: sonix_decompress(map, (unsigned char *) the_buffer->ptr, width, height); bayer2rgb24(cnt->imgs.common_buffer, map, width, height); conv_rgb24toyuv420p(map, cnt->imgs.common_buffer, width, height); return 0; } } return 1;}void v4l2_close(struct video_dev *viddev){ src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private; enum v4l2_buf_type type; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; xioctl(s->fd, VIDIOC_STREAMOFF, &type); close(s->fd); s->fd = -1;}void v4l2_cleanup(struct video_dev *viddev){ src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private; if (s->buffers) { unsigned int i; for (i = 0; i < s->req.count; i++) munmap(s->buffers[i].ptr, s->buffers[i].size); free(s->buffers); s->buffers = NULL; } if (s->controls) { free(s->controls); s->controls = NULL; } free(s); viddev->v4l2_private = NULL;}#endif#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -