aboutsummaryrefslogtreecommitdiff
path: root/src/stb_vorbis.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stb_vorbis.c')
-rw-r--r--src/stb_vorbis.c844
1 files changed, 426 insertions, 418 deletions
diff --git a/src/stb_vorbis.c b/src/stb_vorbis.c
index e2700157..0510edc7 100644
--- a/src/stb_vorbis.c
+++ b/src/stb_vorbis.c
@@ -107,14 +107,8 @@
// trade off storage for speed.
//#define STB_VORBIS_DIVIDES_IN_CODEBOOK
-// STB_VORBIS_CODEBOOK_SHORTS
-// The vorbis file format encodes VQ codebook floats as ax+b where a and
-// b are floating point per-codebook constants, and x is a 16-bit int.
-// Normally, stb_vorbis decodes them to floats rather than leaving them
-// as 16-bit ints and computing ax+b while decoding. This is a speed/space
-// tradeoff; you can save space by defining this flag.
-#ifndef STB_VORBIS_CODEBOOK_SHORTS
-#define STB_VORBIS_CODEBOOK_FLOATS
+#ifdef STB_VORBIS_CODEBOOK_SHORTS
+#error "STB_VORBIS_CODEBOOK_SHORTS is no longer supported as it produced incorrect results for some input formats"
#endif
// STB_VORBIS_DIVIDE_TABLE
@@ -175,11 +169,26 @@
#if !(defined(__APPLE__) || defined(MACOSX) || defined(macintosh) || defined(Macintosh))
#include <malloc.h>
#endif
-#else
+#else // STB_VORBIS_NO_CRT
#define NULL 0
-#endif
-
-#if !defined(_MSC_VER) && !(defined(__MINGW32__) && defined(__forceinline))
+#define malloc(s) 0
+#define free(s) ((void) 0)
+#define realloc(s) 0
+#endif // STB_VORBIS_NO_CRT
+
+#include <limits.h>
+
+#ifdef __MINGW32__
+ // eff you mingw:
+ // "fixed":
+ // http://sourceforge.net/p/mingw-w64/mailman/message/32882927/
+ // "no that broke the build, reverted, who cares about C":
+ // http://sourceforge.net/p/mingw-w64/mailman/message/32890381/
+ #ifdef __forceinline
+ #undef __forceinline
+ #endif
+ #define __forceinline
+#elif !defined(_MSC_VER)
#if __GNUC__
#define __forceinline inline
#else
@@ -196,6 +205,13 @@
#endif
+#if 0
+#include <crtdbg.h>
+#define CHECK(f) _CrtIsValidHeapPointer(f->channel_buffers[1])
+#else
+#define CHECK(f) ((void) 0)
+#endif
+
#define MAX_BLOCKSIZE_LOG 13 // from specification
#define MAX_BLOCKSIZE (1 << MAX_BLOCKSIZE_LOG)
@@ -212,11 +228,7 @@ typedef signed int int32;
#define FALSE 0
#endif
-#ifdef STB_VORBIS_CODEBOOK_FLOATS
typedef float codetype;
-#else
-typedef uint16 codetype;
-#endif
// @NOTE
//
@@ -336,8 +348,6 @@ typedef struct
typedef struct
{
uint32 page_start, page_end;
- uint32 after_previous_page_start;
- uint32 first_decoded_sample;
uint32 last_decoded_sample;
} ProbedPage;
@@ -452,13 +462,6 @@ struct stb_vorbis
int channel_buffer_end;
};
-extern int my_prof(int slot);
-//#define stb_prof my_prof
-
-#ifndef stb_prof
-#define stb_prof(x) ((void) 0)
-#endif
-
#if defined(STB_VORBIS_NO_PUSHDATA_API)
#define IS_PUSH_MODE(f) FALSE
#elif defined(STB_VORBIS_NO_PULLDATA_API)
@@ -525,7 +528,7 @@ static void *setup_malloc(vorb *f, int sz)
static void setup_free(vorb *f, void *p)
{
- if (f->alloc.alloc_buffer) return; // do nothing; setup mem is not a stack
+ if (f->alloc.alloc_buffer) return; // do nothing; setup mem is a stack
free(p);
}
@@ -557,7 +560,7 @@ static void crc32_init(void)
int i,j;
uint32 s;
for(i=0; i < 256; i++) {
- for (s=i<<24, j=0; j < 8; ++j)
+ for (s=(uint32) i << 24, j=0; j < 8; ++j)
s = (s << 1) ^ (s >= (1U<<31) ? CRC32_POLY : 0);
crc_table[i] = s;
}
@@ -658,7 +661,7 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values)
add_entry(c, 0, k, m++, len[k], values);
// add all available leaves
for (i=1; i <= len[k]; ++i)
- available[i] = 1 << (32-i);
+ available[i] = 1U << (32-i);
// note that the above code treats the first case specially,
// but it's really the same as the following code, so they
// could probably be combined (except the initial code is 0,
@@ -674,12 +677,14 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values)
// trivial to prove, but it seems true and the assert never
// fires, so!
while (z > 0 && !available[z]) --z;
- if (z == 0) { assert(0); return FALSE; }
+ if (z == 0) { return FALSE; }
res = available[z];
+ assert(z >= 0 && z < 32);
available[z] = 0;
add_entry(c, bit_reverse(res), i, m++, len[i], values);
// propogate availability up the tree
if (z != len[i]) {
+ assert(len[i] >= 0 && len[i] < 32);
for (y=len[i]; y > z; --y) {
assert(available[y] == 0);
available[y] = res + (1 << (32-y));
@@ -914,7 +919,7 @@ static uint32 get32(vorb *f)
x = get8(f);
x += get8(f) << 8;
x += get8(f) << 16;
- x += get8(f) << 24;
+ x += (uint32) get8(f) << 24;
return x;
}
@@ -1045,8 +1050,6 @@ static int start_page_no_capturepattern(vorb *f)
len += 27 + f->segment_count;
p.page_start = f->first_audio_page_offset;
p.page_end = p.page_start + len;
- p.after_previous_page_start = p.page_start;
- p.first_decoded_sample = 0;
p.last_decoded_sample = loc0;
f->p_first = p;
}
@@ -1189,7 +1192,7 @@ static __forceinline void prep_huffman(vorb *f)
if (f->last_seg && !f->bytes_in_seg) return;
z = get8_packet_raw(f);
if (z == EOP) return;
- f->acc += z << f->valid_bits;
+ f->acc += (unsigned) z << f->valid_bits;
f->valid_bits += 8;
} while (f->valid_bits <= 24);
}
@@ -1199,7 +1202,7 @@ enum
{
VORBIS_packet_id = 1,
VORBIS_packet_comment = 3,
- VORBIS_packet_setup = 5,
+ VORBIS_packet_setup = 5
};
static int codebook_decode_scalar_raw(vorb *f, Codebook *c)
@@ -1207,7 +1210,9 @@ static int codebook_decode_scalar_raw(vorb *f, Codebook *c)
int i;
prep_huffman(f);
- assert(c->sorted_codewords || c->codewords);
+ if (c->codewords == NULL && c->sorted_codewords == NULL)
+ return -1;
+
// cases to use binary search: sorted_codewords && !c->codewords
// sorted_codewords && c->entries > 8
if (c->entries > 8 ? c->sorted_codewords!=NULL : !c->codewords) {
@@ -1315,15 +1320,9 @@ static int codebook_decode_scalar(vorb *f, Codebook *c)
// CODEBOOK_ELEMENT_FAST is an optimization for the CODEBOOK_FLOATS case
// where we avoid one addition
-#ifndef STB_VORBIS_CODEBOOK_FLOATS
- #define CODEBOOK_ELEMENT(c,off) (c->multiplicands[off] * c->delta_value + c->minimum_value)
- #define CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off] * c->delta_value)
- #define CODEBOOK_ELEMENT_BASE(c) (c->minimum_value)
-#else
- #define CODEBOOK_ELEMENT(c,off) (c->multiplicands[off])
- #define CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off])
- #define CODEBOOK_ELEMENT_BASE(c) (0)
-#endif
+#define CODEBOOK_ELEMENT(c,off) (c->multiplicands[off])
+#define CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off])
+#define CODEBOOK_ELEMENT_BASE(c) (0)
static int codebook_decode_start(vorb *f, Codebook *c)
{
@@ -1515,7 +1514,6 @@ static int codebook_decode_deinterleave_repeat_2(vorb *f, Codebook *c, float **o
{
z *= c->dimensions;
- stb_prof(11);
if (c->sequence_p) {
// haven't optimized this case because I don't have any examples
for (i=0; i < effective; ++i) {
@@ -1527,7 +1525,7 @@ static int codebook_decode_deinterleave_repeat_2(vorb *f, Codebook *c, float **o
}
} else {
i=0;
- if (c_inter == 1) {
+ if (c_inter == 1 && i < effective) {
float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last;
if (outputs[c_inter])
outputs[c_inter][p_inter] += val;
@@ -1699,15 +1697,17 @@ static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y
#endif
ady -= abs(base) * adx;
if (x1 > n) x1 = n;
- LINE_OP(output[x], inverse_db_table[y]);
- for (++x; x < x1; ++x) {
- err += ady;
- if (err >= adx) {
- err -= adx;
- y += sy;
- } else
- y += base;
+ if (x < x1) {
LINE_OP(output[x], inverse_db_table[y]);
+ for (++x; x < x1; ++x) {
+ err += ady;
+ if (err >= adx) {
+ err -= adx;
+ y += sy;
+ } else
+ y += base;
+ LINE_OP(output[x], inverse_db_table[y]);
+ }
}
}
@@ -1746,7 +1746,8 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
int **classifications = (int **) temp_block_array(f,f->channels, part_read * sizeof(**classifications));
#endif
- stb_prof(2);
+ CHECK(f);
+
for (i=0; i < ch; ++i)
if (!do_not_decode[i])
memset(residue_buffers[i], 0, sizeof(float) * n);
@@ -1758,11 +1759,9 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
if (j == ch)
goto done;
- stb_prof(3);
for (pass=0; pass < 8; ++pass) {
int pcount = 0, class_set = 0;
if (ch == 2) {
- stb_prof(13);
while (pcount < part_read) {
int z = r->begin + pcount*r->part_size;
int c_inter = (z & 1), p_inter = z>>1;
@@ -1780,7 +1779,6 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
}
#endif
}
- stb_prof(5);
for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) {
int z = r->begin + pcount*r->part_size;
#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
@@ -1791,23 +1789,20 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
int b = r->residue_books[c][pass];
if (b >= 0) {
Codebook *book = f->codebooks + b;
- stb_prof(20); // accounts for X time
#ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK
if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
goto done;
#else
// saves 1%
- if (!codebook_decode_deinterleave_repeat_2(f, book, residue_buffers, &c_inter, &p_inter, n, r->part_size))
+ if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
goto done;
#endif
- stb_prof(7);
} else {
z += r->part_size;
c_inter = z & 1;
p_inter = z >> 1;
}
}
- stb_prof(8);
#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
++class_set;
#endif
@@ -1840,10 +1835,8 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
int b = r->residue_books[c][pass];
if (b >= 0) {
Codebook *book = f->codebooks + b;
- stb_prof(22);
if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
goto done;
- stb_prof(3);
} else {
z += r->part_size;
c_inter = 0;
@@ -1882,10 +1875,8 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
int b = r->residue_books[c][pass];
if (b >= 0) {
Codebook *book = f->codebooks + b;
- stb_prof(22);
if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
goto done;
- stb_prof(3);
} else {
z += r->part_size;
c_inter = z % ch;
@@ -1900,7 +1891,7 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
}
goto done;
}
- stb_prof(9);
+ CHECK(f);
for (pass=0; pass < 8; ++pass) {
int pcount = 0, class_set=0;
@@ -1949,7 +1940,7 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
}
}
done:
- stb_prof(0);
+ CHECK(f);
temp_alloc_restore(f,temp_alloc_point);
}
@@ -2761,18 +2752,36 @@ static int do_floor(vorb *f, Mapping *map, int i, int n, float *target, YTYPE *f
{
int hy = finalY[j] * g->floor1_multiplier;
int hx = g->Xlist[j];
- draw_line(target, lx,ly, hx,hy, n2);
+ if (lx != hx)
+ draw_line(target, lx,ly, hx,hy, n2);
+ CHECK(f);
lx = hx, ly = hy;
}
}
- if (lx < n2)
+ if (lx < n2) {
// optimization of: draw_line(target, lx,ly, n,ly, n2);
for (j=lx; j < n2; ++j)
LINE_OP(target[j], inverse_db_table[ly]);
+ CHECK(f);
+ }
}
return TRUE;
}
+// The meaning of "left" and "right"
+//
+// For a given frame:
+// we compute samples from 0..n
+// window_center is n/2
+// we'll window and mix the samples from left_start to left_end with data from the previous frame
+// all of the samples from left_end to right_start can be output without mixing; however,
+// this interval is 0-length except when transitioning between short and long frames
+// all of the samples from right_start to right_end need to be mixed with the next frame,
+// which we don't have, so those get saved in a buffer
+// frame N's right_end-right_start, the number of samples to mix with the next frame,
+// has to be the same as frame N+1's left_end-left_start (which they are by
+// construction)
+
static int vorbis_decode_initial(vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode)
{
Mode *m;
@@ -2825,6 +2834,7 @@ static int vorbis_decode_initial(vorb *f, int *p_left_start, int *p_left_end, in
*p_right_start = window_center;
*p_right_end = n;
}
+
return TRUE;
}
@@ -2843,7 +2853,8 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
// FLOORS
n2 = n >> 1;
- stb_prof(1);
+ CHECK(f);
+
for (i=0; i < f->channels; ++i) {
int s = map->chan[i].mux, floor;
zero_channel[i] = FALSE;
@@ -2935,7 +2946,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
// at this point we've decoded the floor into buffer
}
}
- stb_prof(0);
+ CHECK(f);
// at this point we've decoded all floors
if (f->alloc.alloc_buffer)
@@ -2948,6 +2959,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
zero_channel[map->chan[i].magnitude] = zero_channel[map->chan[i].angle] = FALSE;
}
+ CHECK(f);
// RESIDUE DECODE
for (i=0; i < map->submaps; ++i) {
float *residue_buffers[STB_VORBIS_MAX_CHANNELS];
@@ -2972,9 +2984,9 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
if (f->alloc.alloc_buffer)
assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset);
+ CHECK(f);
// INVERSE COUPLING
- stb_prof(14);
for (i = map->coupling_steps-1; i >= 0; --i) {
int n2 = n >> 1;
float *m = f->channel_buffers[map->chan[i].magnitude];
@@ -2995,10 +3007,10 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
a[j] = a2;
}
}
+ CHECK(f);
// finish decoding the floors
#ifndef STB_VORBIS_NO_DEFER_FLOOR
- stb_prof(15);
for (i=0; i < f->channels; ++i) {
if (really_zero_channel[i]) {
memset(f->channel_buffers[i], 0, sizeof(*f->channel_buffers[i]) * n2);
@@ -3018,10 +3030,10 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
#endif
// INVERSE MDCT
- stb_prof(16);
+ CHECK(f);
for (i=0; i < f->channels; ++i)
inverse_mdct(f->channel_buffers[i], n, f, m->blockflag);
- stb_prof(0);
+ CHECK(f);
// this shouldn't be necessary, unless we exited on an error
// and want to flush to get to the next packet
@@ -3039,9 +3051,15 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
f->current_loc_valid = TRUE;
f->first_decode = FALSE;
} else if (f->discard_samples_deferred) {
- left_start += f->discard_samples_deferred;
- *p_left = left_start;
- f->discard_samples_deferred = 0;
+ if (f->discard_samples_deferred >= right_start - left_start) {
+ f->discard_samples_deferred -= (right_start - left_start);
+ left_start = right_start;
+ *p_left = left_start;
+ } else {
+ left_start += f->discard_samples_deferred;
+ *p_left = left_start;
+ f->discard_samples_deferred = 0;
+ }
} else if (f->previous_length == 0 && f->current_loc_valid) {
// we're recovering from a seek... that means we're going to discard
// the samples from this packet even though we know our position from
@@ -3057,7 +3075,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) {
uint32 current_end = f->known_loc_for_packet - (n-right_end);
// then let's infer the size of the (probably) short final frame
- if (current_end < f->current_loc + right_end) {
+ if (current_end < f->current_loc + (right_end-left_start)) {
if (current_end < f->current_loc) {
// negative truncation, that's impossible!
*len = 0;
@@ -3065,6 +3083,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
*len = current_end - f->current_loc;
}
*len += left_start;
+ if (*len > right_end) *len = right_end; // this should never happen
f->current_loc += *len;
return TRUE;
}
@@ -3082,6 +3101,8 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
if (f->alloc.alloc_buffer)
assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset);
*len = right_end; // ignore samples after the window goes to 0
+ CHECK(f);
+
return TRUE;
}
@@ -3247,14 +3268,15 @@ static int start_decoder(vorb *f)
get32(f); // bitrate_nominal
get32(f); // bitrate_minimum
x = get8(f);
- { int log0,log1;
- log0 = x & 15;
- log1 = x >> 4;
- f->blocksize_0 = 1 << log0;
- f->blocksize_1 = 1 << log1;
- if (log0 < 6 || log0 > 13) return error(f, VORBIS_invalid_setup);
- if (log1 < 6 || log1 > 13) return error(f, VORBIS_invalid_setup);
- if (log0 > log1) return error(f, VORBIS_invalid_setup);
+ {
+ int log0,log1;
+ log0 = x & 15;
+ log1 = x >> 4;
+ f->blocksize_0 = 1 << log0;
+ f->blocksize_1 = 1 << log1;
+ if (log0 < 6 || log0 > 13) return error(f, VORBIS_invalid_setup);
+ if (log1 < 6 || log1 > 13) return error(f, VORBIS_invalid_setup);
+ if (log0 > log1) return error(f, VORBIS_invalid_setup);
}
// framing_flag
@@ -3303,6 +3325,7 @@ static int start_decoder(vorb *f)
int total=0;
uint8 *lengths;
Codebook *c = f->codebooks+i;
+ CHECK(f);
x = get_bits(f, 8); if (x != 0x42) return error(f, VORBIS_invalid_setup);
x = get_bits(f, 8); if (x != 0x43) return error(f, VORBIS_invalid_setup);
x = get_bits(f, 8); if (x != 0x56) return error(f, VORBIS_invalid_setup);
@@ -3314,6 +3337,8 @@ static int start_decoder(vorb *f)
ordered = get_bits(f,1);
c->sparse = ordered ? 0 : get_bits(f,1);
+ if (c->dimensions == 0 && c->entries != 0) return error(f, VORBIS_invalid_setup);
+
if (c->sparse)
lengths = (uint8 *) setup_temp_malloc(f, c->entries);
else
@@ -3338,6 +3363,8 @@ static int start_decoder(vorb *f)
if (present) {
lengths[j] = get_bits(f, 5) + 1;
++total;
+ if (lengths[j] == 32)
+ return error(f, VORBIS_invalid_setup);
} else {
lengths[j] = NO_CODE;
}
@@ -3350,6 +3377,7 @@ static int start_decoder(vorb *f)
f->setup_temp_memory_required = c->entries;
c->codeword_lengths = (uint8 *) setup_malloc(f, c->entries);
+ if (c->codeword_lengths == NULL) return error(f, VORBIS_outofmem);
memcpy(c->codeword_lengths, lengths, c->entries);
setup_temp_free(f, lengths, c->entries); // note this is only safe if there have been no intervening temp mallocs!
lengths = c->codeword_lengths;
@@ -3371,6 +3399,7 @@ static int start_decoder(vorb *f)
c->sorted_entries = sorted_count;
values = NULL;
+ CHECK(f);
if (!c->sparse) {
c->codewords = (uint32 *) setup_malloc(f, sizeof(c->codewords[0]) * c->entries);
if (!c->codewords) return error(f, VORBIS_outofmem);
@@ -3397,10 +3426,13 @@ static int start_decoder(vorb *f)
if (c->sorted_entries) {
// allocate an extra slot for sentinels
c->sorted_codewords = (uint32 *) setup_malloc(f, sizeof(*c->sorted_codewords) * (c->sorted_entries+1));
+ if (c->sorted_codewords == NULL) return error(f, VORBIS_outofmem);
// allocate an extra slot at the front so that c->sorted_values[-1] is defined
// so that we can catch that case without an extra if
c->sorted_values = ( int *) setup_malloc(f, sizeof(*c->sorted_values ) * (c->sorted_entries+1));
- if (c->sorted_values) { ++c->sorted_values; c->sorted_values[-1] = -1; }
+ if (c->sorted_values == NULL) return error(f, VORBIS_outofmem);
+ ++c->sorted_values;
+ c->sorted_values[-1] = -1;
compute_sorted_huffman(c, lengths, values);
}
@@ -3413,6 +3445,7 @@ static int start_decoder(vorb *f)
compute_accelerated_huffman(c);
+ CHECK(f);
c->lookup_type = get_bits(f, 4);
if (c->lookup_type > 2) return error(f, VORBIS_invalid_setup);
if (c->lookup_type > 0) {
@@ -3426,6 +3459,7 @@ static int start_decoder(vorb *f)
} else {
c->lookup_values = c->entries * c->dimensions;
}
+ if (c->lookup_values == 0) return error(f, VORBIS_invalid_setup);
mults = (uint16 *) setup_temp_malloc(f, sizeof(mults[0]) * c->lookup_values);
if (mults == NULL) return error(f, VORBIS_outofmem);
for (j=0; j < (int) c->lookup_values; ++j) {
@@ -3437,6 +3471,7 @@ static int start_decoder(vorb *f)
#ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK
if (c->lookup_type == 1) {
int len, sparse = c->sparse;
+ float last=0;
// pre-expand the lookup1-style multiplicands, to avoid a divide in the inner loop
if (sparse) {
if (c->sorted_entries == 0) goto skip;
@@ -3446,21 +3481,22 @@ static int start_decoder(vorb *f)
if (c->multiplicands == NULL) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); }
len = sparse ? c->sorted_entries : c->entries;
for (j=0; j < len; ++j) {
- int z = sparse ? c->sorted_values[j] : j, div=1;
+ unsigned int z = sparse ? c->sorted_values[j] : j;
+ unsigned int div=1;
for (k=0; k < c->dimensions; ++k) {
int off = (z / div) % c->lookup_values;
- c->multiplicands[j*c->dimensions + k] =
- #ifndef STB_VORBIS_CODEBOOK_FLOATS
- mults[off];
- #else
- mults[off]*c->delta_value + c->minimum_value;
- // in this case (and this case only) we could pre-expand c->sequence_p,
- // and throw away the decode logic for it; have to ALSO do
- // it in the case below, but it can only be done if
- // STB_VORBIS_CODEBOOK_FLOATS
- // !STB_VORBIS_DIVIDES_IN_CODEBOOK
- #endif
- div *= c->lookup_values;
+ float val = mults[off];
+ val = mults[off]*c->delta_value + c->minimum_value + last;
+ c->multiplicands[j*c->dimensions + k] = val;
+ if (c->sequence_p)
+ last = val;
+ if (k+1 < c->dimensions) {
+ if (div > UINT_MAX / (unsigned int) c->lookup_values) {
+ setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values);
+ return error(f, VORBIS_invalid_setup);
+ }
+ div *= c->lookup_values;
+ }
}
}
setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values);
@@ -3469,27 +3505,25 @@ static int start_decoder(vorb *f)
else
#endif
{
+ float last=0;
+ CHECK(f);
c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->lookup_values);
- #ifndef STB_VORBIS_CODEBOOK_FLOATS
- memcpy(c->multiplicands, mults, sizeof(c->multiplicands[0]) * c->lookup_values);
- #else
- for (j=0; j < (int) c->lookup_values; ++j)
- c->multiplicands[j] = mults[j] * c->delta_value + c->minimum_value;
- #endif
+ if (c->multiplicands == NULL) { setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); }
+ for (j=0; j < (int) c->lookup_values; ++j) {
+ float val = mults[j] * c->delta_value + c->minimum_value + last;
+ c->multiplicands[j] = val;
+ if (c->sequence_p)
+ last = val;
+ }
setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values);
}
#ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK
skip:;
#endif
- #ifdef STB_VORBIS_CODEBOOK_FLOATS
- if (c->lookup_type == 2 && c->sequence_p) {
- for (j=1; j < (int) c->lookup_values; ++j)
- c->multiplicands[j] = c->multiplicands[j-1];
- c->sequence_p = 0;
- }
- #endif
+ CHECK(f);
}
+ CHECK(f);
}
// time domain transfers (notused)
@@ -3503,6 +3537,7 @@ static int start_decoder(vorb *f)
// Floors
f->floor_count = get_bits(f, 6)+1;
f->floor_config = (Floor *) setup_malloc(f, f->floor_count * sizeof(*f->floor_config));
+ if (f->floor_config == NULL) return error(f, VORBIS_outofmem);
for (i=0; i < f->floor_count; ++i) {
f->floor_types[i] = get_bits(f, 16);
if (f->floor_types[i] > 1) return error(f, VORBIS_invalid_setup);
@@ -3574,7 +3609,9 @@ static int start_decoder(vorb *f)
// Residue
f->residue_count = get_bits(f, 6)+1;
- f->residue_config = (Residue *) setup_malloc(f, f->residue_count * sizeof(*f->residue_config));
+ f->residue_config = (Residue *) setup_malloc(f, f->residue_count * sizeof(f->residue_config[0]));
+ if (f->residue_config == NULL) return error(f, VORBIS_outofmem);
+ memset(f->residue_config, 0, f->residue_count * sizeof(f->residue_config[0]));
for (i=0; i < f->residue_count; ++i) {
uint8 residue_cascade[64];
Residue *r = f->residue_config+i;
@@ -3582,9 +3619,11 @@ static int start_decoder(vorb *f)
if (f->residue_types[i] > 2) return error(f, VORBIS_invalid_setup);
r->begin = get_bits(f, 24);
r->end = get_bits(f, 24);
+ if (r->end < r->begin) return error(f, VORBIS_invalid_setup);
r->part_size = get_bits(f,24)+1;
r->classifications = get_bits(f,6)+1;
r->classbook = get_bits(f,8);
+ if (r->classbook >= f->codebook_count) return error(f, VORBIS_invalid_setup);
for (j=0; j < r->classifications; ++j) {
uint8 high_bits=0;
uint8 low_bits=get_bits(f,3);
@@ -3593,6 +3632,7 @@ static int start_decoder(vorb *f)
residue_cascade[j] = high_bits*8 + low_bits;
}
r->residue_books = (short (*)[8]) setup_malloc(f, sizeof(r->residue_books[0]) * r->classifications);
+ if (r->residue_books == NULL) return error(f, VORBIS_outofmem);
for (j=0; j < r->classifications; ++j) {
for (k=0; k < 8; ++k) {
if (residue_cascade[j] & (1 << k)) {
@@ -3612,6 +3652,7 @@ static int start_decoder(vorb *f)
int classwords = f->codebooks[r->classbook].dimensions;
int temp = j;
r->classdata[j] = (uint8 *) setup_malloc(f, sizeof(r->classdata[j][0]) * classwords);
+ if (r->classdata[j] == NULL) return error(f, VORBIS_outofmem);
for (k=classwords-1; k >= 0; --k) {
r->classdata[j][k] = temp % r->classifications;
temp /= r->classifications;
@@ -3621,11 +3662,14 @@ static int start_decoder(vorb *f)
f->mapping_count = get_bits(f,6)+1;
f->mapping = (Mapping *) setup_malloc(f, f->mapping_count * sizeof(*f->mapping));
+ if (f->mapping == NULL) return error(f, VORBIS_outofmem);
+ memset(f->mapping, 0, f->mapping_count * sizeof(*f->mapping));
for (i=0; i < f->mapping_count; ++i) {
Mapping *m = f->mapping + i;
int mapping_type = get_bits(f,16);
if (mapping_type != 0) return error(f, VORBIS_invalid_setup);
m->chan = (MappingChannel *) setup_malloc(f, f->channels * sizeof(*m->chan));
+ if (m->chan == NULL) return error(f, VORBIS_outofmem);
if (get_bits(f,1))
m->submaps = get_bits(f,4)+1;
else
@@ -3686,8 +3730,10 @@ static int start_decoder(vorb *f)
f->channel_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1);
f->previous_window[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2);
f->finalY[i] = (int16 *) setup_malloc(f, sizeof(int16) * longest_floorlist);
+ if (f->channel_buffers[i] == NULL || f->previous_window[i] == NULL || f->finalY[i] == NULL) return error(f, VORBIS_outofmem);
#ifdef STB_VORBIS_NO_DEFER_FLOOR
f->floor_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2);
+ if (f->floor_buffers[i] == NULL) return error(f, VORBIS_outofmem);
#endif
}
@@ -3745,17 +3791,20 @@ static int start_decoder(vorb *f)
static void vorbis_deinit(stb_vorbis *p)
{
int i,j;
- for (i=0; i < p->residue_count; ++i) {
- Residue *r = p->residue_config+i;
- if (r->classdata) {
- for (j=0; j < p->codebooks[r->classbook].entries; ++j)
- setup_free(p, r->classdata[j]);
- setup_free(p, r->classdata);
+ if (p->residue_config) {
+ for (i=0; i < p->residue_count; ++i) {
+ Residue *r = p->residue_config+i;
+ if (r->classdata) {
+ for (j=0; j < p->codebooks[r->classbook].entries; ++j)
+ setup_free(p, r->classdata[j]);
+ setup_free(p, r->classdata);
+ }
+ setup_free(p, r->residue_books);
}
- setup_free(p, r->residue_books);
}
if (p->codebooks) {
+ CHECK(p);
for (i=0; i < p->codebook_count; ++i) {
Codebook *c = p->codebooks + i;
setup_free(p, c->codeword_lengths);
@@ -3769,10 +3818,13 @@ static void vorbis_deinit(stb_vorbis *p)
}
setup_free(p, p->floor_config);
setup_free(p, p->residue_config);
- for (i=0; i < p->mapping_count; ++i)
- setup_free(p, p->mapping[i].chan);
- setup_free(p, p->mapping);
- for (i=0; i < p->channels; ++i) {
+ if (p->mapping) {
+ for (i=0; i < p->mapping_count; ++i)
+ setup_free(p, p->mapping[i].chan);
+ setup_free(p, p->mapping);
+ }
+ CHECK(p);
+ for (i=0; i < p->channels && i < STB_VORBIS_MAX_CHANNELS; ++i) {
setup_free(p, p->channel_buffers[i]);
setup_free(p, p->previous_window[i]);
#ifdef STB_VORBIS_NO_DEFER_FLOOR
@@ -3799,7 +3851,7 @@ void stb_vorbis_close(stb_vorbis *p)
setup_free(p,p);
}
-static void vorbis_init(stb_vorbis *p, stb_vorbis_alloc *z)
+static void vorbis_init(stb_vorbis *p, const stb_vorbis_alloc *z)
{
memset(p, 0, sizeof(*p)); // NULL out all malloc'd pointers to start
if (z) {
@@ -3957,11 +4009,11 @@ static int vorbis_search_for_page_pushdata(vorb *f, uint8 *data, int data_len)
// return value: number of bytes we used
int stb_vorbis_decode_frame_pushdata(
- stb_vorbis *f, // the file we're decoding
- uint8 *data, int data_len, // the memory available for decoding
- int *channels, // place to write number of float * buffers
- float ***output, // place to write float ** array of float * buffers
- int *samples // place to write number of output samples
+ stb_vorbis *f, // the file we're decoding
+ const uint8 *data, int data_len, // the memory available for decoding
+ int *channels, // place to write number of float * buffers
+ float ***output, // place to write float ** array of float * buffers
+ int *samples // place to write number of output samples
)
{
int i;
@@ -3971,11 +4023,11 @@ int stb_vorbis_decode_frame_pushdata(
if (f->page_crc_tests >= 0) {
*samples = 0;
- return vorbis_search_for_page_pushdata(f, data, data_len);
+ return vorbis_search_for_page_pushdata(f, (uint8 *) data, data_len);
}
- f->stream = data;
- f->stream_end = data + data_len;
+ f->stream = (uint8 *) data;
+ f->stream_end = (uint8 *) data + data_len;
f->error = VORBIS__no_error;
// check that we have the entire packet in memory
@@ -4027,14 +4079,14 @@ int stb_vorbis_decode_frame_pushdata(
}
stb_vorbis *stb_vorbis_open_pushdata(
- unsigned char *data, int data_len, // the memory available for decoding
+ const unsigned char *data, int data_len, // the memory available for decoding
int *data_used, // only defined if result is not NULL
- int *error, stb_vorbis_alloc *alloc)
+ int *error, const stb_vorbis_alloc *alloc)
{
stb_vorbis *f, p;
vorbis_init(&p, alloc);
- p.stream = data;
- p.stream_end = data + data_len;
+ p.stream = (uint8 *) data;
+ p.stream_end = (uint8 *) data + data_len;
p.push_mode = TRUE;
if (!start_decoder(&p)) {
if (p.eof)
@@ -4078,7 +4130,7 @@ static uint32 vorbis_find_page(stb_vorbis *f, uint32 *end, uint32 *last)
int n;
if (f->eof) return 0;
n = get8(f);
- if (n == 0x4f) { // page header
+ if (n == 0x4f) { // page header candidate
unsigned int retry_loc = stb_vorbis_get_file_offset(f);
int i;
// check if we're off the end of a file_section stream
@@ -4142,37 +4194,30 @@ static uint32 vorbis_find_page(stb_vorbis *f, uint32 *end, uint32 *last)
}
}
-// seek is implemented with 'interpolation search'--this is like
-// binary search, but we use the data values to estimate the likely
-// location of the data item (plus a bit of a bias so when the
-// estimation is wrong we don't waste overly much time)
#define SAMPLE_unknown 0xffffffff
+// seeking is implemented with a binary search, which narrows down the range to
+// 64K, before using a linear search (because finding the synchronization
+// pattern can be expensive, and the chance we'd find the end page again is
+// relatively high for small ranges)
+//
+// two initial interpolation-style probes are used at the start of the search
+// to try to bound either side of the binary search sensibly, while still
+// working in O(log n) time if they fail.
-// ogg vorbis, in its insane infinite wisdom, only provides
-// information about the sample at the END of the page.
-// therefore we COULD have the data we need in the current
-// page, and not know it. we could just use the end location
-// as our only knowledge for bounds, seek back, and eventually
-// the binary search finds it. or we can try to be smart and
-// not waste time trying to locate more pages. we try to be
-// smart, since this data is already in memory anyway, so
-// doing needless I/O would be crazy!
-static int vorbis_analyze_page(stb_vorbis *f, ProbedPage *z)
+static int get_seek_page_info(stb_vorbis *f, ProbedPage *z)
{
uint8 header[27], lacing[255];
- uint8 packet_type[255];
- int num_packet, packet_start;
int i,len;
- uint32 samples;
// record where the page starts
z->page_start = stb_vorbis_get_file_offset(f);
// parse the header
getn(f, header, 27);
- assert(header[0] == 'O' && header[1] == 'g' && header[2] == 'g' && header[3] == 'S');
+ if (header[0] != 'O' || header[1] != 'g' || header[2] != 'g' || header[3] != 'S')
+ return 0;
getn(f, lacing, header[26]);
// determine the length of the payload
@@ -4184,304 +4229,265 @@ static int vorbis_analyze_page(stb_vorbis *f, ProbedPage *z)
z->page_end = z->page_start + 27 + header[26] + len;
// read the last-decoded sample out of the data
- z->last_decoded_sample = header[6] + (header[7] << 8) + (header[8] << 16) + (header[9] << 16);
+ z->last_decoded_sample = header[6] + (header[7] << 8) + (header[8] << 16) + (header[9] << 24);
- if (header[5] & 4) {
- // if this is the last page, it's not possible to work
- // backwards to figure out the first sample! whoops! fuck.
- z->first_decoded_sample = SAMPLE_unknown;
- set_file_offset(f, z->page_start);
- return 1;
- }
-
- // scan through the frames to determine the sample-count of each one...
- // our goal is the sample # of the first fully-decoded sample on the
- // page, which is the first decoded sample of the 2nd packet
+ // restore file state to where we were
+ set_file_offset(f, z->page_start);
+ return 1;
+}
- num_packet=0;
+// rarely used function to seek back to the preceeding page while finding the
+// start of a packet
+static int go_to_page_before(stb_vorbis *f, unsigned int limit_offset)
+{
+ unsigned int previous_safe, end;
- packet_start = ((header[5] & 1) == 0);
+ // now we want to seek back 64K from the limit
+ if (limit_offset >= 65536 && limit_offset-65536 >= f->first_audio_page_offset)
+ previous_safe = limit_offset - 65536;
+ else
+ previous_safe = f->first_audio_page_offset;
- for (i=0; i < header[26]; ++i) {
- if (packet_start) {
- uint8 n,b;
- if (lacing[i] == 0) goto bail; // trying to read from zero-length packet
- n = get8(f);
- // if bottom bit is non-zero, we've got corruption
- if (n & 1) goto bail;
- n >>= 1;
- b = ilog(f->mode_count-1);
- n &= (1 << b)-1;
- if (n >= f->mode_count) goto bail;
- packet_type[num_packet++] = f->mode_config[n].blockflag;
- skip(f, lacing[i]-1);
- } else
- skip(f, lacing[i]);
- packet_start = (lacing[i] < 255);
- }
-
- // now that we know the sizes of all the pages, we can start determining
- // how much sample data there is.
-
- samples = 0;
-
- // for the last packet, we step by its whole length, because the definition
- // is that we encoded the end sample loc of the 'last packet completed',
- // where 'completed' refers to packets being split, and we are left to guess
- // what 'end sample loc' means. we assume it means ignoring the fact that
- // the last half of the data is useless without windowing against the next
- // packet... (so it's not REALLY complete in that sense)
- if (num_packet > 1)
- samples += f->blocksize[packet_type[num_packet-1]];
-
- for (i=num_packet-2; i >= 1; --i) {
- // now, for this packet, how many samples do we have that
- // do not overlap the following packet?
- if (packet_type[i] == 1)
- if (packet_type[i+1] == 1)
- samples += f->blocksize_1 >> 1;
- else
- samples += ((f->blocksize_1 - f->blocksize_0) >> 2) + (f->blocksize_0 >> 1);
- else
- samples += f->blocksize_0 >> 1;
- }
- // now, at this point, we've rewound to the very beginning of the
- // _second_ packet. if we entirely discard the first packet after
- // a seek, this will be exactly the right sample number. HOWEVER!
- // we can't as easily compute this number for the LAST page. The
- // only way to get the sample offset of the LAST page is to use
- // the end loc from the previous page. But what that returns us
- // is _exactly_ the place where we get our first non-overlapped
- // sample. (I think. Stupid spec for being ambiguous.) So for
- // consistency it's better to do that here, too. However, that
- // will then require us to NOT discard all of the first frame we
- // decode, in some cases, which means an even weirder frame size
- // and extra code. what a fucking pain.
-
- // we're going to discard the first packet if we
- // start the seek here, so we don't care about it. (we could actually
- // do better; if the first packet is long, and the previous packet
- // is short, there's actually data in the first half of the first
- // packet that doesn't need discarding... but not worth paying the
- // effort of tracking that of that here and in the seeking logic)
- // except crap, if we infer it from the _previous_ packet's end
- // location, we DO need to use that definition... and we HAVE to
- // infer the start loc of the LAST packet from the previous packet's
- // end location. fuck you, ogg vorbis.
-
- z->first_decoded_sample = z->last_decoded_sample - samples;
+ set_file_offset(f, previous_safe);
- // restore file state to where we were
- set_file_offset(f, z->page_start);
- return 1;
+ while (vorbis_find_page(f, &end, NULL)) {
+ if (end >= limit_offset && stb_vorbis_get_file_offset(f) < limit_offset)
+ return 1;
+ set_file_offset(f, end);
+ }
- // restore file state to where we were
- bail:
- set_file_offset(f, z->page_start);
return 0;
}
-static int vorbis_seek_frame_from_page(stb_vorbis *f, uint32 page_start, uint32 first_sample, uint32 target_sample, int fine)
-{
- int left_start, left_end, right_start, right_end, mode,i;
- int frame=0;
- uint32 frame_start;
- int frames_to_skip, data_to_skip;
+// implements the search logic for finding a page and starting decoding. if
+// the function succeeds, current_loc_valid will be true and current_loc will
+// be less than or equal to the provided sample number (the closer the
+// better).
+static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number)
+{
+ ProbedPage left, right, mid;
+ int i, start_seg_with_known_loc, end_pos, page_start;
+ uint32 delta, stream_length, padding;
+ double offset, bytes_per_sample;
+ int probe = 0;
+
+ // find the last page and validate the target sample
+ stream_length = stb_vorbis_stream_length_in_samples(f);
+ if (stream_length == 0) return error(f, VORBIS_seek_without_length);
+ if (sample_number > stream_length) return error(f, VORBIS_seek_invalid);
+
+ // this is the maximum difference between the window-center (which is the
+ // actual granule position value), and the right-start (which the spec
+ // indicates should be the granule position (give or take one)).
+ padding = ((f->blocksize_1 - f->blocksize_0) >> 2);
+ if (sample_number < padding)
+ sample_number = 0;
+ else
+ sample_number -= padding;
- // first_sample is the sample # of the first sample that doesn't
- // overlap the previous page... note that this requires us to
- // _partially_ discard the first packet! bleh.
- set_file_offset(f, page_start);
+ left = f->p_first;
+ while (left.last_decoded_sample == ~0U) {
+ // (untested) the first page does not have a 'last_decoded_sample'
+ set_file_offset(f, left.page_end);
+ if (!get_seek_page_info(f, &left)) goto error;
+ }
- f->next_seg = -1; // force page resync
+ right = f->p_last;
+ assert(right.last_decoded_sample != ~0U);
- frame_start = first_sample;
- // frame start is where the previous packet's last decoded sample
- // was, which corresponds to left_end... EXCEPT if the previous
- // packet was long and this packet is short? Probably a bug here.
+ // starting from the start is handled differently
+ if (sample_number <= left.last_decoded_sample) {
+ stb_vorbis_seek_start(f);
+ return 1;
+ }
+ while (left.page_end != right.page_start) {
+ assert(left.page_end < right.page_start);
+ // search range in bytes
+ delta = right.page_start - left.page_end;
+ if (delta <= 65536) {
+ // there's only 64K left to search - handle it linearly
+ set_file_offset(f, left.page_end);
+ } else {
+ if (probe < 2) {
+ if (probe == 0) {
+ // first probe (interpolate)
+ double data_bytes = right.page_end - left.page_start;
+ bytes_per_sample = data_bytes / right.last_decoded_sample;
+ offset = left.page_start + bytes_per_sample * (sample_number - left.last_decoded_sample);
+ } else {
+ // second probe (try to bound the other side)
+ double error = ((double) sample_number - mid.last_decoded_sample) * bytes_per_sample;
+ if (error >= 0 && error < 8000) error = 8000;
+ if (error < 0 && error > -8000) error = -8000;
+ offset += error * 2;
+ }
- // now, we can start decoding frames... we'll only FAKE decode them,
- // until we find the frame that contains our sample; then we'll rewind,
- // and try again
- for (;;) {
- int start;
+ // ensure the offset is valid
+ if (offset < left.page_end)
+ offset = left.page_end;
+ if (offset > right.page_start - 65536)
+ offset = right.page_start - 65536;
- if (!vorbis_decode_initial(f, &left_start, &left_end, &right_start, &right_end, &mode))
- return error(f, VORBIS_seek_failed);
+ set_file_offset(f, (unsigned int) offset);
+ } else {
+ // binary search for large ranges (offset by 32K to ensure
+ // we don't hit the right page)
+ set_file_offset(f, left.page_end + (delta / 2) - 32768);
+ }
- if (frame == 0)
- start = left_end;
- else
- start = left_start;
+ if (!vorbis_find_page(f, NULL, NULL)) goto error;
+ }
- // the window starts at left_start; the last valid sample we generate
- // before the next frame's window start is right_start-1
- if (target_sample < frame_start + right_start-start)
- break;
+ for (;;) {
+ if (!get_seek_page_info(f, &mid)) goto error;
+ if (mid.last_decoded_sample != ~0U) break;
+ // (untested) no frames end on this page
+ set_file_offset(f, mid.page_end);
+ assert(mid.page_start < right.page_start);
+ }
- flush_packet(f);
- if (f->eof)
- return error(f, VORBIS_seek_failed);
+ // if we've just found the last page again then we're in a tricky file,
+ // and we're close enough.
+ if (mid.page_start == right.page_start)
+ break;
- frame_start += right_start - start;
+ if (sample_number < mid.last_decoded_sample)
+ right = mid;
+ else
+ left = mid;
- ++frame;
+ ++probe;
}
- // ok, at this point, the sample we want is contained in frame #'frame'
+ // seek back to start of the last packet
+ page_start = left.page_start;
+ set_file_offset(f, page_start);
+ if (!start_page(f)) return error(f, VORBIS_seek_failed);
+ end_pos = f->end_seg_with_known_loc;
+ assert(end_pos >= 0);
- // to decode frame #'frame' normally, we have to decode the
- // previous frame first... but if it's the FIRST frame of the page
- // we can't. if it's the first frame, it means it falls in the part
- // of the first frame that doesn't overlap either of the other frames.
- // so, if we have to handle that case for the first frame, we might
- // as well handle it for all of them, so:
- if (target_sample > frame_start + (left_end - left_start)) {
- // so what we want to do is go ahead and just immediately decode
- // this frame, but then make it so the next get_frame_float() uses
- // this already-decoded data? or do we want to go ahead and rewind,
- // and leave a flag saying to skip the first N data? let's do that
- frames_to_skip = frame; // if this is frame #1, skip 1 frame (#0)
- data_to_skip = left_end - left_start;
- } else {
- // otherwise, we want to skip frames 0, 1, 2, ... frame-2
- // (which means frame-2+1 total frames) then decode frame-1,
- // then leave frame pending
- frames_to_skip = frame - 1;
- assert(frames_to_skip >= 0);
- data_to_skip = -1;
- }
+ for (;;) {
+ for (i = end_pos; i > 0; --i)
+ if (f->segments[i-1] != 255)
+ break;
- set_file_offset(f, page_start);
- f->next_seg = - 1; // force page resync
+ start_seg_with_known_loc = i;
- for (i=0; i < frames_to_skip; ++i) {
- maybe_start_packet(f);
- flush_packet(f);
- }
+ if (start_seg_with_known_loc > 0 || !(f->page_flag & PAGEFLAG_continued_packet))
+ break;
- if (data_to_skip >= 0) {
- int i,j,n = f->blocksize_0 >> 1;
- f->discard_samples_deferred = data_to_skip;
- for (i=0; i < f->channels; ++i)
- for (j=0; j < n; ++j)
- f->previous_window[i][j] = 0;
- f->previous_length = n;
- frame_start += data_to_skip;
- } else {
- f->previous_length = 0;
- vorbis_pump_first_frame(f);
- }
-
- // at this point, the NEXT decoded frame will generate the desired sample
- if (fine) {
- // so if we're doing sample accurate streaming, we want to go ahead and decode it!
- if (target_sample != frame_start) {
- int n;
- stb_vorbis_get_frame_float(f, &n, NULL);
- assert(target_sample > frame_start);
- assert(f->channel_buffer_start + (int) (target_sample-frame_start) < f->channel_buffer_end);
- f->channel_buffer_start += (target_sample - frame_start);
- }
+ // (untested) the final packet begins on an earlier page
+ if (!go_to_page_before(f, page_start))
+ goto error;
+
+ page_start = stb_vorbis_get_file_offset(f);
+ if (!start_page(f)) goto error;
+ end_pos = f->segment_count - 1;
}
- return 0;
+ // prepare to start decoding
+ f->current_loc_valid = FALSE;
+ f->last_seg = FALSE;
+ f->valid_bits = 0;
+ f->packet_bytes = 0;
+ f->bytes_in_seg = 0;
+ f->previous_length = 0;
+ f->next_seg = start_seg_with_known_loc;
+
+ for (i = 0; i < start_seg_with_known_loc; i++)
+ skip(f, f->segments[i]);
+
+ // start decoding (optimizable - this frame is generally discarded)
+ vorbis_pump_first_frame(f);
+ return 1;
+
+error:
+ // try to restore the file to a valid state
+ stb_vorbis_seek_start(f);
+ return error(f, VORBIS_seek_failed);
}
-static int vorbis_seek_base(stb_vorbis *f, unsigned int sample_number, int fine)
+// the same as vorbis_decode_initial, but without advancing
+static int peek_decode_initial(vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode)
{
- ProbedPage p[2],q;
- if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing);
+ int bits_read, bytes_read;
- // do we know the location of the last page?
- if (f->p_last.page_start == 0) {
- uint32 z = stb_vorbis_stream_length_in_samples(f);
- if (z == 0) return error(f, VORBIS_cant_find_last_page);
- }
+ if (!vorbis_decode_initial(f, p_left_start, p_left_end, p_right_start, p_right_end, mode))
+ return 0;
- p[0] = f->p_first;
- p[1] = f->p_last;
+ // either 1 or 2 bytes were read, figure out which so we can rewind
+ bits_read = 1 + ilog(f->mode_count-1);
+ if (f->mode_config[*mode].blockflag)
+ bits_read += 2;
+ bytes_read = (bits_read + 7) / 8;
+
+ f->bytes_in_seg += bytes_read;
+ f->packet_bytes -= bytes_read;
+ skip(f, -bytes_read);
+ if (f->next_seg == -1)
+ f->next_seg = f->segment_count - 1;
+ else
+ f->next_seg--;
+ f->valid_bits = 0;
- if (sample_number >= f->p_last.last_decoded_sample)
- sample_number = f->p_last.last_decoded_sample-1;
+ return 1;
+}
- if (sample_number < f->p_first.last_decoded_sample) {
- vorbis_seek_frame_from_page(f, p[0].page_start, 0, sample_number, fine);
- return 0;
- } else {
- int attempts=0;
- while (p[0].page_end < p[1].page_start) {
- uint32 probe;
- uint32 start_offset, end_offset;
- uint32 start_sample, end_sample;
-
- // copy these into local variables so we can tweak them
- // if any are unknown
- start_offset = p[0].page_end;
- end_offset = p[1].after_previous_page_start; // an address known to seek to page p[1]
- start_sample = p[0].last_decoded_sample;
- end_sample = p[1].last_decoded_sample;
-
- // currently there is no such tweaking logic needed/possible?
- if (start_sample == SAMPLE_unknown || end_sample == SAMPLE_unknown)
- return error(f, VORBIS_seek_failed);
-
- // now we want to lerp between these for the target samples...
-
- // step 1: we need to bias towards the page start...
- if (start_offset + 4000 < end_offset)
- end_offset -= 4000;
-
- // now compute an interpolated search loc
- probe = start_offset + (int) floor((float) (end_offset - start_offset) / (end_sample - start_sample) * (sample_number - start_sample));
-
- // next we need to bias towards binary search...
- // code is a little wonky to allow for full 32-bit unsigned values
- if (attempts >= 4) {
- uint32 probe2 = start_offset + ((end_offset - start_offset) >> 1);
- if (attempts >= 8)
- probe = probe2;
- else if (probe < probe2)
- probe = probe + ((probe2 - probe) >> 1);
- else
- probe = probe2 + ((probe - probe2) >> 1);
- }
- ++attempts;
+int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number)
+{
+ uint32 max_frame_samples;
- set_file_offset(f, probe);
- if (!vorbis_find_page(f, NULL, NULL)) return error(f, VORBIS_seek_failed);
- if (!vorbis_analyze_page(f, &q)) return error(f, VORBIS_seek_failed);
- q.after_previous_page_start = probe;
+ if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing);
- // it's possible we've just found the last page again
- if (q.page_start == p[1].page_start) {
- p[1] = q;
- continue;
- }
+ // fast page-level search
+ if (!seek_to_sample_coarse(f, sample_number))
+ return 0;
- if (sample_number < q.last_decoded_sample)
- p[1] = q;
- else
- p[0] = q;
- }
+ assert(f->current_loc_valid);
+ assert(f->current_loc <= sample_number);
- if (p[0].last_decoded_sample <= sample_number && sample_number < p[1].last_decoded_sample) {
- vorbis_seek_frame_from_page(f, p[1].page_start, p[0].last_decoded_sample, sample_number, fine);
- return 0;
+ // linear search for the relevant packet
+ max_frame_samples = (f->blocksize_1*3 - f->blocksize_0) >> 2;
+ while (f->current_loc < sample_number) {
+ int left_start, left_end, right_start, right_end, mode, frame_samples;
+ if (!peek_decode_initial(f, &left_start, &left_end, &right_start, &right_end, &mode))
+ return error(f, VORBIS_seek_failed);
+ // calculate the number of samples returned by the next frame
+ frame_samples = right_start - left_start;
+ if (f->current_loc + frame_samples > sample_number) {
+ return 1; // the next frame will contain the sample
+ } else if (f->current_loc + frame_samples + max_frame_samples > sample_number) {
+ // there's a chance the frame after this could contain the sample
+ vorbis_pump_first_frame(f);
+ } else {
+ // this frame is too early to be relevant
+ f->current_loc += frame_samples;
+ f->previous_length = 0;
+ maybe_start_packet(f);
+ flush_packet(f);
}
- return error(f, VORBIS_seek_failed);
}
-}
-
-int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number)
-{
- return vorbis_seek_base(f, sample_number, FALSE);
+ // the next frame will start with the sample
+ assert(f->current_loc == sample_number);
+ return 1;
}
int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number)
{
- return vorbis_seek_base(f, sample_number, TRUE);
+ if (!stb_vorbis_seek_frame(f, sample_number))
+ return 0;
+
+ if (sample_number != f->current_loc) {
+ int n;
+ uint32 frame_start = f->current_loc;
+ stb_vorbis_get_frame_float(f, &n, NULL);
+ assert(sample_number > frame_start);
+ assert(f->channel_buffer_start + (int) (sample_number-frame_start) <= f->channel_buffer_end);
+ f->channel_buffer_start += (sample_number - frame_start);
+ }
+
+ return 1;
}
void stb_vorbis_seek_start(stb_vorbis *f)
@@ -4562,8 +4568,6 @@ unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f)
f->p_last.page_start = last_page_loc;
f->p_last.page_end = end;
f->p_last.last_decoded_sample = lo;
- f->p_last.first_decoded_sample = SAMPLE_unknown;
- f->p_last.after_previous_page_start = previous_safe;
done:
set_file_offset(f, restore_offset);
@@ -4602,7 +4606,7 @@ int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output)
#ifndef STB_VORBIS_NO_STDIO
-stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *error, stb_vorbis_alloc *alloc, unsigned int length)
+stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc, unsigned int length)
{
stb_vorbis *f, p;
vorbis_init(&p, alloc);
@@ -4623,7 +4627,7 @@ stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *er
return NULL;
}
-stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, stb_vorbis_alloc *alloc)
+stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc)
{
unsigned int len, start;
start = ftell(file);
@@ -4633,7 +4637,7 @@ stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, stb
return stb_vorbis_open_file_section(file, close_on_free, error, alloc, len);
}
-stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, stb_vorbis_alloc *alloc)
+stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc)
{
FILE *f = fopen(filename, "rb");
if (f)
@@ -4643,7 +4647,7 @@ stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, stb_vorb
}
#endif // STB_VORBIS_NO_STDIO
-stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, stb_vorbis_alloc *alloc)
+stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, const stb_vorbis_alloc *alloc)
{
stb_vorbis *f, p;
if (data == NULL) return NULL;
@@ -5023,6 +5027,10 @@ int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, in
#endif // STB_VORBIS_NO_PULLDATA_API
/* Version history
+ 1.07 - 2015/01/16 - fixed some warnings, fix mingw, const-correct API
+ some more crash fixes when out of memory or with corrupt files
+ 1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson)
+ some crash fixes when out of memory or with corrupt files
1.05 - 2015/04/19 - don't define __forceinline if it's redundant
1.04 - 2014/08/27 - fix missing const-correct case in API
1.03 - 2014/08/07 - Warning fixes