--- a/gst_plugins_base/gst-libs/gst/audio/gstringbuffer.c Wed Mar 24 17:58:42 2010 -0500
+++ b/gst_plugins_base/gst-libs/gst/audio/gstringbuffer.c Wed Mar 24 18:04:17 2010 -0500
@@ -43,10 +43,6 @@
#include "gstringbuffer.h"
-#ifdef __SYMBIAN32__
-#include <glib_global.h>
-#endif
-
GST_DEBUG_CATEGORY_STATIC (gst_ring_buffer_debug);
#define GST_CAT_DEFAULT gst_ring_buffer_debug
@@ -56,6 +52,9 @@
static void gst_ring_buffer_finalize (GObject * object);
static gboolean gst_ring_buffer_pause_unlocked (GstRingBuffer * buf);
+static void default_clear_all (GstRingBuffer * buf);
+static guint default_commit (GstRingBuffer * buf, guint64 * sample,
+ guchar * data, gint in_samples, gint out_samples, gint * accum);
static GstObjectClass *parent_class = NULL;
@@ -97,14 +96,19 @@
{
GObjectClass *gobject_class;
GstObjectClass *gstobject_class;
+ GstRingBufferClass *gstringbuffer_class;
gobject_class = (GObjectClass *) klass;
gstobject_class = (GstObjectClass *) klass;
+ gstringbuffer_class = (GstRingBufferClass *) klass;
parent_class = g_type_class_peek_parent (klass);
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_ring_buffer_dispose);
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ring_buffer_finalize);
+
+ gstringbuffer_class->clear_all = GST_DEBUG_FUNCPTR (default_clear_all);
+ gstringbuffer_class->commit = GST_DEBUG_FUNCPTR (default_commit);
}
static void
@@ -274,6 +278,7 @@
GST_DEBUG ("acquire ringbuffer: latency time: %" G_GINT64_FORMAT " usec",
spec->latency_time);
GST_DEBUG ("acquire ringbuffer: total segments: %d", spec->segtotal);
+ GST_DEBUG ("acquire ringbuffer: latency segments: %d", spec->seglatency);
GST_DEBUG ("acquire ringbuffer: segment size: %d bytes = %d samples",
spec->segsize, spec->segsize / spec->bytes_per_sample);
GST_DEBUG ("acquire ringbuffer: buffer size: %d bytes = %d samples",
@@ -434,6 +439,9 @@
spec->segsize -= spec->segsize % spec->bytes_per_sample;
spec->segtotal = spec->buffer_time / spec->latency_time;
+ /* leave the latency undefined now, implementations can change it but if it's
+ * not changed, we assume the same value as segtotal */
+ spec->seglatency = -1;
gst_ring_buffer_debug_spec_caps (spec);
gst_ring_buffer_debug_spec_buff (spec);
@@ -449,6 +457,105 @@
}
/**
+ * gst_ring_buffer_convert:
+ * @buf: the #GstRingBuffer
+ * @src_fmt: the source format
+ * @src_val: the source value
+ * @dest_fmt: the destination format
+ * @dest_val: a location to store the converted value
+ *
+ * Convert @src_val in @src_fmt to the equivalent value in @dest_fmt. The result
+ * will be put in @dest_val.
+ *
+ * Returns: TRUE if the conversion succeeded.
+ *
+ * Since: 0.10.22.
+ */
+#ifdef __SYMBIAN32__
+EXPORT_C
+#endif
+
+gboolean
+gst_ring_buffer_convert (GstRingBuffer * buf,
+ GstFormat src_fmt, gint64 src_val, GstFormat dest_fmt, gint64 * dest_val)
+{
+ gboolean res = TRUE;
+ gint bps, rate;
+
+ GST_DEBUG ("converting value %" G_GINT64_FORMAT " from %s (%d) to %s (%d)",
+ src_val, gst_format_get_name (src_fmt), src_fmt,
+ gst_format_get_name (dest_fmt), dest_fmt);
+
+ if (src_fmt == dest_fmt || src_val == -1) {
+ *dest_val = src_val;
+ goto done;
+ }
+
+ /* get important info */
+ GST_OBJECT_LOCK (buf);
+ bps = buf->spec.bytes_per_sample;
+ rate = buf->spec.rate;
+ GST_OBJECT_UNLOCK (buf);
+
+ if (bps == 0 || rate == 0) {
+ GST_DEBUG ("no rate or bps configured");
+ res = FALSE;
+ goto done;
+ }
+
+ switch (src_fmt) {
+ case GST_FORMAT_BYTES:
+ switch (dest_fmt) {
+ case GST_FORMAT_TIME:
+ *dest_val = gst_util_uint64_scale_int (src_val / bps, GST_SECOND,
+ rate);
+ break;
+ case GST_FORMAT_DEFAULT:
+ *dest_val = src_val / bps;
+ break;
+ default:
+ res = FALSE;
+ break;
+ }
+ break;
+ case GST_FORMAT_DEFAULT:
+ switch (dest_fmt) {
+ case GST_FORMAT_TIME:
+ *dest_val = gst_util_uint64_scale_int (src_val, GST_SECOND, rate);
+ break;
+ case GST_FORMAT_BYTES:
+ *dest_val = src_val * bps;
+ break;
+ default:
+ res = FALSE;
+ break;
+ }
+ break;
+ case GST_FORMAT_TIME:
+ switch (dest_fmt) {
+ case GST_FORMAT_DEFAULT:
+ *dest_val = gst_util_uint64_scale_int (src_val, rate, GST_SECOND);
+ break;
+ case GST_FORMAT_BYTES:
+ *dest_val = gst_util_uint64_scale_int (src_val, rate, GST_SECOND);
+ *dest_val *= bps;
+ break;
+ default:
+ res = FALSE;
+ break;
+ }
+ break;
+ default:
+ res = FALSE;
+ break;
+ }
+done:
+ GST_DEBUG ("ret=%d result %" G_GINT64_FORMAT, res, *dest_val);
+
+ return res;
+}
+
+/**
* gst_ring_buffer_set_callback:
* @buf: the #GstRingBuffer to set the callback on
* @cb: the callback to set
@@ -640,7 +747,6 @@
return res;
}
-
/**
* gst_ring_buffer_acquire:
* @buf: the #GstRingBuffer to acquire
@@ -689,6 +795,11 @@
if (G_UNLIKELY ((bps = buf->spec.bytes_per_sample) == 0))
goto invalid_bps;
+ /* if the seglatency was overwritten with something else than -1, use it, else
+ * assume segtotal as the latency */
+ if (buf->spec.seglatency == -1)
+ buf->spec.seglatency = buf->spec.segtotal;
+
segsize = buf->spec.segsize;
buf->samples_per_seg = segsize / bps;
@@ -840,6 +951,111 @@
}
/**
+ * gst_ring_buffer_activate:
+ * @buf: the #GstRingBuffer to activate
+ * @active: the new mode
+ *
+ * Activate @buf to start or stop pulling data.
+ *
+ * MT safe.
+ *
+ * Returns: TRUE if the device could be activated in the requested mode,
+ * FALSE on error.
+ *
+ * Since: 0.10.22.
+ */
+#ifdef __SYMBIAN32__
+EXPORT_C
+#endif
+
+gboolean
+gst_ring_buffer_activate (GstRingBuffer * buf, gboolean active)
+{
+ gboolean res = FALSE;
+ GstRingBufferClass *rclass;
+
+ g_return_val_if_fail (GST_IS_RING_BUFFER (buf), FALSE);
+
+ GST_DEBUG_OBJECT (buf, "activate device");
+
+ GST_OBJECT_LOCK (buf);
+ if (G_UNLIKELY (active && !buf->acquired))
+ goto not_acquired;
+
+ if (G_UNLIKELY (buf->abidata.ABI.active == active))
+ goto was_active;
+
+ rclass = GST_RING_BUFFER_GET_CLASS (buf);
+ /* if there is no activate function we assume it was started/released
+ * in the acquire method */
+ if (G_LIKELY (rclass->activate))
+ res = rclass->activate (buf, active);
+ else
+ res = TRUE;
+
+ if (G_UNLIKELY (!res))
+ goto activate_failed;
+
+ buf->abidata.ABI.active = active;
+
+done:
+ GST_OBJECT_UNLOCK (buf);
+
+ return res;
+
+ /* ERRORS */
+not_acquired:
+ {
+ GST_DEBUG_OBJECT (buf, "device not acquired");
+ g_critical ("Device for %p not acquired", buf);
+ res = FALSE;
+ goto done;
+ }
+was_active:
+ {
+ res = TRUE;
+ GST_DEBUG_OBJECT (buf, "device was active in mode %d", active);
+ goto done;
+ }
+activate_failed:
+ {
+ GST_DEBUG_OBJECT (buf, "failed to activate device");
+ goto done;
+ }
+}
+
+/**
+ * gst_ring_buffer_is_active:
+ * @buf: the #GstRingBuffer
+ *
+ * Check if @buf is activated.
+ *
+ * MT safe.
+ *
+ * Returns: TRUE if the device is active.
+ *
+ * Since: 0.10.22.
+ */
+#ifdef __SYMBIAN32__
+EXPORT_C
+#endif
+
+gboolean
+gst_ring_buffer_is_active (GstRingBuffer * buf)
+{
+ gboolean res;
+
+ g_return_val_if_fail (GST_IS_RING_BUFFER (buf), FALSE);
+
+ GST_OBJECT_LOCK (buf);
+ res = buf->abidata.ABI.active;
+ GST_OBJECT_UNLOCK (buf);
+
+ return res;
+}
+
+
+/**
* gst_ring_buffer_set_flushing:
* @buf: the #GstRingBuffer to flush
* @flushing: the new mode
@@ -860,9 +1076,10 @@
GST_OBJECT_LOCK (buf);
buf->abidata.ABI.flushing = flushing;
- gst_ring_buffer_clear_all (buf);
if (flushing) {
gst_ring_buffer_pause_unlocked (buf);
+ } else {
+ gst_ring_buffer_clear_all (buf);
}
GST_OBJECT_UNLOCK (buf);
}
@@ -904,13 +1121,14 @@
GST_RING_BUFFER_STATE_STOPPED, GST_RING_BUFFER_STATE_STARTED);
if (!res) {
+ GST_DEBUG_OBJECT (buf, "was not stopped, try paused");
/* was not stopped, try from paused */
res = g_atomic_int_compare_and_exchange (&buf->state,
GST_RING_BUFFER_STATE_PAUSED, GST_RING_BUFFER_STATE_STARTED);
if (!res) {
/* was not paused either, must be started then */
res = TRUE;
- GST_DEBUG_OBJECT (buf, "was started");
+ GST_DEBUG_OBJECT (buf, "was not paused, must have been started");
goto done;
}
resume = TRUE;
@@ -1071,10 +1289,16 @@
GST_RING_BUFFER_STATE_STARTED, GST_RING_BUFFER_STATE_STOPPED);
if (!res) {
- /* was not started, must be stopped then */
- GST_DEBUG_OBJECT (buf, "was not started");
- res = TRUE;
- goto done;
+ GST_DEBUG_OBJECT (buf, "was not started, try paused");
+ /* was not started, try from paused */
+ res = g_atomic_int_compare_and_exchange (&buf->state,
+ GST_RING_BUFFER_STATE_PAUSED, GST_RING_BUFFER_STATE_STOPPED);
+ if (!res) {
+ /* was not paused either, must have been stopped then */
+ res = TRUE;
+ GST_DEBUG_OBJECT (buf, "was not paused, must have been stopped");
+ goto done;
+ }
}
/* signal any waiters */
@@ -1220,6 +1444,22 @@
buf->segbase);
}
+static void
+default_clear_all (GstRingBuffer * buf)
+{
+ gint i;
+
+ /* not fatal, we just are not negotiated yet */
+ if (G_UNLIKELY (buf->spec.segtotal <= 0))
+ return;
+
+ GST_DEBUG_OBJECT (buf, "clear all segments");
+
+ for (i = 0; i < buf->spec.segtotal; i++) {
+ gst_ring_buffer_clear (buf, i);
+ }
+}
+
/**
* gst_ring_buffer_clear_all:
* @buf: the #GstRingBuffer to clear
@@ -1235,19 +1475,14 @@
void
gst_ring_buffer_clear_all (GstRingBuffer * buf)
{
- gint i;
+ GstRingBufferClass *rclass;
g_return_if_fail (GST_IS_RING_BUFFER (buf));
- /* not fatal, we just are not negotiated yet */
- if (G_UNLIKELY (buf->spec.segtotal <= 0))
- return;
+ rclass = GST_RING_BUFFER_GET_CLASS (buf);
- GST_DEBUG_OBJECT (buf, "clear all segments");
-
- for (i = 0; i < buf->spec.segtotal; i++) {
- gst_ring_buffer_clear (buf, i);
- }
+ if (G_LIKELY (rclass->clear_all))
+ rclass->clear_all (buf);
}
@@ -1370,7 +1605,7 @@
memcpy (d, se, bps); \
se -= bps; \
*accum += outr; \
- while ((*accum << 1) >= inr) { \
+ while (d < de && (*accum << 1) >= inr) { \
*accum -= inr; \
d += bps; \
} \
@@ -1388,7 +1623,7 @@
memcpy (d, se, bps); \
d += bps; \
*accum += inr; \
- while ((*accum << 1) >= outr) { \
+ while (s <= se && (*accum << 1) >= outr) { \
*accum -= outr; \
se -= bps; \
} \
@@ -1398,47 +1633,8 @@
GST_DEBUG ("rev_down end %d/%d",*accum,*toprocess); \
} G_STMT_END
-/**
- * gst_ring_buffer_commit_full:
- * @buf: the #GstRingBuffer to commit
- * @sample: the sample position of the data
- * @data: the data to commit
- * @in_samples: the number of samples in the data to commit
- * @out_samples: the number of samples to write to the ringbuffer
- * @accum: accumulator for rate conversion.
- *
- * Commit @in_samples samples pointed to by @data to the ringbuffer @buf.
- *
- * @in_samples and @out_samples define the rate conversion to perform on the the
- * samples in @data. For negative rates, @out_samples must be negative and
- * @in_samples positive.
- *
- * When @out_samples is positive, the first sample will be written at position @sample
- * in the ringbuffer. When @out_samples is negative, the last sample will be written to
- * @sample in reverse order.
- *
- * @out_samples does not need to be a multiple of the segment size of the ringbuffer
- * although it is recommended for optimal performance.
- *
- * @accum will hold a temporary accumulator used in rate conversion and should be
- * set to 0 when this function is first called. In case the commit operation is
- * interrupted, one can resume the processing by passing the previously returned
- * @accum value back to this function.
- *
- * Returns: The number of samples written to the ringbuffer or -1 on error. The
- * number of samples written can be less than @out_samples when @buf was interrupted
- * with a flush or stop.
- *
- * Since: 0.10.11.
- *
- * MT safe.
- */
-#ifdef __SYMBIAN32__
-EXPORT_C
-#endif
-
-guint
-gst_ring_buffer_commit_full (GstRingBuffer * buf, guint64 * sample,
+static guint
+default_commit (GstRingBuffer * buf, guint64 * sample,
guchar * data, gint in_samples, gint out_samples, gint * accum)
{
gint segdone;
@@ -1449,10 +1645,6 @@
gint inr, outr;
gboolean reverse;
- if (G_UNLIKELY (in_samples == 0 || out_samples == 0))
- return in_samples;
-
- g_return_val_if_fail (GST_IS_RING_BUFFER (buf), -1);
g_return_val_if_fail (buf->data != NULL, -1);
g_return_val_if_fail (data != NULL, -1);
@@ -1571,6 +1763,65 @@
}
/**
+ * gst_ring_buffer_commit_full:
+ * @buf: the #GstRingBuffer to commit
+ * @sample: the sample position of the data
+ * @data: the data to commit
+ * @in_samples: the number of samples in the data to commit
+ * @out_samples: the number of samples to write to the ringbuffer
+ * @accum: accumulator for rate conversion.
+ *
+ * Commit @in_samples samples pointed to by @data to the ringbuffer @buf.
+ *
+ * @in_samples and @out_samples define the rate conversion to perform on the the
+ * samples in @data. For negative rates, @out_samples must be negative and
+ * @in_samples positive.
+ *
+ * When @out_samples is positive, the first sample will be written at position @sample
+ * in the ringbuffer. When @out_samples is negative, the last sample will be written to
+ * @sample in reverse order.
+ *
+ * @out_samples does not need to be a multiple of the segment size of the ringbuffer
+ * although it is recommended for optimal performance.
+ *
+ * @accum will hold a temporary accumulator used in rate conversion and should be
+ * set to 0 when this function is first called. In case the commit operation is
+ * interrupted, one can resume the processing by passing the previously returned
+ * @accum value back to this function.
+ *
+ * MT safe.
+ *
+ * Returns: The number of samples written to the ringbuffer or -1 on error. The
+ * number of samples written can be less than @out_samples when @buf was interrupted
+ * with a flush or stop.
+ *
+ * Since: 0.10.11.
+ */
+#ifdef __SYMBIAN32__
+EXPORT_C
+#endif
+
+guint
+gst_ring_buffer_commit_full (GstRingBuffer * buf, guint64 * sample,
+ guchar * data, gint in_samples, gint out_samples, gint * accum)
+{
+ GstRingBufferClass *rclass;
+ guint res = -1;
+
+ g_return_val_if_fail (GST_IS_RING_BUFFER (buf), -1);
+
+ if (G_UNLIKELY (in_samples == 0 || out_samples == 0))
+ return in_samples;
+
+ rclass = GST_RING_BUFFER_GET_CLASS (buf);
+
+ if (G_LIKELY (rclass->commit))
+ res = rclass->commit (buf, sample, data, in_samples, out_samples, accum);
+
+ return res;
+}
+
+/**
* gst_ring_buffer_commit:
* @buf: the #GstRingBuffer to commit
* @sample: the sample position of the data
@@ -1742,10 +1993,6 @@
g_return_val_if_fail (GST_IS_RING_BUFFER (buf), FALSE);
- /* buffer must be started */
- if (g_atomic_int_get (&buf->state) != GST_RING_BUFFER_STATE_STARTED)
- return FALSE;
-
g_return_val_if_fail (buf->data != NULL, FALSE);
g_return_val_if_fail (segment != NULL, FALSE);
g_return_val_if_fail (readptr != NULL, FALSE);
@@ -1753,6 +2000,12 @@
data = GST_BUFFER_DATA (buf->data);
+ if (buf->callback == NULL) {
+ /* push mode, fail when nothing is started */
+ if (g_atomic_int_get (&buf->state) != GST_RING_BUFFER_STATE_STARTED)
+ return FALSE;
+ }
+
/* get the position of the pointer */
segdone = g_atomic_int_get (&buf->segdone);
@@ -1760,14 +2013,14 @@
*len = buf->spec.segsize;
*readptr = data + *segment * *len;
+ GST_LOG ("prepare read from segment %d (real %d) @%p",
+ *segment, segdone, *readptr);
+
/* callback to fill the memory with data, for pull based
* scheduling. */
if (buf->callback)
buf->callback (buf, *readptr, *len, buf->cb_data);
- GST_LOG ("prepare read from segment %d (real %d) @%p",
- *segment, segdone, *readptr);
-
return TRUE;
}
@@ -1851,9 +2104,9 @@
* Tell the ringbuffer that it is allowed to start playback when
* the ringbuffer is filled with samples.
*
- * Since: 0.10.6
+ * MT safe.
*
- * MT safe.
+ * Since: 0.10.6
*/
#ifdef __SYMBIAN32__
EXPORT_C
@@ -1865,5 +2118,5 @@
g_return_if_fail (GST_IS_RING_BUFFER (buf));
GST_LOG_OBJECT (buf, "may start: %d", allowed);
- gst_atomic_int_set (&buf->abidata.ABI.may_start, allowed);
+ g_atomic_int_set (&buf->abidata.ABI.may_start, allowed);
}