Updated stb headers
This commit is contained in:
parent
4e4b6bef21
commit
e25f1227c0
@ -39,7 +39,8 @@
|
|||||||
#include "utils.h" // rRES data decompression utility function
|
#include "utils.h" // rRES data decompression utility function
|
||||||
// NOTE: Includes Android fopen function map
|
// NOTE: Includes Android fopen function map
|
||||||
|
|
||||||
#include "stb_vorbis.h" // OGG loading functions
|
#define STB_VORBIS_HEADER_ONLY
|
||||||
|
#include "stb_vorbis.c" // OGG loading functions
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Defines and Macros
|
// Defines and Macros
|
||||||
|
@ -93,7 +93,7 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# define all object files required
|
# define all object files required
|
||||||
OBJS = core.o rlgl.o raymath.o shapes.o text.o textures.o models.o audio.o utils.o stb_vorbis.o camera.o gestures.o
|
OBJS = core.o rlgl.o raymath.o shapes.o text.o textures.o models.o audio.o utils.o camera.o gestures.o
|
||||||
|
|
||||||
# typing 'make' will invoke the first target entry in the file,
|
# typing 'make' will invoke the first target entry in the file,
|
||||||
# in this case, the 'default' target entry is raylib
|
# in this case, the 'default' target entry is raylib
|
||||||
@ -144,10 +144,6 @@ audio.o: audio.c
|
|||||||
utils.o: utils.c
|
utils.o: utils.c
|
||||||
$(CC) -c utils.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
|
$(CC) -c utils.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
|
||||||
|
|
||||||
# compile stb_vorbis library
|
|
||||||
stb_vorbis.o: stb_vorbis.c
|
|
||||||
$(CC) -c stb_vorbis.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
|
|
||||||
|
|
||||||
# compile camera module
|
# compile camera module
|
||||||
camera.o: camera.c
|
camera.o: camera.c
|
||||||
$(CC) -c camera.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
|
$(CC) -c camera.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
|
||||||
|
202
src/stb_image.h
202
src/stb_image.h
@ -1,4 +1,4 @@
|
|||||||
/* stb_image - v2.00b - public domain image loader - http://nothings.org/stb_image.h
|
/* stb_image - v2.05 - public domain image loader - http://nothings.org/stb_image.h
|
||||||
no warranty implied; use at your own risk
|
no warranty implied; use at your own risk
|
||||||
|
|
||||||
Do this:
|
Do this:
|
||||||
@ -143,6 +143,13 @@
|
|||||||
|
|
||||||
|
|
||||||
Latest revision history:
|
Latest revision history:
|
||||||
|
2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning
|
||||||
|
2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit
|
||||||
|
2.03 (2015-04-12) additional corruption checking
|
||||||
|
stbi_set_flip_vertically_on_load
|
||||||
|
fix NEON support; fix mingw support
|
||||||
|
2.02 (2015-01-19) fix incorrect assert, fix warning
|
||||||
|
2.01 (2015-01-17) fix various warnings
|
||||||
2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
|
2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
|
||||||
2.00 (2014-12-25) optimize JPEG, including x86 SSE2 & ARM NEON SIMD
|
2.00 (2014-12-25) optimize JPEG, including x86 SSE2 & ARM NEON SIMD
|
||||||
progressive JPEG
|
progressive JPEG
|
||||||
@ -154,8 +161,6 @@
|
|||||||
1.47 (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted)
|
1.47 (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted)
|
||||||
optimize PNG
|
optimize PNG
|
||||||
fix bug in interlaced PNG with user-specified channel count
|
fix bug in interlaced PNG with user-specified channel count
|
||||||
1.46 (2014-08-26) fix broken tRNS chunk in non-paletted PNG
|
|
||||||
1.45 (2014-08-16) workaround MSVC-ARM internal compiler error by wrapping malloc
|
|
||||||
|
|
||||||
See end of file for full revision history.
|
See end of file for full revision history.
|
||||||
|
|
||||||
@ -178,7 +183,7 @@
|
|||||||
James "moose2000" Brown (iPhone PNG) Roy Eltham
|
James "moose2000" Brown (iPhone PNG) Roy Eltham
|
||||||
Ben "Disch" Wenger (io callbacks) Luke Graham
|
Ben "Disch" Wenger (io callbacks) Luke Graham
|
||||||
Omar Cornut (1/2/4-bit PNG) Thomas Ruf
|
Omar Cornut (1/2/4-bit PNG) Thomas Ruf
|
||||||
John Bartholomew
|
Nicolas Guillemot (vertical flip) John Bartholomew
|
||||||
Ken Hamada
|
Ken Hamada
|
||||||
Optimizations & bugfixes Cort Stratton
|
Optimizations & bugfixes Cort Stratton
|
||||||
Fabian "ryg" Giesen Blazej Dariusz Roszkowski
|
Fabian "ryg" Giesen Blazej Dariusz Roszkowski
|
||||||
@ -191,6 +196,12 @@
|
|||||||
Ronny Chevalier
|
Ronny Chevalier
|
||||||
Michal Cichon
|
Michal Cichon
|
||||||
Tero Hanninen
|
Tero Hanninen
|
||||||
|
Sergio Gonzalez
|
||||||
|
Cass Everitt
|
||||||
|
Engin Manap
|
||||||
|
Martins Mozeiko
|
||||||
|
Joseph Thomson
|
||||||
|
Phil Jordan
|
||||||
|
|
||||||
License:
|
License:
|
||||||
This software is in the public domain. Where that dedication is not
|
This software is in the public domain. Where that dedication is not
|
||||||
@ -371,6 +382,7 @@ License:
|
|||||||
// and only if iPhone convert-to-rgb processing is on).
|
// and only if iPhone convert-to-rgb processing is on).
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
#define STBI_NO_HDR // RaySan: not required by raylib
|
#define STBI_NO_HDR // RaySan: not required by raylib
|
||||||
#define STBI_NO_SIMD // RaySan: issues when compiling with GCC 4.7.2
|
#define STBI_NO_SIMD // RaySan: issues when compiling with GCC 4.7.2
|
||||||
|
|
||||||
@ -489,6 +501,8 @@ STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultipl
|
|||||||
// or just pass them through "as-is"
|
// or just pass them through "as-is"
|
||||||
STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
|
STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
|
||||||
|
|
||||||
|
// flip the image vertically, so the first pixel in the output array is the bottom left
|
||||||
|
STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
|
||||||
|
|
||||||
// ZLIB client - used by PNG, available for other purposes
|
// ZLIB client - used by PNG, available for other purposes
|
||||||
|
|
||||||
@ -626,7 +640,38 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
|
|||||||
#define STBI_FREE(p) free(p)
|
#define STBI_FREE(p) free(p)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(STBI_NO_SIMD) && (defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86))
|
// x86/x64 detection
|
||||||
|
#if defined(__x86_64__) || defined(_M_X64)
|
||||||
|
#define STBI__X64_TARGET
|
||||||
|
#elif defined(__i386) || defined(_M_IX86)
|
||||||
|
#define STBI__X86_TARGET
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)
|
||||||
|
// NOTE: not clear do we actually need this for the 64-bit path?
|
||||||
|
// gcc doesn't support sse2 intrinsics unless you compile with -msse2,
|
||||||
|
// (but compiling with -msse2 allows the compiler to use SSE2 everywhere;
|
||||||
|
// this is just broken and gcc are jerks for not fixing it properly
|
||||||
|
// http://www.virtualdub.org/blog/pivot/entry.php?id=363 )
|
||||||
|
#define STBI_NO_SIMD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD)
|
||||||
|
// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET
|
||||||
|
//
|
||||||
|
// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the
|
||||||
|
// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.
|
||||||
|
// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not
|
||||||
|
// simultaneously enabling "-mstackrealign".
|
||||||
|
//
|
||||||
|
// See https://github.com/nothings/stb/issues/81 for more information.
|
||||||
|
//
|
||||||
|
// So default to no SSE2 on 32-bit MinGW. If you've read this far and added
|
||||||
|
// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2.
|
||||||
|
#define STBI_NO_SIMD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(STBI_NO_SIMD) && defined(STBI__X86_TARGET)
|
||||||
#define STBI_SSE2
|
#define STBI_SSE2
|
||||||
#include <emmintrin.h>
|
#include <emmintrin.h>
|
||||||
|
|
||||||
@ -879,7 +924,14 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp);
|
|||||||
static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp);
|
static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static unsigned char *stbi_load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
|
static int stbi__vertically_flip_on_load = 0;
|
||||||
|
|
||||||
|
STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)
|
||||||
|
{
|
||||||
|
stbi__vertically_flip_on_load = flag_true_if_should_flip;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
|
||||||
{
|
{
|
||||||
#ifndef STBI_NO_JPEG
|
#ifndef STBI_NO_JPEG
|
||||||
if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp);
|
if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp);
|
||||||
@ -919,6 +971,53 @@ static unsigned char *stbi_load_main(stbi__context *s, int *x, int *y, int *comp
|
|||||||
return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt");
|
return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned char *stbi__load_flip(stbi__context *s, int *x, int *y, int *comp, int req_comp)
|
||||||
|
{
|
||||||
|
unsigned char *result = stbi__load_main(s, x, y, comp, req_comp);
|
||||||
|
|
||||||
|
if (stbi__vertically_flip_on_load && result != NULL) {
|
||||||
|
int w = *x, h = *y;
|
||||||
|
int depth = req_comp ? req_comp : *comp;
|
||||||
|
int row,col,z;
|
||||||
|
stbi_uc temp;
|
||||||
|
|
||||||
|
// @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once
|
||||||
|
for (row = 0; row < (h>>1); row++) {
|
||||||
|
for (col = 0; col < w; col++) {
|
||||||
|
for (z = 0; z < depth; z++) {
|
||||||
|
temp = result[(row * w + col) * depth + z];
|
||||||
|
result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z];
|
||||||
|
result[((h - row - 1) * w + col) * depth + z] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)
|
||||||
|
{
|
||||||
|
if (stbi__vertically_flip_on_load && result != NULL) {
|
||||||
|
int w = *x, h = *y;
|
||||||
|
int depth = req_comp ? req_comp : *comp;
|
||||||
|
int row,col,z;
|
||||||
|
float temp;
|
||||||
|
|
||||||
|
// @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once
|
||||||
|
for (row = 0; row < (h>>1); row++) {
|
||||||
|
for (col = 0; col < w; col++) {
|
||||||
|
for (z = 0; z < depth; z++) {
|
||||||
|
temp = result[(row * w + col) * depth + z];
|
||||||
|
result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z];
|
||||||
|
result[((h - row - 1) * w + col) * depth + z] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef STBI_NO_STDIO
|
#ifndef STBI_NO_STDIO
|
||||||
|
|
||||||
static FILE *stbi__fopen(char const *filename, char const *mode)
|
static FILE *stbi__fopen(char const *filename, char const *mode)
|
||||||
@ -949,7 +1048,7 @@ STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req
|
|||||||
unsigned char *result;
|
unsigned char *result;
|
||||||
stbi__context s;
|
stbi__context s;
|
||||||
stbi__start_file(&s,f);
|
stbi__start_file(&s,f);
|
||||||
result = stbi_load_main(&s,x,y,comp,req_comp);
|
result = stbi__load_flip(&s,x,y,comp,req_comp);
|
||||||
if (result) {
|
if (result) {
|
||||||
// need to 'unget' all the characters in the IO buffer
|
// need to 'unget' all the characters in the IO buffer
|
||||||
fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
|
fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
|
||||||
@ -962,25 +1061,29 @@ STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, i
|
|||||||
{
|
{
|
||||||
stbi__context s;
|
stbi__context s;
|
||||||
stbi__start_mem(&s,buffer,len);
|
stbi__start_mem(&s,buffer,len);
|
||||||
return stbi_load_main(&s,x,y,comp,req_comp);
|
return stbi__load_flip(&s,x,y,comp,req_comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
|
STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
|
||||||
{
|
{
|
||||||
stbi__context s;
|
stbi__context s;
|
||||||
stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
|
stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
|
||||||
return stbi_load_main(&s,x,y,comp,req_comp);
|
return stbi__load_flip(&s,x,y,comp,req_comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef STBI_NO_LINEAR
|
#ifndef STBI_NO_LINEAR
|
||||||
static float *stbi_loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
|
static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
|
||||||
{
|
{
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
#ifndef STBI_NO_HDR
|
#ifndef STBI_NO_HDR
|
||||||
if (stbi__hdr_test(s))
|
if (stbi__hdr_test(s)) {
|
||||||
return stbi__hdr_load(s,x,y,comp,req_comp);
|
float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp);
|
||||||
|
if (hdr_data)
|
||||||
|
stbi__float_postprocess(hdr_data,x,y,comp,req_comp);
|
||||||
|
return hdr_data;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
data = stbi_load_main(s, x, y, comp, req_comp);
|
data = stbi__load_flip(s, x, y, comp, req_comp);
|
||||||
if (data)
|
if (data)
|
||||||
return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);
|
return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);
|
||||||
return stbi__errpf("unknown image type", "Image not of any known type, or corrupt");
|
return stbi__errpf("unknown image type", "Image not of any known type, or corrupt");
|
||||||
@ -990,14 +1093,14 @@ STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, in
|
|||||||
{
|
{
|
||||||
stbi__context s;
|
stbi__context s;
|
||||||
stbi__start_mem(&s,buffer,len);
|
stbi__start_mem(&s,buffer,len);
|
||||||
return stbi_loadf_main(&s,x,y,comp,req_comp);
|
return stbi__loadf_main(&s,x,y,comp,req_comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
|
STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
|
||||||
{
|
{
|
||||||
stbi__context s;
|
stbi__context s;
|
||||||
stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
|
stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
|
||||||
return stbi_loadf_main(&s,x,y,comp,req_comp);
|
return stbi__loadf_main(&s,x,y,comp,req_comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef STBI_NO_STDIO
|
#ifndef STBI_NO_STDIO
|
||||||
@ -1015,7 +1118,7 @@ STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_
|
|||||||
{
|
{
|
||||||
stbi__context s;
|
stbi__context s;
|
||||||
stbi__start_file(&s,f);
|
stbi__start_file(&s,f);
|
||||||
return stbi_loadf_main(&s,x,y,comp,req_comp);
|
return stbi__loadf_main(&s,x,y,comp,req_comp);
|
||||||
}
|
}
|
||||||
#endif // !STBI_NO_STDIO
|
#endif // !STBI_NO_STDIO
|
||||||
|
|
||||||
@ -1138,6 +1241,10 @@ stbi_inline static int stbi__at_eof(stbi__context *s)
|
|||||||
|
|
||||||
static void stbi__skip(stbi__context *s, int n)
|
static void stbi__skip(stbi__context *s, int n)
|
||||||
{
|
{
|
||||||
|
if (n < 0) {
|
||||||
|
s->img_buffer = s->img_buffer_end;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (s->io.read) {
|
if (s->io.read) {
|
||||||
int blen = (int) (s->img_buffer_end - s->img_buffer);
|
int blen = (int) (s->img_buffer_end - s->img_buffer);
|
||||||
if (blen < n) {
|
if (blen < n) {
|
||||||
@ -1546,6 +1653,7 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)
|
|||||||
|
|
||||||
sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB
|
sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB
|
||||||
k = stbi_lrot(j->code_buffer, n);
|
k = stbi_lrot(j->code_buffer, n);
|
||||||
|
STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask)));
|
||||||
j->code_buffer = k & ~stbi__bmask[n];
|
j->code_buffer = k & ~stbi__bmask[n];
|
||||||
k &= stbi__bmask[n];
|
k &= stbi__bmask[n];
|
||||||
j->code_bits -= n;
|
j->code_bits -= n;
|
||||||
@ -1730,16 +1838,13 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__
|
|||||||
short *p = &data[stbi__jpeg_dezigzag[k]];
|
short *p = &data[stbi__jpeg_dezigzag[k]];
|
||||||
if (*p != 0)
|
if (*p != 0)
|
||||||
if (stbi__jpeg_get_bit(j))
|
if (stbi__jpeg_get_bit(j))
|
||||||
{
|
if ((*p & bit)==0) {
|
||||||
if ((*p & bit)==0)
|
|
||||||
{
|
|
||||||
if (*p > 0)
|
if (*p > 0)
|
||||||
*p += bit;
|
*p += bit;
|
||||||
else
|
else
|
||||||
*p -= bit;
|
*p -= bit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
k = j->spec_start;
|
k = j->spec_start;
|
||||||
do {
|
do {
|
||||||
@ -1754,8 +1859,11 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__
|
|||||||
if (r)
|
if (r)
|
||||||
j->eob_run += stbi__jpeg_get_bits(j, r);
|
j->eob_run += stbi__jpeg_get_bits(j, r);
|
||||||
r = 64; // force end of block
|
r = 64; // force end of block
|
||||||
} else
|
} else {
|
||||||
r = 16; // r=15 is the code for 16 0s
|
// r=15 s=0 should write 16 0s, so we just do
|
||||||
|
// a run of 15 0s and then write s (which is 0),
|
||||||
|
// so we don't have to do anything special here
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG");
|
if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG");
|
||||||
// sign bit
|
// sign bit
|
||||||
@ -1767,27 +1875,21 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__
|
|||||||
|
|
||||||
// advance by r
|
// advance by r
|
||||||
while (k <= j->spec_end) {
|
while (k <= j->spec_end) {
|
||||||
short *p = &data[stbi__jpeg_dezigzag[k]];
|
short *p = &data[stbi__jpeg_dezigzag[k++]];
|
||||||
if (*p != 0) {
|
if (*p != 0) {
|
||||||
if (stbi__jpeg_get_bit(j))
|
if (stbi__jpeg_get_bit(j))
|
||||||
{
|
if ((*p & bit)==0) {
|
||||||
if ((*p & bit)==0)
|
|
||||||
{
|
|
||||||
if (*p > 0)
|
if (*p > 0)
|
||||||
*p += bit;
|
*p += bit;
|
||||||
else
|
else
|
||||||
*p -= bit;
|
*p -= bit;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
++k;
|
|
||||||
} else {
|
} else {
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
if (s)
|
*p = (short) s;
|
||||||
data[stbi__jpeg_dezigzag[k++]] = s;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
--r;
|
--r;
|
||||||
++k;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (k <= j->spec_end);
|
} while (k <= j->spec_end);
|
||||||
@ -2434,7 +2536,6 @@ static int stbi__parse_entropy_coded_data(stbi__jpeg *z)
|
|||||||
for (x=0; x < z->img_comp[n].h; ++x) {
|
for (x=0; x < z->img_comp[n].h; ++x) {
|
||||||
int x2 = (i*z->img_comp[n].h + x);
|
int x2 = (i*z->img_comp[n].h + x);
|
||||||
int y2 = (j*z->img_comp[n].v + y);
|
int y2 = (j*z->img_comp[n].v + y);
|
||||||
//int ha = z->img_comp[n].ha; // RaySan: Unused, commented to avoid warning
|
|
||||||
short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w);
|
short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w);
|
||||||
if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
|
if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
|
||||||
return 0;
|
return 0;
|
||||||
@ -2701,6 +2802,10 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
|
|||||||
static int stbi__decode_jpeg_image(stbi__jpeg *j)
|
static int stbi__decode_jpeg_image(stbi__jpeg *j)
|
||||||
{
|
{
|
||||||
int m;
|
int m;
|
||||||
|
for (m = 0; m < 4; m++) {
|
||||||
|
j->img_comp[m].raw_data = NULL;
|
||||||
|
j->img_comp[m].raw_coeff = NULL;
|
||||||
|
}
|
||||||
j->restart_interval = 0;
|
j->restart_interval = 0;
|
||||||
if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0;
|
if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0;
|
||||||
m = stbi__get_marker(j);
|
m = stbi__get_marker(j);
|
||||||
@ -3013,7 +3118,7 @@ static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc cons
|
|||||||
__m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));
|
__m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));
|
||||||
__m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));
|
__m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));
|
||||||
__m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f));
|
__m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f));
|
||||||
__m128i y_bias = _mm_set1_epi8((char) 128);
|
__m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128);
|
||||||
__m128i xw = _mm_set1_epi16(255); // alpha channel
|
__m128i xw = _mm_set1_epi16(255); // alpha channel
|
||||||
|
|
||||||
for (; i+7 < count; i += 8) {
|
for (; i+7 < count; i += 8) {
|
||||||
@ -3380,7 +3485,8 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num)
|
|||||||
++sizes[sizelist[i]];
|
++sizes[sizelist[i]];
|
||||||
sizes[0] = 0;
|
sizes[0] = 0;
|
||||||
for (i=1; i < 16; ++i)
|
for (i=1; i < 16; ++i)
|
||||||
STBI_ASSERT(sizes[i] <= (1 << i));
|
if (sizes[i] > (1 << i))
|
||||||
|
return stbi__err("bad sizes", "Corrupt PNG");
|
||||||
code = 0;
|
code = 0;
|
||||||
for (i=1; i < 16; ++i) {
|
for (i=1; i < 16; ++i) {
|
||||||
next_code[i] = code;
|
next_code[i] = code;
|
||||||
@ -3388,7 +3494,7 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num)
|
|||||||
z->firstsymbol[i] = (stbi__uint16) k;
|
z->firstsymbol[i] = (stbi__uint16) k;
|
||||||
code = (code + sizes[i]);
|
code = (code + sizes[i]);
|
||||||
if (sizes[i])
|
if (sizes[i])
|
||||||
if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt JPEG");
|
if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG");
|
||||||
z->maxcode[i] = code << (16-i); // preshift for inner loop
|
z->maxcode[i] = code << (16-i); // preshift for inner loop
|
||||||
code <<= 1;
|
code <<= 1;
|
||||||
k += sizes[i];
|
k += sizes[i];
|
||||||
@ -3557,9 +3663,9 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
|
|||||||
p = (stbi_uc *) (zout - dist);
|
p = (stbi_uc *) (zout - dist);
|
||||||
if (dist == 1) { // run of one byte; common in images.
|
if (dist == 1) { // run of one byte; common in images.
|
||||||
stbi_uc v = *p;
|
stbi_uc v = *p;
|
||||||
do *zout++ = v; while (--len);
|
if (len) { do *zout++ = v; while (--len); }
|
||||||
} else {
|
} else {
|
||||||
do *zout++ = *p++; while (--len);
|
if (len) { do *zout++ = *p++; while (--len); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3587,7 +3693,7 @@ static int stbi__compute_huffman_codes(stbi__zbuf *a)
|
|||||||
n = 0;
|
n = 0;
|
||||||
while (n < hlit + hdist) {
|
while (n < hlit + hdist) {
|
||||||
int c = stbi__zhuffman_decode(a, &z_codelength);
|
int c = stbi__zhuffman_decode(a, &z_codelength);
|
||||||
STBI_ASSERT(c >= 0 && c < 19);
|
if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG");
|
||||||
if (c < 16)
|
if (c < 16)
|
||||||
lencodes[n++] = (stbi_uc) c;
|
lencodes[n++] = (stbi_uc) c;
|
||||||
else if (c == 16) {
|
else if (c == 16) {
|
||||||
@ -4019,7 +4125,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
|
|||||||
cur[i*2+0] = cur[i];
|
cur[i*2+0] = cur[i];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(img_n == 3);
|
STBI_ASSERT(img_n == 3);
|
||||||
for (i=x-1; i >= 0; --i) {
|
for (i=x-1; i >= 0; --i) {
|
||||||
cur[i*4+3] = 255;
|
cur[i*4+3] = 255;
|
||||||
cur[i*4+2] = cur[i*3+2];
|
cur[i*4+2] = cur[i*3+2];
|
||||||
@ -4284,6 +4390,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
|
|||||||
if (first) return stbi__err("first not IHDR", "Corrupt PNG");
|
if (first) return stbi__err("first not IHDR", "Corrupt PNG");
|
||||||
if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG");
|
if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG");
|
||||||
if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }
|
if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }
|
||||||
|
if ((int)(ioff + c.length) < (int)ioff) return 0;
|
||||||
if (ioff + c.length > idata_limit) {
|
if (ioff + c.length > idata_limit) {
|
||||||
stbi_uc *p;
|
stbi_uc *p;
|
||||||
if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
|
if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
|
||||||
@ -4643,7 +4750,7 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (i=0; i < (int) s->img_x; ++i) {
|
for (i=0; i < (int) s->img_x; ++i) {
|
||||||
stbi__uint32 v = (stbi__uint32) (bpp == 16 ? stbi__get16le(s) : stbi__get32le(s));
|
stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));
|
||||||
int a;
|
int a;
|
||||||
out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));
|
out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));
|
||||||
out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));
|
out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));
|
||||||
@ -4800,7 +4907,7 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
|
|||||||
*y = tga_height;
|
*y = tga_height;
|
||||||
if (comp) *comp = tga_comp;
|
if (comp) *comp = tga_comp;
|
||||||
|
|
||||||
tga_data = (unsigned char*)stbi__malloc( tga_width * tga_height * tga_comp );
|
tga_data = (unsigned char*)stbi__malloc( (size_t)tga_width * tga_height * tga_comp );
|
||||||
if (!tga_data) return stbi__errpuc("outofmem", "Out of memory");
|
if (!tga_data) return stbi__errpuc("outofmem", "Out of memory");
|
||||||
|
|
||||||
// skip to the data's starting position (offset usually = 0)
|
// skip to the data's starting position (offset usually = 0)
|
||||||
@ -5461,6 +5568,7 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
|
|||||||
stbi__gif_lzw *p;
|
stbi__gif_lzw *p;
|
||||||
|
|
||||||
lzw_cs = stbi__get8(s);
|
lzw_cs = stbi__get8(s);
|
||||||
|
if (lzw_cs > 12) return NULL;
|
||||||
clear = 1 << lzw_cs;
|
clear = 1 << lzw_cs;
|
||||||
first = 1;
|
first = 1;
|
||||||
codesize = lzw_cs + 1;
|
codesize = lzw_cs + 1;
|
||||||
@ -6192,6 +6300,13 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
revision history:
|
revision history:
|
||||||
|
2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning
|
||||||
|
2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit
|
||||||
|
2.03 (2015-04-12) extra corruption checking (mmozeiko)
|
||||||
|
stbi_set_flip_vertically_on_load (nguillemot)
|
||||||
|
fix NEON support; fix mingw support
|
||||||
|
2.02 (2015-01-19) fix incorrect assert, fix warning
|
||||||
|
2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2
|
||||||
2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
|
2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
|
||||||
2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg)
|
2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg)
|
||||||
progressive JPEG (stb)
|
progressive JPEG (stb)
|
||||||
@ -6276,7 +6391,7 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
|
|||||||
1.21 fix use of 'stbi_uc' in header (reported by jon blow)
|
1.21 fix use of 'stbi_uc' in header (reported by jon blow)
|
||||||
1.20 added support for Softimage PIC, by Tom Seddon
|
1.20 added support for Softimage PIC, by Tom Seddon
|
||||||
1.19 bug in interlaced PNG corruption check (found by ryg)
|
1.19 bug in interlaced PNG corruption check (found by ryg)
|
||||||
1.18 2008-08-02
|
1.18 (2008-08-02)
|
||||||
fix a threading bug (local mutable static)
|
fix a threading bug (local mutable static)
|
||||||
1.17 support interlaced PNG
|
1.17 support interlaced PNG
|
||||||
1.16 major bugfix - stbi__convert_format converted one too many pixels
|
1.16 major bugfix - stbi__convert_format converted one too many pixels
|
||||||
@ -6321,5 +6436,6 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
|
|||||||
0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments
|
0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments
|
||||||
0.51 obey req_comp requests, 1-component jpegs return as 1-component,
|
0.51 obey req_comp requests, 1-component jpegs return as 1-component,
|
||||||
on 'test' only check type, not whether we support this variant
|
on 'test' only check type, not whether we support this variant
|
||||||
0.50 first released version
|
0.50 (2006-11-19)
|
||||||
|
first released version
|
||||||
*/
|
*/
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
/* stb_image_write - v0.95 - public domain - http://nothings.org/stb/stb_image_write.h
|
/* stb_image_write - v0.98 - public domain - http://nothings.org/stb/stb_image_write.h
|
||||||
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010
|
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010
|
||||||
no warranty implied; use at your own risk
|
no warranty implied; use at your own risk
|
||||||
|
|
||||||
|
|
||||||
Before including,
|
Before #including,
|
||||||
|
|
||||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
|
||||||
@ -11,7 +11,6 @@ in the file that you want to have the implementation.
|
|||||||
|
|
||||||
Will probably not work correctly with strict-aliasing optimizations.
|
Will probably not work correctly with strict-aliasing optimizations.
|
||||||
|
|
||||||
|
|
||||||
ABOUT:
|
ABOUT:
|
||||||
|
|
||||||
This header file is a library for writing images to C stdio. It could be
|
This header file is a library for writing images to C stdio. It could be
|
||||||
@ -22,13 +21,21 @@ ABOUT:
|
|||||||
for source code compactness and simplicitly, not optimal image file size
|
for source code compactness and simplicitly, not optimal image file size
|
||||||
or run-time performance.
|
or run-time performance.
|
||||||
|
|
||||||
|
BUILDING:
|
||||||
|
|
||||||
|
You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.
|
||||||
|
You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace
|
||||||
|
malloc,realloc,free.
|
||||||
|
You can define STBIW_MEMMOVE() to replace memmove()
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
|
|
||||||
There are three functions, one for each image file format:
|
There are four functions, one for each image file format:
|
||||||
|
|
||||||
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
|
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||||
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
|
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
|
||||||
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
|
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
|
||||||
|
int stbi_write_hdr(char const *filename, int w, int h, int comp, const void *data);
|
||||||
|
|
||||||
Each function returns 0 on failure and non-0 on success.
|
Each function returns 0 on failure and non-0 on success.
|
||||||
|
|
||||||
@ -51,6 +58,23 @@ USAGE:
|
|||||||
formats do not. (Thus you cannot write a native-format BMP through the BMP
|
formats do not. (Thus you cannot write a native-format BMP through the BMP
|
||||||
writer, both because it is in BGR order and because it may have padding
|
writer, both because it is in BGR order and because it may have padding
|
||||||
at the end of the line.)
|
at the end of the line.)
|
||||||
|
|
||||||
|
HDR expects linear float data. Since the format is always 32-bit rgb(e)
|
||||||
|
data, alpha (if provided) is discarded, and for monochrome data it is
|
||||||
|
replicated across all three channels.
|
||||||
|
|
||||||
|
CREDITS:
|
||||||
|
|
||||||
|
PNG/BMP/TGA
|
||||||
|
Sean Barrett
|
||||||
|
HDR
|
||||||
|
Baldur Karlsson
|
||||||
|
TGA monochrome:
|
||||||
|
Jean-Sebastien Guay
|
||||||
|
misc enhancements:
|
||||||
|
Tim Kelsey
|
||||||
|
bugfixes:
|
||||||
|
github:Chribba
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef INCLUDE_STB_IMAGE_WRITE_H
|
#ifndef INCLUDE_STB_IMAGE_WRITE_H
|
||||||
@ -63,6 +87,7 @@ extern "C" {
|
|||||||
extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
|
extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||||
extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
|
extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
|
||||||
extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
|
extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
|
||||||
|
extern int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
@ -76,7 +101,30 @@ extern int stbi_write_tga(char const *filename, int w, int h, int comp, const vo
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && defined(STBIW_REALLOC)
|
||||||
|
// ok
|
||||||
|
#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC)
|
||||||
|
// ok
|
||||||
|
#else
|
||||||
|
#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STBIW_MALLOC
|
||||||
|
#define STBIW_MALLOC(sz) malloc(sz)
|
||||||
|
#define STBIW_REALLOC(p,sz) realloc(p,sz)
|
||||||
|
#define STBIW_FREE(p) free(p)
|
||||||
|
#endif
|
||||||
|
#ifndef STBIW_MEMMOVE
|
||||||
|
#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef STBIW_ASSERT
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#define STBIW_ASSERT(x) assert(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef unsigned int stbiw_uint32;
|
typedef unsigned int stbiw_uint32;
|
||||||
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
|
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
|
||||||
@ -95,7 +143,7 @@ static void writefv(FILE *f, const char *fmt, va_list v)
|
|||||||
b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24);
|
b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24);
|
||||||
fwrite(b,4,1,f); break; }
|
fwrite(b,4,1,f); break; }
|
||||||
default:
|
default:
|
||||||
assert(0);
|
STBIW_ASSERT(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,7 +156,7 @@ static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c)
|
|||||||
fwrite(arr, 3, 1, f);
|
fwrite(arr, 3, 1, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad)
|
static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)
|
||||||
{
|
{
|
||||||
unsigned char bg[3] = { 255, 0, 255}, px[3];
|
unsigned char bg[3] = { 255, 0, 255}, px[3];
|
||||||
stbiw_uint32 zero = 0;
|
stbiw_uint32 zero = 0;
|
||||||
@ -128,8 +176,12 @@ static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp,
|
|||||||
if (write_alpha < 0)
|
if (write_alpha < 0)
|
||||||
fwrite(&d[comp-1], 1, 1, f);
|
fwrite(&d[comp-1], 1, 1, f);
|
||||||
switch (comp) {
|
switch (comp) {
|
||||||
case 1:
|
case 1: fwrite(d, 1, 1, f);
|
||||||
case 2: fwrite(d, 1, 1, f);
|
break;
|
||||||
|
case 2: if (expand_mono)
|
||||||
|
write3(f, d[0],d[0],d[0]); // monochrome bmp
|
||||||
|
else
|
||||||
|
fwrite(d, 1, 1, f); // monochrome TGA
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
if (!write_alpha) {
|
if (!write_alpha) {
|
||||||
@ -151,7 +203,7 @@ static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, void *data, int alpha, int pad, const char *fmt, ...)
|
static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
if (y < 0 || x < 0) return 0;
|
if (y < 0 || x < 0) return 0;
|
||||||
@ -161,7 +213,7 @@ static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, in
|
|||||||
va_start(v, fmt);
|
va_start(v, fmt);
|
||||||
writefv(f, fmt, v);
|
writefv(f, fmt, v);
|
||||||
va_end(v);
|
va_end(v);
|
||||||
write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad);
|
write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad,expand_mono);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
return f != NULL;
|
return f != NULL;
|
||||||
@ -170,7 +222,7 @@ static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, in
|
|||||||
int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
|
int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
|
||||||
{
|
{
|
||||||
int pad = (-x*3) & 3;
|
int pad = (-x*3) & 3;
|
||||||
return outfile(filename,-1,-1,x,y,comp,(void *) data,0,pad,
|
return outfile(filename,-1,-1,x,y,comp,1,(void *) data,0,pad,
|
||||||
"11 4 22 4" "4 44 22 444444",
|
"11 4 22 4" "4 44 22 444444",
|
||||||
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
|
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
|
||||||
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
|
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
|
||||||
@ -181,10 +233,159 @@ int stbi_write_tga(char const *filename, int x, int y, int comp, const void *dat
|
|||||||
int has_alpha = (comp == 2 || comp == 4);
|
int has_alpha = (comp == 2 || comp == 4);
|
||||||
int colorbytes = has_alpha ? comp-1 : comp;
|
int colorbytes = has_alpha ? comp-1 : comp;
|
||||||
int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
|
int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
|
||||||
return outfile(filename, -1,-1, x, y, comp, (void *) data, has_alpha, 0,
|
return outfile(filename, -1,-1, x, y, comp, 0, (void *) data, has_alpha, 0,
|
||||||
"111 221 2222 11", 0,0,format, 0,0,0, 0,0,x,y, (colorbytes+has_alpha)*8, has_alpha*8);
|
"111 221 2222 11", 0,0,format, 0,0,0, 0,0,x,y, (colorbytes+has_alpha)*8, has_alpha*8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// *************************************************************************************************
|
||||||
|
// Radiance RGBE HDR writer
|
||||||
|
// by Baldur Karlsson
|
||||||
|
#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
|
||||||
|
void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
|
||||||
|
{
|
||||||
|
int exponent;
|
||||||
|
float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));
|
||||||
|
|
||||||
|
if (maxcomp < 1e-32) {
|
||||||
|
rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
|
||||||
|
} else {
|
||||||
|
float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;
|
||||||
|
|
||||||
|
rgbe[0] = (unsigned char)(linear[0] * normalize);
|
||||||
|
rgbe[1] = (unsigned char)(linear[1] * normalize);
|
||||||
|
rgbe[2] = (unsigned char)(linear[2] * normalize);
|
||||||
|
rgbe[3] = (unsigned char)(exponent + 128);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stbiw__write_run_data(FILE *f, int length, unsigned char databyte)
|
||||||
|
{
|
||||||
|
unsigned char lengthbyte = (unsigned char) (length+128);
|
||||||
|
STBIW_ASSERT(length+128 <= 255);
|
||||||
|
fwrite(&lengthbyte, 1, 1, f);
|
||||||
|
fwrite(&databyte, 1, 1, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stbiw__write_dump_data(FILE *f, int length, unsigned char *data)
|
||||||
|
{
|
||||||
|
unsigned char lengthbyte = (unsigned char )(length & 0xff);
|
||||||
|
STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
|
||||||
|
fwrite(&lengthbyte, 1, 1, f);
|
||||||
|
fwrite(data, length, 1, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scratch, const float *scanline)
|
||||||
|
{
|
||||||
|
unsigned char scanlineheader[4] = { 2, 2, 0, 0 };
|
||||||
|
unsigned char rgbe[4];
|
||||||
|
float linear[3];
|
||||||
|
int x;
|
||||||
|
|
||||||
|
scanlineheader[2] = (width&0xff00)>>8;
|
||||||
|
scanlineheader[3] = (width&0x00ff);
|
||||||
|
|
||||||
|
/* skip RLE for images too small or large */
|
||||||
|
if (width < 8 || width >= 32768) {
|
||||||
|
for (x=0; x < width; x++) {
|
||||||
|
switch (comp) {
|
||||||
|
case 4: /* fallthrough */
|
||||||
|
case 3: linear[2] = scanline[x*comp + 2];
|
||||||
|
linear[1] = scanline[x*comp + 1];
|
||||||
|
linear[0] = scanline[x*comp + 0];
|
||||||
|
break;
|
||||||
|
case 2: /* fallthrough */
|
||||||
|
case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
stbiw__linear_to_rgbe(rgbe, linear);
|
||||||
|
fwrite(rgbe, 4, 1, f);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int c,r;
|
||||||
|
/* encode into scratch buffer */
|
||||||
|
for (x=0; x < width; x++) {
|
||||||
|
switch(comp) {
|
||||||
|
case 4: /* fallthrough */
|
||||||
|
case 3: linear[2] = scanline[x*comp + 2];
|
||||||
|
linear[1] = scanline[x*comp + 1];
|
||||||
|
linear[0] = scanline[x*comp + 0];
|
||||||
|
break;
|
||||||
|
case 2: /* fallthrough */
|
||||||
|
case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
stbiw__linear_to_rgbe(rgbe, linear);
|
||||||
|
scratch[x + width*0] = rgbe[0];
|
||||||
|
scratch[x + width*1] = rgbe[1];
|
||||||
|
scratch[x + width*2] = rgbe[2];
|
||||||
|
scratch[x + width*3] = rgbe[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite(scanlineheader, 4, 1, f);
|
||||||
|
|
||||||
|
/* RLE each component separately */
|
||||||
|
for (c=0; c < 4; c++) {
|
||||||
|
unsigned char *comp = &scratch[width*c];
|
||||||
|
|
||||||
|
x = 0;
|
||||||
|
while (x < width) {
|
||||||
|
// find first run
|
||||||
|
r = x;
|
||||||
|
while (r+2 < width) {
|
||||||
|
if (comp[r] == comp[r+1] && comp[r] == comp[r+2])
|
||||||
|
break;
|
||||||
|
++r;
|
||||||
|
}
|
||||||
|
if (r+2 >= width)
|
||||||
|
r = width;
|
||||||
|
// dump up to first run
|
||||||
|
while (x < r) {
|
||||||
|
int len = r-x;
|
||||||
|
if (len > 128) len = 128;
|
||||||
|
stbiw__write_dump_data(f, len, &comp[x]);
|
||||||
|
x += len;
|
||||||
|
}
|
||||||
|
// if there's a run, output it
|
||||||
|
if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd
|
||||||
|
// find next byte after run
|
||||||
|
while (r < width && comp[r] == comp[x])
|
||||||
|
++r;
|
||||||
|
// output run up to r
|
||||||
|
while (x < r) {
|
||||||
|
int len = r-x;
|
||||||
|
if (len > 127) len = 127;
|
||||||
|
stbiw__write_run_data(f, len, comp[x]);
|
||||||
|
x += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
FILE *f;
|
||||||
|
if (y <= 0 || x <= 0 || data == NULL) return 0;
|
||||||
|
f = fopen(filename, "wb");
|
||||||
|
if (f) {
|
||||||
|
/* Each component is stored separately. Allocate scratch space for full output scanline. */
|
||||||
|
unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);
|
||||||
|
fprintf(f, "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n" );
|
||||||
|
fprintf(f, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n" , y, x);
|
||||||
|
for(i=0; i < y; i++)
|
||||||
|
stbiw__write_hdr_scanline(f, x, comp, scratch, data + comp*i*x);
|
||||||
|
STBIW_FREE(scratch);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
return f != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////
|
||||||
|
// PNG
|
||||||
|
|
||||||
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
|
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
|
||||||
#define stbiw__sbraw(a) ((int *) (a) - 2)
|
#define stbiw__sbraw(a) ((int *) (a) - 2)
|
||||||
#define stbiw__sbm(a) stbiw__sbraw(a)[0]
|
#define stbiw__sbm(a) stbiw__sbraw(a)[0]
|
||||||
@ -196,13 +397,13 @@ int stbi_write_tga(char const *filename, int x, int y, int comp, const void *dat
|
|||||||
|
|
||||||
#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
|
#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
|
||||||
#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0)
|
#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0)
|
||||||
#define stbiw__sbfree(a) ((a) ? free(stbiw__sbraw(a)),0 : 0)
|
#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)
|
||||||
|
|
||||||
static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
|
static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
|
||||||
{
|
{
|
||||||
int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
|
int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
|
||||||
void *p = realloc(*arr ? stbiw__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
|
void *p = STBIW_REALLOC(*arr ? stbiw__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
|
||||||
assert(p);
|
STBIW_ASSERT(p);
|
||||||
if (p) {
|
if (p) {
|
||||||
if (!*arr) ((int *) p)[1] = 0;
|
if (!*arr) ((int *) p)[1] = 0;
|
||||||
*arr = (void *) ((int *) p + 2);
|
*arr = (void *) ((int *) p + 2);
|
||||||
@ -300,7 +501,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
|
|||||||
}
|
}
|
||||||
// when hash table entry is too long, delete half the entries
|
// when hash table entry is too long, delete half the entries
|
||||||
if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {
|
if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {
|
||||||
memcpy(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
|
STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
|
||||||
stbiw__sbn(hash_table[h]) = quality;
|
stbiw__sbn(hash_table[h]) = quality;
|
||||||
}
|
}
|
||||||
stbiw__sbpush(hash_table[h],data+i);
|
stbiw__sbpush(hash_table[h],data+i);
|
||||||
@ -323,7 +524,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
|
|||||||
|
|
||||||
if (bestloc) {
|
if (bestloc) {
|
||||||
int d = (int) (data+i - bestloc); // distance back
|
int d = (int) (data+i - bestloc); // distance back
|
||||||
assert(d <= 32767 && best <= 258);
|
STBIW_ASSERT(d <= 32767 && best <= 258);
|
||||||
for (j=0; best > lengthc[j+1]-1; ++j);
|
for (j=0; best > lengthc[j+1]-1; ++j);
|
||||||
stbiw__zlib_huff(j+257);
|
stbiw__zlib_huff(j+257);
|
||||||
if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
|
if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
|
||||||
@ -364,7 +565,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
|
|||||||
}
|
}
|
||||||
*out_len = stbiw__sbn(out);
|
*out_len = stbiw__sbn(out);
|
||||||
// make returned pointer freeable
|
// make returned pointer freeable
|
||||||
memmove(stbiw__sbraw(out), out, *out_len);
|
STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
|
||||||
return (unsigned char *) stbiw__sbraw(out);
|
return (unsigned char *) stbiw__sbraw(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,8 +612,8 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
|
|||||||
if (stride_bytes == 0)
|
if (stride_bytes == 0)
|
||||||
stride_bytes = x * n;
|
stride_bytes = x * n;
|
||||||
|
|
||||||
filt = (unsigned char *) malloc((x*n+1) * y); if (!filt) return 0;
|
filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;
|
||||||
line_buffer = (signed char *) malloc(x * n); if (!line_buffer) { free(filt); return 0; }
|
line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
|
||||||
for (j=0; j < y; ++j) {
|
for (j=0; j < y; ++j) {
|
||||||
static int mapping[] = { 0,1,2,3,4 };
|
static int mapping[] = { 0,1,2,3,4 };
|
||||||
static int firstmap[] = { 0,1,0,5,6 };
|
static int firstmap[] = { 0,1,0,5,6 };
|
||||||
@ -451,20 +652,20 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
|
|||||||
}
|
}
|
||||||
// when we get here, best contains the filter type, and line_buffer contains the data
|
// when we get here, best contains the filter type, and line_buffer contains the data
|
||||||
filt[j*(x*n+1)] = (unsigned char) best;
|
filt[j*(x*n+1)] = (unsigned char) best;
|
||||||
memcpy(filt+j*(x*n+1)+1, line_buffer, x*n);
|
STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
|
||||||
}
|
}
|
||||||
free(line_buffer);
|
STBIW_FREE(line_buffer);
|
||||||
zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
|
zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
|
||||||
free(filt);
|
STBIW_FREE(filt);
|
||||||
if (!zlib) return 0;
|
if (!zlib) return 0;
|
||||||
|
|
||||||
// each tag requires 12 bytes of overhead
|
// each tag requires 12 bytes of overhead
|
||||||
out = (unsigned char *) malloc(8 + 12+13 + 12+zlen + 12);
|
out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12);
|
||||||
if (!out) return 0;
|
if (!out) return 0;
|
||||||
*out_len = 8 + 12+13 + 12+zlen + 12;
|
*out_len = 8 + 12+13 + 12+zlen + 12;
|
||||||
|
|
||||||
o=out;
|
o=out;
|
||||||
memcpy(o,sig,8); o+= 8;
|
STBIW_MEMMOVE(o,sig,8); o+= 8;
|
||||||
stbiw__wp32(o, 13); // header length
|
stbiw__wp32(o, 13); // header length
|
||||||
stbiw__wptag(o, "IHDR");
|
stbiw__wptag(o, "IHDR");
|
||||||
stbiw__wp32(o, x);
|
stbiw__wp32(o, x);
|
||||||
@ -478,14 +679,16 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
|
|||||||
|
|
||||||
stbiw__wp32(o, zlen);
|
stbiw__wp32(o, zlen);
|
||||||
stbiw__wptag(o, "IDAT");
|
stbiw__wptag(o, "IDAT");
|
||||||
memcpy(o, zlib, zlen); o += zlen; free(zlib);
|
STBIW_MEMMOVE(o, zlib, zlen);
|
||||||
|
o += zlen;
|
||||||
|
STBIW_FREE(zlib);
|
||||||
stbiw__wpcrc(&o, zlen);
|
stbiw__wpcrc(&o, zlen);
|
||||||
|
|
||||||
stbiw__wp32(o,0);
|
stbiw__wp32(o,0);
|
||||||
stbiw__wptag(o, "IEND");
|
stbiw__wptag(o, "IEND");
|
||||||
stbiw__wpcrc(&o,0);
|
stbiw__wpcrc(&o,0);
|
||||||
|
|
||||||
assert(o == out + *out_len);
|
STBIW_ASSERT(o == out + *out_len);
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@ -497,16 +700,22 @@ int stbi_write_png(char const *filename, int x, int y, int comp, const void *dat
|
|||||||
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
|
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
|
||||||
if (!png) return 0;
|
if (!png) return 0;
|
||||||
f = fopen(filename, "wb");
|
f = fopen(filename, "wb");
|
||||||
if (!f) { free(png); return 0; }
|
if (!f) { STBIW_FREE(png); return 0; }
|
||||||
fwrite(png, 1, len, f);
|
fwrite(png, 1, len, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
free(png);
|
STBIW_FREE(png);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
|
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
|
||||||
/* Revision history
|
/* Revision history
|
||||||
|
0.98 (2015-04-08)
|
||||||
|
added STBIW_MALLOC, STBIW_ASSERT etc
|
||||||
|
0.97 (2015-01-18)
|
||||||
|
fixed HDR asserts, rewrote HDR rle logic
|
||||||
|
0.96 (2015-01-17)
|
||||||
|
add HDR output
|
||||||
|
fix monochrome BMP
|
||||||
0.95 (2014-08-17)
|
0.95 (2014-08-17)
|
||||||
add monochrome TGA output
|
add monochrome TGA output
|
||||||
0.94 (2014-05-31)
|
0.94 (2014-05-31)
|
||||||
|
391
src/stb_vorbis.c
391
src/stb_vorbis.c
@ -1,5 +1,389 @@
|
|||||||
|
// Ogg Vorbis audio decoder - v1.05 - public domain
|
||||||
|
// http://nothings.org/stb_vorbis/
|
||||||
|
//
|
||||||
|
// Written by Sean Barrett in 2007, last updated in 2014
|
||||||
|
// Sponsored by RAD Game Tools.
|
||||||
|
//
|
||||||
|
// Placed in the public domain April 2007 by the author: no copyright
|
||||||
|
// is claimed, and you may use it for any purpose you like.
|
||||||
|
//
|
||||||
|
// No warranty for any purpose is expressed or implied by the author (nor
|
||||||
|
// by RAD Game Tools). Report bugs and send enhancements to the author.
|
||||||
|
//
|
||||||
|
// Limitations:
|
||||||
|
//
|
||||||
|
// - seeking not supported except manually via PUSHDATA api
|
||||||
|
// - floor 0 not supported (used in old ogg vorbis files pre-2004)
|
||||||
|
// - lossless sample-truncation at beginning ignored
|
||||||
|
// - cannot concatenate multiple vorbis streams
|
||||||
|
// - sample positions are 32-bit, limiting seekable 192Khz
|
||||||
|
// files to around 6 hours (Ogg supports 64-bit)
|
||||||
|
//
|
||||||
|
// Bugfix/warning contributors:
|
||||||
|
// Terje Mathisen Niklas Frykholm Andy Hill
|
||||||
|
// Casey Muratori John Bolton Gargaj
|
||||||
|
// Laurent Gomila Marc LeBlanc Ronny Chevalier
|
||||||
|
// Bernhard Wodo Evan Balster "alxprd"@github
|
||||||
|
// Tom Beaumont Ingo Leitgeb Nicolas Guillemot
|
||||||
|
// (If you reported a bug but do not appear in this list, it is because
|
||||||
|
// someone else reported the bug before you. There were too many of you to
|
||||||
|
// list them all because I was lax about updating for a long time, sorry.)
|
||||||
|
//
|
||||||
|
// Partial history:
|
||||||
|
// 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
|
||||||
|
// 1.02 - 2014/07/09 - declare qsort comparison as explicitly _cdecl in Windows
|
||||||
|
// 1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float (interleaved was correct)
|
||||||
|
// 1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in >2-channel;
|
||||||
|
// (API change) report sample rate for decode-full-file funcs
|
||||||
|
// 0.99996 - - bracket #include <malloc.h> for macintosh compilation
|
||||||
|
// 0.99995 - - avoid alias-optimization issue in float-to-int conversion
|
||||||
|
//
|
||||||
|
// See end of file for full version history.
|
||||||
|
|
||||||
#include "stb_vorbis.h"
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// HEADER BEGINS HERE
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef STB_VORBIS_INCLUDE_STB_VORBIS_H
|
||||||
|
#define STB_VORBIS_INCLUDE_STB_VORBIS_H
|
||||||
|
|
||||||
|
#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO)
|
||||||
|
#define STB_VORBIS_NO_STDIO 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STB_VORBIS_NO_STDIO
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// NOTE: Added to work with raylib on Android
|
||||||
|
#if defined(PLATFORM_ANDROID)
|
||||||
|
#include "utils.h" // Android fopen function map
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// RaySan: Added for Linux
|
||||||
|
#ifdef __linux
|
||||||
|
#include <alloca.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/////////// THREAD SAFETY
|
||||||
|
|
||||||
|
// Individual stb_vorbis* handles are not thread-safe; you cannot decode from
|
||||||
|
// them from multiple threads at the same time. However, you can have multiple
|
||||||
|
// stb_vorbis* handles and decode from them independently in multiple thrads.
|
||||||
|
|
||||||
|
|
||||||
|
/////////// MEMORY ALLOCATION
|
||||||
|
|
||||||
|
// normally stb_vorbis uses malloc() to allocate memory at startup,
|
||||||
|
// and alloca() to allocate temporary memory during a frame on the
|
||||||
|
// stack. (Memory consumption will depend on the amount of setup
|
||||||
|
// data in the file and how you set the compile flags for speed
|
||||||
|
// vs. size. In my test files the maximal-size usage is ~150KB.)
|
||||||
|
//
|
||||||
|
// You can modify the wrapper functions in the source (setup_malloc,
|
||||||
|
// setup_temp_malloc, temp_malloc) to change this behavior, or you
|
||||||
|
// can use a simpler allocation model: you pass in a buffer from
|
||||||
|
// which stb_vorbis will allocate _all_ its memory (including the
|
||||||
|
// temp memory). "open" may fail with a VORBIS_outofmem if you
|
||||||
|
// do not pass in enough data; there is no way to determine how
|
||||||
|
// much you do need except to succeed (at which point you can
|
||||||
|
// query get_info to find the exact amount required. yes I know
|
||||||
|
// this is lame).
|
||||||
|
//
|
||||||
|
// If you pass in a non-NULL buffer of the type below, allocation
|
||||||
|
// will occur from it as described above. Otherwise just pass NULL
|
||||||
|
// to use malloc()/alloca()
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char *alloc_buffer;
|
||||||
|
int alloc_buffer_length_in_bytes;
|
||||||
|
} stb_vorbis_alloc;
|
||||||
|
|
||||||
|
|
||||||
|
/////////// FUNCTIONS USEABLE WITH ALL INPUT MODES
|
||||||
|
|
||||||
|
typedef struct stb_vorbis stb_vorbis;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int sample_rate;
|
||||||
|
int channels;
|
||||||
|
|
||||||
|
unsigned int setup_memory_required;
|
||||||
|
unsigned int setup_temp_memory_required;
|
||||||
|
unsigned int temp_memory_required;
|
||||||
|
|
||||||
|
int max_frame_size;
|
||||||
|
} stb_vorbis_info;
|
||||||
|
|
||||||
|
// get general information about the file
|
||||||
|
extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f);
|
||||||
|
|
||||||
|
// get the last error detected (clears it, too)
|
||||||
|
extern int stb_vorbis_get_error(stb_vorbis *f);
|
||||||
|
|
||||||
|
// close an ogg vorbis file and free all memory in use
|
||||||
|
extern void stb_vorbis_close(stb_vorbis *f);
|
||||||
|
|
||||||
|
// this function returns the offset (in samples) from the beginning of the
|
||||||
|
// file that will be returned by the next decode, if it is known, or -1
|
||||||
|
// otherwise. after a flush_pushdata() call, this may take a while before
|
||||||
|
// it becomes valid again.
|
||||||
|
// NOT WORKING YET after a seek with PULLDATA API
|
||||||
|
extern int stb_vorbis_get_sample_offset(stb_vorbis *f);
|
||||||
|
|
||||||
|
// returns the current seek point within the file, or offset from the beginning
|
||||||
|
// of the memory buffer. In pushdata mode it returns 0.
|
||||||
|
extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f);
|
||||||
|
|
||||||
|
/////////// PUSHDATA API
|
||||||
|
|
||||||
|
#ifndef STB_VORBIS_NO_PUSHDATA_API
|
||||||
|
|
||||||
|
// this API allows you to get blocks of data from any source and hand
|
||||||
|
// them to stb_vorbis. you have to buffer them; stb_vorbis will tell
|
||||||
|
// you how much it used, and you have to give it the rest next time;
|
||||||
|
// and stb_vorbis may not have enough data to work with and you will
|
||||||
|
// need to give it the same data again PLUS more. Note that the Vorbis
|
||||||
|
// specification does not bound the size of an individual frame.
|
||||||
|
|
||||||
|
extern stb_vorbis *stb_vorbis_open_pushdata(
|
||||||
|
unsigned char *datablock, int datablock_length_in_bytes,
|
||||||
|
int *datablock_memory_consumed_in_bytes,
|
||||||
|
int *error,
|
||||||
|
stb_vorbis_alloc *alloc_buffer);
|
||||||
|
// create a vorbis decoder by passing in the initial data block containing
|
||||||
|
// the ogg&vorbis headers (you don't need to do parse them, just provide
|
||||||
|
// the first N bytes of the file--you're told if it's not enough, see below)
|
||||||
|
// on success, returns an stb_vorbis *, does not set error, returns the amount of
|
||||||
|
// data parsed/consumed on this call in *datablock_memory_consumed_in_bytes;
|
||||||
|
// on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed
|
||||||
|
// if returns NULL and *error is VORBIS_need_more_data, then the input block was
|
||||||
|
// incomplete and you need to pass in a larger block from the start of the file
|
||||||
|
|
||||||
|
extern int stb_vorbis_decode_frame_pushdata(
|
||||||
|
stb_vorbis *f, unsigned char *datablock, int datablock_length_in_bytes,
|
||||||
|
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
|
||||||
|
);
|
||||||
|
// decode a frame of audio sample data if possible from the passed-in data block
|
||||||
|
//
|
||||||
|
// return value: number of bytes we used from datablock
|
||||||
|
//
|
||||||
|
// possible cases:
|
||||||
|
// 0 bytes used, 0 samples output (need more data)
|
||||||
|
// N bytes used, 0 samples output (resynching the stream, keep going)
|
||||||
|
// N bytes used, M samples output (one frame of data)
|
||||||
|
// note that after opening a file, you will ALWAYS get one N-bytes,0-sample
|
||||||
|
// frame, because Vorbis always "discards" the first frame.
|
||||||
|
//
|
||||||
|
// Note that on resynch, stb_vorbis will rarely consume all of the buffer,
|
||||||
|
// instead only datablock_length_in_bytes-3 or less. This is because it wants
|
||||||
|
// to avoid missing parts of a page header if they cross a datablock boundary,
|
||||||
|
// without writing state-machiney code to record a partial detection.
|
||||||
|
//
|
||||||
|
// The number of channels returned are stored in *channels (which can be
|
||||||
|
// NULL--it is always the same as the number of channels reported by
|
||||||
|
// get_info). *output will contain an array of float* buffers, one per
|
||||||
|
// channel. In other words, (*output)[0][0] contains the first sample from
|
||||||
|
// the first channel, and (*output)[1][0] contains the first sample from
|
||||||
|
// the second channel.
|
||||||
|
|
||||||
|
extern void stb_vorbis_flush_pushdata(stb_vorbis *f);
|
||||||
|
// inform stb_vorbis that your next datablock will not be contiguous with
|
||||||
|
// previous ones (e.g. you've seeked in the data); future attempts to decode
|
||||||
|
// frames will cause stb_vorbis to resynchronize (as noted above), and
|
||||||
|
// once it sees a valid Ogg page (typically 4-8KB, as large as 64KB), it
|
||||||
|
// will begin decoding the _next_ frame.
|
||||||
|
//
|
||||||
|
// if you want to seek using pushdata, you need to seek in your file, then
|
||||||
|
// call stb_vorbis_flush_pushdata(), then start calling decoding, then once
|
||||||
|
// decoding is returning you data, call stb_vorbis_get_sample_offset, and
|
||||||
|
// if you don't like the result, seek your file again and repeat.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
////////// PULLING INPUT API
|
||||||
|
|
||||||
|
#ifndef STB_VORBIS_NO_PULLDATA_API
|
||||||
|
// This API assumes stb_vorbis is allowed to pull data from a source--
|
||||||
|
// either a block of memory containing the _entire_ vorbis stream, or a
|
||||||
|
// FILE * that you or it create, or possibly some other reading mechanism
|
||||||
|
// if you go modify the source to replace the FILE * case with some kind
|
||||||
|
// of callback to your code. (But if you don't support seeking, you may
|
||||||
|
// just want to go ahead and use pushdata.)
|
||||||
|
|
||||||
|
#if !defined(STB_VORBIS_NO_STDIO) && !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
|
||||||
|
extern int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output);
|
||||||
|
#endif
|
||||||
|
#if !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
|
||||||
|
extern int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *channels, int *sample_rate, short **output);
|
||||||
|
#endif
|
||||||
|
// decode an entire file and output the data interleaved into a malloc()ed
|
||||||
|
// buffer stored in *output. The return value is the number of samples
|
||||||
|
// decoded, or -1 if the file could not be opened or was not an ogg vorbis file.
|
||||||
|
// When you're done with it, just free() the pointer returned in *output.
|
||||||
|
|
||||||
|
extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len,
|
||||||
|
int *error, stb_vorbis_alloc *alloc_buffer);
|
||||||
|
// create an ogg vorbis decoder from an ogg vorbis stream in memory (note
|
||||||
|
// this must be the entire stream!). on failure, returns NULL and sets *error
|
||||||
|
|
||||||
|
#ifndef STB_VORBIS_NO_STDIO
|
||||||
|
extern stb_vorbis * stb_vorbis_open_filename(const char *filename,
|
||||||
|
int *error, stb_vorbis_alloc *alloc_buffer);
|
||||||
|
// create an ogg vorbis decoder from a filename via fopen(). on failure,
|
||||||
|
// returns NULL and sets *error (possibly to VORBIS_file_open_failure).
|
||||||
|
|
||||||
|
extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
|
||||||
|
int *error, stb_vorbis_alloc *alloc_buffer);
|
||||||
|
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
|
||||||
|
// the _current_ seek point (ftell). on failure, returns NULL and sets *error.
|
||||||
|
// note that stb_vorbis must "own" this stream; if you seek it in between
|
||||||
|
// calls to stb_vorbis, it will become confused. Morever, if you attempt to
|
||||||
|
// perform stb_vorbis_seek_*() operations on this file, it will assume it
|
||||||
|
// owns the _entire_ rest of the file after the start point. Use the next
|
||||||
|
// function, stb_vorbis_open_file_section(), to limit it.
|
||||||
|
|
||||||
|
extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close,
|
||||||
|
int *error, stb_vorbis_alloc *alloc_buffer, unsigned int len);
|
||||||
|
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
|
||||||
|
// the _current_ seek point (ftell); the stream will be of length 'len' bytes.
|
||||||
|
// on failure, returns NULL and sets *error. note that stb_vorbis must "own"
|
||||||
|
// this stream; if you seek it in between calls to stb_vorbis, it will become
|
||||||
|
// confused.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number);
|
||||||
|
extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number);
|
||||||
|
// NOT WORKING YET
|
||||||
|
// these functions seek in the Vorbis file to (approximately) 'sample_number'.
|
||||||
|
// after calling seek_frame(), the next call to get_frame_*() will include
|
||||||
|
// the specified sample. after calling stb_vorbis_seek(), the next call to
|
||||||
|
// stb_vorbis_get_samples_* will start with the specified sample. If you
|
||||||
|
// do not need to seek to EXACTLY the target sample when using get_samples_*,
|
||||||
|
// you can also use seek_frame().
|
||||||
|
|
||||||
|
extern void stb_vorbis_seek_start(stb_vorbis *f);
|
||||||
|
// this function is equivalent to stb_vorbis_seek(f,0), but it
|
||||||
|
// actually works
|
||||||
|
|
||||||
|
extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f);
|
||||||
|
extern float stb_vorbis_stream_length_in_seconds(stb_vorbis *f);
|
||||||
|
// these functions return the total length of the vorbis stream
|
||||||
|
|
||||||
|
extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output);
|
||||||
|
// decode the next frame and return the number of samples. the number of
|
||||||
|
// channels returned are stored in *channels (which can be NULL--it is always
|
||||||
|
// the same as the number of channels reported by get_info). *output will
|
||||||
|
// contain an array of float* buffers, one per channel. These outputs will
|
||||||
|
// be overwritten on the next call to stb_vorbis_get_frame_*.
|
||||||
|
//
|
||||||
|
// You generally should not intermix calls to stb_vorbis_get_frame_*()
|
||||||
|
// and stb_vorbis_get_samples_*(), since the latter calls the former.
|
||||||
|
|
||||||
|
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
|
||||||
|
extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts);
|
||||||
|
extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples);
|
||||||
|
#endif
|
||||||
|
// decode the next frame and return the number of samples per channel. the
|
||||||
|
// data is coerced to the number of channels you request according to the
|
||||||
|
// channel coercion rules (see below). You must pass in the size of your
|
||||||
|
// buffer(s) so that stb_vorbis will not overwrite the end of the buffer.
|
||||||
|
// The maximum buffer size needed can be gotten from get_info(); however,
|
||||||
|
// the Vorbis I specification implies an absolute maximum of 4096 samples
|
||||||
|
// per channel. Note that for interleaved data, you pass in the number of
|
||||||
|
// shorts (the size of your array), but the return value is the number of
|
||||||
|
// samples per channel, not the total number of samples.
|
||||||
|
|
||||||
|
// Channel coercion rules:
|
||||||
|
// Let M be the number of channels requested, and N the number of channels present,
|
||||||
|
// and Cn be the nth channel; let stereo L be the sum of all L and center channels,
|
||||||
|
// and stereo R be the sum of all R and center channels (channel assignment from the
|
||||||
|
// vorbis spec).
|
||||||
|
// M N output
|
||||||
|
// 1 k sum(Ck) for all k
|
||||||
|
// 2 * stereo L, stereo R
|
||||||
|
// k l k > l, the first l channels, then 0s
|
||||||
|
// k l k <= l, the first k channels
|
||||||
|
// Note that this is not _good_ surround etc. mixing at all! It's just so
|
||||||
|
// you get something useful.
|
||||||
|
|
||||||
|
extern int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats);
|
||||||
|
extern int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples);
|
||||||
|
// gets num_samples samples, not necessarily on a frame boundary--this requires
|
||||||
|
// buffering so you have to supply the buffers. DOES NOT APPLY THE COERCION RULES.
|
||||||
|
// Returns the number of samples stored per channel; it may be less than requested
|
||||||
|
// at the end of the file. If there are no more samples in the file, returns 0.
|
||||||
|
|
||||||
|
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
|
||||||
|
extern int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts);
|
||||||
|
extern int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples);
|
||||||
|
#endif
|
||||||
|
// gets num_samples samples, not necessarily on a frame boundary--this requires
|
||||||
|
// buffering so you have to supply the buffers. Applies the coercion rules above
|
||||||
|
// to produce 'channels' channels. Returns the number of samples stored per channel;
|
||||||
|
// it may be less than requested at the end of the file. If there are no more
|
||||||
|
// samples in the file, returns 0.
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//////// ERROR CODES
|
||||||
|
|
||||||
|
enum STBVorbisError
|
||||||
|
{
|
||||||
|
VORBIS__no_error,
|
||||||
|
|
||||||
|
VORBIS_need_more_data=1, // not a real error
|
||||||
|
|
||||||
|
VORBIS_invalid_api_mixing, // can't mix API modes
|
||||||
|
VORBIS_outofmem, // not enough memory
|
||||||
|
VORBIS_feature_not_supported, // uses floor 0
|
||||||
|
VORBIS_too_many_channels, // STB_VORBIS_MAX_CHANNELS is too small
|
||||||
|
VORBIS_file_open_failure, // fopen() failed
|
||||||
|
VORBIS_seek_without_length, // can't seek in unknown-length file
|
||||||
|
|
||||||
|
VORBIS_unexpected_eof=10, // file is truncated?
|
||||||
|
VORBIS_seek_invalid, // seek past EOF
|
||||||
|
|
||||||
|
// decoding errors (corrupt/invalid stream) -- you probably
|
||||||
|
// don't care about the exact details of these
|
||||||
|
|
||||||
|
// vorbis errors:
|
||||||
|
VORBIS_invalid_setup=20,
|
||||||
|
VORBIS_invalid_stream,
|
||||||
|
|
||||||
|
// ogg errors:
|
||||||
|
VORBIS_missing_capture_pattern=30,
|
||||||
|
VORBIS_invalid_stream_structure_version,
|
||||||
|
VORBIS_continued_packet_flag_invalid,
|
||||||
|
VORBIS_incorrect_stream_serial_number,
|
||||||
|
VORBIS_invalid_first_page,
|
||||||
|
VORBIS_bad_packet_type,
|
||||||
|
VORBIS_cant_find_last_page,
|
||||||
|
VORBIS_seek_failed,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // STB_VORBIS_INCLUDE_STB_VORBIS_H
|
||||||
|
//
|
||||||
|
// HEADER ENDS HERE
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifndef STB_VORBIS_HEADER_ONLY
|
#ifndef STB_VORBIS_HEADER_ONLY
|
||||||
|
|
||||||
@ -180,7 +564,7 @@
|
|||||||
#define NULL 0
|
#define NULL 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#if !defined(_MSC_VER) && !(defined(__MINGW32__) && defined(__forceinline))
|
||||||
#if __GNUC__
|
#if __GNUC__
|
||||||
#define __forceinline inline
|
#define __forceinline inline
|
||||||
#else
|
#else
|
||||||
@ -3562,7 +3946,7 @@ static int start_decoder(vorb *f)
|
|||||||
g->sorted_order[j] = (uint8) p[j].y;
|
g->sorted_order[j] = (uint8) p[j].y;
|
||||||
// precompute the neighbors
|
// precompute the neighbors
|
||||||
for (j=2; j < g->values; ++j) {
|
for (j=2; j < g->values; ++j) {
|
||||||
int low = 0,hi = 0;
|
int low,hi;
|
||||||
neighbors(g->Xlist, j, &low,&hi);
|
neighbors(g->Xlist, j, &low,&hi);
|
||||||
g->neighbors[j][0] = low;
|
g->neighbors[j][0] = low;
|
||||||
g->neighbors[j][1] = hi;
|
g->neighbors[j][1] = hi;
|
||||||
@ -5024,6 +5408,7 @@ int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, in
|
|||||||
#endif // STB_VORBIS_NO_PULLDATA_API
|
#endif // STB_VORBIS_NO_PULLDATA_API
|
||||||
|
|
||||||
/* Version history
|
/* Version history
|
||||||
|
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.04 - 2014/08/27 - fix missing const-correct case in API
|
||||||
1.03 - 2014/08/07 - Warning fixes
|
1.03 - 2014/08/07 - Warning fixes
|
||||||
1.02 - 2014/07/09 - Declare qsort compare function _cdecl on windows
|
1.02 - 2014/07/09 - Declare qsort compare function _cdecl on windows
|
||||||
|
384
src/stb_vorbis.h
384
src/stb_vorbis.h
@ -1,384 +0,0 @@
|
|||||||
// Ogg Vorbis audio decoder - v1.04 - public domain
|
|
||||||
// http://nothings.org/stb_vorbis/
|
|
||||||
//
|
|
||||||
// Written by Sean Barrett in 2007, last updated in 2014
|
|
||||||
// Sponsored by RAD Game Tools.
|
|
||||||
//
|
|
||||||
// Placed in the public domain April 2007 by the author: no copyright
|
|
||||||
// is claimed, and you may use it for any purpose you like.
|
|
||||||
//
|
|
||||||
// No warranty for any purpose is expressed or implied by the author (nor
|
|
||||||
// by RAD Game Tools). Report bugs and send enhancements to the author.
|
|
||||||
//
|
|
||||||
// Limitations:
|
|
||||||
//
|
|
||||||
// - seeking not supported except manually via PUSHDATA api
|
|
||||||
// - floor 0 not supported (used in old ogg vorbis files pre-2004)
|
|
||||||
// - lossless sample-truncation at beginning ignored
|
|
||||||
// - cannot concatenate multiple vorbis streams
|
|
||||||
// - sample positions are 32-bit, limiting seekable 192Khz
|
|
||||||
// files to around 6 hours (Ogg supports 64-bit)
|
|
||||||
//
|
|
||||||
// Bugfix/warning contributors:
|
|
||||||
// Terje Mathisen Niklas Frykholm Andy Hill
|
|
||||||
// Casey Muratori John Bolton Gargaj
|
|
||||||
// Laurent Gomila Marc LeBlanc Ronny Chevalier
|
|
||||||
// Bernhard Wodo Evan Balster "alxprd"@github
|
|
||||||
// Tom Beaumont Ingo Leitgeb
|
|
||||||
// (If you reported a bug but do not appear in this list, it is because
|
|
||||||
// someone else reported the bug before you. There were too many of you to
|
|
||||||
// list them all because I was lax about updating for a long time, sorry.)
|
|
||||||
//
|
|
||||||
// Partial history:
|
|
||||||
// 1.04 - 2014/08/27 - fix missing const-correct case in API
|
|
||||||
// 1.03 - 2014/08/07 - warning fixes
|
|
||||||
// 1.02 - 2014/07/09 - declare qsort comparison as explicitly _cdecl in Windows
|
|
||||||
// 1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float (interleaved was correct)
|
|
||||||
// 1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in >2-channel;
|
|
||||||
// (API change) report sample rate for decode-full-file funcs
|
|
||||||
// 0.99996 - - bracket #include <malloc.h> for macintosh compilation
|
|
||||||
// 0.99995 - - avoid alias-optimization issue in float-to-int conversion
|
|
||||||
//
|
|
||||||
// See end of file for full version history.
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// HEADER BEGINS HERE
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef STB_VORBIS_INCLUDE_STB_VORBIS_H
|
|
||||||
#define STB_VORBIS_INCLUDE_STB_VORBIS_H
|
|
||||||
|
|
||||||
#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO)
|
|
||||||
#define STB_VORBIS_NO_STDIO 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef STB_VORBIS_NO_STDIO
|
|
||||||
#include <stdio.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// NOTE: Added to work with raylib on Android
|
|
||||||
#if defined(PLATFORM_ANDROID)
|
|
||||||
#include "utils.h" // Android fopen function map
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __linux
|
|
||||||
#include <alloca.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/////////// THREAD SAFETY
|
|
||||||
|
|
||||||
// Individual stb_vorbis* handles are not thread-safe; you cannot decode from
|
|
||||||
// them from multiple threads at the same time. However, you can have multiple
|
|
||||||
// stb_vorbis* handles and decode from them independently in multiple thrads.
|
|
||||||
|
|
||||||
|
|
||||||
/////////// MEMORY ALLOCATION
|
|
||||||
|
|
||||||
// normally stb_vorbis uses malloc() to allocate memory at startup,
|
|
||||||
// and alloca() to allocate temporary memory during a frame on the
|
|
||||||
// stack. (Memory consumption will depend on the amount of setup
|
|
||||||
// data in the file and how you set the compile flags for speed
|
|
||||||
// vs. size. In my test files the maximal-size usage is ~150KB.)
|
|
||||||
//
|
|
||||||
// You can modify the wrapper functions in the source (setup_malloc,
|
|
||||||
// setup_temp_malloc, temp_malloc) to change this behavior, or you
|
|
||||||
// can use a simpler allocation model: you pass in a buffer from
|
|
||||||
// which stb_vorbis will allocate _all_ its memory (including the
|
|
||||||
// temp memory). "open" may fail with a VORBIS_outofmem if you
|
|
||||||
// do not pass in enough data; there is no way to determine how
|
|
||||||
// much you do need except to succeed (at which point you can
|
|
||||||
// query get_info to find the exact amount required. yes I know
|
|
||||||
// this is lame).
|
|
||||||
//
|
|
||||||
// If you pass in a non-NULL buffer of the type below, allocation
|
|
||||||
// will occur from it as described above. Otherwise just pass NULL
|
|
||||||
// to use malloc()/alloca()
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
char *alloc_buffer;
|
|
||||||
int alloc_buffer_length_in_bytes;
|
|
||||||
} stb_vorbis_alloc;
|
|
||||||
|
|
||||||
|
|
||||||
/////////// FUNCTIONS USEABLE WITH ALL INPUT MODES
|
|
||||||
|
|
||||||
typedef struct stb_vorbis stb_vorbis;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
unsigned int sample_rate;
|
|
||||||
int channels;
|
|
||||||
|
|
||||||
unsigned int setup_memory_required;
|
|
||||||
unsigned int setup_temp_memory_required;
|
|
||||||
unsigned int temp_memory_required;
|
|
||||||
|
|
||||||
int max_frame_size;
|
|
||||||
} stb_vorbis_info;
|
|
||||||
|
|
||||||
// get general information about the file
|
|
||||||
extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f);
|
|
||||||
|
|
||||||
// get the last error detected (clears it, too)
|
|
||||||
extern int stb_vorbis_get_error(stb_vorbis *f);
|
|
||||||
|
|
||||||
// close an ogg vorbis file and free all memory in use
|
|
||||||
extern void stb_vorbis_close(stb_vorbis *f);
|
|
||||||
|
|
||||||
// this function returns the offset (in samples) from the beginning of the
|
|
||||||
// file that will be returned by the next decode, if it is known, or -1
|
|
||||||
// otherwise. after a flush_pushdata() call, this may take a while before
|
|
||||||
// it becomes valid again.
|
|
||||||
// NOT WORKING YET after a seek with PULLDATA API
|
|
||||||
extern int stb_vorbis_get_sample_offset(stb_vorbis *f);
|
|
||||||
|
|
||||||
// returns the current seek point within the file, or offset from the beginning
|
|
||||||
// of the memory buffer. In pushdata mode it returns 0.
|
|
||||||
extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f);
|
|
||||||
|
|
||||||
/////////// PUSHDATA API
|
|
||||||
|
|
||||||
#ifndef STB_VORBIS_NO_PUSHDATA_API
|
|
||||||
|
|
||||||
// this API allows you to get blocks of data from any source and hand
|
|
||||||
// them to stb_vorbis. you have to buffer them; stb_vorbis will tell
|
|
||||||
// you how much it used, and you have to give it the rest next time;
|
|
||||||
// and stb_vorbis may not have enough data to work with and you will
|
|
||||||
// need to give it the same data again PLUS more. Note that the Vorbis
|
|
||||||
// specification does not bound the size of an individual frame.
|
|
||||||
|
|
||||||
extern stb_vorbis *stb_vorbis_open_pushdata(
|
|
||||||
unsigned char *datablock, int datablock_length_in_bytes,
|
|
||||||
int *datablock_memory_consumed_in_bytes,
|
|
||||||
int *error,
|
|
||||||
stb_vorbis_alloc *alloc_buffer);
|
|
||||||
// create a vorbis decoder by passing in the initial data block containing
|
|
||||||
// the ogg&vorbis headers (you don't need to do parse them, just provide
|
|
||||||
// the first N bytes of the file--you're told if it's not enough, see below)
|
|
||||||
// on success, returns an stb_vorbis *, does not set error, returns the amount of
|
|
||||||
// data parsed/consumed on this call in *datablock_memory_consumed_in_bytes;
|
|
||||||
// on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed
|
|
||||||
// if returns NULL and *error is VORBIS_need_more_data, then the input block was
|
|
||||||
// incomplete and you need to pass in a larger block from the start of the file
|
|
||||||
|
|
||||||
extern int stb_vorbis_decode_frame_pushdata(
|
|
||||||
stb_vorbis *f, unsigned char *datablock, int datablock_length_in_bytes,
|
|
||||||
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
|
|
||||||
);
|
|
||||||
// decode a frame of audio sample data if possible from the passed-in data block
|
|
||||||
//
|
|
||||||
// return value: number of bytes we used from datablock
|
|
||||||
//
|
|
||||||
// possible cases:
|
|
||||||
// 0 bytes used, 0 samples output (need more data)
|
|
||||||
// N bytes used, 0 samples output (resynching the stream, keep going)
|
|
||||||
// N bytes used, M samples output (one frame of data)
|
|
||||||
// note that after opening a file, you will ALWAYS get one N-bytes,0-sample
|
|
||||||
// frame, because Vorbis always "discards" the first frame.
|
|
||||||
//
|
|
||||||
// Note that on resynch, stb_vorbis will rarely consume all of the buffer,
|
|
||||||
// instead only datablock_length_in_bytes-3 or less. This is because it wants
|
|
||||||
// to avoid missing parts of a page header if they cross a datablock boundary,
|
|
||||||
// without writing state-machiney code to record a partial detection.
|
|
||||||
//
|
|
||||||
// The number of channels returned are stored in *channels (which can be
|
|
||||||
// NULL--it is always the same as the number of channels reported by
|
|
||||||
// get_info). *output will contain an array of float* buffers, one per
|
|
||||||
// channel. In other words, (*output)[0][0] contains the first sample from
|
|
||||||
// the first channel, and (*output)[1][0] contains the first sample from
|
|
||||||
// the second channel.
|
|
||||||
|
|
||||||
extern void stb_vorbis_flush_pushdata(stb_vorbis *f);
|
|
||||||
// inform stb_vorbis that your next datablock will not be contiguous with
|
|
||||||
// previous ones (e.g. you've seeked in the data); future attempts to decode
|
|
||||||
// frames will cause stb_vorbis to resynchronize (as noted above), and
|
|
||||||
// once it sees a valid Ogg page (typically 4-8KB, as large as 64KB), it
|
|
||||||
// will begin decoding the _next_ frame.
|
|
||||||
//
|
|
||||||
// if you want to seek using pushdata, you need to seek in your file, then
|
|
||||||
// call stb_vorbis_flush_pushdata(), then start calling decoding, then once
|
|
||||||
// decoding is returning you data, call stb_vorbis_get_sample_offset, and
|
|
||||||
// if you don't like the result, seek your file again and repeat.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
////////// PULLING INPUT API
|
|
||||||
|
|
||||||
#ifndef STB_VORBIS_NO_PULLDATA_API
|
|
||||||
// This API assumes stb_vorbis is allowed to pull data from a source--
|
|
||||||
// either a block of memory containing the _entire_ vorbis stream, or a
|
|
||||||
// FILE * that you or it create, or possibly some other reading mechanism
|
|
||||||
// if you go modify the source to replace the FILE * case with some kind
|
|
||||||
// of callback to your code. (But if you don't support seeking, you may
|
|
||||||
// just want to go ahead and use pushdata.)
|
|
||||||
|
|
||||||
#if !defined(STB_VORBIS_NO_STDIO) && !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
|
|
||||||
extern int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output);
|
|
||||||
#endif
|
|
||||||
#if !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
|
|
||||||
extern int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *channels, int *sample_rate, short **output);
|
|
||||||
#endif
|
|
||||||
// decode an entire file and output the data interleaved into a malloc()ed
|
|
||||||
// buffer stored in *output. The return value is the number of samples
|
|
||||||
// decoded, or -1 if the file could not be opened or was not an ogg vorbis file.
|
|
||||||
// When you're done with it, just free() the pointer returned in *output.
|
|
||||||
|
|
||||||
extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len,
|
|
||||||
int *error, stb_vorbis_alloc *alloc_buffer);
|
|
||||||
// create an ogg vorbis decoder from an ogg vorbis stream in memory (note
|
|
||||||
// this must be the entire stream!). on failure, returns NULL and sets *error
|
|
||||||
|
|
||||||
#ifndef STB_VORBIS_NO_STDIO
|
|
||||||
extern stb_vorbis * stb_vorbis_open_filename(const char *filename,
|
|
||||||
int *error, stb_vorbis_alloc *alloc_buffer);
|
|
||||||
// create an ogg vorbis decoder from a filename via fopen(). on failure,
|
|
||||||
// returns NULL and sets *error (possibly to VORBIS_file_open_failure).
|
|
||||||
|
|
||||||
extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
|
|
||||||
int *error, stb_vorbis_alloc *alloc_buffer);
|
|
||||||
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
|
|
||||||
// the _current_ seek point (ftell). on failure, returns NULL and sets *error.
|
|
||||||
// note that stb_vorbis must "own" this stream; if you seek it in between
|
|
||||||
// calls to stb_vorbis, it will become confused. Morever, if you attempt to
|
|
||||||
// perform stb_vorbis_seek_*() operations on this file, it will assume it
|
|
||||||
// owns the _entire_ rest of the file after the start point. Use the next
|
|
||||||
// function, stb_vorbis_open_file_section(), to limit it.
|
|
||||||
|
|
||||||
extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close,
|
|
||||||
int *error, stb_vorbis_alloc *alloc_buffer, unsigned int len);
|
|
||||||
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
|
|
||||||
// the _current_ seek point (ftell); the stream will be of length 'len' bytes.
|
|
||||||
// on failure, returns NULL and sets *error. note that stb_vorbis must "own"
|
|
||||||
// this stream; if you seek it in between calls to stb_vorbis, it will become
|
|
||||||
// confused.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number);
|
|
||||||
extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number);
|
|
||||||
// NOT WORKING YET
|
|
||||||
// these functions seek in the Vorbis file to (approximately) 'sample_number'.
|
|
||||||
// after calling seek_frame(), the next call to get_frame_*() will include
|
|
||||||
// the specified sample. after calling stb_vorbis_seek(), the next call to
|
|
||||||
// stb_vorbis_get_samples_* will start with the specified sample. If you
|
|
||||||
// do not need to seek to EXACTLY the target sample when using get_samples_*,
|
|
||||||
// you can also use seek_frame().
|
|
||||||
|
|
||||||
extern void stb_vorbis_seek_start(stb_vorbis *f);
|
|
||||||
// this function is equivalent to stb_vorbis_seek(f,0), but it
|
|
||||||
// actually works
|
|
||||||
|
|
||||||
extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f);
|
|
||||||
extern float stb_vorbis_stream_length_in_seconds(stb_vorbis *f);
|
|
||||||
// these functions return the total length of the vorbis stream
|
|
||||||
|
|
||||||
extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output);
|
|
||||||
// decode the next frame and return the number of samples. the number of
|
|
||||||
// channels returned are stored in *channels (which can be NULL--it is always
|
|
||||||
// the same as the number of channels reported by get_info). *output will
|
|
||||||
// contain an array of float* buffers, one per channel. These outputs will
|
|
||||||
// be overwritten on the next call to stb_vorbis_get_frame_*.
|
|
||||||
//
|
|
||||||
// You generally should not intermix calls to stb_vorbis_get_frame_*()
|
|
||||||
// and stb_vorbis_get_samples_*(), since the latter calls the former.
|
|
||||||
|
|
||||||
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
|
|
||||||
extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts);
|
|
||||||
extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples);
|
|
||||||
#endif
|
|
||||||
// decode the next frame and return the number of samples per channel. the
|
|
||||||
// data is coerced to the number of channels you request according to the
|
|
||||||
// channel coercion rules (see below). You must pass in the size of your
|
|
||||||
// buffer(s) so that stb_vorbis will not overwrite the end of the buffer.
|
|
||||||
// The maximum buffer size needed can be gotten from get_info(); however,
|
|
||||||
// the Vorbis I specification implies an absolute maximum of 4096 samples
|
|
||||||
// per channel. Note that for interleaved data, you pass in the number of
|
|
||||||
// shorts (the size of your array), but the return value is the number of
|
|
||||||
// samples per channel, not the total number of samples.
|
|
||||||
|
|
||||||
// Channel coercion rules:
|
|
||||||
// Let M be the number of channels requested, and N the number of channels present,
|
|
||||||
// and Cn be the nth channel; let stereo L be the sum of all L and center channels,
|
|
||||||
// and stereo R be the sum of all R and center channels (channel assignment from the
|
|
||||||
// vorbis spec).
|
|
||||||
// M N output
|
|
||||||
// 1 k sum(Ck) for all k
|
|
||||||
// 2 * stereo L, stereo R
|
|
||||||
// k l k > l, the first l channels, then 0s
|
|
||||||
// k l k <= l, the first k channels
|
|
||||||
// Note that this is not _good_ surround etc. mixing at all! It's just so
|
|
||||||
// you get something useful.
|
|
||||||
|
|
||||||
extern int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats);
|
|
||||||
extern int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples);
|
|
||||||
// gets num_samples samples, not necessarily on a frame boundary--this requires
|
|
||||||
// buffering so you have to supply the buffers. DOES NOT APPLY THE COERCION RULES.
|
|
||||||
// Returns the number of samples stored per channel; it may be less than requested
|
|
||||||
// at the end of the file. If there are no more samples in the file, returns 0.
|
|
||||||
|
|
||||||
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
|
|
||||||
extern int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts);
|
|
||||||
extern int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples);
|
|
||||||
#endif
|
|
||||||
// gets num_samples samples, not necessarily on a frame boundary--this requires
|
|
||||||
// buffering so you have to supply the buffers. Applies the coercion rules above
|
|
||||||
// to produce 'channels' channels. Returns the number of samples stored per channel;
|
|
||||||
// it may be less than requested at the end of the file. If there are no more
|
|
||||||
// samples in the file, returns 0.
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//////// ERROR CODES
|
|
||||||
|
|
||||||
enum STBVorbisError
|
|
||||||
{
|
|
||||||
VORBIS__no_error,
|
|
||||||
|
|
||||||
VORBIS_need_more_data=1, // not a real error
|
|
||||||
|
|
||||||
VORBIS_invalid_api_mixing, // can't mix API modes
|
|
||||||
VORBIS_outofmem, // not enough memory
|
|
||||||
VORBIS_feature_not_supported, // uses floor 0
|
|
||||||
VORBIS_too_many_channels, // STB_VORBIS_MAX_CHANNELS is too small
|
|
||||||
VORBIS_file_open_failure, // fopen() failed
|
|
||||||
VORBIS_seek_without_length, // can't seek in unknown-length file
|
|
||||||
|
|
||||||
VORBIS_unexpected_eof=10, // file is truncated?
|
|
||||||
VORBIS_seek_invalid, // seek past EOF
|
|
||||||
|
|
||||||
// decoding errors (corrupt/invalid stream) -- you probably
|
|
||||||
// don't care about the exact details of these
|
|
||||||
|
|
||||||
// vorbis errors:
|
|
||||||
VORBIS_invalid_setup=20,
|
|
||||||
VORBIS_invalid_stream,
|
|
||||||
|
|
||||||
// ogg errors:
|
|
||||||
VORBIS_missing_capture_pattern=30,
|
|
||||||
VORBIS_invalid_stream_structure_version,
|
|
||||||
VORBIS_continued_packet_flag_invalid,
|
|
||||||
VORBIS_incorrect_stream_serial_number,
|
|
||||||
VORBIS_invalid_first_page,
|
|
||||||
VORBIS_bad_packet_type,
|
|
||||||
VORBIS_cant_find_last_page,
|
|
||||||
VORBIS_seek_failed,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // STB_VORBIS_INCLUDE_STB_VORBIS_H
|
|
||||||
//
|
|
||||||
// HEADER ENDS HERE
|
|
||||||
//
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
Loading…
Reference in New Issue
Block a user