summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--uvc-gadget.c192
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);