diff options
| -rw-r--r-- | uvc-gadget.c | 192 | 
1 files changed, 103 insertions, 89 deletions
| diff --git a/uvc-gadget.c b/uvc-gadget.c index 222e16c..62377d8 100644 --- a/uvc-gadget.c +++ b/uvc-gadget.c @@ -62,12 +62,9 @@ struct uvc_device  struct uvc_stream  { +	struct v4l2_device *cap;  	struct uvc_device *uvc; -	uint8_t color; -	unsigned int imgsize; -	void *imgdata; -  	struct events *events;  }; @@ -104,28 +101,17 @@ uvc_close(struct uvc_device *dev)   * Video streaming   */ -static void -uvc_video_fill_buffer(struct uvc_stream *stream, struct v4l2_video_buffer *buf) +static void capture_video_process(void *d)  { -	struct uvc_device *dev = stream->uvc; -	unsigned int bpl; -	unsigned int i; - -	switch (dev->fcc) { -	case V4L2_PIX_FMT_YUYV: -		/* Fill the buffer with video data. */ -		bpl = dev->width * 2; -		for (i = 0; i < dev->height; ++i) -			memset(buf->mem + i*bpl, stream->color++, bpl); +	struct uvc_stream *stream = d; +	struct v4l2_video_buffer buf; +	int ret; -		buf->bytesused = bpl * dev->height; -		break; +	ret = v4l2_dequeue_buffer(stream->cap, &buf); +	if (ret < 0) +		return; -	case V4L2_PIX_FMT_MJPEG: -		memcpy(buf->mem, stream->imgdata, stream->imgsize); -		buf->bytesused = stream->imgsize; -		break; -	} +	v4l2_queue_buffer(stream->uvc->vdev, &buf);  }  static void @@ -139,16 +125,14 @@ uvc_video_process(void *d)  	if (ret < 0)  		return; -	uvc_video_fill_buffer(stream, &buf); - -	v4l2_queue_buffer(stream->uvc->vdev, &buf); +	v4l2_queue_buffer(stream->cap, &buf);  }  static int  uvc_video_stream(struct uvc_stream *stream, int enable)  { +	struct v4l2_device *cap = stream->cap;  	struct uvc_device *dev = stream->uvc; -	unsigned int i;  	int ret;  	if (!enable) { @@ -161,43 +145,83 @@ uvc_video_stream(struct uvc_stream *stream, int enable)  	printf("Starting video stream.\n"); -	ret = v4l2_alloc_buffers(dev->vdev, V4L2_MEMORY_MMAP, 4); +	ret = v4l2_alloc_buffers(dev->vdev, V4L2_MEMORY_DMABUF, 4);  	if (ret < 0) { -		printf("Failed to allocate buffers.\n"); +		printf("Failed to allocate buffers: %s (%d)\n", strerror(-ret), -ret);  		return ret;  	} -	ret = v4l2_mmap_buffers(dev->vdev); +	ret = v4l2_import_buffers(dev->vdev, dev->vdev->nbufs, cap->buffers);  	if (ret < 0) { -		printf("Failed to mmap buffers.\n"); +		printf("Failed to import buffers: %s (%d)\n", strerror(-ret), -ret);  		goto error;  	} -	for (i = 0; i < dev->vdev->nbufs; ++i) { -		struct v4l2_video_buffer *buf = &dev->vdev->buffers[i]; +	v4l2_stream_on(dev->vdev); +	events_watch_fd(stream->events, dev->vdev->fd, EVENT_WRITE, +			uvc_video_process, stream); + +	return 0; + +error: +	v4l2_free_buffers(dev->vdev); +	return ret; +} + +static int capture_video_stream(struct uvc_stream *stream, int enable) +{ +	struct v4l2_device *cap = stream->cap; +	unsigned int i; +	int ret; + +	if (!enable) { +		printf("Stopping video capture stream.\n"); +		events_unwatch_fd(stream->events, cap->fd, EVENT_READ); +		v4l2_stream_off(cap); +		v4l2_free_buffers(cap); +		return 0; +	} + +	printf("Starting video capture stream.\n"); -		uvc_video_fill_buffer(stream, buf); +	ret = v4l2_alloc_buffers(cap, V4L2_MEMORY_MMAP, 4); +	if (ret < 0) { +		printf("Failed to allocate capture buffers.\n"); +		return ret; +	} -		ret = v4l2_queue_buffer(dev->vdev, buf); +	ret = v4l2_export_buffers(cap); +	if (ret < 0) { +		printf("Failed to export buffers.\n"); +		goto error; +	} + +	for (i = 0; i < cap->nbufs; ++i) { +		struct v4l2_video_buffer *buf = &cap->buffers[i]; + +		ret = v4l2_queue_buffer(cap, buf);  		if (ret < 0)  			goto error;  	} -	v4l2_stream_on(dev->vdev); -	events_watch_fd(stream->events, dev->vdev->fd, EVENT_WRITE, -			uvc_video_process, stream); +	v4l2_stream_on(cap); +	events_watch_fd(stream->events, cap->fd, EVENT_READ, +			capture_video_process, stream);  	return 0;  error: -	v4l2_free_buffers(dev->vdev); +	v4l2_free_buffers(cap);  	return ret;  }  static int -uvc_video_set_format(struct uvc_device *dev) +uvc_video_set_format(struct uvc_stream *stream)  { +	struct v4l2_device *cap = stream->cap; +	struct uvc_device *dev = stream->uvc;  	struct v4l2_pix_format fmt; +	int ret;  	printf("Setting format to 0x%08x %ux%u\n",  		dev->fcc, dev->width, dev->height); @@ -210,7 +234,11 @@ uvc_video_set_format(struct uvc_device *dev)  	if (dev->fcc == V4L2_PIX_FMT_MJPEG)  		fmt.sizeimage = dev->maxsize * 1.5; -	return v4l2_set_format(dev->vdev, &fmt); +	ret = v4l2_set_format(dev->vdev, &fmt); +	if (ret < 0) +		return ret; + +	return v4l2_set_format(cap, &fmt);  }  static int @@ -424,9 +452,10 @@ uvc_events_process_setup(struct uvc_device *dev,  }  static void -uvc_events_process_data(struct uvc_device *dev, +uvc_events_process_data(struct uvc_stream *stream,  			const struct uvc_request_data *data)  { +	struct uvc_device *dev = stream->uvc;  	const struct uvc_streaming_control *ctrl =  		(const struct uvc_streaming_control *)&data->data;  	struct uvc_streaming_control *target; @@ -461,7 +490,7 @@ uvc_events_process_data(struct uvc_device *dev,  		dev->width = frame->width;  		dev->height = frame->height; -		uvc_video_set_format(dev); +		uvc_video_set_format(stream);  	}  } @@ -495,15 +524,17 @@ uvc_events_process(void *d)  		break;  	case UVC_EVENT_DATA: -		uvc_events_process_data(dev, &uvc_event->data); +		uvc_events_process_data(stream, &uvc_event->data);  		return;  	case UVC_EVENT_STREAMON: +		capture_video_stream(stream, 1);  		uvc_video_stream(stream, 1);  		return;  	case UVC_EVENT_STREAMOFF:  		uvc_video_stream(stream, 0); +		capture_video_stream(stream, 0);  		return;  	} @@ -539,7 +570,8 @@ uvc_events_init(struct uvc_device *dev)   * Stream handling   */ -static struct uvc_stream *uvc_stream_new(const char *device) +static struct uvc_stream *uvc_stream_new(const char *uvc_device, +					 const char *cap_device)  {  	struct uvc_stream *stream; @@ -549,13 +581,22 @@ static struct uvc_stream *uvc_stream_new(const char *device)  	memset(stream, 0, sizeof(*stream)); -	stream->uvc = uvc_open(device); -	if (stream->uvc == NULL) { -		free(stream); -		return NULL; -	} +	stream->cap = v4l2_open(cap_device); +	if (stream->cap == NULL) +		goto error; + +	stream->uvc = uvc_open(uvc_device); +	if (stream->uvc == NULL) +		goto error;  	return stream; + +error: +	if (stream->cap) +		v4l2_close(stream->cap); + +	free(stream); +	return NULL;  }  static void uvc_stream_delete(struct uvc_stream *stream) @@ -563,45 +604,18 @@ static void uvc_stream_delete(struct uvc_stream *stream)  	if (stream == NULL)  		return; +	v4l2_close(stream->cap);  	uvc_close(stream->uvc); -	free(stream->imgdata);  	free(stream);  } -static void uvc_stream_load_image(struct uvc_stream *stream, const char *img) -{ -	int fd = -1; - -	if (img == NULL) -		return; - -	fd = open(img, O_RDONLY); -	if (fd == -1) { -		printf("Unable to open MJPEG image '%s'\n", img); -		return; -	} - -	stream->imgsize = lseek(fd, 0, SEEK_END); -	lseek(fd, 0, SEEK_SET); -	stream->imgdata = malloc(stream->imgsize); -	if (stream->imgdata == NULL) { -		printf("Unable to allocate memory for MJPEG image\n"); -		stream->imgsize = 0; -		return; -	} - -	read(fd, stream->imgdata, stream->imgsize); -	close(fd); -} -  static void uvc_stream_init_uvc(struct uvc_stream *stream)  {  	/*  	 * FIXME: The maximum size should be specified per format and frame. -	 * For now just hardcode it to support MJPEG.  	 */ -	stream->uvc->maxsize = stream->imgsize; +	stream->uvc->maxsize = 0;  	uvc_events_init(stream->uvc);  	uvc_video_init(stream->uvc); @@ -624,6 +638,7 @@ static void usage(const char *argv0)  {  	fprintf(stderr, "Usage: %s [options]\n", argv0);  	fprintf(stderr, "Available options are\n"); +	fprintf(stderr, " -c device	V4L2 source device\n");  	fprintf(stderr, " -d device	Video device\n");  	fprintf(stderr, " -h		Print this help screen and exit\n");  	fprintf(stderr, " -i image	MJPEG image\n"); @@ -640,27 +655,27 @@ static void sigint_handler(int signal __attribute__((__unused__)))  int main(int argc, char *argv[])  { -	char *device = "/dev/video0"; +	char *uvc_device = "/dev/video0"; +	char *cap_device = "/dev/video1";  	struct uvc_stream *stream;  	struct events events; -	char *mjpeg_image = NULL;  	int ret = 0;  	int opt; -	while ((opt = getopt(argc, argv, "d:hi:")) != -1) { +	while ((opt = getopt(argc, argv, "c:d:h")) != -1) {  		switch (opt) { +		case 'c': +			cap_device = optarg; +			break; +  		case 'd': -			device = optarg; +			uvc_device = optarg;  			break;  		case 'h':  			usage(argv[0]);  			return 0; -		case 'i': -			mjpeg_image = optarg; -			break; -  		default:  			fprintf(stderr, "Invalid option '-%c'\n", opt);  			usage(argv[0]); @@ -679,13 +694,12 @@ int main(int argc, char *argv[])  	signal(SIGINT, sigint_handler);  	/* Create and initialise the stream. */ -	stream = uvc_stream_new(device); +	stream = uvc_stream_new(uvc_device, cap_device);  	if (stream == NULL) {  		ret = 1;  		goto done;  	} -	uvc_stream_load_image(stream, mjpeg_image);  	uvc_stream_init_uvc(stream);  	uvc_stream_set_event_handler(stream, &events); | 
