mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-25 01:30:38 +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>
|
2007-08-09 Jan Schmidt <thaytan@mad.scientist.com>
|
||||||
|
|
||||||
* gst/playback/gstplaybasebin.c: (group_commit),
|
* gst/playback/gstplaybasebin.c: (group_commit),
|
||||||
|
|
|
@ -543,45 +543,60 @@ gst_audio_rate_chain (GstPad * pad, GstBuffer * buf)
|
||||||
gint fillsize;
|
gint fillsize;
|
||||||
guint64 fillsamples;
|
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;
|
fillsamples = in_offset - audiorate->next_offset;
|
||||||
fillsize = fillsamples * audiorate->bytes_per_sample;
|
|
||||||
|
|
||||||
fill = gst_buffer_new_and_alloc (fillsize);
|
while (fillsamples > 0) {
|
||||||
/* FIXME, 0 might not be the silence byte for the negotiated format. */
|
guint64 cursamples = MIN (fillsamples, audiorate->rate);
|
||||||
memset (GST_BUFFER_DATA (fill), 0, fillsize);
|
|
||||||
|
|
||||||
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;
|
fillsamples -= cursamples;
|
||||||
audiorate->next_offset += fillsamples;
|
fillsize = cursamples * audiorate->bytes_per_sample;
|
||||||
GST_BUFFER_OFFSET_END (fill) = audiorate->next_offset;
|
|
||||||
|
|
||||||
/* Use next timestamp, then calculate following timestamp based on in_offset
|
fill = gst_buffer_new_and_alloc (fillsize);
|
||||||
* to get duration. Neccesary complexity to get 'perfect' streams */
|
/* FIXME, 0 might not be the silence byte for the negotiated format. */
|
||||||
GST_BUFFER_TIMESTAMP (fill) = audiorate->next_ts;
|
memset (GST_BUFFER_DATA (fill), 0, fillsize);
|
||||||
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);
|
|
||||||
|
|
||||||
/* we created this buffer to fill a gap */
|
GST_DEBUG_OBJECT (audiorate, "inserting %lld samples", cursamples);
|
||||||
GST_BUFFER_FLAG_SET (fill, GST_BUFFER_FLAG_GAP);
|
|
||||||
/* set discont if it's pending, this is mostly done for the first buffer and
|
GST_BUFFER_OFFSET (fill) = audiorate->next_offset;
|
||||||
* after a flushing seek */
|
audiorate->next_offset += cursamples;
|
||||||
if (audiorate->discont) {
|
GST_BUFFER_OFFSET_END (fill) = audiorate->next_offset;
|
||||||
GST_BUFFER_FLAG_SET (fill, GST_BUFFER_FLAG_DISCONT);
|
|
||||||
audiorate->discont = FALSE;
|
/* 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) {
|
} else if (in_offset < audiorate->next_offset) {
|
||||||
/* need to remove samples */
|
/* need to remove samples */
|
||||||
if (in_offset_end <= audiorate->next_offset) {
|
if (in_offset_end <= audiorate->next_offset) {
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#include <gst/check/gstcheck.h>
|
#include <gst/check/gstcheck.h>
|
||||||
|
|
||||||
/* helper element to insert additional buffers overlapping with previous ones */
|
/* helper element to insert additional buffers overlapping with previous ones */
|
||||||
|
|
||||||
static gdouble injector_inject_probability = 0.0;
|
static gdouble injector_inject_probability = 0.0;
|
||||||
|
|
||||||
typedef GstElement TestInjector;
|
typedef GstElement TestInjector;
|
||||||
|
@ -386,6 +385,67 @@ GST_END_TEST;
|
||||||
|
|
||||||
/* TODO: also do all tests with channels=1 and channels=2 */
|
/* 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 *
|
static Suite *
|
||||||
audiorate_suite (void)
|
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_inject10);
|
||||||
tcase_add_test (tc_chain, test_perfect_stream_inject90);
|
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_perfect_stream_drop45_inject25);
|
||||||
|
tcase_add_test (tc_chain, test_large_discont);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue