mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-14 10:37:38 +01:00
Fix stack overflow when seeking with segments/layers
This commit is contained in:
parent
471dadb43f
commit
c6bd158700
@ -28,7 +28,6 @@ void render_vgmstream_segmented(sample_t* outbuf, int32_t sample_count, VGMSTREA
|
||||
|
||||
samples_this_block = vgmstream_get_samples(data->segments[data->current_segment]);
|
||||
|
||||
//VGM_LOG("segment decode start: cur=%i, this=%i, into=%i\n", data->current_segment, samples_this_block, vgmstream->samples_into_block);
|
||||
while (samples_written < sample_count) {
|
||||
int samples_to_do;
|
||||
|
||||
@ -39,7 +38,7 @@ void render_vgmstream_segmented(sample_t* outbuf, int32_t sample_count, VGMSTREA
|
||||
}
|
||||
|
||||
/* detect segment change and restart (after loop, but before decode, to allow looping to kick in) */
|
||||
if (vgmstream->samples_into_block == samples_this_block) {
|
||||
if (vgmstream->samples_into_block >= samples_this_block) {
|
||||
data->current_segment++;
|
||||
|
||||
/* could happen on last segment trying to decode more samples */
|
||||
@ -63,6 +62,11 @@ void render_vgmstream_segmented(sample_t* outbuf, int32_t sample_count, VGMSTREA
|
||||
if (samples_to_do > VGMSTREAM_SEGMENT_SAMPLE_BUFFER /*&& use_internal_buffer*/) /* always for fade/etc mixes */
|
||||
samples_to_do = VGMSTREAM_SEGMENT_SAMPLE_BUFFER;
|
||||
|
||||
if (samples_to_do < 0) { /* ? */
|
||||
VGM_LOG("SEGMENTED: wrong samples_to_do %i found\n", samples_to_do);
|
||||
break;
|
||||
}
|
||||
|
||||
render_vgmstream(
|
||||
use_internal_buffer ?
|
||||
data->buffer : &outbuf[samples_written * data->output_channels],
|
||||
|
47
src/render.c
47
src/render.c
@ -243,9 +243,8 @@ static int render_layout(sample_t* buf, int32_t sample_count, VGMSTREAM* vgmstre
|
||||
|
||||
if (vgmstream->current_sample > vgmstream->num_samples) {
|
||||
int channels = vgmstream->channels;
|
||||
int to_do = sample_count;
|
||||
int done = 0;
|
||||
memset(buf + done * channels, 0, to_do * sizeof(sample_t) * channels);
|
||||
|
||||
memset(buf, 0, sample_count * sizeof(sample_t) * channels);
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
@ -310,27 +309,33 @@ static int render_layout(sample_t* buf, int32_t sample_count, VGMSTREAM* vgmstre
|
||||
|
||||
if (vgmstream->current_sample > vgmstream->num_samples) {
|
||||
int channels = vgmstream->channels;
|
||||
int to_do = (vgmstream->current_sample - vgmstream->num_samples);
|
||||
int done = sample_count - to_do;
|
||||
memset(buf + done * channels, 0, to_do * sizeof(sample_t) * channels);
|
||||
int32_t excess, decoded;
|
||||
|
||||
excess = (vgmstream->current_sample - vgmstream->num_samples);
|
||||
if (excess > sample_count)
|
||||
excess = sample_count;
|
||||
decoded = sample_count - excess;
|
||||
|
||||
memset(buf + decoded * channels, 0, excess * sizeof(sample_t) * channels);
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
|
||||
static void render_trim(VGMSTREAM* vgmstream) {
|
||||
/* big-ish buffer since the average trim would be a few seconds for >=2ch at 48000, and less calls = better */
|
||||
sample_t tmpbuf[0x40000];
|
||||
int max_samples = 0x40000 / vgmstream->pstate.input_channels;
|
||||
sample_t* tmpbuf = vgmstream->tmpbuf;
|
||||
size_t tmpbuf_size = vgmstream->tmpbuf_size;
|
||||
int32_t buf_samples = tmpbuf_size / vgmstream->channels; /* base channels, no need to apply mixing */
|
||||
|
||||
while (vgmstream->pstate.trim_begin_left) {
|
||||
int to_do = vgmstream->pstate.trim_begin_left;
|
||||
if (to_do > max_samples)
|
||||
to_do = max_samples;
|
||||
if (to_do > buf_samples)
|
||||
to_do = buf_samples;
|
||||
|
||||
render_layout(tmpbuf, to_do, vgmstream);
|
||||
/* just consume samples so no need to apply mixing */
|
||||
/* no mixing */
|
||||
vgmstream->pstate.trim_begin_left -= to_do;
|
||||
}
|
||||
}
|
||||
@ -489,18 +494,18 @@ static void seek_force_loop(VGMSTREAM* vgmstream) {
|
||||
}
|
||||
|
||||
static void seek_force_decode(VGMSTREAM* vgmstream, int samples) {
|
||||
sample_t tmpbuf[0x40000]; /* big-ish buffer as less calls = better */
|
||||
int32_t buf_samples = 0x40000 / vgmstream->channels; /* base channels, no need to apply mixing */
|
||||
sample_t* tmpbuf = vgmstream->tmpbuf;
|
||||
size_t tmpbuf_size = vgmstream->tmpbuf_size;
|
||||
int32_t buf_samples = tmpbuf_size / vgmstream->channels; /* base channels, no need to apply mixing */
|
||||
|
||||
int i;
|
||||
while (samples) {
|
||||
int to_do = samples;
|
||||
if (to_do > buf_samples)
|
||||
to_do = buf_samples;
|
||||
|
||||
for (i = 0; i < samples; i += buf_samples) {
|
||||
int to_get = buf_samples;
|
||||
if (i + buf_samples > samples)
|
||||
to_get = samples - i;
|
||||
|
||||
render_layout(tmpbuf, to_get, vgmstream);
|
||||
render_layout(tmpbuf, to_do, vgmstream);
|
||||
/* no mixing */
|
||||
samples -= to_do;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -726,6 +726,12 @@ VGMSTREAM* allocate_vgmstream(int channel_count, int loop_flag) {
|
||||
if (!vgmstream->loop_ch) goto fail;
|
||||
}
|
||||
|
||||
/* garbage buffer for decode discarding (local bufs may cause stack overflows with segments/layers)
|
||||
* in theory the bigger the better but in practice there isn't much difference */
|
||||
vgmstream->tmpbuf_size = 0x10000; /* for all channels */
|
||||
vgmstream->tmpbuf = malloc(sizeof(sample_t) * vgmstream->tmpbuf_size);
|
||||
|
||||
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->loop_flag = loop_flag;
|
||||
|
||||
@ -736,6 +742,7 @@ VGMSTREAM* allocate_vgmstream(int channel_count, int loop_flag) {
|
||||
fail:
|
||||
if (vgmstream) {
|
||||
mixing_close(vgmstream);
|
||||
free(vgmstream->tmpbuf);
|
||||
free(vgmstream->ch);
|
||||
free(vgmstream->start_ch);
|
||||
free(vgmstream->loop_ch);
|
||||
@ -776,6 +783,7 @@ void close_vgmstream(VGMSTREAM* vgmstream) {
|
||||
}
|
||||
|
||||
mixing_close(vgmstream);
|
||||
free(vgmstream->tmpbuf);
|
||||
free(vgmstream->ch);
|
||||
free(vgmstream->start_ch);
|
||||
free(vgmstream->loop_ch);
|
||||
|
@ -975,6 +975,8 @@ typedef struct {
|
||||
play_state_t pstate; /* player state (applied over decoding) */
|
||||
int loop_count; /* counter of complete loops (1=looped once) */
|
||||
int loop_target; /* max loops before continuing with the stream end (loops forever if not set) */
|
||||
sample_t* tmpbuf; /* garbage buffer used for seeking/trimming */
|
||||
size_t tmpbuf_size; /* for all channels (samples = tmpbuf_size / channels) */
|
||||
|
||||
} VGMSTREAM;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user