diff options
-rw-r--r-- | sys/v4l2/gstv4l2element.c | 55 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2element.h | 21 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2src.c | 56 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2src.h | 5 | ||||
-rw-r--r-- | sys/v4l2/v4l2-overlay_calls.c | 24 | ||||
-rw-r--r-- | sys/v4l2/v4l2_calls.c | 167 | ||||
-rw-r--r-- | sys/v4l2/v4l2_calls.h | 23 | ||||
-rw-r--r-- | sys/v4l2/v4l2src_calls.c | 78 | ||||
-rw-r--r-- | sys/v4l2/v4l2src_calls.h | 2 |
9 files changed, 274 insertions, 157 deletions
diff --git a/sys/v4l2/gstv4l2element.c b/sys/v4l2/gstv4l2element.c index 2c3a304d..edff15b1 100644 --- a/sys/v4l2/gstv4l2element.c +++ b/sys/v4l2/gstv4l2element.c @@ -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; } diff --git a/sys/v4l2/gstv4l2element.h b/sys/v4l2/gstv4l2element.h index b0e9fb7c..87ebaad9 100644 --- a/sys/v4l2/gstv4l2element.h +++ b/sys/v4l2/gstv4l2element.h @@ -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); }; diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c index 6ba0ea08..52a677d0 100644 --- a/sys/v4l2/gstv4l2src.c +++ b/sys/v4l2/gstv4l2src.c @@ -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)); diff --git a/sys/v4l2/gstv4l2src.h b/sys/v4l2/gstv4l2src.h index 004347ab..d287076b 100644 --- a/sys/v4l2/gstv4l2src.h +++ b/sys/v4l2/gstv4l2src.h @@ -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; diff --git a/sys/v4l2/v4l2-overlay_calls.c b/sys/v4l2/v4l2-overlay_calls.c index abf11858..ad3ec78a 100644 --- a/sys/v4l2/v4l2-overlay_calls.c +++ b/sys/v4l2/v4l2-overlay_calls.c @@ -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; - - if (ioctl(v4l2element->video_fd, VIDIOC_S_WIN, &vwin) < 0) { + 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_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)); diff --git a/sys/v4l2/v4l2_calls.c b/sys/v4l2/v4l2_calls.c index e09505c2..cb108416 100644 --- a/sys/v4l2/v4l2_calls.c +++ b/sys/v4l2/v4l2_calls.c @@ -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); diff --git a/sys/v4l2/v4l2_calls.h b/sys/v4l2/v4l2_calls.h index de0bbc9e..db9adc08 100644 --- a/sys/v4l2/v4l2_calls.h +++ b/sys/v4l2/v4l2_calls.h @@ -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, diff --git a/sys/v4l2/v4l2src_calls.c b/sys/v4l2/v4l2src_calls.c index 9215de17..a6f244fe 100644 --- a/sys/v4l2/v4l2src_calls.c +++ b/sys/v4l2/v4l2src_calls.c @@ -42,6 +42,62 @@ /****************************************************** + * 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 * return value: TRUE on success, FALSE on error @@ -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)); } diff --git a/sys/v4l2/v4l2src_calls.h b/sys/v4l2/v4l2src_calls.h index c9a108a7..436f65dc 100644 --- a/sys/v4l2/v4l2src_calls.h +++ b/sys/v4l2/v4l2src_calls.h @@ -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); |