Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 3959 → Rev 3960

/programs/develop/libraries/libmpg123/frame.c
1,7 → 1,7
/*
frame: Heap of routines dealing with the core mpg123 data structure.
 
copyright 2008-9 by the mpg123 project - free software under the terms of the LGPL 2.1
copyright 2008-2010 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
initially written by Thomas Orgis
*/
14,18 → 14,33
 
/* that's doubled in decode_ntom.c */
#define NTOM_MUL (32768)
#define aligned_pointer(p,type,alignment) \
(((char*)(p)-(char*)NULL) % (alignment)) \
? (type*)((char*)(p) + (alignment) - (((char*)(p)-(char*)NULL) % (alignment))) \
: (type*)(p)
void frame_default_pars(mpg123_pars *mp)
 
#define aligned_pointer(p, type, alignment) align_the_pointer(p, alignment)
static void *align_the_pointer(void *base, unsigned int alignment)
{
/*
Work in unsigned integer realm, explicitly.
Tricking the compiler into integer operations like % by invoking base-NULL is dangerous: It results into ptrdiff_t, which gets negative on big addresses. Big screw up, that.
I try to do it "properly" here: Casting only to uintptr_t and no artihmethic with void*.
*/
uintptr_t baseval = (uintptr_t)(char*)base;
uintptr_t aoff = baseval % alignment;
 
debug3("align_the_pointer: pointer %p is off by %u from %u",
base, (unsigned int)aoff, alignment);
 
if(aoff) return (char*)base+alignment-aoff;
else return base;
}
 
static void frame_default_pars(mpg123_pars *mp)
{
mp->outscale = 1.0;
mp->flags = 0;
#ifdef GAPLESS
mp->flags = MPG123_GAPLESS;
#else
mp->flags = 0;
mp->flags |= MPG123_GAPLESS;
#endif
mp->flags |= MPG123_AUTO_RESAMPLE;
#ifndef NO_NTOM
mp->force_rate = 0;
#endif
37,9 → 52,7
#ifndef NO_ICY
mp->icy_interval = 0;
#endif
#ifndef WIN32
mp->timeout = 0;
#endif
mp->resync_limit = 1024;
#ifdef FRAME_INDEX
mp->index_size = INDEX_SIZE;
46,6 → 59,11
#endif
mp->preframes = 4; /* That's good for layer 3 ISO compliance bitstream. */
mpg123_fmt_all(mp);
/* Default of keeping some 4K buffers at hand, should cover the "usual" use case (using 16K pipe buffers as role model). */
#ifndef NO_FEEDER
mp->feedpool = 5;
mp->feedbuffer = 4096;
#endif
}
 
void frame_init(mpg123_handle *fr)
55,8 → 73,11
 
void frame_init_par(mpg123_handle *fr, mpg123_pars *mp)
{
fr->own_buffer = FALSE;
fr->own_buffer = TRUE;
fr->buffer.data = NULL;
fr->buffer.rdata = NULL;
fr->buffer.fill = 0;
fr->buffer.size = 0;
fr->rawbuffs = NULL;
fr->rawbuffss = 0;
fr->rawdecwin = NULL;
67,6 → 88,7
#ifdef OPT_DITHER
fr->dithernoise = NULL;
#endif
fr->layerscratch = NULL;
fr->xing_toc = NULL;
fr->cpu_opts.type = defdec();
fr->cpu_opts.class = decclass(fr->cpu_opts.type);
86,11 → 108,21
invalidate_format(&fr->af);
fr->rdat.r_read = NULL;
fr->rdat.r_lseek = NULL;
fr->rdat.iohandle = NULL;
fr->rdat.r_read_handle = NULL;
fr->rdat.r_lseek_handle = NULL;
fr->rdat.cleanup_handle = NULL;
fr->wrapperdata = NULL;
fr->wrapperclean = NULL;
fr->decoder_change = 1;
fr->err = MPG123_OK;
if(mp == NULL) frame_default_pars(&fr->p);
else memcpy(&fr->p, mp, sizeof(struct mpg123_pars_struct));
 
#ifndef NO_FEEDER
bc_prepare(&fr->rdat.buffer, fr->p.feedpool, fr->p.feedbuffer);
#endif
 
fr->down_sample = 0; /* Initialize to silence harmless errors when debugging. */
frame_fixed_reset(fr); /* Reset only the fixed data, dynamic buffers are not there yet! */
fr->synth = NULL;
143,34 → 175,51
 
int frame_outbuffer(mpg123_handle *fr)
{
size_t size = mpg123_safe_buffer()*AUDIOBUFSIZE;
if(!fr->own_buffer) fr->buffer.data = NULL;
if(fr->buffer.data != NULL && fr->buffer.size != size)
size_t size = fr->outblock;
if(!fr->own_buffer)
{
free(fr->buffer.data);
fr->buffer.data = NULL;
if(fr->buffer.size < size)
{
fr->err = MPG123_BAD_BUFFER;
if(NOQUIET) error2("have external buffer of size %"SIZE_P", need %"SIZE_P, (size_p)fr->buffer.size, size);
 
return MPG123_ERR;
}
}
 
debug1("need frame buffer of %"SIZE_P, (size_p)size);
if(fr->buffer.rdata != NULL && fr->buffer.size != size)
{
free(fr->buffer.rdata);
fr->buffer.rdata = NULL;
}
fr->buffer.size = size;
if(fr->buffer.data == NULL) fr->buffer.data = (unsigned char*) malloc(fr->buffer.size);
if(fr->buffer.data == NULL)
fr->buffer.data = NULL;
/* be generous: use 16 byte alignment */
if(fr->buffer.rdata == NULL) fr->buffer.rdata = (unsigned char*) malloc(fr->buffer.size+15);
if(fr->buffer.rdata == NULL)
{
fr->err = MPG123_OUT_OF_MEM;
return -1;
return MPG123_ERR;
}
fr->buffer.data = aligned_pointer(fr->buffer.rdata, unsigned char*, 16);
fr->own_buffer = TRUE;
fr->buffer.fill = 0;
return 0;
return MPG123_OK;
}
 
int attribute_align_arg mpg123_replace_buffer(mpg123_handle *mh, unsigned char *data, size_t size)
{
if(data == NULL || size < mpg123_safe_buffer())
debug2("replace buffer with %p size %"SIZE_P, data, (size_p)size);
/* Will accept any size, the error comes later... */
if(data == NULL)
{
mh->err = MPG123_BAD_BUFFER;
return MPG123_ERR;
}
if(mh->own_buffer && mh->buffer.data != NULL) free(mh->buffer.data);
if(mh->buffer.rdata != NULL) free(mh->buffer.rdata);
mh->own_buffer = FALSE;
mh->buffer.rdata = NULL;
mh->buffer.data = data;
mh->buffer.size = size;
mh->buffer.fill = 0;
293,8 → 342,9
#endif
#endif
#if defined(OPT_ALTIVEC) || defined(OPT_ARM)
if(decwin_size < (512+32)*4) decwin_size = (512+32)*4;
decwin_size += 512*4;
/* sizeof(real) >= 4 ... yes, it could be 8, for example.
We got it intialized to at least (512+32)*sizeof(real).*/
decwin_size += 512*sizeof(real);
#endif
/* Hm, that's basically realloc() ... */
if(fr->rawdecwin != NULL && fr->rawdecwins != decwin_size)
327,6 → 377,51
#endif
#endif
}
 
/* Layer scratch buffers are of compile-time fixed size, so allocate only once. */
if(fr->layerscratch == NULL)
{
/* Allocate specific layer1/2/3 buffers, so that we know they'll work for SSE. */
size_t scratchsize = 0;
real *scratcher;
#ifndef NO_LAYER1
scratchsize += sizeof(real) * 2 * SBLIMIT;
#endif
#ifndef NO_LAYER2
scratchsize += sizeof(real) * 2 * 4 * SBLIMIT;
#endif
#ifndef NO_LAYER3
scratchsize += sizeof(real) * 2 * SBLIMIT * SSLIMIT; /* hybrid_in */
scratchsize += sizeof(real) * 2 * SSLIMIT * SBLIMIT; /* hybrid_out */
#endif
/*
Now figure out correct alignment:
We need 16 byte minimum, smallest unit of the blocks is 2*SBLIMIT*sizeof(real), which is 64*4=256. Let's do 64bytes as heuristic for cache line (as proven useful in buffs above).
*/
fr->layerscratch = malloc(scratchsize+63);
if(fr->layerscratch == NULL) return -1;
 
/* Get aligned part of the memory, then divide it up. */
scratcher = aligned_pointer(fr->layerscratch,real,64);
/* Those funky pointer casts silence compilers...
One might change the code at hand to really just use 1D arrays, but in practice, that would not make a (positive) difference. */
#ifndef NO_LAYER1
fr->layer1.fraction = (real(*)[SBLIMIT])scratcher;
scratcher += 2 * SBLIMIT;
#endif
#ifndef NO_LAYER2
fr->layer2.fraction = (real(*)[4][SBLIMIT])scratcher;
scratcher += 2 * 4 * SBLIMIT;
#endif
#ifndef NO_LAYER3
fr->layer3.hybrid_in = (real(*)[SBLIMIT][SSLIMIT])scratcher;
scratcher += 2 * SBLIMIT * SSLIMIT;
fr->layer3.hybrid_out = (real(*)[SSLIMIT][SBLIMIT])scratcher;
scratcher += 2 * SSLIMIT * SBLIMIT;
#endif
/* Note: These buffers don't need resetting here. */
}
 
/* Only reset the buffers we created just now. */
frame_decode_buffers_reset(fr);
 
341,7 → 436,7
/* Wondering: could it be actually _wanted_ to retain buffer contents over different files? (special gapless / cut stuff) */
fr->bsbuf = fr->bsspace[1];
fr->bsbufold = fr->bsbuf;
fr->bitreservoir = 0; /* Not entirely sure if this is the right place for that counter. */
fr->bitreservoir = 0;
frame_decode_buffers_reset(fr);
memset(fr->bsspace, 0, 2*(MAXFRAMESIZE+512));
memset(fr->ssave, 0, 34);
350,7 → 445,7
return 0;
}
 
void frame_icy_reset(mpg123_handle* fr)
static void frame_icy_reset(mpg123_handle* fr)
{
#ifndef NO_ICY
if(fr->icy.data != NULL) free(fr->icy.data);
360,7 → 455,7
#endif
}
 
void frame_free_toc(mpg123_handle *fr)
static void frame_free_toc(mpg123_handle *fr)
{
if(fr->xing_toc != NULL){ free(fr->xing_toc); fr->xing_toc = NULL; }
}
407,10 → 502,11
fr->to_decode = FALSE;
fr->to_ignore = FALSE;
fr->metaflags = 0;
fr->outblock = mpg123_safe_buffer();
fr->outblock = 0; /* This will be set before decoding! */
fr->num = -1;
fr->input_offset = -1;
fr->playnum = -1;
fr->accurate = TRUE;
fr->state_flags = FRAME_ACCURATE;
fr->silent_resync = 0;
fr->audio_start = 0;
fr->clip = 0;
438,7 → 534,7
fr->fresh = 1;
fr->new_format = 0;
#ifdef GAPLESS
frame_gapless_init(fr,0,0);
frame_gapless_init(fr,-1,0,0);
fr->lastoff = 0;
fr->firstoff = 0;
#endif
461,7 → 557,7
fr->freeformat_framesize = -1;
}
 
void frame_free_buffers(mpg123_handle *fr)
static void frame_free_buffers(mpg123_handle *fr)
{
if(fr->rawbuffs != NULL) free(fr->rawbuffs);
fr->rawbuffs = NULL;
473,16 → 569,17
if(fr->conv16to8_buf != NULL) free(fr->conv16to8_buf);
fr->conv16to8_buf = NULL;
#endif
if(fr->layerscratch != NULL) free(fr->layerscratch);
}
 
void frame_exit(mpg123_handle *fr)
{
if(fr->own_buffer && fr->buffer.data != NULL)
if(fr->buffer.rdata != NULL)
{
debug1("freeing buffer at %p", (void*)fr->buffer.data);
free(fr->buffer.data);
debug1("freeing buffer at %p", (void*)fr->buffer.rdata);
free(fr->buffer.rdata);
}
fr->buffer.data = NULL;
fr->buffer.rdata = NULL;
frame_free_buffers(fr);
frame_free_toc(fr);
#ifdef FRAME_INDEX
497,7 → 594,16
#endif
exit_id3(fr);
clear_icy(&fr->icy);
/* Clean up possible mess from LFS wrapper. */
if(fr->wrapperclean != NULL)
{
fr->wrapperclean(fr->wrapperdata);
fr->wrapperdata = NULL;
}
#ifndef NO_FEEDER
bc_cleanup(&fr->rdat.buffer);
#endif
}
 
int attribute_align_arg mpg123_info(mpg123_handle *mh, struct mpg123_frameinfo *mi)
{
532,7 → 638,18
return MPG123_OK;
}
 
int attribute_align_arg mpg123_framedata(mpg123_handle *mh, unsigned long *header, unsigned char **bodydata, size_t *bodybytes)
{
if(mh == NULL) return MPG123_ERR;
if(!mh->to_decode) return MPG123_ERR;
 
if(header != NULL) *header = mh->oldhead;
if(bodydata != NULL) *bodydata = mh->bsbuf;
if(bodybytes != NULL) *bodybytes = mh->framesize;
 
return MPG123_OK;
}
 
/*
Fuzzy frame offset searching (guessing).
When we don't have an accurate position, we may use an inaccurate one.
541,7 → 658,7
- guess wildly from mean framesize and offset of first frame / beginning of file.
*/
 
off_t frame_fuzzy_find(mpg123_handle *fr, off_t want_frame, off_t* get_frame)
static off_t frame_fuzzy_find(mpg123_handle *fr, off_t want_frame, off_t* get_frame)
{
/* Default is to go to the beginning. */
off_t ret = fr->audio_start;
561,7 → 678,7
 
/* Now estimate back what frame we get. */
*get_frame = (off_t) ((double)toc_entry/100. * fr->track_frames);
fr->accurate = FALSE;
fr->state_flags &= ~FRAME_ACCURATE;
fr->silent_resync = 1;
/* Question: Is the TOC for whole file size (with/without ID3) or the "real" audio data only?
ID3v1 info could also matter. */
570,7 → 687,7
else if(fr->mean_framesize > 0)
{ /* Just guess with mean framesize (may be exact with CBR files). */
/* Query filelen here or not? */
fr->accurate = FALSE; /* Fuzzy! */
fr->state_flags &= ~FRAME_ACCURATE; /* Fuzzy! */
fr->silent_resync = 1;
*get_frame = want_frame;
ret = (off_t) (fr->audio_start+fr->mean_framesize*want_frame);
617,7 → 734,7
/* We have index position, that yields frame and byte offsets. */
*get_frame = fi*fr->index.step;
gopos = fr->index.data[fi];
fr->accurate = TRUE; /* When using the frame index, we are accurate. */
fr->state_flags |= FRAME_ACCURATE; /* When using the frame index, we are accurate. */
}
else
{
674,6 → 791,28
return outs;
}
 
/* Compute the number of output samples we expect from this frame.
This is either simple spf() or a tad more elaborate for ntom. */
off_t frame_expect_outsamples(mpg123_handle *fr)
{
off_t outs = 0;
switch(fr->down_sample)
{
case 0:
# ifndef NO_DOWNSAMPLE
case 1:
case 2:
# endif
outs = spf(fr)>>fr->down_sample;
break;
#ifndef NO_NTOM
case 3: outs = ntom_frame_outsamples(fr); break;
#endif
default: error1("Bad down_sample (%i) ... should not be possible!!", fr->down_sample);
}
return outs;
}
 
off_t frame_offset(mpg123_handle *fr, off_t outs)
{
off_t num = 0;
696,14 → 835,21
 
#ifdef GAPLESS
/* input in _input_ samples */
void frame_gapless_init(mpg123_handle *fr, off_t b, off_t e)
void frame_gapless_init(mpg123_handle *fr, off_t framecount, off_t bskip, off_t eskip)
{
fr->begin_s = b;
fr->end_s = e;
debug3("frame_gaples_init: given %"OFF_P" frames, skip %"OFF_P" and %"OFF_P, (off_p)framecount, (off_p)bskip, (off_p)eskip);
fr->gapless_frames = framecount;
if(fr->gapless_frames > 0)
{
fr->begin_s = bskip+GAPLESS_DELAY;
fr->end_s = framecount*spf(fr)-eskip+GAPLESS_DELAY;
}
else fr->begin_s = fr->end_s = 0;
/* These will get proper values later, from above plus resampling info. */
fr->begin_os = 0;
fr->end_os = 0;
debug2("frame_gapless_init: from %lu to %lu samples", (long unsigned)fr->begin_s, (long unsigned)fr->end_s);
fr->fullend_os = 0;
debug2("frame_gapless_init: from %"OFF_P" to %"OFF_P" samples", (off_p)fr->begin_s, (off_p)fr->end_s);
}
 
void frame_gapless_realinit(mpg123_handle *fr)
710,23 → 856,28
{
fr->begin_os = frame_ins2outs(fr, fr->begin_s);
fr->end_os = frame_ins2outs(fr, fr->end_s);
debug2("frame_gapless_realinit: from %lu to %lu samples", (long unsigned)fr->begin_os, (long unsigned)fr->end_os);
fr->fullend_os = frame_ins2outs(fr, fr->gapless_frames*spf(fr));
debug2("frame_gapless_realinit: from %"OFF_P" to %"OFF_P" samples", (off_p)fr->begin_os, (off_p)fr->end_os);
}
 
/* When we got a new sample count, update the gaplessness. */
/* At least note when there is trouble... */
void frame_gapless_update(mpg123_handle *fr, off_t total_samples)
{
if(fr->end_s < 1)
off_t gapless_samples = fr->gapless_frames*spf(fr);
debug2("gapless update with new sample count %"OFF_P" as opposed to known %"OFF_P, total_samples, gapless_samples);
if(NOQUIET && total_samples != gapless_samples)
fprintf(stderr, "\nWarning: Real sample count differs from given gapless sample count. Frankenstein stream?\n");
 
if(gapless_samples > total_samples)
{
fr->end_s = total_samples;
if(NOQUIET) error2("End sample count smaller than gapless end! (%"OFF_P" < %"OFF_P"). Disabling gapless mode from now on.", (off_p)total_samples, (off_p)fr->end_s);
/* This invalidates the current position... but what should I do? */
frame_gapless_init(fr, -1, 0, 0);
frame_gapless_realinit(fr);
fr->lastframe = -1;
fr->lastoff = 0;
}
else if(fr->end_s > total_samples)
{
if(NOQUIET) error2("end sample count smaller than gapless end! (%"OFF_P" < %"OFF_P").", (off_p)total_samples, (off_p)fr->end_s);
fr->end_s = total_samples;
}
}
 
#endif
 
750,7 → 901,7
{
fr->firstframe = fe;
#ifdef GAPLESS
if(fr->p.flags & MPG123_GAPLESS)
if(fr->p.flags & MPG123_GAPLESS && fr->gapless_frames > 0)
{
/* Take care of the beginning... */
off_t beg_f = frame_offset(fr, fr->begin_os);
765,7 → 916,7
{
fr->lastframe = frame_offset(fr,fr->end_os);
fr->lastoff = fr->end_os - frame_outs(fr, fr->lastframe);
} else fr->lastoff = 0;
} else {fr->lastframe = -1; fr->lastoff = 0; }
} else { fr->firstoff = fr->lastoff = 0; fr->lastframe = -1; }
#endif
fr->ignoreframe = ignoreframe(fr);
791,6 → 942,7
void frame_set_seek(mpg123_handle *fr, off_t sp)
{
fr->firstframe = frame_offset(fr, sp);
debug1("frame_set_seek: from %"OFF_P, fr->num);
#ifndef NO_NTOM
if(fr->down_sample == 3) ntom_set_ntom(fr, fr->firstframe);
#endif
886,3 → 1038,9
return MPG123_OK;
}
 
off_t attribute_align_arg mpg123_framepos(mpg123_handle *mh)
{
if(mh == NULL) return MPG123_ERR;
 
return mh->input_offset;
}