mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
gst-libs/gst/audio/: Do the delay calculation in the source/sink base classes as this is specific for the capture/pla...
Original commit message from CVS: * gst-libs/gst/audio/gstbaseaudiosink.c: (gst_base_audio_sink_get_time), (gst_base_audio_sink_callback): * gst-libs/gst/audio/gstbaseaudiosrc.c: (gst_base_audio_src_get_time), (gst_base_audio_src_fixate), (gst_base_audio_src_get_times), (gst_base_audio_src_get_offset), (gst_base_audio_src_create), (gst_base_audio_src_change_state): Do the delay calculation in the source/sink base classes as this is specific for the capture/playback mode. Try to fixate a bit better, like round depth up to a multiple of 8 bigger than width. Handle underruns correctly by marking DISCONT on buffers and adjusting timestamps to handle the gap. Set offset/offset_end correctly on buffers. * gst-libs/gst/audio/gstringbuffer.c: (gst_ring_buffer_pause), (gst_ring_buffer_samples_done), (gst_ring_buffer_commit), (gst_ring_buffer_read): Remove resync and underrun recovery from the ringbuffer. Fix ringbuffer read code on under/overrun.
This commit is contained in:
parent
102ec386b1
commit
65b1938b38
4 changed files with 163 additions and 65 deletions
22
ChangeLog
22
ChangeLog
|
@ -1,3 +1,25 @@
|
||||||
|
2006-09-15 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
|
* gst-libs/gst/audio/gstbaseaudiosink.c:
|
||||||
|
(gst_base_audio_sink_get_time), (gst_base_audio_sink_callback):
|
||||||
|
* gst-libs/gst/audio/gstbaseaudiosrc.c:
|
||||||
|
(gst_base_audio_src_get_time), (gst_base_audio_src_fixate),
|
||||||
|
(gst_base_audio_src_get_times), (gst_base_audio_src_get_offset),
|
||||||
|
(gst_base_audio_src_create), (gst_base_audio_src_change_state):
|
||||||
|
Do the delay calculation in the source/sink base classes as this is
|
||||||
|
specific for the capture/playback mode.
|
||||||
|
Try to fixate a bit better, like round depth up to a multiple of 8
|
||||||
|
bigger than width.
|
||||||
|
Handle underruns correctly by marking DISCONT on buffers and adjusting
|
||||||
|
timestamps to handle the gap.
|
||||||
|
Set offset/offset_end correctly on buffers.
|
||||||
|
|
||||||
|
* gst-libs/gst/audio/gstringbuffer.c: (gst_ring_buffer_pause),
|
||||||
|
(gst_ring_buffer_samples_done), (gst_ring_buffer_commit),
|
||||||
|
(gst_ring_buffer_read):
|
||||||
|
Remove resync and underrun recovery from the ringbuffer.
|
||||||
|
Fix ringbuffer read code on under/overrun.
|
||||||
|
|
||||||
2006-09-15 Wim Taymans <wim@fluendo.com>
|
2006-09-15 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
* gst/playback/gstplaybasebin.c: (gst_play_base_bin_class_init),
|
* gst/playback/gstplaybasebin.c: (gst_play_base_bin_class_init),
|
||||||
|
|
|
@ -91,7 +91,7 @@ static void gst_base_audio_sink_get_times (GstBaseSink * bsink,
|
||||||
static gboolean gst_base_audio_sink_setcaps (GstBaseSink * bsink,
|
static gboolean gst_base_audio_sink_setcaps (GstBaseSink * bsink,
|
||||||
GstCaps * caps);
|
GstCaps * caps);
|
||||||
|
|
||||||
//static guint gst_base_audio_sink_signals[LAST_SIGNAL] = { 0 };
|
/* static guint gst_base_audio_sink_signals[LAST_SIGNAL] = { 0 }; */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_base_audio_sink_base_init (gpointer g_class)
|
gst_base_audio_sink_base_init (gpointer g_class)
|
||||||
|
@ -217,18 +217,32 @@ clock_disabled:
|
||||||
static GstClockTime
|
static GstClockTime
|
||||||
gst_base_audio_sink_get_time (GstClock * clock, GstBaseAudioSink * sink)
|
gst_base_audio_sink_get_time (GstClock * clock, GstBaseAudioSink * sink)
|
||||||
{
|
{
|
||||||
guint64 samples;
|
guint64 raw, samples;
|
||||||
|
guint delay;
|
||||||
GstClockTime result;
|
GstClockTime result;
|
||||||
|
|
||||||
if (sink->ringbuffer == NULL || sink->ringbuffer->spec.rate == 0)
|
if (sink->ringbuffer == NULL || sink->ringbuffer->spec.rate == 0)
|
||||||
return GST_CLOCK_TIME_NONE;
|
return GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
/* our processed samples are always increasing */
|
/* our processed samples are always increasing */
|
||||||
samples = gst_ring_buffer_samples_done (sink->ringbuffer);
|
raw = samples = gst_ring_buffer_samples_done (sink->ringbuffer);
|
||||||
|
|
||||||
|
/* the number of samples not yet processed, this is still queued in the
|
||||||
|
* device (not played for playback). */
|
||||||
|
delay = gst_ring_buffer_delay (sink->ringbuffer);
|
||||||
|
|
||||||
|
if (G_LIKELY (samples >= delay))
|
||||||
|
samples -= delay;
|
||||||
|
else
|
||||||
|
samples = 0;
|
||||||
|
|
||||||
result = gst_util_uint64_scale_int (samples, GST_SECOND,
|
result = gst_util_uint64_scale_int (samples, GST_SECOND,
|
||||||
sink->ringbuffer->spec.rate);
|
sink->ringbuffer->spec.rate);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (sink,
|
||||||
|
"processed samples: raw %llu, delay %u, real %llu, time %"
|
||||||
|
GST_TIME_FORMAT, raw, delay, samples, GST_TIME_ARGS (result));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -707,7 +721,7 @@ static void
|
||||||
gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
|
gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
//GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (data);
|
/* GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (data); */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* should be called with the LOCK */
|
/* should be called with the LOCK */
|
||||||
|
|
|
@ -75,7 +75,7 @@ static void gst_base_audio_src_get_times (GstBaseSrc * bsrc,
|
||||||
GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
|
GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
|
||||||
static gboolean gst_base_audio_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps);
|
static gboolean gst_base_audio_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps);
|
||||||
|
|
||||||
//static guint gst_base_audio_src_signals[LAST_SIGNAL] = { 0 };
|
/* static guint gst_base_audio_src_signals[LAST_SIGNAL] = { 0 }; */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_base_audio_src_base_init (gpointer g_class)
|
gst_base_audio_src_base_init (gpointer g_class)
|
||||||
|
@ -201,17 +201,28 @@ wrong_state:
|
||||||
static GstClockTime
|
static GstClockTime
|
||||||
gst_base_audio_src_get_time (GstClock * clock, GstBaseAudioSrc * src)
|
gst_base_audio_src_get_time (GstClock * clock, GstBaseAudioSrc * src)
|
||||||
{
|
{
|
||||||
guint64 samples;
|
guint64 raw, samples;
|
||||||
|
guint delay;
|
||||||
GstClockTime result;
|
GstClockTime result;
|
||||||
|
|
||||||
if (G_UNLIKELY (src->ringbuffer == NULL || src->ringbuffer->spec.rate == 0))
|
if (G_UNLIKELY (src->ringbuffer == NULL || src->ringbuffer->spec.rate == 0))
|
||||||
return GST_CLOCK_TIME_NONE;
|
return GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
samples = gst_ring_buffer_samples_done (src->ringbuffer);
|
raw = samples = gst_ring_buffer_samples_done (src->ringbuffer);
|
||||||
|
|
||||||
|
/* the number of samples not yet processed, this is still queued in the
|
||||||
|
* device (not yet read for capture). */
|
||||||
|
delay = gst_ring_buffer_delay (src->ringbuffer);
|
||||||
|
|
||||||
|
samples += delay;
|
||||||
|
|
||||||
result = gst_util_uint64_scale_int (samples, GST_SECOND,
|
result = gst_util_uint64_scale_int (samples, GST_SECOND,
|
||||||
src->ringbuffer->spec.rate);
|
src->ringbuffer->spec.rate);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (src,
|
||||||
|
"processed samples: raw %llu, delay %u, real %llu, time %"
|
||||||
|
GST_TIME_FORMAT, raw, delay, samples, GST_TIME_ARGS (result));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,14 +282,24 @@ static void
|
||||||
gst_base_audio_src_fixate (GstPad * pad, GstCaps * caps)
|
gst_base_audio_src_fixate (GstPad * pad, GstCaps * caps)
|
||||||
{
|
{
|
||||||
GstStructure *s;
|
GstStructure *s;
|
||||||
|
gint width, depth;
|
||||||
|
|
||||||
s = gst_caps_get_structure (caps, 0);
|
s = gst_caps_get_structure (caps, 0);
|
||||||
|
|
||||||
|
/* fields for all formats */
|
||||||
gst_structure_fixate_field_nearest_int (s, "rate", 44100);
|
gst_structure_fixate_field_nearest_int (s, "rate", 44100);
|
||||||
gst_structure_fixate_field_nearest_int (s, "channels", 2);
|
gst_structure_fixate_field_nearest_int (s, "channels", 2);
|
||||||
gst_structure_fixate_field_nearest_int (s, "depth", 16);
|
|
||||||
gst_structure_fixate_field_nearest_int (s, "width", 16);
|
gst_structure_fixate_field_nearest_int (s, "width", 16);
|
||||||
gst_structure_set (s, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
|
|
||||||
|
/* fields for int */
|
||||||
|
if (gst_structure_has_field (s, "depth")) {
|
||||||
|
gst_structure_get_int (s, "width", &width);
|
||||||
|
/* round width to nearest multiple of 8 for the depth */
|
||||||
|
depth = GST_ROUND_UP_8 (width);
|
||||||
|
gst_structure_fixate_field_nearest_int (s, "depth", depth);
|
||||||
|
}
|
||||||
|
if (gst_structure_has_field (s, "signed"))
|
||||||
|
gst_structure_fixate_field_boolean (s, "signed", TRUE);
|
||||||
if (gst_structure_has_field (s, "endianness"))
|
if (gst_structure_has_field (s, "endianness"))
|
||||||
gst_structure_fixate_field_nearest_int (s, "endianness", G_BYTE_ORDER);
|
gst_structure_fixate_field_nearest_int (s, "endianness", G_BYTE_ORDER);
|
||||||
}
|
}
|
||||||
|
@ -341,9 +362,8 @@ static void
|
||||||
gst_base_audio_src_get_times (GstBaseSrc * bsrc, GstBuffer * buffer,
|
gst_base_audio_src_get_times (GstBaseSrc * bsrc, GstBuffer * buffer,
|
||||||
GstClockTime * start, GstClockTime * end)
|
GstClockTime * start, GstClockTime * end)
|
||||||
{
|
{
|
||||||
/* ne need to sync to a clock here, we schedule the samples based
|
/* no need to sync to a clock here, we schedule the samples based
|
||||||
* on our own clock for the moment. FIXME, implement this when
|
* on our own clock for the moment. */
|
||||||
* we are not using our own clock */
|
|
||||||
*start = GST_CLOCK_TIME_NONE;
|
*start = GST_CLOCK_TIME_NONE;
|
||||||
*end = GST_CLOCK_TIME_NONE;
|
*end = GST_CLOCK_TIME_NONE;
|
||||||
}
|
}
|
||||||
|
@ -369,6 +389,45 @@ gst_base_audio_src_event (GstBaseSrc * bsrc, GstEvent * event)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* get the next offset in the ringbuffer for reading samples.
|
||||||
|
* If the next sample is too far away, this function will position itself to the
|
||||||
|
* next most recent sample, creating discontinuity */
|
||||||
|
static guint64
|
||||||
|
gst_base_audio_src_get_offset (GstBaseAudioSrc * src)
|
||||||
|
{
|
||||||
|
guint64 sample;
|
||||||
|
gint readseg, segdone, segtotal, sps;
|
||||||
|
gint diff;
|
||||||
|
|
||||||
|
/* assume we can append to the previous sample */
|
||||||
|
sample = src->next_sample;
|
||||||
|
/* no previous sample, try to read from position 0 */
|
||||||
|
if (sample == -1)
|
||||||
|
sample = 0;
|
||||||
|
|
||||||
|
sps = src->ringbuffer->samples_per_seg;
|
||||||
|
segtotal = src->ringbuffer->spec.segtotal;
|
||||||
|
|
||||||
|
/* figure out the segment and the offset inside the segment where
|
||||||
|
* the sample should be read from. */
|
||||||
|
readseg = sample / sps;
|
||||||
|
|
||||||
|
/* get the currently processed segment */
|
||||||
|
segdone = g_atomic_int_get (&src->ringbuffer->segdone)
|
||||||
|
- src->ringbuffer->segbase;
|
||||||
|
|
||||||
|
/* see how far away it is from the read segment, normally segdone (where new
|
||||||
|
* data is written in the ringbuffer) is bigger than readseg (where we are
|
||||||
|
* reading). */
|
||||||
|
diff = segdone - readseg;
|
||||||
|
if (diff >= segtotal) {
|
||||||
|
/* sample would be dropped, position to next playable position */
|
||||||
|
sample = (segdone - segtotal + 1) * sps;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sample;
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
|
gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
|
||||||
GstBuffer ** outbuf)
|
GstBuffer ** outbuf)
|
||||||
|
@ -396,14 +455,17 @@ gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
|
||||||
/* make sure we round down to an integral number of samples */
|
/* make sure we round down to an integral number of samples */
|
||||||
length -= length % bps;
|
length -= length % bps;
|
||||||
|
|
||||||
/* calculate the sequentially next sample we need to read */
|
/* figure out the offset in the ringbuffer */
|
||||||
sample = (src->next_sample != -1 ? src->next_sample : 0);
|
|
||||||
|
|
||||||
if (G_UNLIKELY (offset != -1)) {
|
if (G_UNLIKELY (offset != -1)) {
|
||||||
/* if a specific offset was given it must be the next
|
sample = offset / bps;
|
||||||
* sequential offset we expect or we fail. */
|
/* if a specific offset was given it must be the next sequential
|
||||||
if (offset / bps != sample)
|
* offset we expect or we fail for now. */
|
||||||
|
if (src->next_sample != -1 && sample != src->next_sample)
|
||||||
goto wrong_offset;
|
goto wrong_offset;
|
||||||
|
} else {
|
||||||
|
/* calculate the sequentially next sample we need to read. This can jump and
|
||||||
|
* create a DISCONT. */
|
||||||
|
sample = gst_base_audio_src_get_offset (src);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get the number of samples to read */
|
/* get the number of samples to read */
|
||||||
|
@ -413,10 +475,19 @@ gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
|
||||||
buf = gst_buffer_new_and_alloc (length);
|
buf = gst_buffer_new_and_alloc (length);
|
||||||
data = GST_BUFFER_DATA (buf);
|
data = GST_BUFFER_DATA (buf);
|
||||||
|
|
||||||
|
/* read the sample */
|
||||||
res = gst_ring_buffer_read (ringbuffer, sample, data, samples);
|
res = gst_ring_buffer_read (ringbuffer, sample, data, samples);
|
||||||
if (G_UNLIKELY (res == -1))
|
if (G_UNLIKELY (res == -1))
|
||||||
goto stopped;
|
goto stopped;
|
||||||
|
|
||||||
|
/* mark discontinuity if needed */
|
||||||
|
if (G_UNLIKELY (sample != src->next_sample) && src->next_sample != -1) {
|
||||||
|
GST_WARNING_OBJECT (src,
|
||||||
|
"create DISCONT of %" G_GUINT64_FORMAT " samples at sample %"
|
||||||
|
G_GUINT64_FORMAT, sample - src->next_sample, sample);
|
||||||
|
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
|
||||||
|
}
|
||||||
|
|
||||||
/* FIXME, we timestamp against our own clock, also handle the case
|
/* FIXME, we timestamp against our own clock, also handle the case
|
||||||
* where we are slaved to another clock. We currently refuse to accept
|
* where we are slaved to another clock. We currently refuse to accept
|
||||||
* any other clock than the one we provide, so this code is fine for
|
* any other clock than the one we provide, so this code is fine for
|
||||||
|
@ -426,6 +497,8 @@ gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
|
||||||
src->next_sample = sample + samples;
|
src->next_sample = sample + samples;
|
||||||
GST_BUFFER_DURATION (buf) = gst_util_uint64_scale_int (src->next_sample,
|
GST_BUFFER_DURATION (buf) = gst_util_uint64_scale_int (src->next_sample,
|
||||||
GST_SECOND, ringbuffer->spec.rate) - GST_BUFFER_TIMESTAMP (buf);
|
GST_SECOND, ringbuffer->spec.rate) - GST_BUFFER_TIMESTAMP (buf);
|
||||||
|
GST_BUFFER_OFFSET (buf) = sample;
|
||||||
|
GST_BUFFER_OFFSET_END (buf) = sample + samples;
|
||||||
|
|
||||||
gst_buffer_set_caps (buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (bsrc)));
|
gst_buffer_set_caps (buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (bsrc)));
|
||||||
|
|
||||||
|
@ -470,13 +543,6 @@ gst_base_audio_src_create_ringbuffer (GstBaseAudioSrc * src)
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
gst_base_audio_src_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
//GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstStateChangeReturn
|
static GstStateChangeReturn
|
||||||
gst_base_audio_src_change_state (GstElement * element,
|
gst_base_audio_src_change_state (GstElement * element,
|
||||||
GstStateChange transition)
|
GstStateChange transition)
|
||||||
|
@ -488,12 +554,10 @@ gst_base_audio_src_change_state (GstElement * element,
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||||
if (src->ringbuffer == NULL) {
|
if (src->ringbuffer == NULL) {
|
||||||
src->ringbuffer = gst_base_audio_src_create_ringbuffer (src);
|
src->ringbuffer = gst_base_audio_src_create_ringbuffer (src);
|
||||||
gst_ring_buffer_set_callback (src->ringbuffer,
|
|
||||||
gst_base_audio_src_callback, src);
|
|
||||||
}
|
}
|
||||||
if (!gst_ring_buffer_open_device (src->ringbuffer))
|
if (!gst_ring_buffer_open_device (src->ringbuffer))
|
||||||
return GST_STATE_CHANGE_FAILURE;
|
return GST_STATE_CHANGE_FAILURE;
|
||||||
src->next_sample = 0;
|
src->next_sample = -1;
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||||
gst_ring_buffer_set_flushing (src->ringbuffer, FALSE);
|
gst_ring_buffer_set_flushing (src->ringbuffer, FALSE);
|
||||||
|
@ -515,7 +579,7 @@ gst_base_audio_src_change_state (GstElement * element,
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||||
gst_ring_buffer_set_flushing (src->ringbuffer, TRUE);
|
gst_ring_buffer_set_flushing (src->ringbuffer, TRUE);
|
||||||
gst_ring_buffer_release (src->ringbuffer);
|
gst_ring_buffer_release (src->ringbuffer);
|
||||||
src->next_sample = 0;
|
src->next_sample = -1;
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
gst_ring_buffer_close_device (src->ringbuffer);
|
gst_ring_buffer_close_device (src->ringbuffer);
|
||||||
|
|
|
@ -920,6 +920,7 @@ gst_ring_buffer_pause (GstRingBuffer * buf)
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
flushing:
|
flushing:
|
||||||
{
|
{
|
||||||
GST_OBJECT_UNLOCK (buf);
|
GST_OBJECT_UNLOCK (buf);
|
||||||
|
@ -989,6 +990,12 @@ done:
|
||||||
* implementation uses another internal buffer between the audio
|
* implementation uses another internal buffer between the audio
|
||||||
* device.
|
* device.
|
||||||
*
|
*
|
||||||
|
* For playback ringbuffers this is the amount of samples transfered from the
|
||||||
|
* ringbuffer to the device but still not played.
|
||||||
|
*
|
||||||
|
* For capture ringbuffers this is the amount of samples in the device that are
|
||||||
|
* not yet transfered to the ringbuffer.
|
||||||
|
*
|
||||||
* Returns: The number of samples queued in the audio device.
|
* Returns: The number of samples queued in the audio device.
|
||||||
*
|
*
|
||||||
* MT safe.
|
* MT safe.
|
||||||
|
@ -1020,7 +1027,8 @@ done:
|
||||||
* @buf: the #GstRingBuffer to query
|
* @buf: the #GstRingBuffer to query
|
||||||
*
|
*
|
||||||
* Get the number of samples that were processed by the ringbuffer
|
* Get the number of samples that were processed by the ringbuffer
|
||||||
* since it was last started.
|
* since it was last started. This does not include the number of samples not
|
||||||
|
* yet processed (see gst_ring_buffer_delay()).
|
||||||
*
|
*
|
||||||
* Returns: The number of samples processed by the ringbuffer.
|
* Returns: The number of samples processed by the ringbuffer.
|
||||||
*
|
*
|
||||||
|
@ -1038,18 +1046,8 @@ gst_ring_buffer_samples_done (GstRingBuffer * buf)
|
||||||
/* get the amount of segments we processed */
|
/* get the amount of segments we processed */
|
||||||
segdone = g_atomic_int_get (&buf->segdone);
|
segdone = g_atomic_int_get (&buf->segdone);
|
||||||
|
|
||||||
/* and the number of samples not yet processed */
|
/* convert to samples */
|
||||||
delay = gst_ring_buffer_delay (buf);
|
samples = ((guint64) segdone) * buf->samples_per_seg;
|
||||||
|
|
||||||
raw = samples = ((guint64) segdone) * buf->samples_per_seg;
|
|
||||||
|
|
||||||
if (G_LIKELY (samples >= delay))
|
|
||||||
samples -= delay;
|
|
||||||
else
|
|
||||||
samples = 0;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (buf, "processed samples: raw %llu, delay %u, real %llu",
|
|
||||||
raw, delay, samples);
|
|
||||||
|
|
||||||
return samples;
|
return samples;
|
||||||
}
|
}
|
||||||
|
@ -1237,9 +1235,10 @@ gst_ring_buffer_commit (GstRingBuffer * buf, guint64 sample, guchar * data,
|
||||||
|
|
||||||
GST_DEBUG
|
GST_DEBUG
|
||||||
("pointer at %d, sample %llu, write to %d-%d, to_write %d, diff %d, segtotal %d, segsize %d",
|
("pointer at %d, sample %llu, write to %d-%d, to_write %d, diff %d, segtotal %d, segsize %d",
|
||||||
segdone, sample, writeseg, sampleoff, to_write, diff, segtotal, sps);
|
segdone, sample, writeseg, sampleoff, to_write, diff, segtotal,
|
||||||
|
segsize);
|
||||||
|
|
||||||
/* segment too far ahead, we need to drop, hopefully UNLIKELY */
|
/* segment too far ahead, writer too slow, we need to drop, hopefully UNLIKELY */
|
||||||
if (G_UNLIKELY (diff < 0)) {
|
if (G_UNLIKELY (diff < 0)) {
|
||||||
/* we need to drop one segment at a time, pretend we wrote a
|
/* we need to drop one segment at a time, pretend we wrote a
|
||||||
* segment. */
|
* segment. */
|
||||||
|
@ -1310,6 +1309,7 @@ gst_ring_buffer_read (GstRingBuffer * buf, guint64 sample, guchar * data,
|
||||||
gint segdone;
|
gint segdone;
|
||||||
gint segsize, segtotal, bps, sps;
|
gint segsize, segtotal, bps, sps;
|
||||||
guint8 *dest;
|
guint8 *dest;
|
||||||
|
guint to_read;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_RING_BUFFER (buf), -1);
|
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 (buf->data != NULL, -1);
|
||||||
|
@ -1321,13 +1321,14 @@ gst_ring_buffer_read (GstRingBuffer * buf, guint64 sample, guchar * data,
|
||||||
bps = buf->spec.bytes_per_sample;
|
bps = buf->spec.bytes_per_sample;
|
||||||
sps = buf->samples_per_seg;
|
sps = buf->samples_per_seg;
|
||||||
|
|
||||||
|
to_read = len;
|
||||||
/* read enough samples */
|
/* read enough samples */
|
||||||
while (len > 0) {
|
while (to_read > 0) {
|
||||||
gint sampleslen;
|
gint sampleslen;
|
||||||
gint readseg, sampleoff;
|
gint readseg, sampleoff;
|
||||||
|
|
||||||
/* figure out the segment and the offset inside the segment where
|
/* figure out the segment and the offset inside the segment where
|
||||||
* the sample should be written. */
|
* the sample should be read from. */
|
||||||
readseg = sample / sps;
|
readseg = sample / sps;
|
||||||
sampleoff = (sample % sps);
|
sampleoff = (sample % sps);
|
||||||
|
|
||||||
|
@ -1337,33 +1338,29 @@ gst_ring_buffer_read (GstRingBuffer * buf, guint64 sample, guchar * data,
|
||||||
/* get the currently processed segment */
|
/* get the currently processed segment */
|
||||||
segdone = g_atomic_int_get (&buf->segdone) - buf->segbase;
|
segdone = g_atomic_int_get (&buf->segdone) - buf->segbase;
|
||||||
|
|
||||||
/* see how far away it is from the read segment */
|
/* see how far away it is from the read segment, normally segdone (where
|
||||||
|
* the hardware is writing) is bigger than readseg (where software is
|
||||||
|
* reading) */
|
||||||
diff = segdone - readseg;
|
diff = segdone - readseg;
|
||||||
|
|
||||||
GST_DEBUG
|
GST_DEBUG
|
||||||
("pointer at %d, sample %llu, read from %d-%d, len %d, diff %d, segtotal %d, segsize %d",
|
("pointer at %d, sample %llu, read from %d-%d, to_read %d, diff %d, segtotal %d, segsize %d",
|
||||||
segdone, sample, readseg, sampleoff, len, diff, segtotal, segsize);
|
segdone, sample, readseg, sampleoff, to_read, diff, segtotal,
|
||||||
|
segsize);
|
||||||
|
|
||||||
/* segment too far ahead, we need to drop */
|
/* segment too far ahead, reader too slow */
|
||||||
if (diff < 0) {
|
if (G_UNLIKELY (diff >= segtotal)) {
|
||||||
/* we need to drop one segment at a time, pretend we read an
|
/* pretend we read an empty segment. */
|
||||||
* empty segment. */
|
sampleslen = MIN (sps, to_read);
|
||||||
sampleslen = MIN (sps, len);
|
|
||||||
memcpy (data, buf->empty_seg, sampleslen * bps);
|
memcpy (data, buf->empty_seg, sampleslen * bps);
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read segment is within readable range, we can break the loop and
|
/* read segment is within readable range, we can break the loop and
|
||||||
* start reading the data. */
|
* start reading the data. */
|
||||||
if (diff > 0 && diff < segtotal)
|
if (diff > 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* flush if diff has grown bigger than ringbuffer */
|
|
||||||
if (diff >= segtotal) {
|
|
||||||
gst_ring_buffer_clear_all (buf);
|
|
||||||
buf->segdone = readseg;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* else we need to wait for the segment to become readable. */
|
/* else we need to wait for the segment to become readable. */
|
||||||
if (!wait_segment (buf))
|
if (!wait_segment (buf))
|
||||||
goto not_started;
|
goto not_started;
|
||||||
|
@ -1371,26 +1368,27 @@ gst_ring_buffer_read (GstRingBuffer * buf, guint64 sample, guchar * data,
|
||||||
|
|
||||||
/* we can read now */
|
/* we can read now */
|
||||||
readseg = readseg % segtotal;
|
readseg = readseg % segtotal;
|
||||||
sampleslen = MIN (sps - sampleoff, len);
|
sampleslen = MIN (sps - sampleoff, to_read);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (buf, "read @%p seg %d, off %d, len %d",
|
GST_DEBUG_OBJECT (buf, "read @%p seg %d, off %d, sampleslen %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),
|
||||||
(sampleslen * bps));
|
(sampleslen * bps));
|
||||||
|
|
||||||
next:
|
next:
|
||||||
len -= sampleslen;
|
to_read -= sampleslen;
|
||||||
sample += sampleslen;
|
sample += sampleslen;
|
||||||
data += sampleslen * bps;
|
data += sampleslen * bps;
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len - to_read;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
not_started:
|
not_started:
|
||||||
{
|
{
|
||||||
GST_DEBUG_OBJECT (buf, "stopped processing");
|
GST_DEBUG_OBJECT (buf, "stopped processing");
|
||||||
|
/* FIXME, return len - to_read after fixing caller */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue