diff --git a/ChangeLog b/ChangeLog index 53d50c20a7..9e1e2da743 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2006-05-05 Edgard Lima + + * sys/v4l2/gstv4l2element.c: + * sys/v4l2/gstv4l2element.h: + * sys/v4l2/gstv4l2src.c: + * sys/v4l2/gstv4l2src.h: + * sys/v4l2/gstv4l2tuner.c: + * sys/v4l2/gstv4l2tuner.h: + * sys/v4l2/v4l2_calls.c: + * sys/v4l2/v4l2_calls.h: + * sys/v4l2/v4l2src_calls.c: + * sys/v4l2/v4l2src_calls.h: + * tests/icles/v4l2src-test.c: + Some changes proposed by wingo in bug #338818 (but not everything + yet). Patch from Martin Rubli to fix framerate detection. + 2006-05-05 Tim-Philipp Müller * ext/sdl/sdlaudiosink.c: (gst_sdlaudio_sink_prepare): diff --git a/sys/v4l2/gstv4l2element.c b/sys/v4l2/gstv4l2element.c index d6f14d473f..5bbc260ee8 100644 --- a/sys/v4l2/gstv4l2element.c +++ b/sys/v4l2/gstv4l2element.c @@ -1,10 +1,11 @@ /* - * GStreamer gstv4l2element.c: base class for V4L2 elements Copyright - * (C) 2001-2002 Ronald Bultje This library - * is free software; you can redistribute it and/or modify it under the - * terms of the GNU Library General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. This library is distributed in the hope + * GStreamer gstv4l2element.c: base class for V4L2 elements + * Copyright (C) 2001-2002 Ronald Bultje + * Copyright (C) 2006 Edgard Lima + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. This library is distributed in the hope * that it will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Library General Public License for more details. @@ -49,19 +50,19 @@ enum static void gst_v4l2element_init_interfaces (GType type); GST_BOILERPLATE_FULL (GstV4l2Element, gst_v4l2element, GstPushSrc, - GST_TYPE_PUSH_SRC, gst_v4l2element_init_interfaces) - static void gst_v4l2element_dispose (GObject * object); - static void gst_v4l2element_set_property (GObject * object, + GST_TYPE_PUSH_SRC, gst_v4l2element_init_interfaces); + +static void gst_v4l2element_dispose (GObject * object); +static void gst_v4l2element_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); - static void gst_v4l2element_get_property (GObject * object, +static void gst_v4l2element_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); - static gboolean gst_v4l2element_start (GstBaseSrc * src); - static gboolean gst_v4l2element_stop (GstBaseSrc * src); +static gboolean gst_v4l2element_start (GstBaseSrc * src); +static gboolean gst_v4l2element_stop (GstBaseSrc * src); - static gboolean - gst_v4l2_iface_supported (GstImplementsInterface * iface, - GType iface_type) +static gboolean +gst_v4l2_iface_supported (GstImplementsInterface * iface, GType iface_type) { GstV4l2Element *v4l2element = GST_V4L2ELEMENT (iface); @@ -99,10 +100,16 @@ gst_v4l2_probe_get_properties (GstPropertyProbe * probe) GObjectClass *klass = G_OBJECT_GET_CLASS (probe); static GList *list = NULL; + /* well, not perfect, but better than no locking at all. + * In the worst case we leak a list node, so who cares? */ + GST_CLASS_LOCK (GST_OBJECT_CLASS (klass)); + if (!list) { list = g_list_append (NULL, g_object_class_find_property (klass, "device")); } + GST_CLASS_UNLOCK (GST_OBJECT_CLASS (klass)); + return list; } @@ -435,12 +442,13 @@ gst_v4l2element_set_property (GObject * object, g_value_get_string (value)); if (norm) { - gst_tuner_set_norm (tuner, norm); + /* more generic would be gst_tuner_set_norm (tuner, norm) + without g_object_notify */ + gst_v4l2_tuner_set_norm (tuner, norm); } } else { g_free (v4l2element->std); v4l2element->std = g_value_dup_string (value); - g_object_notify (object, "std"); } break; case PROP_INPUT: @@ -451,12 +459,13 @@ gst_v4l2element_set_property (GObject * object, g_value_get_string (value)); if (channel) { - gst_tuner_set_channel (tuner, channel); + /* more generic would be gst_tuner_set_channel (tuner, channel) + without g_object_notify */ + gst_v4l2_tuner_set_channel (tuner, channel); } } else { g_free (v4l2element->input); v4l2element->input = g_value_dup_string (value); - g_object_notify (object, "input"); } break; case PROP_FREQUENCY: @@ -466,11 +475,14 @@ gst_v4l2element_set_property (GObject * object, if (channel && GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { - gst_tuner_set_frequency (tuner, channel, g_value_get_ulong (value)); + /* more generic would be + gst_tuner_set_frequency (tuner, channel, g_value_get_ulong (value)) + without g_object_notify */ + gst_v4l2_tuner_set_frequency (tuner, channel, + g_value_get_ulong (value)); } } else { v4l2element->frequency = g_value_get_ulong (value); - g_object_notify (object, "frequency"); } break; default: diff --git a/sys/v4l2/gstv4l2element.h b/sys/v4l2/gstv4l2element.h index 742950a788..b866769577 100644 --- a/sys/v4l2/gstv4l2element.h +++ b/sys/v4l2/gstv4l2element.h @@ -3,6 +3,7 @@ * gstv4l2element.h: base class for V4L2 elements * * Copyright (C) 2001-2002 Ronald Bultje + * Copyright (C) 2006 Edgard Lima * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c index 126cd42171..09767ea602 100644 --- a/sys/v4l2/gstv4l2src.c +++ b/sys/v4l2/gstv4l2src.c @@ -3,6 +3,7 @@ * gstv4l2src.c: BT8x8/V4L2 source element * * Copyright (C) 2001-2002 Ronald Bultje + * Copyright (C) 2006 Edgard Lima * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -207,6 +208,8 @@ gst_v4l2src_init (GstV4l2Src * v4l2src, GstV4l2SrcClass * klass) v4l2src->formats = NULL; /* fps */ + v4l2src->fps_n = 0; + v4l2src->fps_d = 1; v4l2src->use_fixed_fps = TRUE; v4l2src->is_capturing = FALSE; @@ -631,8 +634,7 @@ gst_v4l2src_get_caps (GstBaseSrc * src) int min_w, max_w, min_h, max_h; GSList *walk; GstStructure *structure; - gint fps_n, fps_d; - + guint fps_n, fps_d; if (!GST_V4L2_IS_OPEN (GST_V4L2ELEMENT (v4l2src))) { return @@ -647,6 +649,7 @@ gst_v4l2src_get_caps (GstBaseSrc * src) caps = gst_caps_new_empty (); walk = v4l2src->formats; if (!gst_v4l2src_get_fps (v4l2src, &fps_n, &fps_d)) { + GST_DEBUG_OBJECT (v4l2src, "frame rate is unknown."); fps_n = 0; fps_d = 1; } @@ -857,10 +860,8 @@ gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf) { GstV4l2Src *v4l2src = GST_V4L2SRC (src); GstFlowReturn ret; - gint fps_n, fps_d; - if (v4l2src->use_fixed_fps - && gst_v4l2src_get_fps (v4l2src, &fps_n, &fps_d) == 0) { + if (v4l2src->use_fixed_fps && v4l2src->fps_n == 0) { GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, (NULL), ("could not get frame rate for element")); return GST_FLOW_ERROR; diff --git a/sys/v4l2/gstv4l2src.h b/sys/v4l2/gstv4l2src.h index 3b3f96a660..58815ddd32 100644 --- a/sys/v4l2/gstv4l2src.h +++ b/sys/v4l2/gstv4l2src.h @@ -3,6 +3,7 @@ * gstv4l2src.h: BT8x8/V4L2 video source element * * Copyright (C) 2001-2002 Ronald Bultje + * Copyright (C) 2006 Edgard Lima * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -97,6 +98,7 @@ struct _GstV4l2Src gint offset; /* how are we going to push buffers? */ + guint fps_n, fps_d; gboolean use_fixed_fps; }; diff --git a/sys/v4l2/gstv4l2tuner.c b/sys/v4l2/gstv4l2tuner.c index 7910835aa7..ff813b5e5c 100644 --- a/sys/v4l2/gstv4l2tuner.c +++ b/sys/v4l2/gstv4l2tuner.c @@ -1,5 +1,6 @@ /* GStreamer Tuner interface implementation * Copyright (C) 2003 Ronald Bultje + * Copyright (C) 2006 Edgard Lima * * gstv4l2tuner.c: tuner interface implementation for V4L2 * @@ -28,6 +29,9 @@ #include "gstv4l2tuner.h" #include "gstv4l2element.h" #include "v4l2_calls.h" +#include "v4l2src_calls.h" + +#include static void gst_v4l2_tuner_channel_class_init (GstV4l2TunerChannelClass * klass); @@ -37,21 +41,35 @@ static void gst_v4l2_tuner_norm_class_init (GstV4l2TunerNormClass * klass); static void gst_v4l2_tuner_norm_init (GstV4l2TunerNorm * norm); static const GList *gst_v4l2_tuner_list_channels (GstTuner * mixer); -static void gst_v4l2_tuner_set_channel (GstTuner * mixer, + +static void +gst_v4l2_tuner_set_channel_and_notify (GstTuner * mixer, GstTunerChannel * channel); static GstTunerChannel *gst_v4l2_tuner_get_channel (GstTuner * mixer); static const GList *gst_v4l2_tuner_list_norms (GstTuner * mixer); -static void gst_v4l2_tuner_set_norm (GstTuner * mixer, GstTunerNorm * norm); + +static void +gst_v4l2_tuner_set_norm_and_notify (GstTuner * mixer, GstTunerNorm * norm); static GstTunerNorm *gst_v4l2_tuner_get_norm (GstTuner * mixer); -static void gst_v4l2_tuner_set_frequency (GstTuner * mixer, +static void +gst_v4l2_tuner_set_frequency_and_notify (GstTuner * mixer, GstTunerChannel * channel, gulong frequency); static gulong gst_v4l2_tuner_get_frequency (GstTuner * mixer, GstTunerChannel * channel); static gint gst_v4l2_tuner_signal_strength (GstTuner * mixer, GstTunerChannel * channel); +static gboolean gst_v4l2_get_input (GstV4l2Element * v4l2element, gint * input); +static gboolean gst_v4l2_set_input (GstV4l2Element * v4l2element, gint input); + +#if 0 /* output not handled by now */ +static gboolean +gst_v4l2_get_output (GstV4l2Element * v4l2element, gint * output); +static gboolean gst_v4l2_set_output (GstV4l2Element * v4l2element, gint output); +#endif /* #if 0 - output not handled by now */ + static GstTunerNormClass *norm_parent_class = NULL; static GstTunerChannelClass *channel_parent_class = NULL; @@ -140,18 +158,19 @@ gst_v4l2_tuner_interface_init (GstTunerClass * klass) { /* default virtual functions */ klass->list_channels = gst_v4l2_tuner_list_channels; - klass->set_channel = gst_v4l2_tuner_set_channel; + klass->set_channel = gst_v4l2_tuner_set_channel_and_notify; klass->get_channel = gst_v4l2_tuner_get_channel; klass->list_norms = gst_v4l2_tuner_list_norms; - klass->set_norm = gst_v4l2_tuner_set_norm; + klass->set_norm = gst_v4l2_tuner_set_norm_and_notify; klass->get_norm = gst_v4l2_tuner_get_norm; - klass->set_frequency = gst_v4l2_tuner_set_frequency; + klass->set_frequency = gst_v4l2_tuner_set_frequency_and_notify; klass->get_frequency = gst_v4l2_tuner_get_frequency; klass->signal_strength = gst_v4l2_tuner_signal_strength; } +#if 0 /* output not handled by now */ static gboolean gst_v4l2_tuner_is_sink (GstV4l2Element * v4l2element) { @@ -159,6 +178,7 @@ gst_v4l2_tuner_is_sink (GstV4l2Element * v4l2element) return (dir == GST_PAD_SINK); } +#endif /* #if 0 - output not handled by now */ static G_GNUC_UNUSED gboolean gst_v4l2_tuner_contains_channel (GstV4l2Element * v4l2element, @@ -176,29 +196,86 @@ gst_v4l2_tuner_contains_channel (GstV4l2Element * v4l2element, static const GList * gst_v4l2_tuner_list_channels (GstTuner * mixer) { - /* ... or output, if we're a sink... */ return GST_V4L2ELEMENT (mixer)->inputs; } static void -gst_v4l2_tuner_set_channel (GstTuner * mixer, GstTunerChannel * channel) +gst_v4l2_tuner_set_channel_and_notify (GstTuner * mixer, + GstTunerChannel * channel) { GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); - GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel); - /* assert that we're opened and that we're using a known item */ - g_return_if_fail (GST_V4L2_IS_OPEN (v4l2element)); - g_return_if_fail (gst_v4l2_tuner_contains_channel (v4l2element, v4l2channel)); - - /* ... or output, if we're a sink... */ - if (gst_v4l2_tuner_is_sink (v4l2element) ? - gst_v4l2_set_output (v4l2element, v4l2channel->index) : - gst_v4l2_set_input (v4l2element, v4l2channel->index)) { - gst_tuner_channel_changed (mixer, channel); + if (gst_v4l2_tuner_set_channel (mixer, channel)) { g_object_notify (G_OBJECT (v4l2element), "input"); } } +gboolean +gst_v4l2_tuner_set_channel (GstTuner * mixer, GstTunerChannel * channel) +{ + GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); + GstV4l2Src *v4l2src = GST_V4L2SRC (v4l2element); + GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel); + + /* assert that we're opened and that we're using a known item */ + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), FALSE); + g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2element, + v4l2channel), FALSE); + + if ( +#if 0 /* output not handled by now */ + gst_v4l2_tuner_is_sink (v4l2element) ? + gst_v4l2_set_output (v4l2element, v4l2channel->index) : +#endif /* #if 0 - output not handled by now */ + gst_v4l2_set_input (v4l2element, v4l2channel->index) + ) { + gst_tuner_channel_changed (mixer, channel); + gst_v4l2src_get_fps (v4l2src, &v4l2src->fps_n, &v4l2src->fps_d); + return TRUE; + } + + return FALSE; + +} + +static gboolean +gst_v4l2_get_input (GstV4l2Element * v4l2element, gint * input) +{ + gint n; + + GST_DEBUG_OBJECT (v4l2element, "trying to get input"); + if (!GST_V4L2_IS_OPEN (v4l2element)) + return FALSE; + + if (ioctl (v4l2element->video_fd, VIDIOC_G_INPUT, &n) < 0) { + GST_WARNING_OBJECT (v4l2element, + "Failed to get current input on device %s: %s", + v4l2element->videodev, g_strerror (errno)); + return FALSE; + } + + *input = n; + + return TRUE; +} + +static gboolean +gst_v4l2_set_input (GstV4l2Element * v4l2element, gint input) +{ + GST_DEBUG_OBJECT (v4l2element, "trying to set input to %d", input); + if (!GST_V4L2_IS_OPEN (v4l2element)) + return FALSE; + + if (ioctl (v4l2element->video_fd, VIDIOC_S_INPUT, &input) < 0) { + GST_WARNING_OBJECT (v4l2element, "Failed to set input %d on device %s: %s", + input, v4l2element->videodev, g_strerror (errno)); + return FALSE; + } + + return TRUE; +} + + static GstTunerChannel * gst_v4l2_tuner_get_channel (GstTuner * mixer) { @@ -209,10 +286,11 @@ gst_v4l2_tuner_get_channel (GstTuner * mixer) /* assert that we're opened and that we're using a known item */ g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), NULL); - /* ... or output, if we're a sink... */ +#if 0 /* output not handled by now */ if (gst_v4l2_tuner_is_sink (v4l2element)) gst_v4l2_get_output (v4l2element, &channel); else +#endif /* #if 0 - output not handled by now */ gst_v4l2_get_input (v4l2element, &channel); for (item = v4l2element->inputs; item != NULL; item = item->next) { @@ -243,19 +321,35 @@ gst_v4l2_tuner_list_norms (GstTuner * mixer) } static void +gst_v4l2_tuner_set_norm_and_notify (GstTuner * mixer, GstTunerNorm * norm) +{ + GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); + + if (gst_v4l2_tuner_set_norm (mixer, norm)) { + g_object_notify (G_OBJECT (v4l2element), "std"); + } +} + +gboolean gst_v4l2_tuner_set_norm (GstTuner * mixer, GstTunerNorm * norm) { GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); + GstV4l2Src *v4l2src = GST_V4L2SRC (v4l2element); GstV4l2TunerNorm *v4l2norm = GST_V4L2_TUNER_NORM (norm); /* assert that we're opened and that we're using a known item */ - g_return_if_fail (GST_V4L2_IS_OPEN (v4l2element)); - g_return_if_fail (gst_v4l2_tuner_contains_norm (v4l2element, v4l2norm)); + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), FALSE); + g_return_val_if_fail (gst_v4l2_tuner_contains_norm (v4l2element, v4l2norm), + FALSE); if (gst_v4l2_set_norm (v4l2element, v4l2norm->index)) { gst_tuner_norm_changed (mixer, norm); - g_object_notify (G_OBJECT (v4l2element), "std"); + gst_v4l2src_get_fps (v4l2src, &v4l2src->fps_n, &v4l2src->fps_d); + return TRUE; } + + return FALSE; + } static GstTunerNorm * @@ -279,6 +373,17 @@ gst_v4l2_tuner_get_norm (GstTuner * mixer) } static void +gst_v4l2_tuner_set_frequency_and_notify (GstTuner * mixer, + GstTunerChannel * channel, gulong frequency) +{ + GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); + + if (gst_v4l2_tuner_set_frequency (mixer, channel, frequency)) { + g_object_notify (G_OBJECT (v4l2element), "frequency"); + } +} + +gboolean gst_v4l2_tuner_set_frequency (GstTuner * mixer, GstTunerChannel * channel, gulong frequency) { @@ -287,19 +392,21 @@ gst_v4l2_tuner_set_frequency (GstTuner * mixer, gint chan; /* assert that we're opened and that we're using a known item */ - g_return_if_fail (GST_V4L2_IS_OPEN (v4l2element)); - g_return_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel, - GST_TUNER_CHANNEL_FREQUENCY)); - g_return_if_fail (gst_v4l2_tuner_contains_channel (v4l2element, v4l2channel)); + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), FALSE); + g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel, + GST_TUNER_CHANNEL_FREQUENCY), FALSE); + g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2element, + v4l2channel), FALSE); gst_v4l2_get_input (v4l2element, &chan); if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index && GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { if (gst_v4l2_set_frequency (v4l2element, v4l2channel->tuner, frequency)) { gst_tuner_frequency_changed (mixer, channel, frequency); - g_object_notify (G_OBJECT (v4l2element), "frequency"); + return TRUE; } } + return FALSE; } static gulong @@ -349,3 +456,47 @@ gst_v4l2_tuner_signal_strength (GstTuner * mixer, GstTunerChannel * channel) return signal; } + +#if 0 /* output not handled by now */ + +static gboolean +gst_v4l2_get_output (GstV4l2Element * v4l2element, gint * output) +{ + gint n; + + GST_DEBUG_OBJECT (v4l2element, "trying to get output"); + if (!GST_V4L2_IS_OPEN (v4l2element)) + return FALSE; + + if (ioctl (v4l2element->video_fd, VIDIOC_G_OUTPUT, &n) < 0) { + GST_WARNING_OBJECT (v4l2element, + "Failed to get current output on device %s: %s", + v4l2element->videodev, g_strerror (errno)); + return FALSE; + } + + *output = n; + + return TRUE; +} + +static gboolean +gst_v4l2_set_output (GstV4l2Element * v4l2element, gint output) +{ + GST_DEBUG_OBJECT (v4l2element, "trying to set output to %d", output); + if (!GST_V4L2_IS_OPEN (v4l2element)) + return FALSE; + if (!GST_V4L2_IS_ACTIVE (v4l2element)) + return FALSE; + + if (ioctl (v4l2element->video_fd, VIDIOC_S_OUTPUT, &output) < 0) { + GST_WARNING_OBJECT (v4l2element, + "Failed to set current output on device %s to %d: %s", + v4l2element->videodev, output, g_strerror (errno)); + return FALSE; + } + + return TRUE; +} + +#endif /* #if 0 - output not handled by now */ diff --git a/sys/v4l2/gstv4l2tuner.h b/sys/v4l2/gstv4l2tuner.h index a7a5f43510..ede9ab2df9 100644 --- a/sys/v4l2/gstv4l2tuner.h +++ b/sys/v4l2/gstv4l2tuner.h @@ -1,5 +1,6 @@ /* G-Streamer generic V4L2 element - Tuner interface implementation * Copyright (C) 2003 Ronald Bultje + * Copyright (C) 2006 Edgard Lima * * gstv4l2tuner.h: tuner interface implementation for V4L2 * @@ -82,4 +83,14 @@ GType gst_v4l2_tuner_norm_get_type (void); void gst_v4l2_tuner_interface_init (GstTunerClass *klass); +extern gboolean +gst_v4l2_tuner_set_channel (GstTuner * mixer, GstTunerChannel * channel); + +gboolean +gst_v4l2_tuner_set_norm (GstTuner * mixer, GstTunerNorm * norm); + +extern gboolean +gst_v4l2_tuner_set_frequency (GstTuner * mixer, + GstTunerChannel * channel, gulong frequency); + #endif /* __GST_V4L2_TUNER_H__ */ diff --git a/sys/v4l2/v4l2_calls.c b/sys/v4l2/v4l2_calls.c index a43811fd2e..2ca2d86862 100644 --- a/sys/v4l2/v4l2_calls.c +++ b/sys/v4l2/v4l2_calls.c @@ -1,5 +1,6 @@ /* G-Streamer generic V4L2 element - generic V4L2 calls handling * Copyright (C) 2002 Ronald Bultje + * Copyright (C) 2006 Edgard Lima * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -73,12 +74,18 @@ static gboolean gst_v4l2_fill_lists (GstV4l2Element * v4l2element) { gint n; + +#if 0 /* output not handled by now */ GstPadDirection dir = GST_PAD_UNKNOWN; +#endif /* #if 0 - output not handled by now */ GST_DEBUG_OBJECT (v4l2element, "getting enumerations"); GST_V4L2_CHECK_OPEN (v4l2element); +#if 0 /* output not handled by now */ if (dir != GST_PAD_SINK) { +#endif /* #if 0 - output not handled by now */ + /* and now, the inputs */ for (n = 0;; n++) { struct v4l2_input input; @@ -134,6 +141,8 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element) v4l2element->inputs = g_list_append (v4l2element->inputs, (gpointer) channel); } + +#if 0 /* output not handled by now */ } else { /* outputs */ for (n = 0;; n++) { @@ -170,6 +179,7 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element) g_list_append (v4l2element->inputs, (gpointer) channel); } } +#endif /* #if 0 - output not handled by now */ /* norms... */ for (n = 0;; n++) { @@ -501,6 +511,8 @@ gst_v4l2_get_norm (GstV4l2Element * v4l2element, v4l2_std_id * norm) return FALSE; } + + return TRUE; } @@ -517,8 +529,6 @@ gst_v4l2_set_norm (GstV4l2Element * v4l2element, v4l2_std_id norm) GST_DEBUG_OBJECT (v4l2element, "trying to set norm to %llx", norm); if (!GST_V4L2_IS_OPEN (v4l2element)) return FALSE; - if (!GST_V4L2_IS_ACTIVE (v4l2element)) - return FALSE; if (ioctl (v4l2element->video_fd, VIDIOC_S_STD, &norm) < 0) { GST_WARNING_OBJECT (v4l2element, @@ -530,114 +540,6 @@ gst_v4l2_set_norm (GstV4l2Element * v4l2element, v4l2_std_id norm) return TRUE; } - -/****************************************************** - * gst_v4l2_get_input() - * Get the input of the current device - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l2_get_input (GstV4l2Element * v4l2element, gint * input) -{ - gint n; - - GST_DEBUG_OBJECT (v4l2element, "trying to get input"); - if (!GST_V4L2_IS_OPEN (v4l2element)) - return FALSE; - - if (ioctl (v4l2element->video_fd, VIDIOC_G_INPUT, &n) < 0) { - GST_WARNING_OBJECT (v4l2element, - "Failed to get current input on device %s: %s", - v4l2element->videodev, g_strerror (errno)); - return FALSE; - } - - *input = n; - - return TRUE; -} - - -/****************************************************** - * gst_v4l2_set_input() - * Set the input of the current device - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l2_set_input (GstV4l2Element * v4l2element, gint input) -{ - GST_DEBUG_OBJECT (v4l2element, "trying to set input to %d", input); - if (!GST_V4L2_IS_OPEN (v4l2element)) - return FALSE; - if (!GST_V4L2_IS_ACTIVE (v4l2element)) - return FALSE; - - if (ioctl (v4l2element->video_fd, VIDIOC_S_INPUT, &input) < 0) { - GST_WARNING_OBJECT (v4l2element, "Failed to set input %d on device %s: %s", - input, v4l2element->videodev, g_strerror (errno)); - return FALSE; - } - - return TRUE; -} - - -/****************************************************** - * gst_v4l2_get_output() - * Get the output of the current device - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l2_get_output (GstV4l2Element * v4l2element, gint * output) -{ - gint n; - - GST_DEBUG_OBJECT (v4l2element, "trying to get output"); - if (!GST_V4L2_IS_OPEN (v4l2element)) - return FALSE; - - if (ioctl (v4l2element->video_fd, VIDIOC_G_OUTPUT, &n) < 0) { - GST_WARNING_OBJECT (v4l2element, - "Failed to get current output on device %s: %s", - v4l2element->videodev, g_strerror (errno)); - return FALSE; - } - - *output = n; - - return TRUE; -} - - -/****************************************************** - * gst_v4l2_set_output() - * Set the output of the current device - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l2_set_output (GstV4l2Element * v4l2element, gint output) -{ - GST_DEBUG_OBJECT (v4l2element, "trying to set output to %d", output); - if (!GST_V4L2_IS_OPEN (v4l2element)) - return FALSE; - if (!GST_V4L2_IS_ACTIVE (v4l2element)) - return FALSE; - - if (ioctl (v4l2element->video_fd, VIDIOC_S_OUTPUT, &output) < 0) { - GST_WARNING_OBJECT (v4l2element, - "Failed to set current output on device %s to %d: %s", - v4l2element->videodev, output, g_strerror (errno)); - return FALSE; - } - - return TRUE; -} - - /****************************************************** * gst_v4l2_get_frequency(): * get the current frequency @@ -688,8 +590,6 @@ gst_v4l2_set_frequency (GstV4l2Element * v4l2element, frequency); if (!GST_V4L2_IS_OPEN (v4l2element)) return FALSE; - if (!GST_V4L2_IS_ACTIVE (v4l2element)) - return FALSE; channel = gst_tuner_get_channel (GST_TUNER (v4l2element)); diff --git a/sys/v4l2/v4l2_calls.h b/sys/v4l2/v4l2_calls.h index fcacf354ea..35d80d5043 100644 --- a/sys/v4l2/v4l2_calls.h +++ b/sys/v4l2/v4l2_calls.h @@ -1,5 +1,6 @@ /* G-Streamer generic V4L2 element - generic V4L2 calls handling * Copyright (C) 2002 Ronald Bultje + * Copyright (C) 2006 Edgard Lima * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -90,10 +91,6 @@ gboolean gst_v4l2_get_norm (GstV4l2Element *v4l2element, v4l2_std_id *norm); gboolean gst_v4l2_set_norm (GstV4l2Element *v4l2element, v4l2_std_id norm); -gboolean gst_v4l2_get_input (GstV4l2Element *v4l2element, - gint *input); -gboolean gst_v4l2_set_input (GstV4l2Element *v4l2element, - gint input); gboolean gst_v4l2_get_output (GstV4l2Element *v4l2element, gint *output); gboolean gst_v4l2_set_output (GstV4l2Element *v4l2element, diff --git a/sys/v4l2/v4l2src_calls.c b/sys/v4l2/v4l2src_calls.c index b1d9788f17..f28bc96e8d 100644 --- a/sys/v4l2/v4l2src_calls.c +++ b/sys/v4l2/v4l2src_calls.c @@ -1,5 +1,6 @@ /* G-Streamer Video4linux2 video-capture plugin - system calls * Copyright (C) 2002 Ronald Bultje + * Copyright (C) 2006 Edgard Lima * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -319,6 +320,13 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src) return FALSE; } + /* Determine the device's framerate */ + if (!gst_v4l2src_get_fps (v4l2src, &v4l2src->fps_n, &v4l2src->fps_d)) { + GST_DEBUG_OBJECT (v4l2src, "frame rate is unknown."); + v4l2src->fps_d = 1; + v4l2src->fps_n = 0; + } + if (v4l2src->breq.memory > 0) { if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS) { GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, @@ -588,7 +596,7 @@ gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src, fmt.fmt.pix.height); fmt.fmt.pix.width = G_MAXINT; - fmt.fmt.pix.height = 576; + fmt.fmt.pix.height = G_MAXINT; if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_TRY_FMT, &fmt) < 0) { return FALSE; } @@ -604,14 +612,28 @@ gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src, } gboolean -gst_v4l2src_get_fps (GstV4l2Src * v4l2src, gint * fps_n, gint * fps_d) +gst_v4l2src_get_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d) { v4l2_std_id std; + struct v4l2_streamparm stream; const GList *item; if (!GST_V4L2_IS_OPEN (GST_V4L2ELEMENT (v4l2src))) return FALSE; + /* Try to get the frame rate directly from the device using VIDIOC_G_PARM */ + stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_G_PARM, &stream) == 0 + && stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { + /* Note: V4L2 gives us the frame interval, we need the frame rate */ + *fps_n = stream.parm.capture.timeperframe.denominator; + *fps_d = stream.parm.capture.timeperframe.numerator; + GST_DEBUG_OBJECT (v4l2src, "frame rate returned by G_PARM: %d/%d fps", + *fps_n, *fps_d); + return TRUE; + } + + /* If G_PARM failed, try to get the same information from the video standard */ if (!gst_v4l2_get_norm (GST_V4L2ELEMENT (v4l2src), &std)) return FALSE; for (item = GST_V4L2ELEMENT (v4l2src)->stds; item != NULL; item = item->next) { @@ -624,6 +646,8 @@ gst_v4l2src_get_fps (GstV4l2Src * v4l2src, gint * fps_n, gint * fps_d) *fps_d = gst_value_get_fraction_denominator (&GST_TUNER_NORM (v4l2norm)-> framerate); + GST_DEBUG_OBJECT (v4l2src, "frame rate returned by get_norm: %d/%d fps", + *fps_n, *fps_d); return TRUE; } } @@ -780,14 +804,8 @@ gst_v4l2src_buffer_new (GstV4l2Src * v4l2src, guint size, guint8 * data, GstV4l2Buffer * srcbuf) { GstBuffer *buf; - gint fps_n, fps_d; - GST_DEBUG_OBJECT (v4l2src, "creating buffer %d"); - - if (!gst_v4l2src_get_fps (v4l2src, &fps_n, &fps_d)) { - fps_n = 0; - fps_d = 1; - } + GST_LOG_OBJECT (v4l2src, "creating buffer %d"); if (data == NULL) { buf = gst_buffer_new_and_alloc (size); @@ -805,9 +823,9 @@ gst_v4l2src_buffer_new (GstV4l2Src * v4l2src, guint size, guint8 * data, GST_BUFFER_TIMESTAMP (buf) -= GST_ELEMENT (v4l2src)->base_time; GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_READONLY); - if (fps_n > 0) { - GST_BUFFER_DURATION (buf) = gst_util_uint64_scale_int (GST_SECOND, - fps_n, fps_d); + if (v4l2src->fps_n > 0) { + GST_BUFFER_DURATION (buf) = + gst_util_uint64_scale_int (GST_SECOND, v4l2src->fps_n, v4l2src->fps_d); } else { GST_BUFFER_DURATION (buf) = GST_CLOCK_TIME_NONE; } diff --git a/sys/v4l2/v4l2src_calls.h b/sys/v4l2/v4l2src_calls.h index 1411083e03..3839ef2adb 100644 --- a/sys/v4l2/v4l2src_calls.h +++ b/sys/v4l2/v4l2src_calls.h @@ -1,5 +1,6 @@ /* G-Streamer Video4linux2 video-capture plugin - system calls * Copyright (C) 2002 Ronald Bultje + * Copyright (C) 2006 Edgard Lima * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -48,7 +49,7 @@ gboolean gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src, void gst_v4l2src_free_buffer (GstBuffer * buffer); -gboolean gst_v4l2src_get_fps (GstV4l2Src * v4l2src, gint * fps_n, gint * fps_d); +gboolean gst_v4l2src_get_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d); GValue *gst_v4l2src_get_fps_list (GstV4l2Src * v4l2src); diff --git a/tests/icles/v4l2src-test.c b/tests/icles/v4l2src-test.c index b8f85e1508..df6ad66fdd 100644 --- a/tests/icles/v4l2src-test.c +++ b/tests/icles/v4l2src-test.c @@ -199,7 +199,7 @@ main (int argc, char *argv[]) return -1; } - if (argv < 2) { + if (argc < 2) { g_object_set (source, "device", "/dev/video0", NULL); } else { g_object_set (source, "device", argv[1], NULL); @@ -222,7 +222,7 @@ main (int argc, char *argv[]) return -1; } - if (argv < 2) + if (argc < 2) printf ("\nOpening /dev/video0. Launch ./v4l2src-test.c devname to try another one\n");