1 | /** |
2 | * Copyright (c) 2006-2023 LOVE Development Team |
3 | * |
4 | * This software is provided 'as-is', without any express or implied |
5 | * warranty. In no event will the authors be held liable for any damages |
6 | * arising from the use of this software. |
7 | * |
8 | * Permission is granted to anyone to use this software for any purpose, |
9 | * including commercial applications, and to alter it and redistribute it |
10 | * freely, subject to the following restrictions: |
11 | * |
12 | * 1. The origin of this software must not be misrepresented; you must not |
13 | * claim that you wrote the original software. If you use this software |
14 | * in a product, an acknowledgment in the product documentation would be |
15 | * appreciated but is not required. |
16 | * 2. Altered source versions must be plainly marked as such, and must not be |
17 | * misrepresented as being the original software. |
18 | * 3. This notice may not be removed or altered from any source distribution. |
19 | **/ |
20 | |
21 | #include "Mpg123Decoder.h" |
22 | |
23 | #include "common/Exception.h" |
24 | |
25 | #include <iostream> |
26 | |
27 | #ifndef LOVE_NOMPG123 |
28 | |
29 | namespace love |
30 | { |
31 | namespace sound |
32 | { |
33 | namespace lullaby |
34 | { |
35 | |
36 | /** |
37 | * mpg123 callbacks for seekable streams. |
38 | **/ |
39 | |
40 | static ssize_t read_callback(void *udata, void *buffer, size_t count) |
41 | { |
42 | DecoderFile *file = (DecoderFile *) udata; |
43 | |
44 | // Calculates how much data is still left and takes that value or |
45 | // the buffer size, whichever is lower, as the number of bytes to write. |
46 | size_t countLeft = file->size - file->offset; |
47 | size_t countWrite = countLeft < count ? countLeft : count; |
48 | |
49 | if (countWrite > 0) |
50 | { |
51 | memcpy(buffer, file->data + file->offset, countWrite); |
52 | file->offset += countWrite; |
53 | } |
54 | |
55 | // Returns the number of written bytes. 0 means EOF. |
56 | return countWrite; |
57 | } |
58 | |
59 | static off_t seek_callback(void *udata, off_t offset, int whence) |
60 | { |
61 | DecoderFile *file = (DecoderFile *) udata; |
62 | |
63 | switch (whence) |
64 | { |
65 | case SEEK_SET: |
66 | // Negative values are invalid at this point. |
67 | if (offset < 0) |
68 | return -1; |
69 | |
70 | // Prevents the offset from going over EOF. |
71 | if (file->size > (size_t) offset) |
72 | file->offset = offset; |
73 | else |
74 | file->offset = file->size; |
75 | break; |
76 | case SEEK_END: |
77 | // Offset is set to EOF. Offset calculation is just like SEEK_CUR. |
78 | file->offset = file->size; |
79 | case SEEK_CUR: |
80 | // Prevents the offset from going over EOF or below 0. |
81 | if (offset > 0) |
82 | { |
83 | if (file->size > file->offset + (size_t) offset) |
84 | file->offset = file->offset + offset; |
85 | else |
86 | file->offset = file->size; |
87 | } |
88 | else if (offset < 0) |
89 | { |
90 | if (file->offset >= (size_t) (-offset)) |
91 | file->offset = file->offset - (size_t) (-offset); |
92 | else |
93 | file->offset = 0; |
94 | } |
95 | break; |
96 | default: |
97 | return -1; |
98 | }; |
99 | |
100 | return file->offset; |
101 | } |
102 | |
103 | static void cleanup_callback(void *) |
104 | { |
105 | // Cleanup is done by the Decoder class. |
106 | } |
107 | |
108 | bool Mpg123Decoder::inited = false; |
109 | |
110 | Mpg123Decoder::Mpg123Decoder(Data *data, int bufferSize) |
111 | : Decoder(data, bufferSize) |
112 | , decoder_file(data) |
113 | , handle(0) |
114 | , channels(MPG123_STEREO) |
115 | , duration(-2.0) |
116 | { |
117 | int ret = 0; |
118 | |
119 | if (!inited) |
120 | { |
121 | ret = mpg123_init(); |
122 | if (ret != MPG123_OK) |
123 | throw love::Exception("Could not initialize mpg123." ); |
124 | inited = (ret == MPG123_OK); |
125 | } |
126 | |
127 | // Intialize the handle. |
128 | handle = mpg123_new(nullptr, nullptr); |
129 | if (handle == nullptr) |
130 | throw love::Exception("Could not create decoder." ); |
131 | |
132 | // Suppressing all mpg123 messages. |
133 | mpg123_param(handle, MPG123_ADD_FLAGS, MPG123_QUIET, 0); |
134 | |
135 | try |
136 | { |
137 | ret = mpg123_replace_reader_handle(handle, &read_callback, &seek_callback, &cleanup_callback); |
138 | if (ret != MPG123_OK) |
139 | throw love::Exception("Could not set decoder callbacks." ); |
140 | |
141 | ret = mpg123_open_handle(handle, &decoder_file); |
142 | if (ret != MPG123_OK) |
143 | throw love::Exception("Could not open decoder." ); |
144 | |
145 | // mpg123_getformat should be able to tell us the properties of the stream's first frame. |
146 | long rate = 0; |
147 | ret = mpg123_getformat(handle, &rate, &channels, nullptr); |
148 | if (ret == MPG123_ERR) |
149 | throw love::Exception("Could not get stream information." ); |
150 | |
151 | // I forgot what this was about. |
152 | if (channels == 0) |
153 | channels = 2; |
154 | |
155 | // Force signed 16-bit output. |
156 | mpg123_param(handle, MPG123_FLAGS, (channels == 2 ? MPG123_FORCE_STEREO : MPG123_MONO_MIX), 0); |
157 | mpg123_format_none(handle); |
158 | mpg123_format(handle, rate, channels, MPG123_ENC_SIGNED_16); |
159 | |
160 | sampleRate = (int) rate; |
161 | |
162 | // Force a read, so we can determine if it's actually an mp3 |
163 | struct mpg123_frameinfo info; |
164 | ret = mpg123_info(handle, &info); |
165 | if (ret != MPG123_OK) |
166 | throw love::Exception("Could not read mp3 data." ); |
167 | } |
168 | catch (love::Exception &) |
169 | { |
170 | mpg123_delete(handle); |
171 | throw; |
172 | } |
173 | } |
174 | |
175 | Mpg123Decoder::~Mpg123Decoder() |
176 | { |
177 | mpg123_delete(handle); |
178 | |
179 | } |
180 | |
181 | bool Mpg123Decoder::accepts(const std::string &ext) |
182 | { |
183 | static const std::string supported[] = |
184 | { |
185 | "mp3" , "" |
186 | }; |
187 | |
188 | for (int i = 0; !(supported[i].empty()); i++) |
189 | { |
190 | if (supported[i].compare(ext) == 0) |
191 | return true; |
192 | } |
193 | |
194 | return false; |
195 | } |
196 | |
197 | void Mpg123Decoder::quit() |
198 | { |
199 | if (inited) |
200 | mpg123_exit(); |
201 | } |
202 | |
203 | love::sound::Decoder *Mpg123Decoder::clone() |
204 | { |
205 | return new Mpg123Decoder(data.get(), bufferSize); |
206 | } |
207 | |
208 | int Mpg123Decoder::decode() |
209 | { |
210 | int size = 0; |
211 | |
212 | while (size < bufferSize && !eof) |
213 | { |
214 | size_t numbytes = 0; |
215 | int res = mpg123_read(handle, (unsigned char *) buffer + size, bufferSize - size, &numbytes); |
216 | |
217 | switch (res) |
218 | { |
219 | case MPG123_NEED_MORE: |
220 | case MPG123_NEW_FORMAT: |
221 | case MPG123_OK: |
222 | size += numbytes; |
223 | continue; |
224 | case MPG123_DONE: |
225 | size += numbytes; |
226 | eof = true; |
227 | default: |
228 | return size; |
229 | } |
230 | } |
231 | |
232 | return size; |
233 | } |
234 | |
235 | bool Mpg123Decoder::seek(double s) |
236 | { |
237 | off_t offset = (off_t) (s * (double) sampleRate); |
238 | |
239 | if (offset < 0) |
240 | return false; |
241 | |
242 | if (mpg123_seek(handle, offset, SEEK_SET) >= 0) |
243 | { |
244 | eof = false; |
245 | return true; |
246 | } |
247 | else |
248 | return false; |
249 | } |
250 | |
251 | bool Mpg123Decoder::rewind() |
252 | { |
253 | eof = false; |
254 | |
255 | if (mpg123_seek(handle, 0, SEEK_SET) >= 0) |
256 | return true; |
257 | else |
258 | return false; |
259 | } |
260 | |
261 | bool Mpg123Decoder::isSeekable() |
262 | { |
263 | return true; |
264 | } |
265 | |
266 | int Mpg123Decoder::getChannelCount() const |
267 | { |
268 | return channels; |
269 | } |
270 | |
271 | int Mpg123Decoder::getBitDepth() const |
272 | { |
273 | return 16; |
274 | } |
275 | |
276 | double Mpg123Decoder::getDuration() |
277 | { |
278 | // Only calculate the duration if we haven't done so already. |
279 | if (duration == -2.0) |
280 | { |
281 | mpg123_scan(handle); |
282 | |
283 | off_t length = mpg123_length(handle); |
284 | |
285 | if (length == MPG123_ERR || length < 0) |
286 | duration = -1.0; |
287 | else |
288 | duration = (double) length / (double) sampleRate; |
289 | } |
290 | |
291 | return duration; |
292 | } |
293 | |
294 | } // lullaby |
295 | } // sound |
296 | } // love |
297 | |
298 | #endif // LOVE_NOMPG123 |
299 | |