Skip to content

Latest commit

 

History

History
368 lines (310 loc) · 11.1 KB

mpg123.c

File metadata and controls

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