mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-24 02:31:03 +00:00
gst-libs/gst/audio/gstbaseaudiosink.*: Extract rate from the NEWSEGMENT event.
Original commit message from CVS: * gst-libs/gst/audio/gstbaseaudiosink.c: (gst_base_audio_sink_event), (gst_base_audio_sink_render): * gst-libs/gst/audio/gstbaseaudiosink.h: Extract rate from the NEWSEGMENT event. Use commit_full to also take rate adjustment into account when writing samples to the ringbuffer. * gst-libs/gst/audio/gstringbuffer.c: (gst_ring_buffer_commit_full), (gst_ring_buffer_commit), (gst_ring_buffer_read): * gst-libs/gst/audio/gstringbuffer.h: Added _commit_full() to also take rate into account. Use simple interpolation algorithm to resample audio. API: gst_ring_buffer_commit_full() * tests/examples/seek/scrubby.c: (speed_cb), (do_seek): * tests/examples/seek/seek.c: (segment_done): Don't try to seek with 0.0 rate, just pause instead. Remove bogus debug line.
This commit is contained in:
parent
453f06075c
commit
1166abbc99
7 changed files with 311 additions and 61 deletions
22
ChangeLog
22
ChangeLog
|
@ -1,3 +1,25 @@
|
||||||
|
2006-10-18 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
|
* gst-libs/gst/audio/gstbaseaudiosink.c:
|
||||||
|
(gst_base_audio_sink_event), (gst_base_audio_sink_render):
|
||||||
|
* gst-libs/gst/audio/gstbaseaudiosink.h:
|
||||||
|
Extract rate from the NEWSEGMENT event.
|
||||||
|
Use commit_full to also take rate adjustment into account when writing
|
||||||
|
samples to the ringbuffer.
|
||||||
|
|
||||||
|
* gst-libs/gst/audio/gstringbuffer.c:
|
||||||
|
(gst_ring_buffer_commit_full), (gst_ring_buffer_commit),
|
||||||
|
(gst_ring_buffer_read):
|
||||||
|
* gst-libs/gst/audio/gstringbuffer.h:
|
||||||
|
Added _commit_full() to also take rate into account.
|
||||||
|
Use simple interpolation algorithm to resample audio.
|
||||||
|
API: gst_ring_buffer_commit_full()
|
||||||
|
|
||||||
|
* tests/examples/seek/scrubby.c: (speed_cb), (do_seek):
|
||||||
|
* tests/examples/seek/seek.c: (segment_done):
|
||||||
|
Don't try to seek with 0.0 rate, just pause instead.
|
||||||
|
Remove bogus debug line.
|
||||||
|
|
||||||
2006-10-18 Tim-Philipp Müller <tim at centricular dot net>
|
2006-10-18 Tim-Philipp Müller <tim at centricular dot net>
|
||||||
|
|
||||||
* gst/playback/gstplaybasebin.c: (subbin_startup_sync_msg),
|
* gst/playback/gstplaybasebin.c: (subbin_startup_sync_msg),
|
||||||
|
|
|
@ -441,6 +441,32 @@ gst_base_audio_sink_event (GstBaseSink * bsink, GstEvent * event)
|
||||||
/* now wait till we played everything */
|
/* now wait till we played everything */
|
||||||
gst_base_audio_sink_drain (sink);
|
gst_base_audio_sink_drain (sink);
|
||||||
break;
|
break;
|
||||||
|
case GST_EVENT_NEWSEGMENT:
|
||||||
|
{
|
||||||
|
gdouble rate;
|
||||||
|
GValue src = { 0 };
|
||||||
|
GValue dst = { 0 };
|
||||||
|
|
||||||
|
/* we only need the rate */
|
||||||
|
gst_event_parse_new_segment_full (event, NULL, &rate, NULL, NULL,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
|
||||||
|
g_value_init (&src, G_TYPE_DOUBLE);
|
||||||
|
g_value_set_double (&src, rate);
|
||||||
|
g_value_init (&dst, GST_TYPE_FRACTION);
|
||||||
|
g_value_transform (&src, &dst);
|
||||||
|
g_value_unset (&src);
|
||||||
|
|
||||||
|
sink->abidata.ABI.rate_num = gst_value_get_fraction_numerator (&dst);
|
||||||
|
sink->abidata.ABI.rate_denom = gst_value_get_fraction_denominator (&dst);
|
||||||
|
sink->abidata.ABI.rate_accum = 0;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (sink, "set rate to %f = %d / %d", rate,
|
||||||
|
sink->abidata.ABI.rate_num, sink->abidata.ABI.rate_denom);
|
||||||
|
|
||||||
|
g_value_unset (&dst);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -513,9 +539,10 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
||||||
guint size;
|
guint size;
|
||||||
guint samples, written;
|
guint samples, written;
|
||||||
gint bps;
|
gint bps;
|
||||||
gdouble crate = 1.0;
|
|
||||||
GstClockTime crate_num;
|
GstClockTime crate_num;
|
||||||
GstClockTime crate_denom;
|
GstClockTime crate_denom;
|
||||||
|
gint rate_num;
|
||||||
|
gint rate_denom;
|
||||||
GstClockTime cinternal, cexternal;
|
GstClockTime cinternal, cexternal;
|
||||||
GstClock *clock;
|
GstClock *clock;
|
||||||
gboolean sync;
|
gboolean sync;
|
||||||
|
@ -545,6 +572,9 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
||||||
"time %" GST_TIME_FORMAT ", offset %llu, start %" GST_TIME_FORMAT,
|
"time %" GST_TIME_FORMAT ", offset %llu, start %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (time), in_offset, GST_TIME_ARGS (bsink->segment.start));
|
GST_TIME_ARGS (time), in_offset, GST_TIME_ARGS (bsink->segment.start));
|
||||||
|
|
||||||
|
rate_num = sink->abidata.ABI.rate_num;
|
||||||
|
rate_denom = sink->abidata.ABI.rate_denom;
|
||||||
|
|
||||||
/* if not valid timestamp or we can't clip or sync, try to play
|
/* if not valid timestamp or we can't clip or sync, try to play
|
||||||
* sample ASAP */
|
* sample ASAP */
|
||||||
if (!GST_CLOCK_TIME_IS_VALID (time)) {
|
if (!GST_CLOCK_TIME_IS_VALID (time)) {
|
||||||
|
@ -606,12 +636,17 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
||||||
goto no_sync;
|
goto no_sync;
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_clock_get_calibration (sink->provided_clock, &cinternal, &cexternal,
|
|
||||||
&crate_num, &crate_denom);
|
|
||||||
|
|
||||||
/* bring buffer timestamp to running time */
|
/* bring buffer timestamp to running time */
|
||||||
render_time =
|
render_time =
|
||||||
gst_segment_to_running_time (&bsink->segment, GST_FORMAT_TIME, time);
|
gst_segment_to_running_time (&bsink->segment, GST_FORMAT_TIME, time);
|
||||||
|
GST_DEBUG_OBJECT (sink, "running time %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (render_time));
|
||||||
|
|
||||||
|
/* get calibration parameters to compensate for speed and offset differences
|
||||||
|
* when we are slaved */
|
||||||
|
gst_clock_get_calibration (sink->provided_clock, &cinternal, &cexternal,
|
||||||
|
&crate_num, &crate_denom);
|
||||||
|
|
||||||
/* add base time to get absolute clock time */
|
/* add base time to get absolute clock time */
|
||||||
render_time +=
|
render_time +=
|
||||||
(gst_element_get_base_time (GST_ELEMENT_CAST (bsink)) - cexternal) +
|
(gst_element_get_base_time (GST_ELEMENT_CAST (bsink)) - cexternal) +
|
||||||
|
@ -621,7 +656,7 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
||||||
gst_util_uint64_scale_int (render_time, ringbuf->spec.rate, GST_SECOND);
|
gst_util_uint64_scale_int (render_time, ringbuf->spec.rate, GST_SECOND);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (sink, "render time %" GST_TIME_FORMAT
|
GST_DEBUG_OBJECT (sink, "render time %" GST_TIME_FORMAT
|
||||||
", render offset %llu, samples %u",
|
", render offset %" G_GUINT64_FORMAT ", samples %u",
|
||||||
GST_TIME_ARGS (render_time), render_offset, samples);
|
GST_TIME_ARGS (render_time), render_offset, samples);
|
||||||
|
|
||||||
/* never try to align samples when we are slaved to another clock, just
|
/* never try to align samples when we are slaved to another clock, just
|
||||||
|
@ -646,7 +681,10 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* now try to align the sample to the previous one */
|
/* now try to align the sample to the previous one */
|
||||||
diff = ABS ((gint64) render_offset - (gint64) sink->next_sample);
|
if (render_offset >= sink->next_sample)
|
||||||
|
diff = render_offset - sink->next_sample;
|
||||||
|
else
|
||||||
|
diff = sink->next_sample - render_offset;
|
||||||
|
|
||||||
/* we tollerate half a second diff before we start resyncing. This
|
/* we tollerate half a second diff before we start resyncing. This
|
||||||
* should be enough to compensate for various rounding errors in the timestamp
|
* should be enough to compensate for various rounding errors in the timestamp
|
||||||
|
@ -659,6 +697,8 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
||||||
/* just align with previous sample then */
|
/* just align with previous sample then */
|
||||||
render_offset = sink->next_sample;
|
render_offset = sink->next_sample;
|
||||||
} else {
|
} else {
|
||||||
|
/* bring sample diff to seconds for error message */
|
||||||
|
diff = gst_util_uint64_scale_int (diff, GST_SECOND, ringbuf->spec.rate);
|
||||||
/* timestamps drifted apart from previous samples too much, we need to
|
/* timestamps drifted apart from previous samples too much, we need to
|
||||||
* resync. We log this as an element warning. */
|
* resync. We log this as an element warning. */
|
||||||
GST_ELEMENT_WARNING (sink, CORE, CLOCK,
|
GST_ELEMENT_WARNING (sink, CORE, CLOCK,
|
||||||
|
@ -669,23 +709,47 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
no_align:
|
no_align:
|
||||||
/* crate contains diff against the clock we are using in the pipeline. */
|
/* check if we have a clock rate adjustment to do */
|
||||||
crate =
|
if (crate_num != 1 || crate_num != 1) {
|
||||||
gst_guint64_to_gdouble (crate_num) / gst_guint64_to_gdouble (crate_denom);
|
gint64 num, denom;
|
||||||
GST_DEBUG_OBJECT (sink,
|
|
||||||
"internal %" G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT ", rate %g",
|
/* make clock rate fit in int */
|
||||||
cinternal, cexternal, crate);
|
while ((crate_num | crate_denom) > G_MAXINT) {
|
||||||
|
crate_num /= 2;
|
||||||
|
crate_denom /= 2;
|
||||||
|
}
|
||||||
|
/* full 64bit multiplication */
|
||||||
|
num = ((gint64) crate_denom) * rate_num;
|
||||||
|
denom = ((gint64) crate_num) * rate_denom;
|
||||||
|
|
||||||
|
/* make result fit in int again */
|
||||||
|
while ((num | denom) > G_MAXINT) {
|
||||||
|
num /= 2;
|
||||||
|
denom /= 2;
|
||||||
|
}
|
||||||
|
rate_num = num;
|
||||||
|
rate_denom = denom;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (sink,
|
||||||
|
"clock rate: internal %" G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT
|
||||||
|
" %d/%d", cinternal, cexternal, rate_num, rate_denom);
|
||||||
|
}
|
||||||
|
|
||||||
no_sync:
|
no_sync:
|
||||||
/* clip length based on rate */
|
|
||||||
samples = MIN (samples, samples / (crate * bsink->segment.abs_rate));
|
|
||||||
|
|
||||||
/* the next sample should be current sample and its length */
|
/* the next sample should be current sample and its length, this will be
|
||||||
sink->next_sample = render_offset + samples;
|
* updated as we write samples to the ringbuffer. */
|
||||||
|
sink->next_sample = render_offset;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (sink, "rendering at %" G_GUINT64_FORMAT, sink->next_sample);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
written = gst_ring_buffer_commit (ringbuf, render_offset, data, samples);
|
written =
|
||||||
GST_DEBUG_OBJECT (sink, "wrote %u of %u", written, samples);
|
gst_ring_buffer_commit_full (ringbuf, &sink->next_sample, data, samples,
|
||||||
|
rate_num, rate_denom, &sink->abidata.ABI.rate_accum);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (sink, "wrote %u of %u, resampled %" G_GUINT64_FORMAT,
|
||||||
|
written, samples, sink->next_sample - render_offset);
|
||||||
/* if we wrote all, we're done */
|
/* if we wrote all, we're done */
|
||||||
if (written == samples)
|
if (written == samples)
|
||||||
break;
|
break;
|
||||||
|
@ -694,11 +758,13 @@ no_sync:
|
||||||
if (gst_base_sink_wait_preroll (bsink) != GST_FLOW_OK)
|
if (gst_base_sink_wait_preroll (bsink) != GST_FLOW_OK)
|
||||||
goto stopping;
|
goto stopping;
|
||||||
|
|
||||||
render_offset += written;
|
|
||||||
samples -= written;
|
samples -= written;
|
||||||
data += written * bps;
|
data += written * bps;
|
||||||
} while (TRUE);
|
} while (TRUE);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (sink, "next sample expected at %" G_GUINT64_FORMAT,
|
||||||
|
sink->next_sample);
|
||||||
|
|
||||||
if (GST_CLOCK_TIME_IS_VALID (stop) && stop >= bsink->segment.stop) {
|
if (GST_CLOCK_TIME_IS_VALID (stop) && stop >= bsink->segment.stop) {
|
||||||
GST_DEBUG_OBJECT (sink,
|
GST_DEBUG_OBJECT (sink,
|
||||||
"start playback because we are at the end of segment");
|
"start playback because we are at the end of segment");
|
||||||
|
|
|
@ -105,7 +105,15 @@ struct _GstBaseAudioSink {
|
||||||
GstClock *provided_clock;
|
GstClock *provided_clock;
|
||||||
|
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
union {
|
||||||
|
struct {
|
||||||
|
gint rate_num;
|
||||||
|
gint rate_denom;
|
||||||
|
gint rate_accum;
|
||||||
|
} ABI;
|
||||||
|
/* adding + 0 to mark ABI change to be undone later */
|
||||||
|
gpointer _gst_reserved[GST_PADDING + 0];
|
||||||
|
} abidata;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1174,54 +1174,155 @@ no_start:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define FWD_SAMPLES(s,se,d,de) \
|
||||||
|
G_STMT_START { \
|
||||||
|
/* no rate conversion */ \
|
||||||
|
guint towrite = MIN (se + bps - s, de - d); \
|
||||||
|
/* simple copy */ \
|
||||||
|
if (!skip) \
|
||||||
|
memcpy (d, s, towrite); \
|
||||||
|
*sample += towrite / bps; \
|
||||||
|
s += towrite; \
|
||||||
|
GST_DEBUG ("copy %u bytes", towrite); \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
#define FWD_UP_SAMPLES(s,se,d,de) \
|
||||||
|
G_STMT_START { \
|
||||||
|
guint8 *ds = d; \
|
||||||
|
while (s <= se && d < de) { \
|
||||||
|
if (!skip) \
|
||||||
|
memcpy (d, s, bps); \
|
||||||
|
s += bps; \
|
||||||
|
*accum += denom; \
|
||||||
|
while (*accum > 0) { \
|
||||||
|
*accum -= num; \
|
||||||
|
d += bps; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
*sample += (d - ds) / bps; \
|
||||||
|
GST_DEBUG ("fwd_up %u bytes", d - ds); \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
#define FWD_DOWN_SAMPLES(s,se,d,de) \
|
||||||
|
G_STMT_START { \
|
||||||
|
guint8 *ds = d; \
|
||||||
|
while (s <= se && d < de) { \
|
||||||
|
if (!skip) \
|
||||||
|
memcpy (d, s, bps); \
|
||||||
|
d += bps; \
|
||||||
|
*accum -= num; \
|
||||||
|
while (*accum < 0) { \
|
||||||
|
*accum += denom; \
|
||||||
|
s += bps; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
*sample += (d - ds) / bps; \
|
||||||
|
GST_DEBUG ("fwd_down %u bytes", d - ds); \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
#define REV_UP_SAMPLES(s,se,d,de) \
|
||||||
|
G_STMT_START { \
|
||||||
|
guint8 *ds = d; \
|
||||||
|
while (s <= se && d < de) { \
|
||||||
|
if (!skip) \
|
||||||
|
memcpy (d, se, bps); \
|
||||||
|
se -= bps; \
|
||||||
|
*accum += denom; \
|
||||||
|
while (*accum > 0) { \
|
||||||
|
*accum += num; \
|
||||||
|
d += bps; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
*sample += (d - ds) / bps; \
|
||||||
|
GST_DEBUG ("rev_up %u bytes", d - ds); \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
#define REV_DOWN_SAMPLES(s,se,d,de) \
|
||||||
|
G_STMT_START { \
|
||||||
|
guint8 *ds = d; \
|
||||||
|
while (s <= se && d < de) { \
|
||||||
|
if (!skip) \
|
||||||
|
memcpy (d, se, bps); \
|
||||||
|
d += bps; \
|
||||||
|
*accum += num; \
|
||||||
|
while (*accum < 0) { \
|
||||||
|
*accum += denom; \
|
||||||
|
se -= bps; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
*sample += (d - ds) / bps; \
|
||||||
|
GST_DEBUG ("rev_down %u bytes", d - ds); \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_ring_buffer_commit:
|
* gst_ring_buffer_commit_full:
|
||||||
* @buf: the #GstRingBuffer to commit
|
* @buf: the #GstRingBuffer to commit
|
||||||
* @sample: the sample position of the data
|
* @sample: the sample position of the data
|
||||||
* @data: the data to commit
|
* @data: the data to commit
|
||||||
* @len: the number of samples in the data to commit
|
* @len: the number of samples in the data to commit
|
||||||
|
* @num: the numerator of the speed
|
||||||
|
* @denom: the denominator of the speed
|
||||||
|
* @accum: accumulator for rate conversion.
|
||||||
*
|
*
|
||||||
* Commit @len samples pointed to by @data to the ringbuffer
|
* Commit @len samples pointed to by @data to the ringbuffer @buf.
|
||||||
* @buf. The first sample should be written at position @sample in
|
|
||||||
* the ringbuffer.
|
|
||||||
*
|
*
|
||||||
* @len does not need to be a multiple of the segment size of the ringbuffer
|
* @num and @denom define the rate conversion to perform on the the samples in
|
||||||
* although it is recommended for optimal performance.
|
* @data. For negative rates, @num must be negative and @denom positive.
|
||||||
*
|
*
|
||||||
* Returns: The number of samples written to the ringbuffer or -1 on
|
* When @num is positive, the first sample will be written at position @sample
|
||||||
* error.
|
* in the ringbuffer. When @num is negative, the last sample will be written to
|
||||||
|
* @sample in reverse order.
|
||||||
|
*
|
||||||
|
* @len does not need to be a multiple of the segment size of the ringbuffer (if
|
||||||
|
* @num and @denom are both 1) although it is recommended for optimal performance.
|
||||||
|
*
|
||||||
|
* @sample will be updated with the next position in the ringbuffer. This
|
||||||
|
* position will take into account any resampling done when writing the samples.
|
||||||
|
*
|
||||||
|
* Returns: The number of samples written to the ringbuffer or -1 on error. The
|
||||||
|
* number of samples written can be less than @len when @buf was interrupted
|
||||||
|
* with a flush or stop.
|
||||||
|
*
|
||||||
|
* Since: 0.10.11.
|
||||||
*
|
*
|
||||||
* MT safe.
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
guint
|
guint
|
||||||
gst_ring_buffer_commit (GstRingBuffer * buf, guint64 sample, guchar * data,
|
gst_ring_buffer_commit_full (GstRingBuffer * buf, guint64 * sample,
|
||||||
guint len)
|
guchar * data, guint len, gint num, gint denom, gint * accum)
|
||||||
{
|
{
|
||||||
gint segdone;
|
gint segdone;
|
||||||
gint segsize, segtotal, bps, sps;
|
gint segsize, segtotal, bps, sps;
|
||||||
guint8 *dest;
|
guint8 *dest, *data_end;
|
||||||
guint to_write;
|
gint writeseg, sampleoff;
|
||||||
|
|
||||||
|
if (G_UNLIKELY (len == 0))
|
||||||
|
return 0;
|
||||||
|
|
||||||
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);
|
||||||
g_return_val_if_fail (data != NULL, -1);
|
g_return_val_if_fail (data != NULL, -1);
|
||||||
|
g_return_val_if_fail (denom != 0, -1);
|
||||||
|
|
||||||
dest = GST_BUFFER_DATA (buf->data);
|
dest = GST_BUFFER_DATA (buf->data);
|
||||||
segsize = buf->spec.segsize;
|
segsize = buf->spec.segsize;
|
||||||
segtotal = buf->spec.segtotal;
|
segtotal = buf->spec.segtotal;
|
||||||
bps = buf->spec.bytes_per_sample;
|
bps = buf->spec.bytes_per_sample;
|
||||||
sps = buf->samples_per_seg;
|
sps = buf->samples_per_seg;
|
||||||
|
/* data_end points to the last sample we have to write, not past it. */
|
||||||
|
data_end = data + (bps * (len - 1));
|
||||||
|
|
||||||
|
/* figure out the segment and the offset inside the segment where
|
||||||
|
* the first sample should be written. */
|
||||||
|
writeseg = *sample / sps;
|
||||||
|
sampleoff = (*sample % sps) * bps;
|
||||||
|
|
||||||
to_write = len;
|
|
||||||
/* write out all samples */
|
/* write out all samples */
|
||||||
while (to_write > 0) {
|
while (data <= data_end) {
|
||||||
gint sampleslen;
|
gint avail;
|
||||||
gint writeseg, sampleoff;
|
guint8 *d, *d_end;
|
||||||
|
gint ws;
|
||||||
/* figure out the segment and the offset inside the segment where
|
gboolean skip;
|
||||||
* the sample should be written. */
|
|
||||||
writeseg = sample / sps;
|
|
||||||
sampleoff = (sample % sps);
|
|
||||||
|
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
gint diff;
|
gint diff;
|
||||||
|
@ -1233,22 +1334,23 @@ gst_ring_buffer_commit (GstRingBuffer * buf, guint64 sample, guchar * data,
|
||||||
diff = writeseg - segdone;
|
diff = writeseg - segdone;
|
||||||
|
|
||||||
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, write to %d-%d, diff %d, segtotal %d, segsize %d",
|
||||||
segdone, sample, writeseg, sampleoff, to_write, diff, segtotal,
|
segdone, writeseg, sampleoff, diff, segtotal, segsize);
|
||||||
segsize);
|
|
||||||
|
|
||||||
/* segment too far ahead, writer too slow, 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. */
|
||||||
sampleslen = MIN (sps, to_write);
|
skip = TRUE;
|
||||||
goto next;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write segment is within writable range, we can break the loop and
|
/* write segment is within writable range, we can break the loop and
|
||||||
* start writing the data. */
|
* start writing the data. */
|
||||||
if (diff < segtotal)
|
if (diff < segtotal) {
|
||||||
|
skip = FALSE;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* else we need to wait for the segment to become writable. */
|
/* else we need to wait for the segment to become writable. */
|
||||||
if (!wait_segment (buf))
|
if (!wait_segment (buf))
|
||||||
|
@ -1256,31 +1358,77 @@ gst_ring_buffer_commit (GstRingBuffer * buf, guint64 sample, guchar * data,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we can write now */
|
/* we can write now */
|
||||||
writeseg = writeseg % segtotal;
|
ws = writeseg % segtotal;
|
||||||
sampleslen = MIN (sps - sampleoff, to_write);
|
avail = segsize - sampleoff;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (buf, "write @%p seg %d, off %d, sampleslen %d",
|
d = dest + (ws * segsize) + sampleoff;
|
||||||
dest + writeseg * segsize, writeseg, sampleoff, sampleslen);
|
d_end = d + avail;
|
||||||
|
|
||||||
memcpy (dest + (writeseg * segsize) + (sampleoff * bps), data,
|
GST_DEBUG_OBJECT (buf, "write @%p seg %d, sps %d, off %d, avail %d",
|
||||||
(sampleslen * bps));
|
dest + ws * segsize, ws, sps, sampleoff, avail);
|
||||||
|
|
||||||
next:
|
if (G_LIKELY (num == 1 && denom == 1)) {
|
||||||
to_write -= sampleslen;
|
/* no rate conversion, simply copy samples */
|
||||||
sample += sampleslen;
|
FWD_SAMPLES (data, data_end, d, d_end);
|
||||||
data += sampleslen * bps;
|
} else if (num >= 0) {
|
||||||
|
if (num >= denom)
|
||||||
|
/* forward speed up */
|
||||||
|
FWD_UP_SAMPLES (data, data_end, d, d_end);
|
||||||
|
else
|
||||||
|
/* forward slow down */
|
||||||
|
FWD_DOWN_SAMPLES (data, data_end, d, d_end);
|
||||||
|
} else {
|
||||||
|
if (-num >= denom)
|
||||||
|
/* reverse speed up */
|
||||||
|
REV_UP_SAMPLES (data, data_end, d, d_end);
|
||||||
|
else
|
||||||
|
/* reverse slow down */
|
||||||
|
REV_DOWN_SAMPLES (data, data_end, d, d_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for the next iteration we write to the next segment at the beginning. */
|
||||||
|
writeseg++;
|
||||||
|
sampleoff = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return len - to_write;
|
done:
|
||||||
|
return (len - 1) - ((data_end - data) / bps);
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
not_started:
|
not_started:
|
||||||
{
|
{
|
||||||
GST_DEBUG_OBJECT (buf, "stopped processing");
|
GST_DEBUG_OBJECT (buf, "stopped processing");
|
||||||
return len - to_write;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_ring_buffer_commit:
|
||||||
|
* @buf: the #GstRingBuffer to commit
|
||||||
|
* @sample: the sample position of the data
|
||||||
|
* @data: the data to commit
|
||||||
|
* @len: the number of samples in the data to commit
|
||||||
|
*
|
||||||
|
* Same as gst_ring_buffer_commit_full() but with a num, denom of 1, ignoring
|
||||||
|
* accum.
|
||||||
|
*
|
||||||
|
* Returns: The number of samples written to the ringbuffer or -1 on
|
||||||
|
* error.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
|
*/
|
||||||
|
guint
|
||||||
|
gst_ring_buffer_commit (GstRingBuffer * buf, guint64 sample, guchar * data,
|
||||||
|
guint len)
|
||||||
|
{
|
||||||
|
guint res;
|
||||||
|
guint64 spos = sample;
|
||||||
|
|
||||||
|
res = gst_ring_buffer_commit_full (buf, &spos, data, len, 1, 1, NULL);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_ring_buffer_read:
|
* gst_ring_buffer_read:
|
||||||
* @buf: the #GstRingBuffer to read from
|
* @buf: the #GstRingBuffer to read from
|
||||||
|
|
|
@ -337,6 +337,9 @@ void gst_ring_buffer_clear_all (GstRingBuffer *buf);
|
||||||
/* commit samples */
|
/* commit samples */
|
||||||
guint gst_ring_buffer_commit (GstRingBuffer *buf, guint64 sample,
|
guint gst_ring_buffer_commit (GstRingBuffer *buf, guint64 sample,
|
||||||
guchar *data, guint len);
|
guchar *data, guint len);
|
||||||
|
guint gst_ring_buffer_commit_full (GstRingBuffer *buf, guint64 *sample,
|
||||||
|
guchar *data, guint len,
|
||||||
|
gint num, gint denom, gint *accum);
|
||||||
/* read samples */
|
/* read samples */
|
||||||
guint gst_ring_buffer_read (GstRingBuffer *buf, guint64 sample,
|
guint gst_ring_buffer_read (GstRingBuffer *buf, guint64 sample,
|
||||||
guchar *data, guint len);
|
guchar *data, guint len);
|
||||||
|
|
|
@ -177,6 +177,9 @@ speed_cb (GtkWidget * widget)
|
||||||
GST_DEBUG ("speed change");
|
GST_DEBUG ("speed change");
|
||||||
cur_speed = gtk_range_get_value (GTK_RANGE (widget));
|
cur_speed = gtk_range_get_value (GTK_RANGE (widget));
|
||||||
|
|
||||||
|
if (cur_speed == 0.0)
|
||||||
|
return;
|
||||||
|
|
||||||
s_event = gst_event_new_seek (cur_speed,
|
s_event = gst_event_new_seek (cur_speed,
|
||||||
GST_FORMAT_TIME, 0, GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_NONE, -1);
|
GST_FORMAT_TIME, 0, GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_NONE, -1);
|
||||||
|
|
||||||
|
@ -265,6 +268,8 @@ do_seek (GtkWidget * widget, gboolean flush, gboolean segment)
|
||||||
stop = tmp;
|
stop = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rate == 0.0)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
GST_DEBUG ("seek to %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT ", rate %lf"
|
GST_DEBUG ("seek to %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT ", rate %lf"
|
||||||
" on element %s",
|
" on element %s",
|
||||||
|
|
|
@ -1330,8 +1330,6 @@ segment_done (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
|
||||||
event = gst_event_new_seek (rate,
|
event = gst_event_new_seek (rate,
|
||||||
GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, -1);
|
GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, -1);
|
||||||
|
|
||||||
GST_DEBUG ("segmeent seek to start");
|
|
||||||
|
|
||||||
res = send_event (event);
|
res = send_event (event);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
g_print ("segment seek failed\n");
|
g_print ("segment seek failed\n");
|
||||||
|
|
Loading…
Reference in a new issue