Mercurial > SDL_sound_CoreAudio
comparison decoders/libmpg123/readers.c @ 562:7e08477b0fc1
MP3 decoder upgrade work.
Ripped out SMPEG and mpglib support, replaced it with "mpg123.c" and libmpg123.
libmpg123 is a much better version of mpglib, so it should solve all the
problems about MP3's not seeking, or most modern MP3's not playing at all,
etc. Since you no longer have to make a tradeoff with SMPEG for features, and
SMPEG is basically rotting, I removed it from the project.
There is still work to be done with libmpg123...there are MMX, 3DNow, SSE,
Altivec, etc decoders which we don't have enabled at the moment, and the
build system could use some work to make this compile more cleanly, etc.
Still: huge win.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Fri, 30 Jan 2009 02:44:47 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
561:f2985e08589c | 562:7e08477b0fc1 |
---|---|
1 /* TODO: Check all read calls (in loops, especially!) for return value 0 (EOF)! */ | |
2 | |
3 /* | |
4 readers.c: reading input data | |
5 | |
6 copyright ?-2008 by the mpg123 project - free software under the terms of the LGPL 2.1 | |
7 see COPYING and AUTHORS files in distribution or http://mpg123.org | |
8 initially written by Michael Hipp | |
9 */ | |
10 | |
11 #include "mpg123lib_intern.h" | |
12 #include <sys/stat.h> | |
13 #include <fcntl.h> | |
14 #include <errno.h> | |
15 /* For select(), I need select.h according to POSIX 2001, else: sys/time.h sys/types.h unistd.h */ | |
16 /* Including these here although it works without on my Linux install... curious about _why_. */ | |
17 #ifdef HAVE_SYS_SELECT_H | |
18 #include <sys/select.h> | |
19 #endif | |
20 #ifdef HAVE_SYS_TIME_H | |
21 #include <sys/time.h> | |
22 #endif | |
23 #ifdef HAVE_SYS_TYPES_H | |
24 #include <sys/types.h> | |
25 #endif | |
26 #ifdef HAVE_UNISTD_H | |
27 #include <unistd.h> | |
28 #endif | |
29 #ifdef _MSC_VER | |
30 #include <io.h> | |
31 #endif | |
32 | |
33 #include "debug.h" | |
34 | |
35 static int default_init(mpg123_handle *fr); | |
36 static off_t get_fileinfo(mpg123_handle *); | |
37 static ssize_t posix_read(int fd, void *buf, size_t count){ return read(fd, buf, count); } | |
38 static off_t posix_lseek(int fd, off_t offset, int whence){ return lseek(fd, offset, whence); } | |
39 | |
40 static ssize_t plain_fullread(mpg123_handle *fr,unsigned char *buf, ssize_t count); | |
41 | |
42 /* Bufferchain methods. */ | |
43 static void bc_init(struct bufferchain *bc); | |
44 static void bc_reset(struct bufferchain *bc); | |
45 static int bc_append(struct bufferchain *bc, ssize_t size); | |
46 #if 0 | |
47 static void bc_drop(struct bufferchain *bc); | |
48 #endif | |
49 static int bc_add(struct bufferchain *bc, const unsigned char *data, ssize_t size); | |
50 static ssize_t bc_give(struct bufferchain *bc, unsigned char *out, size_t size); | |
51 static ssize_t bc_skip(struct bufferchain *bc, ssize_t count); | |
52 static ssize_t bc_seekback(struct bufferchain *bc, ssize_t count); | |
53 static void bc_forget(struct bufferchain *bc); | |
54 | |
55 /* A normal read and a read with timeout. */ | |
56 static ssize_t plain_read(mpg123_handle *fr, void *buf, size_t count) | |
57 { | |
58 ssize_t ret = fr->rdat.read(fr->rdat.filept, buf, count); | |
59 if(VERBOSE3) debug2("read %li bytes of %li", (long)ret, (long)count); | |
60 return ret; | |
61 } | |
62 #ifndef WIN32 | |
63 | |
64 /* Wait for data becoming available, allowing soft-broken network connection to die | |
65 This is needed for Shoutcast servers that have forgotten about us while connection was temporarily down. */ | |
66 static ssize_t timeout_read(mpg123_handle *fr, void *buf, size_t count) | |
67 { | |
68 struct timeval tv; | |
69 ssize_t ret = 0; | |
70 fd_set fds; | |
71 tv.tv_sec = fr->rdat.timeout_sec; | |
72 tv.tv_usec = 0; | |
73 FD_ZERO(&fds); | |
74 FD_SET(fr->rdat.filept, &fds); | |
75 ret = select(fr->rdat.filept+1, &fds, NULL, NULL, &tv); | |
76 /* This works only with "my" read function. Not user-replaced. */ | |
77 if(ret > 0) ret = read(fr->rdat.filept, buf, count); | |
78 else | |
79 { | |
80 ret=-1; /* no activity is the error */ | |
81 if(NOQUIET) error("stream timed out"); | |
82 } | |
83 return ret; | |
84 } | |
85 #endif | |
86 | |
87 /* stream based operation with icy meta data*/ | |
88 static ssize_t icy_fullread(mpg123_handle *fr, unsigned char *buf, ssize_t count) | |
89 { | |
90 ssize_t ret,cnt; | |
91 cnt = 0; | |
92 if(fr->rdat.flags & READER_SEEKABLE) | |
93 { | |
94 if(NOQUIET) error("mpg123 programmer error: I don't do ICY on seekable streams."); | |
95 return -1; | |
96 } | |
97 /* | |
98 We check against READER_ID3TAG instead of rds->filelen >= 0 because if we got the ID3 TAG we know we have the end of the file. | |
99 If we don't have an ID3 TAG, then it is possible the file has grown since we started playing, so we want to keep reading from it if possible. | |
100 */ | |
101 if((fr->rdat.flags & READER_ID3TAG) && fr->rdat.filepos + count > fr->rdat.filelen) count = fr->rdat.filelen - fr->rdat.filepos; | |
102 | |
103 while(cnt < count) | |
104 { | |
105 /* all icy code is inside this if block, everything else is the plain fullread we know */ | |
106 /* debug1("read: %li left", (long) count-cnt); */ | |
107 if(fr->icy.next < count-cnt) | |
108 { | |
109 unsigned char temp_buff; | |
110 size_t meta_size; | |
111 ssize_t cut_pos; | |
112 | |
113 /* we are near icy-metaint boundary, read up to the boundary */ | |
114 if(fr->icy.next > 0) | |
115 { | |
116 cut_pos = fr->icy.next; | |
117 ret = fr->rdat.fdread(fr,buf,cut_pos); | |
118 if(ret < 1) | |
119 { | |
120 if(ret == 0) break; /* Just EOF. */ | |
121 if(NOQUIET) error("icy boundary read"); | |
122 | |
123 return READER_ERROR; | |
124 } | |
125 fr->rdat.filepos += ret; | |
126 cnt += ret; | |
127 fr->icy.next -= ret; | |
128 if(fr->icy.next > 0) | |
129 { | |
130 debug1("another try... still %li left", (long)fr->icy.next); | |
131 continue; | |
132 } | |
133 } | |
134 /* now off to read icy data */ | |
135 | |
136 /* one byte icy-meta size (must be multiplied by 16 to get icy-meta length) */ | |
137 | |
138 ret = fr->rdat.fdread(fr,&temp_buff,1); /* Getting one single byte hast to suceed. */ | |
139 if(ret < 0){ if(NOQUIET) error("reading icy size"); return READER_ERROR; } | |
140 if(ret == 0) break; | |
141 | |
142 debug2("got meta-size byte: %u, at filepos %li", temp_buff, (long)fr->rdat.filepos ); | |
143 if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret; /* 1... */ | |
144 | |
145 if((meta_size = ((size_t) temp_buff) * 16)) | |
146 { | |
147 /* we have got some metadata */ | |
148 char *meta_buff; | |
149 meta_buff = malloc(meta_size+1); | |
150 if(meta_buff != NULL) | |
151 { | |
152 ssize_t left = meta_size; | |
153 while(left > 0) | |
154 { | |
155 ret = fr->rdat.fdread(fr,meta_buff+meta_size-left,left); | |
156 /* 0 is error here, too... there _must_ be the ICY data, the server promised! */ | |
157 if(ret < 1){ if(NOQUIET) error("reading icy-meta"); return READER_ERROR; } | |
158 left -= ret; | |
159 } | |
160 meta_buff[meta_size] = 0; /* string paranoia */ | |
161 if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret; | |
162 | |
163 if(fr->icy.data) free(fr->icy.data); | |
164 fr->icy.data = meta_buff; | |
165 fr->metaflags |= MPG123_NEW_ICY; | |
166 debug2("icy-meta: %s size: %d bytes", fr->icy.data, (int)meta_size); | |
167 } | |
168 else | |
169 { | |
170 if(NOQUIET) error1("cannot allocate memory for meta_buff (%lu bytes) ... trying to skip the metadata!", (unsigned long)meta_size); | |
171 fr->rd->skip_bytes(fr, meta_size); | |
172 } | |
173 } | |
174 fr->icy.next = fr->icy.interval; | |
175 } | |
176 | |
177 ret = plain_fullread(fr, buf+cnt, count-cnt); | |
178 if(ret < 0){ if(NOQUIET) error1("reading the rest of %li", (long)(count-cnt)); return READER_ERROR; } | |
179 if(ret == 0) break; | |
180 | |
181 cnt += ret; | |
182 fr->icy.next -= ret; | |
183 } | |
184 /* debug1("done reading, got %li", (long)cnt); */ | |
185 return cnt; | |
186 } | |
187 | |
188 /* stream based operation */ | |
189 static ssize_t plain_fullread(mpg123_handle *fr,unsigned char *buf, ssize_t count) | |
190 { | |
191 ssize_t ret,cnt=0; | |
192 | |
193 /* | |
194 We check against READER_ID3TAG instead of rds->filelen >= 0 because if we got the ID3 TAG we know we have the end of the file. | |
195 If we don't have an ID3 TAG, then it is possible the file has grown since we started playing, so we want to keep reading from it if possible. | |
196 */ | |
197 if((fr->rdat.flags & READER_ID3TAG) && fr->rdat.filepos + count > fr->rdat.filelen) count = fr->rdat.filelen - fr->rdat.filepos; | |
198 while(cnt < count) | |
199 { | |
200 ret = fr->rdat.fdread(fr,buf+cnt,count-cnt); | |
201 if(ret < 0) return READER_ERROR; | |
202 if(ret == 0) break; | |
203 if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret; | |
204 cnt += ret; | |
205 } | |
206 return cnt; | |
207 } | |
208 | |
209 static off_t stream_lseek(mpg123_handle *fr, off_t pos, int whence) | |
210 { | |
211 off_t ret; | |
212 ret = fr->rdat.lseek(fr->rdat.filept, pos, whence); | |
213 if (ret >= 0) fr->rdat.filepos = ret; | |
214 else ret = READER_ERROR; /* not the original value */ | |
215 return ret; | |
216 } | |
217 | |
218 static void stream_close(mpg123_handle *fr) | |
219 { | |
220 if(fr->rdat.flags & READER_FD_OPENED) close(fr->rdat.filept); | |
221 if(fr->rdat.flags & READER_BUFFERED) bc_reset(&fr->rdat.buffer); | |
222 } | |
223 | |
224 static int stream_seek_frame(mpg123_handle *fr, off_t newframe) | |
225 { | |
226 if(fr->rdat.flags & READER_SEEKABLE) | |
227 { | |
228 off_t preframe; | |
229 | |
230 /* two leading frames? hm, doesn't seem to be really needed... */ | |
231 /*if(newframe > 1) newframe -= 2; | |
232 else newframe = 0;*/ | |
233 | |
234 /* now seek to nearest leading index position and read from there until newframe is reached */ | |
235 if(stream_lseek(fr,frame_index_find(fr, newframe, &preframe),SEEK_SET) < 0) | |
236 return READER_ERROR; | |
237 debug2("going to %lu; just got %lu", (long unsigned)newframe, (long unsigned)preframe); | |
238 fr->num = preframe-1; /* Watch out! I am going to read preframe... fr->num should indicate the frame before! */ | |
239 while(fr->num < newframe) | |
240 { | |
241 /* try to be non-fatal now... frameNum only gets advanced on success anyway */ | |
242 if(!read_frame(fr)) break; | |
243 } | |
244 /* Now the wanted frame should be ready for decoding. */ | |
245 | |
246 /* I think, I don't want this... | |
247 if(fr->lay == 3) set_pointer(fr, 512); */ | |
248 | |
249 debug1("arrived at %lu", (long unsigned)fr->num); | |
250 | |
251 return MPG123_OK; | |
252 } | |
253 else return READER_ERROR; /* invalid, no seek happened */ | |
254 } | |
255 | |
256 /* return FALSE on error, TRUE on success, READER_MORE on occasion */ | |
257 static int generic_head_read(mpg123_handle *fr,unsigned long *newhead) | |
258 { | |
259 unsigned char hbuf[4]; | |
260 int ret = fr->rd->fullread(fr,hbuf,4); | |
261 if(ret == READER_MORE) return ret; | |
262 if(ret != 4) return FALSE; | |
263 | |
264 *newhead = ((unsigned long) hbuf[0] << 24) | | |
265 ((unsigned long) hbuf[1] << 16) | | |
266 ((unsigned long) hbuf[2] << 8) | | |
267 (unsigned long) hbuf[3]; | |
268 | |
269 return TRUE; | |
270 } | |
271 | |
272 /* return FALSE on error, TRUE on success, READER_MORE on occasion */ | |
273 static int generic_head_shift(mpg123_handle *fr,unsigned long *head) | |
274 { | |
275 unsigned char hbuf; | |
276 int ret = fr->rd->fullread(fr,&hbuf,1); | |
277 if(ret == READER_MORE) return ret; | |
278 if(ret != 1) return FALSE; | |
279 | |
280 *head <<= 8; | |
281 *head |= hbuf; | |
282 *head &= 0xffffffff; | |
283 return TRUE; | |
284 } | |
285 | |
286 /* returns reached position... negative ones are bad... */ | |
287 static off_t stream_skip_bytes(mpg123_handle *fr,off_t len) | |
288 { | |
289 if(fr->rdat.flags & READER_SEEKABLE) | |
290 { | |
291 off_t ret = stream_lseek(fr, len, SEEK_CUR); | |
292 | |
293 return ret<0 ? READER_ERROR : ret; | |
294 } | |
295 else if(len >= 0) | |
296 { | |
297 unsigned char buf[1024]; /* ThOr: Compaq cxx complained and it makes sense to me... or should one do a cast? What for? */ | |
298 ssize_t ret; | |
299 while (len > 0) | |
300 { | |
301 ssize_t num = len < (off_t)sizeof(buf) ? (ssize_t)len : (ssize_t)sizeof(buf); | |
302 ret = fr->rd->fullread(fr, buf, num); | |
303 if (ret < 0) return ret; | |
304 else if(ret == 0) break; /* EOF... an error? interface defined to tell the actual position... */ | |
305 len -= ret; | |
306 } | |
307 return fr->rd->tell(fr); | |
308 } | |
309 else if(fr->rdat.flags & READER_BUFFERED) | |
310 { /* Perhaps we _can_ go a bit back. */ | |
311 if(fr->rdat.buffer.pos >= -len) | |
312 { | |
313 fr->rdat.buffer.pos += len; | |
314 return fr->rd->tell(fr); | |
315 } | |
316 else return READER_ERROR; | |
317 } | |
318 else return READER_ERROR; | |
319 } | |
320 | |
321 /* Return 0 on success... */ | |
322 static int stream_back_bytes(mpg123_handle *fr, off_t bytes) | |
323 { | |
324 off_t want = fr->rd->tell(fr)-bytes; | |
325 if(want < 0) return READER_ERROR; | |
326 if(stream_skip_bytes(fr,-bytes) != want) return READER_ERROR; | |
327 | |
328 return 0; | |
329 } | |
330 | |
331 | |
332 /* returns size on success... */ | |
333 static int generic_read_frame_body(mpg123_handle *fr,unsigned char *buf, int size) | |
334 { | |
335 long l; | |
336 | |
337 if((l=fr->rd->fullread(fr,buf,size)) != size) | |
338 { | |
339 long ll = l; | |
340 if(ll <= 0) ll = 0; | |
341 | |
342 /* This allows partial frames at the end... do we really want to pad and decode these?! */ | |
343 memset(buf+ll,0,size-ll); | |
344 } | |
345 return l; | |
346 } | |
347 | |
348 static off_t generic_tell(mpg123_handle *fr) | |
349 { | |
350 if(fr->rdat.flags & READER_BUFFERED) | |
351 fr->rdat.filepos = fr->rdat.buffer.fileoff+fr->rdat.buffer.pos; | |
352 | |
353 return fr->rdat.filepos; | |
354 } | |
355 | |
356 /* This does not (fully) work for non-seekable streams... You have to check for that flag, pal! */ | |
357 static void stream_rewind(mpg123_handle *fr) | |
358 { | |
359 if(fr->rdat.flags & READER_SEEKABLE) | |
360 fr->rdat.buffer.fileoff = fr->rdat.filepos = stream_lseek(fr,0,SEEK_SET); | |
361 if(fr->rdat.flags & READER_BUFFERED) | |
362 { | |
363 fr->rdat.buffer.pos = 0; | |
364 fr->rdat.buffer.firstpos = 0; | |
365 fr->rdat.filepos = fr->rdat.buffer.fileoff; | |
366 } | |
367 } | |
368 | |
369 /* | |
370 * returns length of a file (if filept points to a file) | |
371 * reads the last 128 bytes information into buffer | |
372 * ... that is not totally safe... | |
373 */ | |
374 static off_t get_fileinfo(mpg123_handle *fr) | |
375 { | |
376 off_t len; | |
377 | |
378 if((len=fr->rdat.lseek(fr->rdat.filept,0,SEEK_END)) < 0) return -1; | |
379 | |
380 if(fr->rdat.lseek(fr->rdat.filept,-128,SEEK_END) < 0) return -1; | |
381 | |
382 if(fr->rd->fullread(fr,(unsigned char *)fr->id3buf,128) != 128) return -1; | |
383 | |
384 if(!strncmp((char*)fr->id3buf,"TAG",3)) len -= 128; | |
385 | |
386 if(fr->rdat.lseek(fr->rdat.filept,0,SEEK_SET) < 0) return -1; | |
387 | |
388 if(len <= 0) return -1; | |
389 | |
390 return len; | |
391 } | |
392 | |
393 /* Methods for the buffer chain, mainly used for feed reader, but not just that. */ | |
394 | |
395 static void bc_init(struct bufferchain *bc) | |
396 { | |
397 bc->first = NULL; | |
398 bc->last = bc->first; | |
399 bc->size = 0; | |
400 bc->pos = 0; | |
401 bc->firstpos = 0; | |
402 bc->fileoff = 0; | |
403 } | |
404 | |
405 static void bc_reset(struct bufferchain *bc) | |
406 { | |
407 /* free the buffer chain */ | |
408 struct buffy *b = bc->first; | |
409 while(b != NULL) | |
410 { | |
411 struct buffy *n = b->next; | |
412 free(b->data); | |
413 free(b); | |
414 b = n; | |
415 } | |
416 bc_init(bc); | |
417 } | |
418 | |
419 /* Create a new buffy at the end to be filled. */ | |
420 static int bc_append(struct bufferchain *bc, ssize_t size) | |
421 { | |
422 struct buffy *newbuf; | |
423 if(size < 1) return -1; | |
424 | |
425 newbuf = malloc(sizeof(struct buffy)); | |
426 if(newbuf == NULL) return -2; | |
427 | |
428 newbuf->data = malloc(size); | |
429 if(newbuf->data == NULL) | |
430 { | |
431 free(newbuf); | |
432 return -3; | |
433 } | |
434 newbuf->size = size; | |
435 newbuf->next = NULL; | |
436 if(bc->last != NULL) bc->last->next = newbuf; | |
437 else if(bc->first == NULL) bc->first = newbuf; | |
438 | |
439 bc->last = newbuf; | |
440 bc->size += size; | |
441 return 0; | |
442 } | |
443 | |
444 #if 0 | |
445 /* Drop the last one (again). | |
446 This is not optimal but should happen on error situations only, anyway. */ | |
447 static void bc_drop(struct bufferchain *bc) | |
448 { | |
449 struct buffy *cur = bc->first; | |
450 if(bc->first == NULL || bc->last == NULL) return; | |
451 /* Special case: only one buffer there. */ | |
452 if(cur->next == NULL) | |
453 { | |
454 free(cur->data); | |
455 free(cur); | |
456 bc->first = bc->last = NULL; | |
457 bc->size = 0; | |
458 return; | |
459 } | |
460 /* Find the pre-last buffy. If chain is consistent, this _will_ succeed. */ | |
461 while(cur->next != bc->last){ cur = cur->next; } | |
462 | |
463 bc->size -= bc->last->size; | |
464 free(bc->last->data); | |
465 free(bc->last); | |
466 cur->next = NULL; | |
467 bc->last = cur; | |
468 } | |
469 #endif | |
470 | |
471 /* Append a new buffer and copy content to it. */ | |
472 static int bc_add(struct bufferchain *bc, const unsigned char *data, ssize_t size) | |
473 { | |
474 int ret = 0; | |
475 if((ret = bc_append(bc, size)) == 0) | |
476 memcpy(bc->last->data, data, size); | |
477 | |
478 return ret; | |
479 } | |
480 | |
481 /* Give some data, advancing position but not forgetting yet. */ | |
482 static ssize_t bc_give(struct bufferchain *bc, unsigned char *out, size_t size) | |
483 { | |
484 struct buffy *b = bc->first; | |
485 ssize_t gotcount = 0; | |
486 ssize_t offset = 0; | |
487 if(bc->size - bc->pos < size) | |
488 { | |
489 debug3("hit end, back to beginning (%li - %li < %li)", (long)bc->size, (long)bc->pos, (long)size); | |
490 /* go back to firstpos, undo the previous reads */ | |
491 bc->pos = bc->firstpos; | |
492 return READER_MORE; | |
493 } | |
494 /* find the current buffer */ | |
495 while(b != NULL && (offset + b->size) <= bc->pos) | |
496 { | |
497 offset += b->size; | |
498 b = b->next; | |
499 } | |
500 /* now start copying from there */ | |
501 while(gotcount < size && (b != NULL)) | |
502 { | |
503 ssize_t loff = bc->pos - offset; | |
504 ssize_t chunk = size - gotcount; /* amount of bytes to get from here... */ | |
505 if(chunk > b->size - loff) chunk = b->size - loff; | |
506 | |
507 #ifdef EXTRA_DEBUG | |
508 debug3("copying %liB from %p+%li",(long)chunk, b->data, (long)loff); */ | |
509 #endif | |
510 | |
511 memcpy(out+gotcount, b->data+loff, chunk); | |
512 gotcount += chunk; | |
513 bc->pos += chunk; | |
514 offset += b->size; | |
515 b = b->next; | |
516 } | |
517 #ifdef EXTRA_DEBUG | |
518 debug2("got %li bytes, pos advanced to %li", (long)gotcount, (long)bc->pos); | |
519 #endif | |
520 | |
521 return gotcount; | |
522 } | |
523 | |
524 /* Skip some bytes and return the new position. | |
525 The buffers are still there, just the read pointer is moved! */ | |
526 static ssize_t bc_skip(struct bufferchain *bc, ssize_t count) | |
527 { | |
528 if(count >= 0) | |
529 { | |
530 if(bc->size - bc->pos < count) return READER_MORE; | |
531 else return bc->pos += count; | |
532 } | |
533 else return READER_ERROR; | |
534 } | |
535 | |
536 static ssize_t bc_seekback(struct bufferchain *bc, ssize_t count) | |
537 { | |
538 if(count >= 0 && count <= bc->pos) return bc->pos -= count; | |
539 else return READER_ERROR; | |
540 } | |
541 | |
542 /* Throw away buffies that we passed. */ | |
543 static void bc_forget(struct bufferchain *bc) | |
544 { | |
545 struct buffy *b = bc->first; | |
546 /* free all buffers that are def'n'tly outdated */ | |
547 /* we have buffers until filepos... delete all buffers fully below it */ | |
548 #ifdef EXTRA_DEBUG | |
549 if(b) debug2("bc_forget: block %lu pos %lu", (unsigned long)b->size, (unsigned long)bc->pos); | |
550 else debug("forget with nothing there!"); | |
551 #endif | |
552 while(b != NULL && bc->pos >= b->size) | |
553 { | |
554 struct buffy *n = b->next; /* != NULL or this is indeed the end and the last cycle anyway */ | |
555 if(n == NULL) bc->last = NULL; /* Going to delete the last buffy... */ | |
556 bc->fileoff += b->size; | |
557 bc->pos -= b->size; | |
558 bc->size -= b->size; | |
559 #ifdef EXTRA_DEBUG | |
560 debug5("bc_forget: forgot %p with %lu, pos=%li, size=%li, fileoff=%li", (void*)b->data, (long)b->size, (long)bc->pos, (long)bc->size, (long)bc->fileoff); | |
561 #endif | |
562 free(b->data); | |
563 free(b); | |
564 b = n; | |
565 } | |
566 bc->first = b; | |
567 bc->firstpos = bc->pos; | |
568 } | |
569 | |
570 /* reader for input via manually provided buffers */ | |
571 | |
572 static int feed_init(mpg123_handle *fr) | |
573 { | |
574 bc_init(&fr->rdat.buffer); | |
575 fr->rdat.filelen = 0; | |
576 fr->rdat.filepos = 0; | |
577 fr->rdat.flags |= READER_BUFFERED; | |
578 return 0; | |
579 } | |
580 | |
581 /* externally called function, returns 0 on success, -1 on error */ | |
582 int feed_more(mpg123_handle *fr, const unsigned char *in, long count) | |
583 { | |
584 int ret = 0; | |
585 if(VERBOSE3) debug("feed_more"); | |
586 if((ret = bc_add(&fr->rdat.buffer, in, count)) != 0) | |
587 { | |
588 ret = READER_ERROR; | |
589 if(NOQUIET) error1("Failed to add buffer, return: %i", ret); | |
590 } | |
591 else /* Not talking about filelen... that stays at 0. */ | |
592 | |
593 if(VERBOSE3) debug3("feed_more: %p %luB bufsize=%lu", fr->rdat.buffer.last->data, | |
594 (unsigned long)fr->rdat.buffer.last->size, (unsigned long)fr->rdat.buffer.size); | |
595 return ret; | |
596 } | |
597 | |
598 static ssize_t feed_read(mpg123_handle *fr, unsigned char *out, ssize_t count) | |
599 { | |
600 ssize_t gotcount = bc_give(&fr->rdat.buffer, out, count); | |
601 if(gotcount >= 0 && gotcount != count) return READER_ERROR; | |
602 else return gotcount; | |
603 } | |
604 | |
605 /* returns reached position... negative ones are bad... */ | |
606 static off_t feed_skip_bytes(mpg123_handle *fr,off_t len) | |
607 { | |
608 return fr->rdat.buffer.fileoff+bc_skip(&fr->rdat.buffer, (ssize_t)len); | |
609 } | |
610 | |
611 static int feed_back_bytes(mpg123_handle *fr, off_t bytes) | |
612 { | |
613 if(bytes >=0) | |
614 return bc_seekback(&fr->rdat.buffer, (ssize_t)bytes) >= 0 ? 0 : READER_ERROR; | |
615 else | |
616 return feed_skip_bytes(fr, -bytes) >= 0 ? 0 : READER_ERROR; | |
617 } | |
618 | |
619 static int buffered_seek_frame(mpg123_handle *fr, off_t num){ return READER_ERROR; } | |
620 | |
621 /* Not just for feed reader, also for self-feeding buffered reader. */ | |
622 static void buffered_forget(mpg123_handle *fr) | |
623 { | |
624 bc_forget(&fr->rdat.buffer); | |
625 fr->rdat.filepos = fr->rdat.buffer.fileoff + fr->rdat.buffer.pos; | |
626 } | |
627 | |
628 off_t feed_set_pos(mpg123_handle *fr, off_t pos) | |
629 { | |
630 struct bufferchain *bc = &fr->rdat.buffer; | |
631 if(pos >= bc->fileoff && pos-bc->fileoff < bc->size) | |
632 { /* We have the position! */ | |
633 bc->pos = (ssize_t)(pos - bc->fileoff); | |
634 return pos+bc->size; /* Next input after end of buffer... */ | |
635 } | |
636 else | |
637 { /* I expect to get the specific position on next feed. Forget what I have now. */ | |
638 bc_reset(bc); | |
639 bc->fileoff = pos; | |
640 return pos; /* Next input from exactly that position. */ | |
641 } | |
642 } | |
643 | |
644 /* The specific stuff for buffered stream reader. */ | |
645 | |
646 /* Let's work in nice 4K blocks, that may be nicely reusable (by malloc(), even). */ | |
647 #define BUFFBLOCK 4096 | |
648 static ssize_t buffered_fullread(mpg123_handle *fr, unsigned char *out, ssize_t count) | |
649 { | |
650 struct bufferchain *bc = &fr->rdat.buffer; | |
651 ssize_t gotcount; | |
652 if(bc->size - bc->pos < count) | |
653 { /* Add more stuff to buffer. If hitting end of file, adjust count. */ | |
654 unsigned char readbuf[BUFFBLOCK]; | |
655 ssize_t need = count - (bc->size-bc->pos); | |
656 while(need>0) | |
657 { | |
658 int ret; | |
659 ssize_t got = fr->rdat.fullread(fr, readbuf, BUFFBLOCK); | |
660 if(got < 0) | |
661 { | |
662 if(NOQUIET) error("buffer reading"); | |
663 return READER_ERROR; | |
664 } | |
665 | |
666 if(VERBOSE3) debug1("buffered_fullread: buffering %li bytes from stream (if > 0)", (long)got); | |
667 if(got > 0 && (ret=bc_add(bc, readbuf, got)) != 0) | |
668 { | |
669 if(NOQUIET) error1("unable to add to chain, return: %i", ret); | |
670 return READER_ERROR; | |
671 } | |
672 | |
673 need -= got; /* May underflow here... */ | |
674 if(got < BUFFBLOCK) /* That naturally catches got == 0, too. */ | |
675 { | |
676 if(VERBOSE3) fprintf(stderr, "Note: Input data end.\n"); | |
677 break; /* End. */ | |
678 } | |
679 } | |
680 if(bc->size - bc->pos < count) | |
681 count = bc->size - bc->pos; /* We want only what we got. */ | |
682 } | |
683 gotcount = bc_give(bc, out, count); | |
684 | |
685 if(VERBOSE3) debug2("wanted %li, got %li", (long)count, (long)gotcount); | |
686 | |
687 if(gotcount != count){ if(NOQUIET) error("gotcount != count"); return READER_ERROR; } | |
688 else return gotcount; | |
689 } | |
690 | |
691 | |
692 | |
693 /***************************************************************** | |
694 * read frame helper | |
695 */ | |
696 | |
697 #define bugger_off { mh->err = MPG123_NO_READER; return MPG123_ERR; } | |
698 int bad_init(mpg123_handle *mh) bugger_off | |
699 void bad_close(mpg123_handle *mh){} | |
700 ssize_t bad_fullread(mpg123_handle *mh, unsigned char *data, ssize_t count) bugger_off | |
701 int bad_head_read(mpg123_handle *mh, unsigned long *newhead) bugger_off | |
702 int bad_head_shift(mpg123_handle *mh, unsigned long *head) bugger_off | |
703 off_t bad_skip_bytes(mpg123_handle *mh, off_t len) bugger_off | |
704 int bad_read_frame_body(mpg123_handle *mh, unsigned char *data, int size) bugger_off | |
705 int bad_back_bytes(mpg123_handle *mh, off_t bytes) bugger_off | |
706 int bad_seek_frame(mpg123_handle *mh, off_t num) bugger_off | |
707 off_t bad_tell(mpg123_handle *mh) bugger_off | |
708 void bad_rewind(mpg123_handle *mh){} | |
709 #undef bugger_off | |
710 | |
711 #define READER_STREAM 0 | |
712 #define READER_ICY_STREAM 1 | |
713 #define READER_FEED 2 | |
714 #define READER_BUF_STREAM 3 | |
715 #define READER_BUF_ICY_STREAM 4 | |
716 struct reader readers[] = | |
717 { | |
718 { /* READER_STREAM */ | |
719 default_init, | |
720 stream_close, | |
721 plain_fullread, | |
722 generic_head_read, | |
723 generic_head_shift, | |
724 stream_skip_bytes, | |
725 generic_read_frame_body, | |
726 stream_back_bytes, | |
727 stream_seek_frame, | |
728 generic_tell, | |
729 stream_rewind, | |
730 NULL | |
731 } , | |
732 { /* READER_ICY_STREAM */ | |
733 default_init, | |
734 stream_close, | |
735 icy_fullread, | |
736 generic_head_read, | |
737 generic_head_shift, | |
738 stream_skip_bytes, | |
739 generic_read_frame_body, | |
740 stream_back_bytes, | |
741 stream_seek_frame, | |
742 generic_tell, | |
743 stream_rewind, | |
744 NULL | |
745 }, | |
746 { /* READER_FEED */ | |
747 feed_init, | |
748 stream_close, | |
749 feed_read, | |
750 generic_head_read, | |
751 generic_head_shift, | |
752 feed_skip_bytes, | |
753 generic_read_frame_body, | |
754 feed_back_bytes, | |
755 buffered_seek_frame, | |
756 generic_tell, | |
757 stream_rewind, | |
758 buffered_forget | |
759 }, | |
760 { /* READER_BUF_STREAM */ | |
761 default_init, | |
762 stream_close, | |
763 buffered_fullread, | |
764 generic_head_read, | |
765 generic_head_shift, | |
766 stream_skip_bytes, | |
767 generic_read_frame_body, | |
768 stream_back_bytes, | |
769 buffered_seek_frame, | |
770 generic_tell, | |
771 stream_rewind, | |
772 buffered_forget | |
773 } , | |
774 { /* READER_BUF_ICY_STREAM */ | |
775 default_init, | |
776 stream_close, | |
777 buffered_fullread, | |
778 generic_head_read, | |
779 generic_head_shift, | |
780 stream_skip_bytes, | |
781 generic_read_frame_body, | |
782 stream_back_bytes, | |
783 buffered_seek_frame, | |
784 generic_tell, | |
785 stream_rewind, | |
786 buffered_forget | |
787 }, | |
788 #ifdef READ_SYSTEM | |
789 ,{ | |
790 system_init, | |
791 NULL, /* filled in by system_init() */ | |
792 fullread, | |
793 NULL, | |
794 NULL, | |
795 NULL, | |
796 NULL, | |
797 NULL, | |
798 NULL, | |
799 NULL, | |
800 NULL, | |
801 NULL, | |
802 } | |
803 #endif | |
804 }; | |
805 | |
806 struct reader bad_reader = | |
807 { | |
808 bad_init, | |
809 bad_close, | |
810 bad_fullread, | |
811 bad_head_read, | |
812 bad_head_shift, | |
813 bad_skip_bytes, | |
814 bad_read_frame_body, | |
815 bad_back_bytes, | |
816 bad_seek_frame, | |
817 bad_tell, | |
818 bad_rewind, | |
819 NULL | |
820 }; | |
821 | |
822 static int default_init(mpg123_handle *fr) | |
823 { | |
824 #ifndef WIN32 | |
825 if(fr->p.timeout > 0) | |
826 { | |
827 int flags = fcntl(fr->rdat.filept, F_GETFL); | |
828 flags |= O_NONBLOCK; | |
829 fcntl(fr->rdat.filept, F_SETFL, flags); | |
830 fr->rdat.fdread = timeout_read; | |
831 fr->rdat.timeout_sec = fr->p.timeout; | |
832 fr->rdat.flags |= READER_NONBLOCK; | |
833 } | |
834 else | |
835 #endif | |
836 fr->rdat.fdread = plain_read; | |
837 | |
838 fr->rdat.read = fr->rdat.r_read != NULL ? fr->rdat.r_read : posix_read; | |
839 fr->rdat.lseek = fr->rdat.r_lseek != NULL ? fr->rdat.r_lseek : posix_lseek; | |
840 fr->rdat.filelen = get_fileinfo(fr); | |
841 fr->rdat.filepos = 0; | |
842 if(fr->rdat.filelen >= 0) | |
843 { | |
844 fr->rdat.flags |= READER_SEEKABLE; | |
845 if(!strncmp((char*)fr->id3buf,"TAG",3)) | |
846 { | |
847 fr->rdat.flags |= READER_ID3TAG; | |
848 fr->metaflags |= MPG123_NEW_ID3; | |
849 } | |
850 } | |
851 /* Switch reader to a buffered one, if allowed. */ | |
852 else if(fr->p.flags & MPG123_SEEKBUFFER) | |
853 { | |
854 if (fr->rd == &readers[READER_STREAM]) | |
855 { | |
856 fr->rd = &readers[READER_BUF_STREAM]; | |
857 fr->rdat.fullread = plain_fullread; | |
858 } | |
859 else if(fr->rd == &readers[READER_ICY_STREAM]) | |
860 { | |
861 fr->rd = &readers[READER_BUF_ICY_STREAM]; | |
862 fr->rdat.fullread = icy_fullread; | |
863 } | |
864 else | |
865 { | |
866 if(NOQUIET) error("mpg123 Programmer's fault: invalid reader"); | |
867 return -1; | |
868 } | |
869 bc_init(&fr->rdat.buffer); | |
870 fr->rdat.filelen = 0; /* We carry the offset, but never know how big the stream is. */ | |
871 fr->rdat.flags |= READER_BUFFERED; | |
872 } | |
873 return 0; | |
874 } | |
875 | |
876 | |
877 void open_bad(mpg123_handle *mh) | |
878 { | |
879 clear_icy(&mh->icy); | |
880 mh->rd = &bad_reader; | |
881 mh->rdat.flags = 0; | |
882 bc_init(&mh->rdat.buffer); | |
883 } | |
884 | |
885 int open_feed(mpg123_handle *fr) | |
886 { | |
887 debug("feed reader"); | |
888 clear_icy(&fr->icy); | |
889 fr->rd = &readers[READER_FEED]; | |
890 fr->rdat.flags = 0; | |
891 if(fr->rd->init(fr) < 0) return -1; | |
892 return 0; | |
893 } | |
894 | |
895 int open_stream(mpg123_handle *fr, const char *bs_filenam, int fd) | |
896 { | |
897 int filept_opened = 1; | |
898 int filept; /* descriptor of opened file/stream */ | |
899 | |
900 clear_icy(&fr->icy); /* can be done inside frame_clear ...? */ | |
901 if(!bs_filenam) /* no file to open, got a descriptor (stdin) */ | |
902 { | |
903 filept = fd; | |
904 filept_opened = 0; /* and don't try to close it... */ | |
905 } | |
906 #ifndef O_BINARY | |
907 #define O_BINARY (0) | |
908 #endif | |
909 else if((filept = open(bs_filenam, O_RDONLY|O_BINARY)) < 0) /* a plain old file to open... */ | |
910 { | |
911 if(NOQUIET) error2("Cannot open file %s: %s", bs_filenam, strerror(errno)); | |
912 fr->err = MPG123_BAD_FILE; | |
913 return MPG123_ERR; /* error... */ | |
914 } | |
915 | |
916 /* now we have something behind filept and can init the reader */ | |
917 fr->rdat.filelen = -1; | |
918 fr->rdat.filept = filept; | |
919 fr->rdat.flags = 0; | |
920 if(filept_opened) fr->rdat.flags |= READER_FD_OPENED; | |
921 | |
922 if(fr->p.icy_interval > 0) | |
923 { | |
924 debug("ICY reader"); | |
925 fr->icy.interval = fr->p.icy_interval; | |
926 fr->icy.next = fr->icy.interval; | |
927 fr->rd = &readers[READER_ICY_STREAM]; | |
928 } | |
929 else | |
930 { | |
931 fr->rd = &readers[READER_STREAM]; | |
932 debug("stream reader"); | |
933 } | |
934 | |
935 if(fr->rd->init(fr) < 0) return -1; | |
936 | |
937 return MPG123_OK; | |
938 } |