1,7 → 1,7 |
/* |
libmpg123: MPEG Audio Decoder library |
|
copyright 1995-2009 by the mpg123 project - free software under the terms of the LGPL 2.1 |
copyright 1995-2012 by the mpg123 project - free software under the terms of the LGPL 2.1 |
see COPYING and AUTHORS files in distribution or http://mpg123.org |
|
*/ |
10,96 → 10,14 |
#include "icy2utf8.h" |
#include "debug.h" |
|
#ifdef GAPLESS |
#define SAMPLE_ADJUST(x) ((x) - ((mh->p.flags & MPG123_GAPLESS) ? mh->begin_os : 0)) |
#define SAMPLE_UNADJUST(x) ((x) + ((mh->p.flags & MPG123_GAPLESS) ? mh->begin_os : 0)) |
#else |
#define SAMPLE_ADJUST(x) (x) |
#define SAMPLE_UNADJUST(x) (x) |
#endif |
#include "gapless.h" |
|
#define SEEKFRAME(mh) ((mh)->ignoreframe < 0 ? 0 : (mh)->ignoreframe) |
|
static int initialized = 0; |
|
#define ALIGNCHECK(mh) |
#define ALIGNCHECKK |
/* On compilers that support data alignment but not the automatic stack realignment. |
We check for properly aligned stack before risking a crash because of badly compiled |
client program. */ |
#if (defined CCALIGN) && (defined NEED_ALIGNCHECK) && ((defined DEBUG) || (defined CHECK_ALIGN)) |
|
/* Common building block. */ |
#define ALIGNMAINPART \ |
/* minimum size of 16 bytes, not all compilers would align a smaller piece of data */ \ |
double ALIGNED(16) altest[2]; \ |
debug2("testing alignment, with %lu %% 16 = %lu", \ |
(unsigned long)altest, (unsigned long)((size_t)altest % 16)); \ |
if((size_t)altest % 16 != 0) |
|
#undef ALIGNCHECK |
#define ALIGNCHECK(mh) \ |
ALIGNMAINPART \ |
{ \ |
error("Stack variable is not aligned! Your combination of compiler/library is dangerous!"); \ |
if(mh != NULL) mh->err = MPG123_BAD_ALIGN; \ |
\ |
return MPG123_ERR; \ |
} |
#undef ALIGNCHECKK |
#define ALIGNCHECKK \ |
ALIGNMAINPART \ |
{ \ |
error("Stack variable is not aligned! Your combination of compiler/library is dangerous!"); \ |
return MPG123_BAD_ALIGN; \ |
} |
|
#endif |
|
#ifdef GAPLESS |
/* |
Take the buffer after a frame decode (strictly: it is the data from frame fr->num!) and cut samples out. |
fr->buffer.fill may then be smaller than before... |
*/ |
static void frame_buffercheck(mpg123_handle *fr) |
{ |
/* When we have no accurate position, gapless code does not make sense. */ |
if(!fr->accurate) return; |
|
/* The first interesting frame: Skip some leading samples. */ |
if(fr->firstoff && fr->num == fr->firstframe) |
{ |
off_t byteoff = samples_to_bytes(fr, fr->firstoff); |
if((off_t)fr->buffer.fill > byteoff) |
{ |
fr->buffer.fill -= byteoff; |
/* buffer.p != buffer.data only for own buffer */ |
debug6("cutting %li samples/%li bytes on begin, own_buffer=%i at %p=%p, buf[1]=%i", |
(long)fr->firstoff, (long)byteoff, fr->own_buffer, (void*)fr->buffer.p, (void*)fr->buffer.data, ((short*)fr->buffer.p)[2]); |
if(fr->own_buffer) fr->buffer.p = fr->buffer.data + byteoff; |
else memmove(fr->buffer.data, fr->buffer.data + byteoff, fr->buffer.fill); |
debug3("done cutting, buffer at %p =? %p, buf[1]=%i", |
(void*)fr->buffer.p, (void*)fr->buffer.data, ((short*)fr->buffer.p)[2]); |
} |
else fr->buffer.fill = 0; |
fr->firstoff = 0; /* Only enter here once... when you seek, firstoff should be reset. */ |
} |
/* The last interesting (planned) frame: Only use some leading samples. */ |
if(fr->lastoff && fr->num == fr->lastframe) |
{ |
off_t byteoff = samples_to_bytes(fr, fr->lastoff); |
if((off_t)fr->buffer.fill > byteoff) |
{ |
fr->buffer.fill = byteoff; |
} |
fr->lastoff = 0; /* Only enter here once... when you seek, lastoff should be reset. */ |
} |
} |
#endif |
|
int attribute_align_arg mpg123_init(void) |
{ |
ALIGNCHECKK |
if((sizeof(short) != 2) || (sizeof(long) < 4)) return MPG123_BAD_TYPES; |
|
if(initialized) return MPG123_OK; /* no need to initialize twice */ |
132,17 → 50,7 |
{ |
mpg123_handle *fr = NULL; |
int err = MPG123_OK; |
#if (defined CCALIGN) && (defined NEED_ALIGNCHECK) && ((defined DEBUG) || (defined CHECK_ALIGN)) |
#ifdef CCALIGN |
double ALIGNED(16) altest[4]; |
if(((size_t)altest) % 16 != 0) |
{ |
error("Stack variable is not aligned! Your combination of compiler/library is dangerous!"); |
*error = MPG123_BAD_ALIGN; |
return NULL; |
} |
#endif |
#endif |
|
if(initialized) fr = (mpg123_handle*) malloc(sizeof(mpg123_handle)); |
else err = MPG123_NOT_INITIALIZED; |
if(fr != NULL) |
159,28 → 67,8 |
} |
if(fr != NULL) |
{ |
/* Cleanup that mess! ... use mpg123_decoder / decode_update! */ |
if(frame_outbuffer(fr) != 0) |
{ |
err = MPG123_NO_BUFFERS; |
frame_exit(fr); |
free(fr); |
fr = NULL; |
} |
else |
{ |
/* I smell cleanup here... with get_next_frame() */ |
/* if(decode_update(fr) != 0) |
{ |
err = fr->err != MPG123_OK ? fr->err : MPG123_BAD_DECODER; |
frame_exit(fr); |
free(fr); |
fr = NULL; |
} |
else */ |
fr->decoder_change = 1; |
} |
} |
else if(err == MPG123_OK) err = MPG123_OUT_OF_MEM; |
|
if(error != NULL) *error = err; |
190,7 → 78,7 |
int attribute_align_arg mpg123_decoder(mpg123_handle *mh, const char* decoder) |
{ |
enum optdec dt = dectype(decoder); |
ALIGNCHECK(mh); |
|
if(mh == NULL) return MPG123_ERR; |
|
if(dt == nodec) |
217,8 → 105,7 |
frame_exit(mh); |
return MPG123_ERR; |
} |
/* I smell cleanup here... with get_next_frame() */ |
decode_update(mh); |
/* Do _not_ call decode_update here! That is only allowed after a first MPEG frame has been met. */ |
mh->decoder_change = 1; |
return MPG123_OK; |
} |
226,7 → 113,7 |
int attribute_align_arg mpg123_param(mpg123_handle *mh, enum mpg123_parms key, long val, double fval) |
{ |
int r; |
ALIGNCHECK(mh); |
|
if(mh == NULL) return MPG123_ERR; |
r = mpg123_par(&mh->p, key, val, fval); |
if(r != MPG123_OK){ mh->err = r; r = MPG123_ERR; } |
239,6 → 126,11 |
if(r != MPG123_OK) mh->err = MPG123_INDEX_FAIL; |
} |
#endif |
#ifndef NO_FEEDER |
/* Feeder pool size is applied right away, reader will react to that. */ |
if(key == MPG123_FEEDPOOL || key == MPG123_FEEDBUFFER) |
bc_poolsize(&mh->rdat.buffer, mh->p.feedpool, mh->p.feedbuffer); |
#endif |
} |
return r; |
} |
246,7 → 138,7 |
int attribute_align_arg mpg123_par(mpg123_pars *mp, enum mpg123_parms key, long val, double fval) |
{ |
int ret = MPG123_OK; |
ALIGNCHECKK |
|
if(mp == NULL) return MPG123_BAD_PARS; |
switch(key) |
{ |
313,10 → 205,10 |
mp->outscale = val == 0 ? fval : (double)val/SHORT_SCALE; |
break; |
case MPG123_TIMEOUT: |
#ifndef WIN32 |
#ifdef TIMEOUT_READ |
mp->timeout = val >= 0 ? val : 0; |
#else |
ret = MPG123_NO_TIMEOUT; |
if(val > 0) ret = MPG123_NO_TIMEOUT; |
#endif |
break; |
case MPG123_RESYNC_LIMIT: |
333,6 → 225,22 |
if(val >= 0) mp->preframes = val; |
else ret = MPG123_BAD_VALUE; |
break; |
case MPG123_FEEDPOOL: |
#ifndef NO_FEEDER |
if(val >= 0) mp->feedpool = val; |
else ret = MPG123_BAD_VALUE; |
#else |
ret = MPG123_MISSING_FEATURE; |
#endif |
break; |
case MPG123_FEEDBUFFER: |
#ifndef NO_FEEDER |
if(val > 0) mp->feedbuffer = val; |
else ret = MPG123_BAD_VALUE; |
#else |
ret = MPG123_MISSING_FEATURE; |
#endif |
break; |
default: |
ret = MPG123_BAD_PARAM; |
} |
342,7 → 250,7 |
int attribute_align_arg mpg123_getparam(mpg123_handle *mh, enum mpg123_parms key, long *val, double *fval) |
{ |
int r; |
ALIGNCHECK(mh); |
|
if(mh == NULL) return MPG123_ERR; |
r = mpg123_getpar(&mh->p, key, val, fval); |
if(r != MPG123_OK){ mh->err = r; r = MPG123_ERR; } |
352,7 → 260,7 |
int attribute_align_arg mpg123_getpar(mpg123_pars *mp, enum mpg123_parms key, long *val, double *fval) |
{ |
int ret = 0; |
ALIGNCHECKK |
|
if(mp == NULL) return MPG123_BAD_PARS; |
switch(key) |
{ |
408,6 → 316,20 |
case MPG123_PREFRAMES: |
*val = mp->preframes; |
break; |
case MPG123_FEEDPOOL: |
#ifndef NO_FEEDER |
*val = mp->feedpool; |
#else |
ret = MPG123_MISSING_FEATURE; |
#endif |
break; |
case MPG123_FEEDBUFFER: |
#ifndef NO_FEEDER |
*val = mp->feedbuffer; |
#else |
ret = MPG123_MISSING_FEATURE; |
#endif |
break; |
default: |
ret = MPG123_BAD_PARAM; |
} |
419,14 → 341,33 |
int ret = MPG123_OK; |
long theval = 0; |
double thefval = 0.; |
ALIGNCHECK(mh); |
|
if(mh == NULL) return MPG123_ERR; |
|
switch(key) |
{ |
case MPG123_ACCURATE: |
theval = mh->accurate; |
theval = mh->state_flags & FRAME_ACCURATE; |
break; |
case MPG123_FRANKENSTEIN: |
theval = mh->state_flags & FRAME_FRANKENSTEIN; |
break; |
case MPG123_BUFFERFILL: |
#ifndef NO_FEEDER |
{ |
size_t sval = bc_fill(&mh->rdat.buffer); |
theval = (long)sval; |
if((size_t)theval != sval) |
{ |
mh->err = MPG123_INT_OVERFLOW; |
ret = MPG123_ERR; |
} |
} |
#else |
mh->err = MPG123_MISSING_FEATURE; |
ret = MPG123_ERR; |
#endif |
break; |
default: |
mh->err = MPG123_BAD_KEY; |
ret = MPG123_ERR; |
440,7 → 381,6 |
|
int attribute_align_arg mpg123_eq(mpg123_handle *mh, enum mpg123_channels channel, int band, double val) |
{ |
ALIGNCHECK(mh); |
if(mh == NULL) return MPG123_ERR; |
if(band < 0 || band > 31){ mh->err = MPG123_BAD_BAND; return MPG123_ERR; } |
switch(channel) |
461,7 → 401,7 |
double attribute_align_arg mpg123_geteq(mpg123_handle *mh, enum mpg123_channels channel, int band) |
{ |
double ret = 0.; |
ALIGNCHECK(mh); |
|
if(mh == NULL) return MPG123_ERR; |
|
/* Handle this gracefully. When there is no band, it has no volume. */ |
483,31 → 423,38 |
/* plain file access, no http! */ |
int attribute_align_arg mpg123_open(mpg123_handle *mh, const char *path) |
{ |
ALIGNCHECK(mh); |
if(mh == NULL) return MPG123_ERR; |
|
mpg123_close(mh); |
frame_reset(mh); |
return open_stream(mh, path, -1); |
} |
|
int attribute_align_arg mpg123_open_fd(mpg123_handle *mh, int fd) |
{ |
ALIGNCHECK(mh); |
if(mh == NULL) return MPG123_ERR; |
|
mpg123_close(mh); |
frame_reset(mh); |
return open_stream(mh, NULL, fd); |
} |
|
int attribute_align_arg mpg123_open_handle(mpg123_handle *mh, void *iohandle) |
{ |
if(mh == NULL) return MPG123_ERR; |
|
mpg123_close(mh); |
if(mh->rdat.r_read_handle == NULL) |
{ |
mh->err = MPG123_BAD_CUSTOM_IO; |
return MPG123_ERR; |
} |
return open_stream_handle(mh, iohandle); |
} |
|
int attribute_align_arg mpg123_open_feed(mpg123_handle *mh) |
{ |
ALIGNCHECK(mh); |
if(mh == NULL) return MPG123_ERR; |
|
mpg123_close(mh); |
frame_reset(mh); |
return open_feed(mh); |
} |
|
515,19 → 462,45 |
ssize_t (*r_read) (int, void *, size_t), |
off_t (*r_lseek)(int, off_t, int) ) |
{ |
ALIGNCHECK(mh); |
if(mh == NULL) return MPG123_ERR; |
|
mpg123_close(mh); |
mh->rdat.r_read = r_read; |
mh->rdat.r_lseek = r_lseek; |
return MPG123_OK; |
} |
|
int attribute_align_arg mpg123_replace_reader_handle( mpg123_handle *mh, |
ssize_t (*r_read) (void*, void *, size_t), |
off_t (*r_lseek)(void*, off_t, int), |
void (*cleanup)(void*) ) |
{ |
if(mh == NULL) return MPG123_ERR; |
|
mpg123_close(mh); |
mh->rdat.r_read_handle = r_read; |
mh->rdat.r_lseek_handle = r_lseek; |
mh->rdat.cleanup_handle = cleanup; |
return MPG123_OK; |
} |
|
/* Update decoding engine for |
a) a new choice of decoder |
b) a changed native format of the MPEG stream |
... calls are only valid after parsing some MPEG frame! */ |
int decode_update(mpg123_handle *mh) |
{ |
long native_rate; |
int b; |
ALIGNCHECK(mh); |
|
if(mh->num < 0) |
{ |
if(!(mh->p.flags & MPG123_QUIET)) error("decode_update() has been called before reading the first MPEG frame! Internal programming error."); |
|
mh->err = MPG123_BAD_DECODER_SETUP; |
return MPG123_ERR; |
} |
|
native_rate = frame_freq(mh); |
|
b = frame_output_format(mh); /* Select the new output format based on given constraints. */ |
547,7 → 520,7 |
case 2: |
mh->down_sample_sblimit = SBLIMIT>>(mh->down_sample); |
/* With downsampling I get less samples per frame */ |
mh->outblock = samples_to_bytes(mh, (spf(mh)>>mh->down_sample)); |
mh->outblock = samples_to_storage(mh, (spf(mh)>>mh->down_sample)); |
break; |
#ifndef NO_NTOM |
case 3: |
559,10 → 532,10 |
mh->down_sample_sblimit /= frame_freq(mh); |
} |
else mh->down_sample_sblimit = SBLIMIT; |
mh->outblock = mh->af.encsize * mh->af.channels * |
mh->outblock = samples_to_storage(mh, |
( ( NTOM_MUL-1+spf(mh) |
* (((size_t)NTOM_MUL*mh->af.rate)/frame_freq(mh)) |
)/NTOM_MUL ); |
)/NTOM_MUL )); |
} |
break; |
#endif |
576,6 → 549,9 |
else mh->single = (mh->p.flags & MPG123_FORCE_MONO)-1; |
if(set_synth_functions(mh) != 0) return -1;; |
|
/* The needed size of output buffer may have changed. */ |
if(frame_outbuffer(mh) != MPG123_OK) return -1; |
|
do_rva(mh); |
debug3("done updating decoder structure with native rate %li and af.rate %li and down_sample %i", frame_freq(mh), mh->af.rate, mh->down_sample); |
|
582,7 → 558,7 |
return 0; |
} |
|
size_t attribute_align_arg mpg123_safe_buffer() |
size_t attribute_align_arg mpg123_safe_buffer(void) |
{ |
/* real is the largest possible output (it's 32bit float, 32bit int or 64bit double). */ |
return sizeof(real)*2*1152*NTOM_MAX; |
590,12 → 566,18 |
|
size_t attribute_align_arg mpg123_outblock(mpg123_handle *mh) |
{ |
if(mh != NULL) return mh->outblock; |
/* Try to be helpful and never return zero output block size. */ |
if(mh != NULL && mh->outblock > 0) return mh->outblock; |
else return mpg123_safe_buffer(); |
} |
|
/* Read in the next frame we actually want for decoding. |
This includes skipping/ignoring frames, in additon to skipping junk in the parser. */ |
static int get_next_frame(mpg123_handle *mh) |
{ |
/* We have some decoder ready, if the desired decoder has changed, |
it is OK to use the old one for ignoring frames and activating |
the new one for real (decode_update()) after getting the frame. */ |
int change = mh->decoder_change; |
do |
{ |
621,7 → 603,7 |
else if(b <= 0) |
{ |
/* More sophisticated error control? */ |
if(b==0 || mh->rdat.filepos == mh->rdat.filelen) |
if(b==0 || (mh->rdat.filelen >= 0 && mh->rdat.filepos == mh->rdat.filelen)) |
{ /* We simply reached the end. */ |
mh->track_frames = mh->num + 1; |
debug("What about updating/checking gapless sample count here?"); |
650,13 → 632,9 |
/* Or, we are finally done and have a new frame. */ |
else break; |
} while(1); |
/* When we start actually using the CRC, this could move into the loop... */ |
/* A question of semantics ... should I fold start_frame and frame_number into firstframe/lastframe? */ |
if(mh->lastframe >= 0 && mh->num > mh->lastframe) |
{ |
mh->to_decode = mh->to_ignore = FALSE; |
return MPG123_DONE; |
} |
|
/* If we reach this point, we got a new frame ready to be decoded. |
All other situations resulted in returns from the loop. */ |
if(change) |
{ |
if(decode_update(mh) < 0) /* dito... */ |
665,25 → 643,28 |
debug1("new format: %i", mh->new_format); |
|
mh->decoder_change = 0; |
#ifdef GAPLESS |
if(mh->fresh) |
{ |
#ifdef GAPLESS |
int b=0; |
/* Prepare offsets for gapless decoding. */ |
debug1("preparing gapless stuff with native rate %li", frame_freq(mh)); |
frame_gapless_realinit(mh); |
frame_set_frameseek(mh, mh->num); |
#endif |
mh->fresh = 0; |
#ifdef GAPLESS |
/* Could this possibly happen? With a real big gapless offset... */ |
if(mh->num < mh->firstframe) b = get_next_frame(mh); |
if(b < 0) return b; /* Could be error, need for more, new format... */ |
} |
#endif |
} |
} |
return MPG123_OK; |
} |
|
/* Assumption: A buffer full of zero samples can be constructed by repetition of this byte. |
Oh, and it handles some format conversion. |
Only to be used by decode_the_frame() ... */ |
static int zero_byte(mpg123_handle *fr) |
{ |
698,9 → 679,9 |
Not part of the api. This just decodes the frame and fills missing bits with zeroes. |
There can be frames that are broken and thus make do_layer() fail. |
*/ |
void decode_the_frame(mpg123_handle *fr) |
static void decode_the_frame(mpg123_handle *fr) |
{ |
size_t needed_bytes = samples_to_bytes(fr, frame_outs(fr, fr->num+1)-frame_outs(fr, fr->num)); |
size_t needed_bytes = samples_to_storage(fr, frame_expect_outsamples(fr)); |
fr->clip += (fr->do_layer)(fr); |
/*fprintf(stderr, "frame %"OFF_P": got %"SIZE_P" / %"SIZE_P"\n", fr->num,(size_p)fr->buffer.fill, (size_p)needed_bytes);*/ |
/* There could be less data than promised. |
736,48 → 717,77 |
} |
} |
#endif |
/* Handle unsigned output formats via reshifting after decode here. */ |
#ifndef NO_32BIT |
if(fr->af.encoding == MPG123_ENC_UNSIGNED_32) |
{ /* 32bit signed -> unsigned */ |
size_t i; |
int32_t *ssamples; |
uint32_t *usamples; |
ssamples = (int32_t*)fr->buffer.data; |
usamples = (uint32_t*)fr->buffer.data; |
debug("converting output to unsigned 32 bit integer"); |
for(i=0; i<fr->buffer.fill/sizeof(int32_t); ++i) |
postprocess_buffer(fr); |
} |
|
/* |
Decode the current frame into the frame structure's buffer, accessible at the location stored in <audio>, with <bytes> bytes available. |
<num> will contain the last decoded frame number. This function should be called after mpg123_framebyframe_next positioned the stream at a |
valid mp3 frame. The buffer contents will get lost on the next call to mpg123_framebyframe_next or mpg123_framebyframe_decode. |
returns |
MPG123_OK -- successfully decoded or ignored the frame, you get your output data or in case of ignored frames 0 bytes |
MPG123_DONE -- decoding finished, should not happen |
MPG123_ERR -- some error occured. |
MPG123_ERR_NULL -- audio or bytes are not pointing to valid storage addresses |
MPG123_BAD_HANDLE -- mh has not been initialized |
MPG123_NO_SPACE -- not enough space in buffer for safe decoding, should not happen |
*/ |
int attribute_align_arg mpg123_framebyframe_decode(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes) |
{ |
/* Different strategy since we don't have a larger type at hand. |
Also watch out for silly +-1 fun because integer constants are signed in C90! */ |
if(ssamples[i] >= 0) |
usamples[i] = (uint32_t)ssamples[i] + 2147483647+1; |
/* The smalles value goes zero. */ |
else if(ssamples[i] == ((int32_t)-2147483647-1)) |
usamples[i] = 0; |
/* Now -value is in the positive range of signed int ... so it's a possible value at all. */ |
else |
usamples[i] = (uint32_t)2147483647+1 - (uint32_t)(-ssamples[i]); |
if(bytes == NULL) return MPG123_ERR_NULL; |
if(audio == NULL) return MPG123_ERR_NULL; |
if(mh == NULL) return MPG123_BAD_HANDLE; |
if(mh->buffer.size < mh->outblock) return MPG123_NO_SPACE; |
|
*bytes = 0; |
mh->buffer.fill = 0; /* always start fresh */ |
if(!mh->to_decode) return MPG123_OK; |
|
if(num != NULL) *num = mh->num; |
debug("decoding"); |
decode_the_frame(mh); |
mh->to_decode = mh->to_ignore = FALSE; |
mh->buffer.p = mh->buffer.data; |
FRAME_BUFFERCHECK(mh); |
*audio = mh->buffer.p; |
*bytes = mh->buffer.fill; |
return MPG123_OK; |
} |
} |
#endif |
#ifndef NO_16BIT |
if(fr->af.encoding == MPG123_ENC_UNSIGNED_16) |
|
/* |
Find, read and parse the next mp3 frame while skipping junk and parsing id3 tags, lame headers, etc. |
Prepares everything for decoding using mpg123_framebyframe_decode. |
returns |
MPG123_OK -- new frame was read and parsed, call mpg123_framebyframe_decode to actually decode |
MPG123_NEW_FORMAT -- new frame was read, it results in changed output format, call mpg123_framebyframe_decode to actually decode |
MPG123_BAD_HANDLE -- mh has not been initialized |
MPG123_NEED_MORE -- more input data is needed to advance to the next frame. supply more input data using mpg123_feed |
*/ |
int attribute_align_arg mpg123_framebyframe_next(mpg123_handle *mh) |
{ |
size_t i; |
short *ssamples; |
unsigned short *usamples; |
ssamples = (short*)fr->buffer.data; |
usamples = (unsigned short*)fr->buffer.data; |
debug("converting output to unsigned 16 bit integer"); |
for(i=0; i<fr->buffer.fill/sizeof(short); ++i) |
int b; |
if(mh == NULL) return MPG123_BAD_HANDLE; |
|
mh->to_decode = mh->to_ignore = FALSE; |
mh->buffer.fill = 0; |
|
b = get_next_frame(mh); |
if(b < 0) return b; |
debug1("got next frame, %i", mh->to_decode); |
|
/* mpg123_framebyframe_decode will return MPG123_OK with 0 bytes decoded if mh->to_decode is 0 */ |
if(!mh->to_decode) |
return MPG123_OK; |
|
if(mh->new_format) |
{ |
long tmp = (long)ssamples[i]+32768; |
usamples[i] = (unsigned short)tmp; |
debug("notifiying new format"); |
mh->new_format = 0; |
return MPG123_NEW_FORMAT; |
} |
|
return MPG123_OK; |
} |
#endif |
} |
|
/* |
Put _one_ decoded frame into the frame structure's buffer, accessible at the location stored in <audio>, with <bytes> bytes available. |
793,7 → 803,6 |
*/ |
int attribute_align_arg mpg123_decode_frame(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes) |
{ |
ALIGNCHECK(mh); |
if(bytes != NULL) *bytes = 0; |
if(mh == NULL) return MPG123_ERR; |
if(mh->buffer.size < mh->outblock) return MPG123_NO_SPACE; |
816,10 → 825,7 |
|
mh->to_decode = mh->to_ignore = FALSE; |
mh->buffer.p = mh->buffer.data; |
#ifdef GAPLESS |
/* This checks for individual samples to skip, for gapless mode or sample-accurate seek. */ |
frame_buffercheck(mh); |
#endif |
FRAME_BUFFERCHECK(mh); |
if(audio != NULL) *audio = mh->buffer.p; |
if(bytes != NULL) *bytes = mh->buffer.fill; |
|
842,13 → 848,21 |
int attribute_align_arg mpg123_feed(mpg123_handle *mh, const unsigned char *in, size_t size) |
{ |
if(mh == NULL) return MPG123_ERR; |
#ifndef NO_FEEDER |
if(size > 0) |
{ |
if(in != NULL) |
{ |
if(feed_more(mh, in, size) != 0) return MPG123_ERR; |
else return MPG123_OK; |
else |
{ |
/* The need for more data might have triggered an error. |
This one is outdated now with the new data. */ |
if(mh->err == MPG123_ERR_READER) mh->err = MPG123_OK; |
|
return MPG123_OK; |
} |
} |
else |
{ |
mh->err = MPG123_NULL_BUFFER; |
856,6 → 870,10 |
} |
} |
return MPG123_OK; |
#else |
mh->err = MPG123_MISSING_FEATURE; |
return MPG123_ERR; |
#endif |
} |
|
/* |
876,9 → 894,10 |
{ |
int ret = MPG123_OK; |
size_t mdone = 0; |
ALIGNCHECK(mh); |
|
if(done != NULL) *done = 0; |
if(mh == NULL) return MPG123_ERR; |
#ifndef NO_FEEDER |
if(inmemsize > 0 && mpg123_feed(mh, inmemory, inmemsize) != MPG123_OK) |
{ |
ret = MPG123_ERR; |
897,7 → 916,8 |
{ |
debug("notifiying new format"); |
mh->new_format = 0; |
return MPG123_NEW_FORMAT; |
ret = MPG123_NEW_FORMAT; |
goto decodeend; |
} |
if(mh->buffer.size - mh->buffer.fill < mh->outblock) |
{ |
908,9 → 928,7 |
mh->to_decode = mh->to_ignore = FALSE; |
mh->buffer.p = mh->buffer.data; |
debug2("decoded frame %li, got %li samples in buffer", (long)mh->num, (long)(mh->buffer.fill / (samples_to_bytes(mh, 1)))); |
#ifdef GAPLESS |
frame_buffercheck(mh); /* Seek & gapless. */ |
#endif |
FRAME_BUFFERCHECK(mh); |
} |
if(mh->buffer.fill) /* Copy (part of) the decoded data to the caller's buffer. */ |
{ |
934,12 → 952,16 |
decodeend: |
if(done != NULL) *done = mdone; |
return ret; |
#else |
mh->err = MPG123_MISSING_FEATURE; |
return MPG123_ERR; |
#endif |
} |
|
long attribute_align_arg mpg123_clip(mpg123_handle *mh) |
{ |
long ret = 0; |
ALIGNCHECK(mh); |
|
if(mh != NULL) |
{ |
ret = mh->clip; |
948,7 → 970,8 |
return ret; |
} |
|
#define track_need_init(mh) (!(mh)->to_decode && (mh)->fresh) |
/* Simples: Track needs initializtion if no initial frame has been read yet. */ |
#define track_need_init(mh) ((mh)->num < 0) |
|
static int init_track(mpg123_handle *mh) |
{ |
963,9 → 986,11 |
|
int attribute_align_arg mpg123_getformat(mpg123_handle *mh, long *rate, int *channels, int *encoding) |
{ |
ALIGNCHECK(mh); |
int b; |
|
if(mh == NULL) return MPG123_ERR; |
if(init_track(mh) == MPG123_ERR) return MPG123_ERR; |
b = init_track(mh); |
if(b < 0) return b; |
|
if(rate != NULL) *rate = mh->af.rate; |
if(channels != NULL) *channels = mh->af.channels; |
977,7 → 1002,7 |
off_t attribute_align_arg mpg123_timeframe(mpg123_handle *mh, double seconds) |
{ |
off_t b; |
ALIGNCHECK(mh); |
|
if(mh == NULL) return MPG123_ERR; |
b = init_track(mh); |
if(b<0) return b; |
994,7 → 1019,6 |
*/ |
off_t attribute_align_arg mpg123_tell(mpg123_handle *mh) |
{ |
ALIGNCHECK(mh); |
if(mh == NULL) return MPG123_ERR; |
if(track_need_init(mh)) return 0; |
/* Now we have all the info at hand. */ |
1018,7 → 1042,7 |
pos = frame_outs(mh, mh->num+1) - bytes_to_samples(mh, mh->buffer.fill); |
} |
/* Substract padding and delay from the beginning. */ |
pos = SAMPLE_ADJUST(pos); |
pos = SAMPLE_ADJUST(mh,pos); |
/* Negative sample offsets are not right, less than nothing is still nothing. */ |
return pos>0 ? pos : 0; |
} |
1026,7 → 1050,6 |
|
off_t attribute_align_arg mpg123_tellframe(mpg123_handle *mh) |
{ |
ALIGNCHECK(mh); |
if(mh == NULL) return MPG123_ERR; |
if(mh->num < mh->firstframe) return mh->firstframe; |
if(mh->to_decode) return mh->num; |
1036,7 → 1059,6 |
|
off_t attribute_align_arg mpg123_tell_stream(mpg123_handle *mh) |
{ |
ALIGNCHECK(mh); |
if(mh == NULL) return MPG123_ERR; |
/* mh->rd is at least a bad_reader, so no worry. */ |
return mh->rd->tell(mh); |
1070,7 → 1092,7 |
if(mh->down_sample == 3) |
{ |
ntom_set_ntom(mh, fnum); |
debug3("fixed ntom for frame %"OFF_P" to %lu, num=%"OFF_P, fnum, mh->ntom_val[0], mh->num); |
debug3("fixed ntom for frame %"OFF_P" to %lu, num=%"OFF_P, (off_p)fnum, mh->ntom_val[0], (off_p)mh->num); |
} |
#endif |
b = mh->rd->seek_frame(mh, fnum); |
1087,7 → 1109,7 |
{ |
int b; |
off_t pos; |
ALIGNCHECK(mh); |
|
pos = mpg123_tell(mh); /* adjusted samples */ |
/* pos < 0 also can mean that simply a former seek failed at the lower levels. |
In that case, we only allow absolute seeks. */ |
1105,10 → 1127,9 |
/* When we do not know the end already, we can try to find it. */ |
if(mh->track_frames < 1 && (mh->rdat.flags & READER_SEEKABLE)) |
mpg123_scan(mh); |
if(mh->track_frames > 0) pos = SAMPLE_ADJUST(mh,frame_outs(mh, mh->track_frames)) - sampleoff; |
#ifdef GAPLESS |
if(mh->end_os > 0) pos = SAMPLE_ADJUST(mh->end_os) - sampleoff; |
#else |
if(mh->track_frames > 0) pos = SAMPLE_ADJUST(frame_outs(mh, mh->track_frames)) - sampleoff; |
else if(mh->end_os > 0) pos = SAMPLE_ADJUST(mh,mh->end_os) - sampleoff; |
#endif |
else |
{ |
1120,7 → 1141,7 |
} |
if(pos < 0) pos = 0; |
/* pos now holds the wanted sample offset in adjusted samples */ |
frame_set_seek(mh, SAMPLE_UNADJUST(pos)); |
frame_set_seek(mh, SAMPLE_UNADJUST(mh,pos)); |
pos = do_the_seek(mh); |
if(pos < 0) return pos; |
|
1137,11 → 1158,12 |
{ |
int b; |
off_t pos; |
ALIGNCHECK(mh); |
|
pos = mpg123_tell(mh); /* adjusted samples */ |
debug3("seek from %li to %li (whence=%i)", (long)pos, (long)sampleoff, whence); |
/* The special seek error handling does not apply here... there is no lowlevel I/O. */ |
if(pos < 0) return pos; /* mh == NULL is covered in mpg123_tell() */ |
#ifndef NO_FEEDER |
if(input_offset == NULL) |
{ |
mh->err = MPG123_NULL_POINTER; |
1155,10 → 1177,9 |
case SEEK_CUR: pos += sampleoff; break; |
case SEEK_SET: pos = sampleoff; break; |
case SEEK_END: |
if(mh->track_frames > 0) pos = SAMPLE_ADJUST(mh,frame_outs(mh, mh->track_frames)) - sampleoff; |
#ifdef GAPLESS |
if(mh->end_os >= 0) pos = SAMPLE_ADJUST(mh->end_os) - sampleoff; |
#else |
if(mh->track_frames > 0) pos = SAMPLE_ADJUST(frame_outs(mh, mh->track_frames)) - sampleoff; |
else if(mh->end_os >= 0) pos = SAMPLE_ADJUST(mh,mh->end_os) - sampleoff; |
#endif |
else |
{ |
1169,7 → 1190,7 |
default: mh->err = MPG123_BAD_WHENCE; return MPG123_ERR; |
} |
if(pos < 0) pos = 0; |
frame_set_seek(mh, SAMPLE_UNADJUST(pos)); |
frame_set_seek(mh, SAMPLE_UNADJUST(mh,pos)); |
pos = SEEKFRAME(mh); |
mh->buffer.fill = 0; |
|
1185,6 → 1206,10 |
|
feedseekend: |
return mpg123_tell(mh); |
#else |
mh->err = MPG123_MISSING_FEATURE; |
return MPG123_ERR; |
#endif |
} |
|
off_t attribute_align_arg mpg123_seek_frame(mpg123_handle *mh, off_t offset, int whence) |
1191,7 → 1216,7 |
{ |
int b; |
off_t pos = 0; |
ALIGNCHECK(mh); |
|
if(mh == NULL) return MPG123_ERR; |
if((b=init_track(mh)) < 0) return b; |
|
1214,8 → 1239,7 |
return MPG123_ERR; |
} |
if(pos < 0) pos = 0; |
/* Hm, do we need to seek right past the end? */ |
else if(mh->track_frames > 0 && pos >= mh->track_frames) pos = mh->track_frames; |
/* Not limiting the possible position on end for the chance that there might be more to the stream than announced via track_frames. */ |
|
frame_set_frameseek(mh, pos); |
pos = do_the_seek(mh); |
1226,7 → 1250,6 |
|
int attribute_align_arg mpg123_set_filesize(mpg123_handle *mh, off_t size) |
{ |
ALIGNCHECK(mh); |
if(mh == NULL) return MPG123_ERR; |
|
mh->rdat.filelen = size; |
1237,7 → 1260,7 |
{ |
int b; |
off_t length; |
ALIGNCHECK(mh); |
|
if(mh == NULL) return MPG123_ERR; |
b = init_track(mh); |
if(b<0) return b; |
1252,11 → 1275,11 |
else if(mh->rdat.filelen == 0) return mpg123_tell(mh); /* we could be in feeder mode */ |
else return MPG123_ERR; /* No length info there! */ |
|
debug1("mpg123_length: internal sample length: %"OFF_P, (off_p)length); |
|
length = frame_ins2outs(mh, length); |
#ifdef GAPLESS |
if(mh->end_os > 0 && length > mh->end_os) length = mh->end_os; |
length -= mh->begin_os; |
#endif |
debug1("mpg123_length: external sample length: %"OFF_P, (off_p)length); |
length = SAMPLE_ADJUST(mh,length); |
return length; |
} |
|
1263,9 → 1286,10 |
int attribute_align_arg mpg123_scan(mpg123_handle *mh) |
{ |
int b; |
off_t backframe; |
int to_decode, to_ignore; |
ALIGNCHECK(mh); |
off_t oldpos; |
off_t track_frames = 0; |
off_t track_samples = 0; |
|
if(mh == NULL) return MPG123_ERR; |
if(!(mh->rdat.flags & READER_SEEKABLE)){ mh->err = MPG123_NO_SEEK; return MPG123_ERR; } |
/* Scan through the _whole_ file, since the current position is no count but computed assuming constant samples per frame. */ |
1277,28 → 1301,28 |
if(b == MPG123_DONE) return MPG123_OK; |
else return MPG123_ERR; /* Must be error here, NEED_MORE is not for seekable streams. */ |
} |
backframe = mh->num; |
to_decode = mh->to_decode; |
to_ignore = mh->to_ignore; |
oldpos = mpg123_tell(mh); |
b = mh->rd->seek_frame(mh, 0); |
if(b<0 || mh->num != 0) return MPG123_ERR; |
/* One frame must be there now. */ |
mh->track_frames = 1; |
mh->track_samples = spf(mh); /* Internal samples. */ |
track_frames = 1; |
track_samples = spf(mh); /* Internal samples. */ |
debug("TODO: We should disable gapless code when encountering inconsistent spf(mh)!"); |
/* Do not increment mh->track_frames in the loop as tha would confuse Frankenstein detection. */ |
while(read_frame(mh) == 1) |
{ |
++mh->track_frames; |
mh->track_samples += spf(mh); |
++track_frames; |
track_samples += spf(mh); |
} |
mh->track_frames = track_frames; |
mh->track_samples = track_samples; |
mpg123_seek_frame(mh, SEEK_SET, mh->track_frames); |
debug2("Scanning yielded %"OFF_P" track samples, %"OFF_P" frames.", (off_p)mh->track_samples, (off_p)mh->track_frames); |
#ifdef GAPLESS |
/* Also, think about usefulness of that extra value track_samples ... it could be used for consistency checking. */ |
frame_gapless_update(mh, mh->track_samples); |
#endif |
b = mh->rd->seek_frame(mh, backframe); |
if(b<0 || mh->num != backframe) return MPG123_ERR; |
mh->to_decode = to_decode; |
mh->to_ignore = to_ignore; |
return MPG123_OK; |
return mpg123_seek(mh, oldpos, SEEK_SET) >= 0 ? MPG123_OK : MPG123_ERR; |
} |
|
int attribute_align_arg mpg123_meta_check(mpg123_handle *mh) |
1307,9 → 1331,16 |
else return 0; |
} |
|
void attribute_align_arg mpg123_meta_free(mpg123_handle *mh) |
{ |
if(mh == NULL) return; |
|
reset_id3(mh); |
reset_icy(&mh->icy); |
} |
|
int attribute_align_arg mpg123_id3(mpg123_handle *mh, mpg123_id3v1 **v1, mpg123_id3v2 **v2) |
{ |
ALIGNCHECK(mh); |
if(v1 != NULL) *v1 = NULL; |
if(v2 != NULL) *v2 = NULL; |
if(mh == NULL) return MPG123_ERR; |
1333,7 → 1364,6 |
|
int attribute_align_arg mpg123_icy(mpg123_handle *mh, char **icy_meta) |
{ |
ALIGNCHECK(mh); |
if(mh == NULL) return MPG123_ERR; |
#ifndef NO_ICY |
if(icy_meta == NULL) |
1356,11 → 1386,6 |
#endif |
} |
|
/* |
Simple utility functions that do not possibly call code with extra alignment requirements do not use the ALIGNCHECK. |
I am aware of the chance that the compiler could have introduced such code outside assembly functions, but such a modern compiler (gcc) can also honour attribute_align_arg. |
*/ |
|
char* attribute_align_arg mpg123_icy2utf8(const char* icy_text) |
{ |
#ifndef NO_ICY |
1435,7 → 1460,6 |
|
int attribute_align_arg mpg123_index(mpg123_handle *mh, off_t **offsets, off_t *step, size_t *fill) |
{ |
ALIGNCHECK(mh); |
if(mh == NULL) return MPG123_ERR; |
if(offsets == NULL || step == NULL || fill == NULL) |
{ |
1454,12 → 1478,34 |
return MPG123_OK; |
} |
|
int attribute_align_arg mpg123_set_index(mpg123_handle *mh, off_t *offsets, off_t step, size_t fill) |
{ |
if(mh == NULL) return MPG123_ERR; |
#ifdef FRAME_INDEX |
if(step == 0) |
{ |
mh->err = MPG123_BAD_INDEX_PAR; |
return MPG123_ERR; |
} |
if(fi_set(&mh->index, offsets, step, fill) == -1) |
{ |
mh->err = MPG123_OUT_OF_MEM; |
return MPG123_ERR; |
} |
return MPG123_OK; |
#else |
mh->err = MPG123_MISSING_FEATURE; |
return MPG123_ERR; |
#endif |
} |
|
int attribute_align_arg mpg123_close(mpg123_handle *mh) |
{ |
ALIGNCHECK(mh); |
if(mh == NULL) return MPG123_ERR; |
if(mh->rd != NULL && mh->rd->close != NULL) mh->rd->close(mh); |
mh->rd = NULL; |
|
/* mh->rd is never NULL! */ |
if(mh->rd->close != NULL) mh->rd->close(mh); |
|
if(mh->new_format) |
{ |
debug("Hey, we are closing a track before the new format has been queried..."); |
1466,6 → 1512,8 |
invalidate_format(&mh->af); |
mh->new_format = 0; |
} |
/* Always reset the frame buffers on close, so we cannot forget it in funky opening routines (wrappers, even). */ |
frame_reset(mh); |
return MPG123_OK; |
} |
|
1522,6 → 1570,9 |
"Feature not in this build." |
,"Some bad value has been provided." |
,"Low-level seeking has failed (call to lseek(), usually)." |
,"Custom I/O obviously not prepared." |
,"Overflow in LFS (large file support) conversion." |
,"Overflow in integer conversion." |
}; |
|
const char* attribute_align_arg mpg123_plain_strerror(int errcode) |