summaryrefslogtreecommitdiff
path: root/uvc-gadget.c
diff options
context:
space:
mode:
authorPaul Elder <paul.elder@ideasonboard.com>2018-05-24 02:12:38 +0800
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2018-05-24 01:26:38 +0300
commit53b139a22810e00aa0ce872853b45107c4edee98 (patch)
treeee5638d3430532214c272d01f51c0d591aeaf508 /uvc-gadget.c
parentce7513accfc4efc93cd07afd0e6ba595402cad72 (diff)
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 <paul.elder@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'uvc-gadget.c')
-rw-r--r--uvc-gadget.c169
1 files changed, 118 insertions, 51 deletions
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;
}