Commit 3b5f9882 authored by Andy Wingo Wingo's avatar Andy Wingo Wingo
Browse files

sys/v4l2/v4l2src_calls.*: Store the format list in the order that the driver gives it to us.

Original commit message from CVS:
2007-05-30  Andy Wingo  <wingo@pobox.com>

* sys/v4l2/v4l2src_calls.h:
* sys/v4l2/v4l2src_calls.c (gst_v4l2src_fill_format_list): Store
the format list in the order that the driver gives it to us.
(gst_v4l2src_probe_caps_for_format_and_size)
(gst_v4l2src_probe_caps_for_format): New functions, fill GstCaps
based on the capabilities of the device.
(gst_v4l2src_grab_frame): Update for object variable renaming.
(gst_v4l2src_set_capture): Update to be strict in its parameters,
as in the set_caps below.
(gst_v4l2src_capture_init): Update for object variable renaming,
and reflow.
(gst_v4l2src_capture_start, gst_v4l2src_capture_stop)
(gst_v4l2src_capture_deinit): Update for object variable renaming.
(gst_v4l2src_update_fps, gst_v4l2src_set_fps)
(gst_v4l2src_get_fps): Remove; these functions don't have much
meaning outside of an atomic set_caps method.
(gst_v4l2src_buffer_new): Don't set buffer duration, it is not
known.

* sys/v4l2/gstv4l2tuner.c (gst_v4l2_tuner_set_channel): Remove
call to update_fps; not sure about this change.
(gst_v4l2_tuner_set_norm): Work around the fact that for the
moment we don't have an update_fps_func.

* sys/v4l2/gstv4l2src.h (struct _GstV4l2Src): Don't put v4l2
structures in the object, just store what we need. Do store the
probed caps of the device. Don't store the current frame rate.

* sys/v4l2/gstv4l2src.c (gst_v4l2src_init): Remove the
update_fps_function, for now. Update for new object variable
naming.
(gst_v4l2src_set_property, gst_v4l2src_get_property): Update for
new object variable naming.
(gst_v4l2src_v4l2fourcc_to_structure): Rename from ..._to_caps.
(gst_v4l2_structure_to_v4l2fourcc): Rename from ...caps_to_....
(gst_v4l2src_get_caps): Rework to probe the device for supported
frame sizes and frame rates.
(gst_v4l2src_set_caps): Rework to be strict in the given
parameters: if someone asks us to have a certain size and rate,
that is what we configure.
(gst_v4l2src_get_read): Update for object variable naming. Don't
leak buffers on short reads.
(gst_v4l2src_get_mmap): Update for object variable naming, and add
comments.
(gst_v4l2src_create): Update for object variable naming.
parent 3127a32c
2007-05-30 Andy Wingo <wingo@pobox.com>
* sys/v4l2/v4l2src_calls.h:
* sys/v4l2/v4l2src_calls.c (gst_v4l2src_fill_format_list): Store
the format list in the order that the driver gives it to us.
(gst_v4l2src_probe_caps_for_format_and_size)
(gst_v4l2src_probe_caps_for_format): New functions, fill GstCaps
based on the capabilities of the device.
(gst_v4l2src_grab_frame): Update for object variable renaming.
(gst_v4l2src_set_capture): Update to be strict in its parameters,
as in the set_caps below.
(gst_v4l2src_capture_init): Update for object variable renaming,
and reflow.
(gst_v4l2src_capture_start, gst_v4l2src_capture_stop)
(gst_v4l2src_capture_deinit): Update for object variable renaming.
(gst_v4l2src_update_fps, gst_v4l2src_set_fps)
(gst_v4l2src_get_fps): Remove; these functions don't have much
meaning outside of an atomic set_caps method.
(gst_v4l2src_buffer_new): Don't set buffer duration, it is not
known.
* sys/v4l2/gstv4l2tuner.c (gst_v4l2_tuner_set_channel): Remove
call to update_fps; not sure about this change.
(gst_v4l2_tuner_set_norm): Work around the fact that for the
moment we don't have an update_fps_func.
* sys/v4l2/gstv4l2src.h (struct _GstV4l2Src): Don't put v4l2
structures in the object, just store what we need. Do store the
probed caps of the device. Don't store the current frame rate.
* sys/v4l2/gstv4l2src.c (gst_v4l2src_init): Remove the
update_fps_function, for now. Update for new object variable
naming.
(gst_v4l2src_set_property, gst_v4l2src_get_property): Update for
new object variable naming.
(gst_v4l2src_v4l2fourcc_to_structure): Rename from ..._to_caps.
(gst_v4l2_structure_to_v4l2fourcc): Rename from ...caps_to_....
(gst_v4l2src_get_caps): Rework to probe the device for supported
frame sizes and frame rates.
(gst_v4l2src_set_caps): Rework to be strict in the given
parameters: if someone asks us to have a certain size and rate,
that is what we configure.
(gst_v4l2src_get_read): Update for object variable naming. Don't
leak buffers on short reads.
(gst_v4l2src_get_mmap): Update for object variable naming, and add
comments.
(gst_v4l2src_create): Update for object variable naming.
2007-05-30 Tim-Philipp Müller <tim at centricular dot net>
* gst/avi/gstavidemux.c: (gst_avi_demux_base_init),
......
......@@ -249,8 +249,7 @@ gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class)
GstV4l2Object *
gst_v4l2_object_new (GstElement * element,
GstV4l2GetInOutFunction get_in_out_func,
GstV4l2SetInOutFunction set_in_out_func,
GstV4l2UpdateFpsFunction update_fps_func)
GstV4l2SetInOutFunction set_in_out_func)
{
GstV4l2Object *v4l2object;
......@@ -262,7 +261,6 @@ gst_v4l2_object_new (GstElement * element,
v4l2object->element = element;
v4l2object->get_in_out_func = get_in_out_func;
v4l2object->set_in_out_func = set_in_out_func;
v4l2object->update_fps_func = update_fps_func;
v4l2object->video_fd = -1;
v4l2object->buffer = NULL;
......
......@@ -57,7 +57,6 @@ typedef struct _GstV4l2Xv GstV4l2Xv;
typedef gboolean (*GstV4l2GetInOutFunction) (GstV4l2Object * v4l2object, gint * input);
typedef gboolean (*GstV4l2SetInOutFunction) (GstV4l2Object * v4l2object, gint input);
typedef gboolean (*GstV4l2UpdateFpsFunction) (GstV4l2Object * v4l2object);
struct _GstV4l2Object {
GstElement * element;
......@@ -97,7 +96,6 @@ struct _GstV4l2Object {
/* funcs */
GstV4l2GetInOutFunction get_in_out_func;
GstV4l2SetInOutFunction set_in_out_func;
GstV4l2UpdateFpsFunction update_fps_func;
};
struct _GstV4l2ObjectClassHelper {
......@@ -115,8 +113,7 @@ GType gst_v4l2_object_get_type (void);
/* create/destroy */
GstV4l2Object * gst_v4l2_object_new (GstElement * element,
GstV4l2GetInOutFunction get_in_out_func,
GstV4l2SetInOutFunction set_in_out_func,
GstV4l2UpdateFpsFunction update_fps_func);
GstV4l2SetInOutFunction set_in_out_func);
void gst_v4l2_object_destroy (GstV4l2Object * v4l2object);
/* properties */
......
......@@ -293,18 +293,15 @@ gst_v4l2src_class_init (GstV4l2SrcClass * klass)
static void
gst_v4l2src_init (GstV4l2Src * v4l2src, GstV4l2SrcClass * klass)
{
/* fixme: give an update_fps_function */
v4l2src->v4l2object = gst_v4l2_object_new (GST_ELEMENT (v4l2src),
gst_v4l2_get_input, gst_v4l2_set_input, gst_v4l2src_update_fps);
gst_v4l2_get_input, gst_v4l2_set_input, NULL);
/* number of buffers requested */
v4l2src->breq.count = 0;
v4l2src->num_buffers = 0;
v4l2src->formats = NULL;
/* fps */
v4l2src->fps_n = 0;
v4l2src->fps_d = 1;
v4l2src->is_capturing = FALSE;
gst_pad_set_fixatecaps_function (GST_BASE_SRC_PAD (v4l2src),
......@@ -339,16 +336,13 @@ static void
gst_v4l2src_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
GstV4l2Src *v4l2src;
g_return_if_fail (GST_IS_V4L2SRC (object));
v4l2src = GST_V4L2SRC (object);
GstV4l2Src *v4l2src = GST_V4L2SRC (object);
if (!gst_v4l2_object_set_property_helper (v4l2src->v4l2object,
prop_id, value, pspec)) {
switch (prop_id) {
case PROP_QUEUE_SIZE:
v4l2src->breq.count = g_value_get_uint (value);
v4l2src->num_buffers = g_value_get_uint (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
......@@ -362,16 +356,13 @@ static void
gst_v4l2src_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
GstV4l2Src *v4l2src;
g_return_if_fail (GST_IS_V4L2SRC (object));
v4l2src = GST_V4L2SRC (object);
GstV4l2Src *v4l2src = GST_V4L2SRC (object);
if (!gst_v4l2_object_get_property_helper (v4l2src->v4l2object,
prop_id, value, pspec)) {
switch (prop_id) {
case PROP_QUEUE_SIZE:
g_value_set_uint (value, v4l2src->breq.count);
g_value_set_uint (value, v4l2src->num_buffers);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
......@@ -420,7 +411,7 @@ gst_v4l2src_fixate (GstPad * pad, GstCaps * caps)
}
static GstStructure *
gst_v4l2src_v4l2fourcc_to_caps (guint32 fourcc)
gst_v4l2src_v4l2fourcc_to_structure (guint32 fourcc)
{
GstStructure *structure = NULL;
......@@ -690,7 +681,8 @@ gst_v4l2src_get_format_from_fourcc (GstV4l2Src * v4l2src, guint32 fourcc)
}
static struct v4l2_fmtdesc *
gst_v4l2_caps_to_v4l2fourcc (GstV4l2Src * v4l2src, GstStructure * structure)
gst_v4l2_structure_to_v4l2fourcc (GstV4l2Src * v4l2src,
GstStructure * structure)
{
return gst_v4l2src_get_format_from_fourcc (v4l2src,
gst_v4l2_fourcc_from_structure (structure));
......@@ -707,7 +699,7 @@ gst_v4l2src_get_all_caps (void)
caps = gst_caps_new_empty ();
for (i = 0; i < GST_V4L2_FORMAT_COUNT; i++) {
structure = gst_v4l2src_v4l2fourcc_to_caps (gst_v4l2_formats[i]);
structure = gst_v4l2src_v4l2fourcc_to_structure (gst_v4l2_formats[i]);
if (structure) {
gst_structure_set (structure,
"width", GST_TYPE_INT_RANGE, 1, GST_V4L2_MAX_SIZE,
......@@ -725,71 +717,49 @@ static GstCaps *
gst_v4l2src_get_caps (GstBaseSrc * src)
{
GstV4l2Src *v4l2src = GST_V4L2SRC (src);
GstCaps *caps;
struct v4l2_fmtdesc *format;
int min_w, max_w, min_h, max_h;
GstCaps *ret;
GSList *walk;
GstStructure *structure;
guint fps_n, fps_d;
if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
/* FIXME: copy? */
return
gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD
(v4l2src)));
}
if (v4l2src->probed_caps)
return gst_caps_ref (v4l2src->probed_caps);
if (!v4l2src->formats)
gst_v4l2src_fill_format_list (v4l2src);
/* build our own capslist */
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;
}
while (walk) {
ret = gst_caps_new_empty ();
for (walk = v4l2src->formats; walk; walk = walk->next) {
struct v4l2_fmtdesc *format;
GstStructure *template;
format = (struct v4l2_fmtdesc *) walk->data;
walk = g_slist_next (walk);
/* get size delimiters */
if (!gst_v4l2src_get_size_limits (v4l2src, format,
&min_w, &max_w, &min_h, &max_h)) {
continue;
}
/* template, FIXME, why limit if the device reported correct results? */
/* we are doing it right now to avoid unexpected results */
min_w = CLAMP (min_w, 1, GST_V4L2_MAX_SIZE);
min_h = CLAMP (min_h, 1, GST_V4L2_MAX_SIZE);
max_w = CLAMP (max_w, min_w, GST_V4L2_MAX_SIZE);
max_h = CLAMP (max_h, min_h, GST_V4L2_MAX_SIZE);
/* add to list */
structure = gst_v4l2src_v4l2fourcc_to_caps (format->pixelformat);
if (structure) {
gst_structure_set (structure,
"width", GST_TYPE_INT_RANGE, min_w, max_w,
"height", GST_TYPE_INT_RANGE, min_h, max_h, NULL);
/* FIXME, why random range? */
/* AFAIK: in v4l2 standard we still don't have a good way to enum
for a range. Currently it is on discussion on v4l2 forum.
Currently, something more smart could be done for tvcard devices.
The maximum value could be determined by 'v4l2_standard.frameperiod'
and minimum also to the same if V4L2_CAP_TIMEPERFRAME is not set. */
/* another approach for web-cams would be to try to set a very
high(100/1) and low(1/1) FPSs and get the values returned */
gst_structure_set (structure, "framerate", GST_TYPE_FRACTION_RANGE,
0, 1, 100, 1, NULL);
gst_caps_append_structure (caps, structure);
template = gst_v4l2src_v4l2fourcc_to_structure (format->pixelformat);
if (template) {
GstCaps *tmp;
tmp = gst_v4l2src_probe_caps_for_format (v4l2src, format->pixelformat,
template);
if (tmp)
gst_caps_append (ret, tmp);
gst_structure_free (template);
} else {
GST_DEBUG_OBJECT (v4l2src, "unknown format %u", format->pixelformat);
}
}
GST_DEBUG_OBJECT (v4l2src, "returning caps: %" GST_PTR_FORMAT, caps);
return caps;
v4l2src->probed_caps = gst_caps_ref (ret);
return ret;
}
static gboolean
......@@ -820,42 +790,32 @@ gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps)
structure = gst_caps_get_structure (caps, 0);
/* we want our own v4l2 type of fourcc codes */
if (!(format = gst_v4l2_caps_to_v4l2fourcc (v4l2src, structure))) {
if (!(format = gst_v4l2_structure_to_v4l2fourcc (v4l2src, structure))) {
GST_DEBUG_OBJECT (v4l2src, "can't get capture format from caps %"
GST_PTR_FORMAT, caps);
return FALSE;
}
gst_structure_get_int (structure, "width", &w);
gst_structure_get_int (structure, "height", &h);
if (!gst_structure_get_int (structure, "width", &w))
return FALSE;
if (!gst_structure_get_int (structure, "height", &h))
return FALSE;
framerate = gst_structure_get_value (structure, "framerate");
if (!framerate)
return FALSE;
GST_DEBUG_OBJECT (v4l2src, "trying to set_capture %dx%d, format %s",
w, h, format->description);
fps_n = gst_value_get_fraction_numerator (framerate);
fps_d = gst_value_get_fraction_denominator (framerate);
if (framerate) {
fps_n = gst_value_get_fraction_numerator (framerate);
fps_d = gst_value_get_fraction_denominator (framerate);
} else {
fps_n = 0;
fps_d = 1;
}
GST_DEBUG_OBJECT (v4l2src, "trying to set_capture %dx%d at %d/%d fps, "
"format %s", w, h, fps_n, fps_d, format->description);
if (!gst_v4l2src_set_capture (v4l2src, format, &w, &h, &fps_n, &fps_d)) {
GST_WARNING_OBJECT (v4l2src, "could not set_capture %dx%d, format %s",
w, h, format->description);
if (!gst_v4l2src_set_capture (v4l2src, format->pixelformat, w, h, fps_n,
fps_d))
/* error already posted */
return FALSE;
}
if (fps_n) {
gst_structure_set (structure,
"width", G_TYPE_INT, w,
"height", G_TYPE_INT, h,
"framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
} else {
gst_structure_set (structure,
"width", G_TYPE_INT, w, "height", G_TYPE_INT, h, NULL);
}
if (!gst_v4l2src_capture_init (v4l2src))
return FALSE;
......@@ -863,17 +823,6 @@ gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps)
if (!gst_v4l2src_capture_start (v4l2src))
return FALSE;
if (v4l2src->fps_n != fps_n || v4l2src->fps_d != fps_d) {
GST_WARNING_OBJECT (v4l2src,
"framerate changed after start capturing from %u/%u to %u/%u", fps_n,
fps_d, v4l2src->fps_n, v4l2src->fps_d);
if (fps_n) {
gst_structure_set (structure,
"width", G_TYPE_INT, w,
"height", G_TYPE_INT, h,
"framerate", GST_TYPE_FRACTION, v4l2src->fps_n, v4l2src->fps_d, NULL);
}
}
return TRUE;
}
......@@ -920,11 +869,11 @@ gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf)
gint amount;
gint buffersize;
buffersize = v4l2src->format.fmt.pix.sizeimage;
buffersize = v4l2src->frame_byte_size;
do {
*buf = gst_v4l2src_buffer_new (v4l2src, buffersize, NULL, NULL);
*buf = gst_v4l2src_buffer_new (v4l2src, buffersize, NULL, NULL);
do {
amount =
read (v4l2src->v4l2object->video_fd, GST_BUFFER_DATA (*buf),
buffersize);
......@@ -935,8 +884,10 @@ gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf)
continue;
} else
goto read_error;
} else
goto short_read;
} else {
/* short reads can happen if a signal interrupts the read */
continue;
}
} while (TRUE);
return GST_FLOW_OK;
......@@ -950,16 +901,6 @@ read_error:
gst_buffer_unref (*buf);
return GST_FLOW_ERROR;
}
short_read:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC,
(_("Error reading from device '%s'"),
v4l2src->v4l2object->videodev),
("Error read()ing a buffer on device %s: got only %d bytes instead of expected %d.",
v4l2src->v4l2object->videodev, amount, buffersize));
gst_buffer_unref (*buf);
return GST_FLOW_ERROR;
}
}
static GstFlowReturn
......@@ -972,11 +913,13 @@ gst_v4l2src_get_mmap (GstV4l2Src * v4l2src, GstBuffer ** buf)
if (num == -1)
goto grab_failed;
i = v4l2src->format.fmt.pix.sizeimage;
i = v4l2src->frame_byte_size;
/* check if this is the last buffer in the queue. If so do a memcpy to put it back asap
to avoid framedrops and deadlocks because of stupid elements */
if (g_atomic_int_get (&v4l2src->pool->refcount) == v4l2src->breq.count) {
/* FIXME: we should use the userptr interface instead, will remove this
problem */
if (g_atomic_int_get (&v4l2src->pool->refcount) == v4l2src->num_buffers) {
GST_LOG_OBJECT (v4l2src, "using memcpy'd buffer");
*buf = gst_v4l2src_buffer_new (v4l2src, i, NULL, NULL);
......@@ -1017,7 +960,7 @@ gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf)
GstV4l2Src *v4l2src = GST_V4L2SRC (src);
GstFlowReturn ret;
if (v4l2src->breq.memory == V4L2_MEMORY_MMAP) {
if (v4l2src->use_mmap) {
ret = gst_v4l2src_get_mmap (v4l2src, buf);
} else {
ret = gst_v4l2src_get_read (v4l2src, buf);
......
......@@ -85,22 +85,23 @@ struct _GstV4l2Src
/* pads */
GstPad *srcpad;
GstCaps *probed_caps;
/* internal lists */
GSList *formats; /* list of available capture formats */
/* buffers */
GstV4l2BufferPool *pool;
struct v4l2_requestbuffers breq;
struct v4l2_format format;
guint32 num_buffers;
gboolean use_mmap;
guint32 frame_byte_size;
/* True if we want to stop */
gboolean quit, is_capturing;
gboolean quit;
gboolean is_capturing;
guint64 offset;
/* how are we going to push buffers? */
guint fps_n, fps_d;
};
struct _GstV4l2SrcClass
......
......@@ -154,7 +154,7 @@ gst_v4l2_tuner_set_channel (GstV4l2Object * v4l2object,
if (v4l2object->set_in_out_func (v4l2object, v4l2channel->index)) {
gst_tuner_channel_changed (GST_TUNER (v4l2object->element), channel);
v4l2object->update_fps_func (v4l2object);
/* can FPS change here? */
return TRUE;
}
......@@ -223,7 +223,8 @@ gst_v4l2_tuner_set_norm (GstV4l2Object * v4l2object, GstTunerNorm * norm)
if (gst_v4l2_set_norm (v4l2object, v4l2norm->index)) {
gst_tuner_norm_changed (GST_TUNER (v4l2object->element), norm);
v4l2object->update_fps_func (v4l2object);
if (v4l2object->update_fps_func)
v4l2object->update_fps_func (v4l2object);
return TRUE;
}
......
This diff is collapsed.
......@@ -29,9 +29,9 @@
gboolean gst_v4l2src_get_capture (GstV4l2Src * v4l2src);
gboolean gst_v4l2src_set_capture (GstV4l2Src * v4l2src,
struct v4l2_fmtdesc *fmt,
gint * width, gint * height,
guint *fps_n, guint * fps_d);
guint32 pixelformat,
guint32 width, guint32 height,
guint32 fps_n, guint32 fps_d);
gboolean gst_v4l2src_capture_init (GstV4l2Src * v4l2src);
gboolean gst_v4l2src_capture_start (GstV4l2Src * v4l2src);
......@@ -45,6 +45,9 @@ gboolean gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src);
gboolean gst_v4l2src_fill_format_list (GstV4l2Src * v4l2src);
gboolean gst_v4l2src_clear_format_list (GstV4l2Src * v4l2src);
GstCaps* gst_v4l2src_probe_caps_for_format (GstV4l2Src * v4l2src, guint32 pixelformat,
const GstStructure *template);
gboolean gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src,
struct v4l2_fmtdesc *fmt,
gint * min_w, gint * max_w,
......@@ -55,13 +58,5 @@ GstBuffer* gst_v4l2src_buffer_new (GstV4l2Src * v4l2src,
GstV4l2Buffer * srcbuf);
void gst_v4l2src_free_buffer (GstBuffer * buffer);
/* FPS stuff */
gboolean gst_v4l2src_update_fps (GstV4l2Object * v4l2object);
gboolean gst_v4l2src_get_fps (GstV4l2Src * v4l2src,
guint * fps_n, guint * fps_d);
gboolean gst_v4l2src_set_fps (GstV4l2Src * v4l2src,
guint * fps_n, guint * fps_d);
GValue* gst_v4l2src_get_fps_list (GstV4l2Src * v4l2src);
#endif /* __V4L2SRC_CALLS_H__ */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment