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