mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
gst-libs/gst/audio/TODO: Updated TODO
Original commit message from CVS: * gst-libs/gst/audio/TODO: Updated TODO * gst-libs/gst/audio/gstaudiosink.c: (gst_audioringbuffer_open_device), (gst_audioringbuffer_close_device), (gst_audioringbuffer_acquire), (gst_audioringbuffer_release): Small cleanups. * gst-libs/gst/audio/gstbaseaudiosink.c: (gst_base_audio_sink_class_init), (gst_base_audio_sink_render), (gst_base_audio_sink_change_state): Slave to the master clock when going to PLAYING and unslave when going to PAUSED. * gst-libs/gst/audio/gstringbuffer.c: (gst_ring_buffer_open_device), (gst_ring_buffer_close_device), (gst_ring_buffer_acquire), (gst_ring_buffer_release), (gst_ring_buffer_samples_done), (gst_ring_buffer_set_sample), (gst_ring_buffer_clear_all), (wait_segment), (gst_ring_buffer_commit), (gst_ring_buffer_read), (gst_ring_buffer_advance): * gst-libs/gst/audio/gstringbuffer.h: Add some docs and cleanups.
This commit is contained in:
parent
0767718887
commit
3f05db1828
6 changed files with 283 additions and 116 deletions
27
ChangeLog
27
ChangeLog
|
@ -1,3 +1,30 @@
|
||||||
|
2005-11-28 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
|
* gst-libs/gst/audio/TODO:
|
||||||
|
Updated TODO
|
||||||
|
|
||||||
|
* gst-libs/gst/audio/gstaudiosink.c:
|
||||||
|
(gst_audioringbuffer_open_device),
|
||||||
|
(gst_audioringbuffer_close_device), (gst_audioringbuffer_acquire),
|
||||||
|
(gst_audioringbuffer_release):
|
||||||
|
Small cleanups.
|
||||||
|
|
||||||
|
* gst-libs/gst/audio/gstbaseaudiosink.c:
|
||||||
|
(gst_base_audio_sink_class_init), (gst_base_audio_sink_render),
|
||||||
|
(gst_base_audio_sink_change_state):
|
||||||
|
Slave to the master clock when going to PLAYING and unslave when
|
||||||
|
going to PAUSED.
|
||||||
|
|
||||||
|
* gst-libs/gst/audio/gstringbuffer.c:
|
||||||
|
(gst_ring_buffer_open_device), (gst_ring_buffer_close_device),
|
||||||
|
(gst_ring_buffer_acquire), (gst_ring_buffer_release),
|
||||||
|
(gst_ring_buffer_samples_done), (gst_ring_buffer_set_sample),
|
||||||
|
(gst_ring_buffer_clear_all), (wait_segment),
|
||||||
|
(gst_ring_buffer_commit), (gst_ring_buffer_read),
|
||||||
|
(gst_ring_buffer_advance):
|
||||||
|
* gst-libs/gst/audio/gstringbuffer.h:
|
||||||
|
Add some docs and cleanups.
|
||||||
|
|
||||||
2005-11-28 Julien MOUTTE <julien@moutte.net>
|
2005-11-28 Julien MOUTTE <julien@moutte.net>
|
||||||
|
|
||||||
* sys/xvimage/xvimagesink.c:
|
* sys/xvimage/xvimagesink.c:
|
||||||
|
|
|
@ -8,3 +8,8 @@ TODO
|
||||||
- implement seek/query/convert
|
- implement seek/query/convert
|
||||||
- implement getrange scheduling
|
- implement getrange scheduling
|
||||||
- on EOS, only post EOS when the complete ringbuffer has been played.
|
- on EOS, only post EOS when the complete ringbuffer has been played.
|
||||||
|
- more accurate clipping of samples outside of the segment
|
||||||
|
- simple resampling
|
||||||
|
- more accurate master/slave calibration handling
|
||||||
|
- faster audio cutoff when going to PAUSED
|
||||||
|
- resubmit samples from ringbuffer when doing PAUSED->PLAYING again
|
||||||
|
|
|
@ -264,6 +264,7 @@ gst_audioringbuffer_open_device (GstRingBuffer * buf)
|
||||||
|
|
||||||
could_not_open:
|
could_not_open:
|
||||||
{
|
{
|
||||||
|
GST_DEBUG ("could not open device");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,12 +283,13 @@ gst_audioringbuffer_close_device (GstRingBuffer * buf)
|
||||||
result = csink->close (sink);
|
result = csink->close (sink);
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
goto could_not_open;
|
goto could_not_close;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
could_not_open:
|
could_not_close:
|
||||||
{
|
{
|
||||||
|
GST_DEBUG ("could not close device");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -307,7 +309,7 @@ gst_audioringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
|
||||||
result = csink->prepare (sink, spec);
|
result = csink->prepare (sink, spec);
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
goto could_not_open;
|
goto could_not_prepare;
|
||||||
|
|
||||||
/* allocate one more segment as we need some headroom */
|
/* allocate one more segment as we need some headroom */
|
||||||
spec->segtotal++;
|
spec->segtotal++;
|
||||||
|
@ -325,8 +327,9 @@ gst_audioringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
could_not_open:
|
could_not_prepare:
|
||||||
{
|
{
|
||||||
|
GST_DEBUG ("could not prepare device");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,7 +363,16 @@ gst_audioringbuffer_release (GstRingBuffer * buf)
|
||||||
if (csink->unprepare)
|
if (csink->unprepare)
|
||||||
result = csink->unprepare (sink);
|
result = csink->unprepare (sink);
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
goto could_not_unprepare;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
could_not_unprepare:
|
||||||
|
{
|
||||||
|
GST_DEBUG ("could not unprepare device");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
|
|
@ -68,8 +68,6 @@ static GstStateChangeReturn gst_base_audio_sink_change_state (GstElement *
|
||||||
element, GstStateChange transition);
|
element, GstStateChange transition);
|
||||||
|
|
||||||
static GstClock *gst_base_audio_sink_provide_clock (GstElement * elem);
|
static GstClock *gst_base_audio_sink_provide_clock (GstElement * elem);
|
||||||
static gboolean gst_base_audio_sink_set_clock (GstElement * elem,
|
|
||||||
GstClock * clock);
|
|
||||||
static GstClockTime gst_base_audio_sink_get_time (GstClock * clock,
|
static GstClockTime gst_base_audio_sink_get_time (GstClock * clock,
|
||||||
GstBaseAudioSink * sink);
|
GstBaseAudioSink * sink);
|
||||||
static void gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data,
|
static void gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data,
|
||||||
|
@ -127,8 +125,6 @@ gst_base_audio_sink_class_init (GstBaseAudioSinkClass * klass)
|
||||||
GST_DEBUG_FUNCPTR (gst_base_audio_sink_change_state);
|
GST_DEBUG_FUNCPTR (gst_base_audio_sink_change_state);
|
||||||
gstelement_class->provide_clock =
|
gstelement_class->provide_clock =
|
||||||
GST_DEBUG_FUNCPTR (gst_base_audio_sink_provide_clock);
|
GST_DEBUG_FUNCPTR (gst_base_audio_sink_provide_clock);
|
||||||
gstelement_class->set_clock =
|
|
||||||
GST_DEBUG_FUNCPTR (gst_base_audio_sink_set_clock);
|
|
||||||
|
|
||||||
gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_base_audio_sink_event);
|
gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_base_audio_sink_event);
|
||||||
gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_base_audio_sink_preroll);
|
gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_base_audio_sink_preroll);
|
||||||
|
@ -184,25 +180,6 @@ gst_base_audio_sink_provide_clock (GstElement * elem)
|
||||||
return clock;
|
return clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_base_audio_sink_set_clock (GstElement * elem, GstClock * clock)
|
|
||||||
{
|
|
||||||
GstBaseAudioSink *sink;
|
|
||||||
gboolean ret;
|
|
||||||
|
|
||||||
sink = GST_BASE_AUDIO_SINK (elem);
|
|
||||||
|
|
||||||
GST_OBJECT_LOCK (sink);
|
|
||||||
if (clock != sink->provided_clock) {
|
|
||||||
ret = gst_clock_set_master (sink->provided_clock, clock);
|
|
||||||
} else {
|
|
||||||
ret = gst_clock_set_master (sink->provided_clock, NULL);
|
|
||||||
}
|
|
||||||
GST_OBJECT_UNLOCK (sink);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstClockTime
|
static GstClockTime
|
||||||
gst_base_audio_sink_get_time (GstClock * clock, GstBaseAudioSink * sink)
|
gst_base_audio_sink_get_time (GstClock * clock, GstBaseAudioSink * sink)
|
||||||
{
|
{
|
||||||
|
@ -593,10 +570,13 @@ gst_base_audio_sink_change_state (GstElement * element,
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
||||||
{
|
{
|
||||||
|
GstClock *clock;
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (sink);
|
||||||
|
clock = GST_ELEMENT_CLOCK (sink);
|
||||||
/* if we are slaved to a clock, we need to set the initial
|
/* if we are slaved to a clock, we need to set the initial
|
||||||
* calibration */
|
* calibration */
|
||||||
/* FIXME, this is not yet accurate enough for smooth playback */
|
if (clock != sink->provided_clock) {
|
||||||
if (gst_clock_get_master (sink->provided_clock)) {
|
|
||||||
GstClockTime time;
|
GstClockTime time;
|
||||||
GstClockTime rate_num, rate_denom;
|
GstClockTime rate_num, rate_denom;
|
||||||
|
|
||||||
|
@ -605,12 +585,15 @@ gst_base_audio_sink_change_state (GstElement * element,
|
||||||
GST_DEBUG_OBJECT (sink, "time: %" GST_TIME_FORMAT,
|
GST_DEBUG_OBJECT (sink, "time: %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (time));
|
GST_TIME_ARGS (time));
|
||||||
|
|
||||||
|
gst_clock_set_master (sink->provided_clock, clock);
|
||||||
|
/* FIXME, this is not yet accurate enough for smooth playback */
|
||||||
gst_clock_get_calibration (sink->provided_clock, NULL, NULL, &rate_num,
|
gst_clock_get_calibration (sink->provided_clock, NULL, NULL, &rate_num,
|
||||||
&rate_denom);
|
&rate_denom);
|
||||||
/* Does not work yet. */
|
/* Does not work yet. */
|
||||||
gst_clock_set_calibration (sink->provided_clock,
|
gst_clock_set_calibration (sink->provided_clock,
|
||||||
time, element->base_time, rate_num, rate_denom);
|
time, element->base_time, rate_num, rate_denom);
|
||||||
}
|
}
|
||||||
|
GST_OBJECT_UNLOCK (sink);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||||
|
@ -625,6 +608,8 @@ gst_base_audio_sink_change_state (GstElement * element,
|
||||||
switch (transition) {
|
switch (transition) {
|
||||||
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
||||||
gst_ring_buffer_pause (sink->ringbuffer);
|
gst_ring_buffer_pause (sink->ringbuffer);
|
||||||
|
/* slop slaving ourselves to the master, if any */
|
||||||
|
gst_clock_set_master (sink->provided_clock, NULL);
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||||
gst_ring_buffer_release (sink->ringbuffer);
|
gst_ring_buffer_release (sink->ringbuffer);
|
||||||
|
|
|
@ -18,6 +18,15 @@
|
||||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
* Boston, MA 02111-1307, USA.
|
* Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* SECTION:gstringbuffer
|
||||||
|
* @short_description: Base class for audio ringbuffer implementations
|
||||||
|
*
|
||||||
|
* This object is the base class for audio ringbuffers used by the base
|
||||||
|
* audio source and sink classes.
|
||||||
|
*
|
||||||
|
* Last reviewed on 2005-11-24 (0.9.6)
|
||||||
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -183,6 +192,12 @@ build_linear_format (int depth, int width, int unsignd, int big_endian)
|
||||||
return ((int (*)[2][2]) linear_formats)[depth][!!unsignd][!!big_endian];
|
return ((int (*)[2][2]) linear_formats)[depth][!!unsignd][!!big_endian];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_ring_buffer_debug_spec_caps:
|
||||||
|
* @spec: the spec to debug
|
||||||
|
*
|
||||||
|
* Print debug info about the parsed caps in @spec to the debug log.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
gst_ring_buffer_debug_spec_caps (GstRingBufferSpec * spec)
|
gst_ring_buffer_debug_spec_caps (GstRingBufferSpec * spec)
|
||||||
{
|
{
|
||||||
|
@ -198,6 +213,12 @@ gst_ring_buffer_debug_spec_caps (GstRingBufferSpec * spec)
|
||||||
GST_DEBUG ("parsed caps: sample bytes: %d", spec->bytes_per_sample);
|
GST_DEBUG ("parsed caps: sample bytes: %d", spec->bytes_per_sample);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_ring_buffer_debug_spec_buff:
|
||||||
|
* @spec: the spec to debug
|
||||||
|
*
|
||||||
|
* Print debug info about the buffer sized in @spec to the debug log.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
gst_ring_buffer_debug_spec_buff (GstRingBufferSpec * spec)
|
gst_ring_buffer_debug_spec_buff (GstRingBufferSpec * spec)
|
||||||
{
|
{
|
||||||
|
@ -213,6 +234,15 @@ gst_ring_buffer_debug_spec_buff (GstRingBufferSpec * spec)
|
||||||
spec->segsize * spec->segtotal / spec->bytes_per_sample);
|
spec->segsize * spec->segtotal / spec->bytes_per_sample);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_ring_buffer_parse_caps:
|
||||||
|
* @spec: a spec
|
||||||
|
* @caps: a #GstCaps
|
||||||
|
*
|
||||||
|
* Parse @caps into @spec.
|
||||||
|
*
|
||||||
|
* Returns: TRUE if the caps could be parsed.
|
||||||
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
gst_ring_buffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps)
|
gst_ring_buffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps)
|
||||||
{
|
{
|
||||||
|
@ -355,11 +385,9 @@ gst_ring_buffer_open_device (GstRingBuffer * buf)
|
||||||
GST_DEBUG_OBJECT (buf, "opening device");
|
GST_DEBUG_OBJECT (buf, "opening device");
|
||||||
|
|
||||||
GST_OBJECT_LOCK (buf);
|
GST_OBJECT_LOCK (buf);
|
||||||
if (buf->open) {
|
if (buf->open)
|
||||||
g_warning ("Device for ring buffer %p already open, fix your code", buf);
|
goto was_opened;
|
||||||
res = TRUE;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
buf->open = TRUE;
|
buf->open = TRUE;
|
||||||
|
|
||||||
/* if this fails, something is wrong in this file */
|
/* if this fails, something is wrong in this file */
|
||||||
|
@ -369,17 +397,30 @@ gst_ring_buffer_open_device (GstRingBuffer * buf)
|
||||||
if (rclass->open_device)
|
if (rclass->open_device)
|
||||||
res = rclass->open_device (buf);
|
res = rclass->open_device (buf);
|
||||||
|
|
||||||
if (!res) {
|
if (!res)
|
||||||
buf->open = FALSE;
|
goto open_failed;
|
||||||
GST_DEBUG_OBJECT (buf, "failed opening device");
|
|
||||||
} else {
|
GST_DEBUG_OBJECT (buf, "opened device");
|
||||||
GST_DEBUG_OBJECT (buf, "opened device");
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
GST_OBJECT_UNLOCK (buf);
|
GST_OBJECT_UNLOCK (buf);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
was_opened:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (buf, "Device for ring buffer already open");
|
||||||
|
g_warning ("Device for ring buffer %p already open, fix your code", buf);
|
||||||
|
res = TRUE;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
open_failed:
|
||||||
|
{
|
||||||
|
buf->open = FALSE;
|
||||||
|
GST_DEBUG_OBJECT (buf, "failed opening device");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -404,17 +445,11 @@ gst_ring_buffer_close_device (GstRingBuffer * buf)
|
||||||
GST_DEBUG_OBJECT (buf, "closing device");
|
GST_DEBUG_OBJECT (buf, "closing device");
|
||||||
|
|
||||||
GST_OBJECT_LOCK (buf);
|
GST_OBJECT_LOCK (buf);
|
||||||
if (!buf->open) {
|
if (!buf->open)
|
||||||
g_warning ("Device for ring buffer %p already closed, fix your code", buf);
|
goto was_closed;
|
||||||
res = TRUE;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buf->acquired) {
|
if (buf->acquired)
|
||||||
g_critical ("Resources for ring buffer %p still acquired", buf);
|
goto was_acquired;
|
||||||
res = FALSE;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf->open = FALSE;
|
buf->open = FALSE;
|
||||||
|
|
||||||
|
@ -422,17 +457,37 @@ gst_ring_buffer_close_device (GstRingBuffer * buf)
|
||||||
if (rclass->close_device)
|
if (rclass->close_device)
|
||||||
res = rclass->close_device (buf);
|
res = rclass->close_device (buf);
|
||||||
|
|
||||||
if (!res) {
|
if (!res)
|
||||||
buf->open = TRUE;
|
goto close_error;
|
||||||
GST_DEBUG_OBJECT (buf, "error closing device");
|
|
||||||
} else {
|
GST_DEBUG_OBJECT (buf, "closed device");
|
||||||
GST_DEBUG_OBJECT (buf, "closed device");
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
GST_OBJECT_UNLOCK (buf);
|
GST_OBJECT_UNLOCK (buf);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
was_closed:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (buf, "Device for ring buffer already closed");
|
||||||
|
g_warning ("Device for ring buffer %p already closed, fix your code", buf);
|
||||||
|
res = TRUE;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
was_acquired:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (buf, "Resources for ring buffer still acquired");
|
||||||
|
g_critical ("Resources for ring buffer %p still acquired", buf);
|
||||||
|
res = FALSE;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
close_error:
|
||||||
|
{
|
||||||
|
buf->open = TRUE;
|
||||||
|
GST_DEBUG_OBJECT (buf, "error closing device");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -480,56 +535,78 @@ gst_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
|
||||||
{
|
{
|
||||||
gboolean res = FALSE;
|
gboolean res = FALSE;
|
||||||
GstRingBufferClass *rclass;
|
GstRingBufferClass *rclass;
|
||||||
|
gint i, j;
|
||||||
|
gint segsize, bps;
|
||||||
|
|
||||||
g_return_val_if_fail (buf != NULL, FALSE);
|
g_return_val_if_fail (buf != NULL, FALSE);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (buf, "acquiring device");
|
GST_DEBUG_OBJECT (buf, "acquiring device");
|
||||||
|
|
||||||
GST_OBJECT_LOCK (buf);
|
GST_OBJECT_LOCK (buf);
|
||||||
if (!buf->open) {
|
if (!buf->open)
|
||||||
g_critical ("Device for %p not opened", buf);
|
goto not_opened;
|
||||||
res = FALSE;
|
|
||||||
goto done;
|
if (buf->acquired)
|
||||||
}
|
goto was_acquired;
|
||||||
if (buf->acquired) {
|
|
||||||
res = TRUE;
|
|
||||||
GST_DEBUG_OBJECT (buf, "device was acquired");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
buf->acquired = TRUE;
|
buf->acquired = TRUE;
|
||||||
|
|
||||||
rclass = GST_RING_BUFFER_GET_CLASS (buf);
|
rclass = GST_RING_BUFFER_GET_CLASS (buf);
|
||||||
if (rclass->acquire)
|
if (rclass->acquire)
|
||||||
res = rclass->acquire (buf, spec);
|
res = rclass->acquire (buf, spec);
|
||||||
|
|
||||||
if (!res) {
|
if (!res)
|
||||||
buf->acquired = FALSE;
|
goto acquire_failed;
|
||||||
GST_DEBUG_OBJECT (buf, "failed to acquire device");
|
|
||||||
} else {
|
|
||||||
if (buf->spec.bytes_per_sample != 0) {
|
|
||||||
gint i, j;
|
|
||||||
|
|
||||||
buf->samples_per_seg = buf->spec.segsize / buf->spec.bytes_per_sample;
|
if ((bps = buf->spec.bytes_per_sample) == 0)
|
||||||
|
goto invalid_bps;
|
||||||
|
|
||||||
/* create an empty segment */
|
segsize = buf->spec.segsize;
|
||||||
g_free (buf->empty_seg);
|
|
||||||
buf->empty_seg = g_malloc (buf->spec.segsize);
|
buf->samples_per_seg = segsize / bps;
|
||||||
for (i = 0, j = 0; i < buf->spec.segsize; i++) {
|
|
||||||
buf->empty_seg[i] = buf->spec.silence_sample[j];
|
/* create an empty segment */
|
||||||
j = (j + 1) % buf->spec.bytes_per_sample;
|
g_free (buf->empty_seg);
|
||||||
}
|
buf->empty_seg = g_malloc (segsize);
|
||||||
GST_DEBUG_OBJECT (buf, "acquired device");
|
for (i = 0, j = 0; i < segsize; i++) {
|
||||||
} else {
|
buf->empty_seg[i] = buf->spec.silence_sample[j];
|
||||||
g_warning
|
j = (j + 1) % bps;
|
||||||
("invalid bytes_per_sample from acquire ringbuffer, fix the element");
|
|
||||||
buf->acquired = FALSE;
|
|
||||||
res = FALSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
GST_DEBUG_OBJECT (buf, "acquired device");
|
||||||
|
|
||||||
done:
|
done:
|
||||||
GST_OBJECT_UNLOCK (buf);
|
GST_OBJECT_UNLOCK (buf);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
not_opened:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (buf, "device not opened");
|
||||||
|
g_critical ("Device for %p not opened", buf);
|
||||||
|
res = FALSE;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
was_acquired:
|
||||||
|
{
|
||||||
|
res = TRUE;
|
||||||
|
GST_DEBUG_OBJECT (buf, "device was acquired");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
acquire_failed:
|
||||||
|
{
|
||||||
|
buf->acquired = FALSE;
|
||||||
|
GST_DEBUG_OBJECT (buf, "failed to acquire device");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
invalid_bps:
|
||||||
|
{
|
||||||
|
g_warning
|
||||||
|
("invalid bytes_per_sample from acquire ringbuffer, fix the element");
|
||||||
|
buf->acquired = FALSE;
|
||||||
|
res = FALSE;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -555,11 +632,9 @@ gst_ring_buffer_release (GstRingBuffer * buf)
|
||||||
gst_ring_buffer_stop (buf);
|
gst_ring_buffer_stop (buf);
|
||||||
|
|
||||||
GST_OBJECT_LOCK (buf);
|
GST_OBJECT_LOCK (buf);
|
||||||
if (!buf->acquired) {
|
if (!buf->acquired)
|
||||||
res = TRUE;
|
goto was_released;
|
||||||
GST_DEBUG_OBJECT (buf, "device was released");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
buf->acquired = FALSE;
|
buf->acquired = FALSE;
|
||||||
|
|
||||||
/* if this fails, something is wrong in this file */
|
/* if this fails, something is wrong in this file */
|
||||||
|
@ -572,19 +647,31 @@ gst_ring_buffer_release (GstRingBuffer * buf)
|
||||||
/* signal any waiters */
|
/* signal any waiters */
|
||||||
GST_RING_BUFFER_SIGNAL (buf);
|
GST_RING_BUFFER_SIGNAL (buf);
|
||||||
|
|
||||||
if (!res) {
|
if (!res)
|
||||||
buf->acquired = TRUE;
|
goto release_failed;
|
||||||
GST_DEBUG_OBJECT (buf, "failed to release device");
|
|
||||||
} else {
|
g_free (buf->empty_seg);
|
||||||
g_free (buf->empty_seg);
|
buf->empty_seg = NULL;
|
||||||
buf->empty_seg = NULL;
|
GST_DEBUG_OBJECT (buf, "released device");
|
||||||
GST_DEBUG_OBJECT (buf, "released device");
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
GST_OBJECT_UNLOCK (buf);
|
GST_OBJECT_UNLOCK (buf);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
was_released:
|
||||||
|
{
|
||||||
|
res = TRUE;
|
||||||
|
GST_DEBUG_OBJECT (buf, "device was released");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
release_failed:
|
||||||
|
{
|
||||||
|
buf->acquired = TRUE;
|
||||||
|
GST_DEBUG_OBJECT (buf, "failed to release device");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -891,8 +978,8 @@ gst_ring_buffer_samples_done (GstRingBuffer * buf)
|
||||||
if (samples >= delay)
|
if (samples >= delay)
|
||||||
samples -= delay;
|
samples -= delay;
|
||||||
|
|
||||||
GST_DEBUG ("processed samples: raw %llu, delay %u, real %llu", raw, delay,
|
GST_DEBUG_OBJECT (buf, "processed samples: raw %llu, delay %u, real %llu",
|
||||||
samples);
|
raw, delay, samples);
|
||||||
|
|
||||||
return samples;
|
return samples;
|
||||||
}
|
}
|
||||||
|
@ -929,7 +1016,8 @@ gst_ring_buffer_set_sample (GstRingBuffer * buf, guint64 sample)
|
||||||
|
|
||||||
gst_ring_buffer_clear_all (buf);
|
gst_ring_buffer_clear_all (buf);
|
||||||
|
|
||||||
GST_DEBUG ("set sample to %llu, segbase %d", sample, buf->segbase);
|
GST_DEBUG_OBJECT (buf, "set sample to %llu, segbase %d", sample,
|
||||||
|
buf->segbase);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -951,7 +1039,7 @@ gst_ring_buffer_clear_all (GstRingBuffer * buf)
|
||||||
if (buf->spec.segtotal <= 0)
|
if (buf->spec.segtotal <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GST_DEBUG ("clear all segments");
|
GST_DEBUG_OBJECT (buf, "clear all segments");
|
||||||
|
|
||||||
for (i = 0; i < buf->spec.segtotal; i++) {
|
for (i = 0; i < buf->spec.segtotal; i++) {
|
||||||
gst_ring_buffer_clear (buf, i);
|
gst_ring_buffer_clear (buf, i);
|
||||||
|
@ -964,7 +1052,7 @@ wait_segment (GstRingBuffer * buf)
|
||||||
{
|
{
|
||||||
/* buffer must be started now or we deadlock since nobody is reading */
|
/* buffer must be started now or we deadlock since nobody is reading */
|
||||||
if (g_atomic_int_get (&buf->state) != GST_RING_BUFFER_STATE_STARTED) {
|
if (g_atomic_int_get (&buf->state) != GST_RING_BUFFER_STATE_STARTED) {
|
||||||
GST_DEBUG ("start!");
|
GST_DEBUG_OBJECT (buf, "start!");
|
||||||
gst_ring_buffer_start (buf);
|
gst_ring_buffer_start (buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -974,7 +1062,7 @@ wait_segment (GstRingBuffer * buf)
|
||||||
goto flushing;
|
goto flushing;
|
||||||
|
|
||||||
if (g_atomic_int_compare_and_exchange (&buf->waiting, 0, 1)) {
|
if (g_atomic_int_compare_and_exchange (&buf->waiting, 0, 1)) {
|
||||||
GST_DEBUG ("waiting..");
|
GST_DEBUG_OBJECT (buf, "waiting..");
|
||||||
if (g_atomic_int_get (&buf->state) != GST_RING_BUFFER_STATE_STARTED)
|
if (g_atomic_int_get (&buf->state) != GST_RING_BUFFER_STATE_STARTED)
|
||||||
goto not_started;
|
goto not_started;
|
||||||
|
|
||||||
|
@ -993,13 +1081,13 @@ wait_segment (GstRingBuffer * buf)
|
||||||
not_started:
|
not_started:
|
||||||
{
|
{
|
||||||
GST_OBJECT_UNLOCK (buf);
|
GST_OBJECT_UNLOCK (buf);
|
||||||
GST_DEBUG ("stopped processing");
|
GST_DEBUG_OBJECT (buf, "stopped processing");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
flushing:
|
flushing:
|
||||||
{
|
{
|
||||||
GST_OBJECT_UNLOCK (buf);
|
GST_OBJECT_UNLOCK (buf);
|
||||||
GST_DEBUG ("flushing");
|
GST_DEBUG_OBJECT (buf, "flushing");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1016,7 +1104,7 @@ flushing:
|
||||||
* the ringbuffer.
|
* the ringbuffer.
|
||||||
*
|
*
|
||||||
* @len not needs to be a multiple of the segment size of the ringbuffer
|
* @len not needs to be a multiple of the segment size of the ringbuffer
|
||||||
* although it is recommended.
|
* although it is recommended for optimal performance.
|
||||||
*
|
*
|
||||||
* Returns: The number of samples written to the ringbuffer or -1 on
|
* Returns: The number of samples written to the ringbuffer or -1 on
|
||||||
* error.
|
* error.
|
||||||
|
@ -1086,7 +1174,7 @@ gst_ring_buffer_commit (GstRingBuffer * buf, guint64 sample, guchar * data,
|
||||||
writeseg = writeseg % segtotal;
|
writeseg = writeseg % segtotal;
|
||||||
sampleslen = MIN (sps - sampleoff, len);
|
sampleslen = MIN (sps - sampleoff, len);
|
||||||
|
|
||||||
GST_DEBUG ("write @%p seg %d, off %d, len %d",
|
GST_DEBUG_OBJECT (buf, "write @%p seg %d, off %d, len %d",
|
||||||
dest + writeseg * segsize, writeseg, sampleoff, sampleslen);
|
dest + writeseg * segsize, writeseg, sampleoff, sampleslen);
|
||||||
|
|
||||||
memcpy (dest + (writeseg * segsize) + (sampleoff * bps), data,
|
memcpy (dest + (writeseg * segsize) + (sampleoff * bps), data,
|
||||||
|
@ -1103,7 +1191,7 @@ gst_ring_buffer_commit (GstRingBuffer * buf, guint64 sample, guchar * data,
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
not_started:
|
not_started:
|
||||||
{
|
{
|
||||||
GST_DEBUG ("stopped processing");
|
GST_DEBUG_OBJECT (buf, "stopped processing");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1198,7 +1286,7 @@ gst_ring_buffer_read (GstRingBuffer * buf, guint64 sample, guchar * data,
|
||||||
readseg = readseg % segtotal;
|
readseg = readseg % segtotal;
|
||||||
sampleslen = MIN (sps - sampleoff, len);
|
sampleslen = MIN (sps - sampleoff, len);
|
||||||
|
|
||||||
GST_DEBUG ("read @%p seg %d, off %d, len %d",
|
GST_DEBUG_OBJECT (buf, "read @%p seg %d, off %d, len %d",
|
||||||
dest + readseg * segsize, readseg, sampleoff, sampleslen);
|
dest + readseg * segsize, readseg, sampleoff, sampleslen);
|
||||||
|
|
||||||
memcpy (data, dest + (readseg * segsize) + (sampleoff * bps),
|
memcpy (data, dest + (readseg * segsize) + (sampleoff * bps),
|
||||||
|
@ -1215,7 +1303,7 @@ gst_ring_buffer_read (GstRingBuffer * buf, guint64 sample, guchar * data,
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
not_started:
|
not_started:
|
||||||
{
|
{
|
||||||
GST_DEBUG ("stopped processing");
|
GST_DEBUG_OBJECT (buf, "stopped processing");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1293,7 +1381,7 @@ gst_ring_buffer_advance (GstRingBuffer * buf, guint advance)
|
||||||
* waiting for the signal */
|
* waiting for the signal */
|
||||||
if (g_atomic_int_compare_and_exchange (&buf->waiting, 1, 0)) {
|
if (g_atomic_int_compare_and_exchange (&buf->waiting, 1, 0)) {
|
||||||
GST_OBJECT_LOCK (buf);
|
GST_OBJECT_LOCK (buf);
|
||||||
GST_DEBUG ("signal waiter");
|
GST_DEBUG_OBJECT (buf, "signal waiter");
|
||||||
GST_RING_BUFFER_SIGNAL (buf);
|
GST_RING_BUFFER_SIGNAL (buf);
|
||||||
GST_OBJECT_UNLOCK (buf);
|
GST_OBJECT_UNLOCK (buf);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,12 +41,29 @@ typedef struct _GstRingBufferSpec GstRingBufferSpec;
|
||||||
/* called to fill data with len bytes of samples */
|
/* called to fill data with len bytes of samples */
|
||||||
typedef void (*GstRingBufferCallback) (GstRingBuffer *rbuf, guint8* data, guint len, gpointer user_data);
|
typedef void (*GstRingBufferCallback) (GstRingBuffer *rbuf, guint8* data, guint len, gpointer user_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstRingBufferState:
|
||||||
|
* @GST_RING_BUFFER_STATE_STOPPED: The ringbuffer is stopped
|
||||||
|
* @GST_RING_BUFFER_STATE_PAUSED: The ringbuffer is paused
|
||||||
|
* @GST_RING_BUFFER_STATE_STARTED: The ringbuffer is started
|
||||||
|
*
|
||||||
|
* The state of the ringbuffer.
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GST_RING_BUFFER_STATE_STOPPED,
|
GST_RING_BUFFER_STATE_STOPPED,
|
||||||
GST_RING_BUFFER_STATE_PAUSED,
|
GST_RING_BUFFER_STATE_PAUSED,
|
||||||
GST_RING_BUFFER_STATE_STARTED,
|
GST_RING_BUFFER_STATE_STARTED,
|
||||||
} GstRingBufferState;
|
} GstRingBufferState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstRingBufferSegState:
|
||||||
|
* @GST_SEGSTATE_INVALID: The content of the segment is invalid
|
||||||
|
* @GST_SEGSTATE_EMPTY: The segment is empty
|
||||||
|
* @GST_SEGSTATE_FILLED: The segment contains valid data
|
||||||
|
* @GST_SEGSTATE_PARTIAL: The segment partially contains valid data
|
||||||
|
*
|
||||||
|
* The state of a segment in the ringbuffer.
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GST_SEGSTATE_INVALID,
|
GST_SEGSTATE_INVALID,
|
||||||
GST_SEGSTATE_EMPTY,
|
GST_SEGSTATE_EMPTY,
|
||||||
|
@ -54,6 +71,18 @@ typedef enum {
|
||||||
GST_SEGSTATE_PARTIAL,
|
GST_SEGSTATE_PARTIAL,
|
||||||
} GstRingBufferSegState;
|
} GstRingBufferSegState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstBufferFormatType:
|
||||||
|
* @GST_BUFTYPE_LINEAR: samples in linear PCM
|
||||||
|
* @GST_BUFTYPE_FLOAT: samples in float
|
||||||
|
* @GST_BUFTYPE_MU_LAW: samples in mulaw
|
||||||
|
* @GST_BUFTYPE_A_LAW: samples in alaw
|
||||||
|
* @GST_BUFTYPE_IMA_ADPCM: samples in ima adpcm
|
||||||
|
* @GST_BUFTYPE_MPEG: samples in mpeg audio format
|
||||||
|
* @GST_BUFTYPE_GSM: samples in gsm format
|
||||||
|
*
|
||||||
|
* The format of the samples in the ringbuffer.
|
||||||
|
*/
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
GST_BUFTYPE_LINEAR,
|
GST_BUFTYPE_LINEAR,
|
||||||
|
@ -116,8 +145,29 @@ typedef enum
|
||||||
|
|
||||||
} GstBufferFormat;
|
} GstBufferFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstRingBufferSpec:
|
||||||
|
* @caps: The caps that generated the Spec.
|
||||||
|
* @type: the sample type
|
||||||
|
* @format: the sample format
|
||||||
|
* @sign: the sample sign
|
||||||
|
* @bigend: the endianness of the samples
|
||||||
|
* @width: the width of the samples
|
||||||
|
* @depth: th depth of the samples
|
||||||
|
* @rate: the samplerate
|
||||||
|
* @channels: the number of channels
|
||||||
|
* @latency_time: the latency in time units
|
||||||
|
* @buffer_time: the total buffer size in time units
|
||||||
|
* @segsize: the size of one segment in bytes
|
||||||
|
* @segtotal: the total number of segments
|
||||||
|
* @bytes_per_sample: number of bytes in one sample
|
||||||
|
* @silence_sample: bytes representing one sample of silence
|
||||||
|
*
|
||||||
|
* The structure containing the format specification of the ringbuffer.
|
||||||
|
*/
|
||||||
struct _GstRingBufferSpec
|
struct _GstRingBufferSpec
|
||||||
{
|
{
|
||||||
|
/*< public >*/
|
||||||
/* in */
|
/* in */
|
||||||
GstCaps *caps; /* the caps of the buffer */
|
GstCaps *caps; /* the caps of the buffer */
|
||||||
|
|
||||||
|
@ -215,8 +265,8 @@ void gst_ring_buffer_set_callback (GstRingBuffer *buf, GstRingBufferCall
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
gboolean gst_ring_buffer_parse_caps (GstRingBufferSpec *spec, GstCaps *caps);
|
gboolean gst_ring_buffer_parse_caps (GstRingBufferSpec *spec, GstCaps *caps);
|
||||||
void gst_ring_buffer_debug_spec_caps (GstRingBufferSpec *spec);
|
void gst_ring_buffer_debug_spec_caps (GstRingBufferSpec *spec);
|
||||||
void gst_ring_buffer_debug_spec_buff (GstRingBufferSpec *spec);
|
void gst_ring_buffer_debug_spec_buff (GstRingBufferSpec *spec);
|
||||||
|
|
||||||
/* device state */
|
/* device state */
|
||||||
gboolean gst_ring_buffer_open_device (GstRingBuffer *buf);
|
gboolean gst_ring_buffer_open_device (GstRingBuffer *buf);
|
||||||
|
|
Loading…
Reference in a new issue