mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 17:20:36 +00:00
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:
parent
9730f452ee
commit
9f9e76bc99
3 changed files with 119 additions and 32 deletions
11
ChangeLog
11
ChangeLog
|
@ -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),
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue