Rev 1905 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1905 | Rev 3960 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | /* |
1 | /* |
2 | libmpg123: MPEG Audio Decoder library |
2 | libmpg123: MPEG Audio Decoder library |
Line 3... | Line 3... | ||
3 | 3 | ||
4 | copyright 1995-2009 by the mpg123 project - free software under the terms of the LGPL 2.1 |
4 | copyright 1995-2012 by the mpg123 project - free software under the terms of the LGPL 2.1 |
Line 5... | Line 5... | ||
5 | see COPYING and AUTHORS files in distribution or http://mpg123.org |
5 | see COPYING and AUTHORS files in distribution or http://mpg123.org |
Line 6... | Line 6... | ||
6 | 6 | ||
7 | */ |
7 | */ |
8 | 8 | ||
Line 9... | Line 9... | ||
9 | #include "mpg123lib_intern.h" |
9 | #include "mpg123lib_intern.h" |
10 | #include "icy2utf8.h" |
- | |
11 | #include "debug.h" |
- | |
12 | - | ||
13 | #ifdef GAPLESS |
- | |
14 | #define SAMPLE_ADJUST(x) ((x) - ((mh->p.flags & MPG123_GAPLESS) ? mh->begin_os : 0)) |
- | |
15 | #define SAMPLE_UNADJUST(x) ((x) + ((mh->p.flags & MPG123_GAPLESS) ? mh->begin_os : 0)) |
- | |
Line 16... | Line 10... | ||
16 | #else |
10 | #include "icy2utf8.h" |
Line 17... | Line 11... | ||
17 | #define SAMPLE_ADJUST(x) (x) |
11 | #include "debug.h" |
Line 18... | Line -... | ||
18 | #define SAMPLE_UNADJUST(x) (x) |
- | |
19 | #endif |
- | |
20 | - | ||
21 | #define SEEKFRAME(mh) ((mh)->ignoreframe < 0 ? 0 : (mh)->ignoreframe) |
- | |
22 | - | ||
23 | static int initialized = 0; |
- | |
24 | - | ||
25 | #define ALIGNCHECK(mh) |
- | |
26 | #define ALIGNCHECKK |
- | |
27 | /* On compilers that support data alignment but not the automatic stack realignment. |
- | |
28 | We check for properly aligned stack before risking a crash because of badly compiled |
- | |
29 | client program. */ |
- | |
30 | #if (defined CCALIGN) && (defined NEED_ALIGNCHECK) && ((defined DEBUG) || (defined CHECK_ALIGN)) |
- | |
31 | - | ||
32 | /* Common building block. */ |
- | |
33 | #define ALIGNMAINPART \ |
- | |
34 | /* minimum size of 16 bytes, not all compilers would align a smaller piece of data */ \ |
- | |
35 | double ALIGNED(16) altest[2]; \ |
- | |
36 | debug2("testing alignment, with %lu %% 16 = %lu", \ |
- | |
37 | (unsigned long)altest, (unsigned long)((size_t)altest % 16)); \ |
- | |
38 | if((size_t)altest % 16 != 0) |
- | |
39 | - | ||
40 | #undef ALIGNCHECK |
- | |
41 | #define ALIGNCHECK(mh) \ |
- | |
42 | ALIGNMAINPART \ |
- | |
43 | { \ |
- | |
44 | error("Stack variable is not aligned! Your combination of compiler/library is dangerous!"); \ |
- | |
45 | if(mh != NULL) mh->err = MPG123_BAD_ALIGN; \ |
- | |
46 | \ |
- | |
47 | return MPG123_ERR; \ |
- | |
48 | } |
- | |
49 | #undef ALIGNCHECKK |
- | |
50 | #define ALIGNCHECKK \ |
- | |
51 | ALIGNMAINPART \ |
- | |
52 | { \ |
- | |
53 | error("Stack variable is not aligned! Your combination of compiler/library is dangerous!"); \ |
- | |
54 | return MPG123_BAD_ALIGN; \ |
- | |
55 | } |
- | |
56 | - | ||
57 | #endif |
- | |
58 | - | ||
59 | #ifdef GAPLESS |
- | |
60 | /* |
- | |
61 | Take the buffer after a frame decode (strictly: it is the data from frame fr->num!) and cut samples out. |
- | |
62 | fr->buffer.fill may then be smaller than before... |
- | |
63 | */ |
- | |
64 | static void frame_buffercheck(mpg123_handle *fr) |
- | |
65 | { |
- | |
66 | /* When we have no accurate position, gapless code does not make sense. */ |
- | |
67 | if(!fr->accurate) return; |
- | |
68 | - | ||
69 | /* The first interesting frame: Skip some leading samples. */ |
- | |
70 | if(fr->firstoff && fr->num == fr->firstframe) |
- | |
71 | { |
- | |
72 | off_t byteoff = samples_to_bytes(fr, fr->firstoff); |
- | |
73 | if((off_t)fr->buffer.fill > byteoff) |
- | |
74 | { |
- | |
75 | fr->buffer.fill -= byteoff; |
- | |
76 | /* buffer.p != buffer.data only for own buffer */ |
- | |
77 | debug6("cutting %li samples/%li bytes on begin, own_buffer=%i at %p=%p, buf[1]=%i", |
- | |
78 | (long)fr->firstoff, (long)byteoff, fr->own_buffer, (void*)fr->buffer.p, (void*)fr->buffer.data, ((short*)fr->buffer.p)[2]); |
- | |
79 | if(fr->own_buffer) fr->buffer.p = fr->buffer.data + byteoff; |
- | |
80 | else memmove(fr->buffer.data, fr->buffer.data + byteoff, fr->buffer.fill); |
- | |
81 | debug3("done cutting, buffer at %p =? %p, buf[1]=%i", |
- | |
82 | (void*)fr->buffer.p, (void*)fr->buffer.data, ((short*)fr->buffer.p)[2]); |
- | |
83 | } |
- | |
84 | else fr->buffer.fill = 0; |
- | |
85 | fr->firstoff = 0; /* Only enter here once... when you seek, firstoff should be reset. */ |
- | |
86 | } |
- | |
87 | /* The last interesting (planned) frame: Only use some leading samples. */ |
- | |
88 | if(fr->lastoff && fr->num == fr->lastframe) |
- | |
89 | { |
- | |
90 | off_t byteoff = samples_to_bytes(fr, fr->lastoff); |
- | |
91 | if((off_t)fr->buffer.fill > byteoff) |
- | |
92 | { |
- | |
93 | fr->buffer.fill = byteoff; |
12 | |
94 | } |
13 | #include "gapless.h" |
95 | fr->lastoff = 0; /* Only enter here once... when you seek, lastoff should be reset. */ |
- | |
96 | } |
14 | |
Line 97... | Line 15... | ||
97 | } |
15 | #define SEEKFRAME(mh) ((mh)->ignoreframe < 0 ? 0 : (mh)->ignoreframe) |
Line 98... | Line 16... | ||
98 | #endif |
16 | |
Line 130... | Line 48... | ||
130 | /* ...the full routine with optional initial parameters to override defaults. */ |
48 | /* ...the full routine with optional initial parameters to override defaults. */ |
131 | mpg123_handle attribute_align_arg *mpg123_parnew(mpg123_pars *mp, const char* decoder, int *error) |
49 | mpg123_handle attribute_align_arg *mpg123_parnew(mpg123_pars *mp, const char* decoder, int *error) |
132 | { |
50 | { |
133 | mpg123_handle *fr = NULL; |
51 | mpg123_handle *fr = NULL; |
134 | int err = MPG123_OK; |
52 | int err = MPG123_OK; |
135 | #if (defined CCALIGN) && (defined NEED_ALIGNCHECK) && ((defined DEBUG) || (defined CHECK_ALIGN)) |
- | |
136 | #ifdef CCALIGN |
- | |
137 | double ALIGNED(16) altest[4]; |
- | |
138 | if(((size_t)altest) % 16 != 0) |
- | |
139 | { |
53 | |
140 | error("Stack variable is not aligned! Your combination of compiler/library is dangerous!"); |
- | |
141 | *error = MPG123_BAD_ALIGN; |
- | |
142 | return NULL; |
- | |
143 | } |
- | |
144 | #endif |
- | |
145 | #endif |
- | |
146 | if(initialized) fr = (mpg123_handle*) malloc(sizeof(mpg123_handle)); |
54 | if(initialized) fr = (mpg123_handle*) malloc(sizeof(mpg123_handle)); |
147 | else err = MPG123_NOT_INITIALIZED; |
55 | else err = MPG123_NOT_INITIALIZED; |
148 | if(fr != NULL) |
56 | if(fr != NULL) |
149 | { |
57 | { |
150 | frame_init_par(fr, mp); |
58 | frame_init_par(fr, mp); |
Line 157... | Line 65... | ||
157 | fr = NULL; |
65 | fr = NULL; |
158 | } |
66 | } |
159 | } |
67 | } |
160 | if(fr != NULL) |
68 | if(fr != NULL) |
161 | { |
69 | { |
162 | /* Cleanup that mess! ... use mpg123_decoder / decode_update! */ |
- | |
163 | if(frame_outbuffer(fr) != 0) |
- | |
164 | { |
- | |
165 | err = MPG123_NO_BUFFERS; |
- | |
166 | frame_exit(fr); |
- | |
167 | free(fr); |
- | |
168 | fr = NULL; |
- | |
169 | } |
- | |
170 | else |
- | |
171 | { |
- | |
172 | /* I smell cleanup here... with get_next_frame() */ |
- | |
173 | /* if(decode_update(fr) != 0) |
- | |
174 | { |
- | |
175 | err = fr->err != MPG123_OK ? fr->err : MPG123_BAD_DECODER; |
- | |
176 | frame_exit(fr); |
- | |
177 | free(fr); |
- | |
178 | fr = NULL; |
- | |
179 | } |
- | |
180 | else */ |
- | |
181 | fr->decoder_change = 1; |
70 | fr->decoder_change = 1; |
182 | } |
71 | } |
183 | } |
- | |
184 | else if(err == MPG123_OK) err = MPG123_OUT_OF_MEM; |
72 | else if(err == MPG123_OK) err = MPG123_OUT_OF_MEM; |
Line 185... | Line 73... | ||
185 | 73 | ||
186 | if(error != NULL) *error = err; |
74 | if(error != NULL) *error = err; |
187 | return fr; |
75 | return fr; |
Line 188... | Line 76... | ||
188 | } |
76 | } |
189 | 77 | ||
190 | int attribute_align_arg mpg123_decoder(mpg123_handle *mh, const char* decoder) |
78 | int attribute_align_arg mpg123_decoder(mpg123_handle *mh, const char* decoder) |
191 | { |
- | |
- | 79 | { |
|
192 | enum optdec dt = dectype(decoder); |
80 | enum optdec dt = dectype(decoder); |
Line 193... | Line 81... | ||
193 | ALIGNCHECK(mh); |
81 | |
194 | if(mh == NULL) return MPG123_ERR; |
82 | if(mh == NULL) return MPG123_ERR; |
195 | 83 | ||
Line 215... | Line 103... | ||
215 | { |
103 | { |
216 | mh->err = MPG123_NO_BUFFERS; |
104 | mh->err = MPG123_NO_BUFFERS; |
217 | frame_exit(mh); |
105 | frame_exit(mh); |
218 | return MPG123_ERR; |
106 | return MPG123_ERR; |
219 | } |
107 | } |
220 | /* I smell cleanup here... with get_next_frame() */ |
108 | /* Do _not_ call decode_update here! That is only allowed after a first MPEG frame has been met. */ |
221 | decode_update(mh); |
- | |
222 | mh->decoder_change = 1; |
109 | mh->decoder_change = 1; |
223 | return MPG123_OK; |
110 | return MPG123_OK; |
224 | } |
111 | } |
Line 225... | Line 112... | ||
225 | 112 | ||
226 | int attribute_align_arg mpg123_param(mpg123_handle *mh, enum mpg123_parms key, long val, double fval) |
113 | int attribute_align_arg mpg123_param(mpg123_handle *mh, enum mpg123_parms key, long val, double fval) |
227 | { |
114 | { |
228 | int r; |
- | |
- | 115 | int r; |
|
229 | ALIGNCHECK(mh); |
116 | |
230 | if(mh == NULL) return MPG123_ERR; |
117 | if(mh == NULL) return MPG123_ERR; |
231 | r = mpg123_par(&mh->p, key, val, fval); |
118 | r = mpg123_par(&mh->p, key, val, fval); |
232 | if(r != MPG123_OK){ mh->err = r; r = MPG123_ERR; } |
119 | if(r != MPG123_OK){ mh->err = r; r = MPG123_ERR; } |
233 | else |
120 | else |
Line 237... | Line 124... | ||
237 | { /* Apply frame index size and grow property on the fly. */ |
124 | { /* Apply frame index size and grow property on the fly. */ |
238 | r = frame_index_setup(mh); |
125 | r = frame_index_setup(mh); |
239 | if(r != MPG123_OK) mh->err = MPG123_INDEX_FAIL; |
126 | if(r != MPG123_OK) mh->err = MPG123_INDEX_FAIL; |
240 | } |
127 | } |
241 | #endif |
128 | #endif |
- | 129 | #ifndef NO_FEEDER |
|
- | 130 | /* Feeder pool size is applied right away, reader will react to that. */ |
|
- | 131 | if(key == MPG123_FEEDPOOL || key == MPG123_FEEDBUFFER) |
|
- | 132 | bc_poolsize(&mh->rdat.buffer, mh->p.feedpool, mh->p.feedbuffer); |
|
- | 133 | #endif |
|
242 | } |
134 | } |
243 | return r; |
135 | return r; |
244 | } |
136 | } |
Line 245... | Line 137... | ||
245 | 137 | ||
246 | int attribute_align_arg mpg123_par(mpg123_pars *mp, enum mpg123_parms key, long val, double fval) |
138 | int attribute_align_arg mpg123_par(mpg123_pars *mp, enum mpg123_parms key, long val, double fval) |
247 | { |
139 | { |
248 | int ret = MPG123_OK; |
140 | int ret = MPG123_OK; |
249 | ALIGNCHECKK |
141 | |
250 | if(mp == NULL) return MPG123_BAD_PARS; |
142 | if(mp == NULL) return MPG123_BAD_PARS; |
251 | switch(key) |
143 | switch(key) |
252 | { |
144 | { |
253 | case MPG123_VERBOSE: |
145 | case MPG123_VERBOSE: |
Line 311... | Line 203... | ||
311 | /* Choose the value that is non-zero, if any. |
203 | /* Choose the value that is non-zero, if any. |
312 | Downscaling integers to 1.0 . */ |
204 | Downscaling integers to 1.0 . */ |
313 | mp->outscale = val == 0 ? fval : (double)val/SHORT_SCALE; |
205 | mp->outscale = val == 0 ? fval : (double)val/SHORT_SCALE; |
314 | break; |
206 | break; |
315 | case MPG123_TIMEOUT: |
207 | case MPG123_TIMEOUT: |
316 | #ifndef WIN32 |
208 | #ifdef TIMEOUT_READ |
317 | mp->timeout = val >= 0 ? val : 0; |
209 | mp->timeout = val >= 0 ? val : 0; |
318 | #else |
210 | #else |
319 | ret = MPG123_NO_TIMEOUT; |
211 | if(val > 0) ret = MPG123_NO_TIMEOUT; |
320 | #endif |
212 | #endif |
321 | break; |
213 | break; |
322 | case MPG123_RESYNC_LIMIT: |
214 | case MPG123_RESYNC_LIMIT: |
323 | mp->resync_limit = val; |
215 | mp->resync_limit = val; |
324 | break; |
216 | break; |
Line 331... | Line 223... | ||
331 | break; |
223 | break; |
332 | case MPG123_PREFRAMES: |
224 | case MPG123_PREFRAMES: |
333 | if(val >= 0) mp->preframes = val; |
225 | if(val >= 0) mp->preframes = val; |
334 | else ret = MPG123_BAD_VALUE; |
226 | else ret = MPG123_BAD_VALUE; |
335 | break; |
227 | break; |
- | 228 | case MPG123_FEEDPOOL: |
|
- | 229 | #ifndef NO_FEEDER |
|
- | 230 | if(val >= 0) mp->feedpool = val; |
|
- | 231 | else ret = MPG123_BAD_VALUE; |
|
- | 232 | #else |
|
- | 233 | ret = MPG123_MISSING_FEATURE; |
|
- | 234 | #endif |
|
- | 235 | break; |
|
- | 236 | case MPG123_FEEDBUFFER: |
|
- | 237 | #ifndef NO_FEEDER |
|
- | 238 | if(val > 0) mp->feedbuffer = val; |
|
- | 239 | else ret = MPG123_BAD_VALUE; |
|
- | 240 | #else |
|
- | 241 | ret = MPG123_MISSING_FEATURE; |
|
- | 242 | #endif |
|
- | 243 | break; |
|
336 | default: |
244 | default: |
337 | ret = MPG123_BAD_PARAM; |
245 | ret = MPG123_BAD_PARAM; |
338 | } |
246 | } |
339 | return ret; |
247 | return ret; |
340 | } |
248 | } |
Line 341... | Line 249... | ||
341 | 249 | ||
342 | int attribute_align_arg mpg123_getparam(mpg123_handle *mh, enum mpg123_parms key, long *val, double *fval) |
250 | int attribute_align_arg mpg123_getparam(mpg123_handle *mh, enum mpg123_parms key, long *val, double *fval) |
343 | { |
251 | { |
344 | int r; |
- | |
- | 252 | int r; |
|
345 | ALIGNCHECK(mh); |
253 | |
346 | if(mh == NULL) return MPG123_ERR; |
254 | if(mh == NULL) return MPG123_ERR; |
347 | r = mpg123_getpar(&mh->p, key, val, fval); |
255 | r = mpg123_getpar(&mh->p, key, val, fval); |
348 | if(r != MPG123_OK){ mh->err = r; r = MPG123_ERR; } |
256 | if(r != MPG123_OK){ mh->err = r; r = MPG123_ERR; } |
349 | return r; |
257 | return r; |
Line 350... | Line 258... | ||
350 | } |
258 | } |
351 | 259 | ||
352 | int attribute_align_arg mpg123_getpar(mpg123_pars *mp, enum mpg123_parms key, long *val, double *fval) |
260 | int attribute_align_arg mpg123_getpar(mpg123_pars *mp, enum mpg123_parms key, long *val, double *fval) |
353 | { |
261 | { |
354 | int ret = 0; |
262 | int ret = 0; |
355 | ALIGNCHECKK |
263 | |
356 | if(mp == NULL) return MPG123_BAD_PARS; |
264 | if(mp == NULL) return MPG123_BAD_PARS; |
357 | switch(key) |
265 | switch(key) |
358 | { |
266 | { |
Line 406... | Line 314... | ||
406 | #endif |
314 | #endif |
407 | break; |
315 | break; |
408 | case MPG123_PREFRAMES: |
316 | case MPG123_PREFRAMES: |
409 | *val = mp->preframes; |
317 | *val = mp->preframes; |
410 | break; |
318 | break; |
- | 319 | case MPG123_FEEDPOOL: |
|
- | 320 | #ifndef NO_FEEDER |
|
- | 321 | *val = mp->feedpool; |
|
- | 322 | #else |
|
- | 323 | ret = MPG123_MISSING_FEATURE; |
|
- | 324 | #endif |
|
- | 325 | break; |
|
- | 326 | case MPG123_FEEDBUFFER: |
|
- | 327 | #ifndef NO_FEEDER |
|
- | 328 | *val = mp->feedbuffer; |
|
- | 329 | #else |
|
- | 330 | ret = MPG123_MISSING_FEATURE; |
|
- | 331 | #endif |
|
- | 332 | break; |
|
411 | default: |
333 | default: |
412 | ret = MPG123_BAD_PARAM; |
334 | ret = MPG123_BAD_PARAM; |
413 | } |
335 | } |
414 | return ret; |
336 | return ret; |
415 | } |
337 | } |
Line 417... | Line 339... | ||
417 | int attribute_align_arg mpg123_getstate(mpg123_handle *mh, enum mpg123_state key, long *val, double *fval) |
339 | int attribute_align_arg mpg123_getstate(mpg123_handle *mh, enum mpg123_state key, long *val, double *fval) |
418 | { |
340 | { |
419 | int ret = MPG123_OK; |
341 | int ret = MPG123_OK; |
420 | long theval = 0; |
342 | long theval = 0; |
421 | double thefval = 0.; |
343 | double thefval = 0.; |
422 | ALIGNCHECK(mh); |
- | |
- | 344 | ||
423 | if(mh == NULL) return MPG123_ERR; |
345 | if(mh == NULL) return MPG123_ERR; |
Line 424... | Line 346... | ||
424 | 346 | ||
425 | switch(key) |
347 | switch(key) |
426 | { |
348 | { |
- | 349 | case MPG123_ACCURATE: |
|
- | 350 | theval = mh->state_flags & FRAME_ACCURATE; |
|
- | 351 | break; |
|
- | 352 | case MPG123_FRANKENSTEIN: |
|
- | 353 | theval = mh->state_flags & FRAME_FRANKENSTEIN; |
|
- | 354 | break; |
|
- | 355 | case MPG123_BUFFERFILL: |
|
- | 356 | #ifndef NO_FEEDER |
|
- | 357 | { |
|
427 | case MPG123_ACCURATE: |
358 | size_t sval = bc_fill(&mh->rdat.buffer); |
- | 359 | theval = (long)sval; |
|
- | 360 | if((size_t)theval != sval) |
|
- | 361 | { |
|
- | 362 | mh->err = MPG123_INT_OVERFLOW; |
|
- | 363 | ret = MPG123_ERR; |
|
- | 364 | } |
|
- | 365 | } |
|
- | 366 | #else |
|
- | 367 | mh->err = MPG123_MISSING_FEATURE; |
|
- | 368 | ret = MPG123_ERR; |
|
428 | theval = mh->accurate; |
369 | #endif |
429 | break; |
370 | break; |
430 | default: |
371 | default: |
431 | mh->err = MPG123_BAD_KEY; |
372 | mh->err = MPG123_BAD_KEY; |
432 | ret = MPG123_ERR; |
373 | ret = MPG123_ERR; |
Line 438... | Line 379... | ||
438 | return ret; |
379 | return ret; |
439 | } |
380 | } |
Line 440... | Line 381... | ||
440 | 381 | ||
441 | int attribute_align_arg mpg123_eq(mpg123_handle *mh, enum mpg123_channels channel, int band, double val) |
382 | int attribute_align_arg mpg123_eq(mpg123_handle *mh, enum mpg123_channels channel, int band, double val) |
442 | { |
- | |
443 | ALIGNCHECK(mh); |
383 | { |
444 | if(mh == NULL) return MPG123_ERR; |
384 | if(mh == NULL) return MPG123_ERR; |
445 | if(band < 0 || band > 31){ mh->err = MPG123_BAD_BAND; return MPG123_ERR; } |
385 | if(band < 0 || band > 31){ mh->err = MPG123_BAD_BAND; return MPG123_ERR; } |
446 | switch(channel) |
386 | switch(channel) |
447 | { |
387 | { |
Line 459... | Line 399... | ||
459 | } |
399 | } |
Line 460... | Line 400... | ||
460 | 400 | ||
461 | double attribute_align_arg mpg123_geteq(mpg123_handle *mh, enum mpg123_channels channel, int band) |
401 | double attribute_align_arg mpg123_geteq(mpg123_handle *mh, enum mpg123_channels channel, int band) |
462 | { |
402 | { |
463 | double ret = 0.; |
- | |
- | 403 | double ret = 0.; |
|
464 | ALIGNCHECK(mh); |
404 | |
Line 465... | Line 405... | ||
465 | if(mh == NULL) return MPG123_ERR; |
405 | if(mh == NULL) return MPG123_ERR; |
466 | 406 | ||
467 | /* Handle this gracefully. When there is no band, it has no volume. */ |
407 | /* Handle this gracefully. When there is no band, it has no volume. */ |
Line 481... | Line 421... | ||
481 | 421 | ||
482 | 422 | ||
483 | /* plain file access, no http! */ |
423 | /* plain file access, no http! */ |
484 | int attribute_align_arg mpg123_open(mpg123_handle *mh, const char *path) |
- | |
485 | { |
424 | int attribute_align_arg mpg123_open(mpg123_handle *mh, const char *path) |
Line 486... | Line 425... | ||
486 | ALIGNCHECK(mh); |
425 | { |
487 | if(mh == NULL) return MPG123_ERR; |
- | |
488 | 426 | if(mh == NULL) return MPG123_ERR; |
|
489 | mpg123_close(mh); |
427 | |
Line 490... | Line 428... | ||
490 | frame_reset(mh); |
428 | mpg123_close(mh); |
491 | return open_stream(mh, path, -1); |
429 | return open_stream(mh, path, -1); |
492 | } |
- | |
493 | 430 | } |
|
Line 494... | Line 431... | ||
494 | int attribute_align_arg mpg123_open_fd(mpg123_handle *mh, int fd) |
431 | |
495 | { |
- | |
496 | ALIGNCHECK(mh); |
432 | int attribute_align_arg mpg123_open_fd(mpg123_handle *mh, int fd) |
497 | if(mh == NULL) return MPG123_ERR; |
433 | { |
Line -... | Line 434... | ||
- | 434 | if(mh == NULL) return MPG123_ERR; |
|
- | 435 | ||
- | 436 | mpg123_close(mh); |
|
- | 437 | return open_stream(mh, NULL, fd); |
|
- | 438 | } |
|
- | 439 | ||
- | 440 | int attribute_align_arg mpg123_open_handle(mpg123_handle *mh, void *iohandle) |
|
- | 441 | { |
|
- | 442 | if(mh == NULL) return MPG123_ERR; |
|
- | 443 | ||
- | 444 | mpg123_close(mh); |
|
- | 445 | if(mh->rdat.r_read_handle == NULL) |
|
- | 446 | { |
|
498 | 447 | mh->err = MPG123_BAD_CUSTOM_IO; |
|
499 | mpg123_close(mh); |
448 | return MPG123_ERR; |
500 | frame_reset(mh); |
- | |
501 | return open_stream(mh, NULL, fd); |
449 | } |
Line 502... | Line 450... | ||
502 | } |
450 | return open_stream_handle(mh, iohandle); |
503 | - | ||
504 | int attribute_align_arg mpg123_open_feed(mpg123_handle *mh) |
451 | } |
505 | { |
452 | |
Line 506... | Line 453... | ||
506 | ALIGNCHECK(mh); |
453 | int attribute_align_arg mpg123_open_feed(mpg123_handle *mh) |
507 | if(mh == NULL) return MPG123_ERR; |
454 | { |
508 | 455 | if(mh == NULL) return MPG123_ERR; |
|
509 | mpg123_close(mh); |
456 | |
510 | frame_reset(mh); |
- | |
511 | return open_feed(mh); |
457 | mpg123_close(mh); |
- | 458 | return open_feed(mh); |
|
- | 459 | } |
|
512 | } |
460 | |
513 | 461 | int attribute_align_arg mpg123_replace_reader( mpg123_handle *mh, |
|
514 | int attribute_align_arg mpg123_replace_reader( mpg123_handle *mh, |
462 | ssize_t (*r_read) (int, void *, size_t), |
515 | ssize_t (*r_read) (int, void *, size_t), |
463 | off_t (*r_lseek)(int, off_t, int) ) |
Line -... | Line 464... | ||
- | 464 | { |
|
- | 465 | if(mh == NULL) return MPG123_ERR; |
|
- | 466 | ||
- | 467 | mpg123_close(mh); |
|
- | 468 | mh->rdat.r_read = r_read; |
|
- | 469 | mh->rdat.r_lseek = r_lseek; |
|
Line -... | Line 470... | ||
- | 470 | return MPG123_OK; |
|
- | 471 | } |
|
- | 472 | ||
- | 473 | int attribute_align_arg mpg123_replace_reader_handle( mpg123_handle *mh, |
|
- | 474 | ssize_t (*r_read) (void*, void *, size_t), |
|
- | 475 | off_t (*r_lseek)(void*, off_t, int), |
|
- | 476 | void (*cleanup)(void*) ) |
|
- | 477 | { |
|
- | 478 | if(mh == NULL) return MPG123_ERR; |
|
- | 479 | ||
- | 480 | mpg123_close(mh); |
|
516 | off_t (*r_lseek)(int, off_t, int) ) |
481 | mh->rdat.r_read_handle = r_read; |
517 | { |
482 | mh->rdat.r_lseek_handle = r_lseek; |
518 | ALIGNCHECK(mh); |
483 | mh->rdat.cleanup_handle = cleanup; |
519 | if(mh == NULL) return MPG123_ERR; |
484 | return MPG123_OK; |
- | 485 | } |
|
520 | mh->rdat.r_read = r_read; |
486 | |
- | 487 | /* Update decoding engine for |
|
- | 488 | a) a new choice of decoder |
|
- | 489 | b) a changed native format of the MPEG stream |
|
- | 490 | ... calls are only valid after parsing some MPEG frame! */ |
|
- | 491 | int decode_update(mpg123_handle *mh) |
|
- | 492 | { |
|
- | 493 | long native_rate; |
|
521 | mh->rdat.r_lseek = r_lseek; |
494 | int b; |
Line 522... | Line 495... | ||
522 | return MPG123_OK; |
495 | |
523 | } |
496 | if(mh->num < 0) |
Line 545... | Line 518... | ||
545 | case 0: |
518 | case 0: |
546 | case 1: |
519 | case 1: |
547 | case 2: |
520 | case 2: |
548 | mh->down_sample_sblimit = SBLIMIT>>(mh->down_sample); |
521 | mh->down_sample_sblimit = SBLIMIT>>(mh->down_sample); |
549 | /* With downsampling I get less samples per frame */ |
522 | /* With downsampling I get less samples per frame */ |
550 | mh->outblock = samples_to_bytes(mh, (spf(mh)>>mh->down_sample)); |
523 | mh->outblock = samples_to_storage(mh, (spf(mh)>>mh->down_sample)); |
551 | break; |
524 | break; |
552 | #ifndef NO_NTOM |
525 | #ifndef NO_NTOM |
553 | case 3: |
526 | case 3: |
554 | { |
527 | { |
555 | if(synth_ntom_set_step(mh) != 0) return -1; |
528 | if(synth_ntom_set_step(mh) != 0) return -1; |
Line 557... | Line 530... | ||
557 | { |
530 | { |
558 | mh->down_sample_sblimit = SBLIMIT * mh->af.rate; |
531 | mh->down_sample_sblimit = SBLIMIT * mh->af.rate; |
559 | mh->down_sample_sblimit /= frame_freq(mh); |
532 | mh->down_sample_sblimit /= frame_freq(mh); |
560 | } |
533 | } |
561 | else mh->down_sample_sblimit = SBLIMIT; |
534 | else mh->down_sample_sblimit = SBLIMIT; |
562 | mh->outblock = mh->af.encsize * mh->af.channels * |
535 | mh->outblock = samples_to_storage(mh, |
563 | ( ( NTOM_MUL-1+spf(mh) |
536 | ( ( NTOM_MUL-1+spf(mh) |
564 | * (((size_t)NTOM_MUL*mh->af.rate)/frame_freq(mh)) |
537 | * (((size_t)NTOM_MUL*mh->af.rate)/frame_freq(mh)) |
565 | )/NTOM_MUL ); |
538 | )/NTOM_MUL )); |
566 | } |
539 | } |
567 | break; |
540 | break; |
568 | #endif |
541 | #endif |
569 | } |
542 | } |
Line 574... | Line 547... | ||
574 | else mh->single = SINGLE_STEREO; |
547 | else mh->single = SINGLE_STEREO; |
575 | } |
548 | } |
576 | else mh->single = (mh->p.flags & MPG123_FORCE_MONO)-1; |
549 | else mh->single = (mh->p.flags & MPG123_FORCE_MONO)-1; |
577 | if(set_synth_functions(mh) != 0) return -1;; |
550 | if(set_synth_functions(mh) != 0) return -1;; |
Line -... | Line 551... | ||
- | 551 | ||
- | 552 | /* The needed size of output buffer may have changed. */ |
|
- | 553 | if(frame_outbuffer(mh) != MPG123_OK) return -1; |
|
578 | 554 | ||
579 | do_rva(mh); |
555 | do_rva(mh); |
Line 580... | Line 556... | ||
580 | 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); |
556 | 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); |
581 | 557 | ||
Line 582... | Line 558... | ||
582 | return 0; |
558 | return 0; |
583 | } |
559 | } |
584 | 560 | ||
585 | size_t attribute_align_arg mpg123_safe_buffer() |
561 | size_t attribute_align_arg mpg123_safe_buffer(void) |
586 | { |
562 | { |
Line 587... | Line 563... | ||
587 | /* real is the largest possible output (it's 32bit float, 32bit int or 64bit double). */ |
563 | /* real is the largest possible output (it's 32bit float, 32bit int or 64bit double). */ |
588 | return sizeof(real)*2*1152*NTOM_MAX; |
564 | return sizeof(real)*2*1152*NTOM_MAX; |
- | 565 | } |
|
589 | } |
566 | |
590 | 567 | size_t attribute_align_arg mpg123_outblock(mpg123_handle *mh) |
|
591 | size_t attribute_align_arg mpg123_outblock(mpg123_handle *mh) |
568 | { |
Line -... | Line 569... | ||
- | 569 | /* Try to be helpful and never return zero output block size. */ |
|
- | 570 | if(mh != NULL && mh->outblock > 0) return mh->outblock; |
|
592 | { |
571 | else return mpg123_safe_buffer(); |
593 | if(mh != NULL) return mh->outblock; |
572 | } |
- | 573 | ||
- | 574 | /* Read in the next frame we actually want for decoding. |
|
- | 575 | This includes skipping/ignoring frames, in additon to skipping junk in the parser. */ |
|
594 | else return mpg123_safe_buffer(); |
576 | static int get_next_frame(mpg123_handle *mh) |
595 | } |
577 | { |
596 | 578 | /* We have some decoder ready, if the desired decoder has changed, |
|
597 | static int get_next_frame(mpg123_handle *mh) |
579 | it is OK to use the old one for ignoring frames and activating |
598 | { |
580 | the new one for real (decode_update()) after getting the frame. */ |
Line 619... | Line 601... | ||
619 | debug4("read of frame %li returned %i (to_decode=%i) at sample %li", (long)mh->num, b, mh->to_decode, (long)mpg123_tell(mh)); |
601 | debug4("read of frame %li returned %i (to_decode=%i) at sample %li", (long)mh->num, b, mh->to_decode, (long)mpg123_tell(mh)); |
620 | if(b == MPG123_NEED_MORE) return MPG123_NEED_MORE; /* need another call with data */ |
602 | if(b == MPG123_NEED_MORE) return MPG123_NEED_MORE; /* need another call with data */ |
621 | else if(b <= 0) |
603 | else if(b <= 0) |
622 | { |
604 | { |
623 | /* More sophisticated error control? */ |
605 | /* More sophisticated error control? */ |
624 | if(b==0 || mh->rdat.filepos == mh->rdat.filelen) |
606 | if(b==0 || (mh->rdat.filelen >= 0 && mh->rdat.filepos == mh->rdat.filelen)) |
625 | { /* We simply reached the end. */ |
607 | { /* We simply reached the end. */ |
626 | mh->track_frames = mh->num + 1; |
608 | mh->track_frames = mh->num + 1; |
627 | debug("What about updating/checking gapless sample count here?"); |
609 | debug("What about updating/checking gapless sample count here?"); |
628 | return MPG123_DONE; |
610 | return MPG123_DONE; |
629 | } |
611 | } |
Line 648... | Line 630... | ||
648 | } |
630 | } |
649 | } |
631 | } |
650 | /* Or, we are finally done and have a new frame. */ |
632 | /* Or, we are finally done and have a new frame. */ |
651 | else break; |
633 | else break; |
652 | } while(1); |
634 | } while(1); |
653 | /* When we start actually using the CRC, this could move into the loop... */ |
- | |
654 | /* A question of semantics ... should I fold start_frame and frame_number into firstframe/lastframe? */ |
- | |
655 | if(mh->lastframe >= 0 && mh->num > mh->lastframe) |
- | |
656 | { |
635 | |
657 | mh->to_decode = mh->to_ignore = FALSE; |
636 | /* If we reach this point, we got a new frame ready to be decoded. |
658 | return MPG123_DONE; |
637 | All other situations resulted in returns from the loop. */ |
659 | } |
- | |
660 | if(change) |
638 | if(change) |
661 | { |
639 | { |
662 | if(decode_update(mh) < 0) /* dito... */ |
640 | if(decode_update(mh) < 0) /* dito... */ |
663 | return MPG123_ERR; |
641 | return MPG123_ERR; |
Line 664... | Line 642... | ||
664 | 642 | ||
Line 665... | Line 643... | ||
665 | debug1("new format: %i", mh->new_format); |
643 | debug1("new format: %i", mh->new_format); |
666 | - | ||
667 | mh->decoder_change = 0; |
644 | |
668 | #ifdef GAPLESS |
645 | mh->decoder_change = 0; |
- | 646 | if(mh->fresh) |
|
669 | if(mh->fresh) |
647 | { |
670 | { |
648 | #ifdef GAPLESS |
671 | int b=0; |
649 | int b=0; |
672 | /* Prepare offsets for gapless decoding. */ |
650 | /* Prepare offsets for gapless decoding. */ |
673 | debug1("preparing gapless stuff with native rate %li", frame_freq(mh)); |
651 | debug1("preparing gapless stuff with native rate %li", frame_freq(mh)); |
- | 652 | frame_gapless_realinit(mh); |
|
674 | frame_gapless_realinit(mh); |
653 | frame_set_frameseek(mh, mh->num); |
- | 654 | #endif |
|
675 | frame_set_frameseek(mh, mh->num); |
655 | mh->fresh = 0; |
676 | mh->fresh = 0; |
656 | #ifdef GAPLESS |
677 | /* Could this possibly happen? With a real big gapless offset... */ |
657 | /* Could this possibly happen? With a real big gapless offset... */ |
678 | if(mh->num < mh->firstframe) b = get_next_frame(mh); |
- | |
679 | if(b < 0) return b; /* Could be error, need for more, new format... */ |
658 | if(mh->num < mh->firstframe) b = get_next_frame(mh); |
680 | } |
659 | if(b < 0) return b; /* Could be error, need for more, new format... */ |
- | 660 | #endif |
|
681 | #endif |
661 | } |
682 | } |
662 | } |
Line 683... | Line 663... | ||
683 | return MPG123_OK; |
663 | return MPG123_OK; |
- | 664 | } |
|
684 | } |
665 | |
685 | 666 | /* Assumption: A buffer full of zero samples can be constructed by repetition of this byte. |
|
686 | /* Assumption: A buffer full of zero samples can be constructed by repetition of this byte. |
667 | Oh, and it handles some format conversion. |
687 | Only to be used by decode_the_frame() ... */ |
668 | Only to be used by decode_the_frame() ... */ |
688 | static int zero_byte(mpg123_handle *fr) |
669 | static int zero_byte(mpg123_handle *fr) |
Line 696... | Line 677... | ||
696 | 677 | ||
697 | /* |
678 | /* |
698 | Not part of the api. This just decodes the frame and fills missing bits with zeroes. |
679 | Not part of the api. This just decodes the frame and fills missing bits with zeroes. |
699 | There can be frames that are broken and thus make do_layer() fail. |
680 | There can be frames that are broken and thus make do_layer() fail. |
700 | */ |
681 | */ |
701 | void decode_the_frame(mpg123_handle *fr) |
682 | static void decode_the_frame(mpg123_handle *fr) |
702 | { |
683 | { |
703 | size_t needed_bytes = samples_to_bytes(fr, frame_outs(fr, fr->num+1)-frame_outs(fr, fr->num)); |
684 | size_t needed_bytes = samples_to_storage(fr, frame_expect_outsamples(fr)); |
704 | fr->clip += (fr->do_layer)(fr); |
685 | fr->clip += (fr->do_layer)(fr); |
705 | /*fprintf(stderr, "frame %"OFF_P": got %"SIZE_P" / %"SIZE_P"\n", fr->num,(size_p)fr->buffer.fill, (size_p)needed_bytes);*/ |
686 | /*fprintf(stderr, "frame %"OFF_P": got %"SIZE_P" / %"SIZE_P"\n", fr->num,(size_p)fr->buffer.fill, (size_p)needed_bytes);*/ |
706 | /* There could be less data than promised. |
687 | /* There could be less data than promised. |
707 | Also, then debugging, we look out for coding errors that could result in _more_ data than expected. */ |
688 | Also, then debugging, we look out for coding errors that could result in _more_ data than expected. */ |
Line 734... | Line 715... | ||
734 | if(NOQUIET) |
715 | if(NOQUIET) |
735 | error2("I got _more_ bytes than expected (%"SIZE_P" / %"SIZE_P"), that should not be possible!", (size_p)fr->buffer.fill, (size_p)needed_bytes); |
716 | error2("I got _more_ bytes than expected (%"SIZE_P" / %"SIZE_P"), that should not be possible!", (size_p)fr->buffer.fill, (size_p)needed_bytes); |
736 | } |
717 | } |
737 | } |
718 | } |
738 | #endif |
719 | #endif |
739 | /* Handle unsigned output formats via reshifting after decode here. */ |
- | |
740 | #ifndef NO_32BIT |
- | |
741 | if(fr->af.encoding == MPG123_ENC_UNSIGNED_32) |
- | |
742 | { /* 32bit signed -> unsigned */ |
- | |
743 | size_t i; |
- | |
744 | int32_t *ssamples; |
720 | postprocess_buffer(fr); |
745 | uint32_t *usamples; |
- | |
746 | ssamples = (int32_t*)fr->buffer.data; |
- | |
747 | usamples = (uint32_t*)fr->buffer.data; |
- | |
748 | debug("converting output to unsigned 32 bit integer"); |
- | |
749 | for(i=0; i |
- | |
750 | { |
- | |
751 | /* Different strategy since we don't have a larger type at hand. |
- | |
752 | Also watch out for silly +-1 fun because integer constants are signed in C90! */ |
- | |
753 | if(ssamples[i] >= 0) |
- | |
754 | usamples[i] = (uint32_t)ssamples[i] + 2147483647+1; |
- | |
755 | /* The smalles value goes zero. */ |
- | |
756 | else if(ssamples[i] == ((int32_t)-2147483647-1)) |
- | |
757 | usamples[i] = 0; |
- | |
758 | /* Now -value is in the positive range of signed int ... so it's a possible value at all. */ |
- | |
759 | else |
- | |
760 | usamples[i] = (uint32_t)2147483647+1 - (uint32_t)(-ssamples[i]); |
- | |
761 | } |
721 | } |
- | 722 | ||
- | 723 | /* |
|
- | 724 | Decode the current frame into the frame structure's buffer, accessible at the location stored in |
|
- | 725 |
|
|
- | 726 | valid mp3 frame. The buffer contents will get lost on the next call to mpg123_framebyframe_next or mpg123_framebyframe_decode. |
|
- | 727 | returns |
|
- | 728 | MPG123_OK -- successfully decoded or ignored the frame, you get your output data or in case of ignored frames 0 bytes |
|
- | 729 | MPG123_DONE -- decoding finished, should not happen |
|
- | 730 | MPG123_ERR -- some error occured. |
|
- | 731 | MPG123_ERR_NULL -- audio or bytes are not pointing to valid storage addresses |
|
- | 732 | MPG123_BAD_HANDLE -- mh has not been initialized |
|
- | 733 | MPG123_NO_SPACE -- not enough space in buffer for safe decoding, should not happen |
|
- | 734 | */ |
|
- | 735 | int attribute_align_arg mpg123_framebyframe_decode(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes) |
|
- | 736 | { |
|
- | 737 | if(bytes == NULL) return MPG123_ERR_NULL; |
|
- | 738 | if(audio == NULL) return MPG123_ERR_NULL; |
|
- | 739 | if(mh == NULL) return MPG123_BAD_HANDLE; |
|
- | 740 | if(mh->buffer.size < mh->outblock) return MPG123_NO_SPACE; |
|
- | 741 | ||
- | 742 | *bytes = 0; |
|
- | 743 | mh->buffer.fill = 0; /* always start fresh */ |
|
- | 744 | if(!mh->to_decode) return MPG123_OK; |
|
- | 745 | ||
- | 746 | if(num != NULL) *num = mh->num; |
|
- | 747 | debug("decoding"); |
|
- | 748 | decode_the_frame(mh); |
|
- | 749 | mh->to_decode = mh->to_ignore = FALSE; |
|
- | 750 | mh->buffer.p = mh->buffer.data; |
|
- | 751 | FRAME_BUFFERCHECK(mh); |
|
- | 752 | *audio = mh->buffer.p; |
|
- | 753 | *bytes = mh->buffer.fill; |
|
- | 754 | return MPG123_OK; |
|
762 | } |
755 | } |
- | 756 | ||
763 | #endif |
757 | /* |
- | 758 | Find, read and parse the next mp3 frame while skipping junk and parsing id3 tags, lame headers, etc. |
|
- | 759 | Prepares everything for decoding using mpg123_framebyframe_decode. |
|
764 | #ifndef NO_16BIT |
760 | returns |
- | 761 | MPG123_OK -- new frame was read and parsed, call mpg123_framebyframe_decode to actually decode |
|
- | 762 | MPG123_NEW_FORMAT -- new frame was read, it results in changed output format, call mpg123_framebyframe_decode to actually decode |
|
765 | if(fr->af.encoding == MPG123_ENC_UNSIGNED_16) |
763 | MPG123_BAD_HANDLE -- mh has not been initialized |
- | 764 | MPG123_NEED_MORE -- more input data is needed to advance to the next frame. supply more input data using mpg123_feed |
|
- | 765 | */ |
|
- | 766 | int attribute_align_arg mpg123_framebyframe_next(mpg123_handle *mh) |
|
766 | { |
767 | { |
767 | size_t i; |
768 | int b; |
- | 769 | if(mh == NULL) return MPG123_BAD_HANDLE; |
|
- | 770 | ||
- | 771 | mh->to_decode = mh->to_ignore = FALSE; |
|
768 | short *ssamples; |
772 | mh->buffer.fill = 0; |
- | 773 | ||
769 | unsigned short *usamples; |
774 | b = get_next_frame(mh); |
770 | ssamples = (short*)fr->buffer.data; |
775 | if(b < 0) return b; |
771 | usamples = (unsigned short*)fr->buffer.data; |
776 | debug1("got next frame, %i", mh->to_decode); |
- | 777 | ||
772 | debug("converting output to unsigned 16 bit integer"); |
778 | /* mpg123_framebyframe_decode will return MPG123_OK with 0 bytes decoded if mh->to_decode is 0 */ |
- | 779 | if(!mh->to_decode) |
|
- | 780 | return MPG123_OK; |
|
- | 781 | ||
773 | for(i=0; i |
782 | if(mh->new_format) |
774 | { |
783 | { |
775 | long tmp = (long)ssamples[i]+32768; |
784 | debug("notifiying new format"); |
776 | usamples[i] = (unsigned short)tmp; |
785 | mh->new_format = 0; |
777 | } |
786 | return MPG123_NEW_FORMAT; |
778 | } |
787 | } |
- | 788 | ||
779 | #endif |
789 | return MPG123_OK; |
780 | } |
790 | } |
Line 781... | Line 791... | ||
781 | 791 | ||
782 | /* |
792 | /* |
783 | Put _one_ decoded frame into the frame structure's buffer, accessible at the location stored in |
793 | Put _one_ decoded frame into the frame structure's buffer, accessible at the location stored in |
Line 791... | Line 801... | ||
791 | 801 | ||
792 | num will be updated to the last decoded frame number (may possibly _not_ increase, p.ex. when format changed). |
802 | num will be updated to the last decoded frame number (may possibly _not_ increase, p.ex. when format changed). |
793 | */ |
803 | */ |
794 | int attribute_align_arg mpg123_decode_frame(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes) |
804 | int attribute_align_arg mpg123_decode_frame(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes) |
795 | { |
- | |
796 | ALIGNCHECK(mh); |
805 | { |
797 | if(bytes != NULL) *bytes = 0; |
806 | if(bytes != NULL) *bytes = 0; |
798 | if(mh == NULL) return MPG123_ERR; |
807 | if(mh == NULL) return MPG123_ERR; |
799 | if(mh->buffer.size < mh->outblock) return MPG123_NO_SPACE; |
808 | if(mh->buffer.size < mh->outblock) return MPG123_NO_SPACE; |
800 | mh->buffer.fill = 0; /* always start fresh */ |
809 | mh->buffer.fill = 0; /* always start fresh */ |
Line 814... | Line 823... | ||
814 | 823 | ||
Line 815... | Line 824... | ||
815 | decode_the_frame(mh); |
824 | decode_the_frame(mh); |
816 | 825 | ||
817 | mh->to_decode = mh->to_ignore = FALSE; |
- | |
818 | mh->buffer.p = mh->buffer.data; |
- | |
819 | #ifdef GAPLESS |
826 | mh->to_decode = mh->to_ignore = FALSE; |
820 | /* This checks for individual samples to skip, for gapless mode or sample-accurate seek. */ |
- | |
821 | frame_buffercheck(mh); |
827 | mh->buffer.p = mh->buffer.data; |
822 | #endif |
828 | FRAME_BUFFERCHECK(mh); |
Line 823... | Line 829... | ||
823 | if(audio != NULL) *audio = mh->buffer.p; |
829 | if(audio != NULL) *audio = mh->buffer.p; |
824 | if(bytes != NULL) *bytes = mh->buffer.fill; |
830 | if(bytes != NULL) *bytes = mh->buffer.fill; |
Line 840... | Line 846... | ||
840 | } |
846 | } |
Line 841... | Line 847... | ||
841 | 847 | ||
842 | int attribute_align_arg mpg123_feed(mpg123_handle *mh, const unsigned char *in, size_t size) |
848 | int attribute_align_arg mpg123_feed(mpg123_handle *mh, const unsigned char *in, size_t size) |
843 | { |
849 | { |
- | 850 | if(mh == NULL) return MPG123_ERR; |
|
844 | if(mh == NULL) return MPG123_ERR; |
851 | #ifndef NO_FEEDER |
845 | if(size > 0) |
852 | if(size > 0) |
846 | { |
853 | { |
847 | if(in != NULL) |
854 | if(in != NULL) |
848 | { |
855 | { |
- | 856 | if(feed_more(mh, in, size) != 0) return MPG123_ERR; |
|
- | 857 | else |
|
- | 858 | { |
|
- | 859 | /* The need for more data might have triggered an error. |
|
- | 860 | This one is outdated now with the new data. */ |
|
- | 861 | if(mh->err == MPG123_ERR_READER) mh->err = MPG123_OK; |
|
849 | if(feed_more(mh, in, size) != 0) return MPG123_ERR; |
862 | |
- | 863 | return MPG123_OK; |
|
850 | else return MPG123_OK; |
864 | } |
851 | } |
865 | } |
852 | else |
866 | else |
853 | { |
867 | { |
854 | mh->err = MPG123_NULL_BUFFER; |
868 | mh->err = MPG123_NULL_BUFFER; |
855 | return MPG123_ERR; |
869 | return MPG123_ERR; |
856 | } |
870 | } |
857 | } |
871 | } |
- | 872 | return MPG123_OK; |
|
- | 873 | #else |
|
- | 874 | mh->err = MPG123_MISSING_FEATURE; |
|
- | 875 | return MPG123_ERR; |
|
858 | return MPG123_OK; |
876 | #endif |
Line 859... | Line 877... | ||
859 | } |
877 | } |
860 | 878 | ||
861 | /* |
879 | /* |
Line 874... | Line 892... | ||
874 | 892 | ||
875 | int attribute_align_arg mpg123_decode(mpg123_handle *mh, const unsigned char *inmemory, size_t inmemsize, unsigned char *outmemory, size_t outmemsize, size_t *done) |
893 | int attribute_align_arg mpg123_decode(mpg123_handle *mh, const unsigned char *inmemory, size_t inmemsize, unsigned char *outmemory, size_t outmemsize, size_t *done) |
876 | { |
894 | { |
877 | int ret = MPG123_OK; |
895 | int ret = MPG123_OK; |
878 | size_t mdone = 0; |
- | |
- | 896 | size_t mdone = 0; |
|
879 | ALIGNCHECK(mh); |
897 | |
880 | if(done != NULL) *done = 0; |
898 | if(done != NULL) *done = 0; |
- | 899 | if(mh == NULL) return MPG123_ERR; |
|
881 | if(mh == NULL) return MPG123_ERR; |
900 | #ifndef NO_FEEDER |
882 | if(inmemsize > 0 && mpg123_feed(mh, inmemory, inmemsize) != MPG123_OK) |
901 | if(inmemsize > 0 && mpg123_feed(mh, inmemory, inmemsize) != MPG123_OK) |
883 | { |
902 | { |
884 | ret = MPG123_ERR; |
903 | ret = MPG123_ERR; |
885 | goto decodeend; |
904 | goto decodeend; |
Line 895... | Line 914... | ||
895 | { |
914 | { |
896 | if(mh->new_format) |
915 | if(mh->new_format) |
897 | { |
916 | { |
898 | debug("notifiying new format"); |
917 | debug("notifiying new format"); |
899 | mh->new_format = 0; |
918 | mh->new_format = 0; |
900 | return MPG123_NEW_FORMAT; |
919 | ret = MPG123_NEW_FORMAT; |
- | 920 | goto decodeend; |
|
901 | } |
921 | } |
902 | if(mh->buffer.size - mh->buffer.fill < mh->outblock) |
922 | if(mh->buffer.size - mh->buffer.fill < mh->outblock) |
903 | { |
923 | { |
904 | ret = MPG123_NO_SPACE; |
924 | ret = MPG123_NO_SPACE; |
905 | goto decodeend; |
925 | goto decodeend; |
906 | } |
926 | } |
907 | decode_the_frame(mh); |
927 | decode_the_frame(mh); |
908 | mh->to_decode = mh->to_ignore = FALSE; |
928 | mh->to_decode = mh->to_ignore = FALSE; |
909 | mh->buffer.p = mh->buffer.data; |
929 | mh->buffer.p = mh->buffer.data; |
910 | debug2("decoded frame %li, got %li samples in buffer", (long)mh->num, (long)(mh->buffer.fill / (samples_to_bytes(mh, 1)))); |
930 | debug2("decoded frame %li, got %li samples in buffer", (long)mh->num, (long)(mh->buffer.fill / (samples_to_bytes(mh, 1)))); |
911 | #ifdef GAPLESS |
- | |
912 | frame_buffercheck(mh); /* Seek & gapless. */ |
931 | FRAME_BUFFERCHECK(mh); |
913 | #endif |
- | |
914 | } |
932 | } |
915 | if(mh->buffer.fill) /* Copy (part of) the decoded data to the caller's buffer. */ |
933 | if(mh->buffer.fill) /* Copy (part of) the decoded data to the caller's buffer. */ |
916 | { |
934 | { |
917 | /* get what is needed - or just what is there */ |
935 | /* get what is needed - or just what is there */ |
918 | int a = mh->buffer.fill > (outmemsize - mdone) ? outmemsize - mdone : mh->buffer.fill; |
936 | int a = mh->buffer.fill > (outmemsize - mdone) ? outmemsize - mdone : mh->buffer.fill; |
Line 932... | Line 950... | ||
932 | } |
950 | } |
933 | } |
951 | } |
934 | decodeend: |
952 | decodeend: |
935 | if(done != NULL) *done = mdone; |
953 | if(done != NULL) *done = mdone; |
936 | return ret; |
954 | return ret; |
- | 955 | #else |
|
- | 956 | mh->err = MPG123_MISSING_FEATURE; |
|
- | 957 | return MPG123_ERR; |
|
- | 958 | #endif |
|
937 | } |
959 | } |
Line 938... | Line 960... | ||
938 | 960 | ||
939 | long attribute_align_arg mpg123_clip(mpg123_handle *mh) |
961 | long attribute_align_arg mpg123_clip(mpg123_handle *mh) |
940 | { |
962 | { |
941 | long ret = 0; |
- | |
- | 963 | long ret = 0; |
|
942 | ALIGNCHECK(mh); |
964 | |
943 | if(mh != NULL) |
965 | if(mh != NULL) |
944 | { |
966 | { |
945 | ret = mh->clip; |
967 | ret = mh->clip; |
946 | mh->clip = 0; |
968 | mh->clip = 0; |
947 | } |
969 | } |
948 | return ret; |
970 | return ret; |
Line -... | Line 971... | ||
- | 971 | } |
|
949 | } |
972 | |
Line 950... | Line 973... | ||
950 | 973 | /* Simples: Track needs initializtion if no initial frame has been read yet. */ |
|
951 | #define track_need_init(mh) (!(mh)->to_decode && (mh)->fresh) |
974 | #define track_need_init(mh) ((mh)->num < 0) |
952 | 975 | ||
953 | static int init_track(mpg123_handle *mh) |
976 | static int init_track(mpg123_handle *mh) |
Line 961... | Line 984... | ||
961 | return 0; |
984 | return 0; |
962 | } |
985 | } |
Line 963... | Line 986... | ||
963 | 986 | ||
964 | int attribute_align_arg mpg123_getformat(mpg123_handle *mh, long *rate, int *channels, int *encoding) |
987 | int attribute_align_arg mpg123_getformat(mpg123_handle *mh, long *rate, int *channels, int *encoding) |
965 | { |
988 | { |
- | 989 | int b; |
|
966 | ALIGNCHECK(mh); |
990 | |
- | 991 | if(mh == NULL) return MPG123_ERR; |
|
967 | if(mh == NULL) return MPG123_ERR; |
992 | b = init_track(mh); |
Line 968... | Line 993... | ||
968 | if(init_track(mh) == MPG123_ERR) return MPG123_ERR; |
993 | if(b < 0) return b; |
969 | 994 | ||
970 | if(rate != NULL) *rate = mh->af.rate; |
995 | if(rate != NULL) *rate = mh->af.rate; |
971 | if(channels != NULL) *channels = mh->af.channels; |
996 | if(channels != NULL) *channels = mh->af.channels; |
Line 975... | Line 1000... | ||
975 | } |
1000 | } |
Line 976... | Line 1001... | ||
976 | 1001 | ||
977 | off_t attribute_align_arg mpg123_timeframe(mpg123_handle *mh, double seconds) |
1002 | off_t attribute_align_arg mpg123_timeframe(mpg123_handle *mh, double seconds) |
978 | { |
1003 | { |
979 | off_t b; |
- | |
- | 1004 | off_t b; |
|
980 | ALIGNCHECK(mh); |
1005 | |
981 | if(mh == NULL) return MPG123_ERR; |
1006 | if(mh == NULL) return MPG123_ERR; |
982 | b = init_track(mh); |
1007 | b = init_track(mh); |
983 | if(b<0) return b; |
1008 | if(b<0) return b; |
984 | return (off_t)(seconds/mpg123_tpf(mh)); |
1009 | return (off_t)(seconds/mpg123_tpf(mh)); |
Line 992... | Line 1017... | ||
992 | Then, there is firstframe...when we didn't reach it yet, then the next data will come from there. |
1017 | Then, there is firstframe...when we didn't reach it yet, then the next data will come from there. |
993 | mh->num starts with -1 |
1018 | mh->num starts with -1 |
994 | */ |
1019 | */ |
995 | off_t attribute_align_arg mpg123_tell(mpg123_handle *mh) |
1020 | off_t attribute_align_arg mpg123_tell(mpg123_handle *mh) |
996 | { |
1021 | { |
997 | ALIGNCHECK(mh); |
- | |
998 | if(mh == NULL) return MPG123_ERR; |
1022 | if(mh == NULL) return MPG123_ERR; |
999 | if(track_need_init(mh)) return 0; |
1023 | if(track_need_init(mh)) return 0; |
1000 | /* Now we have all the info at hand. */ |
1024 | /* Now we have all the info at hand. */ |
1001 | debug5("tell: %li/%i first %li buffer %lu; frame_outs=%li", (long)mh->num, mh->to_decode, (long)mh->firstframe, (unsigned long)mh->buffer.fill, (long)frame_outs(mh, mh->num)); |
1025 | debug5("tell: %li/%i first %li buffer %lu; frame_outs=%li", (long)mh->num, mh->to_decode, (long)mh->firstframe, (unsigned long)mh->buffer.fill, (long)frame_outs(mh, mh->num)); |
Line 1016... | Line 1040... | ||
1016 | else |
1040 | else |
1017 | { /* We serve what we have in buffer and then the beginning of next frame... */ |
1041 | { /* We serve what we have in buffer and then the beginning of next frame... */ |
1018 | pos = frame_outs(mh, mh->num+1) - bytes_to_samples(mh, mh->buffer.fill); |
1042 | pos = frame_outs(mh, mh->num+1) - bytes_to_samples(mh, mh->buffer.fill); |
1019 | } |
1043 | } |
1020 | /* Substract padding and delay from the beginning. */ |
1044 | /* Substract padding and delay from the beginning. */ |
1021 | pos = SAMPLE_ADJUST(pos); |
1045 | pos = SAMPLE_ADJUST(mh,pos); |
1022 | /* Negative sample offsets are not right, less than nothing is still nothing. */ |
1046 | /* Negative sample offsets are not right, less than nothing is still nothing. */ |
1023 | return pos>0 ? pos : 0; |
1047 | return pos>0 ? pos : 0; |
1024 | } |
1048 | } |
1025 | } |
1049 | } |
Line 1026... | Line 1050... | ||
1026 | 1050 | ||
1027 | off_t attribute_align_arg mpg123_tellframe(mpg123_handle *mh) |
1051 | off_t attribute_align_arg mpg123_tellframe(mpg123_handle *mh) |
1028 | { |
- | |
1029 | ALIGNCHECK(mh); |
1052 | { |
1030 | if(mh == NULL) return MPG123_ERR; |
1053 | if(mh == NULL) return MPG123_ERR; |
1031 | if(mh->num < mh->firstframe) return mh->firstframe; |
1054 | if(mh->num < mh->firstframe) return mh->firstframe; |
1032 | if(mh->to_decode) return mh->num; |
1055 | if(mh->to_decode) return mh->num; |
1033 | /* Consider firstoff? */ |
1056 | /* Consider firstoff? */ |
1034 | return mh->buffer.fill ? mh->num : mh->num + 1; |
1057 | return mh->buffer.fill ? mh->num : mh->num + 1; |
Line 1035... | Line 1058... | ||
1035 | } |
1058 | } |
1036 | 1059 | ||
1037 | off_t attribute_align_arg mpg123_tell_stream(mpg123_handle *mh) |
- | |
1038 | { |
1060 | off_t attribute_align_arg mpg123_tell_stream(mpg123_handle *mh) |
1039 | ALIGNCHECK(mh); |
1061 | { |
1040 | if(mh == NULL) return MPG123_ERR; |
1062 | if(mh == NULL) return MPG123_ERR; |
1041 | /* mh->rd is at least a bad_reader, so no worry. */ |
1063 | /* mh->rd is at least a bad_reader, so no worry. */ |
Line 1068... | Line 1090... | ||
1068 | frame_buffers_reset(mh); |
1090 | frame_buffers_reset(mh); |
1069 | #ifndef NO_NTOM |
1091 | #ifndef NO_NTOM |
1070 | if(mh->down_sample == 3) |
1092 | if(mh->down_sample == 3) |
1071 | { |
1093 | { |
1072 | ntom_set_ntom(mh, fnum); |
1094 | ntom_set_ntom(mh, fnum); |
1073 | debug3("fixed ntom for frame %"OFF_P" to %lu, num=%"OFF_P, fnum, mh->ntom_val[0], mh->num); |
1095 | debug3("fixed ntom for frame %"OFF_P" to %lu, num=%"OFF_P, (off_p)fnum, mh->ntom_val[0], (off_p)mh->num); |
1074 | } |
1096 | } |
1075 | #endif |
1097 | #endif |
1076 | b = mh->rd->seek_frame(mh, fnum); |
1098 | b = mh->rd->seek_frame(mh, fnum); |
1077 | debug1("seek_frame returned: %i", b); |
1099 | debug1("seek_frame returned: %i", b); |
1078 | if(b<0) return b; |
1100 | if(b<0) return b; |
Line 1085... | Line 1107... | ||
1085 | 1107 | ||
1086 | off_t attribute_align_arg mpg123_seek(mpg123_handle *mh, off_t sampleoff, int whence) |
1108 | off_t attribute_align_arg mpg123_seek(mpg123_handle *mh, off_t sampleoff, int whence) |
1087 | { |
1109 | { |
1088 | int b; |
1110 | int b; |
1089 | off_t pos; |
- | |
- | 1111 | off_t pos; |
|
1090 | ALIGNCHECK(mh); |
1112 | |
1091 | pos = mpg123_tell(mh); /* adjusted samples */ |
1113 | pos = mpg123_tell(mh); /* adjusted samples */ |
1092 | /* pos < 0 also can mean that simply a former seek failed at the lower levels. |
1114 | /* pos < 0 also can mean that simply a former seek failed at the lower levels. |
1093 | In that case, we only allow absolute seeks. */ |
1115 | In that case, we only allow absolute seeks. */ |
1094 | if(pos < 0 && whence != SEEK_SET) |
1116 | if(pos < 0 && whence != SEEK_SET) |
Line 1103... | Line 1125... | ||
1103 | case SEEK_SET: pos = sampleoff; break; |
1125 | case SEEK_SET: pos = sampleoff; break; |
1104 | case SEEK_END: |
1126 | case SEEK_END: |
1105 | /* When we do not know the end already, we can try to find it. */ |
1127 | /* When we do not know the end already, we can try to find it. */ |
1106 | if(mh->track_frames < 1 && (mh->rdat.flags & READER_SEEKABLE)) |
1128 | if(mh->track_frames < 1 && (mh->rdat.flags & READER_SEEKABLE)) |
1107 | mpg123_scan(mh); |
1129 | mpg123_scan(mh); |
- | 1130 | if(mh->track_frames > 0) pos = SAMPLE_ADJUST(mh,frame_outs(mh, mh->track_frames)) - sampleoff; |
|
1108 | #ifdef GAPLESS |
1131 | #ifdef GAPLESS |
1109 | if(mh->end_os > 0) pos = SAMPLE_ADJUST(mh->end_os) - sampleoff; |
1132 | else if(mh->end_os > 0) pos = SAMPLE_ADJUST(mh,mh->end_os) - sampleoff; |
1110 | #else |
- | |
1111 | if(mh->track_frames > 0) pos = SAMPLE_ADJUST(frame_outs(mh, mh->track_frames)) - sampleoff; |
- | |
1112 | #endif |
1133 | #endif |
1113 | else |
1134 | else |
1114 | { |
1135 | { |
1115 | mh->err = MPG123_NO_SEEK_FROM_END; |
1136 | mh->err = MPG123_NO_SEEK_FROM_END; |
1116 | return MPG123_ERR; |
1137 | return MPG123_ERR; |
Line 1118... | Line 1139... | ||
1118 | break; |
1139 | break; |
1119 | default: mh->err = MPG123_BAD_WHENCE; return MPG123_ERR; |
1140 | default: mh->err = MPG123_BAD_WHENCE; return MPG123_ERR; |
1120 | } |
1141 | } |
1121 | if(pos < 0) pos = 0; |
1142 | if(pos < 0) pos = 0; |
1122 | /* pos now holds the wanted sample offset in adjusted samples */ |
1143 | /* pos now holds the wanted sample offset in adjusted samples */ |
1123 | frame_set_seek(mh, SAMPLE_UNADJUST(pos)); |
1144 | frame_set_seek(mh, SAMPLE_UNADJUST(mh,pos)); |
1124 | pos = do_the_seek(mh); |
1145 | pos = do_the_seek(mh); |
1125 | if(pos < 0) return pos; |
1146 | if(pos < 0) return pos; |
Line 1126... | Line 1147... | ||
1126 | 1147 | ||
1127 | return mpg123_tell(mh); |
1148 | return mpg123_tell(mh); |
Line 1135... | Line 1156... | ||
1135 | */ |
1156 | */ |
1136 | off_t attribute_align_arg mpg123_feedseek(mpg123_handle *mh, off_t sampleoff, int whence, off_t *input_offset) |
1157 | off_t attribute_align_arg mpg123_feedseek(mpg123_handle *mh, off_t sampleoff, int whence, off_t *input_offset) |
1137 | { |
1158 | { |
1138 | int b; |
1159 | int b; |
1139 | off_t pos; |
1160 | off_t pos; |
1140 | ALIGNCHECK(mh); |
- | |
- | 1161 | ||
1141 | pos = mpg123_tell(mh); /* adjusted samples */ |
1162 | pos = mpg123_tell(mh); /* adjusted samples */ |
1142 | debug3("seek from %li to %li (whence=%i)", (long)pos, (long)sampleoff, whence); |
1163 | debug3("seek from %li to %li (whence=%i)", (long)pos, (long)sampleoff, whence); |
1143 | /* The special seek error handling does not apply here... there is no lowlevel I/O. */ |
1164 | /* The special seek error handling does not apply here... there is no lowlevel I/O. */ |
1144 | if(pos < 0) return pos; /* mh == NULL is covered in mpg123_tell() */ |
1165 | if(pos < 0) return pos; /* mh == NULL is covered in mpg123_tell() */ |
- | 1166 | #ifndef NO_FEEDER |
|
1145 | if(input_offset == NULL) |
1167 | if(input_offset == NULL) |
1146 | { |
1168 | { |
1147 | mh->err = MPG123_NULL_POINTER; |
1169 | mh->err = MPG123_NULL_POINTER; |
1148 | return MPG123_ERR; |
1170 | return MPG123_ERR; |
1149 | } |
1171 | } |
Line 1153... | Line 1175... | ||
1153 | switch(whence) |
1175 | switch(whence) |
1154 | { |
1176 | { |
1155 | case SEEK_CUR: pos += sampleoff; break; |
1177 | case SEEK_CUR: pos += sampleoff; break; |
1156 | case SEEK_SET: pos = sampleoff; break; |
1178 | case SEEK_SET: pos = sampleoff; break; |
1157 | case SEEK_END: |
1179 | case SEEK_END: |
- | 1180 | if(mh->track_frames > 0) pos = SAMPLE_ADJUST(mh,frame_outs(mh, mh->track_frames)) - sampleoff; |
|
1158 | #ifdef GAPLESS |
1181 | #ifdef GAPLESS |
1159 | if(mh->end_os >= 0) pos = SAMPLE_ADJUST(mh->end_os) - sampleoff; |
1182 | else if(mh->end_os >= 0) pos = SAMPLE_ADJUST(mh,mh->end_os) - sampleoff; |
1160 | #else |
- | |
1161 | if(mh->track_frames > 0) pos = SAMPLE_ADJUST(frame_outs(mh, mh->track_frames)) - sampleoff; |
- | |
1162 | #endif |
1183 | #endif |
1163 | else |
1184 | else |
1164 | { |
1185 | { |
1165 | mh->err = MPG123_NO_SEEK_FROM_END; |
1186 | mh->err = MPG123_NO_SEEK_FROM_END; |
1166 | return MPG123_ERR; |
1187 | return MPG123_ERR; |
1167 | } |
1188 | } |
1168 | break; |
1189 | break; |
1169 | default: mh->err = MPG123_BAD_WHENCE; return MPG123_ERR; |
1190 | default: mh->err = MPG123_BAD_WHENCE; return MPG123_ERR; |
1170 | } |
1191 | } |
1171 | if(pos < 0) pos = 0; |
1192 | if(pos < 0) pos = 0; |
1172 | frame_set_seek(mh, SAMPLE_UNADJUST(pos)); |
1193 | frame_set_seek(mh, SAMPLE_UNADJUST(mh,pos)); |
1173 | pos = SEEKFRAME(mh); |
1194 | pos = SEEKFRAME(mh); |
1174 | mh->buffer.fill = 0; |
1195 | mh->buffer.fill = 0; |
Line 1175... | Line 1196... | ||
1175 | 1196 | ||
1176 | /* Shortcuts without modifying input stream. */ |
1197 | /* Shortcuts without modifying input stream. */ |
Line 1183... | Line 1204... | ||
1183 | mh->num = pos-1; /* The next read frame will have num = pos. */ |
1204 | mh->num = pos-1; /* The next read frame will have num = pos. */ |
1184 | if(*input_offset < 0) return MPG123_ERR; |
1205 | if(*input_offset < 0) return MPG123_ERR; |
Line 1185... | Line 1206... | ||
1185 | 1206 | ||
1186 | feedseekend: |
1207 | feedseekend: |
- | 1208 | return mpg123_tell(mh); |
|
- | 1209 | #else |
|
- | 1210 | mh->err = MPG123_MISSING_FEATURE; |
|
- | 1211 | return MPG123_ERR; |
|
1187 | return mpg123_tell(mh); |
1212 | #endif |
Line 1188... | Line 1213... | ||
1188 | } |
1213 | } |
1189 | 1214 | ||
1190 | off_t attribute_align_arg mpg123_seek_frame(mpg123_handle *mh, off_t offset, int whence) |
1215 | off_t attribute_align_arg mpg123_seek_frame(mpg123_handle *mh, off_t offset, int whence) |
1191 | { |
1216 | { |
1192 | int b; |
- | |
- | 1217 | int b; |
|
1193 | off_t pos = 0; |
1218 | off_t pos = 0; |
1194 | ALIGNCHECK(mh); |
1219 | |
Line 1195... | Line 1220... | ||
1195 | if(mh == NULL) return MPG123_ERR; |
1220 | if(mh == NULL) return MPG123_ERR; |
1196 | if((b=init_track(mh)) < 0) return b; |
1221 | if((b=init_track(mh)) < 0) return b; |
Line 1212... | Line 1237... | ||
1212 | default: |
1237 | default: |
1213 | mh->err = MPG123_BAD_WHENCE; |
1238 | mh->err = MPG123_BAD_WHENCE; |
1214 | return MPG123_ERR; |
1239 | return MPG123_ERR; |
1215 | } |
1240 | } |
1216 | if(pos < 0) pos = 0; |
1241 | if(pos < 0) pos = 0; |
1217 | /* Hm, do we need to seek right past the end? */ |
- | |
1218 | else if(mh->track_frames > 0 && pos >= mh->track_frames) pos = mh->track_frames; |
1242 | /* Not limiting the possible position on end for the chance that there might be more to the stream than announced via track_frames. */ |
Line 1219... | Line 1243... | ||
1219 | 1243 | ||
1220 | frame_set_frameseek(mh, pos); |
1244 | frame_set_frameseek(mh, pos); |
1221 | pos = do_the_seek(mh); |
1245 | pos = do_the_seek(mh); |
Line 1222... | Line 1246... | ||
1222 | if(pos < 0) return pos; |
1246 | if(pos < 0) return pos; |
1223 | 1247 | ||
Line 1224... | Line 1248... | ||
1224 | return mpg123_tellframe(mh); |
1248 | return mpg123_tellframe(mh); |
1225 | } |
1249 | } |
1226 | - | ||
1227 | int attribute_align_arg mpg123_set_filesize(mpg123_handle *mh, off_t size) |
1250 | |
Line 1228... | Line 1251... | ||
1228 | { |
1251 | int attribute_align_arg mpg123_set_filesize(mpg123_handle *mh, off_t size) |
1229 | ALIGNCHECK(mh); |
1252 | { |
1230 | if(mh == NULL) return MPG123_ERR; |
1253 | if(mh == NULL) return MPG123_ERR; |
Line 1231... | Line 1254... | ||
1231 | 1254 | ||
1232 | mh->rdat.filelen = size; |
1255 | mh->rdat.filelen = size; |
1233 | return MPG123_OK; |
1256 | return MPG123_OK; |
1234 | } |
1257 | } |
1235 | - | ||
- | 1258 | ||
1236 | off_t attribute_align_arg mpg123_length(mpg123_handle *mh) |
1259 | off_t attribute_align_arg mpg123_length(mpg123_handle *mh) |
1237 | { |
1260 | { |
1238 | int b; |
1261 | int b; |
1239 | off_t length; |
1262 | off_t length; |
1240 | ALIGNCHECK(mh); |
1263 | |
Line 1250... | Line 1273... | ||
1250 | length = (off_t)((double)(mh->rdat.filelen)/bpf*spf(mh)); |
1273 | length = (off_t)((double)(mh->rdat.filelen)/bpf*spf(mh)); |
1251 | } |
1274 | } |
1252 | else if(mh->rdat.filelen == 0) return mpg123_tell(mh); /* we could be in feeder mode */ |
1275 | else if(mh->rdat.filelen == 0) return mpg123_tell(mh); /* we could be in feeder mode */ |
1253 | else return MPG123_ERR; /* No length info there! */ |
1276 | else return MPG123_ERR; /* No length info there! */ |
Line -... | Line 1277... | ||
- | 1277 | ||
- | 1278 | debug1("mpg123_length: internal sample length: %"OFF_P, (off_p)length); |
|
1254 | 1279 | ||
1255 | length = frame_ins2outs(mh, length); |
- | |
1256 | #ifdef GAPLESS |
1280 | length = frame_ins2outs(mh, length); |
1257 | if(mh->end_os > 0 && length > mh->end_os) length = mh->end_os; |
1281 | debug1("mpg123_length: external sample length: %"OFF_P, (off_p)length); |
1258 | length -= mh->begin_os; |
- | |
1259 | #endif |
1282 | length = SAMPLE_ADJUST(mh,length); |
1260 | return length; |
1283 | return length; |
Line 1261... | Line 1284... | ||
1261 | } |
1284 | } |
1262 | 1285 | ||
1263 | int attribute_align_arg mpg123_scan(mpg123_handle *mh) |
1286 | int attribute_align_arg mpg123_scan(mpg123_handle *mh) |
1264 | { |
1287 | { |
1265 | int b; |
1288 | int b; |
1266 | off_t backframe; |
1289 | off_t oldpos; |
- | 1290 | off_t track_frames = 0; |
|
1267 | int to_decode, to_ignore; |
1291 | off_t track_samples = 0; |
1268 | ALIGNCHECK(mh); |
1292 | |
1269 | if(mh == NULL) return MPG123_ERR; |
1293 | if(mh == NULL) return MPG123_ERR; |
1270 | if(!(mh->rdat.flags & READER_SEEKABLE)){ mh->err = MPG123_NO_SEEK; return MPG123_ERR; } |
1294 | if(!(mh->rdat.flags & READER_SEEKABLE)){ mh->err = MPG123_NO_SEEK; return MPG123_ERR; } |
1271 | /* Scan through the _whole_ file, since the current position is no count but computed assuming constant samples per frame. */ |
1295 | /* Scan through the _whole_ file, since the current position is no count but computed assuming constant samples per frame. */ |
Line 1275... | Line 1299... | ||
1275 | if(b<0) |
1299 | if(b<0) |
1276 | { |
1300 | { |
1277 | if(b == MPG123_DONE) return MPG123_OK; |
1301 | if(b == MPG123_DONE) return MPG123_OK; |
1278 | else return MPG123_ERR; /* Must be error here, NEED_MORE is not for seekable streams. */ |
1302 | else return MPG123_ERR; /* Must be error here, NEED_MORE is not for seekable streams. */ |
1279 | } |
1303 | } |
1280 | backframe = mh->num; |
- | |
1281 | to_decode = mh->to_decode; |
1304 | oldpos = mpg123_tell(mh); |
1282 | to_ignore = mh->to_ignore; |
- | |
1283 | b = mh->rd->seek_frame(mh, 0); |
1305 | b = mh->rd->seek_frame(mh, 0); |
1284 | if(b<0 || mh->num != 0) return MPG123_ERR; |
1306 | if(b<0 || mh->num != 0) return MPG123_ERR; |
1285 | /* One frame must be there now. */ |
1307 | /* One frame must be there now. */ |
1286 | mh->track_frames = 1; |
1308 | track_frames = 1; |
1287 | mh->track_samples = spf(mh); /* Internal samples. */ |
1309 | track_samples = spf(mh); /* Internal samples. */ |
- | 1310 | debug("TODO: We should disable gapless code when encountering inconsistent spf(mh)!"); |
|
- | 1311 | /* Do not increment mh->track_frames in the loop as tha would confuse Frankenstein detection. */ |
|
1288 | while(read_frame(mh) == 1) |
1312 | while(read_frame(mh) == 1) |
1289 | { |
1313 | { |
1290 | ++mh->track_frames; |
1314 | ++track_frames; |
1291 | mh->track_samples += spf(mh); |
1315 | track_samples += spf(mh); |
1292 | } |
1316 | } |
- | 1317 | mh->track_frames = track_frames; |
|
- | 1318 | mh->track_samples = track_samples; |
|
- | 1319 | mpg123_seek_frame(mh, SEEK_SET, mh->track_frames); |
|
- | 1320 | debug2("Scanning yielded %"OFF_P" track samples, %"OFF_P" frames.", (off_p)mh->track_samples, (off_p)mh->track_frames); |
|
1293 | #ifdef GAPLESS |
1321 | #ifdef GAPLESS |
1294 | /* Also, think about usefulness of that extra value track_samples ... it could be used for consistency checking. */ |
1322 | /* Also, think about usefulness of that extra value track_samples ... it could be used for consistency checking. */ |
1295 | frame_gapless_update(mh, mh->track_samples); |
1323 | frame_gapless_update(mh, mh->track_samples); |
1296 | #endif |
1324 | #endif |
1297 | b = mh->rd->seek_frame(mh, backframe); |
- | |
1298 | if(b<0 || mh->num != backframe) return MPG123_ERR; |
1325 | return mpg123_seek(mh, oldpos, SEEK_SET) >= 0 ? MPG123_OK : MPG123_ERR; |
1299 | mh->to_decode = to_decode; |
- | |
1300 | mh->to_ignore = to_ignore; |
- | |
1301 | return MPG123_OK; |
- | |
1302 | } |
1326 | } |
Line 1303... | Line 1327... | ||
1303 | 1327 | ||
1304 | int attribute_align_arg mpg123_meta_check(mpg123_handle *mh) |
1328 | int attribute_align_arg mpg123_meta_check(mpg123_handle *mh) |
1305 | { |
1329 | { |
1306 | if(mh != NULL) return mh->metaflags; |
1330 | if(mh != NULL) return mh->metaflags; |
1307 | else return 0; |
1331 | else return 0; |
Line -... | Line 1332... | ||
- | 1332 | } |
|
- | 1333 | ||
- | 1334 | void attribute_align_arg mpg123_meta_free(mpg123_handle *mh) |
|
- | 1335 | { |
|
- | 1336 | if(mh == NULL) return; |
|
- | 1337 | ||
- | 1338 | reset_id3(mh); |
|
- | 1339 | reset_icy(&mh->icy); |
|
1308 | } |
1340 | } |
1309 | 1341 | ||
1310 | int attribute_align_arg mpg123_id3(mpg123_handle *mh, mpg123_id3v1 **v1, mpg123_id3v2 **v2) |
- | |
1311 | { |
1342 | int attribute_align_arg mpg123_id3(mpg123_handle *mh, mpg123_id3v1 **v1, mpg123_id3v2 **v2) |
1312 | ALIGNCHECK(mh); |
1343 | { |
1313 | if(v1 != NULL) *v1 = NULL; |
1344 | if(v1 != NULL) *v1 = NULL; |
Line 1314... | Line 1345... | ||
1314 | if(v2 != NULL) *v2 = NULL; |
1345 | if(v2 != NULL) *v2 = NULL; |
Line 1331... | Line 1362... | ||
1331 | return MPG123_OK; |
1362 | return MPG123_OK; |
1332 | } |
1363 | } |
Line 1333... | Line 1364... | ||
1333 | 1364 | ||
1334 | int attribute_align_arg mpg123_icy(mpg123_handle *mh, char **icy_meta) |
1365 | int attribute_align_arg mpg123_icy(mpg123_handle *mh, char **icy_meta) |
1335 | { |
- | |
1336 | ALIGNCHECK(mh); |
1366 | { |
1337 | if(mh == NULL) return MPG123_ERR; |
1367 | if(mh == NULL) return MPG123_ERR; |
1338 | #ifndef NO_ICY |
1368 | #ifndef NO_ICY |
1339 | if(icy_meta == NULL) |
1369 | if(icy_meta == NULL) |
1340 | { |
1370 | { |
Line 1354... | Line 1384... | ||
1354 | mh->err = MPG123_MISSING_FEATURE; |
1384 | mh->err = MPG123_MISSING_FEATURE; |
1355 | return MPG123_ERR; |
1385 | return MPG123_ERR; |
1356 | #endif |
1386 | #endif |
1357 | } |
1387 | } |
Line 1358... | Line -... | ||
1358 | - | ||
1359 | /* |
- | |
1360 | Simple utility functions that do not possibly call code with extra alignment requirements do not use the ALIGNCHECK. |
- | |
1361 | 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. |
- | |
1362 | */ |
- | |
1363 | 1388 | ||
1364 | char* attribute_align_arg mpg123_icy2utf8(const char* icy_text) |
1389 | char* attribute_align_arg mpg123_icy2utf8(const char* icy_text) |
1365 | { |
1390 | { |
1366 | #ifndef NO_ICY |
1391 | #ifndef NO_ICY |
1367 | return icy2utf8(icy_text, 0); |
1392 | return icy2utf8(icy_text, 0); |
Line 1433... | Line 1458... | ||
1433 | } |
1458 | } |
1434 | #endif |
1459 | #endif |
Line 1435... | Line 1460... | ||
1435 | 1460 | ||
1436 | int attribute_align_arg mpg123_index(mpg123_handle *mh, off_t **offsets, off_t *step, size_t *fill) |
1461 | int attribute_align_arg mpg123_index(mpg123_handle *mh, off_t **offsets, off_t *step, size_t *fill) |
1437 | { |
- | |
1438 | ALIGNCHECK(mh); |
1462 | { |
1439 | if(mh == NULL) return MPG123_ERR; |
1463 | if(mh == NULL) return MPG123_ERR; |
1440 | if(offsets == NULL || step == NULL || fill == NULL) |
1464 | if(offsets == NULL || step == NULL || fill == NULL) |
1441 | { |
1465 | { |
1442 | mh->err = MPG123_BAD_INDEX_PAR; |
1466 | mh->err = MPG123_BAD_INDEX_PAR; |
Line 1452... | Line 1476... | ||
1452 | *fill = 0; |
1476 | *fill = 0; |
1453 | #endif |
1477 | #endif |
1454 | return MPG123_OK; |
1478 | return MPG123_OK; |
1455 | } |
1479 | } |
Line -... | Line 1480... | ||
- | 1480 | ||
- | 1481 | int attribute_align_arg mpg123_set_index(mpg123_handle *mh, off_t *offsets, off_t step, size_t fill) |
|
- | 1482 | { |
|
- | 1483 | if(mh == NULL) return MPG123_ERR; |
|
- | 1484 | #ifdef FRAME_INDEX |
|
- | 1485 | if(step == 0) |
|
- | 1486 | { |
|
- | 1487 | mh->err = MPG123_BAD_INDEX_PAR; |
|
- | 1488 | return MPG123_ERR; |
|
- | 1489 | } |
|
- | 1490 | if(fi_set(&mh->index, offsets, step, fill) == -1) |
|
- | 1491 | { |
|
- | 1492 | mh->err = MPG123_OUT_OF_MEM; |
|
- | 1493 | return MPG123_ERR; |
|
- | 1494 | } |
|
- | 1495 | return MPG123_OK; |
|
- | 1496 | #else |
|
- | 1497 | mh->err = MPG123_MISSING_FEATURE; |
|
- | 1498 | return MPG123_ERR; |
|
- | 1499 | #endif |
|
- | 1500 | } |
|
1456 | 1501 | ||
1457 | int attribute_align_arg mpg123_close(mpg123_handle *mh) |
1502 | int attribute_align_arg mpg123_close(mpg123_handle *mh) |
1458 | { |
- | |
1459 | ALIGNCHECK(mh); |
1503 | { |
- | 1504 | if(mh == NULL) return MPG123_ERR; |
|
- | 1505 | ||
1460 | if(mh == NULL) return MPG123_ERR; |
1506 | /* mh->rd is never NULL! */ |
1461 | if(mh->rd != NULL && mh->rd->close != NULL) mh->rd->close(mh); |
1507 | if(mh->rd->close != NULL) mh->rd->close(mh); |
1462 | mh->rd = NULL; |
1508 | |
1463 | if(mh->new_format) |
1509 | if(mh->new_format) |
1464 | { |
1510 | { |
1465 | debug("Hey, we are closing a track before the new format has been queried..."); |
1511 | debug("Hey, we are closing a track before the new format has been queried..."); |
1466 | invalidate_format(&mh->af); |
1512 | invalidate_format(&mh->af); |
1467 | mh->new_format = 0; |
1513 | mh->new_format = 0; |
- | 1514 | } |
|
- | 1515 | /* Always reset the frame buffers on close, so we cannot forget it in funky opening routines (wrappers, even). */ |
|
1468 | } |
1516 | frame_reset(mh); |
1469 | return MPG123_OK; |
1517 | return MPG123_OK; |
Line 1470... | Line 1518... | ||
1470 | } |
1518 | } |
1471 | 1519 | ||
Line 1520... | Line 1568... | ||
1520 | "Frame index operation failed.", |
1568 | "Frame index operation failed.", |
1521 | "Decoder setup failed (invalid combination of settings?)", |
1569 | "Decoder setup failed (invalid combination of settings?)", |
1522 | "Feature not in this build." |
1570 | "Feature not in this build." |
1523 | ,"Some bad value has been provided." |
1571 | ,"Some bad value has been provided." |
1524 | ,"Low-level seeking has failed (call to lseek(), usually)." |
1572 | ,"Low-level seeking has failed (call to lseek(), usually)." |
- | 1573 | ,"Custom I/O obviously not prepared." |
|
- | 1574 | ,"Overflow in LFS (large file support) conversion." |
|
- | 1575 | ,"Overflow in integer conversion." |
|
1525 | }; |
1576 | }; |
Line 1526... | Line 1577... | ||
1526 | 1577 | ||
1527 | const char* attribute_align_arg mpg123_plain_strerror(int errcode) |
1578 | const char* attribute_align_arg mpg123_plain_strerror(int errcode) |
1528 | { |
1579 | { |