📄 video_common.c
字号:
j++; } avg = avg / j; /* average is above window - turn down brightness - go for the target */ if (avg > brightness_window_high) { step = MIN2((avg - brightness_target) / AUTOBRIGHT_DAMPER + 1, viddev->brightness - AUTOBRIGHT_MIN); if (viddev->brightness > step + 1 - AUTOBRIGHT_MIN) { viddev->brightness -= step; make_change = 1; } } else if (avg < brightness_window_low) { /* average is below window - turn up brightness - go for the target */ step = MIN2((brightness_target - avg) / AUTOBRIGHT_DAMPER + 1, AUTOBRIGHT_MAX - viddev->brightness); if (viddev->brightness < AUTOBRIGHT_MAX - step) { viddev->brightness += step; make_change = 1; } } return make_change;}/***************************************************************************** Wrappers calling the actual capture routines *****************************************************************************/#ifndef WITHOUT_V4L/* big lock for vid_start to ensure exclusive access to viddevs while adding * devices during initialization of each thread */static pthread_mutex_t vid_mutex;/* for the v4l stuff: */#include <sys/mman.h>#include <sys/utsname.h>#include <dirent.h>/* Here we setup the viddevs structure which is used globally in the vid_* * functions. */static struct video_dev *viddevs = NULL;/** * vid_init * * Called from motion.c at the very beginning before setting up the threads. * Function prepares the vid_mutex */void vid_init(void){ pthread_mutex_init(&vid_mutex, NULL);}/** * vid_cleanup * * vid_cleanup is called from motion.c when Motion is stopped or restarted */void vid_cleanup(void){ pthread_mutex_destroy(&vid_mutex);}#endif /* WITHOUT_V4L *//** * vid_close * * vid_close is called from motion.c when a Motion thread is stopped or restarted */void vid_close(struct context *cnt){#ifndef WITHOUT_V4L struct video_dev *dev = viddevs; struct video_dev *prev = NULL;#endif /* WITHOUT_V4L */ /* Cleanup the netcam part */ if(cnt->netcam) { motion_log(LOG_DEBUG, 0, "vid_close: calling netcam_cleanup"); netcam_cleanup(cnt->netcam, 0); cnt->netcam = NULL; return; }#ifndef WITHOUT_V4L /* Cleanup the v4l part */ pthread_mutex_lock(&vid_mutex); while (dev) { if (dev->fd == cnt->video_dev) break; prev = dev; dev = dev->next; } pthread_mutex_unlock(&vid_mutex); /* Set it as closed in thread context */ cnt->video_dev = -1; if (dev == NULL) { motion_log(LOG_ERR, 0, "vid_close: Unable to find video device"); return; } if( --dev->usage_count == 0) { motion_log(LOG_INFO, 0, "Closing video device %s", dev->video_device);#ifdef MOTION_V4L2 if (dev->v4l2) { v4l2_close(dev); v4l2_cleanup(dev); } else {#endif close(dev->fd); munmap(viddevs->v4l_buffers[0], viddevs->size_map); munmap(viddevs->v4l_buffers[1], viddevs->size_map);#ifdef MOTION_V4L2 }#endif dev->fd = -1; pthread_mutex_lock(&vid_mutex); /* Remove from list */ if (prev == NULL) viddevs = dev->next; else prev->next = dev->next; pthread_mutex_unlock(&vid_mutex); pthread_mutexattr_destroy(&dev->attr); pthread_mutex_destroy(&dev->mutex); free(dev); } else { motion_log(LOG_INFO, 0, "Still %d users of video device %s, so we don't close it now", dev->usage_count, dev->video_device); /* There is still at least one thread using this device * If we own it, release it */ if (dev->owner == cnt->threadnr) { dev->frames = 0; dev->owner = -1; pthread_mutex_unlock(&dev->mutex); } }#endif /* WITHOUT_V4L */}#ifndef WITHOUT_V4L/** * vid_v4lx_start * * Called from vid_start setup the V4L/V4L2 capture device * The function does the following: * * - Setup basic V4L/V4L2 properties incl palette incl setting * - Open the device * - Returns the device number. * * Parameters: * cnt Pointer to the context for this thread * * "Global" variable * viddevs The viddevs struct is "global" within the context of video.c * and used in functions vid_*. * vid_mutex Mutex needed to handle exclusive access to the viddevs struct when * each thread adds a new video device during startup calling vid_start * * Returns * device number * -1 if failed to open device. */static int vid_v4lx_start(struct context *cnt){ struct config *conf = &cnt->conf; int fd = -1; struct video_dev *dev; int width, height, input, norm, tuner_number; unsigned long frequency; /* We use width and height from conf in this function. They will be assigned * to width and height in imgs here, and cap_width and cap_height in * rotate_data won't be set until in rotate_init. * Motion requires that width and height is a multiple of 16 so we check * for this first. */ if (conf->width % 16) { motion_log(LOG_ERR, 0, "config image width (%d) is not modulo 16", conf->width); return -1; } if (conf->height % 16) { motion_log(LOG_ERR, 0, "config image height (%d) is not modulo 16", conf->height); return -1; } width = conf->width; height = conf->height; input = conf->input; norm = conf->norm; frequency = conf->frequency; tuner_number = conf->tuner_number; pthread_mutex_lock(&vid_mutex); /* Transfer width and height from conf to imgs. The imgs values are the ones * that is used internally in Motion. That way, setting width and height via * http remote control won't screw things up. */ cnt->imgs.width = width; cnt->imgs.height = height; /* First we walk through the already discovered video devices to see * if we have already setup the same device before. If this is the case * the device is a Round Robin device and we set the basic settings * and return the file descriptor */ dev = viddevs; while (dev) { if (!strcmp(conf->video_device, dev->video_device)) { dev->usage_count++; cnt->imgs.type = dev->v4l_fmt; switch (cnt->imgs.type) { case VIDEO_PALETTE_GREY: cnt->imgs.motionsize = width * height; cnt->imgs.size = width * height; break; case VIDEO_PALETTE_YUYV: case VIDEO_PALETTE_RGB24: case VIDEO_PALETTE_YUV422: cnt->imgs.type = VIDEO_PALETTE_YUV420P; case VIDEO_PALETTE_YUV420P: cnt->imgs.motionsize = width * height; cnt->imgs.size = (width * height * 3) / 2; break; } pthread_mutex_unlock(&vid_mutex); return dev->fd; } dev = dev->next; } dev = mymalloc(sizeof(struct video_dev)); memset(dev, 0, sizeof(struct video_dev)); dev->video_device = conf->video_device; fd = open(dev->video_device, O_RDWR); if (fd < 0) { motion_log(LOG_ERR, 1, "Failed to open video device %s", conf->video_device); free(dev); pthread_mutex_unlock(&vid_mutex); return -1; } pthread_mutexattr_init(&dev->attr); pthread_mutex_init(&dev->mutex, &dev->attr); dev->usage_count = 1; dev->fd = fd; dev->input = input; dev->height = height; dev->width = width; dev->freq = frequency; dev->tuner_number = tuner_number; /* We set brightness, contrast, saturation and hue = 0 so that they only get * set if the config is not zero. */ dev->brightness = 0; dev->contrast = 0; dev->saturation = 0; dev->hue = 0; dev->owner = -1; dev->v4l_fmt = VIDEO_PALETTE_YUV420P;#ifdef MOTION_V4L2 /* First lets try V4L2 and if it's not supported V4L1 */ dev->v4l2 = 1; if (!v4l2_start(cnt, dev, width, height, input, norm, frequency, tuner_number)) { /* restore width & height before test with v4l * because could be changed in v4l2_start () */ dev->width = width; dev->height = height;#endif if (!v4l_start(cnt, dev, width, height, input, norm, frequency, tuner_number)) { close(dev->fd); pthread_mutexattr_destroy(&dev->attr); pthread_mutex_destroy(&dev->mutex); free(dev); pthread_mutex_unlock(&vid_mutex); return -1; }#ifdef MOTION_V4L2 dev->v4l2 = 0; }#endif if (dev->v4l2 == 0) { motion_log(-1, 0, "Using V4L1"); } else { motion_log(-1, 0, "Using V4L2"); /* Update width & height because could be changed in v4l2_start () */ width = dev->width; height = dev->height; cnt->imgs.width = width; cnt->imgs.height = height; } cnt->imgs.type = dev->v4l_fmt; switch (cnt->imgs.type) { case VIDEO_PALETTE_GREY: cnt->imgs.size = width * height; cnt->imgs.motionsize = width * height; break; case VIDEO_PALETTE_YUYV: case VIDEO_PALETTE_RGB24: case VIDEO_PALETTE_YUV422: cnt->imgs.type = VIDEO_PALETTE_YUV420P; case VIDEO_PALETTE_YUV420P: cnt->imgs.size = (width * height * 3) / 2; cnt->imgs.motionsize = width * height; break; } /* Insert into linked list */ dev->next = viddevs; viddevs = dev; pthread_mutex_unlock(&vid_mutex);return fd;}#endif /*WITHOUT_V4L *//** * vid_start * * vid_start setup the capture device. This will be either a V4L device or a netcam. * The function does the following: * - If the camera is a netcam - netcam_start is called and function returns * - Width and height are checked for valid value (multiple of 16) * - Copy the config height and width to the imgs struct. Note that height and width are * only copied to the from the conf struct to the imgs struct during program startup * The width and height can no later be changed via http remote control as this would * require major re-memory allocations of all image buffers. * * - if the camera is V4L/V4L2 vid_v4lx_start is called * * Parameters: * cnt Pointer to the context for this thread * * Returns * device number * -1 if failed to open device. */int vid_start(struct context *cnt){ struct config *conf = &cnt->conf; int dev = -1; if (conf->netcam_url) { dev = netcam_start(cnt); if (dev < 0) { netcam_cleanup(cnt->netcam, 1); cnt->netcam = NULL; } }#ifdef WITHOUT_V4L else motion_log(LOG_ERR, 0,"You must setup netcam_url");#else else dev = vid_v4lx_start(cnt);#endif /*WITHOUT_V4L */ return dev;}/** * vid_next * * vid_next fetches a video frame from a either v4l device or netcam * * Parameters: * cnt Pointer to the context for this thread * map Pointer to the buffer in which the function puts the new image * * Global variable * viddevs The viddevs struct is "global" within the context of video.c * and used in functions vid_*. * Returns * 0 Success * -1 Fatal V4L error * -2 Fatal Netcam error * Positive numbers... * with bit 0 set Non fatal V4L error (not implemented) * with bit 1 set Non fatal Netcam error */int vid_next(struct context *cnt, unsigned char *map){ int ret = -2; struct config *conf = &cnt->conf; if (conf->netcam_url) { if (cnt->video_dev == -1) return NETCAM_GENERAL_ERROR; return netcam_next(cnt, map); }#ifndef WITHOUT_V4L /* We start a new block so we can make declarations without breaking * gcc 2.95 or older */ { struct video_dev *dev; int width, height; /* NOTE: Since this is a capture, we need to use capture dimensions. */ width = cnt->rotate_data.cap_width; height = cnt->rotate_data.cap_height; pthread_mutex_lock(&vid_mutex); dev = viddevs; while (dev) { if (dev->fd == cnt->video_dev) break; dev = dev->next; } pthread_mutex_unlock(&vid_mutex); if (dev == NULL) return V4L_FATAL_ERROR; if (dev->owner != cnt->threadnr) { pthread_mutex_lock(&dev->mutex); dev->owner = cnt->threadnr; dev->frames = conf->roundrobin_frames; }#ifdef MOTION_V4L2 if (dev->v4l2) { v4l2_set_input(cnt, dev, map, width, height, conf); ret = v4l2_next(cnt, dev, map, width, height); } else {#endif v4l_set_input(cnt, dev, map, width, height, conf->input, conf->norm, conf->roundrobin_skip, conf->frequency, conf->tuner_number); ret = v4l_next(dev, map, width, height);#ifdef MOTION_V4L2 }#endif if (--dev->frames <= 0) { dev->owner = -1; dev->frames = 0; pthread_mutex_unlock(&dev->mutex); } if (cnt->rotate_data.degrees > 0) { /* rotate the image as specified */ rotate_map(cnt, map); } }#endif /*WITHOUT_V4L */ return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -