gst/audiorate/gstaudiorate.c: If we have a large (> 1 second) discontinuity, push a series of smaller buffers rather ...

Original commit message from CVS:
* gst/audiorate/gstaudiorate.c: (gst_audio_rate_chain):
If we have a large (> 1 second) discontinuity, push a series of
smaller buffers rather than a single very large buffer. Avoids
unreasonably large single buffer allocations when encountering a
large gap.
* tests/check/elements/audiorate.c: (GST_START_TEST),
(audiorate_suite):
Add a test for this.
This commit is contained in:
Michael Smith 2007-08-09 15:44:02 +00:00
parent 9730f452ee
commit 9f9e76bc99
3 changed files with 119 additions and 32 deletions

View file

@ -1,3 +1,14 @@
2007-08-09 Michael Smith <msmith@fluendo.com>
* gst/audiorate/gstaudiorate.c: (gst_audio_rate_chain):
If we have a large (> 1 second) discontinuity, push a series of
smaller buffers rather than a single very large buffer. Avoids
unreasonably large single buffer allocations when encountering a
large gap.
* tests/check/elements/audiorate.c: (GST_START_TEST),
(audiorate_suite):
Add a test for this.
2007-08-09 Jan Schmidt <thaytan@mad.scientist.com>
* gst/playback/gstplaybasebin.c: (group_commit),

View file

@ -543,45 +543,60 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf)
gint fillsize;
guint64 fillsamples;
/* We don't want to allocate a single unreasonably huge buffer - it might
be hundreds of megabytes. So, limit each output buffer to one second of
audio */
fillsamples = in_offset - audiorate->next_offset;
fillsize = fillsamples * audiorate->bytes_per_sample;
fill = gst_buffer_new_and_alloc (fillsize);
/* FIXME, 0 might not be the silence byte for the negotiated format. */
memset (GST_BUFFER_DATA (fill), 0, fillsize);
while (fillsamples > 0) {
guint64 cursamples = MIN (fillsamples, audiorate->rate);
GST_DEBUG_OBJECT (audiorate, "inserting %lld samples", fillsamples);
GST_DEBUG_OBJECT (audiorate,
"inserting %lld samples of total %lld at ts %lld", cursamples,
fillsamples, audiorate->next_ts);
GST_BUFFER_OFFSET (fill) = audiorate->next_offset;
audiorate->next_offset += fillsamples;
GST_BUFFER_OFFSET_END (fill) = audiorate->next_offset;
fillsamples -= cursamples;
fillsize = cursamples * audiorate->bytes_per_sample;
/* Use next timestamp, then calculate following timestamp based on in_offset
* to get duration. Neccesary complexity to get 'perfect' streams */
GST_BUFFER_TIMESTAMP (fill) = audiorate->next_ts;
audiorate->next_ts = gst_util_uint64_scale_int (in_offset,
GST_SECOND, audiorate->rate);
GST_BUFFER_DURATION (fill) = audiorate->next_ts -
GST_BUFFER_TIMESTAMP (fill);
fill = gst_buffer_new_and_alloc (fillsize);
/* FIXME, 0 might not be the silence byte for the negotiated format. */
memset (GST_BUFFER_DATA (fill), 0, fillsize);
/* we created this buffer to fill a gap */
GST_BUFFER_FLAG_SET (fill, GST_BUFFER_FLAG_GAP);
/* set discont if it's pending, this is mostly done for the first buffer and
* after a flushing seek */
if (audiorate->discont) {
GST_BUFFER_FLAG_SET (fill, GST_BUFFER_FLAG_DISCONT);
audiorate->discont = FALSE;
GST_DEBUG_OBJECT (audiorate, "inserting %lld samples", cursamples);
GST_BUFFER_OFFSET (fill) = audiorate->next_offset;
audiorate->next_offset += cursamples;
GST_BUFFER_OFFSET_END (fill) = audiorate->next_offset;
/* Use next timestamp, then calculate following timestamp based on
* offset to get duration. Neccesary complexity to get 'perfect'
* streams */
GST_BUFFER_TIMESTAMP (fill) = audiorate->next_ts;
audiorate->next_ts = gst_util_uint64_scale_int (audiorate->next_offset,
GST_SECOND, audiorate->rate);
GST_BUFFER_DURATION (fill) = audiorate->next_ts -
GST_BUFFER_TIMESTAMP (fill);
/* we created this buffer to fill a gap */
GST_BUFFER_FLAG_SET (fill, GST_BUFFER_FLAG_GAP);
/* set discont if it's pending, this is mostly done for the first buffer
* and after a flushing seek */
if (audiorate->discont) {
GST_BUFFER_FLAG_SET (fill, GST_BUFFER_FLAG_DISCONT);
audiorate->discont = FALSE;
}
gst_buffer_set_caps (fill, GST_PAD_CAPS (audiorate->srcpad));
ret = gst_pad_push (audiorate->srcpad, fill);
if (ret != GST_FLOW_OK)
goto beach;
audiorate->out++;
audiorate->add += cursamples;
if (!audiorate->silent)
g_object_notify (G_OBJECT (audiorate), "add");
}
gst_buffer_set_caps (fill, GST_PAD_CAPS (audiorate->srcpad));
ret = gst_pad_push (audiorate->srcpad, fill);
if (ret != GST_FLOW_OK)
goto beach;
audiorate->out++;
audiorate->add += fillsamples;
if (!audiorate->silent)
g_object_notify (G_OBJECT (audiorate), "add");
} else if (in_offset < audiorate->next_offset) {
/* need to remove samples */
if (in_offset_end <= audiorate->next_offset) {

View file

@ -25,7 +25,6 @@
#include <gst/check/gstcheck.h>
/* helper element to insert additional buffers overlapping with previous ones */
static gdouble injector_inject_probability = 0.0;
typedef GstElement TestInjector;
@ -386,6 +385,67 @@ GST_END_TEST;
/* TODO: also do all tests with channels=1 and channels=2 */
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-float,channels=1,rate=44100,width=32")
);
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-float,channels=1,rate=44100,width=32")
);
GST_START_TEST (test_large_discont)
{
GstElement *audiorate;
GstCaps *caps;
GstPad *srcpad, *sinkpad;
GstBuffer *buf;
audiorate = gst_check_setup_element ("audiorate");
caps = gst_caps_new_simple ("audio/x-raw-float",
"channels", G_TYPE_INT, 1,
"rate", G_TYPE_INT, 44100, "width", G_TYPE_INT, 32, NULL);
srcpad = gst_check_setup_src_pad (audiorate, &srctemplate, caps);
sinkpad = gst_check_setup_sink_pad (audiorate, &sinktemplate, caps);
gst_pad_set_active (srcpad, TRUE);
gst_pad_set_active (sinkpad, TRUE);
fail_unless (gst_element_set_state (audiorate,
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
"failed to set audiorate playing");
buf = gst_buffer_new_and_alloc (4);
gst_buffer_set_caps (buf, caps);
GST_BUFFER_TIMESTAMP (buf) = 0;
gst_pad_push (srcpad, buf);
fail_unless_equals_int (g_list_length (buffers), 1);
buf = gst_buffer_new_and_alloc (4);
gst_buffer_set_caps (buf, caps);
GST_BUFFER_TIMESTAMP (buf) = 2 * GST_SECOND;
gst_pad_push (srcpad, buf);
/* Now we should have 3 more buffers: the one we injected, plus _two_ filler
* buffers, because the gap is > 1 second (but less than 2 seconds) */
fail_unless_equals_int (g_list_length (buffers), 4);
gst_element_set_state (audiorate, GST_STATE_NULL);
gst_caps_unref (caps);
gst_check_teardown_sink_pad (audiorate);
gst_check_teardown_src_pad (audiorate);
gst_object_unref (audiorate);
}
GST_END_TEST;
static Suite *
audiorate_suite (void)
{
@ -401,6 +461,7 @@ audiorate_suite (void)
tcase_add_test (tc_chain, test_perfect_stream_inject10);
tcase_add_test (tc_chain, test_perfect_stream_inject90);
tcase_add_test (tc_chain, test_perfect_stream_drop45_inject25);
tcase_add_test (tc_chain, test_large_discont);
return s;
}