audio: libsamplerate can't resample in-place; make space for a copy if needed.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
diff --git a/src/audio/SDL_audiocvt.c b/src/audio/SDL_audiocvt.c
index 73fb0c7..02b0559 100644
--- a/src/audio/SDL_audiocvt.c
+++ b/src/audio/SDL_audiocvt.c
@@ -867,7 +867,6 @@ struct SDL_AudioStream
SDL_AudioCVT cvt_before_resampling;
SDL_AudioCVT cvt_after_resampling;
SDL_DataQueue *queue;
- Uint8 *work_buffer; /* always aligned to 16 bytes. */
Uint8 *work_buffer_base; /* maybe unaligned pointer from SDL_realloc(). */
int work_buffer_len;
int src_sample_frame_size;
@@ -887,6 +886,29 @@ struct SDL_AudioStream
SDL_CleanupAudioStreamResamplerFunc cleanup_resampler_func;
};
+static Uint8 *
+EnsureStreamBufferSize(SDL_AudioStream *stream, const int newlen)
+{
+ Uint8 *ptr;
+ size_t offset;
+
+ if (stream->work_buffer_len >= newlen) {
+ ptr = stream->work_buffer_base;
+ } else {
+ ptr = (Uint8 *) SDL_realloc(stream->work_buffer_base, newlen + 32);
+ if (!ptr) {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+ /* Make sure we're aligned to 16 bytes for SIMD code. */
+ stream->work_buffer_base = ptr;
+ stream->work_buffer_len = newlen;
+ }
+
+ offset = ((size_t) ptr) & 15;
+ return offset ? ptr + (16 - offset) : ptr;
+}
+
#ifdef HAVE_LIBSAMPLERATE_H
static int
SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
@@ -898,6 +920,17 @@ SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const void *_inbuf, const i
SRC_DATA data;
int result;
+ if (inbuf == ((const float *) outbuf)) { /* libsamplerate can't work in-place. */
+ Uint8 *ptr = EnsureStreamBufferSize(stream, inbuflen + outbuflen);
+ if (ptr == NULL) {
+ SDL_OutOfMemory();
+ return 0;
+ }
+ SDL_memcpy(ptr + outbuflen, ptr, inbuflen);
+ inbuf = (const float *) (ptr + outbuflen);
+ outbuf = (float *) ptr;
+ }
+
data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
data.input_frames = inbuflen / framelen;
data.input_frames_used = 0;
@@ -1125,24 +1158,6 @@ SDL_NewAudioStream(const SDL_AudioFormat src_format,
return retval;
}
-static Uint8 *
-EnsureStreamBufferSize(SDL_AudioStream *stream, const int newlen)
-{
- if (stream->work_buffer_len < newlen) {
- Uint8 *ptr = (Uint8 *) SDL_realloc(stream->work_buffer_base, newlen + 32);
- const size_t offset = ((size_t) ptr) & 15;
- if (!ptr) {
- SDL_OutOfMemory();
- return NULL;
- }
- /* Make sure we're aligned to 16 bytes for SIMD code. */
- stream->work_buffer = offset ? ptr + (16 - offset) : ptr;
- stream->work_buffer_base = ptr;
- stream->work_buffer_len = newlen;
- }
- return stream->work_buffer;
-}
-
int
SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _buflen)
{
@@ -1190,11 +1205,14 @@ SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _bufle
if (workbuf == NULL) {
return -1; /* probably out of memory. */
}
- if (buf == origbuf) { /* copy if we haven't before. */
- SDL_memcpy(workbuf, buf, buflen);
+ /* don't SDL_memcpy(workbuf, buf, buflen) here; our resampler can work inplace or not,
+ libsamplerate needs buffers to be separate; either way, avoid a copy here if possible. */
+ if (buf != origbuf) {
+ buf = workbuf; /* in case we realloc()'d the pointer. */
}
- buflen = stream->resampler_func(stream, workbuf, buflen, workbuf, workbuflen);
- buf = workbuf;
+ buflen = stream->resampler_func(stream, buf, buflen, workbuf, workbuflen);
+ buf = EnsureStreamBufferSize(stream, workbuflen);
+ SDL_assert(buf != NULL); /* shouldn't be growing, just aligning. */
}
if (stream->cvt_after_resampling.needed) {