mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 09:55:36 +00:00
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:
parent
e4e86b0bad
commit
6eed8ca285
4 changed files with 209 additions and 58 deletions
25
ChangeLog
25
ChangeLog
|
@ -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):
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue