pcm_utils: pass only one buffer size to pcm_mix()
pcm_mix() might overflow the destination buffer if it is smaller than the second buffer. This is ok because the physical buffer size passed by cross_fade_apply() is always big enough, but clutters pcm_mix() with complicated length checks and contains a dangerous buffer overflow pitfall. Simplify pcm_mix()/pcm_add() and pass only the smaller buffer size; let cross_fade_apply() do the memcpy().
This commit is contained in:
parent
6e21e24cae
commit
c85b570ad7
@ -49,14 +49,28 @@ void cross_fade_apply(ob_chunk * a, const ob_chunk * b,
|
|||||||
const struct audio_format *format,
|
const struct audio_format *format,
|
||||||
unsigned int current_chunk, unsigned int num_chunks)
|
unsigned int current_chunk, unsigned int num_chunks)
|
||||||
{
|
{
|
||||||
|
size_t size;
|
||||||
|
|
||||||
assert(current_chunk <= num_chunks);
|
assert(current_chunk <= num_chunks);
|
||||||
|
|
||||||
|
size = b->chunkSize > a->chunkSize
|
||||||
|
? a->chunkSize
|
||||||
|
: b->chunkSize;
|
||||||
|
|
||||||
pcm_mix(a->data,
|
pcm_mix(a->data,
|
||||||
b->data,
|
b->data,
|
||||||
a->chunkSize,
|
size,
|
||||||
b->chunkSize,
|
|
||||||
format,
|
format,
|
||||||
((float)current_chunk) / num_chunks);
|
((float)current_chunk) / num_chunks);
|
||||||
if (b->chunkSize > a->chunkSize)
|
|
||||||
|
if (b->chunkSize > a->chunkSize) {
|
||||||
|
/* the second buffer is larger than the first one:
|
||||||
|
there is unmixed rest at the end. Copy it over.
|
||||||
|
The output buffer API guarantees that there is
|
||||||
|
enough room in a->data. */
|
||||||
|
memcpy(a->data + a->chunkSize,
|
||||||
|
b->data + a->chunkSize,
|
||||||
|
b->chunkSize - a->chunkSize);
|
||||||
a->chunkSize = b->chunkSize;
|
a->chunkSize = b->chunkSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,8 +90,8 @@ void pcm_volumeChange(char *buffer, int bufferSize,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pcm_add(char *buffer1, const char *buffer2, size_t bufferSize1,
|
static void pcm_add(char *buffer1, const char *buffer2, size_t size,
|
||||||
size_t bufferSize2, int vol1, int vol2,
|
int vol1, int vol2,
|
||||||
const struct audio_format *format)
|
const struct audio_format *format)
|
||||||
{
|
{
|
||||||
int32_t temp32;
|
int32_t temp32;
|
||||||
@ -102,7 +102,7 @@ static void pcm_add(char *buffer1, const char *buffer2, size_t bufferSize1,
|
|||||||
|
|
||||||
switch (format->bits) {
|
switch (format->bits) {
|
||||||
case 16:
|
case 16:
|
||||||
while (bufferSize1 > 0 && bufferSize2 > 0) {
|
while (size > 0) {
|
||||||
temp32 =
|
temp32 =
|
||||||
(vol1 * (*buffer16_1) +
|
(vol1 * (*buffer16_1) +
|
||||||
vol2 * (*buffer16_2));
|
vol2 * (*buffer16_2));
|
||||||
@ -112,14 +112,11 @@ static void pcm_add(char *buffer1, const char *buffer2, size_t bufferSize1,
|
|||||||
*buffer16_1 = pcm_range(temp32, 16);
|
*buffer16_1 = pcm_range(temp32, 16);
|
||||||
buffer16_1++;
|
buffer16_1++;
|
||||||
buffer16_2++;
|
buffer16_2++;
|
||||||
bufferSize1 -= 2;
|
size -= 2;
|
||||||
bufferSize2 -= 2;
|
|
||||||
}
|
}
|
||||||
if (bufferSize2 > 0)
|
|
||||||
memcpy(buffer16_1, buffer16_2, bufferSize2);
|
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
while (bufferSize1 > 0 && bufferSize2 > 0) {
|
while (size > 0) {
|
||||||
temp32 =
|
temp32 =
|
||||||
(vol1 * (*buffer8_1) + vol2 * (*buffer8_2));
|
(vol1 * (*buffer8_1) + vol2 * (*buffer8_2));
|
||||||
temp32 += pcm_dither();
|
temp32 += pcm_dither();
|
||||||
@ -128,20 +125,16 @@ static void pcm_add(char *buffer1, const char *buffer2, size_t bufferSize1,
|
|||||||
*buffer8_1 = pcm_range(temp32, 8);
|
*buffer8_1 = pcm_range(temp32, 8);
|
||||||
buffer8_1++;
|
buffer8_1++;
|
||||||
buffer8_2++;
|
buffer8_2++;
|
||||||
bufferSize1--;
|
size--;
|
||||||
bufferSize2--;
|
|
||||||
}
|
}
|
||||||
if (bufferSize2 > 0)
|
|
||||||
memcpy(buffer8_1, buffer8_2, bufferSize2);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
FATAL("%i bits not supported by pcm_add!\n", format->bits);
|
FATAL("%i bits not supported by pcm_add!\n", format->bits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_mix(char *buffer1, const char *buffer2, size_t bufferSize1,
|
void pcm_mix(char *buffer1, const char *buffer2, size_t size,
|
||||||
size_t bufferSize2, const struct audio_format *format,
|
const struct audio_format *format, float portion1)
|
||||||
float portion1)
|
|
||||||
{
|
{
|
||||||
int vol1;
|
int vol1;
|
||||||
float s = sin(M_PI_2 * portion1);
|
float s = sin(M_PI_2 * portion1);
|
||||||
@ -150,8 +143,7 @@ void pcm_mix(char *buffer1, const char *buffer2, size_t bufferSize1,
|
|||||||
vol1 = s * 1000 + 0.5;
|
vol1 = s * 1000 + 0.5;
|
||||||
vol1 = vol1 > 1000 ? 1000 : (vol1 < 0 ? 0 : vol1);
|
vol1 = vol1 > 1000 ? 1000 : (vol1 < 0 ? 0 : vol1);
|
||||||
|
|
||||||
pcm_add(buffer1, buffer2, bufferSize1, bufferSize2, vol1, 1000 - vol1,
|
pcm_add(buffer1, buffer2, size, vol1, 1000 - vol1, format);
|
||||||
format);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LIBSAMPLERATE
|
#ifdef HAVE_LIBSAMPLERATE
|
||||||
|
@ -47,8 +47,8 @@ typedef struct _ConvState {
|
|||||||
void pcm_volumeChange(char *buffer, int bufferSize, const struct audio_format *format,
|
void pcm_volumeChange(char *buffer, int bufferSize, const struct audio_format *format,
|
||||||
int volume);
|
int volume);
|
||||||
|
|
||||||
void pcm_mix(char *buffer1, const char *buffer2, size_t bufferSize1,
|
void pcm_mix(char *buffer1, const char *buffer2, size_t size,
|
||||||
size_t bufferSize2, const struct audio_format *format, float portion1);
|
const struct audio_format *format, float portion1);
|
||||||
|
|
||||||
size_t pcm_convertAudioFormat(const struct audio_format *inFormat,
|
size_t pcm_convertAudioFormat(const struct audio_format *inFormat,
|
||||||
const char *inBuffer, size_t inSize,
|
const char *inBuffer, size_t inSize,
|
||||||
|
Loading…
Reference in New Issue
Block a user