From 53b139a22810e00aa0ce872853b45107c4edee98 Mon Sep 17 00:00:00 2001 From: Paul Elder Date: Thu, 24 May 2018 02:12:38 +0800 Subject: uvc-gadget: Add struct uvc_stream Since we are preparing to stream frames from a capture v4l2 device to uvc-gadget, add a struct to represent this "frame-forwarding" stream, such that it contains a representation of the uvc gadget device (struct uvc_device) and other data relative to the stream, such as a pointer to the events handler and test pattern generation data. A capture v4l2 device object will be added in a subsequent modification. The stream is allocated dynamically, and the event handler is created separately from the stream. This will allow replacing the event handling mechanism with a different implementation without impacting the stream implementation. Change the argument to functions that need to be able to access stream data from uvc_device to uvc_stream. Signed-off-by: Paul Elder Signed-off-by: Laurent Pinchart --- uvc-gadget.c | 169 +++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 118 insertions(+), 51 deletions(-) (limited to 'uvc-gadget.c') diff --git a/uvc-gadget.c b/uvc-gadget.c index 5a1d8dc..222e16c 100644 --- a/uvc-gadget.c +++ b/uvc-gadget.c @@ -57,12 +57,18 @@ struct uvc_device unsigned int fcc; unsigned int width; unsigned int height; + unsigned int maxsize; +}; + +struct uvc_stream +{ + struct uvc_device *uvc; uint8_t color; unsigned int imgsize; void *imgdata; - struct events events; + struct events *events; }; static struct uvc_device * @@ -82,8 +88,6 @@ uvc_open(const char *devname) return NULL; } - events_init(&dev->events); - return dev; } @@ -93,7 +97,6 @@ uvc_close(struct uvc_device *dev) v4l2_close(dev->vdev); dev->vdev = NULL; - free(dev->imgdata); free(dev); } @@ -102,8 +105,9 @@ uvc_close(struct uvc_device *dev) */ static void -uvc_video_fill_buffer(struct uvc_device *dev, struct v4l2_video_buffer *buf) +uvc_video_fill_buffer(struct uvc_stream *stream, struct v4l2_video_buffer *buf) { + struct uvc_device *dev = stream->uvc; unsigned int bpl; unsigned int i; @@ -112,14 +116,14 @@ uvc_video_fill_buffer(struct uvc_device *dev, struct v4l2_video_buffer *buf) /* Fill the buffer with video data. */ bpl = dev->width * 2; for (i = 0; i < dev->height; ++i) - memset(buf->mem + i*bpl, dev->color++, bpl); + memset(buf->mem + i*bpl, stream->color++, bpl); buf->bytesused = bpl * dev->height; break; case V4L2_PIX_FMT_MJPEG: - memcpy(buf->mem, dev->imgdata, dev->imgsize); - buf->bytesused = dev->imgsize; + memcpy(buf->mem, stream->imgdata, stream->imgsize); + buf->bytesused = stream->imgsize; break; } } @@ -127,28 +131,29 @@ uvc_video_fill_buffer(struct uvc_device *dev, struct v4l2_video_buffer *buf) static void uvc_video_process(void *d) { - struct uvc_device *dev = d; + struct uvc_stream *stream = d; struct v4l2_video_buffer buf; int ret; - ret = v4l2_dequeue_buffer(dev->vdev, &buf); + ret = v4l2_dequeue_buffer(stream->uvc->vdev, &buf); if (ret < 0) return; - uvc_video_fill_buffer(dev, &buf); + uvc_video_fill_buffer(stream, &buf); - v4l2_queue_buffer(dev->vdev, &buf); + v4l2_queue_buffer(stream->uvc->vdev, &buf); } static int -uvc_video_stream(struct uvc_device *dev, int enable) +uvc_video_stream(struct uvc_stream *stream, int enable) { + struct uvc_device *dev = stream->uvc; unsigned int i; int ret; if (!enable) { printf("Stopping video stream.\n"); - events_unwatch_fd(&dev->events, dev->vdev->fd, EVENT_WRITE); + events_unwatch_fd(stream->events, dev->vdev->fd, EVENT_WRITE); v4l2_stream_off(dev->vdev); v4l2_free_buffers(dev->vdev); return 0; @@ -171,7 +176,7 @@ uvc_video_stream(struct uvc_device *dev, int enable) for (i = 0; i < dev->vdev->nbufs; ++i) { struct v4l2_video_buffer *buf = &dev->vdev->buffers[i]; - uvc_video_fill_buffer(dev, buf); + uvc_video_fill_buffer(stream, buf); ret = v4l2_queue_buffer(dev->vdev, buf); if (ret < 0) @@ -179,8 +184,8 @@ uvc_video_stream(struct uvc_device *dev, int enable) } v4l2_stream_on(dev->vdev); - events_watch_fd(&dev->events, dev->vdev->fd, EVENT_WRITE, - uvc_video_process, dev); + events_watch_fd(stream->events, dev->vdev->fd, EVENT_WRITE, + uvc_video_process, stream); return 0; @@ -203,7 +208,7 @@ uvc_video_set_format(struct uvc_device *dev) fmt.pixelformat = dev->fcc; fmt.field = V4L2_FIELD_NONE; if (dev->fcc == V4L2_PIX_FMT_MJPEG) - fmt.sizeimage = dev->imgsize * 1.5; + fmt.sizeimage = dev->maxsize * 1.5; return v4l2_set_format(dev->vdev, &fmt); } @@ -290,7 +295,7 @@ uvc_fill_streaming_control(struct uvc_device *dev, ctrl->dwMaxVideoFrameSize = frame->width * frame->height * 2; break; case V4L2_PIX_FMT_MJPEG: - ctrl->dwMaxVideoFrameSize = dev->imgsize; + ctrl->dwMaxVideoFrameSize = dev->maxsize; break; } @@ -463,7 +468,8 @@ uvc_events_process_data(struct uvc_device *dev, static void uvc_events_process(void *d) { - struct uvc_device *dev = d; + struct uvc_stream *stream = d; + struct uvc_device *dev = stream->uvc; struct v4l2_event v4l2_event; const struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; struct uvc_request_data resp; @@ -493,11 +499,11 @@ uvc_events_process(void *d) return; case UVC_EVENT_STREAMON: - uvc_video_stream(dev, 1); + uvc_video_stream(stream, 1); return; case UVC_EVENT_STREAMOFF: - uvc_video_stream(dev, 0); + uvc_video_stream(stream, 0); return; } @@ -530,10 +536,40 @@ uvc_events_init(struct uvc_device *dev) } /* --------------------------------------------------------------------------- - * main + * Stream handling */ -static void image_load(struct uvc_device *dev, const char *img) +static struct uvc_stream *uvc_stream_new(const char *device) +{ + struct uvc_stream *stream; + + stream = malloc(sizeof(*stream)); + if (stream == NULL) + return NULL; + + memset(stream, 0, sizeof(*stream)); + + stream->uvc = uvc_open(device); + if (stream->uvc == NULL) { + free(stream); + return NULL; + } + + return stream; +} + +static void uvc_stream_delete(struct uvc_stream *stream) +{ + if (stream == NULL) + return; + + 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; @@ -546,19 +582,44 @@ static void image_load(struct uvc_device *dev, const char *img) return; } - dev->imgsize = lseek(fd, 0, SEEK_END); + stream->imgsize = lseek(fd, 0, SEEK_END); lseek(fd, 0, SEEK_SET); - dev->imgdata = malloc(dev->imgsize); - if (dev->imgdata == NULL) { + stream->imgdata = malloc(stream->imgsize); + if (stream->imgdata == NULL) { printf("Unable to allocate memory for MJPEG image\n"); - dev->imgsize = 0; + stream->imgsize = 0; return; } - read(fd, dev->imgdata, dev->imgsize); + 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; + + uvc_events_init(stream->uvc); + uvc_video_init(stream->uvc); +} + +static void uvc_stream_set_event_handler(struct uvc_stream *stream, + struct events *events) +{ + stream->events = events; + + events_watch_fd(stream->events, stream->uvc->vdev->fd, EVENT_EXCEPTION, + uvc_events_process, stream); +} + +/* --------------------------------------------------------------------------- + * main + */ + static void usage(const char *argv0) { fprintf(stderr, "Usage: %s [options]\n", argv0); @@ -569,19 +630,21 @@ static void usage(const char *argv0) } /* Necessary for and only used by signal handler. */ -static struct uvc_device *uvc_device; +static struct events *sigint_events; static void sigint_handler(int signal __attribute__((__unused__))) { /* Stop the main loop when the user presses CTRL-C */ - events_stop(&uvc_device->events); + events_stop(sigint_events); } int main(int argc, char *argv[]) { char *device = "/dev/video0"; - struct uvc_device *dev; + struct uvc_stream *stream; + struct events events; char *mjpeg_image = NULL; + int ret = 0; int opt; while ((opt = getopt(argc, argv, "d:hi:")) != -1) { @@ -605,30 +668,34 @@ int main(int argc, char *argv[]) } } - dev = uvc_open(device); - if (dev == NULL) - return 1; - - image_load(dev, mjpeg_image); - - uvc_events_init(dev); - uvc_video_init(dev); - /* - * Register a signal handler for SIGINT, received when the user presses - * CTRL-C. This will allow the main loop to be interrupted, and resources - * to be freed cleanly. + * Create the events handler. Register a signal handler for SIGINT, + * received when the user presses CTRL-C. This will allow the main loop + * to be interrupted, and resources to be freed cleanly. */ - uvc_device = dev; + events_init(&events); + + sigint_events = &events; signal(SIGINT, sigint_handler); - events_watch_fd(&dev->events, dev->vdev->fd, EVENT_EXCEPTION, - uvc_events_process, dev); + /* Create and initialise the stream. */ + stream = uvc_stream_new(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); /* Main capture loop */ - events_loop(&dev->events); + events_loop(&events); - events_cleanup(&dev->events); - uvc_close(dev); - return 0; +done: + /* Cleanup */ + uvc_stream_delete(stream); + events_cleanup(&events); + + return ret; } -- cgit v1.2.3