summaryrefslogtreecommitdiff
path: root/lib/stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stream.c')
-rw-r--r--lib/stream.c223
1 files changed, 223 insertions, 0 deletions
diff --git a/lib/stream.c b/lib/stream.c
new file mode 100644
index 0000000..57745aa
--- /dev/null
+++ b/lib/stream.c
@@ -0,0 +1,223 @@
+/*
+ * UVC stream handling
+ *
+ * Copyright (C) 2010 Ideas on board SPRL <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "events.h"
+#include "stream.h"
+#include "uvc.h"
+#include "v4l2.h"
+#include "video-buffers.h"
+#include "video-source.h"
+
+/*
+ * struct uvc_stream - Representation of a UVC stream
+ * @src: video source
+ * @uvc: UVC V4L2 output device
+ * @events: struct events containing event information
+ */
+struct uvc_stream
+{
+ struct video_source *src;
+ struct uvc_device *uvc;
+
+ struct events *events;
+};
+
+/* ---------------------------------------------------------------------------
+ * Video streaming
+ */
+
+static void uvc_stream_source_process(void *d, struct video_source *src,
+ struct video_buffer *buffer)
+{
+ struct uvc_stream *stream = d;
+ struct v4l2_device *sink = uvc_v4l2_device(stream->uvc);
+
+ v4l2_queue_buffer(sink, buffer);
+}
+
+static void uvc_stream_uvc_process(void *d)
+{
+ struct uvc_stream *stream = d;
+ struct v4l2_device *sink = uvc_v4l2_device(stream->uvc);
+ struct video_buffer buf;
+ int ret;
+
+ ret = v4l2_dequeue_buffer(sink, &buf);
+ if (ret < 0)
+ return;
+
+ video_source_queue_buffer(stream->src, &buf);
+}
+
+static int uvc_stream_start(struct uvc_stream *stream)
+{
+ struct v4l2_device *sink = uvc_v4l2_device(stream->uvc);
+ struct video_buffer_set *buffers = NULL;
+ int ret;
+
+ printf("Starting video stream.\n");
+
+ /* Allocate and export the buffers on the source. */
+ ret = video_source_alloc_buffers(stream->src, 4);
+ if (ret < 0) {
+ printf("Failed to allocate source buffers: %s (%d)\n",
+ strerror(-ret), -ret);
+ return ret;
+ }
+
+ ret = video_source_export_buffers(stream->src, &buffers);
+ if (ret < 0) {
+ printf("Failed to export buffers on source: %s (%d)\n",
+ strerror(-ret), -ret);
+ goto error_free_source;
+ }
+
+ /* Allocate and import the buffers on the sink. */
+ ret = v4l2_alloc_buffers(sink, V4L2_MEMORY_DMABUF, buffers->nbufs);
+ if (ret < 0) {
+ printf("Failed to allocate sink buffers: %s (%d)\n",
+ strerror(-ret), -ret);
+ goto error_free_source;
+ }
+
+ ret = v4l2_import_buffers(sink, buffers);
+ if (ret < 0) {
+ printf("Failed to import buffers on sink: %s (%d)\n",
+ strerror(-ret), -ret);
+ goto error_free_sink;
+ }
+
+ /* Start the source and sink. */
+ video_source_stream_on(stream->src);
+ v4l2_stream_on(sink);
+
+ events_watch_fd(stream->events, sink->fd, EVENT_WRITE,
+ uvc_stream_uvc_process, stream);
+
+ return 0;
+
+error_free_sink:
+ v4l2_free_buffers(sink);
+error_free_source:
+ video_source_free_buffers(stream->src);
+ if (buffers)
+ video_buffer_set_delete(buffers);
+ return ret;
+}
+
+static int uvc_stream_stop(struct uvc_stream *stream)
+{
+ struct v4l2_device *sink = uvc_v4l2_device(stream->uvc);
+
+ printf("Stopping video stream.\n");
+
+ events_unwatch_fd(stream->events, sink->fd, EVENT_WRITE);
+
+ v4l2_stream_off(sink);
+ video_source_stream_off(stream->src);
+
+ v4l2_free_buffers(sink);
+ video_source_free_buffers(stream->src);
+
+ return 0;
+}
+
+void uvc_stream_enable(struct uvc_stream *stream, int enable)
+{
+ if (enable)
+ uvc_stream_start(stream);
+ else
+ uvc_stream_stop(stream);
+}
+
+int uvc_stream_set_format(struct uvc_stream *stream,
+ const struct v4l2_pix_format *format)
+{
+ struct v4l2_pix_format fmt = *format;
+ int ret;
+
+ printf("Setting format to 0x%08x %ux%u\n",
+ format->pixelformat, format->width, format->height);
+
+ ret = uvc_set_format(stream->uvc, &fmt);
+ if (ret < 0)
+ return ret;
+
+ return video_source_set_format(stream->src, &fmt);
+}
+
+/* ---------------------------------------------------------------------------
+ * Stream handling
+ */
+
+struct uvc_stream *uvc_stream_new(const char *uvc_device)
+{
+ struct uvc_stream *stream;
+
+ stream = malloc(sizeof(*stream));
+ if (stream == NULL)
+ return NULL;
+
+ memset(stream, 0, sizeof(*stream));
+
+ stream->uvc = uvc_open(uvc_device, stream);
+ if (stream->uvc == NULL)
+ goto error;
+
+ return stream;
+
+error:
+ free(stream);
+ return NULL;
+}
+
+void uvc_stream_delete(struct uvc_stream *stream)
+{
+ if (stream == NULL)
+ return;
+
+ uvc_close(stream->uvc);
+
+ free(stream);
+}
+
+void uvc_stream_init_uvc(struct uvc_stream *stream,
+ struct uvc_function_config *fc)
+{
+ uvc_set_config(stream->uvc, fc);
+ uvc_events_init(stream->uvc, stream->events);
+}
+
+void uvc_stream_set_event_handler(struct uvc_stream *stream,
+ struct events *events)
+{
+ stream->events = events;
+}
+
+void uvc_stream_set_video_source(struct uvc_stream *stream,
+ struct video_source *src)
+{
+ stream->src = src;
+
+ video_source_set_buffer_handler(src, uvc_stream_source_process, stream);
+}