|
From: libvidcap c. <lib...@li...> - 2010-03-09 18:35:51
|
Revision: 107
http://libvidcap.svn.sourceforge.net/libvidcap/?rev=107&view=rev
Author: kretikus
Date: 2010-03-09 18:35:43 +0000 (Tue, 09 Mar 2010)
Log Message:
-----------
* first commit to get v4l2 support for libvidcap
What is working:
- Detection if device supports v4l2
- Scanning device capabilities
- Setting desired video format
Modified Paths:
--------------
branches/v4l2_support/src/Makefile.am
branches/v4l2_support/src/sapi_v4l.c
Added Paths:
-----------
branches/v4l2_support/src/v4l/
branches/v4l2_support/src/v4l/v4l1_backend.c
branches/v4l2_support/src/v4l/v4l2_backend.c
branches/v4l2_support/src/v4l/v4l_ctx.h
Modified: branches/v4l2_support/src/Makefile.am
===================================================================
--- branches/v4l2_support/src/Makefile.am 2010-03-09 18:21:45 UTC (rev 106)
+++ branches/v4l2_support/src/Makefile.am 2010-03-09 18:35:43 UTC (rev 107)
@@ -34,7 +34,11 @@
vidcap.c
if HAVE_V4L
-libvidcap_la_SOURCES += sapi_v4l.c
+libvidcap_la_SOURCES += \
+ v4l/v4l_ctx.h \
+ v4l/v4l1_backend.c \
+ v4l/v4l2_backend.c \
+ sapi_v4l.c
endif
if HAVE_QUICKTIME
Modified: branches/v4l2_support/src/sapi_v4l.c
===================================================================
--- branches/v4l2_support/src/sapi_v4l.c 2010-03-09 18:21:45 UTC (rev 106)
+++ branches/v4l2_support/src/sapi_v4l.c 2010-03-09 18:35:43 UTC (rev 107)
@@ -25,56 +25,16 @@
#include <errno.h>
#include <fcntl.h>
-#include <linux/videodev.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <unistd.h>
-#include "conv.h"
-#include "hotlist.h"
-#include "logging.h"
-#include "sapi.h"
+#include "v4l/v4l_ctx.h"
+
static const char * identifier = "video4linux";
static const char * description = "Video for Linux (v4l) video capture API";
-enum
-{
- device_path_max = 128,
- device_num_max = 16,
- v4l_fps_mask = 0x003f0000,
- v4l_fps_shift = 16,
-};
-struct sapi_v4l_context
-{
- vc_mutex mutex;
- vc_thread notify_thread;
- unsigned int notify_thread_id;
- int notifying;
- struct sapi_src_list acquired_src_list;
-};
-
-struct sapi_v4l_src_context
-{
- struct sapi_v4l_context * v4l_ctx;
-
- int fd;
- char device_path[device_path_max];
- int channel;
-
- struct video_capability caps;
- struct video_picture picture;
- struct video_window window;
- struct video_mbuf mbuf;
-
- int capturing;
- vc_thread capture_thread;
- unsigned int capture_thread_id;
-};
-
static int
parse_src_identifier(const char * identifier,
char * device_path,
@@ -118,81 +78,7 @@
return 0;
}
-static int
-map_fourcc_to_palette(int fourcc, __u16 * palette)
-{
- switch ( fourcc )
- {
- case VIDCAP_FOURCC_I420:
- *palette = VIDEO_PALETTE_YUV420P;
- break;
- case VIDCAP_FOURCC_RGB24:
- *palette = VIDEO_PALETTE_RGB24;
- break;
-
- case VIDCAP_FOURCC_YUY2:
- *palette = VIDEO_PALETTE_YUYV;
- break;
-
- case VIDCAP_FOURCC_2VUY:
- *palette = VIDEO_PALETTE_UYVY;
- break;
-
- case VIDCAP_FOURCC_RGB32:
- *palette = VIDEO_PALETTE_RGB32;
- break;
-
- case VIDCAP_FOURCC_RGB555:
- *palette = VIDEO_PALETTE_RGB555;
- break;
-
- case VIDCAP_FOURCC_YVU9:
- return 1;
-
- default:
- return -1;
- }
-
- return 0;
-}
-
-static int
-map_palette_to_fourcc(__u16 palette, int * fourcc)
-{
- switch ( palette )
- {
- case VIDEO_PALETTE_YUV420P:
- *fourcc = VIDCAP_FOURCC_I420;
- break;
-
- case VIDEO_PALETTE_RGB24:
- *fourcc = VIDCAP_FOURCC_RGB24;
- break;
-
- case VIDEO_PALETTE_YUYV:
- *fourcc = VIDCAP_FOURCC_YUY2;
- break;
-
- case VIDEO_PALETTE_UYVY:
- *fourcc = VIDCAP_FOURCC_2VUY;
- break;
-
- case VIDEO_PALETTE_RGB32:
- *fourcc = VIDCAP_FOURCC_RGB32;
- break;
-
- case VIDEO_PALETTE_RGB555:
- *fourcc = VIDCAP_FOURCC_RGB555;
- break;
-
- default:
- return -1;
- }
-
- return 0;
-}
-
#if 0
static void
src_list_debug(const struct sapi_src_list * src_list, const char * name)
@@ -314,7 +200,7 @@
return 0;
}
-static int
+int
src_list_device_append(struct sapi_src_list * src_list,
const char * device_path, int channel,
const char * device_name, const char * channel_name)
@@ -332,6 +218,7 @@
return src_list_src_append(src_list, &src_info);
}
+
static int
src_list_device_scan(struct sapi_src_list * src_list,
const char * device_path)
@@ -339,56 +226,24 @@
int ret = 0;
int fd;
int i;
- struct video_capability caps;
- fd = open(device_path, O_RDONLY);
+ fd = open(device_path, O_RDONLY);
- if ( fd == -1 )
+ if ( fd == -1 ) {
return 1;
+ }
/* Ensures file descriptor is closed on exec() */
fcntl(fd, F_SETFD, FD_CLOEXEC);
- memset(&caps, 0, sizeof(caps));
- if ( ioctl(fd, VIDIOCGCAP, &caps) == -1 )
- {
- log_warn("failed to get capabilities for %s\n", device_path);
- ret = -1;
- goto bail;
- }
+ if( is_v4l2_device(fd) ) {
- if ( caps.type != VID_TYPE_CAPTURE )
- {
- ret = -1;
- goto bail;
+ ret = v4l2_src_list_device_scan( fd, src_list, device_path );
+ } else {
+ ret = v4l1_src_list_device_scan( fd, src_list, device_path );
}
- for ( i = 0; i < caps.channels; ++i )
- {
- struct video_channel channel;
-
- memset(&channel, 0, sizeof(channel));
-
- channel.channel = i;
-
- if ( ioctl(fd, VIDIOCGCHAN, &channel) == -1 )
- {
- log_warn("failed VIDIOCGCHAN for %s\n", device_path);
- continue;
- }
-
- if ( src_list_device_append(src_list, device_path,
- channel.channel, caps.name,
- channel.name) )
- {
- ret = -1;
- goto bail;
- }
- }
-
-bail:
-
if ( close(fd) == -1 )
log_warn("failed to close fd %d for %s (%s)\n",
fd, device_path, strerror(errno));
@@ -511,249 +366,9 @@
return src_list->len;
}
-static int
-capture_kickoff(struct sapi_src_context * src_ctx,
- unsigned int frame_count)
-{
- struct sapi_v4l_src_context * v4l_src_ctx =
- (struct sapi_v4l_src_context *)src_ctx->priv;
- struct video_mmap vmap;
-
- vmap.frame = frame_count % v4l_src_ctx->mbuf.frames;
- vmap.height = v4l_src_ctx->window.height;
- vmap.width = v4l_src_ctx->window.width;
- vmap.format = v4l_src_ctx->picture.palette;
-
- if ( ioctl(v4l_src_ctx->fd, VIDIOCMCAPTURE, &vmap) == -1 )
- {
- log_error("failed VIDIOCMCAPTURE %d\n", errno);
- return -1;
- }
-
- return 0;
-}
-
-static unsigned int
-capture_thread_proc(void * data)
+int common_source_release(struct sapi_src_context * src_ctx)
{
- struct sapi_src_context * src_ctx =
- (struct sapi_src_context *)data;
- struct sapi_v4l_src_context * v4l_src_ctx =
- (struct sapi_v4l_src_context *)src_ctx->priv;
- const int capture_size = conv_fmt_size_get(
- src_ctx->fmt_native.width,
- src_ctx->fmt_native.height,
- src_ctx->fmt_native.fourcc);
-
- const char * fb_base = mmap(0, v4l_src_ctx->mbuf.size,
- PROT_READ, MAP_SHARED, v4l_src_ctx->fd, 0);
-
- unsigned int started_frame_count = 0;
- unsigned int capture_frame_count = 0;
-
- if ( fb_base == (void *)-1 )
- {
- log_error("failed mmap() %d\n", errno);
- return -1;
- }
-
- if ( capture_kickoff(src_ctx, started_frame_count) )
- goto bail;
-
- while ( v4l_src_ctx->capturing )
- {
- const unsigned int capture_frame =
- capture_frame_count % v4l_src_ctx->mbuf.frames;
-
- if ( capture_kickoff(src_ctx, ++started_frame_count) )
- goto bail;
-
- if ( ioctl( v4l_src_ctx->fd, VIDIOCSYNC,
- &capture_frame ) == -1 )
- {
- log_error("failed VIDIOCSYNC %d\n", errno);
- goto bail;
- }
-
- sapi_src_capture_notify(src_ctx, (char *)(fb_base +
- v4l_src_ctx->mbuf.offsets[capture_frame]),
- capture_size,
- 0,
- 0);
-
- ++capture_frame_count;
- }
-
- /* Sync with the last frame when capture has stopped (since we
- * have overlapped capture kickoffs).
- */
- {
- const unsigned int capture_frame =
- capture_frame_count % v4l_src_ctx->mbuf.frames;
-
- if ( ioctl( v4l_src_ctx->fd, VIDIOCSYNC,
- &capture_frame ) == -1 )
- {
- log_error("failed VIDIOCSYNC (2) %d\n", errno);
- goto bail;
- }
- }
-
-
- if ( munmap((void *)fb_base, v4l_src_ctx->mbuf.size) == -1 )
- {
- log_error("failed munmap() %d\n", errno);
- return -1;
- }
-
- return 0;
-
-bail:
- if ( munmap((void *)fb_base, v4l_src_ctx->mbuf.size) == -1 )
- log_warn("failed munmap() %d\n", errno);
-
- return -1;
-}
-
-static int
-source_capture_start(struct sapi_src_context * src_ctx)
-{
- struct sapi_v4l_src_context * v4l_src_ctx =
- (struct sapi_v4l_src_context *)src_ctx->priv;
- int ret;
-
- v4l_src_ctx->capturing = 1;
-
- if ( (ret = vc_create_thread(&v4l_src_ctx->capture_thread,
- capture_thread_proc, src_ctx,
- &v4l_src_ctx->capture_thread_id)) )
- {
- log_error("failed vc_create_thread() for capture thread %d\n",
- ret);
- return -1;
- }
-
- return 0;
-}
-
-static int
-source_capture_stop(struct sapi_src_context * src_ctx)
-{
- struct sapi_v4l_src_context * v4l_src_ctx =
- (struct sapi_v4l_src_context *)src_ctx->priv;
- int ret;
-
- v4l_src_ctx->capturing = 0;
-
- if ( (ret = vc_thread_join(&v4l_src_ctx->capture_thread)) )
- {
- log_error("failed vc_thread_join() %d\n", ret);
- return -1;
- }
-
- return 0;
-}
-
-static int
-source_format_validate(struct sapi_src_context * src_ctx,
- const struct vidcap_fmt_info * fmt_nominal,
- struct vidcap_fmt_info * fmt_native, int forBinding )
-{
- struct sapi_v4l_src_context * v4l_src_ctx =
- (struct sapi_v4l_src_context *)src_ctx->priv;
-
- *fmt_native = *fmt_nominal;
-
- __u16 palette;
-
- if ( fmt_nominal->width < v4l_src_ctx->caps.minwidth ||
- fmt_nominal->width > v4l_src_ctx->caps.maxwidth ||
- fmt_nominal->height < v4l_src_ctx->caps.minheight ||
- fmt_nominal->height > v4l_src_ctx->caps.maxheight )
- return 0;
-
- if ( map_fourcc_to_palette(fmt_nominal->fourcc, &palette) )
- return 0;
-
- if ( map_palette_to_fourcc(v4l_src_ctx->picture.palette,
- &fmt_native->fourcc) )
- return 0;
-
- if ( !sapi_can_convert_native_to_nominal(fmt_native, fmt_nominal) )
- return 0;
-
- return 1;
-}
-
-static int
-source_format_bind(struct sapi_src_context * src_ctx,
- const struct vidcap_fmt_info * fmt_info)
-{
- struct sapi_v4l_src_context * v4l_src_ctx =
- (struct sapi_v4l_src_context *)src_ctx->priv;
-
- memcpy(&src_ctx->fmt_native, fmt_info, sizeof(*fmt_info));
-
- if ( map_palette_to_fourcc(v4l_src_ctx->picture.palette,
- &src_ctx->fmt_native.fourcc) )
- {
- log_warn("failed map_palette_to_fourcc %d\n",
- v4l_src_ctx->picture.palette);
- return -1;
- }
-
- if ( ioctl(v4l_src_ctx->fd, VIDIOCSPICT, &v4l_src_ctx->picture) == -1 )
- {
- log_warn("failed to set v4l picture parameters\n");
- return -1;
- }
-
- /* Only set the parameters we know/care about. */
- v4l_src_ctx->window.x = 0;
- v4l_src_ctx->window.y = 0;
- v4l_src_ctx->window.width = fmt_info->width;
- v4l_src_ctx->window.height = fmt_info->height;
- /* TODO: for pwc, framerate is encoded in flags. For other
- * cameras, who knows.
- */
- v4l_src_ctx->window.flags =
- (v4l_src_ctx->window.flags & ~v4l_fps_mask) |
- (((src_ctx->fmt_native.fps_numerator /
- src_ctx->fmt_native.fps_denominator) << v4l_fps_shift) &
- v4l_fps_mask);
-
- if ( ioctl(v4l_src_ctx->fd, VIDIOCSWIN, &v4l_src_ctx->window) == -1 )
- {
- log_warn("failed to set v4l window parameters x=%d y=%d "
- "w=%d h=%d fl=0x%08x\n",
- v4l_src_ctx->window.x,
- v4l_src_ctx->window.y,
- v4l_src_ctx->window.width,
- v4l_src_ctx->window.height,
- v4l_src_ctx->window.flags);
- return -1;
- }
-
- if ( ioctl(v4l_src_ctx->fd, VIDIOCGWIN, &v4l_src_ctx->window) == -1 )
- {
- log_warn("failed to get v4l window parameters\n");
- return -1;
- }
-
- if ( ioctl(v4l_src_ctx->fd, VIDIOCGMBUF, &v4l_src_ctx->mbuf) == -1 )
- {
- log_warn("failed to get v4l memory info for %s\n",
- v4l_src_ctx->device_path);
- return -1;
- }
-
- return 0;
-}
-
-static int
-source_release(struct sapi_src_context * src_ctx)
-{
int ret = 0;
struct sapi_v4l_src_context * v4l_src_ctx =
@@ -786,6 +401,8 @@
return ret;
}
+
+
static int
source_acquire(struct sapi_context * sapi_ctx,
struct sapi_src_context * src_ctx,
@@ -865,7 +482,7 @@
goto bail;
}
- v4l_src_ctx->fd = open(v4l_src_ctx->device_path, O_RDONLY);
+ v4l_src_ctx->fd = open(v4l_src_ctx->device_path, O_RDWR );
if ( v4l_src_ctx->fd == -1 )
{
@@ -875,24 +492,14 @@
goto bail;
}
- if ( ioctl(v4l_src_ctx->fd, VIDIOCGCAP, &v4l_src_ctx->caps) == -1 )
- {
- log_warn("failed to get v4l capability parameters for %s\n",
- v4l_src_ctx->device_path);
- goto bail;
- }
+ int ret = 0;
+ if( is_v4l2_device(v4l_src_ctx->fd) ) {
+ ret = v4l2_source_acquire( src_ctx, v4l_src_ctx );
+ } else {
- if ( ioctl(v4l_src_ctx->fd, VIDIOCGWIN, &v4l_src_ctx->window) == -1 )
- {
- log_warn("failed to get v4l window parameters for %s\n",
- v4l_src_ctx->device_path);
- goto bail;
+ ret = v4l1_source_acquire( src_ctx, v4l_src_ctx );
}
-
- if ( ioctl(v4l_src_ctx->fd, VIDIOCGPICT, &v4l_src_ctx->picture) == -1 )
- {
- log_warn("failed to get v4l picture parameters for %s\n",
- v4l_src_ctx->device_path);
+ if( ret == -1 ) {
goto bail;
}
@@ -910,21 +517,17 @@
}
v4l_src_ctx->capturing = 0;
-
- src_ctx->release = source_release;
- src_ctx->format_validate = source_format_validate;
- src_ctx->format_bind = source_format_bind;
- src_ctx->start_capture = source_capture_start;
- src_ctx->stop_capture = source_capture_stop;
src_ctx->priv = v4l_src_ctx;
return 0;
+
bail:
free(v4l_src_ctx);
return -1;
}
+
static unsigned int
notify_thread_proc(void * data)
{
@@ -955,6 +558,7 @@
return 0;
}
+
static int
notify_thread_stop(struct sapi_context * sapi_ctx)
{
@@ -973,6 +577,7 @@
return 0;
}
+
static int
monitor_sources(struct sapi_context * sapi_ctx)
{
@@ -997,6 +602,7 @@
return 0;
}
+
static void
sapi_v4l_destroy(struct sapi_context * sapi_ctx)
{
@@ -1009,6 +615,7 @@
free(v4l_ctx);
}
+
int
sapi_v4l_initialize(struct sapi_context * sapi_ctx)
{
@@ -1043,4 +650,3 @@
return 0;
}
-
Added: branches/v4l2_support/src/v4l/v4l1_backend.c
===================================================================
--- branches/v4l2_support/src/v4l/v4l1_backend.c (rev 0)
+++ branches/v4l2_support/src/v4l/v4l1_backend.c 2010-03-09 18:35:43 UTC (rev 107)
@@ -0,0 +1,433 @@
+#include "v4l_ctx.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/videodev.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+struct sapi_v4l1_backend_context
+{
+ struct video_capability caps;
+ struct video_picture picture;
+ struct video_window window;
+ struct video_mbuf mbuf;
+};
+
+
+static int
+map_fourcc_to_palette(int fourcc, __u16 * palette)
+{
+ switch ( fourcc )
+ {
+ case VIDCAP_FOURCC_I420:
+ *palette = VIDEO_PALETTE_YUV420P;
+ break;
+
+ case VIDCAP_FOURCC_RGB24:
+ *palette = VIDEO_PALETTE_RGB24;
+ break;
+
+ case VIDCAP_FOURCC_YUY2:
+ *palette = VIDEO_PALETTE_YUYV;
+ break;
+
+ case VIDCAP_FOURCC_2VUY:
+ *palette = VIDEO_PALETTE_UYVY;
+ break;
+
+ case VIDCAP_FOURCC_RGB32:
+ *palette = VIDEO_PALETTE_RGB32;
+ break;
+
+ case VIDCAP_FOURCC_RGB555:
+ *palette = VIDEO_PALETTE_RGB555;
+ break;
+
+ case VIDCAP_FOURCC_YVU9:
+ return 1;
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+map_palette_to_fourcc(__u16 palette, int * fourcc)
+{
+ switch ( palette )
+ {
+ case VIDEO_PALETTE_YUV420P:
+ *fourcc = VIDCAP_FOURCC_I420;
+ break;
+
+ case VIDEO_PALETTE_RGB24:
+ *fourcc = VIDCAP_FOURCC_RGB24;
+ break;
+
+ case VIDEO_PALETTE_YUYV:
+ *fourcc = VIDCAP_FOURCC_YUY2;
+ break;
+
+ case VIDEO_PALETTE_UYVY:
+ *fourcc = VIDCAP_FOURCC_2VUY;
+ break;
+
+ case VIDEO_PALETTE_RGB32:
+ *fourcc = VIDCAP_FOURCC_RGB32;
+ break;
+
+ case VIDEO_PALETTE_RGB555:
+ *fourcc = VIDCAP_FOURCC_RGB555;
+ break;
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int v4l1_src_list_device_scan(int fd, struct sapi_src_list * src_list, const char * device_path)
+{
+ int ret = 0;
+ int i = 0;
+ struct video_capability caps;
+ memset(&caps, 0, sizeof(caps));
+
+ if ( ioctl(fd, VIDIOCGCAP, &caps) == -1 )
+ {
+ log_warn("failed to get capabilities for %s\n", device_path);
+ ret = -1;
+ goto bail;
+ }
+
+ if ( caps.type != VID_TYPE_CAPTURE )
+ {
+ ret = -1;
+ goto bail;
+ }
+
+ for( i = 0; i < caps.channels; ++i )
+ {
+ struct video_channel channel;
+
+ memset(&channel, 0, sizeof(channel));
+
+ channel.channel = i;
+
+ if ( ioctl(fd, VIDIOCGCHAN, &channel) == -1 )
+ {
+ log_warn("failed VIDIOCGCHAN for %s\n", device_path);
+ continue;
+ }
+
+ if ( src_list_device_append(src_list, device_path,
+ channel.channel, caps.name,
+ channel.name) )
+ {
+ ret = -1;
+ }
+ }
+
+bail:
+ return ret;
+}
+
+
+static int capture_kickoff(struct sapi_src_context * src_ctx,
+ unsigned int frame_count)
+{
+ struct sapi_v4l_src_context * v4l_src_ctx =
+ (struct sapi_v4l_src_context *)src_ctx->priv;
+
+ struct video_mmap vmap;
+
+ vmap.frame = frame_count % v4l_src_ctx->v4l1_ctx->mbuf.frames;
+ vmap.height = v4l_src_ctx->v4l1_ctx->window.height;
+ vmap.width = v4l_src_ctx->v4l1_ctx->window.width;
+ vmap.format = v4l_src_ctx->v4l1_ctx->picture.palette;
+
+ if ( ioctl(v4l_src_ctx->fd, VIDIOCMCAPTURE, &vmap) == -1 )
+ {
+ log_error("failed VIDIOCMCAPTURE %d\n", errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static unsigned int capture_thread_proc(void * data)
+{
+ struct sapi_src_context * src_ctx =
+ (struct sapi_src_context *)data;
+ struct sapi_v4l_src_context * v4l_src_ctx =
+ (struct sapi_v4l_src_context *)src_ctx->priv;
+ const int capture_size = conv_fmt_size_get(
+ src_ctx->fmt_native.width,
+ src_ctx->fmt_native.height,
+ src_ctx->fmt_native.fourcc);
+
+ const char * fb_base = mmap(0, v4l_src_ctx->v4l1_ctx->mbuf.size, PROT_READ, MAP_SHARED, v4l_src_ctx->fd, 0);
+
+ unsigned int started_frame_count = 0;
+ unsigned int capture_frame_count = 0;
+
+ if ( fb_base == (void *)-1 )
+ {
+ log_error("failed mmap() %d\n", errno);
+ return -1;
+ }
+
+ if ( capture_kickoff(src_ctx, started_frame_count) )
+ goto bail;
+
+ while ( v4l_src_ctx->capturing )
+ {
+ const unsigned int capture_frame =
+ capture_frame_count % v4l_src_ctx->v4l1_ctx->mbuf.frames;
+
+ if ( capture_kickoff(src_ctx, ++started_frame_count) )
+ goto bail;
+
+ if ( ioctl( v4l_src_ctx->fd, VIDIOCSYNC, &capture_frame ) == -1 )
+ {
+ log_error("failed VIDIOCSYNC %d\n", errno);
+ goto bail;
+ }
+
+ sapi_src_capture_notify(src_ctx, (char *)(fb_base +
+ v4l_src_ctx->v4l1_ctx->mbuf.offsets[capture_frame]),
+ capture_size,
+ 0,
+ 0);
+
+ ++capture_frame_count;
+ }
+
+ /* Sync with the last frame when capture has stopped (since we
+ * have overlapped capture kickoffs).
+ */
+ {
+ const unsigned int capture_frame =
+ capture_frame_count % v4l_src_ctx->v4l1_ctx->mbuf.frames;
+
+ if ( ioctl( v4l_src_ctx->fd, VIDIOCSYNC,
+ &capture_frame ) == -1 )
+ {
+ log_error("failed VIDIOCSYNC (2) %d\n", errno);
+ goto bail;
+ }
+ }
+
+
+ if ( munmap((void *)fb_base, v4l_src_ctx->v4l1_ctx->mbuf.size) == -1 )
+ {
+ log_error("failed munmap() %d\n", errno);
+ return -1;
+ }
+
+ return 0;
+
+bail:
+ if ( munmap((void *)fb_base, v4l_src_ctx->v4l1_ctx->mbuf.size) == -1 )
+ log_warn("failed munmap() %d\n", errno);
+
+ return -1;
+}
+
+
+
+static int
+v4l1_source_release(struct sapi_src_context * src_ctx)
+{
+ struct sapi_v4l_src_context * v4l_src_ctx =
+ (struct sapi_v4l_src_context *)src_ctx->priv;
+ free( v4l_src_ctx->v4l1_ctx );
+ return common_source_release( src_ctx );
+}
+
+
+static int
+v4l1_source_format_validate(struct sapi_src_context * src_ctx,
+ const struct vidcap_fmt_info * fmt_nominal,
+ struct vidcap_fmt_info * fmt_native, int forBinding )
+{
+ struct sapi_v4l_src_context * v4l_src_ctx =
+ (struct sapi_v4l_src_context *)src_ctx->priv;
+
+ *fmt_native = *fmt_nominal;
+
+ __u16 palette;
+
+ if ( fmt_nominal->width < v4l_src_ctx->v4l1_ctx->caps.minwidth ||
+ fmt_nominal->width > v4l_src_ctx->v4l1_ctx->caps.maxwidth ||
+ fmt_nominal->height < v4l_src_ctx->v4l1_ctx->caps.minheight ||
+ fmt_nominal->height > v4l_src_ctx->v4l1_ctx->caps.maxheight )
+ return 0;
+
+ if ( map_fourcc_to_palette(fmt_nominal->fourcc, &palette) )
+ return 0;
+
+ if ( map_palette_to_fourcc(v4l_src_ctx->v4l1_ctx->picture.palette,
+ &fmt_native->fourcc) )
+ return 0;
+
+ if ( !sapi_can_convert_native_to_nominal(fmt_native, fmt_nominal) )
+ return 0;
+
+ return 1;
+}
+
+static int
+v4l1_source_format_bind(struct sapi_src_context * src_ctx,
+ const struct vidcap_fmt_info * fmt_info)
+{
+ struct sapi_v4l_src_context * v4l_src_ctx =
+ (struct sapi_v4l_src_context *)src_ctx->priv;
+
+ memcpy(&src_ctx->fmt_native, fmt_info, sizeof(*fmt_info));
+
+ if ( map_palette_to_fourcc(v4l_src_ctx->v4l1_ctx->picture.palette,
+ &src_ctx->fmt_native.fourcc) )
+ {
+ log_warn("failed map_palette_to_fourcc %d\n",
+ v4l_src_ctx->v4l1_ctx->picture.palette);
+ return -1;
+ }
+
+ if ( ioctl(v4l_src_ctx->fd, VIDIOCSPICT, &v4l_src_ctx->v4l1_ctx->picture) == -1 )
+ {
+ log_warn("failed to set v4l picture parameters\n");
+ return -1;
+ }
+
+ /* Only set the parameters we know/care about. */
+ v4l_src_ctx->v4l1_ctx->window.x = 0;
+ v4l_src_ctx->v4l1_ctx->window.y = 0;
+ v4l_src_ctx->v4l1_ctx->window.width = fmt_info->width;
+ v4l_src_ctx->v4l1_ctx->window.height = fmt_info->height;
+ /* TODO: for pwc, framerate is encoded in flags. For other
+ * cameras, who knows.
+ */
+ v4l_src_ctx->v4l1_ctx->window.flags =
+ (v4l_src_ctx->v4l1_ctx->window.flags & ~v4l_fps_mask) |
+ (((src_ctx->fmt_native.fps_numerator /
+ src_ctx->fmt_native.fps_denominator) << v4l_fps_shift) &
+ v4l_fps_mask);
+
+ if ( ioctl(v4l_src_ctx->fd, VIDIOCSWIN, &v4l_src_ctx->v4l1_ctx->window) == -1 )
+ {
+ log_warn("failed to set v4l window parameters x=%d y=%d "
+ "w=%d h=%d fl=0x%08x\n",
+ v4l_src_ctx->v4l1_ctx->window.x,
+ v4l_src_ctx->v4l1_ctx->window.y,
+ v4l_src_ctx->v4l1_ctx->window.width,
+ v4l_src_ctx->v4l1_ctx->window.height,
+ v4l_src_ctx->v4l1_ctx->window.flags);
+ return -1;
+ }
+
+ if ( ioctl(v4l_src_ctx->fd, VIDIOCGWIN, &v4l_src_ctx->v4l1_ctx->window) == -1 )
+ {
+ log_warn("failed to get v4l window parameters\n");
+ return -1;
+ }
+
+ if ( ioctl(v4l_src_ctx->fd, VIDIOCGMBUF, &v4l_src_ctx->v4l1_ctx->mbuf) == -1 )
+ {
+ log_warn("failed to get v4l memory info for %s\n",
+ v4l_src_ctx->device_path);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+v4l1_source_capture_start(struct sapi_src_context * src_ctx)
+{
+ struct sapi_v4l_src_context * v4l_src_ctx =
+ (struct sapi_v4l_src_context *)src_ctx->priv;
+ int ret;
+
+ v4l_src_ctx->capturing = 1;
+
+ if ( (ret = vc_create_thread(&v4l_src_ctx->capture_thread,
+ capture_thread_proc, src_ctx,
+ &v4l_src_ctx->capture_thread_id)) )
+ {
+ log_error("failed vc_create_thread() for capture thread %d\n",
+ ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+v4l1_source_capture_stop(struct sapi_src_context * src_ctx)
+{
+ struct sapi_v4l_src_context * v4l_src_ctx =
+ (struct sapi_v4l_src_context *)src_ctx->priv;
+ int ret;
+
+ v4l_src_ctx->capturing = 0;
+
+ if ( (ret = vc_thread_join(&v4l_src_ctx->capture_thread)) )
+ {
+ log_error("failed vc_thread_join() %d\n", ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int v4l1_source_acquire( struct sapi_src_context * src_ctx, struct sapi_v4l_src_context * v4l_src_ctx )
+{
+ int ret = 0;
+ v4l_src_ctx->v4l1_ctx = (struct sapi_v4l1_backend_context*) calloc( 1, sizeof( struct sapi_v4l1_backend_context ) );
+
+ if ( ioctl(v4l_src_ctx->fd, VIDIOCGCAP, &v4l_src_ctx->v4l1_ctx->caps) == -1 )
+ {
+ log_warn("failed to get v4l capability parameters for %s\n",
+ v4l_src_ctx->device_path);
+ ret = -1;
+ goto bail;
+ }
+
+ if ( ioctl(v4l_src_ctx->fd, VIDIOCGWIN, &v4l_src_ctx->v4l1_ctx->window) == -1 )
+ {
+ log_warn("failed to get v4l window parameters for %s\n",
+ v4l_src_ctx->device_path);
+ ret = -1;
+ goto bail;
+ }
+
+ if ( ioctl(v4l_src_ctx->fd, VIDIOCGPICT, &v4l_src_ctx->v4l1_ctx->picture) == -1 )
+ {
+ log_warn("failed to get v4l picture parameters for %s\n",
+ v4l_src_ctx->device_path);
+ ret = -1;
+ goto bail;
+ }
+
+ src_ctx->release = v4l1_source_release;
+ src_ctx->format_validate = v4l1_source_format_validate;
+ src_ctx->format_bind = v4l1_source_format_bind;
+ src_ctx->start_capture = v4l1_source_capture_start;
+ src_ctx->stop_capture = v4l1_source_capture_stop;
+
+bail:
+ return ret;
+}
Added: branches/v4l2_support/src/v4l/v4l2_backend.c
===================================================================
--- branches/v4l2_support/src/v4l/v4l2_backend.c (rev 0)
+++ branches/v4l2_support/src/v4l/v4l2_backend.c 2010-03-09 18:35:43 UTC (rev 107)
@@ -0,0 +1,617 @@
+#include "v4l_ctx.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <asm/types.h> /* for videodev2.h */
+#include <linux/videodev2.h>
+#define CLEAR(x) memset (&(x), 0, sizeof (x))
+
+
+typedef enum {
+ IO_METHOD_READ,
+ IO_METHOD_MMAP,
+ IO_METHOD_USERPTR,
+} io_method;
+
+struct pic_buffer {
+ void* data;
+ int length;
+};
+
+struct sapi_v4l2_backend_context
+{
+ struct v4l2_capability caps;
+ struct v4l2_cropcap cropcap;
+ struct v4l2_crop crop;
+ struct v4l2_format fmt;
+
+ struct v4l2_buffer readBuffer;
+
+ io_method method;
+
+ struct pic_buffer* buffers;
+ int buffercnt;
+};
+
+int is_v4l2_device( int fd )
+{
+ int isV4l = 1;
+
+ struct v4l2_capability caps;
+ memset(&caps, 0, sizeof(caps));
+ if( ioctl( fd, VIDIOC_QUERYCAP, &caps ) == -1 )
+ {
+ isV4l = 0;
+ }
+
+ return isV4l;
+}
+
+static unsigned int v4l2_capture_thread_proc(void * data);
+
+
+static void errno_exit( const char * s )
+{
+ fprintf( stderr, "%s error %d, %s\n",s, errno, strerror (errno) );
+ exit( EXIT_FAILURE );
+}
+
+
+static int xioctl( int fd, int request, void* arg )
+{
+ int r;
+ do {
+ r = ioctl ( fd, request, arg );
+ } while (-1 == r && EINTR == errno );
+ return r;
+}
+
+
+static int
+ v4l2_map_fourcc_to_palette( int fourcc, unsigned int *palette)
+{
+ switch ( fourcc )
+ {
+ case VIDCAP_FOURCC_I420:
+ *palette = V4L2_PIX_FMT_YVU420;
+ break;
+
+ case VIDCAP_FOURCC_RGB24:
+ *palette = V4L2_PIX_FMT_RGB24;
+ break;
+
+ case VIDCAP_FOURCC_YUY2:
+ *palette = V4L2_PIX_FMT_YUYV;
+ break;
+
+ case VIDCAP_FOURCC_2VUY:
+ *palette = V4L2_PIX_FMT_UYVY;
+ break;
+
+ case VIDCAP_FOURCC_RGB32:
+ *palette = V4L2_PIX_FMT_RGB32;
+ break;
+
+ case VIDCAP_FOURCC_RGB555:
+ *palette = V4L2_PIX_FMT_RGB555;
+ break;
+
+ case VIDCAP_FOURCC_YVU9:
+ *palette = V4L2_PIX_FMT_YVU410;
+ break;
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+ v4l2_map_palette_to_fourcc( unsigned int palette, int * fourcc)
+{
+ switch ( palette )
+ {
+ case V4L2_PIX_FMT_YVU420:
+ *fourcc = VIDCAP_FOURCC_I420;
+ break;
+
+ case V4L2_PIX_FMT_RGB24:
+ *fourcc = VIDCAP_FOURCC_RGB24;
+ break;
+
+ case V4L2_PIX_FMT_YUYV:
+ *fourcc = VIDCAP_FOURCC_YUY2;
+ break;
+
+ case V4L2_PIX_FMT_UYVY:
+ *fourcc = VIDCAP_FOURCC_2VUY;
+ break;
+
+ case V4L2_PIX_FMT_RGB32:
+ *fourcc = VIDCAP_FOURCC_RGB32;
+ break;
+
+ case V4L2_PIX_FMT_RGB555:
+ *fourcc = VIDCAP_FOURCC_RGB555;
+ break;
+
+ case V4L2_PIX_FMT_YVU410:
+ *fourcc = VIDCAP_FOURCC_YVU9;
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void get_fourcc_string( int sapi_fourcc, char* dst)
+{
+ unsigned int v4l2_fourcc;
+ v4l2_map_fourcc_to_palette( sapi_fourcc, &v4l2_fourcc );
+ memcpy( dst, (char*) &v4l2_fourcc, 4);
+}
+
+
+int v4l2_src_list_device_scan(int fd, struct sapi_src_list * src_list, const char * device_path)
+{
+ int ret = 0;
+ struct v4l2_capability deviceCaps;
+
+ memset(&deviceCaps, 0, sizeof(deviceCaps));
+ if( ioctl( fd, VIDIOC_QUERYCAP, &deviceCaps ) == -1 )
+ {
+ ret = -1;
+ goto bail;
+ }
+
+ log_info( "Driver: %s\n", deviceCaps.driver );
+ log_info( "Card: %s\n", deviceCaps.card );
+ log_info( "BusInfo: %s\n", deviceCaps.bus_info );
+ log_info ("Version: %u.%u.%u\n", (deviceCaps.version >> 16) & 0xFF
+ , (deviceCaps.version >> 8) & 0xFF
+ , deviceCaps.version & 0xFF);
+
+ log_info( "Video cpabilities flag: %u\n", deviceCaps.capabilities );
+ log_info( "Video Capture support: %s\n", ( (deviceCaps.capabilities & V4L2_CAP_VIDEO_CAPTURE) > 0) ? "yes" : "no" );
+/*
+ log_info( "Video Output support: %s\n", ( (deviceCaps.capabilities & V4L2_CAP_VIDEO_OUTPUT) > 0) ? "yes" : "no" );
+ log_info( "Video Overlay support: %s\n", ( (deviceCaps.capabilities & V4L2_CAP_VIDEO_OVERLAY) > 0) ? "yes" : "no" );
+
+ log_info( "Video VBI Capture support: %s\n", ( (deviceCaps.capabilities & V4L2_CAP_VBI_CAPTURE) > 0) ? "yes" : "no" );
+ log_info( "Video VBI Output support: %s\n", ( (deviceCaps.capabilities & V4L2_CAP_VBI_OUTPUT) > 0) ? "yes" : "no" );
+ log_info( "Video Sliced VBI capture support: %s\n", ( (deviceCaps.capabilities & V4L2_CAP_SLICED_VBI_CAPTURE) > 0) ? "yes" : "no" );
+ log_info( "Video Sliced VBI output support: %s\n", ( (deviceCaps.capabilities & V4L2_CAP_SLICED_VBI_OUTPUT) > 0) ? "yes" : "no" );
+ log_info( "Video RDS capture support: %s\n", ( (deviceCaps.capabilities & V4L2_CAP_RDS_CAPTURE) > 0) ? "yes" : "no" );
+
+ log_info( "Video Output Overlay support: %s\n", ( (deviceCaps.capabilities & V4L2_CAP_VIDEO_OUTPUT_OVERLAY) > 0) ? "yes" : "no" );
+
+ log_info( "Video Tuner support: %s\n", ( (deviceCaps.capabilities & V4L2_CAP_TUNER) > 0) ? "yes" : "no" );
+ log_info( "Video Audio support: %s\n", ( (deviceCaps.capabilities & V4L2_CAP_AUDIO) > 0) ? "yes" : "no" );
+ log_info( "Video Radio support: %s\n", ( (deviceCaps.capabilities & V4L2_CAP_RADIO) > 0) ? "yes" : "no" );
+*/
+ log_info( "Video ReadWrite support: %s\n", ( (deviceCaps.capabilities & V4L2_CAP_READWRITE) > 0) ? "yes" : "no" );
+ log_info( "Video AsyncI/O support: %s\n", ( (deviceCaps.capabilities & V4L2_CAP_ASYNCIO) > 0) ? "yes" : "no" );
+ log_info( "Video Streaming support: %s\n", ( (deviceCaps.capabilities & V4L2_CAP_STREAMING) > 0) ? "yes" : "no" );
+
+
+ if( (deviceCaps.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0 ) {
+ ret = -1;
+ goto bail;
+ }
+ if( src_list_device_append( src_list, device_path,
+ 0, (char *)deviceCaps.driver
+ , (char *) deviceCaps.card ) )
+ {
+ ret = -1;
+ goto bail;
+ }
+
+ bail:
+ return ret;
+}
+
+
+static int v4l2_source_release(struct sapi_src_context * src_ctx)
+{
+ struct sapi_v4l_src_context * v4l_src_ctx = (struct sapi_v4l_src_context *)src_ctx->priv;
+ free( v4l_src_ctx->v4l2_ctx );
+ return common_source_release( src_ctx );
+}
+
+
+void set_picture_format( struct v4l2_format* v4l2_fmt, const struct vidcap_fmt_info * vidcap_fmt )
+{
+ struct v4l2_pix_format* pix = (struct v4l2_pix_format*)&v4l2_fmt->fmt;
+ pix->height = vidcap_fmt->height;
+ pix->width = vidcap_fmt->width;
+ v4l2_map_fourcc_to_palette( vidcap_fmt->fourcc, &pix->pixelformat );
+ pix->bytesperline = 0;
+ pix->field = V4L2_FIELD_ANY;
+}
+
+
+static int v4l2_source_format_validate( struct sapi_src_context * src_ctx
+ , const struct vidcap_fmt_info * fmt_nominal
+ , struct vidcap_fmt_info * fmt_native
+ , int forBinding )
+{
+ struct sapi_v4l_src_context * v4l_src_ctx = (struct sapi_v4l_src_context *)src_ctx->priv;
+ struct sapi_v4l2_backend_context* v4l2_ctx = v4l_src_ctx->v4l2_ctx;
+
+ *fmt_native = *fmt_nominal;
+
+ char fourcc[5];
+/*
+ unsigned int reqPalette;
+ v4l2_map_fourcc_to_palette( fmt_native->fourcc, &reqPalette );
+ memcpy( fourcc, (char*)&reqPalette, 4);
+ fourcc[4] = '\0';
+ printf("Requested fourcc: %s\n", fourcc );
+*/
+ /* let the structure be filled by the driver... */
+ struct v4l2_format fmt;
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if( ioctl( v4l_src_ctx->fd, VIDIOC_G_FMT, &fmt ) == -1 ) {
+ printf( "Failed to get the video format. Error was: %d\n", errno );
+ return 0;
+ }
+ /* now set the new data */
+
+ set_picture_format( &fmt, fmt_nominal );
+
+ if( ioctl( v4l_src_ctx->fd, VIDIOC_TRY_FMT, &fmt ) == -1 )
+ {
+ /*log_warn("Failed to query the video format. Error was: %d\n", errno );*/
+ return 0;
+ }
+
+ struct v4l2_pix_format* pix = (struct v4l2_pix_format*)&fmt.fmt;
+ memcpy( fourcc, (char*)&pix->pixelformat, 4);
+ fourcc[4] = '\0';
+
+ /*
+ printf("Driver Returned:\n");
+ printf( "Width: %d, Heith %d, Pixelformat: %s, Field: %d, BytesPerLine: %d, imgSize: %d, ColorSpace: %d\n"
+ , pix->width, pix->height, fourcc, pix->field, pix->bytesperline
+ , pix->sizeimage, pix->colorspace );
+ */
+
+ if( v4l2_map_palette_to_fourcc( pix->pixelformat, &fmt_native->fourcc ) )
+ {
+ return 0;
+ }
+ if ( !sapi_can_convert_native_to_nominal(fmt_native, fmt_nominal) )
+ return 0;
+
+ return 1;
+}
+
+
+static int v4l2_source_format_bind( struct sapi_src_context * src_ctx
+ , const struct vidcap_fmt_info * fmt_info )
+{
+ struct sapi_v4l_src_context * v4l_src_ctx = (struct sapi_v4l_src_context *)src_ctx->priv;
+ struct sapi_v4l2_backend_context* v4l2_ctx = v4l_src_ctx->v4l2_ctx;
+
+ char fourcc[5];
+ get_fourcc_string( fmt_info->fourcc, fourcc );
+ fourcc[4] = '\0';
+ log_info("Binding format: Size: %dx%d, Format: %s\n", fmt_info->width, fmt_info->height, fourcc );
+
+ /* let the structure be filled by the driver...*/
+ v4l2_ctx->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if( ioctl( v4l_src_ctx->fd, VIDIOC_G_FMT, &v4l2_ctx->fmt ) == -1 ) {
+ log_error( "Failed to get the video format. Error was: %d\n", errno );
+ return 0;
+ }
+
+ /* now set the new data */
+ set_picture_format( &v4l2_ctx->fmt, fmt_info );
+ if( ioctl( v4l_src_ctx->fd, VIDIOC_TRY_FMT, &v4l2_ctx->fmt ) == -1 )
+ {
+ log_error( "Failed to query the video format. Error was: %d\n", errno );
+ return -1;
+ }
+ return 0;
+}
+
+
+static int v4l2_source_capture_start( struct sapi_src_context * src_ctx )
+{
+ log_info("Start capturing\n");
+ struct sapi_v4l_src_context * v4l_src_ctx = (struct sapi_v4l_src_context *)src_ctx->priv;
+ struct sapi_v4l2_backend_context* v4l2_ctx = v4l_src_ctx->v4l2_ctx;
+ struct v4l2_requestbuffers rbufs;
+ int ret, cnt;
+ enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ struct v4l2_pix_format* pix = (struct v4l2_pix_format*)&v4l2_ctx->fmt;
+
+ if( v4l2_ctx->method == IO_METHOD_READ ) {
+ log_info("USING READ METHOD\n");
+ int i=0;
+ /* take a fixed count of buffers */
+ v4l2_ctx->buffercnt = 5;
+ v4l2_ctx->buffers = (struct pic_buffer*)calloc( v4l2_ctx->buffercnt, sizeof(struct pic_buffer) );
+ for( i=0; i < v4l2_ctx->buffercnt; ++i ) {
+ v4l2_ctx->buffers[i].data = malloc( pix->sizeimage );
+ }
+ } else {
+ log_info("USING MMAP METHOD\n");
+ int i=0;
+ /* take a fixed count of buffers */
+ v4l2_ctx->buffercnt = 5;
+ rbufs.count = v4l2_ctx->buffercnt;
+ rbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ rbufs.memory = V4L2_MEMORY_MMAP;
+ if( ioctl( v4l_src_ctx->fd, VIDIOC_REQBUFS, &rbufs ) == -1 ) {
+ /* \TODO implement userptr */
+ log_error("MMAP is not supported by this device and USERPTRs are not yet implemented.\n");
+ return -1;
+ }
+
+ if( rbufs.count < 2 ) {
+ log_error("Isufficient bufer memory\n");
+ return -1;
+ }
+ v4l2_ctx->buffercnt = rbufs.count;
+
+ v4l2_ctx->buffers = (struct pic_buffer*)calloc( v4l2_ctx->buffercnt, sizeof(*v4l2_ctx->buffers) );
+ if( !v4l2_ctx->buffers ) {
+ log_error("Out of memory\n");
+ return -1;
+ }
+
+ log_info("Mapping memory for %d pictures.\n", v4l2_ctx->buffercnt);
+
+ for( i = 0; i < v4l2_ctx->buffercnt; ++i ) {
+ struct v4l2_buffer buf;
+ CLEAR( buf );
+
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.index = i;
+ if( ioctl( v4l_src_ctx->fd, VIDIOC_QUERYBUF, &buf) == -1 ) {
+ log_error("Could not map memory\n");
+ // TODO clear structures
+ return -1;
+ }
+
+ v4l2_ctx->buffers[i].length = buf.length;
+ v4l2_ctx->buffers[i].data = mmap( NULL, buf.length
+ , PROT_READ | PROT_WRITE
+ , MAP_SHARED
+ , v4l_src_ctx->fd, buf.m.offset );
+ if( v4l2_ctx->buffers[i].data == MAP_FAILED ) {
+ log_error("Error mapping memory at memory chunk %d with error: %d, %s\n"
+ , i, errno, strerror( errno ) );
+ return -1;
+ }
+ }
+ }
+
+
+ v4l_src_ctx->capturing = 1;
+
+ if ( (ret = vc_create_thread( &v4l_src_ctx->capture_thread
+ , v4l2_capture_thread_proc, src_ctx
+ , &v4l_src_ctx->capture_thread_id ) ) )
+ {
+ log_error("failed vc_create_thread() for capture thread %d\n", ret);
+ return -1;
+ }
+
+ switch( v4l_src_ctx->v4l2_ctx->method )
+ {
+ case IO_METHOD_READ:
+ /* nothing to do*/
+ break;
+ case IO_METHOD_MMAP:
+ case IO_METHOD_USERPTR:
+
+ for( cnt = 0; cnt < v4l2_ctx->buffercnt; ++cnt) {
+ CLEAR( v4l2_ctx->readBuffer );
+ v4l2_ctx->readBuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ v4l2_ctx->readBuffer.memory = V4L2_MEMORY_MMAP;
+ v4l2_ctx->readBuffer.index = cnt;
+ if( -1 == xioctl( v4l_src_ctx->fd, VIDIOC_QBUF, &v4l2_ctx->readBuffer ) ) {
+ log_error("Could not queue image buffers\n");
+ }
+ }
+
+ if( -1 == xioctl( v4l_src_ctx->fd, VIDIOC_STREAMON, &type ) ) {
+ log_error("failed to start the capture stream. ErrNr: %d\n", errno);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+static int v4l2_source_capture_stop( struct sapi_src_context* src_ctx )
+{
+ log_info("Stop capturing\n");
+ struct sapi_v4l_src_context * v4l_src_ctx = (struct sapi_v4l_src_context *)src_ctx->priv;
+ int ret;
+ v4l_src_ctx->capturing = 0;
+ if ( (ret = vc_thread_join( &v4l_src_ctx->capture_thread) ) )
+ {
+ log_error("failed vc_thread_join() %d\n", ret);
+ return -1;
+ }
+
+ enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ switch( v4l_src_ctx->v4l2_ctx->method )
+ {
+ case IO_METHOD_READ: // nothing to do
+ break;
+ case IO_METHOD_MMAP:
+ case IO_METHOD_USERPTR:
+ if( -1 == xioctl( v4l_src_ctx->fd, VIDIOC_STREAMOFF, &type) ) {
+ log_error("failed to stop stream %d\n", errno);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+int v4l2_source_acquire( struct sapi_src_context * src_ctx, struct sapi_v4l_src_context * v4l_src_ctx )
+{
+ int ret = 0;
+
+ v4l_src_ctx->v4l2_ctx = (struct sapi_v4l2_backend_context*) calloc( 1, sizeof( struct sapi_v4l2_backend_context ) );
+
+ if( ioctl( v4l_src_ctx->fd, VIDIOC_QUERYCAP, &v4l_src_ctx->v4l2_ctx->caps ) == -1 )
+ {
+ log_warn("failed to get v4l2 capability parameters for %s\n", v4l_src_ctx->device_path);
+ ret = -1;
+ goto bail;
+
+ }
+
+ /* set method:*/
+ if( ( v4l_src_ctx->v4l2_ctx->caps.capabilities & V4L2_CAP_READWRITE ) > 0 ) v4l_src_ctx->v4l2_ctx->method = IO_METHOD_READ;
+ /*if( (v4l_src_ctx->v4l2_ctx->caps.capabilities & V4L2_CAP_ASYNCIO ) > 0 ) */ /* not yet specified*/
+ if( ( v4l_src_ctx->v4l2_ctx->caps.capabilities & V4L2_CAP_STREAMING ) > 0 ) v4l_src_ctx->v4l2_ctx->method = IO_METHOD_MMAP;
+
+ CLEAR( v4l_src_ctx->v4l2_ctx->cropcap );
+ v4l_src_ctx->v4l2_ctx->cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (0 == ioctl( v4l_src_ctx->fd, VIDIOC_CROPCAP, &v4l_src_ctx->v4l2_ctx->cropcap ) ) {
+ v4l_src_ctx->v4l2_ctx->crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ v4l_src_ctx->v4l2_ctx->crop.c = v4l_src_ctx->v4l2_ctx->cropcap.defrect; /* reset to default */
+ if ( ioctl(v4l_src_ctx->fd, VIDIOC_S_CROP, &v4l_src_ctx->v4l2_ctx->crop) == -1 ) {
+ switch (errno) {
+ case EINVAL:
+ log_warn("Cropping not supported on %s\n", v4l_src_ctx->device_path);
+ break;
+ default:
+ /* Errors ignored. */
+ break;
+ }
+ }
+ } else {
+ /* Errors ignored. */
+ }
+
+ CLEAR( v4l_src_ctx->v4l2_ctx->fmt );
+ v4l_src_ctx->v4l2_ctx->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if( ioctl(v4l_src_ctx->fd, VIDIOC_G_FMT, &v4l_src_ctx->v4l2_ctx->fmt) == -1 )
+ {
+ log_warn("failed to get v4l2 picture format for %s\n", v4l_src_ctx->device_path);
+ ret = -1;
+ goto bail;
+ }
+
+ src_ctx->release = v4l2_source_release;
+ src_ctx->format_validate = v4l2_source_format_validate;
+ src_ctx->format_bind = v4l2_source_format_bind;
+ src_ctx->start_capture = v4l2_source_capture_start;
+ src_ctx->stop_capture = v4l2_source_capture_stop;
+
+bail:
+ return ret;
+}
+
+
+static unsigned int v4l2_read_frame( struct sapi_src_context* src_ctx )
+{
+ int ret = 0;
+ struct sapi_v4l_src_context * v4l_src_ctx =(struct sapi_v4l_src_context *)src_ctx->priv;
+ struct sapi_v4l2_backend_context* v4l2_ctx = v4l_src_ctx->v4l2_ctx;
+
+ switch( v4l2_ctx->method )
+ {
+ case IO_METHOD_READ:
+ case IO_METHOD_USERPTR:
+ ret = 0;
+ printf("Method not supported yet.\n");
+ break;
+
+ case IO_METHOD_MMAP:
+ CLEAR( v4l2_ctx->readBuffer );
+ v4l2_ctx->readBuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ v4l2_ctx->readBuffer.memory = V4L2_MEMORY_MMAP;
+
+ if (-1 == xioctl( v4l_src_ctx->fd, VIDIOC_DQBUF, &v4l2_ctx->readBuffer ) )
+ {
+ switch (errno) {
+ case EAGAIN:
+ return 0;
+ case EIO:
+ /* Could ignore EIO, see spec. */
+ /* fall through */
+ default:
+ log_error("Error while calling DQBUF. Msg was: %d, %s\n", errno, strerror( errno ) );
+ return -1;
+ }
+ }
+ assert( v4l2_ctx->readBuffer.index < v4l2_ctx->buffercnt );
+
+ sapi_src_capture_notify( src_ctx
+ , (char *)(v4l2_ctx->buffers[v4l2_ctx->readBuffer.index].data)
+ , v4l2_ctx->readBuffer.bytesused, 0, 0 );
+
+ ret = 1;
+
+ if (-1 == xioctl( v4l_src_ctx->fd, VIDIOC_QBUF, &v4l2_ctx->readBuffer)) {
+ errno_exit( "VIDIOC_QBUF" );
+ }
+
+ };
+ return ret;
+}
+
+
+static unsigned int v4l2_capture_thread_proc(void * data)
+{
+ struct sapi_src_context* src_ctx =(struct sapi_src_context *)data;
+ struct sapi_v4l_src_context* v4l_src_ctx =(struct sapi_v4l_src_context *)src_ctx->priv;
+
+ unsigned int started_frame_count = 0;
+ unsigned int capture_frame_count = 0;
+
+ while( v4l_src_ctx->capturing )
+ {
+ for( ;; )
+ {
+ fd_set fds;
+ struct timeval tv;
+ int r = 0;
+ FD_ZERO( &fds );
+ FD_SET( v4l_src_ctx->fd, &fds );
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+ r = select( v4l_src_ctx->fd +1, &fds, NULL, NULL, &tv );
+ if( r == -1) {
+ if( errno == EINTR )
+ continue;
+ errno_exit ("select");
+ }
+ if( r == 0 ) {
+ fprintf (stderr, "select timeout\n");
+ exit (EXIT_FAILURE);
+ }
+ if( v4l2_read_frame( src_ctx ) ) {
+ ++capture_frame_count;
+ break;
+ }
+ /* EAGAIN - continue select loop. */
+ }
+ }
+ return 0;
+}
Added: branches/v4l2_support/src/v4l/v4l_ctx.h
===================================================================
--- branches/v4l2_support/src/v4l/v4l_ctx.h (rev 0)
+++ branches/v4l2_support/src/v4l/v4l_ctx.h 2010-03-09 18:35:43 UTC (rev 107)
@@ -0,0 +1,59 @@
+#ifndef _V4L_CTX_H
+#define _V4L_CTX_H
+
+#include "conv.h"
+#include "hotlist.h"
+#include "logging.h"
+#include "sapi.h"
+
+/* fwd declarations;*/
+struct sapi_v4l1_backend_context* v4l1_ctx;
+struct sapi_v4l2_backend_context* v4l2_ctx;
+
+enum
+{
+ device_path_max = 128,
+ device_num_max = 16,
+ v4l_fps_mask = 0x003f0000,
+ v4l_fps_shift = 16,
+};
+
+
+struct sapi_v4l_context
+{
+ vc_mutex mutex;
+ vc_thread notify_thread;
+ unsigned int notify_thread_id;
+ int notifying;
+ struct sapi_src_list acquired_src_list;
+};
+
+
+struct sapi_v4l_src_context
+{
+ struct sapi_v4l_context * v4l_ctx;
+
+ struct sapi_v4l1_backend_context* v4l1_ctx;
+ struct sapi_v4l2_backend_context* v4l2_ctx;
+
+ int fd;
+ char device_path[device_path_max];
+ int channel;
+
+ int capturing;
+ vc_thread capture_thread;
+ unsigned int capture_thread_id;
+};
+
+
+int src_list_device_append( struct sapi_src_list * src_list
+ , const char * device_path, int channel
+ , const char * device_name, const char * channel_name );
+int common_source_release(struct sapi_src_context * src_ctx);
+int is_v4l2_device( int fd );
+int v4l1_source_acquire( struct sapi_src_context * src_ctx, struct sapi_v4l_src_context * v4l_src_ctx );
+int v4l2_source_acquire( struct sapi_src_context * src_ctx, struct sapi_v4l_src_context * v4l_src_ctx );
+int v4l1_src_list_device_scan(int fd, struct sapi_src_list * src_list, const char * device_path);
+int v4l2_src_list_device_scan(int fd, struct sapi_src_list * src_list, const char * device_path);
+
+#endif
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|