mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 10:11:08 +00:00
gst/audioresample/gstaudioresample.c: Handle discontinuous streams.
Original commit message from CVS: 2007-03-14 Julien MOUTTE <julien@moutte.net> * gst/audioresample/gstaudioresample.c: (gst_audioresample_init), (audioresample_transform_size), (audioresample_do_output), (audioresample_transform), (audioresample_pushthrough): Handle discontinuous streams. * gst/audioresample/gstaudioresample.h: * tests/check/elements/audioresample.c: (test_discont_stream_instance), (GST_START_TEST), (audioresample_suite): Add a test for discontinuous streams. * win32/common/config.h: Updated.
This commit is contained in:
parent
8b80c6f13a
commit
6940042ecf
5 changed files with 151 additions and 15 deletions
12
ChangeLog
12
ChangeLog
|
@ -1,3 +1,15 @@
|
|||
2007-03-14 Julien MOUTTE <julien@moutte.net>
|
||||
|
||||
* gst/audioresample/gstaudioresample.c: (gst_audioresample_init),
|
||||
(audioresample_transform_size), (audioresample_do_output),
|
||||
(audioresample_transform), (audioresample_pushthrough): Handle
|
||||
discontinuous streams.
|
||||
* gst/audioresample/gstaudioresample.h:
|
||||
* tests/check/elements/audioresample.c:
|
||||
(test_discont_stream_instance), (GST_START_TEST),
|
||||
(audioresample_suite): Add a test for discontinuous streams.
|
||||
* win32/common/config.h: Updated.
|
||||
|
||||
2007-03-14 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||
|
||||
* po/af.po:
|
||||
|
|
|
@ -194,6 +194,8 @@ gst_audioresample_init (GstAudioresample * audioresample,
|
|||
gst_pad_set_bufferalloc_function (trans->sinkpad, NULL);
|
||||
|
||||
audioresample->filter_length = DEFAULT_FILTERLEN;
|
||||
|
||||
audioresample->need_discont = FALSE;
|
||||
}
|
||||
|
||||
/* vmethods */
|
||||
|
@ -371,7 +373,7 @@ audioresample_transform_size (GstBaseTransform * base,
|
|||
gboolean use_internal = FALSE; /* whether we use the internal state */
|
||||
gboolean ret = TRUE;
|
||||
|
||||
GST_DEBUG_OBJECT (base, "asked to transform size %d in direction %s",
|
||||
GST_LOG_OBJECT (base, "asked to transform size %d in direction %s",
|
||||
size, direction == GST_PAD_SINK ? "SINK" : "SRC");
|
||||
if (direction == GST_PAD_SINK) {
|
||||
sinkcaps = caps;
|
||||
|
@ -406,7 +408,7 @@ audioresample_transform_size (GstBaseTransform * base,
|
|||
|
||||
/* we make room for one extra sample, given that the resampling filter
|
||||
* can output an extra one for non-integral i_rate/o_rate */
|
||||
GST_DEBUG_OBJECT (base, "transformed size %d to %d", size, *othersize);
|
||||
GST_LOG_OBJECT (base, "transformed size %d to %d", size, *othersize);
|
||||
|
||||
if (!use_internal) {
|
||||
resample_free (state);
|
||||
|
@ -492,8 +494,7 @@ audioresample_do_output (GstAudioresample * audioresample, GstBuffer * outbuf)
|
|||
r = audioresample->resample;
|
||||
|
||||
outsize = resample_get_output_size (r);
|
||||
GST_DEBUG_OBJECT (audioresample, "audioresample can give me %d bytes",
|
||||
outsize);
|
||||
GST_LOG_OBJECT (audioresample, "audioresample can give me %d bytes", outsize);
|
||||
|
||||
/* protect against mem corruption */
|
||||
if (outsize > GST_BUFFER_SIZE (outbuf)) {
|
||||
|
@ -556,6 +557,13 @@ audioresample_do_output (GstAudioresample * audioresample, GstBuffer * outbuf)
|
|||
}
|
||||
GST_BUFFER_SIZE (outbuf) = outsize;
|
||||
|
||||
if (G_UNLIKELY (audioresample->need_discont)) {
|
||||
GST_DEBUG_OBJECT (audioresample,
|
||||
"marking this buffer with the DISCONT flag");
|
||||
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
|
||||
audioresample->need_discont = FALSE;
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (audioresample, "transformed to buffer of %ld bytes, ts %"
|
||||
GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %"
|
||||
G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
|
||||
|
@ -591,6 +599,25 @@ audioresample_transform (GstBaseTransform * base, GstBuffer * inbuf,
|
|||
GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)),
|
||||
GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf));
|
||||
|
||||
/* check for timestamp discontinuities and flush/reset if needed */
|
||||
if (GST_CLOCK_TIME_IS_VALID (audioresample->prev_ts) &&
|
||||
GST_CLOCK_TIME_IS_VALID (audioresample->prev_duration)) {
|
||||
GstClockTime ts_expected = audioresample->prev_ts +
|
||||
audioresample->prev_duration;
|
||||
GstClockTimeDiff ts_diff = GST_CLOCK_DIFF (ts_expected, timestamp);
|
||||
|
||||
if (G_UNLIKELY (ts_diff != 0)) {
|
||||
GST_WARNING_OBJECT (audioresample,
|
||||
"encountered timestamp discontinuity of %" G_GINT64_FORMAT, ts_diff);
|
||||
/* Flush internal samples */
|
||||
audioresample_pushthrough (audioresample);
|
||||
/* Inform downstream element about discontinuity */
|
||||
audioresample->need_discont = TRUE;
|
||||
/* We want to recalculate the offset */
|
||||
audioresample->ts_offset = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (audioresample->ts_offset == -1) {
|
||||
/* if we don't know the initial offset yet, calculate it based on the
|
||||
* input timestamp. */
|
||||
|
@ -610,6 +637,8 @@ audioresample_transform (GstBaseTransform * base, GstBuffer * inbuf,
|
|||
gst_util_uint64_scale_int (stime, r->o_rate, GST_SECOND);
|
||||
}
|
||||
}
|
||||
audioresample->prev_ts = timestamp;
|
||||
audioresample->prev_duration = GST_BUFFER_DURATION (inbuf);
|
||||
|
||||
/* need to memdup, resample takes ownership. */
|
||||
datacopy = g_memdup (data, size);
|
||||
|
@ -631,17 +660,25 @@ audioresample_pushthrough (GstAudioresample * audioresample)
|
|||
r = audioresample->resample;
|
||||
|
||||
outsize = resample_get_output_size (r);
|
||||
if (outsize == 0)
|
||||
goto done;
|
||||
|
||||
outbuf = gst_buffer_new_and_alloc (outsize);
|
||||
|
||||
res = audioresample_do_output (audioresample, outbuf);
|
||||
if (res != GST_FLOW_OK)
|
||||
if (outsize == 0) {
|
||||
GST_DEBUG_OBJECT (audioresample, "no internal buffers needing flush");
|
||||
goto done;
|
||||
}
|
||||
|
||||
trans = GST_BASE_TRANSFORM (audioresample);
|
||||
|
||||
res = gst_pad_alloc_buffer (trans->srcpad, GST_BUFFER_OFFSET_NONE, outsize,
|
||||
GST_PAD_CAPS (trans->srcpad), &outbuf);
|
||||
if (G_UNLIKELY (res != GST_FLOW_OK)) {
|
||||
GST_WARNING_OBJECT (audioresample, "failed allocating buffer of %d bytes",
|
||||
outsize);
|
||||
goto done;
|
||||
}
|
||||
|
||||
res = audioresample_do_output (audioresample, outbuf);
|
||||
if (G_UNLIKELY (res != GST_FLOW_OK))
|
||||
goto done;
|
||||
|
||||
res = gst_pad_push (trans->srcpad, outbuf);
|
||||
|
||||
done:
|
||||
|
|
|
@ -53,10 +53,12 @@ struct _GstAudioresample {
|
|||
GstCaps *srccaps, *sinkcaps;
|
||||
|
||||
gboolean passthru;
|
||||
gboolean need_discont;
|
||||
|
||||
guint64 offset;
|
||||
guint64 ts_offset;
|
||||
GstClockTime next_ts;
|
||||
GstClockTime prev_ts, prev_duration;
|
||||
int channels;
|
||||
|
||||
int i_rate;
|
||||
|
|
|
@ -144,6 +144,7 @@ fail_unless_perfect_stream ()
|
|||
buffers = NULL;
|
||||
}
|
||||
|
||||
/* this tests that the output is a perfect stream if the input is */
|
||||
static void
|
||||
test_perfect_stream_instance (int inrate, int outrate, int samples,
|
||||
int numbuffers)
|
||||
|
@ -224,6 +225,89 @@ GST_START_TEST (test_perfect_stream)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
/* this tests that the output is a correct discontinuous stream
|
||||
* if the input is; ie input drops in time come out the same way */
|
||||
static void
|
||||
test_discont_stream_instance (int inrate, int outrate, int samples,
|
||||
int numbuffers)
|
||||
{
|
||||
GstElement *audioresample;
|
||||
GstBuffer *inbuffer, *outbuffer;
|
||||
GstCaps *caps;
|
||||
GstClockTime ints;
|
||||
|
||||
int i, j;
|
||||
gint16 *p;
|
||||
|
||||
audioresample = setup_audioresample (2, inrate, outrate);
|
||||
caps = gst_pad_get_negotiated_caps (mysrcpad);
|
||||
fail_unless (gst_caps_is_fixed (caps));
|
||||
|
||||
fail_unless (gst_element_set_state (audioresample,
|
||||
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
|
||||
"could not set to playing");
|
||||
|
||||
for (j = 1; j <= numbuffers; ++j) {
|
||||
|
||||
inbuffer = gst_buffer_new_and_alloc (samples * 4);
|
||||
GST_BUFFER_DURATION (inbuffer) = samples * GST_SECOND / inrate;
|
||||
/* "drop" half the buffers */
|
||||
ints = GST_BUFFER_DURATION (inbuffer) * 2 * (j - 1);
|
||||
GST_BUFFER_TIMESTAMP (inbuffer) = ints;
|
||||
GST_BUFFER_OFFSET (inbuffer) = (j - 1) * 2 * samples;
|
||||
GST_BUFFER_OFFSET_END (inbuffer) = j * 2 * samples + samples;
|
||||
|
||||
gst_buffer_set_caps (inbuffer, caps);
|
||||
|
||||
p = (gint16 *) GST_BUFFER_DATA (inbuffer);
|
||||
|
||||
/* create a 16 bit signed ramp */
|
||||
for (i = 0; i < samples; ++i) {
|
||||
*p = -32767 + i * (65535 / samples);
|
||||
++p;
|
||||
*p = -32767 + i * (65535 / samples);
|
||||
++p;
|
||||
}
|
||||
|
||||
/* pushing gives away my reference ... */
|
||||
fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
|
||||
|
||||
/* check if the timestamp of the pushed buffer matches the incoming one */
|
||||
outbuffer = g_list_nth_data (buffers, g_list_length (buffers) - 1);
|
||||
fail_if (outbuffer == NULL);
|
||||
fail_unless_equals_uint64 (ints, GST_BUFFER_TIMESTAMP (outbuffer));
|
||||
if (j > 1) {
|
||||
fail_unless (GST_BUFFER_IS_DISCONT (outbuffer),
|
||||
"expected discont buffer");
|
||||
}
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
gst_caps_unref (caps);
|
||||
cleanup_audioresample (audioresample);
|
||||
}
|
||||
|
||||
GST_START_TEST (test_discont_stream)
|
||||
{
|
||||
/* integral scalings */
|
||||
test_discont_stream_instance (48000, 24000, 500, 20);
|
||||
test_discont_stream_instance (48000, 12000, 500, 20);
|
||||
test_discont_stream_instance (12000, 24000, 500, 20);
|
||||
test_discont_stream_instance (12000, 48000, 500, 20);
|
||||
|
||||
/* non-integral scalings */
|
||||
test_discont_stream_instance (44100, 8000, 500, 20);
|
||||
test_discont_stream_instance (8000, 44100, 500, 20);
|
||||
|
||||
/* wacky scalings */
|
||||
test_discont_stream_instance (12345, 54321, 500, 20);
|
||||
test_discont_stream_instance (101, 99, 500, 20);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
|
||||
|
||||
GST_START_TEST (test_reuse)
|
||||
{
|
||||
GstElement *audioresample;
|
||||
|
@ -295,6 +379,7 @@ audioresample_suite (void)
|
|||
|
||||
suite_add_tcase (s, tc_chain);
|
||||
tcase_add_test (tc_chain, test_perfect_stream);
|
||||
tcase_add_test (tc_chain, test_discont_stream);
|
||||
tcase_add_test (tc_chain, test_reuse);
|
||||
|
||||
return s;
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
#define GST_LICENSE "LGPL"
|
||||
|
||||
/* package name in plugins */
|
||||
#define GST_PACKAGE_NAME "GStreamer Base Plug-ins source release"
|
||||
#define GST_PACKAGE_NAME "GStreamer Base Plug-ins CVS/prerelease"
|
||||
|
||||
/* package origin */
|
||||
#define GST_PACKAGE_ORIGIN "Unknown package origin"
|
||||
|
@ -211,13 +211,13 @@
|
|||
#undef PACKAGE_NAME "GStreamer Base Plug-ins"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING "GStreamer Base Plug-ins 0.10.12"
|
||||
#undef PACKAGE_STRING "GStreamer Base Plug-ins 0.10.12.1"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME "gst-plugins-base"
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION "0.10.12"
|
||||
#undef PACKAGE_VERSION "0.10.12.1"
|
||||
|
||||
/* directory where plugins are located */
|
||||
#undef PLUGINDIR
|
||||
|
@ -241,7 +241,7 @@
|
|||
#undef STDC_HEADERS
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "0.10.12"
|
||||
#define VERSION "0.10.12.1"
|
||||
|
||||
/* Define to 1 if your processor stores words with the most significant byte
|
||||
first (like Motorola and SPARC, unlike Intel and VAX). */
|
||||
|
|
Loading…
Reference in a new issue