📄 video.c
字号:
char *minor; struct utsname uts; if (uname(&uts) < 0) { motion_log(LOG_ERR, 1, "Unable to execute uname"); return -1; } major = strtok(uts.release, "."); minor = strtok(NULL, "."); if ((major == NULL) || (minor == NULL) || (strcmp(major, "2"))) { motion_log(LOG_ERR, 1, "Unable to decipher OS version"); return -1; } if (strcmp(minor, "5") < 0) { FILE *vloopbacks; char *loop; char *input; char *istatus; char *output; char *ostatus; vloopbacks=fopen("/proc/video/vloopback/vloopbacks", "r"); if (!vloopbacks) { motion_log(LOG_ERR, 1, "Failed to open '/proc/video/vloopback/vloopbacks'"); return -1; } /* Read vloopback version*/ if (!fgets(buffer, 255, vloopbacks)) { motion_log(LOG_ERR, 1, "Unable to read vloopback version"); return -1; } fprintf(stderr,"\t%s", buffer); /* Read explanation line */ if (!fgets(buffer, 255, vloopbacks)) { motion_log(LOG_ERR, 1, "Unable to read vloopback explanation line"); return -1; } while (fgets(buffer, 255, vloopbacks)) { if (strlen(buffer)>1) { buffer[strlen(buffer)-1]=0; loop=strtok(buffer, "\t"); input=strtok(NULL, "\t"); istatus=strtok(NULL, "\t"); output=strtok(NULL, "\t"); ostatus=strtok(NULL, "\t"); if (istatus[0]=='-') { snprintf(pipepath, 255, "/dev/%s", input); pipe_fd=open(pipepath, O_RDWR); if (pipe_fd>=0) { motion_log(-1, 0, "\tInput: /dev/%s", input); motion_log(-1, 0, "\tOutput: /dev/%s", output); break; } } } } fclose(vloopbacks); } else { DIR *dir; struct dirent *dirp; const char prefix[]="/sys/class/video4linux/"; char *ptr, *io; int fd; int low=9999; int tfd; int tnum; if ((dir=opendir(prefix))== NULL) { motion_log(LOG_ERR, 1, "Failed to open '%s'", prefix); return -1; } while ((dirp=readdir(dir)) != NULL) { if (!strncmp(dirp->d_name, "video", 5)) { strncpy(buffer, prefix, 255); strncat(buffer, dirp->d_name, 255); strncat(buffer, "/name", 255); if ((fd=open(buffer, O_RDONLY)) >= 0) { if ((read(fd, buffer, sizeof(buffer)-1))<0) { close(fd); continue; } ptr = strtok(buffer, " "); if (strcmp(ptr,"Video")) { close(fd); continue; } major = strtok(NULL, " "); minor = strtok(NULL, " "); io = strtok(NULL, " \n"); if (strcmp(major, "loopback") || strcmp(io, "input")) { close(fd); continue; } if ((ptr=strtok(buffer, " "))==NULL) { close(fd); continue; } tnum = atoi(minor); if (tnum < low) { strcpy(buffer, "/dev/"); strcat(buffer, dirp->d_name); if ((tfd=open(buffer, O_RDWR))>=0) { strcpy(pipepath, buffer); if (pipe_fd>=0) { close(pipe_fd); } pipe_fd = tfd; low = tnum; } } close(fd); } } } closedir(dir); if (pipe_fd >= 0) motion_log(-1, 0, "Opened input of %s", pipepath); } return pipe_fd;}static int v4l_startpipe(char *devname, int width, int height, int type){ int dev; struct video_picture vid_pic; struct video_window vid_win; if (!strcmp(devname, "-")) { dev=v4l_open_vidpipe(); } else { dev=open(devname, O_RDWR); } if (dev < 0) return(-1); if (ioctl(dev, VIDIOCGPICT, &vid_pic)== -1) { motion_log(LOG_ERR, 1, "ioctl (VIDIOCGPICT)"); return(-1); } vid_pic.palette=type; if (ioctl(dev, VIDIOCSPICT, &vid_pic)== -1) { motion_log(LOG_ERR, 1, "ioctl (VIDIOCSPICT)"); return(-1); } if (ioctl(dev, VIDIOCGWIN, &vid_win)== -1) { motion_log(LOG_ERR, 1, "ioctl (VIDIOCGWIN)"); return(-1); } vid_win.height=height; vid_win.width=width; if (ioctl(dev, VIDIOCSWIN, &vid_win)== -1) { motion_log(LOG_ERR, 1, "ioctl (VIDIOCSWIN)"); return(-1); } return dev;}static int v4l_putpipe (int dev, unsigned char *image, int size){ return write(dev, image, size);}#endif /*WITHOUT_V4L*//***************************************************************************** Wrappers calling the actual capture routines *****************************************************************************//* big lock for vid_start to ensure exclusive access to viddevs while adding * devices during initialization of each thread */pthread_mutex_t vid_mutex;#ifndef WITHOUT_V4L/* Here we setup the viddevs structure which is used globally in the vid_* * functions. */struct video_dev **viddevs=NULL;/** * vid_init * * Called from motion.c at the very beginning before setting up the threads. * Function prepares the viddevs struct for the threads and the vid_mutex */void vid_init(void){ if (!viddevs) { viddevs = mymalloc(sizeof(struct video_dev *)); viddevs[0] = NULL; } pthread_mutex_init(&vid_mutex, NULL);}/** * vid_close * * vid_close is called from motion.c when Motion is stopped or restarted * It gets rid of all open video devices. It is called BEFORE vid_cleanup. */void vid_close(void){ int i=-1; if (viddevs) { while(viddevs[++i]) { close(viddevs[i]->fd); } }}/** * vid_cleanup * * vid_cleanup is called from motion.c when Motion is stopped or restarted * It free all the memory held by the viddevs structs. */void vid_cleanup(void){ int i=-1; if (viddevs) { while(viddevs[++i]) { munmap(viddevs[i]->v4l_buffers[0],viddevs[i]->size_map); free(viddevs[i]); } free(viddevs); viddevs=NULL; }}#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. * - Setup basic V4L 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. */int vid_start(struct context *cnt){ struct config *conf = &cnt->conf; int dev = -1; if (conf->netcam_url) { return netcam_start(cnt); }#ifndef WITHOUT_V4L /* Start a new block so we can make declarations without breaking good old * gcc 2.95 or older. */ { int i = -1; 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 */ while (viddevs[++i]) { if (!strcmp(conf->video_device, viddevs[i]->video_device)) { int fd; cnt->imgs.type = viddevs[i]->v4l_fmt; switch (cnt->imgs.type) { case VIDEO_PALETTE_GREY: cnt->imgs.motionsize = width * height; cnt->imgs.size = width * height; break; 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; } fd=viddevs[i]->fd; pthread_mutex_unlock(&vid_mutex); return fd; } } viddevs = myrealloc(viddevs, sizeof(struct video_dev *)*(i+2), "vid_start"); viddevs[i] = mymalloc(sizeof(struct video_dev)); memset(viddevs[i], 0, sizeof(struct video_dev)); viddevs[i+1]=NULL; pthread_mutexattr_init(&viddevs[i]->attr); pthread_mutex_init(&viddevs[i]->mutex, NULL); dev = open(conf->video_device, O_RDWR); if (dev <0) { motion_log(LOG_ERR, 1, "Failed to open video device %s", conf->video_device); return -1; } viddevs[i]->video_device = conf->video_device; viddevs[i]->fd = dev; viddevs[i]->input = input; viddevs[i]->height = height; viddevs[i]->width = width; viddevs[i]->freq = frequency; viddevs[i]->tuner_number = tuner_number; /* We set brightness, contrast, saturation and hue = 0 so that they only get * set if the config is not zero. */ viddevs[i]->brightness = 0; viddevs[i]->contrast = 0; viddevs[i]->saturation = 0; viddevs[i]->hue = 0; viddevs[i]->owner = -1; viddevs[i]->v4l_fmt = VIDEO_PALETTE_YUV420P; if (!v4l_start(cnt, viddevs[i], width, height, input, norm, frequency, tuner_number)) { pthread_mutex_unlock(&vid_mutex); return -1; } cnt->imgs.type = viddevs[i]->v4l_fmt; switch (cnt->imgs.type) { case VIDEO_PALETTE_GREY: cnt->imgs.size = width*height; cnt->imgs.motionsize = width*height; break; 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; } pthread_mutex_unlock(&vid_mutex); }#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){ struct config *conf=&cnt->conf; int ret = -1; if (conf->netcam_url) { if (cnt->video_dev == -1) return NETCAM_GENERAL_ERROR; ret = netcam_next(cnt, map); return ret; }#ifndef WITHOUT_V4L /* We start a new block so we can make declarations without breaking * gcc 2.95 or older */ { int i = -1; int width, height; int dev = cnt->video_dev; /* NOTE: Since this is a capture, we need to use capture dimensions. */ width = cnt->rotate_data.cap_width; height = cnt->rotate_data.cap_height; while (viddevs[++i]) if (viddevs[i]->fd == dev) break; if (!viddevs[i]) return V4L_FATAL_ERROR; if (viddevs[i]->owner != cnt->threadnr) { pthread_mutex_lock(&viddevs[i]->mutex); viddevs[i]->owner = cnt->threadnr; viddevs[i]->frames = conf->roundrobin_frames; cnt->switched = 1; } v4l_set_input(cnt, viddevs[i], map, width, height, conf->input, conf->norm, conf->roundrobin_skip, conf->frequency, conf->tuner_number); ret = v4l_next(viddevs[i], map, width, height); if (--viddevs[i]->frames <= 0) { viddevs[i]->owner = -1; pthread_mutex_unlock(&viddevs[i]->mutex); } if(cnt->rotate_data.degrees > 0) { /* rotate the image as specified */ rotate_map(cnt, map); } }#endif /*WITHOUT_V4L*/ return ret;}#ifndef WITHOUT_V4Lint vid_startpipe(const char *devname, int width, int height, int type){ return v4l_startpipe( (char *)devname, width, height, type);}int vid_putpipe (int dev, unsigned char *image, int size){ return v4l_putpipe(dev, image, size);}#endif /*WITHOUT_V4L*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -