Mercurial > SDL_sound_CoreAudio
comparison decoders/mpg123.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 | 72eb2d7debbe |
comparison
equal
deleted
inserted
replaced
561:f2985e08589c | 562:7e08477b0fc1 |
---|---|
1 /* | |
2 * SDL_sound -- An abstract sound format decoding API. | |
3 * Copyright (C) 2001 Ryan C. Gordon. | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2.1 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 */ | |
19 | |
20 /* | |
21 * libmpg123 decoder for SDL_sound. This is a very lightweight MP3 decoder, | |
22 * which is included with the SDL_sound source, so that it doesn't rely on | |
23 * unnecessary external libraries. | |
24 * | |
25 * libmpg123 is part of mpg123, and can be found in its original | |
26 * form at: http://www.mpg123.org/ | |
27 * | |
28 * Please see the file LICENSE.txt in the source's root directory. The included | |
29 * source code for libmpg123 falls under the LGPL, which is the same license | |
30 * as SDL_sound (so you can consider it a single work). | |
31 * | |
32 * This file written by Ryan C. Gordon. (icculus@icculus.org) | |
33 */ | |
34 | |
35 #if HAVE_CONFIG_H | |
36 # include <config.h> | |
37 #endif | |
38 | |
39 #ifdef SOUND_SUPPORTS_MPG123 | |
40 | |
41 #include <stdio.h> | |
42 #include <stdlib.h> | |
43 #include <string.h> | |
44 | |
45 #define MPG123_NO_CONFIGURE 1 | |
46 #include "libmpg123/mpg123.h" | |
47 | |
48 #include "SDL_sound.h" | |
49 | |
50 #define __SDL_SOUND_INTERNAL__ | |
51 #include "SDL_sound_internal.h" | |
52 | |
53 static int MPG123_init(void); | |
54 static void MPG123_quit(void); | |
55 static int MPG123_open(Sound_Sample *sample, const char *ext); | |
56 static void MPG123_close(Sound_Sample *sample); | |
57 static Uint32 MPG123_read(Sound_Sample *sample); | |
58 static int MPG123_rewind(Sound_Sample *sample); | |
59 static int MPG123_seek(Sound_Sample *sample, Uint32 ms); | |
60 | |
61 /* !!! FIXME: MPEG and MPG extensions? */ | |
62 static const char *extensions_mpg123[] = { "MP3", NULL }; | |
63 const Sound_DecoderFunctions __Sound_DecoderFunctions_MPG123 = | |
64 { | |
65 { | |
66 extensions_mpg123, | |
67 "MP3 decoding via internal libmpg123", | |
68 "Ryan C. Gordon <icculus@icculus.org>", | |
69 "http://www.icculus.org/SDL_sound/" | |
70 }, | |
71 | |
72 MPG123_init, /* init() method */ | |
73 MPG123_quit, /* quit() method */ | |
74 MPG123_open, /* open() method */ | |
75 MPG123_close, /* close() method */ | |
76 MPG123_read, /* read() method */ | |
77 MPG123_rewind, /* rewind() method */ | |
78 MPG123_seek /* seek() method */ | |
79 }; | |
80 | |
81 | |
82 /* this is what we store in our internal->decoder_private field... */ | |
83 typedef mpg123_handle mpg123_t; | |
84 | |
85 static SDL_mutex *mpg123_mutex = NULL; | |
86 static int mpg123_rwops_count = 0; | |
87 static SDL_RWops **mpg123_rwops = NULL; | |
88 | |
89 static void print_decoders(const char *kind, char **decoders) | |
90 { | |
91 SNDDBG(("%s:", kind)); | |
92 if (*decoders == NULL) | |
93 SNDDBG((" [none]")); | |
94 else | |
95 { | |
96 do | |
97 { | |
98 SNDDBG((" %s", *decoders)); | |
99 } while (*(++decoders)); | |
100 } /* else */ | |
101 } /* print_decoders */ | |
102 | |
103 | |
104 static int MPG123_init(void) | |
105 { | |
106 int retval = 0; | |
107 assert(mpg123_mutex == NULL); | |
108 if (mpg123_init() == MPG123_OK) | |
109 { | |
110 char **supported = mpg123_supported_decoders(); | |
111 print_decoders("ALL MPG123 DECODERS", mpg123_decoders()); | |
112 print_decoders("SUPPORTED MPG123 DECODERS", mpg123_supported_decoders()); | |
113 if ((supported != NULL) && (*supported != NULL)) | |
114 { | |
115 mpg123_mutex = SDL_CreateMutex(); | |
116 if (mpg123_mutex != NULL) | |
117 retval = 1; /* at least one decoder available. */ | |
118 } /* if */ | |
119 } /* if */ | |
120 | |
121 return retval; | |
122 } /* MPG123_init */ | |
123 | |
124 | |
125 static void MPG123_quit(void) | |
126 { | |
127 mpg123_exit(); | |
128 SDL_DestroyMutex(mpg123_mutex); | |
129 mpg123_mutex = NULL; | |
130 free(mpg123_rwops); | |
131 mpg123_rwops = NULL; | |
132 mpg123_rwops_count = 0; | |
133 } /* MPG123_quit */ | |
134 | |
135 | |
136 /* bridge rwops reading to libmpg123 hooks. */ | |
137 static ssize_t rwread(int fd, void *buf, size_t len) | |
138 { | |
139 SDL_RWops *rw = NULL; | |
140 SDL_LockMutex(mpg123_mutex); | |
141 rw = mpg123_rwops[fd]; | |
142 SDL_UnlockMutex(mpg123_mutex); | |
143 return (ssize_t) SDL_RWread(rw, buf, 1, len); | |
144 } /* rwread */ | |
145 | |
146 | |
147 /* bridge rwops seeking to libmpg123 hooks. */ | |
148 static off_t rwseek(int fd, off_t pos, int whence) | |
149 { | |
150 SDL_RWops *rw = NULL; | |
151 SDL_LockMutex(mpg123_mutex); | |
152 rw = mpg123_rwops[fd]; | |
153 SDL_UnlockMutex(mpg123_mutex); | |
154 return (off_t) SDL_RWseek(rw, pos, whence); | |
155 } /* rwseek */ | |
156 | |
157 | |
158 static const char *set_error(mpg123_handle *mp, const int err) | |
159 { | |
160 char buffer[128]; | |
161 const char *str = NULL; | |
162 if ((err == MPG123_ERR) && (mp != NULL)) | |
163 str = mpg123_strerror(mp); | |
164 else | |
165 str = mpg123_plain_strerror(err); | |
166 | |
167 snprintf(buffer, sizeof (buffer), "MPG123: %s", str); | |
168 __Sound_SetError(buffer); | |
169 | |
170 return(NULL); /* this is for BAIL_MACRO to not try to reset the string. */ | |
171 } /* set_error */ | |
172 | |
173 | |
174 /* Make sure we are only given decoded data in a format we can handle. */ | |
175 static int set_formats(mpg123_handle *mp) | |
176 { | |
177 int rc = 0; | |
178 const long *rates = NULL; | |
179 size_t ratecount = 0; | |
180 const int channels = MPG123_STEREO | MPG123_MONO; | |
181 const int encodings = /* !!! FIXME: SDL 1.3 can do sint32 and float32. | |
182 MPG123_ENC_SIGNED_32 | MPG123_ENC_FLOAT_32 | */ | |
183 MPG123_ENC_SIGNED_8 | MPG123_ENC_UNSIGNED_8 | | |
184 MPG123_ENC_SIGNED_16 | MPG123_ENC_UNSIGNED_16; | |
185 | |
186 mpg123_rates(&rates, &ratecount); | |
187 | |
188 rc = mpg123_format_none(mp); | |
189 while ((ratecount--) && (rc == MPG123_OK)) | |
190 rc = mpg123_format(mp, *(rates++), channels, encodings); | |
191 | |
192 return(rc); | |
193 } /* set_formats */ | |
194 | |
195 | |
196 static int MPG123_open(Sound_Sample *sample, const char *ext) | |
197 { | |
198 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
199 mpg123_handle *mp = NULL; | |
200 long rate = 0; | |
201 int channels = 0; | |
202 int fmt = 0; | |
203 int rc = 0; | |
204 off_t len = 0; | |
205 int seekable = 0; | |
206 void *ptr = NULL; | |
207 int rwops = 0; | |
208 | |
209 /* !!! FIXME: so much tapdance because we need a pointer, not an int. */ | |
210 SDL_LockMutex(mpg123_mutex); | |
211 for (rwops = 0; rwops < mpg123_rwops_count; rwops++) | |
212 { | |
213 if (mpg123_rwops[rwops] == NULL) | |
214 break; | |
215 } /* for */ | |
216 if (rwops < mpg123_rwops_count) | |
217 ptr = mpg123_rwops; | |
218 else | |
219 { | |
220 mpg123_rwops_count++; | |
221 ptr = realloc(mpg123_rwops, sizeof (SDL_RWops *) * mpg123_rwops_count); | |
222 if (ptr != NULL) | |
223 mpg123_rwops = (SDL_RWops **) ptr; | |
224 } /* else */ | |
225 if (ptr != NULL) | |
226 mpg123_rwops[rwops] = internal->rw; | |
227 SDL_UnlockMutex(mpg123_mutex); | |
228 BAIL_IF_MACRO(ptr == NULL, ERR_OUT_OF_MEMORY, 0); | |
229 | |
230 if ((mp = mpg123_new(NULL, &rc)) == NULL) | |
231 goto mpg123_open_failed; | |
232 else if ((rc = set_formats(mp)) != MPG123_OK) | |
233 goto mpg123_open_failed; | |
234 else if ((rc = mpg123_replace_reader(mp, rwread, rwseek)) != MPG123_OK) | |
235 goto mpg123_open_failed; | |
236 else if ((rc = mpg123_open_fd(mp, rwops)) != MPG123_OK) | |
237 goto mpg123_open_failed; | |
238 else if ((rc = mpg123_scan(mp)) != MPG123_OK) | |
239 goto mpg123_open_failed; /* !!! FIXME: this may be wrong. */ | |
240 else if ((rc = mpg123_getformat(mp, &rate, &channels, &fmt)) != MPG123_OK) | |
241 goto mpg123_open_failed; | |
242 | |
243 if (mpg123_seek(mp, 0, SEEK_END) >= 0) /* can seek? */ | |
244 { | |
245 len = mpg123_tell(mp); | |
246 if ((rc = (int) mpg123_seek(mp, 0, SEEK_SET)) < 0) | |
247 goto mpg123_open_failed; | |
248 seekable = 1; | |
249 } /* if */ | |
250 | |
251 SNDDBG(("MPG123: Accepting data stream.\n")); | |
252 | |
253 internal->decoder_private = mp; | |
254 sample->actual.rate = rate; | |
255 sample->actual.channels = channels; | |
256 | |
257 rc = MPG123_BAD_OUTFORMAT; /* in case this fails... */ | |
258 if (fmt == MPG123_ENC_SIGNED_8) | |
259 sample->actual.format = AUDIO_S8; | |
260 else if (fmt == MPG123_ENC_UNSIGNED_8) | |
261 sample->actual.format = AUDIO_U8; | |
262 else if (fmt == MPG123_ENC_SIGNED_16) | |
263 sample->actual.format = AUDIO_S16SYS; | |
264 else if (fmt == MPG123_ENC_UNSIGNED_16) | |
265 sample->actual.format = AUDIO_U16SYS; | |
266 /* !!! FIXME: SDL 1.3 can do sint32 and float32 ... | |
267 else if (fmt == MPG123_ENC_SIGNED_32) | |
268 sample->actual.format = AUDIO_S32SYS; | |
269 else if (fmt == MPG123_ENC_FLOAT_32) | |
270 sample->actual.format = AUDIO_F32SYS; | |
271 */ | |
272 else | |
273 goto mpg123_open_failed; | |
274 | |
275 sample->flags = SOUND_SAMPLEFLAG_NONE; | |
276 internal->total_time = -1; | |
277 if (seekable) | |
278 { | |
279 sample->flags |= SOUND_SAMPLEFLAG_CANSEEK; | |
280 internal->total_time = ((len / rate) * 1000) + | |
281 (((len % rate) * 1000) / rate); | |
282 } /* if */ | |
283 | |
284 return(1); /* we'll handle this data. */ | |
285 | |
286 mpg123_open_failed: | |
287 SDL_LockMutex(mpg123_mutex); | |
288 mpg123_rwops[rwops] = NULL; | |
289 if (rwops == mpg123_rwops_count) | |
290 mpg123_rwops_count--; | |
291 SDL_UnlockMutex(mpg123_mutex); | |
292 set_error(mp, rc); | |
293 mpg123_delete(mp); /* NULL is safe. */ | |
294 return(0); | |
295 } /* MPG123_open */ | |
296 | |
297 | |
298 static void MPG123_close(Sound_Sample *sample) | |
299 { | |
300 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
301 mpg123_t *mp = ((mpg123_t *) internal->decoder_private); | |
302 int i; | |
303 | |
304 SDL_LockMutex(mpg123_mutex); | |
305 for (i = 0; i < mpg123_rwops_count; i++) | |
306 { | |
307 if (mpg123_rwops[i] == internal->rw) | |
308 mpg123_rwops[i] = NULL; | |
309 } /* for */ | |
310 | |
311 for (i = mpg123_rwops_count-1; i >= 0; i--) | |
312 { | |
313 if (mpg123_rwops[i] != NULL) | |
314 break; | |
315 } /* for */ | |
316 mpg123_rwops_count = i + 1; | |
317 SDL_UnlockMutex(mpg123_mutex); | |
318 | |
319 mpg123_close(mp); /* don't need this at the moment, but it's safe. */ | |
320 mpg123_delete(mp); | |
321 } /* MPG123_close */ | |
322 | |
323 | |
324 static Uint32 MPG123_read(Sound_Sample *sample) | |
325 { | |
326 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
327 mpg123_t *mp = ((mpg123_t *) internal->decoder_private); | |
328 size_t bw = 0; | |
329 const int rc = mpg123_read(mp, (unsigned char *) internal->buffer, | |
330 internal->buffer_size, &bw); | |
331 if (rc == MPG123_DONE) | |
332 sample->flags |= SOUND_SAMPLEFLAG_EOF; | |
333 else if (rc != MPG123_OK) | |
334 { | |
335 sample->flags |= SOUND_SAMPLEFLAG_ERROR; | |
336 set_error(mp, rc); | |
337 } /* else if */ | |
338 | |
339 return((Uint32) bw); | |
340 } /* MPG123_read */ | |
341 | |
342 | |
343 static int MPG123_rewind(Sound_Sample *sample) | |
344 { | |
345 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
346 mpg123_t *mp = ((mpg123_t *) internal->decoder_private); | |
347 const int rc = (int) mpg123_seek(mp, 0, SEEK_SET); | |
348 BAIL_IF_MACRO(rc < 0, set_error(mp, rc), 0); | |
349 return(1); | |
350 } /* MPG123_rewind */ | |
351 | |
352 | |
353 static int MPG123_seek(Sound_Sample *sample, Uint32 ms) | |
354 { | |
355 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
356 mpg123_t *mp = ((mpg123_t *) internal->decoder_private); | |
357 const float frames_per_ms = ((float) sample->actual.rate) / 1000.0f; | |
358 const off_t frame_offset = (off_t) (frames_per_ms * ((float) ms)); | |
359 const int rc = (int) mpg123_seek(mp, frame_offset , SEEK_SET); | |
360 BAIL_IF_MACRO(rc < 0, set_error(mp, rc), 0); | |
361 return(1); | |
362 } /* MPG123_seek */ | |
363 | |
364 #endif /* SOUND_SUPPORTS_MPG123 */ | |
365 | |
366 /* end of mpg123.c ... */ | |
367 |