v4l plugins: add open/close signals v4l2 plugins: add open/close signals move source format enumeration from v4l2elem...

Original commit message from CVS:
v4l plugins:
* add open/close signals

v4l2 plugins:
* add open/close signals
* move source format enumeration from v4l2element to v4l2src
* adapt to the final v4l2 API in kernel 2.5 (patches for 2.4 on http://bytesex.org/patches)
* small tweaks
This commit is contained in:
Ronald S. Bultje 2002-11-13 12:35:56 +00:00
parent 15e3ef0e55
commit 851ddec4d5
9 changed files with 273 additions and 156 deletions

View file

@ -37,6 +37,8 @@ static GstElementDetails gst_v4l2element_details = {
/* V4l2Element signals and args */
enum {
/* FILL ME */
SIGNAL_OPEN,
SIGNAL_CLOSE,
LAST_SIGNAL
};
@ -58,7 +60,7 @@ enum {
ARG_DEVICE_NAME,
ARG_DEVICE_HAS_CAPTURE,
ARG_DEVICE_HAS_OVERLAY,
ARG_DEVICE_HAS_CODEC,
ARG_DEVICE_HAS_PLAYBACK,
ARG_DISPLAY,
ARG_VIDEOWINDOW,
ARG_DO_OVERLAY,
@ -79,7 +81,7 @@ static GstElementStateReturn gst_v4l2element_change_state (GstElement *
static GstElementClass *parent_class = NULL;
/*static guint gst_v4l2element_signals[LAST_SIGNAL] = { 0 }; */
static guint gst_v4l2element_signals[LAST_SIGNAL] = { 0 };
GType
@ -168,12 +170,12 @@ gst_v4l2element_class_init (GstV4l2ElementClass *klass)
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_HAS_CAPTURE,
g_param_spec_boolean("can_capture","can_capture","can_capture",
0,G_PARAM_READABLE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_HAS_PLAYBACK,
g_param_spec_boolean("can_playback","can_playback","can_playback",
0,G_PARAM_READABLE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_HAS_OVERLAY,
g_param_spec_boolean("has_overlay","has_overlay","has_overlay",
0,G_PARAM_READABLE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_HAS_CODEC,
g_param_spec_boolean("has_compression","has_compression","has_compression",
0,G_PARAM_READABLE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DISPLAY,
g_param_spec_string("display","display","display",
@ -185,6 +187,18 @@ gst_v4l2element_class_init (GstV4l2ElementClass *klass)
g_param_spec_pointer("videowindow","videowindow","videowindow",
G_PARAM_WRITABLE));
/* signals */
gst_v4l2element_signals[SIGNAL_OPEN] =
g_signal_new("open", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(GstV4l2ElementClass, open),
NULL, NULL, g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1, G_TYPE_STRING);
gst_v4l2element_signals[SIGNAL_CLOSE] =
g_signal_new("close", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(GstV4l2ElementClass, close),
NULL, NULL, g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1, G_TYPE_STRING);
gobject_class->set_property = gst_v4l2element_set_property;
gobject_class->get_property = gst_v4l2element_get_property;
@ -206,7 +220,6 @@ gst_v4l2element_init (GstV4l2Element *v4l2element)
v4l2element->frequency = 0;
v4l2element->controls = NULL;
v4l2element->formats = NULL;
v4l2element->outputs = NULL;
v4l2element->inputs = NULL;
v4l2element->norms = NULL;
@ -277,7 +290,7 @@ gst_v4l2element_set_property (GObject *object,
GByteArray *array = (GByteArray *) g_value_get_pointer(value);
struct v4l2_clip *clips = (struct v4l2_clip *) array->data;
gst_v4l2_set_window(v4l2element,
clips->x, clips->y, clips->width, clips->height,
clips->c.left, clips->c.top, clips->c.width, clips->c.height,
&clips[1], array->len/sizeof(struct v4l2_clip)-1);
}
break;
@ -342,8 +355,8 @@ gst_v4l2element_get_property (GObject *object,
break;
case ARG_HAS_TUNER:
if (GST_V4L2_IS_OPEN(v4l2element))
temp_i = gst_v4l2_has_tuner(v4l2element);
g_value_set_boolean(value, temp_i>0?TRUE:FALSE);
g_value_set_boolean(value,
gst_v4l2_has_tuner(v4l2element, &temp_i));
break;
case ARG_FREQUENCY:
if (GST_V4L2_IS_OPEN(v4l2element))
@ -376,25 +389,25 @@ gst_v4l2element_get_property (GObject *object,
break;
case ARG_DEVICE_NAME:
if (GST_V4L2_IS_OPEN(v4l2element))
g_value_set_string(value, g_strdup(v4l2element->vcap.name));
g_value_set_string(value, g_strdup(v4l2element->vcap.card));
break;
case ARG_DEVICE_HAS_CAPTURE:
if (GST_V4L2_IS_OPEN(v4l2element) &&
(v4l2element->vcap.type == V4L2_TYPE_CODEC ||
v4l2element->vcap.type == V4L2_TYPE_CAPTURE) &&
v4l2element->vcap.flags & V4L2_FLAG_STREAMING)
v4l2element->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE &&
v4l2element->vcap.capabilities & V4L2_CAP_STREAMING)
temp_i = 1;
g_value_set_boolean(value, temp_i>0?TRUE:FALSE);
break;
case ARG_DEVICE_HAS_OVERLAY:
if (GST_V4L2_IS_OPEN(v4l2element) &&
v4l2element->vcap.flags & V4L2_FLAG_PREVIEW)
v4l2element->vcap.capabilities & V4L2_CAP_VIDEO_OVERLAY)
temp_i = 1;
g_value_set_boolean(value, temp_i>0?TRUE:FALSE);
break;
case ARG_DEVICE_HAS_CODEC:
case ARG_DEVICE_HAS_PLAYBACK:
if (GST_V4L2_IS_OPEN(v4l2element) &&
v4l2element->vcap.type == V4L2_TYPE_CODEC)
v4l2element->vcap.capabilities & V4L2_CAP_VIDEO_OUTPUT &&
v4l2element->vcap.capabilities & V4L2_CAP_STREAMING)
temp_i = 1;
g_value_set_boolean(value, temp_i>0?TRUE:FALSE);
break;
@ -422,6 +435,11 @@ gst_v4l2element_change_state (GstElement *element)
if (!gst_v4l2_open(v4l2element))
return GST_STATE_FAILURE;
/* emit a signal! whoopie! */
g_signal_emit(G_OBJECT(v4l2element),
gst_v4l2element_signals[SIGNAL_OPEN], 0,
v4l2element->device);
/* now, sync options */
if (v4l2element->norm >= 0)
if (!gst_v4l2_set_norm(v4l2element, v4l2element->norm))
@ -439,6 +457,11 @@ gst_v4l2element_change_state (GstElement *element)
case GST_STATE_READY_TO_NULL:
if (!gst_v4l2_close(v4l2element))
return GST_STATE_FAILURE;
/* emit yet another signal! wheehee! */
g_signal_emit(G_OBJECT(v4l2element),
gst_v4l2element_signals[SIGNAL_CLOSE], 0,
v4l2element->device);
break;
}

View file

@ -41,21 +41,17 @@
typedef struct _GstV4l2Element GstV4l2Element;
typedef struct _GstV4l2ElementClass GstV4l2ElementClass;
typedef struct _GstV4l2Rect {
gint x, y, w, h;
} GstV4l2Rect;
typedef enum {
GST_V4L2_ATTRIBUTE_VALUE_TYPE_INT,
GST_V4L2_ATTRIBUTE_VALUE_TYPE_BOOLEAN,
GST_V4L2_ATTRIBUTE_VALUE_TYPE_BUTTON,
GST_V4L2_ATTRIBUTE_VALUE_TYPE_LIST,
GST_V4L2_ATTRIBUTE_VALUE_TYPE_INTEGER = V4L2_CTRL_TYPE_INTEGER,
GST_V4L2_ATTRIBUTE_VALUE_TYPE_BOOLEAN = V4L2_CTRL_TYPE_BOOLEAN,
GST_V4L2_ATTRIBUTE_VALUE_TYPE_MENU = V4L2_CTRL_TYPE_MENU,
GST_V4L2_ATTRIBUTE_VALUE_TYPE_BUTTON = V4L2_CTRL_TYPE_BUTTON,
} GstV4l2AttributeValueType;
typedef enum {
GST_V4L2_ATTRIBUTE_TYPE_VIDEO,
GST_V4L2_ATTRIBUTE_TYPE_AUDIO,
GST_V4L2_ATTRIBUTE_TYPE_EFFECT,
GST_V4L2_ATTRIBUTE_TYPE_OTHER,
} GstV4l2AttributeType;
typedef struct _GstV4l2Attribute {
@ -83,7 +79,6 @@ struct _GstV4l2Element {
struct v4l2_capability vcap;
/* the toys available to us */
GList /*v4l2_fmtdesc*/ *formats; /* list of available capture formats */
GList /*v4l2_input*/ *inputs;
GList /*v4l2_output*/ *outputs;
GList /*v4l2_enumstd*/ *norms;
@ -99,6 +94,12 @@ struct _GstV4l2Element {
struct _GstV4l2ElementClass {
GstElementClass parent_class;
/* signals */
void (*open) (GstElement *element,
const gchar *device);
void (*close) (GstElement *element,
const gchar *device);
};

View file

@ -56,6 +56,12 @@ enum {
static void gst_v4l2src_class_init (GstV4l2SrcClass *klass);
static void gst_v4l2src_init (GstV4l2Src *v4l2src);
/* signal functions */
static void gst_v4l2src_open (GstElement *element,
const gchar *device);
static void gst_v4l2src_close (GstElement *element,
const gchar *device);
/* pad/buffer functions */
static gboolean gst_v4l2src_srcconvert (GstPad *pad,
GstFormat src_format,
@ -127,9 +133,11 @@ gst_v4l2src_class_init (GstV4l2SrcClass *klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstV4l2ElementClass *v4l2_class;
gobject_class = (GObjectClass*)klass;
gstelement_class = (GstElementClass*)klass;
v4l2_class = (GstV4l2ElementClass*)klass;
parent_class = g_type_class_ref(GST_TYPE_V4L2ELEMENT);
@ -164,6 +172,9 @@ gst_v4l2src_class_init (GstV4l2SrcClass *klass)
gobject_class->get_property = gst_v4l2src_get_property;
gstelement_class->change_state = gst_v4l2src_change_state;
v4l2_class->open = gst_v4l2src_open;
v4l2_class->close = gst_v4l2src_close;
}
@ -188,6 +199,24 @@ gst_v4l2src_init (GstV4l2Src *v4l2src)
v4l2src->width = 160;
v4l2src->height = 120;
v4l2src->breq.count = 0;
v4l2src->formats = NULL;
}
static void
gst_v4l2src_open (GstElement *element,
const gchar *device)
{
gst_v4l2src_fill_format_list(GST_V4L2SRC(element));
}
static void
gst_v4l2src_close (GstElement *element,
const gchar *device)
{
gst_v4l2src_empty_format_list(GST_V4L2SRC(element));
}
@ -211,8 +240,8 @@ gst_v4l2src_srcconvert (GstPad *pad,
if (!gst_v4l2_get_norm(GST_V4L2ELEMENT(v4l2src), &norm))
return FALSE;
std = &((struct v4l2_enumstd *) g_list_nth_data(GST_V4L2ELEMENT(v4l2src)->norms, norm))->std;
fps = std->framerate.numerator / std->framerate.denominator;
std = ((struct v4l2_standard *) g_list_nth_data(GST_V4L2ELEMENT(v4l2src)->norms, norm));
fps = std->frameperiod.numerator / std->frameperiod.denominator;
switch (src_format) {
case GST_FORMAT_TIME:
@ -453,8 +482,8 @@ gst_v4l2_caps_to_v4l2fourcc (GstV4l2Src *v4l2src,
break; }
}
for (i=0;i<g_list_length(GST_V4L2ELEMENT(v4l2src)->formats);i++) {
struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(GST_V4L2ELEMENT(v4l2src)->formats, i);
for (i=0;i<g_list_length(v4l2src->formats);i++) {
struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(v4l2src->formats, i);
if (fmt->pixelformat == fourcc)
fourcclist = g_list_append(fourcclist, (gpointer)fourcc);
}
@ -585,8 +614,8 @@ gst_v4l2src_srcconnect (GstPad *pad,
for (i=0;i<g_list_length(fourccs);i++) {
guint32 fourcc = (guint32)g_list_nth_data(fourccs, i);
gint n;
for (n=0;n<g_list_length(v4l2element->formats);n++) {
struct v4l2_fmtdesc *format = g_list_nth_data(v4l2element->formats, n);
for (n=0;n<g_list_length(v4l2src->formats);n++) {
struct v4l2_fmtdesc *format = g_list_nth_data(v4l2src->formats, n);
if (format->pixelformat == fourcc) {
/* we found the pixelformat! - try it out */
if (gst_v4l2src_set_capture(v4l2src, format,
@ -631,15 +660,15 @@ gst_v4l2src_getcaps (GstPad *pad,
/* build our own capslist */
if (v4l2src->palette) {
struct v4l2_fmtdesc *format = g_list_nth_data(v4l2element->formats, v4l2src->palette);
struct v4l2_fmtdesc *format = g_list_nth_data(v4l2src->formats, v4l2src->palette);
owncapslist = gst_v4l2src_v4l2fourcc_to_caps(format->pixelformat,
v4l2src->width, v4l2src->height,
format->flags & V4L2_FMT_FLAG_COMPRESSED);
} else {
gint i;
owncapslist = NULL;
for (i=0;i<g_list_length(v4l2element->formats);i++) {
struct v4l2_fmtdesc *format = g_list_nth_data(v4l2element->formats, i);
for (i=0;i<g_list_length(v4l2src->formats);i++) {
struct v4l2_fmtdesc *format = g_list_nth_data(v4l2src->formats, i);
caps = gst_v4l2src_v4l2fourcc_to_caps(format->pixelformat,
v4l2src->width, v4l2src->height,
format->flags & V4L2_FMT_FLAG_COMPRESSED);
@ -675,7 +704,8 @@ gst_v4l2src_get (GstPad *pad)
GST_BUFFER_DATA(buf) = GST_V4L2ELEMENT(v4l2src)->buffer[num];
GST_BUFFER_SIZE(buf) = v4l2src->bufsettings.bytesused;
if (!v4l2src->first_timestamp)
v4l2src->first_timestamp = v4l2src->bufsettings.timestamp;
v4l2src->first_timestamp = v4l2src->bufsettings.timestamp.tv_sec * GST_SECOND +
v4l2src->bufsettings.timestamp.tv_usec * (GST_SECOND/1000000);
GST_BUFFER_TIMESTAMP(buf) = v4l2src->bufsettings.length - v4l2src->first_timestamp;
return buf;
@ -717,8 +747,8 @@ gst_v4l2src_set_property (GObject *object,
gint i;
const gchar *formatstr = g_value_get_string(value);
guint32 fourcc = GST_MAKE_FOURCC(formatstr[0],formatstr[1],formatstr[2],formatstr[3]);
for (i=0;i<g_list_length(GST_V4L2ELEMENT(v4l2src)->formats);i++) {
struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(GST_V4L2ELEMENT(v4l2src)->formats, i);
for (i=0;i<g_list_length(v4l2src->formats);i++) {
struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(v4l2src->formats, i);
if (fmt->pixelformat == fourcc)
v4l2src->palette = i;
}
@ -767,7 +797,7 @@ gst_v4l2src_get_property (GObject *object,
break;
case ARG_FOURCC: {
struct v4l2_fmtdesc *fmt = g_list_nth_data(GST_V4L2ELEMENT(v4l2src)->formats, v4l2src->palette);
struct v4l2_fmtdesc *fmt = g_list_nth_data(v4l2src->formats, v4l2src->palette);
guint32 print_format = GUINT32_FROM_LE(fmt->pixelformat);
gchar *print_format_str = (gchar *) &print_format;
g_value_set_string(value, g_strndup(print_format_str, 4));

View file

@ -44,11 +44,14 @@ struct _GstV4l2Src {
/* pads */
GstPad *srcpad;
/* internal lists */
GList /*v4l2_fmtdesc*/ *formats; /* list of available capture formats */
/* buffer properties */
struct v4l2_buffer bufsettings;
struct v4l2_requestbuffers breq;
struct v4l2_format format;
stamp_t first_timestamp;
guint64 first_timestamp;
/* bufferpool for the buffers we're gonna use */
GstBufferPool *bufferpool;

View file

@ -89,21 +89,23 @@ gst_v4l2_set_window (GstV4l2Element *v4l2element,
struct v4l2_clip *clips,
gint num_clips)
{
struct v4l2_window vwin;
struct v4l2_format fmt;
DEBUG("trying to set video window to %dx%d,%d,%d", x,y,w,h);
GST_V4L2_CHECK_OVERLAY(v4l2element);
GST_V4L2_CHECK_OPEN(v4l2element);
vwin.clipcount = 0;
vwin.x = x;
vwin.y = y;
vwin.width = w;
vwin.height = h;
vwin.clips = clips;
vwin.clipcount = num_clips;
fmt.type = V4L2_CAP_VIDEO_OVERLAY;
fmt.fmt.win.clipcount = 0;
fmt.fmt.win.w.left = x;
fmt.fmt.win.w.top = y;
fmt.fmt.win.w.width = w;
fmt.fmt.win.w.height = h;
fmt.fmt.win.clips = clips;
fmt.fmt.win.clipcount = num_clips;
fmt.fmt.win.bitmap = NULL;
if (ioctl(v4l2element->video_fd, VIDIOC_S_WIN, &vwin) < 0) {
if (ioctl(v4l2element->video_fd, VIDIOC_S_FMT, &fmt) < 0) {
gst_element_error(GST_ELEMENT(v4l2element),
"Failed to set the video window on device %s: %s",
v4l2element->device, g_strerror(errno));
@ -130,7 +132,7 @@ gst_v4l2_enable_overlay (GstV4l2Element *v4l2element,
GST_V4L2_CHECK_OPEN(v4l2element);
GST_V4L2_CHECK_OVERLAY(v4l2element);
if (ioctl(v4l2element->video_fd, VIDIOC_PREVIEW, &doit) < 0) {
if (ioctl(v4l2element->video_fd, VIDIOC_OVERLAY, &doit) < 0) {
gst_element_error(GST_ELEMENT(v4l2element),
"Failed to %s overlay display for device %s: %s",
enable?"enable":"disable", v4l2element->device, g_strerror(errno));

View file

@ -73,25 +73,6 @@ gst_v4l2_fill_lists (GstV4l2Element *v4l2element)
DEBUG("getting enumerations");
GST_V4L2_CHECK_OPEN(v4l2element);
/* create enumeration lists - let's start with format enumeration */
for (n=0;;n++) {
struct v4l2_fmtdesc format, *fmtptr;
format.index = n;
if (ioctl(v4l2element->video_fd, VIDIOC_ENUM_PIXFMT, &format) < 0) {
if (errno == EINVAL)
break; /* end of enumeration */
else {
gst_element_error(GST_ELEMENT(v4l2element),
"Failed to get no. %d in pixelformat enumeration for %s: %s",
n, v4l2element->device, g_strerror(errno));
return FALSE;
}
}
fmtptr = g_malloc(sizeof(format));
memcpy(fmtptr, &format, sizeof(format));
v4l2element->formats = g_list_append(v4l2element->formats, fmtptr);
}
/* and now, the inputs */
for (n=0;;n++) {
struct v4l2_input input, *inpptr;
@ -132,7 +113,7 @@ gst_v4l2_fill_lists (GstV4l2Element *v4l2element)
/* norms... */
for (n=0;;n++) {
struct v4l2_enumstd standard, *stdptr;
struct v4l2_standard standard, *stdptr;
standard.index = n;
if (ioctl(v4l2element->video_fd, VIDIOC_ENUMSTD, &standard) < 0) {
if (errno == EINVAL)
@ -150,20 +131,28 @@ gst_v4l2_fill_lists (GstV4l2Element *v4l2element)
}
/* and lastly, controls+menus (if appropriate) */
for (n=0;;n++) {
for (n=V4L2_CID_BASE;;n++) {
struct v4l2_queryctrl control, *ctrlptr;
GList *menus = NULL;
/* hacky... */
if (n == V4L2_CID_LASTP1)
n = V4L2_CID_PRIVATE_BASE;
control.id = n;
if (ioctl(v4l2element->video_fd, VIDIOC_QUERYCTRL, &control) < 0) {
if (errno == EINVAL)
break; /* end of enumeration */
else {
if (errno == EINVAL) {
if (n < V4L2_CID_PRIVATE_BASE)
continue;
else
break;
} else {
gst_element_error(GST_ELEMENT(v4l2element),
"Failed to get no. %d in control enumeration for %s: %s",
n, v4l2element->device, g_strerror(errno));
return FALSE;
}
}
if (control.flags & V4L2_CTRL_FLAG_DISABLED)
continue;
ctrlptr = g_malloc(sizeof(control));
memcpy(ctrlptr, &control, sizeof(control));
v4l2element->controls = g_list_append(v4l2element->controls, ctrlptr);
@ -216,11 +205,6 @@ gst_v4l2_empty_lists (GstV4l2Element *v4l2element)
v4l2element->norms = g_list_remove(v4l2element->norms, data);
g_free(data);
}
while (g_list_length(v4l2element->formats) > 0) {
gpointer data = g_list_nth_data(v4l2element->formats, 0);
v4l2element->formats = g_list_remove(v4l2element->formats, data);
g_free(data);
}
while (g_list_length(v4l2element->controls) > 0) {
gpointer data = g_list_nth_data(v4l2element->controls, 0);
v4l2element->controls = g_list_remove(v4l2element->controls, data);
@ -275,7 +259,7 @@ gst_v4l2_open (GstV4l2Element *v4l2element)
goto error;
gst_info("Opened device '%s' (%s) successfully\n",
v4l2element->vcap.name, v4l2element->device);
v4l2element->vcap.card, v4l2element->device);
return TRUE;
@ -326,13 +310,13 @@ gboolean
gst_v4l2_get_norm (GstV4l2Element *v4l2element,
gint *norm)
{
struct v4l2_standard standard;
v4l2_std_id std_id;
gint n;
DEBUG("getting norm");
GST_V4L2_CHECK_OPEN(v4l2element);
if (ioctl(v4l2element->video_fd, VIDIOC_G_STD, &standard) < 0) {
if (ioctl(v4l2element->video_fd, VIDIOC_G_STD, &std_id) < 0) {
gst_element_error(GST_ELEMENT(v4l2element),
"Failed to get the current norm for device %s: %s",
v4l2element->device, g_strerror(errno));
@ -341,16 +325,16 @@ gst_v4l2_get_norm (GstV4l2Element *v4l2element,
/* try to find out what norm number this actually is */
for (n=0;n<g_list_length(v4l2element->norms);n++) {
struct v4l2_enumstd *stdptr = (struct v4l2_enumstd *) g_list_nth_data(v4l2element->norms, n);
if (!strcmp(stdptr->std.name, standard.name)) {
struct v4l2_standard *stdptr = (struct v4l2_standard *) g_list_nth_data(v4l2element->norms, n);
if (stdptr->id == std_id) {
*norm = n;
return TRUE;
}
}
gst_element_error(GST_ELEMENT(v4l2element),
"Failed to find norm '%s' in our list of available norms for device %s",
standard.name, v4l2element->device);
"Failed to find norm '%llu' in our list of available norms for device %s",
std_id, v4l2element->device);
return FALSE;
}
@ -365,7 +349,7 @@ gboolean
gst_v4l2_set_norm (GstV4l2Element *v4l2element,
gint norm)
{
struct v4l2_enumstd *standard;
struct v4l2_standard *standard;
DEBUG("trying to set norm to %d", norm);
GST_V4L2_CHECK_OPEN(v4l2element);
@ -378,12 +362,12 @@ gst_v4l2_set_norm (GstV4l2Element *v4l2element,
return FALSE;
}
standard = (struct v4l2_enumstd *) g_list_nth_data(v4l2element->norms, norm);
standard = (struct v4l2_standard *) g_list_nth_data(v4l2element->norms, norm);
if (ioctl(v4l2element->video_fd, VIDIOC_S_STD, &standard->std) < 0) {
if (ioctl(v4l2element->video_fd, VIDIOC_S_STD, &standard->id) < 0) {
gst_element_error(GST_ELEMENT(v4l2element),
"Failed to set norm '%s' (%d) for device %s: %s",
standard->std.name, norm, v4l2element->device, g_strerror(errno));
"Failed to set norm '%s' (%llu) for device %s: %s",
standard->name, standard->id, v4l2element->device, g_strerror(errno));
return FALSE;
}
@ -406,8 +390,8 @@ gst_v4l2_get_norm_names (GstV4l2Element *v4l2element)
DEBUG("getting a list of norm names");
for (n=0;n<g_list_length(v4l2element->norms);n++) {
struct v4l2_enumstd *standard = (struct v4l2_enumstd *) g_list_nth_data(v4l2element->norms, n);
names = g_list_append(names, g_strdup(standard->std.name));
struct v4l2_standard *standard = (struct v4l2_standard *) g_list_nth_data(v4l2element->norms, n);
names = g_list_append(names, g_strdup(standard->name));
}
return names;
@ -586,8 +570,9 @@ gst_v4l2_get_output_names (GstV4l2Element *v4l2element)
* return value: TRUE if it has a tuner, else FALSE
******************************************************/
gboolean
gst_v4l2_has_tuner (GstV4l2Element *v4l2element)
gint
gst_v4l2_has_tuner (GstV4l2Element *v4l2element,
gint *tuner_num)
{
gint input_num;
struct v4l2_input *input;
@ -600,8 +585,12 @@ gst_v4l2_has_tuner (GstV4l2Element *v4l2element)
input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num);
return (input->type == V4L2_INPUT_TYPE_TUNER &&
v4l2element->vcap.flags & V4L2_FLAG_TUNER);
if (input->type == V4L2_INPUT_TYPE_TUNER &&
v4l2element->vcap.capabilities & V4L2_CAP_TUNER) {
*tuner_num = input->tuner;
return TRUE;
}
return FALSE;
}
@ -615,22 +604,24 @@ gboolean
gst_v4l2_get_frequency (GstV4l2Element *v4l2element,
gulong *frequency)
{
gint n;
struct v4l2_frequency freq;
DEBUG("getting current tuner frequency");
GST_V4L2_CHECK_OPEN(v4l2element);
if (!gst_v4l2_has_tuner(v4l2element))
if (!gst_v4l2_has_tuner(v4l2element, &freq.tuner))
return FALSE;
if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQ, &n) < 0) {
freq.type = 0;
if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0) {
gst_element_error(GST_ELEMENT(v4l2element),
"Failed to get current tuner frequency for device %s: %s",
v4l2element->device, g_strerror(errno));
return FALSE;
}
*frequency = n;
*frequency = freq.frequency;
return TRUE;
}
@ -646,16 +637,19 @@ gboolean
gst_v4l2_set_frequency (GstV4l2Element *v4l2element,
gulong frequency)
{
gint n = frequency;
struct v4l2_frequency freq;
DEBUG("setting current tuner frequency to %lu", frequency);
GST_V4L2_CHECK_OPEN(v4l2element);
GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
if (!gst_v4l2_has_tuner(v4l2element))
if (!gst_v4l2_has_tuner(v4l2element, &freq.tuner))
return FALSE;
if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQ, &n) < 0) {
freq.frequency = frequency;
freq.type = 0;
if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0) {
gst_element_error(GST_ELEMENT(v4l2element),
"Failed to set tuner frequency to %lu for device %s: %s",
frequency, v4l2element->device, g_strerror(errno));
@ -683,7 +677,7 @@ gst_v4l2_signal_strength (GstV4l2Element *v4l2element,
if (ioctl(v4l2element->video_fd, VIDIOC_G_TUNER, &tuner) < 0) {
gst_element_error(GST_ELEMENT(v4l2element),
"Failed to set signal strength for device %s: %s",
"Failed to get signal strength for device %s: %s",
v4l2element->device, g_strerror(errno));
return FALSE;
}
@ -714,7 +708,7 @@ gst_v4l2_has_audio (GstV4l2Element *v4l2element)
input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num);
return (input->capability & V4L2_INPUT_CAP_AUDIO);
return (input->audioset != 0);
}
@ -738,36 +732,47 @@ gst_v4l2_get_attributes (GstV4l2Element *v4l2element)
attribute->name = g_strdup(control->name);
attribute->index = i;
attribute->list_items = NULL;
switch (control->type) {
case V4L2_CTRL_TYPE_INTEGER:
attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_INT;
break;
case V4L2_CTRL_TYPE_BOOLEAN:
attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_BOOLEAN;
break;
case V4L2_CTRL_TYPE_MENU: {
/* list items */
gint n;
GList *menus = (GList *) g_list_nth_data(v4l2element->menus, i);
for (n=0;n<g_list_length(menus);n++) {
struct v4l2_querymenu *menu = g_list_nth_data(menus, n);
attribute->list_items = g_list_append(attribute->list_items, g_strdup(menu->name));
}
attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_LIST;
break; }
case V4L2_CTRL_TYPE_BUTTON:
attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_BUTTON;
break;
attribute->val_type = control->type;
if (control->type == V4L2_CTRL_TYPE_MENU) {
/* list items */
gint n;
GList *menus = (GList *) g_list_nth_data(v4l2element->menus, i);
for (n=0;n<g_list_length(menus);n++) {
struct v4l2_querymenu *menu = g_list_nth_data(menus, n);
attribute->list_items = g_list_append(attribute->list_items,
g_strdup(menu->name));
}
}
switch (control->category) {
case V4L2_CTRL_CAT_VIDEO:
switch (control->id) {
case V4L2_CID_BRIGHTNESS:
case V4L2_CID_CONTRAST:
case V4L2_CID_SATURATION:
case V4L2_CID_HUE:
case V4L2_CID_BLACK_LEVEL:
case V4L2_CID_AUTO_WHITE_BALANCE:
case V4L2_CID_DO_WHITE_BALANCE:
case V4L2_CID_RED_BALANCE:
case V4L2_CID_BLUE_BALANCE:
case V4L2_CID_GAMMA:
case V4L2_CID_EXPOSURE:
case V4L2_CID_AUTOGAIN:
case V4L2_CID_GAIN:
case V4L2_CID_HFLIP:
case V4L2_CID_VFLIP:
case V4L2_CID_HCENTER:
case V4L2_CID_VCENTER:
attribute->type = GST_V4L2_ATTRIBUTE_TYPE_VIDEO;
break;
case V4L2_CTRL_CAT_AUDIO:
case V4L2_CID_AUDIO_VOLUME:
case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_BASS:
case V4L2_CID_AUDIO_TREBLE:
case V4L2_CID_AUDIO_MUTE:
case V4L2_CID_AUDIO_LOUDNESS:
attribute->type = GST_V4L2_ATTRIBUTE_TYPE_AUDIO;
break;
case V4L2_CTRL_CAT_EFFECT:
attribute->type = GST_V4L2_ATTRIBUTE_TYPE_EFFECT;
default:
attribute->type = GST_V4L2_ATTRIBUTE_TYPE_OTHER;
break;
}
gst_v4l2_get_attribute(v4l2element, i, &attribute->value);

View file

@ -32,11 +32,11 @@
(v4l2element->buffer != NULL)
#define GST_V4L2_IS_OVERLAY(v4l2element) \
(v4l2element->vcap.flags & V4L2_FLAG_PREVIEW)
(v4l2element->vcap.capabilities & V4L2_CAP_VIDEO_OVERLAY)
/* checks whether the current v4lelement has already been open()'ed or not */
#define GST_V4L2_CHECK_OPEN(v4l2element) \
if (v4l2element->video_fd <= 0) \
if (!GST_V4L2_IS_OPEN(v4l2element)) \
{ \
gst_element_error(GST_ELEMENT(v4l2element), \
"Device is not open"); \
@ -45,7 +45,7 @@
/* checks whether the current v4lelement is close()'ed or whether it is still open */
#define GST_V4L2_CHECK_NOT_OPEN(v4l2element) \
if (v4l2element->video_fd != -1) \
if (GST_V4L2_IS_OPEN(v4l2element)) \
{ \
gst_element_error(GST_ELEMENT(v4l2element), \
"Device is open"); \
@ -54,16 +54,16 @@
/* checks whether the current v4lelement does video overlay */
#define GST_V4L2_CHECK_OVERLAY(v4l2element) \
if (!(v4l2element->vcap.flags & V4L2_FLAG_PREVIEW)) \
{ \
gst_element_error(GST_ELEMENT(v4l2element), \
"Device doesn't do overlay"); \
return FALSE; \
if (!GST_V4L2_IS_OVERLAY(v4l2element)) \
{ \
gst_element_error(GST_ELEMENT(v4l2element), \
"Device doesn't do overlay"); \
return FALSE; \
}
/* checks whether we're in capture mode or not */
#define GST_V4L2_CHECK_ACTIVE(v4l2element) \
if (v4l2element->buffer == NULL) \
if (!GST_V4L2_IS_ACTIVE(v4l2element)) \
{ \
gst_element_error(GST_ELEMENT(v4l2element), \
"Device is not in streaming mode"); \
@ -72,7 +72,7 @@
/* checks whether we're out of capture mode or not */
#define GST_V4L2_CHECK_NOT_ACTIVE(v4l2element) \
if (v4l2element->buffer != NULL) \
if (GST_V4L2_IS_ACTIVE(v4l2element)) \
{ \
gst_element_error(GST_ELEMENT(v4l2element), \
"Device is in streaming mode"); \
@ -102,7 +102,8 @@ gboolean gst_v4l2_set_output (GstV4l2Element *v4l2element,
GList * gst_v4l2_get_output_names (GstV4l2Element *v4l2element);
/* frequency control */
gboolean gst_v4l2_has_tuner (GstV4l2Element *v4l2element);
gboolean gst_v4l2_has_tuner (GstV4l2Element *v4l2element,
gint *tuner_num);
gboolean gst_v4l2_get_frequency (GstV4l2Element *v4l2element,
gulong *frequency);
gboolean gst_v4l2_set_frequency (GstV4l2Element *v4l2element,

View file

@ -41,6 +41,62 @@
#endif
/******************************************************
* gst_v4l2src_fill_format_list():
* create list of supported capture formats
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2src_fill_format_list (GstV4l2Src *v4l2src)
{
gint n;
DEBUG("getting src format enumerations");
/* format enumeration */
for (n=0;;n++) {
struct v4l2_fmtdesc format, *fmtptr;
format.index = n;
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(GST_V4L2ELEMENT(v4l2src)->video_fd, VIDIOC_ENUM_FMT, &format) < 0) {
if (errno == EINVAL)
break; /* end of enumeration */
else {
gst_element_error(GST_ELEMENT(v4l2src),
"Failed to get no. %d in pixelformat enumeration for %s: %s",
n, GST_V4L2ELEMENT(v4l2src)->device, g_strerror(errno));
return FALSE;
}
}
fmtptr = g_malloc(sizeof(format));
memcpy(fmtptr, &format, sizeof(format));
v4l2src->formats = g_list_append(v4l2src->formats, fmtptr);
}
return TRUE;
}
/******************************************************
* gst_v4l2src_empty_format_list():
* free list of supported capture formats
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2src_empty_format_list (GstV4l2Src *v4l2src)
{
while (g_list_length(v4l2src->formats) > 0) {
gpointer data = g_list_nth_data(v4l2src->formats, 0);
v4l2src->formats = g_list_remove(v4l2src->formats, data);
g_free(data);
}
return TRUE;
}
/******************************************************
* gst_v4l2src_queue_frame():
* queue a frame for capturing
@ -101,6 +157,7 @@ gst_v4l2src_get_capture (GstV4l2Src *v4l2src)
GST_V4L2_CHECK_OPEN(GST_V4L2ELEMENT(v4l2src));
v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(GST_V4L2ELEMENT(v4l2src)->video_fd, VIDIOC_G_FMT, &v4l2src->format) < 0) {
gst_element_error(GST_ELEMENT(v4l2src),
"Failed to get pixel format for device %s: %s",
@ -134,12 +191,7 @@ gst_v4l2src_set_capture (GstV4l2Src *v4l2src,
v4l2src->format.fmt.pix.width = width;
v4l2src->format.fmt.pix.height = height;
v4l2src->format.fmt.pix.pixelformat = fmt->pixelformat;
if (fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
v4l2src->format.fmt.pix.flags = V4L2_FMT_FLAG_COMPRESSED;
v4l2src->format.type = V4L2_BUF_TYPE_CODECIN;
} else {
v4l2src->format.type = V4L2_BUF_TYPE_CAPTURE;
}
v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(GST_V4L2ELEMENT(v4l2src)->video_fd, VIDIOC_S_FMT, &v4l2src->format) < 0) {
gst_element_error(GST_ELEMENT(v4l2src),
@ -189,8 +241,8 @@ gst_v4l2src_capture_init (GstV4l2Src *v4l2src)
}
v4l2src->bufsettings.type = v4l2src->format.type;
for (n=0;n<g_list_length(GST_V4L2ELEMENT(v4l2src)->formats);n++) {
struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(GST_V4L2ELEMENT(v4l2src)->formats, n);
for (n=0;n<g_list_length(v4l2src->formats);n++) {
struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(v4l2src->formats, n);
if (v4l2src->format.fmt.pix.pixelformat == fmt->pixelformat) {
desc = fmt->description;
break;
@ -359,11 +411,10 @@ GList *
gst_v4l2src_get_fourcc_list (GstV4l2Src *v4l2src)
{
GList *list = NULL;
GstV4l2Element *v4l2element = GST_V4L2ELEMENT(v4l2src);
gint n;
for (n=0;n<g_list_length(v4l2element->formats);n++) {
struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(v4l2element->formats, n);
for (n=0;n<g_list_length(v4l2src->formats);n++) {
struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(v4l2src->formats, n);
guint32 print_format = GUINT32_FROM_LE(fmt->pixelformat);
gchar *print_format_str = (gchar *) &print_format;
@ -384,11 +435,10 @@ GList *
gst_v4l2src_get_format_list (GstV4l2Src *v4l2src)
{
GList *list = NULL;
GstV4l2Element *v4l2element = GST_V4L2ELEMENT(v4l2src);
gint n;
for (n=0;n<g_list_length(v4l2element->formats);n++) {
struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(v4l2element->formats, n);
for (n=0;n<g_list_length(v4l2src->formats);n++) {
struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(v4l2src->formats, n);
list = g_list_append(list, g_strdup(fmt->description));
}

View file

@ -38,6 +38,8 @@ gboolean gst_v4l2src_requeue_frame (GstV4l2Src *v4l2src,
gboolean gst_v4l2src_capture_stop (GstV4l2Src *v4l2src);
gboolean gst_v4l2src_capture_deinit (GstV4l2Src *v4l2src);
gboolean gst_v4l2src_fill_format_list (GstV4l2Src *v4l2src);
gboolean gst_v4l2src_empty_format_list (GstV4l2Src *v4l2src);
GList * gst_v4l2src_get_fourcc_list (GstV4l2Src *v4l2src);
GList * gst_v4l2src_get_format_list (GstV4l2Src *v4l2src);