gst-libs/gst/audio/gstaudiosink.c: Implement a separate activate functions to start monitoring the segments or, in pu...

Original commit message from CVS:
* gst-libs/gst/audio/gstaudiosink.c:
(gst_audioringbuffer_class_init), (gst_audioringbuffer_acquire),
(gst_audioringbuffer_activate), (gst_audioringbuffer_release),
(gst_audioringbuffer_stop):
Implement a separate activate functions to start monitoring the segments
or, in pull mode, pulling in data.
* gst-libs/gst/audio/gstbaseaudiosink.c:
(gst_base_audio_sink_init), (gst_base_audio_sink_dispose),
(gst_base_audio_sink_query_pad), (gst_base_audio_sink_query),
(gst_base_audio_sink_setcaps), (gst_base_audio_sink_callback),
(gst_base_audio_sink_activate_pull),
(gst_base_audio_sink_async_play),
(gst_base_audio_sink_change_state):
Implement pad and element convert query function.
Activate the ringbuffer.
Use the segment last_stop value as the offset to pull.
Use new basesink _do_preroll() method to preroll in the pulling thread.
Take appropriate locking in the pulling thread.
* gst-libs/gst/audio/gstringbuffer.h:
Update some docs.
This commit is contained in:
Wim Taymans 2008-10-20 15:35:37 +00:00
parent e4e86b0bad
commit 6eed8ca285
4 changed files with 209 additions and 58 deletions

View file

@ -1,3 +1,28 @@
2008-10-20 Wim Taymans <wim.taymans@collabora.co.uk>
* gst-libs/gst/audio/gstaudiosink.c:
(gst_audioringbuffer_class_init), (gst_audioringbuffer_acquire),
(gst_audioringbuffer_activate), (gst_audioringbuffer_release),
(gst_audioringbuffer_stop):
Implement a separate activate functions to start monitoring the segments
or, in pull mode, pulling in data.
* gst-libs/gst/audio/gstbaseaudiosink.c:
(gst_base_audio_sink_init), (gst_base_audio_sink_dispose),
(gst_base_audio_sink_query_pad), (gst_base_audio_sink_query),
(gst_base_audio_sink_setcaps), (gst_base_audio_sink_callback),
(gst_base_audio_sink_activate_pull),
(gst_base_audio_sink_async_play),
(gst_base_audio_sink_change_state):
Implement pad and element convert query function.
Activate the ringbuffer.
Use the segment last_stop value as the offset to pull.
Use new basesink _do_preroll() method to preroll in the pulling thread.
Take appropriate locking in the pulling thread.
* gst-libs/gst/audio/gstringbuffer.h:
Update some docs.
2008-10-20 Sebastian Dröge <sebastian.droege@collabora.co.uk>
* gst/typefind/gsttypefindfunctions.c: (mxf_type_find):

View file

@ -129,6 +129,8 @@ static gboolean gst_audioringbuffer_start (GstRingBuffer * buf);
static gboolean gst_audioringbuffer_pause (GstRingBuffer * buf);
static gboolean gst_audioringbuffer_stop (GstRingBuffer * buf);
static guint gst_audioringbuffer_delay (GstRingBuffer * buf);
static gboolean gst_audioringbuffer_activate (GstRingBuffer * buf,
gboolean active);
/* ringbuffer abstract base class */
static GType
@ -187,6 +189,8 @@ gst_audioringbuffer_class_init (GstAudioRingBufferClass * klass)
gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_audioringbuffer_stop);
gstringbuffer_class->delay = GST_DEBUG_FUNCPTR (gst_audioringbuffer_delay);
gstringbuffer_class->activate =
GST_DEBUG_FUNCPTR (gst_audioringbuffer_activate);
}
typedef guint (*WriteFunc) (GstAudioSink * sink, gpointer data, guint length);
@ -360,16 +364,13 @@ gst_audioringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
{
GstAudioSink *sink;
GstAudioSinkClass *csink;
GstAudioRingBuffer *abuf;
gboolean result = FALSE;
GError *error = NULL;
sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
csink = GST_AUDIO_SINK_GET_CLASS (sink);
if (csink->prepare)
result = csink->prepare (sink, spec);
if (!result)
goto could_not_prepare;
@ -379,37 +380,61 @@ gst_audioringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data));
abuf = GST_AUDIORING_BUFFER_CAST (buf);
abuf->running = TRUE;
GST_DEBUG_OBJECT (sink, "starting thread");
sink->thread =
g_thread_create ((GThreadFunc) audioringbuffer_thread_func, buf, TRUE,
&error);
if (!sink->thread || error != NULL)
goto thread_failed;
GST_DEBUG_OBJECT (sink, "waiting for thread");
/* the object lock is taken */
GST_AUDIORING_BUFFER_WAIT (buf);
GST_DEBUG_OBJECT (sink, "thread is started");
return result;
return TRUE;
/* ERRORS */
could_not_prepare:
{
GST_DEBUG_OBJECT (sink, "could not prepare device");
return FALSE;
}
}
static gboolean
gst_audioringbuffer_activate (GstRingBuffer * buf, gboolean active)
{
GstAudioSink *sink;
GstAudioRingBuffer *abuf;
GError *error = NULL;
sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
abuf = GST_AUDIORING_BUFFER_CAST (buf);
if (active) {
abuf->running = TRUE;
GST_DEBUG_OBJECT (sink, "starting thread");
sink->thread =
g_thread_create ((GThreadFunc) audioringbuffer_thread_func, buf, TRUE,
&error);
if (!sink->thread || error != NULL)
goto thread_failed;
GST_DEBUG_OBJECT (sink, "waiting for thread");
/* the object lock is taken */
GST_AUDIORING_BUFFER_WAIT (buf);
GST_DEBUG_OBJECT (sink, "thread is started");
} else {
abuf->running = FALSE;
GST_DEBUG_OBJECT (sink, "signal wait");
GST_AUDIORING_BUFFER_SIGNAL (buf);
GST_OBJECT_UNLOCK (buf);
/* join the thread */
g_thread_join (sink->thread);
GST_OBJECT_LOCK (buf);
}
return TRUE;
/* ERRORS */
thread_failed:
{
if (error)
GST_ERROR_OBJECT (sink, "could not create thread %s", error->message);
else
GST_ERROR_OBJECT (sink, "could not create thread for unknown reason");
/* still unprepare */
if (csink->unprepare)
result = csink->unprepare (sink);
return FALSE;
}
}
@ -427,17 +452,6 @@ gst_audioringbuffer_release (GstRingBuffer * buf)
csink = GST_AUDIO_SINK_GET_CLASS (sink);
abuf = GST_AUDIORING_BUFFER_CAST (buf);
abuf->running = FALSE;
GST_DEBUG_OBJECT (sink, "signal wait");
GST_AUDIORING_BUFFER_SIGNAL (buf);
GST_OBJECT_UNLOCK (buf);
/* join the thread */
g_thread_join (sink->thread);
GST_OBJECT_LOCK (buf);
/* free the buffer */
gst_buffer_unref (buf->data);
buf->data = NULL;

View file

@ -148,6 +148,9 @@ static gboolean gst_base_audio_sink_setcaps (GstBaseSink * bsink,
GstCaps * caps);
static void gst_base_audio_sink_fixate (GstBaseSink * bsink, GstCaps * caps);
static gboolean gst_base_audio_sink_query_pad (GstPad * pad, GstQuery * query);
/* static guint gst_base_audio_sink_signals[LAST_SIGNAL] = { 0 }; */
static void
@ -239,6 +242,10 @@ gst_base_audio_sink_init (GstBaseAudioSink * baseaudiosink,
/* FIXME, enable pull mode when segments, latency, state changes, negotiation
* and clock slaving are figured out */
GST_BASE_SINK (baseaudiosink)->can_activate_pull = FALSE;
/* install some custom pad_query functions */
gst_pad_set_query_function (GST_BASE_SINK_PAD (baseaudiosink),
GST_DEBUG_FUNCPTR (gst_base_audio_sink_query_pad));
}
static void
@ -260,6 +267,7 @@ gst_base_audio_sink_dispose (GObject * object)
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static GstClock *
gst_base_audio_sink_provide_clock (GstElement * elem)
{
@ -298,12 +306,48 @@ clock_disabled:
}
}
static gboolean
gst_base_audio_sink_query_pad (GstPad * pad, GstQuery * query)
{
gboolean res = FALSE;
GstBaseAudioSink *basesink;
basesink = GST_BASE_AUDIO_SINK (gst_pad_get_parent (pad));
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CONVERT:
{
GstFormat src_fmt, dest_fmt;
gint64 src_val, dest_val;
GST_LOG_OBJECT (pad, "query convert");
if (basesink->ringbuffer) {
gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, NULL);
res = gst_ring_buffer_convert (basesink->ringbuffer, src_fmt, src_val,
dest_fmt, &dest_val);
if (res) {
gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
}
}
break;
}
default:
break;
}
gst_object_unref (basesink);
return res;
}
static gboolean
gst_base_audio_sink_query (GstElement * element, GstQuery * query)
{
gboolean res = FALSE;
GstBaseAudioSink *basesink;
GstBaseAudioSink *basesink = GST_BASE_AUDIO_SINK (element);
basesink = GST_BASE_AUDIO_SINK (element);
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_LATENCY:
@ -358,6 +402,23 @@ gst_base_audio_sink_query (GstElement * element, GstQuery * query)
}
break;
}
case GST_QUERY_CONVERT:
{
GstFormat src_fmt, dest_fmt;
gint64 src_val, dest_val;
GST_LOG_OBJECT (basesink, "query convert");
if (basesink->ringbuffer) {
gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, NULL);
res = gst_ring_buffer_convert (basesink->ringbuffer, src_fmt, src_val,
dest_fmt, &dest_val);
if (res) {
gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
}
}
break;
}
default:
res = GST_ELEMENT_CLASS (parent_class)->query (element, query);
break;
@ -559,6 +620,7 @@ gst_base_audio_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
GST_DEBUG_OBJECT (sink, "release old ringbuffer");
/* release old ringbuffer */
gst_ring_buffer_activate (sink->ringbuffer, FALSE);
gst_ring_buffer_release (sink->ringbuffer);
GST_DEBUG_OBJECT (sink, "parse caps");
@ -572,11 +634,15 @@ gst_base_audio_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
gst_ring_buffer_debug_spec_buff (spec);
GST_DEBUG_OBJECT (sink, "acquire new ringbuffer");
GST_DEBUG_OBJECT (sink, "acquire ringbuffer");
if (!gst_ring_buffer_acquire (sink->ringbuffer, spec))
goto acquire_error;
if (bsink->pad_mode == GST_ACTIVATE_PUSH) {
GST_DEBUG_OBJECT (sink, "activate ringbuffer");
gst_ring_buffer_activate (sink->ringbuffer, TRUE);
}
/* calculate actual latency and buffer times.
* FIXME: In 0.11, store the latency_time internally in ns */
spec->latency_time = gst_util_uint64_scale (spec->segsize,
@ -1523,25 +1589,6 @@ gst_base_audio_sink_create_ringbuffer (GstBaseAudioSink * sink)
return buffer;
}
static gboolean
gst_base_audio_sink_activate_pull (GstBaseSink * basesink, gboolean active)
{
gboolean ret;
GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (basesink);
if (active) {
gst_ring_buffer_set_callback (sink->ringbuffer,
gst_base_audio_sink_callback, sink);
ret = gst_ring_buffer_start (sink->ringbuffer);
} else {
gst_ring_buffer_set_callback (sink->ringbuffer, NULL, NULL);
/* stop thread */
ret = gst_ring_buffer_release (sink->ringbuffer);
}
return ret;
}
static void
gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
gpointer user_data)
@ -1554,11 +1601,15 @@ gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
basesink = GST_BASE_SINK (user_data);
sink = GST_BASE_AUDIO_SINK (user_data);
GST_PAD_STREAM_LOCK (basesink->sinkpad);
/* would be nice to arrange for pad_alloc_buffer to return data -- as it is we
will copy twice, once into data, once into DMA */
GST_LOG_OBJECT (basesink, "pulling %d bytes offset %" G_GUINT64_FORMAT
" to fill audio buffer", len, basesink->offset);
ret = gst_pad_pull_range (basesink->sinkpad, basesink->offset, len, &buf);
ret =
gst_pad_pull_range (basesink->sinkpad, basesink->segment.last_stop, len,
&buf);
if (ret != GST_FLOW_OK) {
if (ret == GST_FLOW_UNEXPECTED)
@ -1567,15 +1618,27 @@ gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
goto error;
}
GST_PAD_PREROLL_LOCK (basesink->sinkpad);
if (basesink->flushing)
goto flushing;
/* complete preroll and wait for PLAYING */
ret = gst_base_sink_do_preroll (basesink, GST_MINI_OBJECT_CAST (buf));
if (ret != GST_FLOW_OK)
goto preroll_error;
if (len != GST_BUFFER_SIZE (buf)) {
GST_INFO_OBJECT (basesink, "short read pulling from sink pad: %d<%d",
len, GST_BUFFER_SIZE (buf));
len = MIN (GST_BUFFER_SIZE (buf), len);
}
basesink->offset += len;
basesink->segment.last_stop += len;
memcpy (data, GST_BUFFER_DATA (buf), len);
GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
return;
@ -1583,6 +1646,8 @@ error:
{
GST_WARNING_OBJECT (basesink, "Got flow error but can't return it: %d",
ret);
gst_ring_buffer_pause (rbuf);
GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
return;
}
eos:
@ -1594,7 +1659,47 @@ eos:
gst_element_post_message (GST_ELEMENT_CAST (sink),
gst_message_new_eos (GST_OBJECT_CAST (sink)));
gst_base_audio_sink_drain (sink);
gst_ring_buffer_pause (rbuf);
GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
}
flushing:
{
GST_DEBUG_OBJECT (sink, "we are flushing");
gst_ring_buffer_pause (rbuf);
GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
return;
}
preroll_error:
{
GST_DEBUG_OBJECT (sink, "error %s", gst_flow_get_name (ret));
gst_ring_buffer_pause (rbuf);
GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
return;
}
}
static gboolean
gst_base_audio_sink_activate_pull (GstBaseSink * basesink, gboolean active)
{
gboolean ret;
GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (basesink);
if (active) {
GST_DEBUG_OBJECT (basesink, "activating pull");
gst_ring_buffer_set_callback (sink->ringbuffer,
gst_base_audio_sink_callback, sink);
ret = gst_ring_buffer_activate (sink->ringbuffer, TRUE);
} else {
GST_DEBUG_OBJECT (basesink, "deactivating pull");
gst_ring_buffer_set_callback (sink->ringbuffer, NULL, NULL);
ret = gst_ring_buffer_activate (sink->ringbuffer, FALSE);
}
return ret;
}
/* should be called with the LOCK */
@ -1608,6 +1713,10 @@ gst_base_audio_sink_async_play (GstBaseSink * basesink)
GST_DEBUG_OBJECT (sink, "ringbuffer may start now");
sink->priv->sync_latency = TRUE;
gst_ring_buffer_may_start (sink->ringbuffer, TRUE);
if (basesink->pad_mode == GST_ACTIVATE_PULL) {
/* we always start the ringbuffer in pull mode immediatly */
gst_ring_buffer_start (sink->ringbuffer);
}
return GST_STATE_CHANGE_SUCCESS;
}
@ -1676,6 +1785,7 @@ gst_base_audio_sink_change_state (GstElement * element,
gst_clock_set_master (sink->provided_clock, NULL);
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_ring_buffer_activate (sink->ringbuffer, FALSE);
gst_ring_buffer_release (sink->ringbuffer);
break;
case GST_STATE_CHANGE_READY_TO_NULL:
@ -1683,6 +1793,7 @@ gst_base_audio_sink_change_state (GstElement * element,
* caps, which happens before we commit the state to PAUSED and thus the
* PAUSED->READY state change (see above, where we release the ringbuffer)
* might not be called when we get here. */
gst_ring_buffer_activate (sink->ringbuffer, FALSE);
gst_ring_buffer_release (sink->ringbuffer);
gst_ring_buffer_close_device (sink->ringbuffer);
break;

View file

@ -298,7 +298,8 @@ struct _GstRingBuffer {
* @resume: resume processing of samples after pause
* @stop: stop processing of samples
* @delay: get number of samples queued in device
* @activate: activate the thread that starts pulling. Since 0.10.22
* @activate: activate the thread that starts pulling and monitoring the
* consumed segments in the device. Since 0.10.22
*
* The vmethods that subclasses can override to implement the ringbuffer.
*/