Example #1
0
int initdevice(void) 
{
	struct v4l2_capability cap;
	struct v4l2_cropcap cropcap;
	struct v4l2_crop crop;
	struct v4l2_format fmt;
	unsigned int min;

	if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap)) {
		if (EINVAL == errno) {
			LOGE("%s is no V4L2 device", dev_name);
			return ERROR_LOCAL;
		} else {
			return errnoexit ("VIDIOC_QUERYCAP");
		}
	}

	if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
		LOGE("%s is no video capture device", dev_name);
		return ERROR_LOCAL;
	}

	if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
		LOGE("%s does not support streaming i/o", dev_name);
		return ERROR_LOCAL;
	}
	
	CLEAR (cropcap);

	cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

	if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
		crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		crop.c = cropcap.defrect; 

		if (-1 == xioctl (fd, VIDIOC_S_CROP, &crop)) {
			switch (errno) {
				case EINVAL:
					break;
				default:
					break;
			}
		}
	} else {
	}

	CLEAR (fmt);

	fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;

	fmt.fmt.pix.width       = IMG_WIDTH; 
	fmt.fmt.pix.height      = IMG_HEIGHT;

	fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
	fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;

	if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt))
		return errnoexit ("VIDIOC_S_FMT");

	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;

	return initmmap ();

}
Example #2
0
static void init_mmap(void)
{
        struct v4l2_requestbuffers req;

        CLEAR(req);

        req.count = 4;
        req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        req.memory = V4L2_MEMORY_MMAP;

        if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
                if (EINVAL == errno) {
                        fprintf(stderr, "%s does not support "
                                 "memory mapping\n", dev_name);
                        exit(EXIT_FAILURE);
                } else {
                        errno_exit("VIDIOC_REQBUFS");
                }
        }

        if (req.count < 2) {
                fprintf(stderr, "Insufficient buffer memory on %s\n",
                         dev_name);
                exit(EXIT_FAILURE);
        }

		printf("req.count: %d\n", req.count);

        buffers = calloc(req.count, sizeof(*buffers));

        if (!buffers) {
                fprintf(stderr, "Out of memory\n");
                exit(EXIT_FAILURE);
        }

		int count = 0;
        for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
                struct v4l2_buffer buf;

                CLEAR(buf);

                buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                buf.memory      = V4L2_MEMORY_MMAP;
                buf.index       = n_buffers;

                if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
                        errno_exit("VIDIOC_QUERYBUF");
				
				printf("mmap try count: %d\n", n_buffers);
				printf("buf.length: %d\n", buf.length);
				printf("buf.m.offset: %d\n", buf.m.offset);

                buffers[n_buffers].length = buf.length;
                buffers[n_buffers].start =
                        mmap(NULL /* start anywhere */,
                              buf.length,
                              PROT_READ | PROT_WRITE /* required */,
                              MAP_SHARED /* recommended */,
                              fd, buf.m.offset);

                if (MAP_FAILED == buffers[n_buffers].start)
                        errno_exit("mmap");
        }
}
Example #3
0
static int read_frame(void)
{
        struct v4l2_buffer buf;
        unsigned int i;

        switch (io) {
        case IO_METHOD_READ:
                if (-1 == read(fd, buffers[0].start, buffers[0].length)) {
                        switch (errno) {
                        case EAGAIN:
                                return 0;

                        case EIO:
                                /* Could ignore EIO, see spec. */

                                /* fall through */

                        default:
                                errno_exit("read");
                        }
                }

                process_image(buffers[0].start, buffers[0].length);
                break;

        case IO_METHOD_MMAP:
                CLEAR(buf);

                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                buf.memory = V4L2_MEMORY_MMAP;

                if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
                        switch (errno) {
                        case EAGAIN:
                                return 0;

                        case EIO:
                                /* Could ignore EIO, see spec. */

                                /* fall through */

                        default:
                                errno_exit("VIDIOC_DQBUF");
                        }
                }

                assert(buf.index < n_buffers);

                process_image(buffers[buf.index].start, buf.bytesused);

                if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
                        errno_exit("VIDIOC_QBUF");
                break;

        case IO_METHOD_USERPTR:
                CLEAR(buf);

                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                buf.memory = V4L2_MEMORY_USERPTR;

                if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
                        switch (errno) {
                        case EAGAIN:
                                return 0;

                        case EIO:
                                /* Could ignore EIO, see spec. */

                                /* fall through */

                        default:
                                errno_exit("VIDIOC_DQBUF");
                        }
                }

                for (i = 0; i < n_buffers; ++i)
                        if (buf.m.userptr == (unsigned long)buffers[i].start
                            && buf.length == buffers[i].length)
                                break;

                assert(i < n_buffers);

                process_image((void *)buf.m.userptr, buf.bytesused);

                if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
                        errno_exit("VIDIOC_QBUF");
                break;
        }

        return 1;
}
    void StartCapture()
    {
        if( mCapturing ) THROW("already capturing!");
        mCapturing = true;
        
        // grab current frame format
        v4l2_pix_format fmt = GetFormat();

        // from the v4l2 docs: "Buggy driver paranoia."
        unsigned int min = fmt.width * 2;
        if (fmt.bytesperline < min)
            fmt.bytesperline = min;
        min = fmt.bytesperline * fmt.height;
        if (fmt.sizeimage < min)
            fmt.sizeimage = min;

        const unsigned int bufCount = 4;
        
        if( mIO == READ )
        {
            // allocate buffer
            mBuffers.resize( 1 );
            mBuffers[ 0 ].length = fmt.sizeimage;
            mBuffers[ 0 ].start = new char[ fmt.sizeimage ];
        }
        else
        {
            // request buffers
            v4l2_requestbuffers req;
            memset( &req, 0, sizeof(req) );
            req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            req.memory = ( mIO == MMAP ? V4L2_MEMORY_MMAP : V4L2_MEMORY_USERPTR );
            req.count = bufCount;
            xioctl( mFd, VIDIOC_REQBUFS, &req );            
            
            if( mIO == USERPTR )
            {
                // allocate buffers
                mBuffers.resize( req.count );
                for( size_t i = 0; i < mBuffers.size(); ++i )
                {
                    mBuffers[ i ].length = fmt.sizeimage;
                    mBuffers[ i ].start = new char[ fmt.sizeimage ];
                }
            }            
            else
            {
                // mmap buffers
                mBuffers.resize( req.count );
                for( size_t i = 0; i < mBuffers.size(); ++i )
                {
                    v4l2_buffer buf;
                    memset( &buf, 0, sizeof(buf) );
                    buf.type    = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                    buf.memory  = V4L2_MEMORY_MMAP;
                    buf.index   = i;
                    xioctl( mFd, VIDIOC_QUERYBUF, &buf );

                    mBuffers[i].length = buf.length;
                    mBuffers[i].start = (char*)v4l2_mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, mFd, buf.m.offset);
                    if( mBuffers[i].start == MAP_FAILED )
                        THROW("mmap() failed!");
                }                
            }
            
            // queue buffers
            for( size_t i = 0; i < mBuffers.size(); ++i )
            {
                v4l2_buffer buf;
                memset( &buf, 0, sizeof(buf) );
                buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                buf.index       = i;
                buf.memory = ( mIO == MMAP ? V4L2_MEMORY_MMAP : V4L2_MEMORY_USERPTR );
                if( mIO == USERPTR )
                {
                    buf.m.userptr   = (unsigned long)mBuffers[i].start;
                    buf.length      = mBuffers[i].length;
                }
                
                xioctl( mFd, VIDIOC_QBUF, &buf );
            }     
            
            // start streaming
            v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            xioctl( mFd, VIDIOC_STREAMON, &type );            
        }
    }
Example #5
0
// process video data
void CaptureThread::run() {
	while (devam) {
		mutex.lock();
		do {
			FD_ZERO(&fds);
			FD_SET(fd, &fds);

			/* Timeout. */
			tv.tv_sec = 2;
			tv.tv_usec = 0;

			r = select(fd + 1, &fds, NULL, NULL, &tv);
		} while ((r == -1 && (errno = EINTR)));

		if (r == -1) {
			kDebug() << "select";
			quit();
			return;
		}

		CLEAR(buf);
		buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory = V4L2_MEMORY_MMAP;
		xioctl(fd, VIDIOC_DQBUF, &buf);

		if (v4lconvert_convert(v4lconvert_data,
													 &src_fmt,
													 &fmt,
													 (unsigned char*)buffers[buf.index].start, buf.bytesused,
													 dst_buf, fmt.fmt.pix.sizeimage) < 0) {
			if (errno != EAGAIN)
				kDebug() << "v4l_convert";
		}

		unsigned char* asil=(unsigned char*)malloc(fmt.fmt.pix.sizeimage+qstrlen(header));
		memmove(asil, dst_buf, fmt.fmt.pix.sizeimage);
		memmove(asil+qstrlen(header), asil, fmt.fmt.pix.sizeimage);
		memcpy(asil,header,qstrlen(header));

		QImage *qq=new QImage();

		if(qq->loadFromData(asil,fmt.fmt.pix.sizeimage+qstrlen(header), "PPM")){
			QTransform outTransform;

			if(Settings::mirror()){
				// scaling x * -1 - making the output image mirror.
				outTransform.scale(-1, 1);
			}

			if(Settings::flip()){
				// flipping y * -1
				outTransform.scale(1, -1);
			}

			emit renderedImage(qq->transformed(outTransform));
		}
		free(asil);
		delete qq;
		if (delay>0) {
			this->msleep(delay);
		}
		xioctl(fd, VIDIOC_QBUF, &buf);
		di++;
		mutex.unlock();
	}
}
Example #6
0
LOCAL JPEG_RET_E JPEGENC_Scale_For_Thumbnail(SCALE_PARAM_T *scale_param)
{
	static int fd = -1; 	
	SCALE_CONFIG_T scale_config;	
	SCALE_MODE_E scale_mode;
	uint32_t enable = 0, endian_mode;

	fd = open("/dev/sc8800g_scale", O_RDONLY);//O_RDWR /* required */, 0);  
	if (-1 == fd) 
	{   
		SCI_TRACE_LOW("Fail to open scale device.");
        	return JPEG_FAILED;   
   	 }
    	
	//set mode
	scale_config.id = SCALE_PATH_MODE;	
	scale_mode = SCALE_MODE_SCALE;
	scale_config.param = &scale_mode;	 
	if (-1 == xioctl(fd, SCALE_IOC_CONFIG, &scale_config))   
	{
		SCI_TRACE_LOW("Fail to SCALE_IOC_CONFIG: id=%d", scale_config.id);
		return JPEG_FAILED;
	}
	//set input data format
	scale_config.id = SCALE_PATH_INPUT_FORMAT;	
	scale_config.param = &scale_param->in_fmt;	 
	if (-1 == xioctl(fd, SCALE_IOC_CONFIG, &scale_config))   
	{
		SCI_TRACE_LOW("Fail to SCALE_IOC_CONFIG: id=%d", scale_config.id);
		return JPEG_FAILED;
	}
	//set output data format
	scale_config.id = SCALE_PATH_OUTPUT_FORMAT;	
	scale_config.param = &scale_param->out_fmt;	 
	if (-1 == xioctl(fd, SCALE_IOC_CONFIG, &scale_config))   
	{
		SCI_TRACE_LOW("Fail to SCALE_IOC_CONFIG: id=%d", scale_config.id);
		return JPEG_FAILED;
	}
	//set input size
	scale_config.id = SCALE_PATH_INPUT_SIZE;	
	scale_config.param = &scale_param->in_size;	 
	if (-1 == xioctl(fd, SCALE_IOC_CONFIG, &scale_config))   
	{
		SCI_TRACE_LOW("Fail to SCALE_IOC_CONFIG: id=%d", scale_config.id);
		return JPEG_FAILED;
	}
	//set output size
	scale_config.id = SCALE_PATH_OUTPUT_SIZE;	
	scale_config.param = &scale_param->out_size;	 
	if (-1 == xioctl(fd, SCALE_IOC_CONFIG, &scale_config))   
	{
		SCI_TRACE_LOW("Fail to SCALE_IOC_CONFIG: id=%d", scale_config.id);
		return JPEG_FAILED;
	}	
	//set input size
	scale_config.id = SCALE_PATH_INPUT_RECT;
	scale_config.param = &scale_param->in_rect;	 
	if (-1 == xioctl(fd, SCALE_IOC_CONFIG, &scale_config))   
	{
		SCI_TRACE_LOW("Fail to SCALE_IOC_CONFIG: id=%d", scale_config.id);
		return JPEG_FAILED;
	}
	//set input address
	scale_config.id = SCALE_PATH_INPUT_ADDR;	
	scale_config.param = &scale_param->in_addr;	 
	if (-1 == xioctl(fd, SCALE_IOC_CONFIG, &scale_config))   
	{
		SCI_TRACE_LOW("Fail to SCALE_IOC_CONFIG: id=%d", scale_config.id);
		return JPEG_FAILED;
	}
	//set output address
	scale_config.id = SCALE_PATH_OUTPUT_ADDR;	
	scale_config.param = &scale_param->out_addr;	 
	if (-1 == xioctl(fd, SCALE_IOC_CONFIG, &scale_config))   
	{
		SCI_TRACE_LOW("Fail to SCALE_IOC_CONFIG: id=%d", scale_config.id);
		return JPEG_FAILED;
	}	
	
	if((scale_param->in_rect.w > scale_param->out_size.w * 4)  ||
		(scale_param->in_rect.h > scale_param->out_size.h * 4))
	{
		//set sub sample mode
		uint32_t mode = 0; //0: 1/2 1:1/4 2:1/8 3:1/16
		uint32_t enable = 1;
		if((scale_param->in_rect.w <= scale_param->out_size.w * 4 * 2) && 
		(scale_param->in_rect.h <= scale_param->out_size.h * 4 * 2)){
			mode = 0;
		}
		else if((scale_param->in_rect.w <= scale_param->out_size.w * 4 * 4) && 
		(scale_param->in_rect.h <= scale_param->out_size.h * 4 * 4)){
			mode = 1;
		}
		else if((scale_param->in_rect.w <= scale_param->out_size.w * 4 * 8) && 
		(scale_param->in_rect.h <= scale_param->out_size.h * 4 * 8)){
			mode = 2;
		}
		else if((scale_param->in_rect.w <= scale_param->out_size.w * 4 * 16) && 
		(scale_param->in_rect.h <= scale_param->out_size.h * 4 * 16)){
			mode = 3;
		}		
		scale_config.id = SCALE_PATH_SUB_SAMPLE_EN;
		scale_config.param = &enable;
		if (-1 == xioctl(fd, SCALE_IOC_CONFIG, &scale_config))	
		{
			SCI_TRACE_LOW("Fail to SCALE_IOC_CONFIG: id=%d", scale_config.id);
			return JPEG_FAILED;
		}
		scale_config.id = SCALE_PATH_SUB_SAMPLE_MOD;
		scale_config.param = &mode;
		if (-1 == xioctl(fd, SCALE_IOC_CONFIG, &scale_config))	
		{
			SCI_TRACE_LOW("Fail to SCALE_IOC_CONFIG: id=%d", scale_config.id);
			return JPEG_FAILED;
		}
	}
	//set input endian
	scale_config.id = SCALE_PATH_INPUT_ENDIAN;
	endian_mode = 1;
	scale_config.param = &endian_mode;	 
	if (-1 == xioctl(fd, SCALE_IOC_CONFIG, &scale_config))   
	{
		SCI_TRACE_LOW("Fail to SCALE_IOC_CONFIG: id=%d", scale_config.id);
		return JPEG_FAILED;
	}
	//set output endian
	scale_config.id = SCALE_PATH_OUTPUT_ENDIAN;
	endian_mode = 1;
	scale_config.param = &endian_mode;	 
	if (-1 == xioctl(fd, SCALE_IOC_CONFIG, &scale_config))   
	{
		SCI_TRACE_LOW("Fail to SCALE_IOC_CONFIG: id=%d", scale_config.id);
		return JPEG_FAILED;
	}	
	
	//done	 
	if (-1 == xioctl(fd, SCALE_IOC_DONE, 0))   
	{
		SCI_TRACE_LOW("Fail to SCALE_IOC_DONE");
		return JPEG_FAILED;
	}

	if(-1 == close(fd))   
	{   
		SCI_TRACE_LOW("Fail to close scale device.");
        	return JPEG_FAILED;   
   	 } 
    	fd = -1;   

	return JPEG_SUCCESS;
}
/* Scan V4L2 devices */
static pj_status_t v4l2_scan_devs(vid4lin_factory *f)
{
    vid4lin_dev_info vdi[V4L2_MAX_DEVS];
    char dev_name[32];
    unsigned i, old_count;
    pj_status_t status;

    if (f->dev_pool) {
        pj_pool_release(f->dev_pool);
        f->dev_pool = NULL;
    }

    pj_bzero(vdi, sizeof(vdi));
    old_count = f->dev_count;
    f->dev_count = 0;
    f->dev_pool = pj_pool_create(f->pf, DRIVER_NAME, 500, 500, NULL);

    for (i=0; i<V4L2_MAX_DEVS && f->dev_count < V4L2_MAX_DEVS; ++i) {
	int fd;
	vid4lin_dev_info *pdi;
	pj_uint32_t fmt_cap[8];
	int j, fmt_cnt=0;

	pdi = &vdi[f->dev_count];

	snprintf(dev_name, sizeof(dev_name), "/dev/video%d", i);
	if (!pj_file_exists(dev_name))
	    continue;

	fd = v4l2_open(dev_name, O_RDWR, 0);
	if (fd == -1)
	    continue;

	status = xioctl(fd, VIDIOC_QUERYCAP, &pdi->v4l2_cap);
	if (status != PJ_SUCCESS) {
	    PJ_PERROR(4,(THIS_FILE, status, "Error querying %s", dev_name));
	    v4l2_close(fd);
	    continue;
	}

	if ((pdi->v4l2_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {
	    v4l2_close(fd);
	    continue;
	}

	PJ_LOG(5,(THIS_FILE, "Found capture device %s", pdi->v4l2_cap.card));
	PJ_LOG(5,(THIS_FILE, "  Enumerating formats:"));
	for (j=0; fmt_cnt<PJ_ARRAY_SIZE(fmt_cap); ++j) {
	    struct v4l2_fmtdesc fdesc;
	    unsigned k;

	    pj_bzero(&fdesc, sizeof(fdesc));
	    fdesc.index = j;
	    fdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

	    status = xioctl(fd, VIDIOC_ENUM_FMT, &fdesc);
	    if (status != PJ_SUCCESS)
		break;

	    for (k=0; k<PJ_ARRAY_SIZE(v4l2_fmt_maps); ++k) {
		if (v4l2_fmt_maps[k].v4l2_fmt_id == fdesc.pixelformat) {
		    fmt_cap[fmt_cnt++] = v4l2_fmt_maps[k].pjmedia_fmt_id;
		    PJ_LOG(5,(THIS_FILE, "   Supported: %s",
			      fdesc.description));
		    break;
		}
	    }
	    if (k==PJ_ARRAY_SIZE(v4l2_fmt_maps)) {
		PJ_LOG(5,(THIS_FILE, "   Unsupported: %s", fdesc.description));
	    }
	}

	v4l2_close(fd);

	if (fmt_cnt==0) {
	    PJ_LOG(5,(THIS_FILE, "    Found no common format"));
	    continue;
	}

	strncpy(pdi->dev_name, dev_name, sizeof(pdi->dev_name));
	pdi->dev_name[sizeof(pdi->dev_name)-1] = '\0';
	strncpy(pdi->info.name, (char*)pdi->v4l2_cap.card,
		sizeof(pdi->info.name));
	pdi->info.name[sizeof(pdi->info.name)-1] = '\0';
	strncpy(pdi->info.driver, DRIVER_NAME, sizeof(pdi->info.driver));
	pdi->info.driver[sizeof(pdi->info.driver)-1] = '\0';
	pdi->info.dir = PJMEDIA_DIR_CAPTURE;
	pdi->info.has_callback = PJ_FALSE;
	pdi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT;

	pdi->info.fmt_cnt = fmt_cnt;
	for (j=0; j<fmt_cnt; ++j) {
	    pjmedia_format_init_video(&pdi->info.fmt[j],
				      fmt_cap[j],
				      DEFAULT_WIDTH,
				      DEFAULT_HEIGHT,
				      DEFAULT_FPS, 1);
	}
	if (j < fmt_cnt)
	    continue;

	f->dev_count++;
    }

    if (f->dev_count == 0)
	return PJ_SUCCESS;

    if (f->dev_count > old_count || f->dev_info == NULL) {
	f->dev_info = (vid4lin_dev_info*)
		      pj_pool_calloc(f->dev_pool,
				     f->dev_count,
				     sizeof(vid4lin_dev_info));
    }
    pj_memcpy(f->dev_info, vdi, f->dev_count * sizeof(vid4lin_dev_info));

    return PJ_SUCCESS;
}
Example #8
0
int rtcwake_main(int argc UNUSED_PARAM, char **argv)
{
	unsigned opt;
	const char *rtcname = NULL;
	const char *suspend = "standby";
	const char *opt_seconds;
	const char *opt_time;

	time_t rtc_time;
	time_t sys_time;
	time_t alarm_time = alarm_time;
	unsigned seconds = seconds; /* for compiler */
	int utc = -1;
	int fd;

#if ENABLE_LONG_OPTS
	static const char rtcwake_longopts[] ALIGN1 =
		"auto\0"    No_argument "a"
		"local\0"   No_argument "l"
		"utc\0"     No_argument "u"
		"device\0"  Required_argument "d"
		"mode\0"    Required_argument "m"
		"seconds\0" Required_argument "s"
		"time\0"    Required_argument "t"
		;
#endif
	opt = getopt32long(argv,
			/* Must have -s or -t, exclusive */
			"^alud:m:s:t:" "\0" "s:t:s--t:t--s", rtcwake_longopts,
			&rtcname, &suspend, &opt_seconds, &opt_time);

	/* this is the default
	if (opt & RTCWAKE_OPT_AUTO)
		utc = -1;
	*/
	if (opt & (RTCWAKE_OPT_UTC | RTCWAKE_OPT_LOCAL))
		utc = opt & RTCWAKE_OPT_UTC;
	if (opt & RTCWAKE_OPT_SECONDS) {
		/* alarm time, seconds-to-sleep (relative) */
		seconds = xatou(opt_seconds);
	} else {
		/* RTCWAKE_OPT_TIME */
		/* alarm time, time_t (absolute, seconds since 1/1 1970 UTC) */
		if (sizeof(alarm_time) <= sizeof(long))
			alarm_time = xatol(opt_time);
		else
			alarm_time = xatoll(opt_time);
	}

	if (utc == -1)
		utc = rtc_adjtime_is_utc();

	/* the rtcname is relative to /dev */
	xchdir("/dev");

	/* this RTC must exist and (if we'll sleep) be wakeup-enabled */
	fd = rtc_xopen(&rtcname, O_RDONLY);

	if (strcmp(suspend, "on") != 0)
		if (!may_wakeup(rtcname))
			bb_error_msg_and_die("%s not enabled for wakeup events", rtcname);

	/* relative or absolute alarm time, normalized to time_t */
	sys_time = time(NULL);
	{
		struct tm tm_time;
		rtc_read_tm(&tm_time, fd);
		rtc_time = rtc_tm2time(&tm_time, utc);
	}

	if (opt & RTCWAKE_OPT_TIME) {
		/* Correct for RTC<->system clock difference */
		alarm_time += rtc_time - sys_time;
		if (alarm_time < rtc_time)
			/*
			 * Compat message text.
			 * I'd say "RTC time is already ahead of ..." instead.
			 */
			bb_error_msg_and_die("time doesn't go backward to %s", ctime(&alarm_time));
	} else
		alarm_time = rtc_time + seconds + 1;

	setup_alarm(fd, &alarm_time, rtc_time);
	sync();
#if 0 /*debug*/
	printf("sys_time: %s", ctime(&sys_time));
	printf("rtc_time: %s", ctime(&rtc_time));
#endif
	printf("wakeup from \"%s\" at %s", suspend, ctime(&alarm_time));
	fflush_all();
	usleep(10 * 1000);

	if (strcmp(suspend, "on") != 0)
		xopen_xwrite_close(SYS_POWER_PATH, suspend);
	else {
		/* "fake" suspend ... we'll do the delay ourselves */
		unsigned long data;

		do {
			ssize_t ret = safe_read(fd, &data, sizeof(data));
			if (ret < 0) {
				bb_perror_msg("rtc read");
				break;
			}
		} while (!(data & RTC_AF));
	}

	xioctl(fd, RTC_AIE_OFF, 0);

	if (ENABLE_FEATURE_CLEAN_UP)
		close(fd);

	return EXIT_SUCCESS;
}
Example #9
0
void Camera::Init() {
  struct v4l2_capability cap;
  struct v4l2_cropcap cropcap;
  struct v4l2_crop crop;
  struct v4l2_format fmt;
  unsigned int min;

  if(-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap)) {
    if (EINVAL == errno) {
      fprintf(stderr, "%s is no V4L2 device\n",name);
      exit(1);
    } else {
       errno_exit("VIDIOC_QUERYCAP");
    }
  }

  if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
    fprintf(stderr, "%s is no video capture device\n", name);
    exit(1);
  }

  switch(io) {
    case IO_METHOD_READ:
      if(!(cap.capabilities & V4L2_CAP_READWRITE)) {
        fprintf(stderr, "%s does not support read i/o\n", name);
        exit (1);
      }

      break;

    case IO_METHOD_MMAP:
    case IO_METHOD_USERPTR:
    if(!(cap.capabilities & V4L2_CAP_STREAMING)) {
      fprintf (stderr, "%s does not support streaming i/o\n", name);
      exit(1);
    }

    break;
  }


  CLEAR (cropcap);

  cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  if(0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
    crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    crop.c = cropcap.defrect; /* reset to default */

    if(-1 == xioctl (fd, VIDIOC_S_CROP, &crop)) {
      switch (errno) {
        case EINVAL:
          /* Cropping not supported. */
          break;
        default:
          /* Errors ignored. */
          break;
        }
      }
    } else {
      /* Errors ignored. */
    }

    CLEAR (fmt);

    fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width       = width;
    fmt.fmt.pix.height      = height;
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
    fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;


  if(-1 == xioctl (fd, VIDIOC_S_FMT, &fmt))
    errno_exit ("VIDIOC_S_FMT");



/*
struct v4l2_standard s;
s.name[0]='A';
s.frameperiod.numerator=1;
s.frameperiod.denominator=fps;

if(-1==xioctl(fd, VIDIOC_S_STD, &s))
  errno_exit("VIDIOC_S_STD");
*/


struct v4l2_streamparm p;
p.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
//p.parm.capture.capability=V4L2_CAP_TIMEPERFRAME;
//p.parm.capture.capturemode=V4L2_MODE_HIGHQUALITY;
p.parm.capture.timeperframe.numerator=1;
p.parm.capture.timeperframe.denominator=fps;
p.parm.output.timeperframe.numerator=1;
p.parm.output.timeperframe.denominator=fps;
//p.parm.output.outputmode=V4L2_MODE_HIGHQUALITY;
//p.parm.capture.extendedmode=0;
//p.parm.capture.readbuffers=n_buffers;


if(-1==xioctl(fd, VIDIOC_S_PARM, &p))
  errno_exit("VIDIOC_S_PARM");

  //default values, mins and maxes
  struct v4l2_queryctrl queryctrl;

  memset(&queryctrl, 0, sizeof(queryctrl));
  queryctrl.id = V4L2_CID_BRIGHTNESS;
  if(-1 == xioctl (fd, VIDIOC_QUERYCTRL, &queryctrl)) {
    if(errno != EINVAL) {
      //perror ("VIDIOC_QUERYCTRL");
      //exit(EXIT_FAILURE);
      printf("brightness error\n");
    } else {
      printf("brightness is not supported\n");
    }
  } else if(queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
    printf ("brightness is not supported\n");
  }
  mb=queryctrl.minimum;
  Mb=queryctrl.maximum;
  db=queryctrl.default_value;


  memset(&queryctrl, 0, sizeof(queryctrl));
  queryctrl.id = V4L2_CID_CONTRAST;
  if(-1 == xioctl (fd, VIDIOC_QUERYCTRL, &queryctrl)) {
    if(errno != EINVAL) {
      //perror ("VIDIOC_QUERYCTRL");
      //exit(EXIT_FAILURE);
      printf("contrast error\n");
    } else {
      printf("contrast is not supported\n");
    }
  } else if(queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
    printf ("contrast is not supported\n");
  }
  mc=queryctrl.minimum;
  Mc=queryctrl.maximum;
  dc=queryctrl.default_value;


  memset(&queryctrl, 0, sizeof(queryctrl));
  queryctrl.id = V4L2_CID_SATURATION;
  if(-1 == xioctl (fd, VIDIOC_QUERYCTRL, &queryctrl)) {
    if(errno != EINVAL) {
      //perror ("VIDIOC_QUERYCTRL");
      //exit(EXIT_FAILURE);
      printf("saturation error\n");
    } else {
      printf("saturation is not supported\n");
    }
  } else if(queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
    printf ("saturation is not supported\n");
  }
  ms=queryctrl.minimum;
  Ms=queryctrl.maximum;
  ds=queryctrl.default_value;


  memset(&queryctrl, 0, sizeof(queryctrl));
  queryctrl.id = V4L2_CID_HUE;
  if(-1 == xioctl (fd, VIDIOC_QUERYCTRL, &queryctrl)) {
    if(errno != EINVAL) {
      //perror ("VIDIOC_QUERYCTRL");
      //exit(EXIT_FAILURE);
      printf("hue error\n");
    } else {
      printf("hue is not supported\n");
    }
  } else if(queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
    printf ("hue is not supported\n");
  }
  mh=queryctrl.minimum;
  Mh=queryctrl.maximum;
  dh=queryctrl.default_value;


  memset(&queryctrl, 0, sizeof(queryctrl));
  queryctrl.id = V4L2_CID_HUE_AUTO;
  if(-1 == xioctl (fd, VIDIOC_QUERYCTRL, &queryctrl)) {
    if(errno != EINVAL) {
      //perror ("VIDIOC_QUERYCTRL");
      //exit(EXIT_FAILURE);
      printf("hueauto error\n");
    } else {
      printf("hueauto is not supported\n");
    }
  } else if(queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
    printf ("hueauto is not supported\n");
  }
  ha=queryctrl.default_value;


  memset(&queryctrl, 0, sizeof(queryctrl));
  queryctrl.id = V4L2_CID_SHARPNESS;
  if(-1 == xioctl (fd, VIDIOC_QUERYCTRL, &queryctrl)) {
    if(errno != EINVAL) {
      //perror ("VIDIOC_QUERYCTRL");
      //exit(EXIT_FAILURE);
      printf("sharpness error\n");
    } else {
      printf("sharpness is not supported\n");
    }
  } else if(queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
    printf ("sharpness is not supported\n");
  }
  msh=queryctrl.minimum;
  Msh=queryctrl.maximum;
  dsh=queryctrl.default_value;

//TODO: TO ADD SETTINGS
//here should go custom calls to xioctl

//END TO ADD SETTINGS

  /* Note VIDIOC_S_FMT may change width and 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;

  switch(io) {
    case IO_METHOD_READ:
      init_read(fmt.fmt.pix.sizeimage);
      break;

    case IO_METHOD_MMAP:
      init_mmap();
      break;

    case IO_METHOD_USERPTR:
      init_userp(fmt.fmt.pix.sizeimage);
      break;
    }

}
Example #10
0
static int
read_frame (V4L2WHandler_t * handle, int (*process_frame)(V4L2WHandler_t *, const void *, int))
{
        struct v4l2_buffer buf;
        unsigned int i;

        switch (handle->io) {
        case IO_METHOD_READ:
                if (-1 == read (handle->fd, handle->buffers[0].start, handle->buffers[0].length)) {
                        switch (errno) {
                        case EAGAIN:
                                return 0;

                        case EIO:
                                /* Could ignore EIO, see spec. */

                                /* fall through */

                        default:
                                errno_exit ("read");
                        }
                }

                process_frame (handle, handle->buffers[0].start, buf.bytesused);

                break;

        case IO_METHOD_MMAP:
                CLEAR (buf);

                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                buf.memory = V4L2_MEMORY_MMAP;

                if (-1 == xioctl (handle->fd, VIDIOC_DQBUF, &buf)) {
                        switch (errno) {
                        case EAGAIN:
                                return 0;

                        case EIO:
                                /* Could ignore EIO, see spec. */

                                /* fall through */

                        default:
                                errno_exit ("VIDIOC_DQBUF");
                        }
                }

                assert (buf.index < handle->n_buffers);

                process_frame (handle, handle->buffers[buf.index].start, buf.bytesused);
                // fprintf(stderr, "%d\n", buf.bytesused);

                if (-1 == xioctl (handle->fd, VIDIOC_QBUF, &buf))
                        errno_exit ("VIDIOC_QBUF");

                break;

        case IO_METHOD_USERPTR:
                CLEAR (buf);

                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                buf.memory = V4L2_MEMORY_USERPTR;

                if (-1 == xioctl (handle->fd, VIDIOC_DQBUF, &buf)) {
                        switch (errno) {
                        case EAGAIN:
                                return 0;

                        case EIO:
                                /* Could ignore EIO, see spec. */

                                /* fall through */

                        default:
                                errno_exit ("VIDIOC_DQBUF");
                        }
                }

                for (i = 0; i < handle->n_buffers; ++i)
                        if (buf.m.userptr == (unsigned long) handle->buffers[i].start
                            && buf.length == handle->buffers[i].length)
                                break;

                assert (i < handle->n_buffers);

                process_frame (handle, (void *) buf.m.userptr, buf.bytesused);

                if (-1 == xioctl (handle->fd, VIDIOC_QBUF, &buf))
                        errno_exit ("VIDIOC_QBUF");

                break;
        }

        return 1;
}
Example #11
0
static void
init_device                     (V4L2WHandler_t * handle)
{
        struct v4l2_capability cap;
        struct v4l2_cropcap cropcap;
        struct v4l2_crop crop;
        struct v4l2_format fmt;
        struct v4l2_streamparm stream;
        unsigned int min;

        if (-1 == xioctl (handle->fd, VIDIOC_QUERYCAP, &cap)) {
                if (EINVAL == errno) {
                        fprintf (stderr, "%s is no V4L2 device\n",
                                 handle->dev_name);
                        exit (EXIT_FAILURE);
                } else {
                        errno_exit ("VIDIOC_QUERYCAP");
                }
        }

        if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
                fprintf (stderr, "%s is no video capture device\n",
                         handle->dev_name);
                exit (EXIT_FAILURE);
        }

        switch (handle->io) {
        case IO_METHOD_READ:
                if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
                        fprintf (stderr, "%s does not support read i/o\n",
                                 handle->dev_name);
                        exit (EXIT_FAILURE);
                }

                break;

        case IO_METHOD_MMAP:
        case IO_METHOD_USERPTR:
                if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
                        fprintf (stderr, "%s does not support streaming i/o\n",
                                 handle->dev_name);
                        exit (EXIT_FAILURE);
                }

                break;
        }


        /* Select video input, video standard and tune here. */


        CLEAR (cropcap);

        cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

        if (0 == xioctl (handle->fd, VIDIOC_CROPCAP, &cropcap)) {
                crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                crop.c = cropcap.defrect; /* reset to default */

                if (-1 == xioctl (handle->fd, VIDIOC_S_CROP, &crop)) {
                        switch (errno) {
                        case EINVAL:
                                /* Cropping not supported. */
                                break;
                        default:
                                /* Errors ignored. */
                                break;
                        }
                }
        } else {        
                /* Errors ignored. */
        }


        CLEAR (fmt);

        fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        fmt.fmt.pix.width       = handle->imgparam.width; 
        fmt.fmt.pix.height      = handle->imgparam.height;
        fmt.fmt.pix.pixelformat = handle->imgparam.pix_fmt;
        fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;

        if (-1 == xioctl (handle->fd, VIDIOC_S_FMT, &fmt))
                errno_exit ("VIDIOC_S_FMT");

        CLEAR (stream);

        stream.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;        
        stream.parm.capture.timeperframe.numerator = 1;
        stream.parm.capture.timeperframe.denominator = handle->imgparam.fps;
        /* stream.parm.capture.timeperframe.numerator = 1; */
        /* stream.parm.capture.timeperframe.denominator = 10; */
        stream.parm.capture.readbuffers = 4;

        if (-1 == xioctl (handle->fd, VIDIOC_S_PARM, &stream))
                errno_exit ("VIDIOC_S_PARM");
        //printf("%d %d/n", stream.parm.capture.timeperframe.numerator, stream.parm.capture.timeperframe.denominator);
        stream.parm.capture.readbuffers = 4;

        /* Note VIDIOC_S_FMT may change width and 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;

        switch (handle->io) {
        case IO_METHOD_READ:
                init_read (handle, fmt.fmt.pix.sizeimage);
                break;

        case IO_METHOD_MMAP:
                init_mmap (handle);
                break;

        case IO_METHOD_USERPTR:
                init_userp (handle, fmt.fmt.pix.sizeimage);
                break;
        }

        int ii;
                for (ii = 0; ii < handle->n_buffers; ii++) {
                    memset(handle->buffers[ii].start, 0, handle->buffers[ii].length);
                }
}
Example #12
0
int zcip_main(int argc UNUSED_PARAM, char **argv)
{
	char *r_opt;
	const char *l_opt = "169.254.0.0";
	int state;
	int nsent;
	unsigned opts;

	// Ugly trick, but I want these zeroed in one go
	struct {
		const struct ether_addr null_ethaddr;
		struct ifreq ifr;
		uint32_t chosen_nip;
		int conflicts;
		int timeout_ms; // must be signed
		int verbose;
	} L;
#define null_ethaddr (L.null_ethaddr)
#define ifr          (L.ifr         )
#define chosen_nip   (L.chosen_nip  )
#define conflicts    (L.conflicts   )
#define timeout_ms   (L.timeout_ms  )
#define verbose      (L.verbose     )

	memset(&L, 0, sizeof(L));
	INIT_G();

#define FOREGROUND (opts & 1)
#define QUIT       (opts & 2)
	// Parse commandline: prog [options] ifname script
	// exactly 2 args; -v accumulates and implies -f
	opt_complementary = "=2:vv:vf";
	opts = getopt32(argv, "fqr:l:v", &r_opt, &l_opt, &verbose);
#if !BB_MMU
	// on NOMMU reexec early (or else we will rerun things twice)
	if (!FOREGROUND)
		bb_daemonize_or_rexec(0 /*was: DAEMON_CHDIR_ROOT*/, argv);
#endif
	// Open an ARP socket
	// (need to do it before openlog to prevent openlog from taking
	// fd 3 (sock_fd==3))
	xmove_fd(xsocket(AF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)), sock_fd);
	if (!FOREGROUND) {
		// do it before all bb_xx_msg calls
		openlog(applet_name, 0, LOG_DAEMON);
		logmode |= LOGMODE_SYSLOG;
	}
	bb_logenv_override();

	{ // -l n.n.n.n
		struct in_addr net;
		if (inet_aton(l_opt, &net) == 0
		 || (net.s_addr & htonl(IN_CLASSB_NET)) != net.s_addr
		) {
			bb_error_msg_and_die("invalid network address");
		}
		G.localnet_ip = ntohl(net.s_addr);
	}
	if (opts & 4) { // -r n.n.n.n
		struct in_addr ip;
		if (inet_aton(r_opt, &ip) == 0
		 || (ntohl(ip.s_addr) & IN_CLASSB_NET) != G.localnet_ip
		) {
			bb_error_msg_and_die("invalid link address");
		}
		chosen_nip = ip.s_addr;
	}
	argv += optind - 1;

	/* Now: argv[0]:junk argv[1]:intf argv[2]:script argv[3]:NULL */
	/* We need to make space for script argument: */
	argv[0] = argv[1];
	argv[1] = argv[2];
	/* Now: argv[0]:intf argv[1]:script argv[2]:junk argv[3]:NULL */
#define argv_intf (argv[0])

	xsetenv("interface", argv_intf);

	// Initialize the interface (modprobe, ifup, etc)
	if (run(argv, "init", 0))
		return EXIT_FAILURE;

	// Initialize G.iface_sockaddr
	// G.iface_sockaddr is: { u16 sa_family; u8 sa_data[14]; }
	//memset(&G.iface_sockaddr, 0, sizeof(G.iface_sockaddr));
	//TODO: are we leaving sa_family == 0 (AF_UNSPEC)?!
	safe_strncpy(G.iface_sockaddr.sa_data, argv_intf, sizeof(G.iface_sockaddr.sa_data));

	// Bind to the interface's ARP socket
	xbind(sock_fd, &G.iface_sockaddr, sizeof(G.iface_sockaddr));

	// Get the interface's ethernet address
	//memset(&ifr, 0, sizeof(ifr));
	strncpy_IFNAMSIZ(ifr.ifr_name, argv_intf);
	xioctl(sock_fd, SIOCGIFHWADDR, &ifr);
	memcpy(&G.our_ethaddr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);

	// Start with some stable ip address, either a function of
	// the hardware address or else the last address we used.
	// we are taking low-order four bytes, as top-order ones
	// aren't random enough.
	// NOTE: the sequence of addresses we try changes only
	// depending on when we detect conflicts.
	{
		uint32_t t;
		move_from_unaligned32(t, ((char *)&G.our_ethaddr + 2));
		t += getpid();
		srand(t);
	}
	// FIXME cases to handle:
	//  - zcip already running!
	//  - link already has local address... just defend/update

	// Daemonize now; don't delay system startup
	if (!FOREGROUND) {
#if BB_MMU
		bb_daemonize(0 /*was: DAEMON_CHDIR_ROOT*/);
#endif
		bb_info_msg("start, interface %s", argv_intf);
	}

	// Run the dynamic address negotiation protocol,
	// restarting after address conflicts:
	//  - start with some address we want to try
	//  - short random delay
	//  - arp probes to see if another host uses it
	//    00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff arp who-has 169.254.194.171 tell 0.0.0.0
	//  - arp announcements that we're claiming it
	//    00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff arp who-has 169.254.194.171 (00:04:e2:64:23:c2) tell 169.254.194.171
	//  - use it
	//  - defend it, within limits
	// exit if:
	// - address is successfully obtained and -q was given:
	//   run "<script> config", then exit with exitcode 0
	// - poll error (when does this happen?)
	// - read error (when does this happen?)
	// - sendto error (in send_arp_request()) (when does this happen?)
	// - revents & POLLERR (link down). run "<script> deconfig" first
	if (chosen_nip == 0) {
 new_nip_and_PROBE:
		chosen_nip = pick_nip();
	}
	nsent = 0;
	state = PROBE;
	while (1) {
		struct pollfd fds[1];
		unsigned deadline_us;
		struct arp_packet p;
		int ip_conflict;
		int n;

		fds[0].fd = sock_fd;
		fds[0].events = POLLIN;
		fds[0].revents = 0;

		// Poll, being ready to adjust current timeout
		if (!timeout_ms) {
			timeout_ms = random_delay_ms(PROBE_WAIT);
			// FIXME setsockopt(sock_fd, SO_ATTACH_FILTER, ...) to
			// make the kernel filter out all packets except
			// ones we'd care about.
		}
		// Set deadline_us to the point in time when we timeout
		deadline_us = MONOTONIC_US() + timeout_ms * 1000;

		VDBG("...wait %d %s nsent=%u\n",
				timeout_ms, argv_intf, nsent);

		n = safe_poll(fds, 1, timeout_ms);
		if (n < 0) {
			//bb_perror_msg("poll"); - done in safe_poll
			return EXIT_FAILURE;
		}
		if (n == 0) { // timed out?
			VDBG("state:%d\n", state);
			switch (state) {
			case PROBE:
				// No conflicting ARP packets were seen:
				// we can progress through the states
				if (nsent < PROBE_NUM) {
					nsent++;
					VDBG("probe/%u %s@%s\n",
							nsent, argv_intf, nip_to_a(chosen_nip));
					timeout_ms = PROBE_MIN * 1000;
					timeout_ms += random_delay_ms(PROBE_MAX - PROBE_MIN);
					send_arp_request(0, &null_ethaddr, chosen_nip);
					continue;
				}
  				// Switch to announce state
				nsent = 0;
				state = ANNOUNCE;
				goto send_announce;
			case ANNOUNCE:
				// No conflicting ARP packets were seen:
				// we can progress through the states
				if (nsent < ANNOUNCE_NUM) {
 send_announce:
					nsent++;
					VDBG("announce/%u %s@%s\n",
							nsent, argv_intf, nip_to_a(chosen_nip));
					timeout_ms = ANNOUNCE_INTERVAL * 1000;
					send_arp_request(chosen_nip, &G.our_ethaddr, chosen_nip);
					continue;
				}
				// Switch to monitor state
				// FIXME update filters
				run(argv, "config", chosen_nip);
				// NOTE: all other exit paths should deconfig...
				if (QUIT)
					return EXIT_SUCCESS;
				// fall through: switch to MONITOR
			default:
			// case DEFEND:
			// case MONITOR: (shouldn't happen, MONITOR timeout is infinite)
				// Defend period ended with no ARP replies - we won
				timeout_ms = -1; // never timeout in monitor state
				state = MONITOR;
				continue;
			}
		}

		// Packet arrived, or link went down.
		// We need to adjust the timeout in case we didn't receive
		// a conflicting packet.
		if (timeout_ms > 0) {
			unsigned diff = deadline_us - MONOTONIC_US();
			if ((int)(diff) < 0) {
				// Current time is greater than the expected timeout time.
				diff = 0;
			}
			VDBG("adjusting timeout\n");
			timeout_ms = (diff / 1000) | 1; // never 0
		}

		if ((fds[0].revents & POLLIN) == 0) {
			if (fds[0].revents & POLLERR) {
				// FIXME: links routinely go down;
				// this shouldn't necessarily exit.
				bb_error_msg("iface %s is down", argv_intf);
				if (state >= MONITOR) {
					// Only if we are in MONITOR or DEFEND
					run(argv, "deconfig", chosen_nip);
				}
				return EXIT_FAILURE;
			}
			continue;
		}

		// Read ARP packet
		if (safe_read(sock_fd, &p, sizeof(p)) < 0) {
			bb_perror_msg_and_die(bb_msg_read_error);
		}

		if (p.eth.ether_type != htons(ETHERTYPE_ARP))
			continue;
		if (p.arp.arp_op != htons(ARPOP_REQUEST)
		 && p.arp.arp_op != htons(ARPOP_REPLY)
		) {
			continue;
		}
#ifdef DEBUG
		{
			struct ether_addr *sha = (struct ether_addr *) p.arp.arp_sha;
			struct ether_addr *tha = (struct ether_addr *) p.arp.arp_tha;
			struct in_addr *spa = (struct in_addr *) p.arp.arp_spa;
			struct in_addr *tpa = (struct in_addr *) p.arp.arp_tpa;
			VDBG("source=%s %s\n", ether_ntoa(sha),	inet_ntoa(*spa));
			VDBG("target=%s %s\n", ether_ntoa(tha),	inet_ntoa(*tpa));
		}
#endif
		ip_conflict = 0;
		if (memcmp(&p.arp.arp_sha, &G.our_ethaddr, ETH_ALEN) != 0) {
			if (memcmp(p.arp.arp_spa, &chosen_nip, 4) == 0) {
				// A probe or reply with source_ip == chosen ip
				ip_conflict = 1;
			}
			if (p.arp.arp_op == htons(ARPOP_REQUEST)
			 && memcmp(p.arp.arp_spa, &const_int_0, 4) == 0
			 && memcmp(p.arp.arp_tpa, &chosen_nip, 4) == 0
			) {
				// A probe with source_ip == 0.0.0.0, target_ip == chosen ip:
				// another host trying to claim this ip!
				ip_conflict |= 2;
			}
		}
		VDBG("state:%d ip_conflict:%d\n", state, ip_conflict);
		if (!ip_conflict)
			continue;

		// Either src or target IP conflict exists
		if (state <= ANNOUNCE) {
			// PROBE or ANNOUNCE
			conflicts++;
			timeout_ms = PROBE_MIN * 1000
				+ CONFLICT_MULTIPLIER * random_delay_ms(conflicts);
			goto new_nip_and_PROBE;
		}

		// MONITOR or DEFEND: only src IP conflict is a problem
		if (ip_conflict & 1) {
			if (state == MONITOR) {
				// Src IP conflict, defend with a single ARP probe
				VDBG("monitor conflict - defending\n");
				timeout_ms = DEFEND_INTERVAL * 1000;
				state = DEFEND;
				send_arp_request(chosen_nip, &G.our_ethaddr, chosen_nip);
				continue;
			}
			// state == DEFEND
			// Another src IP conflict, start over
			VDBG("defend conflict - starting over\n");
			run(argv, "deconfig", chosen_nip);
			conflicts = 0;
			timeout_ms = 0;
			goto new_nip_and_PROBE;
		}
		// Note: if we only have a target IP conflict here (ip_conflict & 2),
		// IOW: if we just saw this sort of ARP packet:
		//  aa:bb:cc:dd:ee:ff > xx:xx:xx:xx:xx:xx arp who-has <chosen_nip> tell 0.0.0.0
		// we expect _kernel_ to respond to that, because <chosen_nip>
		// is (expected to be) configured on this iface.
	} // while (1)
#undef argv_intf
}
Example #13
0
static void device_read_thread(v4l_device_t *dev)
{
  int working;
  int frame;

  dprintf("Entering read thread\n");

  /* Queue all available frame buffers */
  if ( dev->streaming ) {
    for (frame = 0; frame < dev->mbuf.frames; frame++)
      device_qbuf_streaming(dev, frame);
  }

  frame = 0;
  working = 1;

  while ( working ) {
    unsigned char index;
    int ret = 0;

    /* Get an available output buffer */
    if ( dev->read_in[1] != -1 ) {
      ret = read(dev->read_in[0], &index, 1);
    }

    if ( ret == 1 ) {
      unsigned char *ibuf = NULL;
      int isize = 0;

      dprintf("Read thread input: buf%d\n", index);
      dev->h.bufs[index].bytesused = 0;

      /* Read input buffer from capture device */
      if ( dev->streaming ) {
	dprintf("ioctl(VIDIOCSYNC,%d)\n", frame);
	if ( xioctl(dev->fd, VIDIOCSYNC, &frame) == -1 ) {
	  eprintf("%s: ioctl(VIDIOCSYNC,%d): %s\n", dev->h.name, frame, strerror(errno));
	  exit(EXIT_FAILURE);
	}

	ibuf = dev->buf + dev->mbuf.offsets[frame];
	isize = dev->imagesize;
      }
      else {
	ibuf = dev->buf;
	isize = read(dev->fd, ibuf, dev->imagesize);

	if ( isize < 0 ) {
	  if ( (errno != EAGAIN) && (errno != EINTR) ) {
	    eprintf("%s: read(%lu): %s\n", dev->h.name, dev->imagesize, strerror(errno));
	    exit(EXIT_FAILURE);
	  }
	  else {
	    isize = 0;
	  }
	}
      }

      /* Copy input buffer to output buffer */
      if ( isize > 0 ) {
	int length = 0;

	dprintf("Got %d bytes from capture device\n", isize);

	if ( dev->decoder != NULL ) {
	  if ( dev->decoder->process != NULL ) {
	    length = dev->decoder->process(dev->decoder,
					   ibuf, isize,
					   dev->h.bufs[index].base, dev->h.bufs[index].length);
	  }
	}
	else {
	  length = isize;
	  if ( length > dev->h.bufs[index].length )
	    length = dev->h.bufs[index].length;
	  memcpy(dev->h.bufs[index].base, ibuf, length);
	}

	dev->h.bufs[index].bytesused = length;
      }

      /* Send filled output buffer back for processing */
      if ( dev->streaming ) {
	device_qbuf_streaming(dev, frame);

	frame++;
	if ( frame >= dev->mbuf.frames )
	  frame = 0;
      }

      if ( dev->read_out[1] != -1 ) {
	dprintf("Read thread output: buf%d\n", index);
	if ( write(dev->read_out[1], &index, 1) != 1 ) {
	  eprintf("%s: Read output pipe: write error: %s\n", dev->h.name, strerror(errno));
	  exit(EXIT_FAILURE);
	}
      }
    }
    else if ( ret == 0 ) {
      working = 0;
    }
    else if ( ret == -1 ) {
      if ( (errno != EAGAIN) && (errno != EINTR) ) {
	eprintf("Read input pipe: read error: %s\n", strerror(errno));
	working = 0;
      }
    }
  }

  dprintf("Leaving read thread\n");
}
Example #14
0
static int device_init_format(v4l_device_t *dev)
{
  struct video_window window;
  struct video_picture picture;
  int palette;
  unsigned long pixelformat2 = 0;

  /* Get frame size */
  if ( xioctl(dev->fd, VIDIOCGWIN, &window) == -1 ) {
    eprintf("%s: Cannot get video device window: %s\n",
	    dev->h.name, strerror(errno));
    return -1;
  }

  dprintf("%s: VIDIOCGWIN -> width=%d height=%d\n", dev->h.name, window.width, window.height);
  dev->h.width = window.width;
  dev->h.height = window.height;

  /* Choose an acceptable pixel format */
  if ( xioctl(dev->fd, VIDIOCGPICT, &picture) == -1 ) {
    eprintf("%s: Cannot get video device picture format: %s\n",
	    dev->h.name, strerror(errno));
    return -1;
  }

  dprintf("%s: VIDIOCGPICT -> palette=%d currently selected\n", dev->h.name, picture.palette);
  palette = picture.palette;

  picture.palette = VIDEO_PALETTE_RGB24;
  if ( xioctl(dev->fd, VIDIOCSPICT, &picture) == 0 ) {
    palette = picture.palette;
  }
  else {
    dprintf("%s: VIDIOCSPICT -> palette=%d rejected\n", dev->h.name, picture.palette);
  }

  dev->pixelformat = palette;
  dev->imagesize = dev->h.width * dev->h.height * picture.depth / 8;
  dprintf("%s: Using palette=%d - imagesize=%lu\n", dev->h.name, palette, dev->imagesize);

  switch ( palette ) {
  case VIDEO_PALETTE_RGB24:
    dev->h.pixfmt = CAPTURE_PIXFMT_BGR24;  /* V4L1 RGB is actually BGR */
    pixelformat2 = V4L2_PIX_FMT_BGR24;
    break;
  case VIDEO_PALETTE_YUV420:
    dev->h.pixfmt = CAPTURE_PIXFMT_RGB24;
    pixelformat2 = V4L2_PIX_FMT_YUV420;
    dev->decoder = yuv_create(pixelformat2, dev->h.width, dev->h.height);
    break;
  default:
    eprintf("%s: Video device does not support pixel formats RGB24/YUV420\n",
	    dev->h.name);
    eprintf("%s: Video device only supports format #%d\n",
	    dev->h.name, palette);
    return -1;
    break;
  }

  /* Set pixel format string */
  dev->pixelformat_str[0] = (pixelformat2 >> 0)  & 0xFF;
  dev->pixelformat_str[1] = (pixelformat2 >> 8)  & 0xFF;
  dev->pixelformat_str[2] = (pixelformat2 >> 16) & 0xFF;
  dev->pixelformat_str[3] = (pixelformat2 >> 24) & 0xFF;
  dev->pixelformat_str[4] = '\0';

  /* Check for streaming capabilitiy */
  if ( xioctl(dev->fd, VIDIOCGMBUF, &(dev->mbuf)) == 0 ) {
    dprintf("%s: VIDIOCGMBUF -> size=%d frames=%d\n",
	    dev->h.name, dev->mbuf.size, dev->mbuf.frames);
    if ( dev->mbuf.frames > 0 ) {
      dev->streaming = 1;
      dprintf("%s: Streaming mode enabled\n", dev->h.name);
    }
  }

  return 0;
}
Example #15
0
int inotifyd_main(int argc, char **argv)
{
	int n;
	unsigned mask;
	struct pollfd pfd;
	char **watches; // names of files being watched
	const char *args[5];

	// sanity check: agent and at least one watch must be given
	if (!argv[1] || !argv[2])
		bb_show_usage();

	argv++;
	// inotify_add_watch will number watched files
	// starting from 1, thus watches[0] is unimportant,
	// and 1st file name is watches[1].
	watches = argv;
	args[0] = *argv;
	args[4] = NULL;
	argc -= 2; // number of files we watch

	// open inotify
	pfd.fd = inotify_init();
	if (pfd.fd < 0)
		bb_perror_msg_and_die("no kernel support");

	// setup watches
	while (*++argv) {
		char *path = *argv;
		char *masks = strchr(path, ':');

		mask = 0x0fff; // assuming we want all non-kernel events
		// if mask is specified ->
		if (masks) {
			*masks = '\0'; // split path and mask
			// convert mask names to mask bitset
			mask = 0;
			while (*++masks) {
				const char *found;
				found = memchr(mask_names, *masks, MASK_BITS);
				if (found)
					mask |= (1 << (found - mask_names));
			}
		}
		// add watch
		n = inotify_add_watch(pfd.fd, path, mask);
		if (n < 0)
			bb_perror_msg_and_die("add watch (%s) failed", path);
		//bb_error_msg("added %d [%s]:%4X", n, path, mask);
	}

	// setup signals
	bb_signals(BB_FATAL_SIGS, record_signo);

	// do watch
	pfd.events = POLLIN;
	while (1) {
		int len;
		void *buf;
		struct inotify_event *ie;
 again:
		if (bb_got_signal)
			break;
		n = poll(&pfd, 1, -1);
		// Signal interrupted us?
		if (n < 0 && errno == EINTR)
			goto again;
		// Under Linux, above if() is not necessary.
		// Non-fatal signals, e.g. SIGCHLD, when set to SIG_DFL,
		// are not interrupting poll().
		// Thus we can just break if n <= 0 (see below),
		// because EINTR will happen only on SIGTERM et al.
		// But this might be not true under other Unixes,
		// and is generally way too subtle to depend on.
		if (n <= 0) // strange error?
			break;

		// read out all pending events
		// (NB: len must be int, not ssize_t or long!)
#define eventbuf bb_common_bufsiz1
		setup_common_bufsiz();
		xioctl(pfd.fd, FIONREAD, &len);
		ie = buf = (len <= COMMON_BUFSIZE) ? eventbuf : xmalloc(len);
		len = full_read(pfd.fd, buf, len);
		// process events. N.B. events may vary in length
		while (len > 0) {
			int i;
			// cache relevant events mask
			unsigned m = ie->mask & ((1 << MASK_BITS) - 1);
			if (m) {
				char events[MASK_BITS + 1];
				char *s = events;
				for (i = 0; i < MASK_BITS; ++i, m >>= 1) {
					if ((m & 1) && (mask_names[i] != '\0'))
						*s++ = mask_names[i];
				}
				*s = '\0';
				if (LONE_CHAR(args[0], '-')) {
					/* "inotifyd - FILE": built-in echo */
					printf(ie->len ? "%s\t%s\t%s\n" : "%s\t%s\n", events,
							watches[ie->wd],
							ie->name);
					fflush(stdout);
				} else {
//					bb_error_msg("exec %s %08X\t%s\t%s\t%s", args[0],
//						ie->mask, events, watches[ie->wd], ie->len ? ie->name : "");
					args[1] = events;
					args[2] = watches[ie->wd];
					args[3] = ie->len ? ie->name : NULL;
					spawn_and_wait((char **)args);
				}
				// we are done if all files got final x event
				if (ie->mask & 0x8000) {
					if (--argc <= 0)
						goto done;
					inotify_rm_watch(pfd.fd, ie->wd);
				}
			}
			// next event
			i = sizeof(struct inotify_event) + ie->len;
			len -= i;
			ie = (void*)((char*)ie + i);
		}
		if (eventbuf != buf)
			free(buf);
	} // while (1)
 done:
	return bb_got_signal;
}
Example #16
0
unsigned char *Camera::Get() {
  struct v4l2_buffer buf;

  switch(io) {
    case IO_METHOD_READ:
/*
    		if (-1 == read (fd, buffers[0].start, buffers[0].length)) {
            		switch (errno) {
            		case EAGAIN:
                    		return 0;

			case EIO:


			default:
				errno_exit ("read");
			}
		}

    		process_image (buffers[0].start);
*/
      break;

    case IO_METHOD_MMAP:
      CLEAR(buf);

      buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
      buf.memory = V4L2_MEMORY_MMAP;
      if(-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
        switch (errno) {
          case EAGAIN:
            return 0;
          case EIO:
          default:
            return 0; //errno_exit ("VIDIOC_DQBUF");
        }
      }

      assert(buf.index < (unsigned int)n_buffers);

      memcpy(data, (unsigned char *)buffers[buf.index].start, buffers[buf.index].length);

      if(-1 == xioctl (fd, VIDIOC_QBUF, &buf))
        return 0; //errno_exit ("VIDIOC_QBUF");

    return data;


      break;

    case IO_METHOD_USERPTR:
/*
		CLEAR (buf);

    		buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    		buf.memory = V4L2_MEMORY_USERPTR;

		if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
			switch (errno) {
			case EAGAIN:
				return 0;

			case EIO:


			default:
				errno_exit ("VIDIOC_DQBUF");
			}
		}

		for (i = 0; i < n_buffers; ++i)
			if (buf.m.userptr == (unsigned long) buffers[i].start
			    && buf.length == buffers[i].length)
				break;

		assert (i < n_buffers);

    		process_image ((void *) buf.m.userptr);

		if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
			errno_exit ("VIDIOC_QBUF");
*/
      break;
  }

  return 0;
}
Example #17
0
void init_camera(struct camera *cam) {
	struct v4l2_capability *cap = &(cam->v4l2_cap);
	struct v4l2_cropcap *cropcap = &(cam->v4l2_cropcap);
	struct v4l2_crop *crop = &(cam->crop);
	struct v4l2_format *fmt = &(cam->v4l2_fmt);
	unsigned int min;

	if (-1 == xioctl(cam->fd, VIDIOC_QUERYCAP, cap)) {
		if (EINVAL == errno) {
			fprintf(stderr, "%s is no V4L2 device\n", cam->device_name);
			exit(EXIT_FAILURE);
		} else {
			errno_exit("VIDIOC_QUERYCAP");
		}
	}

	if (!(cap->capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
		fprintf(stderr, "%s is no video capture device\n", cam->device_name);
		exit(EXIT_FAILURE);
	}

	if (!(cap->capabilities & V4L2_CAP_STREAMING)) {
		fprintf(stderr, "%s does not support streaming i/o\n",
				cam->device_name);
		exit(EXIT_FAILURE);
	}

	//#ifdef DEBUG_CAM
	printf("\nVIDOOC_QUERYCAP\n");
	printf("the camera driver is %s\n", cap->driver);
	printf("the camera card is %s\n", cap->card);
	printf("the camera bus info is %s\n", cap->bus_info);
	printf("the version is %d\n", cap->version);
	//#endif
	/* Select video input, video standard and tune here. */

	CLEAR(*cropcap);

	cropcap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

	crop->c.width = cam->width;
	crop->c.height = cam->height;
	crop->c.left = 0;
	crop->c.top = 0;
	crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

	CLEAR(*fmt);

	fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	fmt->fmt.pix.width = cam->width;
	fmt->fmt.pix.height = cam->height;
	fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; //yuv422
	//  fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420  //yuv420 但是我电脑不支持
	fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; //隔行扫描

	if (-1 == xioctl(cam->fd, VIDIOC_S_FMT, fmt))
		errno_exit("VIDIOC_S_FMT");

	/* Note VIDIOC_S_FMT may change width and 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;

	init_mmap(cam);

}
////////////////////////////////////////////////////////////////////////////////
///
/// @fn int captureFrames(int fileDescriptor)
///
///  Creates memory buffers for receiving frames from the video capture device
///  and then enters a frame-capture loop that runs until the terminate flag is
///  toggled.
///
/// @param fileDescriptor The open file descriptor to the camera device
///
/// @return 0 on success, -1 otherwise.
///
////////////////////////////////////////////////////////////////////////////////
int captureFrames(int fileDescriptor) {
  struct v4l2_buffer deviceBuffer;
  struct v4l2_buffer readBuffer;
  struct v4l2_buffer queryBuffer;
  fd_set fileDescriptorSet;
  struct timeval time;
  int ready = -1;
  int i = 0;

  CLEAR(time);

  for(i = 0; i < bufferCount; i++) {
    CLEAR(deviceBuffer);
    CLEAR(queryBuffer);

    deviceBuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    deviceBuffer.memory = V4L2_MEMORY_MMAP;
    deviceBuffer.index = i;

    // Query the device memory buffer for settings
    if (xioctl(fileDescriptor, VIDIOC_QUERYBUF, &deviceBuffer) == -1) {
      perror("Error querying the device memory buffer");
      return -1;
    }

    // Generate memory-mapped buffer to device memory
    frameBuffers[i].length = deviceBuffer.length;
    frameBuffers[i].data = mmap(
        NULL, deviceBuffer.length, PROT_READ | PROT_WRITE, MAP_SHARED,
        fileDescriptor, deviceBuffer.m.offset);

    if (frameBuffers[i].data == MAP_FAILED) {
      perror("Error establishing memory map");
    }

    queryBuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    queryBuffer.memory = V4L2_MEMORY_MMAP;
    queryBuffer.index = i;
    if(xioctl(fileDescriptor, VIDIOC_QBUF, &queryBuffer) == -1) {
      perror("Error establishing device query buffer");
      return -1;
    }
  }

  // Turn video streaming on
  if (xioctl(fileDescriptor, VIDIOC_STREAMON, &queryBuffer.type) == -1) {
    perror("Error starting the device video stream");
    return -1;
  }

  // Begin reading from the device
  while(!terminate) {
    // Initiailize the file descriptor set
    FD_ZERO(&fileDescriptorSet);
    FD_SET(fileDescriptor, &fileDescriptorSet);

    // Set select timeout to be one second
    time.tv_sec = 2;
    time.tv_usec = 0;

    // Wait for signal indicating the device has delivered a frame
    ready = select(fileDescriptor + 1, &fileDescriptorSet, NULL, NULL, &time);
    if (ready == -1) {
      perror("Error waiting on video frame");
      continue;
    }

    // Capture the frame
    CLEAR(readBuffer);
    readBuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    readBuffer.memory = V4L2_MEMORY_MMAP;

    if (xioctl(fileDescriptor, VIDIOC_DQBUF, &readBuffer) == -1) {
      perror("Failed to retrieve frame from device");
    } else {
      fprintf(stderr, ".");
      fflush(stdout);
    }

    if (xioctl(fileDescriptor, VIDIOC_QBUF, &readBuffer) == -1) {
      perror("Error queueing the video buffer");
    }
  }

  return 0;
}
static void init_device(void)
{
  struct v4l2_capability cap;
  struct v4l2_cropcap cropcap;
  struct v4l2_crop crop;
  struct v4l2_format fmt;
  unsigned int min;

  if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap))
  {
    if (EINVAL == errno)
    {
      fprintf(stderr, "%s is no V4L2 device\n", dev_name);
      exit(EXIT_FAILURE);
    }
    else
    {
      errno_exit("VIDIOC_QUERYCAP");
    }
  }

  if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
  {
    fprintf(stderr, "%s is no video capture device\n", dev_name);
    exit(EXIT_FAILURE);
  }

  if (!(cap.capabilities & V4L2_CAP_STREAMING))
  {
    fprintf(stderr, "%s does not support streaming i/o\n", dev_name);
    exit(EXIT_FAILURE);
  }



  /* Select video input, video standard and tune here. */


  CLEAR(cropcap);

  cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap))
  {
    crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    crop.c = cropcap.defrect;   /* reset to default */

    if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop))
    {
      switch (errno)
      {
      case EINVAL:
        /* Cropping not supported. */
        break;
      default:
        /* Errors ignored. */
        break;
      }
    }
  }
  else
  {
      /* Errors ignored. */
  }


  CLEAR(fmt);

  fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  fmt.fmt.pix.width = WIDTH;
  fmt.fmt.pix.height = HEIGHT;
  fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
  fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;

  if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
    errno_exit("VIDIOC_S_FMT");

  /* Note VIDIOC_S_FMT may change width and 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;

  if (WIDTH > fmt.fmt.pix.width)
    errno_exit("Width parameter is too big.\n");

  if (fmt.fmt.pix.height != HEIGHT)
    errno_exit("Height parameter is too big.\n");


  init_mmap();
}
Example #20
0
int zcip_main(int argc UNUSED_PARAM, char **argv)
{
	int state;
	char *r_opt;
	const char *l_opt = "169.254.0.0";
	unsigned opts;

	// ugly trick, but I want these zeroed in one go
	struct {
		const struct in_addr null_ip;
		const struct ether_addr null_addr;
		struct in_addr ip;
		struct ifreq ifr;
		int timeout_ms; /* must be signed */
		unsigned conflicts;
		unsigned nprobes;
		unsigned nclaims;
		int ready;
		int verbose;
	} L;
#define null_ip    (L.null_ip   )
#define null_addr  (L.null_addr )
#define ip         (L.ip        )
#define ifr        (L.ifr       )
#define timeout_ms (L.timeout_ms)
#define conflicts  (L.conflicts )
#define nprobes    (L.nprobes   )
#define nclaims    (L.nclaims   )
#define ready      (L.ready     )
#define verbose    (L.verbose   )

	memset(&L, 0, sizeof(L));
	INIT_G();

#define FOREGROUND (opts & 1)
#define QUIT       (opts & 2)
	// parse commandline: prog [options] ifname script
	// exactly 2 args; -v accumulates and implies -f
	opt_complementary = "=2:vv:vf";
	opts = getopt32(argv, "fqr:l:v", &r_opt, &l_opt, &verbose);
#if !BB_MMU
	// on NOMMU reexec early (or else we will rerun things twice)
	if (!FOREGROUND)
		bb_daemonize_or_rexec(0 /*was: DAEMON_CHDIR_ROOT*/, argv);
#endif
	// open an ARP socket
	// (need to do it before openlog to prevent openlog from taking
	// fd 3 (sock_fd==3))
	xmove_fd(xsocket(AF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)), sock_fd);
	if (!FOREGROUND) {
		// do it before all bb_xx_msg calls
		openlog(applet_name, 0, LOG_DAEMON);
		logmode |= LOGMODE_SYSLOG;
	}
	bb_logenv_override();

	{ // -l n.n.n.n
		struct in_addr net;
		if (inet_aton(l_opt, &net) == 0
		 || (net.s_addr & htonl(IN_CLASSB_NET)) != net.s_addr
		) {
			bb_error_msg_and_die("invalid network address");
		}
		G.localnet_ip = ntohl(net.s_addr);
	}
	if (opts & 4) { // -r n.n.n.n
		if (inet_aton(r_opt, &ip) == 0
		 || (ntohl(ip.s_addr) & IN_CLASSB_NET) != G.localnet_ip
		) {
			bb_error_msg_and_die("invalid link address");
		}
	}
	argv += optind - 1;

	/* Now: argv[0]:junk argv[1]:intf argv[2]:script argv[3]:NULL */
	/* We need to make space for script argument: */
	argv[0] = argv[1];
	argv[1] = argv[2];
	/* Now: argv[0]:intf argv[1]:script argv[2]:junk argv[3]:NULL */
#define argv_intf (argv[0])

	xsetenv("interface", argv_intf);

	// initialize the interface (modprobe, ifup, etc)
	if (run(argv, "init", NULL))
		return EXIT_FAILURE;

	// initialize saddr
	// saddr is: { u16 sa_family; u8 sa_data[14]; }
	//memset(&saddr, 0, sizeof(saddr));
	//TODO: are we leaving sa_family == 0 (AF_UNSPEC)?!
	safe_strncpy(saddr.sa_data, argv_intf, sizeof(saddr.sa_data));

	// bind to the interface's ARP socket
	xbind(sock_fd, &saddr, sizeof(saddr));

	// get the interface's ethernet address
	//memset(&ifr, 0, sizeof(ifr));
	strncpy_IFNAMSIZ(ifr.ifr_name, argv_intf);
	xioctl(sock_fd, SIOCGIFHWADDR, &ifr);
	memcpy(&eth_addr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);

	// start with some stable ip address, either a function of
	// the hardware address or else the last address we used.
	// we are taking low-order four bytes, as top-order ones
	// aren't random enough.
	// NOTE: the sequence of addresses we try changes only
	// depending on when we detect conflicts.
	{
		uint32_t t;
		move_from_unaligned32(t, ((char *)&eth_addr + 2));
		t += getpid();
		srand(t);
	}
	if (ip.s_addr == 0)
		ip.s_addr = pick_nip();

	// FIXME cases to handle:
	//  - zcip already running!
	//  - link already has local address... just defend/update

	// daemonize now; don't delay system startup
	if (!FOREGROUND) {
#if BB_MMU
		bb_daemonize(0 /*was: DAEMON_CHDIR_ROOT*/);
#endif
		bb_info_msg("start, interface %s", argv_intf);
	}

	// run the dynamic address negotiation protocol,
	// restarting after address conflicts:
	//  - start with some address we want to try
	//  - short random delay
	//  - arp probes to see if another host uses it
	//  - arp announcements that we're claiming it
	//  - use it
	//  - defend it, within limits
	// exit if:
	// - address is successfully obtained and -q was given:
	//   run "<script> config", then exit with exitcode 0
	// - poll error (when does this happen?)
	// - read error (when does this happen?)
	// - sendto error (in arp()) (when does this happen?)
	// - revents & POLLERR (link down). run "<script> deconfig" first
	state = PROBE;
	while (1) {
		struct pollfd fds[1];
		unsigned deadline_us;
		struct arp_packet p;
		int source_ip_conflict;
		int target_ip_conflict;

		fds[0].fd = sock_fd;
		fds[0].events = POLLIN;
		fds[0].revents = 0;

		// poll, being ready to adjust current timeout
		if (!timeout_ms) {
			timeout_ms = random_delay_ms(PROBE_WAIT);
			// FIXME setsockopt(sock_fd, SO_ATTACH_FILTER, ...) to
			// make the kernel filter out all packets except
			// ones we'd care about.
		}
		// set deadline_us to the point in time when we timeout
		deadline_us = MONOTONIC_US() + timeout_ms * 1000;

		VDBG("...wait %d %s nprobes=%u, nclaims=%u\n",
				timeout_ms, argv_intf, nprobes, nclaims);

		switch (safe_poll(fds, 1, timeout_ms)) {

		default:
			//bb_perror_msg("poll"); - done in safe_poll
			return EXIT_FAILURE;

		// timeout
		case 0:
			VDBG("state = %d\n", state);
			switch (state) {
			case PROBE:
				// timeouts in the PROBE state mean no conflicting ARP packets
				// have been received, so we can progress through the states
				if (nprobes < PROBE_NUM) {
					nprobes++;
					VDBG("probe/%u %s@%s\n",
							nprobes, argv_intf, inet_ntoa(ip));
					timeout_ms = PROBE_MIN * 1000;
					timeout_ms += random_delay_ms(PROBE_MAX - PROBE_MIN);
					arp(/* ARPOP_REQUEST, */
							/* &eth_addr, */ null_ip,
							&null_addr, ip);
				}
				else {
					// Switch to announce state.
					state = ANNOUNCE;
					nclaims = 0;
					VDBG("announce/%u %s@%s\n",
							nclaims, argv_intf, inet_ntoa(ip));
					timeout_ms = ANNOUNCE_INTERVAL * 1000;
					arp(/* ARPOP_REQUEST, */
							/* &eth_addr, */ ip,
							&eth_addr, ip);
				}
				break;
			case RATE_LIMIT_PROBE:
				// timeouts in the RATE_LIMIT_PROBE state mean no conflicting ARP packets
				// have been received, so we can move immediately to the announce state
				state = ANNOUNCE;
				nclaims = 0;
				VDBG("announce/%u %s@%s\n",
						nclaims, argv_intf, inet_ntoa(ip));
				timeout_ms = ANNOUNCE_INTERVAL * 1000;
				arp(/* ARPOP_REQUEST, */
						/* &eth_addr, */ ip,
						&eth_addr, ip);
				break;
			case ANNOUNCE:
				// timeouts in the ANNOUNCE state mean no conflicting ARP packets
				// have been received, so we can progress through the states
				if (nclaims < ANNOUNCE_NUM) {
					nclaims++;
					VDBG("announce/%u %s@%s\n",
							nclaims, argv_intf, inet_ntoa(ip));
					timeout_ms = ANNOUNCE_INTERVAL * 1000;
					arp(/* ARPOP_REQUEST, */
							/* &eth_addr, */ ip,
							&eth_addr, ip);
				}
				else {
					// Switch to monitor state.
					state = MONITOR;
					// link is ok to use earlier
					// FIXME update filters
					run(argv, "config", &ip);
					ready = 1;
					conflicts = 0;
					timeout_ms = -1; // Never timeout in the monitor state.

					// NOTE: all other exit paths
					// should deconfig ...
					if (QUIT)
						return EXIT_SUCCESS;
				}
				break;
			case DEFEND:
				// We won!  No ARP replies, so just go back to monitor.
				state = MONITOR;
				timeout_ms = -1;
				conflicts = 0;
				break;
			default:
				// Invalid, should never happen.  Restart the whole protocol.
				state = PROBE;
				ip.s_addr = pick_nip();
				timeout_ms = 0;
				nprobes = 0;
				nclaims = 0;
				break;
			} // switch (state)
			break; // case 0 (timeout)

		// packets arriving, or link went down
		case 1:
			// We need to adjust the timeout in case we didn't receive
			// a conflicting packet.
			if (timeout_ms > 0) {
				unsigned diff = deadline_us - MONOTONIC_US();
				if ((int)(diff) < 0) {
					// Current time is greater than the expected timeout time.
					// Should never happen.
					VDBG("missed an expected timeout\n");
					timeout_ms = 0;
				} else {
					VDBG("adjusting timeout\n");
					timeout_ms = (diff / 1000) | 1; /* never 0 */
				}
			}

			if ((fds[0].revents & POLLIN) == 0) {
				if (fds[0].revents & POLLERR) {
					// FIXME: links routinely go down;
					// this shouldn't necessarily exit.
					bb_error_msg("iface %s is down", argv_intf);
					if (ready) {
						run(argv, "deconfig", &ip);
					}
					return EXIT_FAILURE;
				}
				continue;
			}

			// read ARP packet
			if (safe_read(sock_fd, &p, sizeof(p)) < 0) {
				bb_perror_msg_and_die(bb_msg_read_error);
			}
			if (p.eth.ether_type != htons(ETHERTYPE_ARP))
				continue;
#ifdef DEBUG
			{
				struct ether_addr *sha = (struct ether_addr *) p.arp.arp_sha;
				struct ether_addr *tha = (struct ether_addr *) p.arp.arp_tha;
				struct in_addr *spa = (struct in_addr *) p.arp.arp_spa;
				struct in_addr *tpa = (struct in_addr *) p.arp.arp_tpa;
				VDBG("%s recv arp type=%d, op=%d,\n",
					argv_intf, ntohs(p.eth.ether_type),
					ntohs(p.arp.arp_op));
				VDBG("\tsource=%s %s\n",
					ether_ntoa(sha),
					inet_ntoa(*spa));
				VDBG("\ttarget=%s %s\n",
					ether_ntoa(tha),
					inet_ntoa(*tpa));
			}
#endif
			if (p.arp.arp_op != htons(ARPOP_REQUEST)
			 && p.arp.arp_op != htons(ARPOP_REPLY)
			) {
				continue;
			}

			source_ip_conflict = 0;
			target_ip_conflict = 0;

			if (memcmp(&p.arp.arp_sha, &eth_addr, ETH_ALEN) != 0) {
				if (memcmp(p.arp.arp_spa, &ip.s_addr, sizeof(struct in_addr)) == 0) {
					/* A probe or reply with source_ip == chosen ip */
					source_ip_conflict = 1;
				}
				if (p.arp.arp_op == htons(ARPOP_REQUEST)
				 && memcmp(p.arp.arp_spa, &null_ip, sizeof(struct in_addr)) == 0
				 && memcmp(p.arp.arp_tpa, &ip.s_addr, sizeof(struct in_addr)) == 0
				) {
					/* A probe with source_ip == 0.0.0.0, target_ip == chosen ip:
					 * another host trying to claim this ip!
					 */
					target_ip_conflict = 1;
				}
			}

			VDBG("state = %d, source ip conflict = %d, target ip conflict = %d\n",
				state, source_ip_conflict, target_ip_conflict);
			switch (state) {
			case PROBE:
			case ANNOUNCE:
				// When probing or announcing, check for source IP conflicts
				// and other hosts doing ARP probes (target IP conflicts).
				if (source_ip_conflict || target_ip_conflict) {
					conflicts++;
					if (conflicts >= MAX_CONFLICTS) {
						VDBG("%s ratelimit\n", argv_intf);
						timeout_ms = RATE_LIMIT_INTERVAL * 1000;
						state = RATE_LIMIT_PROBE;
					}

					// restart the whole protocol
					ip.s_addr = pick_nip();
					timeout_ms = 0;
					nprobes = 0;
					nclaims = 0;
				}
				break;
			case MONITOR:
				// If a conflict, we try to defend with a single ARP probe.
				if (source_ip_conflict) {
					VDBG("monitor conflict -- defending\n");
					state = DEFEND;
					timeout_ms = DEFEND_INTERVAL * 1000;
					arp(/* ARPOP_REQUEST, */
						/* &eth_addr, */ ip,
						&eth_addr, ip);
				}
				break;
			case DEFEND:
				// Well, we tried.  Start over (on conflict).
				if (source_ip_conflict) {
					state = PROBE;
					VDBG("defend conflict -- starting over\n");
					ready = 0;
					run(argv, "deconfig", &ip);

					// restart the whole protocol
					ip.s_addr = pick_nip();
					timeout_ms = 0;
					nprobes = 0;
					nclaims = 0;
				}
				break;
			default:
				// Invalid, should never happen.  Restart the whole protocol.
				VDBG("invalid state -- starting over\n");
				state = PROBE;
				ip.s_addr = pick_nip();
				timeout_ms = 0;
				nprobes = 0;
				nclaims = 0;
				break;
			} // switch state
			break; // case 1 (packets arriving)
		} // switch poll
	} // while (1)
#undef argv_intf
}
Example #21
0
static int print_caps(int fd)
{
	struct v4l2_capability caps;
	struct v4l2_fmtdesc fmtdesc;
	struct v4l2_format fmt;
	bool support_h264 = false;
	char fourcc[5] = {0};
	char c;
	int err;

	memset(&caps, 0, sizeof(caps));
	memset(&fmtdesc, 0, sizeof(fmtdesc));
	memset(&fmt, 0, sizeof(fmt));

	if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &caps)) {
		err = errno;
		warning("v4l2_codec: error Querying Capabilities (%m)\n", err);
		return err;
	}

	info("v4l2_codec: Driver Caps:\n"
		"  Driver:        \"%s\"\n"
		"  Card:          \"%s\"\n"
		"  Bus:           \"%s\"\n"
		"  Version:       %d.%d\n"
		"  Capabilities:  0x%08x\n",
		caps.driver,
		caps.card,
		caps.bus_info,
		(caps.version>>16) & 0xff,
		(caps.version>>24) & 0xff,
		caps.capabilities);


	fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

	info("  FMT : CE Desc\n--------------------\n");

	while (0 == xioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)) {
		bool selected = fmtdesc.pixelformat == V4L2_PIX_FMT_H264;

		strncpy(fourcc, (char *)&fmtdesc.pixelformat, 4);

		if (fmtdesc.pixelformat == V4L2_PIX_FMT_H264)
		    support_h264 = true;

		c = fmtdesc.flags & V4L2_FMT_FLAG_COMPRESSED ? 'C' : ' ';

		info("  %c  %s: %c  '%s'\n",
		       selected ? '>' : ' ',
		       fourcc, c, fmtdesc.description);

		fmtdesc.index++;
	}

	info("\n");

	if (!support_h264) {
		warning("v4l2_codec: Doesn't support H264.\n");
		return ENODEV;
	}

	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	fmt.fmt.pix.width = v4l2.width;
	fmt.fmt.pix.height = v4l2.height;
	fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
	fmt.fmt.pix.field = V4L2_FIELD_NONE;

	if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt)) {
		err = errno;
		warning("v4l2_codec: Setting Pixel Format (%m)\n", err);
		return err;
	}

	strncpy(fourcc, (char *)&fmt.fmt.pix.pixelformat, 4);
	info("v4l2_codec: Selected Camera Mode:\n"
		"  Width:   %d\n"
		"  Height:  %d\n"
		"  PixFmt:  %s\n"
		"  Field:   %d\n",
		fmt.fmt.pix.width,
		fmt.fmt.pix.height,
		fourcc,
		fmt.fmt.pix.field);

	return 0;
}
Example #22
0
int rtcwake_main(int argc UNUSED_PARAM, char **argv)
{
	time_t rtc_time;

	unsigned opt;
	const char *rtcname = NULL;
	const char *suspend;
	const char *opt_seconds;
	const char *opt_time;

	time_t sys_time;
	time_t alarm_time = 0;
	unsigned seconds = 0;
	int utc = -1;
	int fd;

#if ENABLE_LONG_OPTS
	static const char rtcwake_longopts[] ALIGN1 =
		"auto\0"    No_argument "a"
		"local\0"   No_argument "l"
		"utc\0"     No_argument "u"
		"device\0"  Required_argument "d"
		"mode\0"    Required_argument "m"
		"seconds\0" Required_argument "s"
		"time\0"    Required_argument "t"
		;
	applet_long_options = rtcwake_longopts;
#endif
	opt = getopt32(argv, "alud:m:s:t:", &rtcname, &suspend, &opt_seconds, &opt_time);

	/* this is the default
	if (opt & RTCWAKE_OPT_AUTO)
		utc = -1;
	*/
	if (opt & (RTCWAKE_OPT_UTC | RTCWAKE_OPT_LOCAL))
		utc = opt & RTCWAKE_OPT_UTC;
	if (!(opt & RTCWAKE_OPT_SUSPEND_MODE))
		suspend = DEFAULT_MODE;
	if (opt & RTCWAKE_OPT_SECONDS)
		/* alarm time, seconds-to-sleep (relative) */
		seconds = xatoi(opt_seconds);
	if (opt & RTCWAKE_OPT_TIME)
		/* alarm time, time_t (absolute, seconds since 1/1 1970 UTC) */
		alarm_time = xatol(opt_time);

	if (!alarm_time && !seconds)
		bb_error_msg_and_die("must provide wake time");

	if (utc == -1)
		utc = rtc_adjtime_is_utc();

	/* the rtcname is relative to /dev */
	xchdir("/dev");

	/* this RTC must exist and (if we'll sleep) be wakeup-enabled */
	fd = rtc_xopen(&rtcname, O_RDONLY);

	if (strcmp(suspend, "on") && !may_wakeup(rtcname))
		bb_error_msg_and_die("%s not enabled for wakeup events", rtcname);

	/* relative or absolute alarm time, normalized to time_t */
	sys_time = time(NULL);
	{
		struct tm tm_time;
		rtc_read_tm(&tm_time, fd);
		rtc_time = rtc_tm2time(&tm_time, utc);
	}


	if (alarm_time) {
		if (alarm_time < sys_time)
			bb_error_msg_and_die("time doesn't go backward to %s", ctime(&alarm_time));
		alarm_time += sys_time - rtc_time;
	} else
		alarm_time = rtc_time + seconds + 1;
	setup_alarm(fd, &alarm_time, rtc_time);

	sync();
	printf("wakeup from \"%s\" at %s", suspend, ctime(&alarm_time));
	fflush_all();
	usleep(10 * 1000);

	if (strcmp(suspend, "on"))
		xopen_xwrite_close(SYS_POWER_PATH, suspend);
	else {
		/* "fake" suspend ... we'll do the delay ourselves */
		unsigned long data;

		do {
			ssize_t ret = safe_read(fd, &data, sizeof(data));
			if (ret < 0) {
				bb_perror_msg("rtc read");
				break;
			}
		} while (!(data & RTC_AF));
	}

	xioctl(fd, RTC_AIE_OFF, 0);

	if (ENABLE_FEATURE_CLEAN_UP)
		close(fd);

	return EXIT_SUCCESS;
}
Example #23
0
int CaptureThread::start() {
	wait();

	devam=false;
	fd = -1;

	// read config
	dev_name = Settings::node();
	width    = Settings::width();
	height   = Settings::height();
	fps      = Settings::fps();
	if (fps>0) {
		delay = 1000/fps;
	}
	else { delay = 0; }

	// open webcam device node
	fd = v4l2_open(dev_name.toStdString().c_str(), O_RDWR | O_NONBLOCK, 0);
	if (fd < 0) {
		kError() << "Cannot open device";
		quit();
		return 1;
	}

	CLEAR(fmt);
	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	fmt.fmt.pix.width       = width;
	fmt.fmt.pix.height      = height;
	fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
	fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
	xioctl(fd, VIDIOC_S_FMT, &fmt);
	if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_RGB24) {
		kError() << "Libv4l didn't accept RGB24 format. Can't proceed.";
		quit();
		return 1;
	}
	emit startedCapture(fmt.fmt.pix.width, fmt.fmt.pix.height);

	v4lconvert_data = v4lconvert_create(fd);
	if (v4lconvert_data == NULL)
		kDebug() << "v4lconvert_create";
	if (v4lconvert_try_format(v4lconvert_data, &fmt, &src_fmt) != 0)
		kDebug() << "v4lconvert_try_format";
	xioctl(fd, VIDIOC_S_FMT, &src_fmt);
	dst_buf = (unsigned char*)malloc(fmt.fmt.pix.sizeimage);

	CLEAR(req);
	req.count = 2;
	req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	req.memory = V4L2_MEMORY_MMAP;
	xioctl(fd, VIDIOC_REQBUFS, &req);

	buffers = (buffer*)calloc(req.count, sizeof(*buffers));
	for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
		CLEAR(buf);

		buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory      = V4L2_MEMORY_MMAP;
		buf.index       = n_buffers;

		xioctl(fd, VIDIOC_QUERYBUF, &buf);

		buffers[n_buffers].length = buf.length;
		buffers[n_buffers].start = v4l2_mmap(NULL, buf.length,
																				 PROT_READ | PROT_WRITE, MAP_SHARED,
																				 fd, buf.m.offset);

		if (MAP_FAILED == buffers[n_buffers].start) {
			kDebug() << "mmap";
			quit();
			return 1;
		}
	}

	for (unsigned int i = 0; i < n_buffers; ++i) {
		CLEAR(buf);
		buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory = V4L2_MEMORY_MMAP;
		buf.index = i;
		xioctl(fd, VIDIOC_QBUF, &buf);
	}
	type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	xioctl(fd, VIDIOC_STREAMON, &type);

	di=0;
	sprintf(header,"P6\n%d %d 255\n",fmt.fmt.pix.width,fmt.fmt.pix.height);
	devam=true;

	// start processing video data
	running = true;
	QThread::start();
	return 0;
}
int grab_frame()
{
        struct v4l2_format              fmt;
        struct v4l2_buffer              buf;
        struct v4l2_requestbuffers      req;
        enum v4l2_buf_type              type;
        fd_set                          fds;
        struct timeval                  tv;
        int                             r, fd = -1;
        unsigned int                    i, n_buffers;
        char                            *dev_name = "/dev/video1";
        struct buffer                   *buffers;

        fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0);
        if (fd < 0) {
                perror("Cannot open device");
                exit(EXIT_FAILURE);
        }

        printf("grabbing frame...\n");
        CLEAR(fmt);
        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        fmt.fmt.pix.width       = 640;
        fmt.fmt.pix.height      = 480;
        fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
        fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
        xioctl(fd, VIDIOC_S_FMT, &fmt);
        if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_RGB24) {
                printf("Libv4l didn't accept RGB24 format. Can't proceed.\n");
                exit(EXIT_FAILURE);
        }
        if ((fmt.fmt.pix.width != 640) || (fmt.fmt.pix.height != 480))
                printf("Warning: driver is sending image at %dx%d\n",
                        fmt.fmt.pix.width, fmt.fmt.pix.height);

        CLEAR(req);
        req.count = 100;
        req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        req.memory = V4L2_MEMORY_MMAP;
        xioctl(fd, VIDIOC_REQBUFS, &req);

        buffers = calloc(req.count, sizeof(*buffers));
        for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
                CLEAR(buf);

                buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                buf.memory      = V4L2_MEMORY_MMAP;
                buf.index       = n_buffers;

                xioctl(fd, VIDIOC_QUERYBUF, &buf);

                buffers[n_buffers].length = buf.length;
                buffers[n_buffers].start = v4l2_mmap(NULL, buf.length,
                              PROT_READ | PROT_WRITE, MAP_SHARED,
                              fd, buf.m.offset);

                if (MAP_FAILED == buffers[n_buffers].start) {
                        perror("mmap");
                        exit(EXIT_FAILURE);
                }
        }

        for (i = 0; i < n_buffers; ++i) {
                CLEAR(buf);
                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                buf.memory = V4L2_MEMORY_MMAP;
                buf.index = i;
                xioctl(fd, VIDIOC_QBUF, &buf);
        }
        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

        xioctl(fd, VIDIOC_STREAMON, &type);
        for (i = 0; i < req.count; i++) {
                do {
                        FD_ZERO(&fds);
                        FD_SET(fd, &fds);

                        /* Timeout. */
                        tv.tv_sec = 2;
                        tv.tv_usec = 0;

                        r = select(fd + 1, &fds, NULL, NULL, &tv);
                } while ((r == -1 && (errno = EINTR)));
                if (r == -1) {
                        perror("select");
                        return errno;
                }

                CLEAR(buf);
                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                buf.memory = V4L2_MEMORY_MMAP;
                xioctl(fd, VIDIOC_DQBUF, &buf);


                xioctl(fd, VIDIOC_QBUF, &buf);
        }

        binarize(buffers, buf);

        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        xioctl(fd, VIDIOC_STREAMOFF, &type);
        for (i = 0; i < n_buffers; ++i)
                v4l2_munmap(buffers[i].start, buffers[i].length);
        v4l2_close(fd);

        return 0;
}
Example #25
0
void V4LIn::stop() {
	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type)) errno_exit("VIDIOC_STREAMOFF");
	bStarted = false;
}
Example #26
0
int flash_eraseall_main(int argc UNUSED_PARAM, char **argv)
{
	struct jffs2_unknown_node cleanmarker;
	mtd_info_t meminfo;
	int fd, clmpos, clmlen;
	erase_info_t erase;
	struct stat st;
	unsigned int flags;
	char *mtd_name;

	opt_complementary = "=1";
	flags = BBTEST | getopt32(argv, "jq");

	mtd_name = argv[optind];
	fd = xopen(mtd_name, O_RDWR);
	fstat(fd, &st);
	if (!S_ISCHR(st.st_mode))
		bb_error_msg_and_die("%s: not a char device", mtd_name);

	xioctl(fd, MEMGETINFO, &meminfo);
	erase.length = meminfo.erasesize;
	if (meminfo.type == MTD_NANDFLASH)
		flags |= IS_NAND;

	clmpos = 0;
	clmlen = 8;
	if (flags & OPTION_J) {
		uint32_t *crc32_table;

		crc32_table = crc32_filltable(NULL, 0);

		cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
		cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
		if (!(flags & IS_NAND))
			cleanmarker.totlen = cpu_to_je32(sizeof(struct jffs2_unknown_node));
		else {
			struct nand_oobinfo oobinfo;

			xioctl(fd, MEMGETOOBSEL, &oobinfo);

			/* Check for autoplacement */
			if (oobinfo.useecc == MTD_NANDECC_AUTOPLACE) {
				/* Get the position of the free bytes */
				clmpos = oobinfo.oobfree[0][0];
				clmlen = oobinfo.oobfree[0][1];
				if (clmlen > 8)
					clmlen = 8;
				if (clmlen == 0)
					bb_error_msg_and_die("autoplacement selected and no empty space in oob");
			} else {
				/* Legacy mode */
				switch (meminfo.oobsize) {
				case 8:
					clmpos = 6;
					clmlen = 2;
					break;
				case 16:
					clmpos = 8;
					/*clmlen = 8;*/
					break;
				case 64:
					clmpos = 16;
					/*clmlen = 8;*/
					break;
				}
			}
			cleanmarker.totlen = cpu_to_je32(8);
		}

		cleanmarker.hdr_crc = cpu_to_je32(
			crc32_block_endian0(0, &cleanmarker, sizeof(struct jffs2_unknown_node) - 4, crc32_table)
		);
	}

	/* Don't want to destroy progress indicator by bb_error_msg's */
	applet_name = xasprintf("\n%s: %s", applet_name, mtd_name);

	for (erase.start = 0; erase.start < meminfo.size;
	     erase.start += meminfo.erasesize) {
		if (flags & BBTEST) {
			int ret;
			loff_t offset = erase.start;

			ret = ioctl(fd, MEMGETBADBLOCK, &offset);
			if (ret > 0) {
				if (!(flags & OPTION_Q))
					bb_info_msg("\nSkipping bad block at 0x%08x", erase.start);
				continue;
			}
			if (ret < 0) {
				/* Black block table is not available on certain flash
				 * types e.g. NOR
				 */
				if (errno == EOPNOTSUPP) {
					flags &= ~BBTEST;
					if (flags & IS_NAND)
						bb_error_msg_and_die("bad block check not available");
				} else {
					bb_perror_msg_and_die("MEMGETBADBLOCK error");
				}
			}
		}

		if (!(flags & OPTION_Q))
			show_progress(&meminfo, &erase);

		xioctl(fd, MEMERASE, &erase);

		/* format for JFFS2 ? */
		if (!(flags & OPTION_J))
			continue;

		/* write cleanmarker */
		if (flags & IS_NAND) {
			struct mtd_oob_buf oob;

			oob.ptr = (unsigned char *) &cleanmarker;
			oob.start = erase.start + clmpos;
			oob.length = clmlen;
			xioctl(fd, MEMWRITEOOB, &oob);
		} else {
			xlseek(fd, erase.start, SEEK_SET);
			/* if (lseek(fd, erase.start, SEEK_SET) < 0) {
				bb_perror_msg("MTD %s failure", "seek");
				continue;
			} */
			xwrite(fd, &cleanmarker, sizeof(cleanmarker));
			/* if (write(fd, &cleanmarker, sizeof(cleanmarker)) != sizeof(cleanmarker)) {
				bb_perror_msg("MTD %s failure", "write");
				continue;
			} */
		}
		if (!(flags & OPTION_Q))
			printf(" Cleanmarker written at %x.", erase.start);
	}
	if (!(flags & OPTION_Q)) {
		show_progress(&meminfo, &erase);
		bb_putchar('\n');
	}

	if (ENABLE_FEATURE_CLEAN_UP)
		close(fd);
	return EXIT_SUCCESS;
}
Example #27
0
static void init_device(void)
{
        struct v4l2_capability cap;
        struct v4l2_cropcap cropcap;
        struct v4l2_crop crop;
        struct v4l2_format fmt;
        unsigned int min;

        if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) {
                if (EINVAL == errno) {
                        fprintf(stderr, "%s is no V4L2 device\n",
                                 dev_name);
                        exit(EXIT_FAILURE);
                } else {
                        errno_exit("VIDIOC_QUERYCAP");
                }
        }

        if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
                fprintf(stderr, "%s is no video capture device\n",
                         dev_name);
                exit(EXIT_FAILURE);
        }

        switch (io) {
        case IO_METHOD_READ:
                if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
                        fprintf(stderr, "%s does not support read i/o\n",
                                 dev_name);
                        exit(EXIT_FAILURE);
                }
                break;

        case IO_METHOD_MMAP:
        case IO_METHOD_USERPTR:
                if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
                        fprintf(stderr, "%s does not support streaming i/o\n",
                                 dev_name);
                        exit(EXIT_FAILURE);
                }
                break;
        }


        /* Select video input, video standard and tune here. */


        CLEAR(cropcap);

        cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

        if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
                crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                crop.c = cropcap.defrect; /* reset to default */

                if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
                        switch (errno) {
                        case EINVAL:
                                /* Cropping not supported. */
                                break;
                        default:
                                /* Errors ignored. */
                                break;
                        }
                }
        } else {
                /* Errors ignored. */
        }


        CLEAR(fmt);

        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        if (force_format) {
                fmt.fmt.pix.width       = 640;
                fmt.fmt.pix.height      = 480;
                fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
                fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;

                if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
                        errno_exit("VIDIOC_S_FMT");

                /* Note VIDIOC_S_FMT may change width and height. */
        } else {
                /* Preserve original settings as set by v4l2-ctl for example */
                if (-1 == xioctl(fd, VIDIOC_G_FMT, &fmt))
                        errno_exit("VIDIOC_G_FMT");
        }

        /* 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;

        switch (io) {
        case IO_METHOD_READ:
                init_read(fmt.fmt.pix.sizeimage);
                break;

        case IO_METHOD_MMAP:
                init_mmap();
                break;

        case IO_METHOD_USERPTR:
                init_userp(fmt.fmt.pix.sizeimage);
                break;
        }
}
Example #28
0
int showkey_main(int argc UNUSED_PARAM, char **argv)
{
	enum {
		OPT_a = (1<<0), // display the decimal/octal/hex values of the keys
		OPT_k = (1<<1), // display only the interpreted keycodes (default)
		OPT_s = (1<<2), // display only the raw scan-codes
	};

	INIT_G();

	// FIXME: aks are all mutually exclusive
	getopt32(argv, "aks");

	// prepare for raw mode
	xget1(&tio, &tio0);
	// put stdin in raw mode
	xset1(&tio);

#define press_keys "Press any keys, program terminates %s:\r\n\n"

	if (option_mask32 & OPT_a) {
		// just read stdin char by char
		unsigned char c;

		printf(press_keys, "on EOF (ctrl-D)");

		// read and show byte values
		while (1 == read(STDIN_FILENO, &c, 1)) {
			printf("%3u 0%03o 0x%02x\r\n", c, c, c);
			if (04 /*CTRL-D*/ == c)
				break;
		}

	} else {
		// we assume a PC keyboard
		xioctl(STDIN_FILENO, KDGKBMODE, &kbmode);
		printf("Keyboard mode was %s.\r\n\n",
			kbmode == K_RAW ? "RAW" :
				(kbmode == K_XLATE ? "XLATE" :
					(kbmode == K_MEDIUMRAW ? "MEDIUMRAW" :
						(kbmode == K_UNICODE ? "UNICODE" : "UNKNOWN")))
		);

		// set raw keyboard mode
		xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)((option_mask32 & OPT_k) ? K_MEDIUMRAW : K_RAW));

		// we should exit on any signal; signals should interrupt read
		bb_signals_recursive_norestart(BB_FATAL_SIGS, record_signo);

		// inform user that program ends after time of inactivity
		printf(press_keys, "10s after last keypress");

		// read and show scancodes
		while (!bb_got_signal) {
			char buf[18];
			int i, n;

			// setup 10s watchdog
			alarm(10);

			// read scancodes
			n = read(STDIN_FILENO, buf, sizeof(buf));
			i = 0;
			while (i < n) {
				if (option_mask32 & OPT_s) {
					// show raw scancodes
					printf("0x%02x ", buf[i++]);
				} else {
					// show interpreted scancodes (default)
					char c = buf[i];
					int kc;
					if (i+2 < n
					 && (c & 0x7f) == 0
					 && (buf[i+1] & 0x80) != 0
					 && (buf[i+2] & 0x80) != 0
					) {
						kc = ((buf[i+1] & 0x7f) << 7) | (buf[i+2] & 0x7f);
						i += 3;
					} else {
						kc = (c & 0x7f);
						i++;
					}
					printf("keycode %3u %s", kc, (c & 0x80) ? "release" : "press");
				}
			}
			puts("\r");
		}

		// restore keyboard mode
		xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)kbmode);
	}

	// restore console settings
	xset1(&tio0);

	return EXIT_SUCCESS;
}
int OrangePi_VideoIn(struct vdIn *vd,char *device,int width,int height,int fps, int format,
	    int grabmethod,globals *pglobal,int id)
{
    int currentWidth, currentHeight = 0;
    struct v4l2_format currentFormat;

    if(vd == NULL || device == NULL) 
	return -1;
    if(width == 0 || height == 0) 
	return -1;
    if(grabmethod < 0 || grabmethod > 1) 
	grabmethod = 1;
    vd->videodevice = NULL;
    vd->status = NULL;
    vd->pictName = NULL;
    vd->videodevice = (char *)calloc(1 , 16 * sizeof(char));
    vd->status = (char *)calloc(1 , 100 * sizeof(char));
    vd->pictName = (char *)calloc(1 , 80 * sizeof(char));
    snprintf(vd->videodevice , 12 , "%s" , device);
    vd->toggleAvi = 0;
    vd->getPict = 0;
    vd->signalquit = 1;
    vd->width = width;
    vd->height = height;
    vd->fps = fps;
    vd->formatIn = format;
    vd->grabmethod = grabmethod;
    if(OrangePi_init(&OrangePi,vd) < 0) {
	fprintf(stderr,"Init v4l2 failed !! exit fatal \n");
	printf("ERROR %s %d\n",__func__,__LINE__);
    }

    // enumerating formats
    currentFormat.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if(xioctl(vd->fd, VIDIOC_G_FMT, &currentFormat) == 0) {
        currentWidth = currentFormat.fmt.pix.width;
        currentHeight = currentFormat.fmt.pix.height;
        DBG("Current size: %dx%d\n", currentWidth, currentHeight);
    }

    pglobal->in[id].in_formats = NULL;
    for(pglobal->in[id].formatCount = 0; 1; pglobal->in[id].formatCount++) {
        struct v4l2_fmtdesc fmtdesc;
        fmtdesc.index = pglobal->in[id].formatCount;
        fmtdesc.type  = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        if(xioctl(vd->fd, VIDIOC_ENUM_FMT, &fmtdesc) < 0) {
            break;
        }

        if (pglobal->in[id].in_formats == NULL) {
            pglobal->in[id].in_formats = (input_format*)calloc(1, sizeof(input_format));
        } else {
            pglobal->in[id].in_formats = (input_format*)realloc(pglobal->in[id].in_formats, (pglobal->in[id].formatCount + 1) * sizeof(input_format));
        }

        if (pglobal->in[id].in_formats == NULL) {
            DBG("Calloc/realloc failed: %s\n", strerror(errno));
            return -1;
        }


        memcpy(&pglobal->in[id].in_formats[pglobal->in[id].formatCount], &fmtdesc, sizeof(input_format));

        if(fmtdesc.pixelformat == format)
            pglobal->in[id].currentFormat = pglobal->in[id].formatCount;

        DBG("Supported format: %s\n", fmtdesc.description);
        struct v4l2_frmsizeenum fsenum;
        fsenum.index = pglobal->in[id].formatCount;
        fsenum.pixel_format = fmtdesc.pixelformat;
        int j = 0;
        pglobal->in[id].in_formats[pglobal->in[id].formatCount].supportedResolutions = NULL;
        pglobal->in[id].in_formats[pglobal->in[id].formatCount].resolutionCount = 0;
        pglobal->in[id].in_formats[pglobal->in[id].formatCount].currentResolution = -1;
        while(1) {
            fsenum.index = j;
            j++;
            if(xioctl(vd->fd, VIDIOC_ENUM_FRAMESIZES, &fsenum) == 0) {
                pglobal->in[id].in_formats[pglobal->in[id].formatCount].resolutionCount++;
                if (pglobal->in[id].in_formats[pglobal->in[id].formatCount].supportedResolutions == NULL) {
                    pglobal->in[id].in_formats[pglobal->in[id].formatCount].supportedResolutions =
                        (input_resolution*)calloc(1, sizeof(input_resolution));
                } else {
                    pglobal->in[id].in_formats[pglobal->in[id].formatCount].supportedResolutions =
                        (input_resolution*)realloc(pglobal->in[id].in_formats[pglobal->in[id].formatCount].supportedResolutions, j * sizeof(input_resolution));
                }

                if (pglobal->in[id].in_formats[pglobal->in[id].formatCount].supportedResolutions == NULL) {
                    DBG("Calloc/realloc failed\n");
                    return -1;
                }

                pglobal->in[id].in_formats[pglobal->in[id].formatCount].supportedResolutions[j-1].width = fsenum.discrete.width;
                pglobal->in[id].in_formats[pglobal->in[id].formatCount].supportedResolutions[j-1].height = fsenum.discrete.height;
                if(format == fmtdesc.pixelformat) {
                    pglobal->in[id].in_formats[pglobal->in[id].formatCount].currentResolution = (j - 1);
                    DBG("\tSupported size with the current format: %dx%d\n", fsenum.discrete.width, fsenum.discrete.height);
                } else {
                    DBG("\tSupported size: %dx%d\n", fsenum.discrete.width, fsenum.discrete.height);
                }
            } else {
                break;
            }
        }
    }

    vd->framesizeIn = (vd->width * vd->height * 3 / 2);
    vd->framebuffer =
	(unsigned char *)calloc(1 , (size_t)vd->width * (vd->height + 8) * 2);
    vd->Y2V = 
	(unsigned char *)calloc(1 , (size_t)vd->width * (vd->height + 8) * 2);
    return 0;
}
Example #30
0
void v4l2_stream_record(QSP_ARG_DECL  Image_File *ifp,long n_frames,int n_cameras, Video_Device **vd_tbl)
{
#ifdef HAVE_RAWVOL
	int fd_arr[MAX_DISKS];
	int ndisks, which_disk;
	uint32_t blocks_per_frame;
	Shape_Info shp1;
	Shape_Info *shpp=(&shp1);
	RV_Inode *inp;
	struct v4l2_buffer *bufp;
	int i;

	if( record_state != NOT_RECORDING ){
		sprintf(ERROR_STRING,
	"v4l2_stream_record:  can't record file %s until previous record completes",
			ifp->if_name);
		WARN(ERROR_STRING);
		return;
	}

/* grabber dependent? */
	blocks_per_frame = get_blocks_per_frame();

	n_to_write = blocks_per_frame * BLOCK_SIZE;
//n_to_write>>=2;		/* write quarter for testing */


	if( FT_CODE(IF_TYPE(ifp)) != IFT_RV ){
		sprintf(ERROR_STRING,
	"stream record:  image file %s (type %s) should be type %s",
			ifp->if_name,
			FT_NAME(IF_TYPE(ifp)),
			FT_NAME(FILETYPE_FOR_CODE(IFT_RV)) );
		WARN(ERROR_STRING);
		return;
	}


	inp = (RV_Inode *) ifp->if_hdr_p;
	ndisks = queue_rv_file(QSP_ARG  inp,fd_arr);

#ifdef CAUTIOUS
	if( ndisks < 1 ){
		sprintf(ERROR_STRING,
			"Bad number (%d) of raw volume disks",ndisks);
		WARN(ERROR_STRING);
		return;
	}
#endif /* CAUTIOUS */


	/* meteor_get_geometry(&_geo); */
	SET_SHP_FLAGS(shpp, 0);
	SET_SHP_ROWS(shpp, 480);	/* BUG don't hard code */
	SET_SHP_COLS(shpp, 640); /* BUG don't hard code */
	/* should get bytes per pixel from _geo... */
	SET_SHP_COMPS(shpp,  DEFAULT_BYTES_PER_PIXEL);
	SET_SHP_FRAMES(shpp, n_frames);
	SET_SHP_SEQS(shpp, 1);
	SET_SHP_PREC_PTR(shpp, PREC_FOR_CODE(PREC_UBY) );
	set_shape_flags(shpp,NO_OBJ,AUTO_SHAPE);

	rv_set_shape(QSP_ARG  ifp->if_name,shpp);


	/* We write an entire frame to each disk in turn... */

#ifdef RECORD_TIMESTAMPS
	if( stamping ) init_stamps(n_frames);
#endif /* RECORD_TIMESTAMPS */

	record_state = RECORDING;

	/* stuff from video_reader */

	for(i=0;i<n_cameras;i++)
		start_capturing(QSP_ARG  vd_tbl[i]);

	n_so_far = 0;
	which_disk=0;

	bufp=next_frame(QSP_ARG  n_cameras,vd_tbl);
	while( bufp != NULL ){
		int n_written;

		/* write the frame to disk */
if( really_writing ){
		if( (n_written = write(fd_arr[which_disk],vd_tbl[which_device]->vd_buf_tbl[ bufp->index ].mb_start,n_to_write))
			!= n_to_write ){
			sprintf(ERROR_STRING,"write (frm %ld, fd=%d)",n_so_far,ifp->if_fd);
			perror(ERROR_STRING);
			sprintf(ERROR_STRING,
				"%ld requested, %d written",
				n_to_write,n_written);
			WARN(ERROR_STRING);
			return;
		}

		which_disk = (which_disk+1) % ndisks;
}
		n_so_far++;

		/* QBUG releases this buffer to be used again */
		if( xioctl(vd_tbl[which_device]->vd_fd, VIDIOC_QBUF, bufp) < 0 )
			ERRNO_WARN ("v4l2_stream_record:  error queueing frame");

		if( n_so_far >= n_frames )
			bufp = NULL;
		else
			bufp=next_frame(QSP_ARG  n_cameras,vd_tbl);
	}
	if( bufp != NULL ){
		if( xioctl(vd_tbl[which_device]->vd_fd, VIDIOC_QBUF, bufp) < 0 )
			ERRNO_WARN ("v4l2_stream_record:  error queueing frame");
	}

	for(i=0;i<n_cameras;i++)
		stop_capturing(QSP_ARG  vd_tbl[i]);

	rv_sync(SINGLE_QSP_ARG);

	/* we used to disable real-time scheduling here, but
	 * when video_reader executes as a separate thread there
	 * is no point, because it won't affect the main process!
	 */

	recording_in_process = 0;
	record_state=NOT_RECORDING;

#ifdef RECORD_TIMESTAMPS
	n_stored_times = n_so_far;
#endif

#ifdef CAUTIOUS
	if( ifp == NO_IMAGE_FILE ){
		WARN("CAUTIOUS:  v4l2_stream_record:  ifp is NULL!?");
		return;
	}
#endif /* CAUTIOUS */

	v4l2_finish_recording( QSP_ARG  ifp );

	/* Because the disk writers don't use the fileio library,
	 * the ifp doesn't know how many frames have been written.
	 */

	ifp->if_nfrms = n_frames;	/* BUG? is this really what happened? */
#else // ! HAVE_RAWVOL
	WARN("v4l2_stream_record:  Program not compiled with raw volume support, can't record!?");
#endif // ! HAVE_RAWVOL
} /* end v4l2_stream_record */