gst/audioresample/: add room for extra overlap samples when asked to transform size protect against possible mem corr...

Original commit message from CVS:
* gst/audioresample/debug.c:
* gst/audioresample/gstaudioresample.c:
add room for extra overlap samples when asked to transform size
protect against possible mem corruption and check for discrepancies
between written size and outbuffer's size so we can warn for
potential problems
* gst/audioresample/resample.c: (resample_init),
(resample_get_output_size_for_input), (resample_get_output_size),
(resample_set_n_channels), (resample_set_format):
set debug level based on RESAMPLE_DEBUG env var
make sure that get_output_size* returns a whole number of
sample_size
set sample_size each time either channel or format is set
* gst/audioresample/resample_chunk.c: (resample_scale_chunk):
* gst/audioresample/resample_functable.c:
(resample_scale_functable):
* gst/audioresample/resample_ref.c: (resample_scale_ref):
remove r->sample_size, it's done in resample.c now
add some debugging to the ref implementation
make sure we only give back bytes that are wholes of the sample
size
This commit is contained in:
Thomas Vander Stichele 2005-08-25 12:31:31 +00:00
parent f488ccf221
commit 0daade2ce6
6 changed files with 73 additions and 35 deletions

View file

@ -16,7 +16,7 @@ static const char *resample_debug_level_names[] = {
"LOG" "LOG"
}; };
static int resample_debug_level = RESAMPLE_LEVEL_LOG; static int resample_debug_level = RESAMPLE_LEVEL_ERROR;
void void
resample_debug_log (int level, const char *file, const char *function, resample_debug_log (int level, const char *file, const char *function,

View file

@ -55,14 +55,15 @@ enum
}; };
#define SUPPORTED_CAPS \ #define SUPPORTED_CAPS \
GST_STATIC_CAPS (\ GST_STATIC_CAPS ( \
"audio/x-raw-int, " \ "audio/x-raw-int, " \
"rate = (int) [ 1, MAX ], " \ "rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \ "channels = (int) [ 1, MAX ], " \
"endianness = (int) BYTE_ORDER, " \ "endianness = (int) BYTE_ORDER, " \
"width = (int) 16, " \ "width = (int) 16, " \
"depth = (int) 16, " \ "depth = (int) 16, " \
"signed = (boolean) true") "signed = (boolean) true " \
)
#if 0 #if 0
/* disabled because it segfaults */ /* disabled because it segfaults */
@ -255,18 +256,18 @@ static gboolean
return TRUE; return TRUE;
} }
gboolean audioresample_transform_size (GstBaseTransform * base, gboolean
audioresample_transform_size (GstBaseTransform * base,
GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps, GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps,
guint * othersize) guint * othersize) {
{
GstAudioresample *audioresample = GST_AUDIORESAMPLE (base); GstAudioresample *audioresample = GST_AUDIORESAMPLE (base);
ResampleState *state; ResampleState *state;
GstCaps *srccaps, *sinkcaps; GstCaps *srccaps, *sinkcaps;
gboolean use_internal = FALSE; /* whether we use the internal state */ gboolean use_internal = FALSE; /* whether we use the internal state */
gboolean ret = TRUE; gboolean ret = TRUE;
/* FIXME: make sure incaps/outcaps get renamed to caps/othercaps, since GST_DEBUG_OBJECT (base, "asked to transform size %d in direction %s",
* interpretation depends on the direction */ size, direction == GST_PAD_SINK ? "SINK" : "SRC");
if (direction == GST_PAD_SINK) { if (direction == GST_PAD_SINK) {
sinkcaps = caps; sinkcaps = caps;
srccaps = othercaps; srccaps = othercaps;
@ -282,11 +283,12 @@ gboolean audioresample_transform_size (GstBaseTransform * base,
use_internal = TRUE; use_internal = TRUE;
state = audioresample->resample; state = audioresample->resample;
} else { } else {
GST_DEBUG_OBJECT (audioresample,
"caps are not the set caps, creating state");
state = resample_new (); state = resample_new ();
resample_set_state_from_caps (state, sinkcaps, srccaps, NULL, NULL, NULL); resample_set_state_from_caps (state, sinkcaps, srccaps, NULL, NULL, NULL);
} }
/* we can use our own state to answer the question */
if (direction == GST_PAD_SINK) { if (direction == GST_PAD_SINK) {
/* asked to convert size of an incoming buffer */ /* asked to convert size of an incoming buffer */
*othersize = resample_get_output_size_for_input (state, size); *othersize = resample_get_output_size_for_input (state, size);
@ -294,6 +296,11 @@ gboolean audioresample_transform_size (GstBaseTransform * base,
/* take a best guess, this is called cheating */ /* take a best guess, this is called cheating */
*othersize = floor (size * state->i_rate / state->o_rate); *othersize = floor (size * state->i_rate / state->o_rate);
} }
*othersize += state->sample_size;
/* 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);
if (!use_internal) { if (!use_internal) {
resample_free (state); resample_free (state);
@ -302,9 +309,9 @@ gboolean audioresample_transform_size (GstBaseTransform * base,
return ret; return ret;
} }
gboolean audioresample_set_caps (GstBaseTransform * base, GstCaps * incaps, gboolean
GstCaps * outcaps) audioresample_set_caps (GstBaseTransform * base, GstCaps * incaps,
{ GstCaps * outcaps) {
gboolean ret; gboolean ret;
gint inrate, outrate; gint inrate, outrate;
int channels; int channels;
@ -365,32 +372,45 @@ static GstFlowReturn
resample_add_input_data (r, data, size, NULL, NULL); resample_add_input_data (r, data, size, NULL, NULL);
outsize = resample_get_output_size (r); outsize = resample_get_output_size (r);
if (outsize != GST_BUFFER_SIZE (outbuf)) { GST_DEBUG_OBJECT (audioresample, "audioresample can give me %d bytes",
outsize);
/* protect against mem corruption */
if (outsize > GST_BUFFER_SIZE (outbuf)) {
GST_WARNING_OBJECT (audioresample, GST_WARNING_OBJECT (audioresample,
"overriding audioresample's outsize %d with outbuffer's size %d", "overriding audioresample's outsize %d with outbuffer's size %d",
outsize, GST_BUFFER_SIZE (outbuf)); outsize, GST_BUFFER_SIZE (outbuf));
outsize = GST_BUFFER_SIZE (outbuf); outsize = GST_BUFFER_SIZE (outbuf);
} }
/* catch possibly wrong size differences */
if (GST_BUFFER_SIZE (outbuf) - outsize > r->sample_size) {
GST_WARNING_OBJECT (audioresample,
"audioresample's outsize %d too far from outbuffer's size %d",
outsize, GST_BUFFER_SIZE (outbuf));
}
outsize = resample_get_output_data (r, GST_BUFFER_DATA (outbuf), outsize); outsize = resample_get_output_data (r, GST_BUFFER_DATA (outbuf), outsize);
GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (outbuf) =
audioresample->offset * GST_SECOND / audioresample->o_rate; audioresample->offset * GST_SECOND / audioresample->o_rate;
audioresample->offset += outsize / sizeof (gint16) / audioresample->channels; audioresample->offset += outsize / sizeof (gint16) / audioresample->channels;
GST_BUFFER_DURATION (outbuf) = outsize * GST_SECOND / audioresample->o_rate;
if (outsize != GST_BUFFER_SIZE (outbuf)) { /* check for possible mem corruption */
if (outsize > GST_BUFFER_SIZE (outbuf)) {
/* this is an error that when it happens, would need fixing in the
* resample library; we told
* it we wanted only GST_BUFFER_SIZE (outbuf), and it gave us more ! */
GST_WARNING_OBJECT (audioresample, GST_WARNING_OBJECT (audioresample,
"audioresample, you bastard ! you only gave me %d bytes, not %d", "audioresample, you memory corrupting bastard. "
"you gave me outsize %d while my buffer was size %d",
outsize, GST_BUFFER_SIZE (outbuf));
return GST_FLOW_ERROR;
}
/* catch possibly wrong size differences */
if (GST_BUFFER_SIZE (outbuf) - outsize > r->sample_size) {
GST_WARNING_OBJECT (audioresample,
"audioresample's written outsize %d too far from outbuffer's size %d",
outsize, GST_BUFFER_SIZE (outbuf)); outsize, GST_BUFFER_SIZE (outbuf));
/* if the size we get is smaller than the buffer, it's still fine; we
* just waste a bit of space on the end */
if (outsize < GST_BUFFER_SIZE (outbuf)) {
GST_BUFFER_SIZE (outbuf) = outsize;
return GST_FLOW_OK;
} else {
/* this is an error that needs fixing in the resample library; we told
* it we wanted only GST_BUFFER_SIZE (outbuf), and it gave us more ! */
return GST_FLOW_ERROR;
}
} }
return GST_FLOW_OK; return GST_FLOW_OK;
@ -408,7 +428,7 @@ static void
switch (prop_id) { switch (prop_id) {
case ARG_FILTERLEN: case ARG_FILTERLEN:
audioresample->filter_length = g_value_get_int (value); audioresample->filter_length = g_value_get_int (value);
GST_DEBUG_OBJECT (GST_ELEMENT (audioresample), "new filter length %d\n", GST_DEBUG_OBJECT (GST_ELEMENT (audioresample), "new filter length %d",
audioresample->filter_length); audioresample->filter_length);
resample_set_filter_length (audioresample->resample, resample_set_filter_length (audioresample->resample,
audioresample->filter_length); audioresample->filter_length);

View file

@ -42,11 +42,16 @@ void
resample_init (void) resample_init (void)
{ {
static int inited = 0; static int inited = 0;
const char *debug;
if (!inited) { if (!inited) {
oil_init (); oil_init ();
inited = 1; inited = 1;
} }
if ((debug = g_getenv ("RESAMPLE_DEBUG"))) {
resample_debug_set_level (atoi (debug));
}
} }
ResampleState * ResampleState *
@ -141,14 +146,24 @@ resample_input_eos (ResampleState * r)
int int
resample_get_output_size_for_input (ResampleState * r, int size) resample_get_output_size_for_input (ResampleState * r, int size)
{ {
return floor (size * r->o_rate / r->i_rate); int outsize;
double outd;
g_return_val_if_fail (r->sample_size != 0, 0);
RESAMPLE_DEBUG ("size %d, o_rate %f, i_rate %f", size, r->o_rate, r->i_rate);
outd = (double) size / r->i_rate * r->o_rate;
outsize = (int) floor (outd);
/* round off for sample size */
return outsize - (outsize % r->sample_size);
} }
int int
resample_get_output_size (ResampleState * r) resample_get_output_size (ResampleState * r)
{ {
return floor (audioresample_buffer_queue_get_depth (r->queue) * r->o_rate / return resample_get_output_size_for_input (r,
r->i_rate); audioresample_buffer_queue_get_depth (r->queue));
} }
int int
@ -196,6 +211,7 @@ void
resample_set_n_channels (ResampleState * r, int n_channels) resample_set_n_channels (ResampleState * r, int n_channels)
{ {
r->n_channels = n_channels; r->n_channels = n_channels;
r->sample_size = r->n_channels * resample_format_size (r->format);
r->need_reinit = 1; r->need_reinit = 1;
} }
@ -203,6 +219,7 @@ void
resample_set_format (ResampleState * r, ResampleFormat format) resample_set_format (ResampleState * r, ResampleFormat format)
{ {
r->format = format; r->format = format;
r->sample_size = r->n_channels * resample_format_size (r->format);
r->need_reinit = 1; r->need_reinit = 1;
} }

View file

@ -56,7 +56,6 @@ void
resample_scale_chunk (ResampleState * r) resample_scale_chunk (ResampleState * r)
{ {
if (r->need_reinit) { if (r->need_reinit) {
r->sample_size = r->n_channels * resample_format_size (r->format);
RESAMPLE_DEBUG ("sample size %d", r->sample_size); RESAMPLE_DEBUG ("sample size %d", r->sample_size);
if (r->buffer) if (r->buffer)

View file

@ -109,7 +109,6 @@ resample_scale_functable (ResampleState * r)
if (r->need_reinit) { if (r->need_reinit) {
double hanning_width; double hanning_width;
r->sample_size = r->n_channels * resample_format_size (r->format);
RESAMPLE_DEBUG ("sample size %d", r->sample_size); RESAMPLE_DEBUG ("sample size %d", r->sample_size);
if (r->buffer) if (r->buffer)

View file

@ -56,7 +56,6 @@ void
resample_scale_ref (ResampleState * r) resample_scale_ref (ResampleState * r)
{ {
if (r->need_reinit) { if (r->need_reinit) {
r->sample_size = r->n_channels * resample_format_size (r->format);
RESAMPLE_DEBUG ("sample size %d", r->sample_size); RESAMPLE_DEBUG ("sample size %d", r->sample_size);
if (r->buffer) if (r->buffer)
@ -88,19 +87,24 @@ resample_scale_ref (ResampleState * r)
#endif #endif
} }
while (r->o_size > 0) { RESAMPLE_DEBUG ("asked to resample %d bytes", r->o_size);
while (r->o_size >= r->sample_size) {
double midpoint; double midpoint;
int i; int i;
int j; int j;
RESAMPLE_DEBUG ("i_start %g", r->i_start);
midpoint = r->i_start + (r->filter_length - 1) * 0.5 * r->i_inc; midpoint = r->i_start + (r->filter_length - 1) * 0.5 * r->i_inc;
RESAMPLE_DEBUG ("still need to output %d bytes, i_start %g, midpoint %f",
r->o_size, r->i_start, midpoint);
if (midpoint > 0.5 * r->i_inc) { if (midpoint > 0.5 * r->i_inc) {
RESAMPLE_ERROR ("inconsistent state"); RESAMPLE_ERROR ("inconsistent state");
} }
while (midpoint < -0.5 * r->i_inc) { while (midpoint < -0.5 * r->i_inc) {
AudioresampleBuffer *buffer; AudioresampleBuffer *buffer;
RESAMPLE_DEBUG ("midpoint %f < %f, r->i_inc %f", midpoint,
-0.5 * r->i_inc, r->i_inc);
buffer = audioresample_buffer_queue_pull (r->queue, r->sample_size); buffer = audioresample_buffer_queue_pull (r->queue, r->sample_size);
if (buffer == NULL) { if (buffer == NULL) {
RESAMPLE_ERROR ("buffer_queue_pull returned NULL"); RESAMPLE_ERROR ("buffer_queue_pull returned NULL");
@ -206,5 +210,4 @@ resample_scale_ref (ResampleState * r)
r->o_buf += r->sample_size; r->o_buf += r->sample_size;
r->o_size -= r->sample_size; r->o_size -= r->sample_size;
} }
} }