Mercurial > audlegacy-plugins
comparison src/mpg123/mpg123.c @ 12:3da1b8942b8b trunk
[svn] - remove src/Input src/Output src/Effect src/General src/Visualization src/Container
author | nenolod |
---|---|
date | Mon, 18 Sep 2006 03:14:20 -0700 |
parents | src/Input/mpg123/mpg123.c@088092a52fea |
children | 98de08786b0a |
comparison
equal
deleted
inserted
replaced
11:cff1d04026ae | 12:3da1b8942b8b |
---|---|
1 #include "mpg123.h" | |
2 #include "common.h" | |
3 | |
4 #include <glib.h> | |
5 #include <glib/gi18n.h> | |
6 #include <gtk/gtk.h> | |
7 #include <stdlib.h> | |
8 #include <string.h> | |
9 #include <unistd.h> | |
10 | |
11 #include <fcntl.h> | |
12 #include <unistd.h> | |
13 #include <errno.h> | |
14 #include <sys/types.h> | |
15 #include <sys/socket.h> | |
16 #include <sys/time.h> | |
17 #include <netinet/in.h> | |
18 #include <arpa/inet.h> | |
19 #include <netdb.h> | |
20 | |
21 #include "audacious/util.h" | |
22 #include "audacious/configdb.h" | |
23 #include "audacious/vfs.h" | |
24 #include "audacious/titlestring.h" | |
25 #include "audacious/util.h" | |
26 #include <tag_c.h> | |
27 | |
28 #define BUFSIZE_X 2048 | |
29 | |
30 static struct frame fr, temp_fr; | |
31 | |
32 PlayerInfo *mpgdec_info = NULL; | |
33 static GThread *decode_thread; | |
34 | |
35 static gboolean audio_error = FALSE, output_opened = FALSE, dopause = FALSE; | |
36 gint mpgdec_bitrate, mpgdec_frequency, mpgdec_length, mpgdec_layer, | |
37 mpgdec_lsf; | |
38 gchar *mpgdec_title = NULL, *mpgdec_filename = NULL; | |
39 static int disp_bitrate, skip_frames = 0; | |
40 static int cpu_fflags, cpu_efflags; | |
41 gboolean mpgdec_stereo, mpgdec_mpeg25; | |
42 int mpgdec_mode; | |
43 | |
44 mpgdec_t *ins; | |
45 | |
46 gchar **mpgdec_id3_encoding_list = NULL; | |
47 | |
48 const char *mpgdec_id3_genres[GENRE_MAX] = { | |
49 N_("Blues"), N_("Classic Rock"), N_("Country"), N_("Dance"), | |
50 N_("Disco"), N_("Funk"), N_("Grunge"), N_("Hip-Hop"), | |
51 N_("Jazz"), N_("Metal"), N_("New Age"), N_("Oldies"), | |
52 N_("Other"), N_("Pop"), N_("R&B"), N_("Rap"), N_("Reggae"), | |
53 N_("Rock"), N_("Techno"), N_("Industrial"), N_("Alternative"), | |
54 N_("Ska"), N_("Death Metal"), N_("Pranks"), N_("Soundtrack"), | |
55 N_("Euro-Techno"), N_("Ambient"), N_("Trip-Hop"), N_("Vocal"), | |
56 N_("Jazz+Funk"), N_("Fusion"), N_("Trance"), N_("Classical"), | |
57 N_("Instrumental"), N_("Acid"), N_("House"), N_("Game"), | |
58 N_("Sound Clip"), N_("Gospel"), N_("Noise"), N_("AlternRock"), | |
59 N_("Bass"), N_("Soul"), N_("Punk"), N_("Space"), | |
60 N_("Meditative"), N_("Instrumental Pop"), | |
61 N_("Instrumental Rock"), N_("Ethnic"), N_("Gothic"), | |
62 N_("Darkwave"), N_("Techno-Industrial"), N_("Electronic"), | |
63 N_("Pop-Folk"), N_("Eurodance"), N_("Dream"), | |
64 N_("Southern Rock"), N_("Comedy"), N_("Cult"), | |
65 N_("Gangsta Rap"), N_("Top 40"), N_("Christian Rap"), | |
66 N_("Pop/Funk"), N_("Jungle"), N_("Native American"), | |
67 N_("Cabaret"), N_("New Wave"), N_("Psychedelic"), N_("Rave"), | |
68 N_("Showtunes"), N_("Trailer"), N_("Lo-Fi"), N_("Tribal"), | |
69 N_("Acid Punk"), N_("Acid Jazz"), N_("Polka"), N_("Retro"), | |
70 N_("Musical"), N_("Rock & Roll"), N_("Hard Rock"), N_("Folk"), | |
71 N_("Folk/Rock"), N_("National Folk"), N_("Swing"), | |
72 N_("Fast-Fusion"), N_("Bebob"), N_("Latin"), N_("Revival"), | |
73 N_("Celtic"), N_("Bluegrass"), N_("Avantgarde"), | |
74 N_("Gothic Rock"), N_("Progressive Rock"), | |
75 N_("Psychedelic Rock"), N_("Symphonic Rock"), N_("Slow Rock"), | |
76 N_("Big Band"), N_("Chorus"), N_("Easy Listening"), | |
77 N_("Acoustic"), N_("Humour"), N_("Speech"), N_("Chanson"), | |
78 N_("Opera"), N_("Chamber Music"), N_("Sonata"), N_("Symphony"), | |
79 N_("Booty Bass"), N_("Primus"), N_("Porn Groove"), | |
80 N_("Satire"), N_("Slow Jam"), N_("Club"), N_("Tango"), | |
81 N_("Samba"), N_("Folklore"), N_("Ballad"), N_("Power Ballad"), | |
82 N_("Rhythmic Soul"), N_("Freestyle"), N_("Duet"), | |
83 N_("Punk Rock"), N_("Drum Solo"), N_("A Cappella"), | |
84 N_("Euro-House"), N_("Dance Hall"), N_("Goa"), | |
85 N_("Drum & Bass"), N_("Club-House"), N_("Hardcore"), | |
86 N_("Terror"), N_("Indie"), N_("BritPop"), N_("Negerpunk"), | |
87 N_("Polsk Punk"), N_("Beat"), N_("Christian Gangsta Rap"), | |
88 N_("Heavy Metal"), N_("Black Metal"), N_("Crossover"), | |
89 N_("Contemporary Christian"), N_("Christian Rock"), | |
90 N_("Merengue"), N_("Salsa"), N_("Thrash Metal"), | |
91 N_("Anime"), N_("JPop"), N_("Synthpop") | |
92 }; | |
93 | |
94 double | |
95 mpgdec_compute_tpf(struct frame *fr) | |
96 { | |
97 const int bs[4] = { 0, 384, 1152, 1152 }; | |
98 double tpf; | |
99 | |
100 tpf = bs[fr->lay]; | |
101 tpf /= mpgdec_freqs[fr->sampling_frequency] << (fr->lsf); | |
102 return tpf; | |
103 } | |
104 | |
105 static void | |
106 set_synth_functions(struct frame *fr) | |
107 { | |
108 typedef int (*func) (mpgdec_real *, int, unsigned char *, int *); | |
109 typedef int (*func_mono) (mpgdec_real *, unsigned char *, int *); | |
110 typedef void (*func_dct36) (mpgdec_real *, mpgdec_real *, mpgdec_real *, mpgdec_real *, mpgdec_real *); | |
111 | |
112 int ds = fr->down_sample; | |
113 int p8 = 0; | |
114 | |
115 static func funcs[2][2] = { | |
116 {mpgdec_synth_1to1, | |
117 mpgdec_synth_ntom}, | |
118 {mpgdec_synth_1to1_8bit, | |
119 mpgdec_synth_ntom_8bit} | |
120 }; | |
121 | |
122 static func_mono funcs_mono[2][2] = { | |
123 {mpgdec_synth_1to1_mono, | |
124 mpgdec_synth_ntom_mono}, | |
125 {mpgdec_synth_1to1_8bit_mono, | |
126 mpgdec_synth_ntom_8bit_mono} | |
127 }; | |
128 | |
129 /* Compatibility with older configs. */ | |
130 if (ds > 1) | |
131 ds = 1; | |
132 | |
133 if (mpgdec_cfg.resolution == 8) | |
134 p8 = 1; | |
135 fr->synth = funcs[p8][ds]; | |
136 fr->synth_mono = funcs_mono[p8][ds]; | |
137 fr->synth_type = SYNTH_FPU; | |
138 | |
139 if (p8) { | |
140 mpgdec_make_conv16to8_table(); | |
141 } | |
142 } | |
143 | |
144 static void | |
145 init(void) | |
146 { | |
147 ConfigDb *db; | |
148 gchar *tmp = NULL; | |
149 | |
150 ins = mpgdec_new(); | |
151 | |
152 memset(&mpgdec_cfg, 0, sizeof(mpgdec_cfg)); | |
153 | |
154 mpgdec_cfg.resolution = 16; | |
155 mpgdec_cfg.channels = 2; | |
156 mpgdec_cfg.downsample = 0; | |
157 mpgdec_cfg.http_buffer_size = 128; | |
158 mpgdec_cfg.http_prebuffer = 25; | |
159 mpgdec_cfg.proxy_port = 8080; | |
160 mpgdec_cfg.proxy_use_auth = FALSE; | |
161 mpgdec_cfg.proxy_user = NULL; | |
162 mpgdec_cfg.proxy_pass = NULL; | |
163 mpgdec_cfg.use_udp_channel = TRUE; | |
164 mpgdec_cfg.title_override = FALSE; | |
165 mpgdec_cfg.disable_id3v2 = FALSE; | |
166 mpgdec_cfg.default_synth = SYNTH_AUTO; | |
167 | |
168 mpgdec_cfg.title_encoding_enabled = FALSE; | |
169 mpgdec_cfg.title_encoding = NULL; | |
170 | |
171 db = bmp_cfg_db_open(); | |
172 | |
173 bmp_cfg_db_get_int(db, "MPG123", "resolution", &mpgdec_cfg.resolution); | |
174 bmp_cfg_db_get_int(db, "MPG123", "channels", &mpgdec_cfg.channels); | |
175 bmp_cfg_db_get_int(db, "MPG123", "downsample", &mpgdec_cfg.downsample); | |
176 bmp_cfg_db_get_int(db, "MPG123", "http_buffer_size", | |
177 &mpgdec_cfg.http_buffer_size); | |
178 bmp_cfg_db_get_int(db, "MPG123", "http_prebuffer", | |
179 &mpgdec_cfg.http_prebuffer); | |
180 bmp_cfg_db_get_bool(db, "MPG123", "save_http_stream", | |
181 &mpgdec_cfg.save_http_stream); | |
182 if (!bmp_cfg_db_get_string | |
183 (db, "MPG123", "save_http_path", &mpgdec_cfg.save_http_path)) | |
184 mpgdec_cfg.save_http_path = g_strdup(g_get_home_dir()); | |
185 | |
186 bmp_cfg_db_get_bool(db, "MPG123", "use_udp_channel", | |
187 &mpgdec_cfg.use_udp_channel); | |
188 | |
189 bmp_cfg_db_get_bool(db, "MPG123", "title_override", | |
190 &mpgdec_cfg.title_override); | |
191 bmp_cfg_db_get_bool(db, "MPG123", "disable_id3v2", | |
192 &mpgdec_cfg.disable_id3v2); | |
193 if (!bmp_cfg_db_get_string | |
194 (db, "MPG123", "id3_format", &mpgdec_cfg.id3_format)) | |
195 mpgdec_cfg.id3_format = g_strdup("%p - %t"); | |
196 bmp_cfg_db_get_int(db, "MPG123", "default_synth", | |
197 &mpgdec_cfg.default_synth); | |
198 | |
199 bmp_cfg_db_get_bool(db, "MPG123", "title_encoding_enabled", &mpgdec_cfg.title_encoding_enabled); | |
200 bmp_cfg_db_get_string(db, "MPG123", "title_encoding", &mpgdec_cfg.title_encoding); | |
201 if (mpgdec_cfg.title_encoding_enabled) | |
202 mpgdec_id3_encoding_list = g_strsplit_set(mpgdec_cfg.title_encoding, ENCODING_SEPARATOR, 0); | |
203 | |
204 bmp_cfg_db_get_bool(db, NULL, "use_proxy", &mpgdec_cfg.use_proxy); | |
205 bmp_cfg_db_get_string(db, NULL, "proxy_host", &mpgdec_cfg.proxy_host); | |
206 bmp_cfg_db_get_string(db, NULL, "proxy_port", &tmp); | |
207 | |
208 if (tmp != NULL) | |
209 mpgdec_cfg.proxy_port = atoi(tmp); | |
210 | |
211 bmp_cfg_db_get_bool(db, NULL, "proxy_use_auth", &mpgdec_cfg.proxy_use_auth); | |
212 bmp_cfg_db_get_string(db, NULL, "proxy_user", &mpgdec_cfg.proxy_user); | |
213 bmp_cfg_db_get_string(db, NULL, "proxy_pass", &mpgdec_cfg.proxy_pass); | |
214 | |
215 bmp_cfg_db_close(db); | |
216 | |
217 if (mpgdec_cfg.resolution != 16 && mpgdec_cfg.resolution != 8) | |
218 mpgdec_cfg.resolution = 16; | |
219 | |
220 mpgdec_cfg.channels = CLAMP(mpgdec_cfg.channels, 0, 2); | |
221 mpgdec_cfg.downsample = CLAMP(mpgdec_cfg.downsample, 0, 2); | |
222 mpgdec_getcpuflags(&cpu_fflags, &cpu_efflags); | |
223 } | |
224 | |
225 static void | |
226 cleanup(void) | |
227 { | |
228 g_free(mpgdec_ip.description); | |
229 mpgdec_ip.description = NULL; | |
230 | |
231 if (mpgdec_cfg.save_http_path) { | |
232 free(mpgdec_cfg.save_http_path); | |
233 mpgdec_cfg.save_http_path = NULL; | |
234 } | |
235 | |
236 if (mpgdec_cfg.proxy_host) { | |
237 free(mpgdec_cfg.proxy_host); | |
238 mpgdec_cfg.proxy_host = NULL; | |
239 } | |
240 | |
241 if (mpgdec_cfg.proxy_user) { | |
242 free(mpgdec_cfg.proxy_user); | |
243 mpgdec_cfg.proxy_user = NULL; | |
244 } | |
245 | |
246 if (mpgdec_cfg.proxy_pass) { | |
247 free(mpgdec_cfg.proxy_pass); | |
248 mpgdec_cfg.proxy_pass = NULL; | |
249 } | |
250 | |
251 if (mpgdec_cfg.id3_format) { | |
252 free(mpgdec_cfg.id3_format); | |
253 mpgdec_cfg.id3_format = NULL; | |
254 } | |
255 | |
256 if (mpgdec_cfg.title_encoding) { | |
257 free(mpgdec_cfg.title_encoding); | |
258 mpgdec_cfg.title_encoding = NULL; | |
259 } | |
260 | |
261 g_strfreev(mpgdec_id3_encoding_list); | |
262 } | |
263 | |
264 static guint32 | |
265 convert_to_header(guint8 * buf) | |
266 { | |
267 return (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]; | |
268 } | |
269 | |
270 | |
271 #define DET_BUF_SIZE 4096 | |
272 | |
273 static gboolean | |
274 mpgdec_detect_by_content(char *filename) | |
275 { | |
276 VFSFile *file; | |
277 guchar tmp[4]; | |
278 guint32 head; | |
279 struct frame fr; | |
280 guchar buf[DET_BUF_SIZE]; | |
281 int in_buf, i; | |
282 gboolean ret = FALSE; | |
283 guint cyc = 0; | |
284 | |
285 if ((file = vfs_fopen(filename, "rb")) == NULL) | |
286 return FALSE; | |
287 if (vfs_fread(tmp, 1, 4, file) != 4) | |
288 goto done; | |
289 if (!memcmp(tmp, "ID3", 3)) | |
290 { | |
291 ret = TRUE; | |
292 goto done; | |
293 } | |
294 head = convert_to_header(tmp); | |
295 while (!mpgdec_head_check(head)) { | |
296 /* | |
297 * The mpeg-stream can start anywhere in the file, | |
298 * so we check the entire file | |
299 * | |
300 * Incorrect! We give up past twenty iterations of this | |
301 * code for safety's sake. Buffer overflows suck. --nenolod | |
302 */ | |
303 /* Optimize this */ | |
304 in_buf = vfs_fread(buf, 1, DET_BUF_SIZE, file); | |
305 if (in_buf == 0) | |
306 goto done; | |
307 | |
308 for (i = 0; i < in_buf; i++) { | |
309 head <<= 8; | |
310 head |= buf[i]; | |
311 if (mpgdec_head_check(head)) { | |
312 vfs_fseek(file, i + 1 - in_buf, SEEK_CUR); | |
313 break; | |
314 } | |
315 } | |
316 | |
317 if (++cyc > 1024) | |
318 goto done; | |
319 } | |
320 if (mpgdec_decode_header(&fr, head)) { | |
321 /* | |
322 * We found something which looks like a MPEG-header. | |
323 * We check the next frame too, to be sure | |
324 */ | |
325 | |
326 if (vfs_fseek(file, fr.framesize, SEEK_CUR) != 0) | |
327 goto done; | |
328 if (vfs_fread(tmp, 1, 4, file) != 4) | |
329 goto done; | |
330 head = convert_to_header(tmp); | |
331 if (mpgdec_head_check(head) && mpgdec_decode_header(&fr, head)) | |
332 ret = TRUE; | |
333 } | |
334 | |
335 done: | |
336 vfs_fclose(file); | |
337 return ret; | |
338 } | |
339 | |
340 static int | |
341 is_our_file(char *filename) | |
342 { | |
343 gchar *ext = strrchr(filename, '.'); | |
344 | |
345 if (CHECK_STREAM(filename) && | |
346 (ext && strncasecmp(ext, ".ogg", 4)) && | |
347 (ext && strncasecmp(ext, ".flac", 5))) | |
348 return TRUE; | |
349 else if (mpgdec_detect_by_content(filename)) | |
350 return TRUE; | |
351 #if 0 | |
352 else if (ext && (!strncasecmp(ext, ".mp3", 4) | |
353 || !strncasecmp(ext, ".mp2", 4) | |
354 || !strncasecmp(ext, ".mpg", 4))) | |
355 return TRUE; | |
356 #endif | |
357 | |
358 return FALSE; | |
359 } | |
360 | |
361 static void | |
362 play_frame(struct frame *fr) | |
363 { | |
364 if (fr->error_protection) { | |
365 bsi.wordpointer += 2; | |
366 /* mpgdec_getbits(16); *//* skip crc */ | |
367 } | |
368 if (!fr->do_layer(fr)) { | |
369 skip_frames = 2; | |
370 mpgdec_info->output_audio = FALSE; | |
371 } | |
372 else { | |
373 if (!skip_frames) | |
374 mpgdec_info->output_audio = TRUE; | |
375 else | |
376 skip_frames--; | |
377 } | |
378 } | |
379 | |
380 static const char * | |
381 get_id3_genre(unsigned char genre_code) | |
382 { | |
383 if (genre_code < GENRE_MAX) | |
384 return gettext(mpgdec_id3_genres[genre_code]); | |
385 | |
386 return ""; | |
387 } | |
388 | |
389 guint | |
390 mpgdec_strip_spaces(char *src, size_t n) | |
391 { | |
392 gchar *space = NULL, /* last space in src */ | |
393 *start = src; | |
394 | |
395 while (n--) | |
396 switch (*src++) { | |
397 case '\0': | |
398 n = 0; /* breaks out of while loop */ | |
399 | |
400 src--; | |
401 break; | |
402 case ' ': | |
403 if (space == NULL) | |
404 space = src - 1; | |
405 break; | |
406 default: | |
407 space = NULL; /* don't terminate intermediate spaces */ | |
408 | |
409 break; | |
410 } | |
411 if (space != NULL) { | |
412 src = space; | |
413 *src = '\0'; | |
414 } | |
415 return src - start; | |
416 } | |
417 | |
418 /* | |
419 * Function extname (filename) | |
420 * | |
421 * Return pointer within filename to its extenstion, or NULL if | |
422 * filename has no extension. | |
423 * | |
424 */ | |
425 static gchar * | |
426 extname(const char *filename) | |
427 { | |
428 gchar *ext = strrchr(filename, '.'); | |
429 | |
430 if (ext != NULL) | |
431 ++ext; | |
432 | |
433 return ext; | |
434 } | |
435 | |
436 /* | |
437 * Function id3v1_to_id3v2 (v1, v2) | |
438 * | |
439 * Convert ID3v1 tag `v1' to ID3v2 tag `v2'. | |
440 * | |
441 */ | |
442 void | |
443 mpgdec_id3v1_to_id3v2(struct id3v1tag_t *v1, struct id3tag_t *v2) | |
444 { | |
445 memset(v2, 0, sizeof(struct id3tag_t)); | |
446 strncpy(v2->title, v1->title, 30); | |
447 strncpy(v2->artist, v1->artist, 30); | |
448 strncpy(v2->album, v1->album, 30); | |
449 strncpy(v2->comment, v1->u.v1_0.comment, 30); | |
450 strncpy(v2->genre, get_id3_genre(v1->genre), sizeof(v2->genre)); | |
451 g_strstrip(v2->title); | |
452 g_strstrip(v2->artist); | |
453 g_strstrip(v2->album); | |
454 g_strstrip(v2->comment); | |
455 g_strstrip(v2->genre); | |
456 { | |
457 char y[5]; | |
458 memcpy(y, v1->year, 4); y[4]=0; | |
459 v2->year = atoi(y); | |
460 } | |
461 | |
462 /* Check for v1.1 tags. */ | |
463 if (v1->u.v1_1.__zero == 0) | |
464 v2->track_number = v1->u.v1_1.track_number; | |
465 else | |
466 v2->track_number = 0; | |
467 } | |
468 | |
469 #define REMOVE_NONEXISTANT_TAG(x) if (!*x) { x = NULL; } | |
470 | |
471 static long | |
472 get_song_length(VFSFile * file) | |
473 { | |
474 int len; | |
475 char tmp[4]; | |
476 | |
477 vfs_fseek(file, 0, SEEK_END); | |
478 len = vfs_ftell(file); | |
479 vfs_fseek(file, -128, SEEK_END); | |
480 vfs_fread(tmp, 1, 3, file); | |
481 if (!strncmp(tmp, "TAG", 3)) | |
482 len -= 128; | |
483 return len; | |
484 } | |
485 | |
486 | |
487 static guint | |
488 get_song_time(VFSFile * file) | |
489 { | |
490 guint32 head; | |
491 guchar tmp[4], *buf; | |
492 struct frame frm; | |
493 xing_header_t xing_header; | |
494 double tpf, bpf; | |
495 guint32 len; | |
496 | |
497 if (!file) | |
498 return -1; | |
499 | |
500 vfs_fseek(file, 0, SEEK_SET); | |
501 if (vfs_fread(tmp, 1, 4, file) != 4) | |
502 return 0; | |
503 head = convert_to_header(tmp); | |
504 while (!mpgdec_head_check(head)) { | |
505 head <<= 8; | |
506 if (vfs_fread(tmp, 1, 1, file) != 1) | |
507 return 0; | |
508 head |= tmp[0]; | |
509 } | |
510 if (mpgdec_decode_header(&frm, head)) { | |
511 buf = g_malloc(frm.framesize + 4); | |
512 vfs_fseek(file, -4, SEEK_CUR); | |
513 vfs_fread(buf, 1, frm.framesize + 4, file); | |
514 tpf = mpgdec_compute_tpf(&frm); | |
515 if (mpgdec_get_xing_header(&xing_header, buf)) { | |
516 g_free(buf); | |
517 if (xing_header.bytes == 0) | |
518 xing_header.bytes = get_song_length(file); | |
519 return (tpf * xing_header.frames * 1000); | |
520 } | |
521 g_free(buf); | |
522 bpf = mpgdec_compute_bpf(&frm); | |
523 len = get_song_length(file); | |
524 return ((guint) (len / bpf) * tpf * 1000); | |
525 } | |
526 return 0; | |
527 } | |
528 | |
529 static TitleInput * | |
530 get_song_tuple(char *filename) | |
531 { | |
532 VFSFile *file; | |
533 TitleInput *tuple = NULL; | |
534 TagLib_File *taglib_file; | |
535 TagLib_Tag *taglib_tag; | |
536 | |
537 #ifdef USE_CHARDET | |
538 taglib_set_strings_unicode(FALSE); | |
539 #endif | |
540 | |
541 if ((file = vfs_fopen(filename, "rb")) != NULL) | |
542 { | |
543 tuple = bmp_title_input_new(); | |
544 | |
545 taglib_file = taglib_file_new(filename); | |
546 taglib_tag = NULL; | |
547 | |
548 if (taglib_file != NULL) | |
549 { | |
550 taglib_tag = taglib_file_tag(taglib_file); | |
551 } | |
552 | |
553 if (taglib_tag != NULL) | |
554 { | |
555 tuple->performer = g_strdup(taglib_tag_artist(taglib_tag)); | |
556 tuple->album_name = g_strdup(taglib_tag_album(taglib_tag)); | |
557 tuple->track_name = g_strdup(taglib_tag_title(taglib_tag)); | |
558 | |
559 mpgdec_strip_spaces(tuple->performer, strlen(tuple->performer)); | |
560 mpgdec_strip_spaces(tuple->album_name, strlen(tuple->album_name)); | |
561 mpgdec_strip_spaces(tuple->track_name, strlen(tuple->track_name)); | |
562 | |
563 tuple->year = taglib_tag_year(taglib_tag); | |
564 tuple->track_number = taglib_tag_track(taglib_tag); | |
565 tuple->genre = g_strdup(taglib_tag_genre(taglib_tag)); | |
566 tuple->comment = g_strdup(taglib_tag_comment(taglib_tag)); | |
567 | |
568 /* remove any blank tags, fucking taglib */ | |
569 REMOVE_NONEXISTANT_TAG(tuple->performer); | |
570 REMOVE_NONEXISTANT_TAG(tuple->album_name); | |
571 REMOVE_NONEXISTANT_TAG(tuple->track_name); | |
572 REMOVE_NONEXISTANT_TAG(tuple->genre); | |
573 REMOVE_NONEXISTANT_TAG(tuple->comment); | |
574 } | |
575 | |
576 if (tuple->performer != NULL) | |
577 tuple->performer = str_to_utf8(tuple->performer); | |
578 | |
579 if (tuple->album_name != NULL) | |
580 tuple->album_name = str_to_utf8(tuple->album_name); | |
581 | |
582 if (tuple->track_name != NULL) | |
583 tuple->track_name = str_to_utf8(tuple->track_name); | |
584 | |
585 if (tuple->comment != NULL) | |
586 tuple->comment = str_to_utf8(tuple->comment); | |
587 | |
588 tuple->file_name = g_path_get_basename(filename); | |
589 tuple->file_path = g_path_get_dirname(filename); | |
590 tuple->file_ext = extname(filename); | |
591 tuple->length = get_song_time(file); | |
592 | |
593 if (taglib_file != NULL) | |
594 taglib_file_free(taglib_file); | |
595 | |
596 taglib_tag_free_strings(); | |
597 vfs_fclose(file); | |
598 } | |
599 | |
600 return tuple; | |
601 } | |
602 | |
603 static gchar * | |
604 get_song_title(TitleInput *tuple) | |
605 { | |
606 return xmms_get_titlestring(mpgdec_cfg.title_override ? | |
607 mpgdec_cfg.id3_format : | |
608 xmms_get_gentitle_format(), tuple); | |
609 } | |
610 | |
611 static void | |
612 get_song_info(char *filename, char **title_real, int *len_real) | |
613 { | |
614 TitleInput *tuple; | |
615 | |
616 (*len_real) = -1; | |
617 (*title_real) = NULL; | |
618 | |
619 /* | |
620 * TODO: Getting song info from http streams. | |
621 */ | |
622 if (CHECK_STREAM(filename)) | |
623 return; | |
624 | |
625 if ((tuple = get_song_tuple(filename)) != NULL) { | |
626 (*len_real) = tuple->length; | |
627 (*title_real) = get_song_title(tuple); | |
628 } | |
629 | |
630 bmp_title_input_free(tuple); | |
631 } | |
632 | |
633 static int | |
634 open_output(void) | |
635 { | |
636 int r; | |
637 AFormat fmt = mpgdec_cfg.resolution == 16 ? FMT_S16_NE : FMT_U8; | |
638 /* int freq = mpgdec_freqs[fr.sampling_frequency] >> mpgdec_cfg.downsample; */ | |
639 int freq = mpgdec_frequency; | |
640 int channels = mpgdec_cfg.channels == 2 ? fr.stereo : 1; | |
641 r = mpgdec_ip.output->open_audio(fmt, freq, channels); | |
642 | |
643 if (r && dopause) { | |
644 mpgdec_ip.output->pause(TRUE); | |
645 dopause = FALSE; | |
646 } | |
647 | |
648 return r; | |
649 } | |
650 | |
651 | |
652 static int | |
653 mpgdec_seek(struct frame *fr, xing_header_t * xh, gboolean vbr, int time) | |
654 { | |
655 int jumped = -1; | |
656 | |
657 if (xh) { | |
658 int percent = ((double) time * 100.0) / | |
659 (mpgdec_info->num_frames * mpgdec_info->tpf); | |
660 int byte = mpgdec_seek_point(xh, percent); | |
661 jumped = mpgdec_stream_jump_to_byte(fr, byte); | |
662 } | |
663 else if (vbr && mpgdec_length > 0) { | |
664 int byte = ((guint64) time * 1000 * mpgdec_info->filesize) / | |
665 mpgdec_length; | |
666 jumped = mpgdec_stream_jump_to_byte(fr, byte); | |
667 } | |
668 else { | |
669 int frame = time / mpgdec_info->tpf; | |
670 jumped = mpgdec_stream_jump_to_frame(fr, frame); | |
671 } | |
672 | |
673 return jumped; | |
674 } | |
675 | |
676 | |
677 static void * | |
678 decode_loop(void *arg) | |
679 { | |
680 gboolean have_xing_header = FALSE, vbr = FALSE; | |
681 int disp_count = 0; | |
682 char *filename = arg; | |
683 xing_header_t xing_header; | |
684 | |
685 /* This is used by fileinfo on http streams */ | |
686 mpgdec_bitrate = 0; | |
687 | |
688 mpgdec_pcm_sample = g_malloc0(32768); | |
689 mpgdec_pcm_point = 0; | |
690 mpgdec_filename = filename; | |
691 | |
692 mpgdec_read_frame_init(); | |
693 | |
694 mpgdec_open_stream(filename, -1); | |
695 | |
696 if (mpgdec_info->eof || !mpgdec_read_frame(&fr)) | |
697 mpgdec_info->eof = TRUE; | |
698 | |
699 if (!mpgdec_info->eof && mpgdec_info->going) { | |
700 if (mpgdec_cfg.channels == 2) | |
701 fr.single = -1; | |
702 else | |
703 fr.single = 3; | |
704 | |
705 fr.down_sample = mpgdec_cfg.downsample; | |
706 fr.down_sample_sblimit = SBLIMIT >> mpgdec_cfg.downsample; | |
707 set_synth_functions(&fr); | |
708 | |
709 mpgdec_info->tpf = mpgdec_compute_tpf(&fr); | |
710 if (!CHECK_STREAM(filename)) { | |
711 if (mpgdec_stream_check_for_xing_header(&fr, &xing_header)) { | |
712 mpgdec_info->num_frames = xing_header.frames; | |
713 have_xing_header = TRUE; | |
714 mpgdec_read_frame(&fr); | |
715 } | |
716 } | |
717 | |
718 for (;;) { | |
719 memcpy(&temp_fr, &fr, sizeof(struct frame)); | |
720 if (!mpgdec_read_frame(&temp_fr)) { | |
721 mpgdec_info->eof = TRUE; | |
722 break; | |
723 } | |
724 if (fr.lay != temp_fr.lay || | |
725 fr.sampling_frequency != temp_fr.sampling_frequency || | |
726 fr.stereo != temp_fr.stereo || fr.lsf != temp_fr.lsf) | |
727 memcpy(&fr, &temp_fr, sizeof(struct frame)); | |
728 else | |
729 break; | |
730 } | |
731 | |
732 if (!have_xing_header && !CHECK_STREAM(filename)) | |
733 mpgdec_info->num_frames = mpgdec_calc_numframes(&fr); | |
734 | |
735 memcpy(&fr, &temp_fr, sizeof(struct frame)); | |
736 mpgdec_bitrate = tabsel_123[fr.lsf][fr.lay - 1][fr.bitrate_index]; | |
737 disp_bitrate = mpgdec_bitrate; | |
738 mpgdec_frequency = mpgdec_freqs[fr.sampling_frequency]; | |
739 mpgdec_stereo = fr.stereo; | |
740 mpgdec_layer = fr.lay; | |
741 mpgdec_lsf = fr.lsf; | |
742 mpgdec_mpeg25 = fr.mpeg25; | |
743 mpgdec_mode = fr.mode; | |
744 | |
745 /* XXX: note that this is temporary, until custom resampling is implemented | |
746 * in prefs. | |
747 */ | |
748 if (fr.down_sample) | |
749 { | |
750 long n = mpgdec_freqs[fr.sampling_frequency]; | |
751 long m = n / (fr.down_sample * 2); | |
752 | |
753 mpgdec_synth_ntom_set_step(n, m); | |
754 | |
755 mpgdec_frequency = (gint) m; | |
756 } | |
757 | |
758 if (strncasecmp(filename, "http://", 7)) { | |
759 TitleInput *tuple = NULL; | |
760 mpgdec_length = mpgdec_info->num_frames * mpgdec_info->tpf * 1000; | |
761 if (!mpgdec_title) | |
762 { | |
763 tuple = get_song_tuple(filename); | |
764 mpgdec_title = get_song_title(tuple); | |
765 bmp_title_input_free(tuple); | |
766 } | |
767 } | |
768 else { | |
769 if (!mpgdec_title) | |
770 mpgdec_title = mpgdec_http_get_title(filename); | |
771 mpgdec_length = -1; | |
772 } | |
773 | |
774 set_synth_functions(&fr); | |
775 mpgdec_init_layer3(fr.down_sample_sblimit); | |
776 | |
777 mpgdec_ip.set_info(mpgdec_title, mpgdec_length, | |
778 mpgdec_bitrate * 1000, | |
779 mpgdec_freqs[fr.sampling_frequency], fr.stereo); | |
780 | |
781 output_opened = TRUE; | |
782 | |
783 if (!open_output()) { | |
784 audio_error = TRUE; | |
785 mpgdec_info->eof = TRUE; | |
786 } | |
787 else | |
788 play_frame(&fr); | |
789 } | |
790 | |
791 mpgdec_info->first_frame = FALSE; | |
792 while (mpgdec_info->going) { | |
793 if (mpgdec_info->jump_to_time != -1) { | |
794 void *xp = NULL; | |
795 if (have_xing_header) | |
796 xp = &xing_header; | |
797 if (mpgdec_seek(&fr, xp, vbr, mpgdec_info->jump_to_time) > -1) { | |
798 mpgdec_ip.output->flush(mpgdec_info->jump_to_time * 1000); | |
799 mpgdec_info->eof = FALSE; | |
800 } | |
801 mpgdec_info->jump_to_time = -1; | |
802 } | |
803 if (!mpgdec_info->eof) { | |
804 if (mpgdec_read_frame(&fr) != 0) { | |
805 if (fr.lay != mpgdec_layer || fr.lsf != mpgdec_lsf) { | |
806 memcpy(&temp_fr, &fr, sizeof(struct frame)); | |
807 if (mpgdec_read_frame(&temp_fr) != 0) { | |
808 if (fr.lay == temp_fr.lay && fr.lsf == temp_fr.lsf) { | |
809 mpgdec_layer = fr.lay; | |
810 mpgdec_lsf = fr.lsf; | |
811 memcpy(&fr, &temp_fr, sizeof(struct frame)); | |
812 } | |
813 else { | |
814 memcpy(&fr, &temp_fr, sizeof(struct frame)); | |
815 skip_frames = 2; | |
816 mpgdec_info->output_audio = FALSE; | |
817 continue; | |
818 } | |
819 | |
820 } | |
821 } | |
822 | |
823 if (tabsel_123[fr.lsf][fr.lay - 1][fr.bitrate_index] != | |
824 mpgdec_bitrate) | |
825 mpgdec_bitrate = | |
826 tabsel_123[fr.lsf][fr.lay - 1][fr.bitrate_index]; | |
827 | |
828 if (!disp_count) { | |
829 disp_count = 20; | |
830 if (mpgdec_bitrate != disp_bitrate) { | |
831 /* FIXME networks streams */ | |
832 disp_bitrate = mpgdec_bitrate; | |
833 if (!have_xing_header | |
834 && !CHECK_STREAM(filename)) { | |
835 double rel = mpgdec_relative_pos(); | |
836 if (rel) { | |
837 mpgdec_length = | |
838 mpgdec_ip.output->written_time() / rel; | |
839 vbr = TRUE; | |
840 } | |
841 | |
842 if (rel == 0 || !(mpgdec_length > 0)) { | |
843 mpgdec_info->num_frames = | |
844 mpgdec_calc_numframes(&fr); | |
845 mpgdec_info->tpf = mpgdec_compute_tpf(&fr); | |
846 mpgdec_length = | |
847 mpgdec_info->num_frames * | |
848 mpgdec_info->tpf * 1000; | |
849 } | |
850 | |
851 | |
852 } | |
853 mpgdec_ip.set_info(mpgdec_title, mpgdec_length, | |
854 mpgdec_bitrate * 1000, | |
855 mpgdec_frequency, mpgdec_stereo); | |
856 } | |
857 } | |
858 else | |
859 disp_count--; | |
860 play_frame(&fr); | |
861 } | |
862 else { | |
863 mpgdec_ip.output->buffer_free(); | |
864 mpgdec_ip.output->buffer_free(); | |
865 mpgdec_info->eof = TRUE; | |
866 g_usleep(10000); | |
867 } | |
868 } | |
869 else { | |
870 g_usleep(10000); | |
871 } | |
872 } | |
873 g_free(mpgdec_title); | |
874 mpgdec_title = NULL; | |
875 mpgdec_stream_close(); | |
876 if (output_opened && !audio_error) | |
877 mpgdec_ip.output->close_audio(); | |
878 g_free(mpgdec_pcm_sample); | |
879 mpgdec_filename = NULL; | |
880 g_free(filename); | |
881 | |
882 return NULL; | |
883 } | |
884 | |
885 static void | |
886 play_file(char *filename) | |
887 { | |
888 memset(&fr, 0, sizeof(struct frame)); | |
889 memset(&temp_fr, 0, sizeof(struct frame)); | |
890 | |
891 mpgdec_info = g_malloc0(sizeof(PlayerInfo)); | |
892 mpgdec_info->going = 1; | |
893 mpgdec_info->first_frame = TRUE; | |
894 mpgdec_info->output_audio = TRUE; | |
895 mpgdec_info->jump_to_time = -1; | |
896 skip_frames = 0; | |
897 audio_error = FALSE; | |
898 output_opened = FALSE; | |
899 dopause = FALSE; | |
900 | |
901 decode_thread = g_thread_create(decode_loop, g_strdup(filename), TRUE, | |
902 NULL); | |
903 } | |
904 | |
905 static void | |
906 stop(void) | |
907 { | |
908 if (mpgdec_info && mpgdec_info->going) { | |
909 mpgdec_info->going = FALSE; | |
910 g_thread_join(decode_thread); | |
911 g_free(mpgdec_info); | |
912 mpgdec_info = NULL; | |
913 } | |
914 } | |
915 | |
916 static void | |
917 seek(int time) | |
918 { | |
919 mpgdec_info->jump_to_time = time; | |
920 | |
921 while (mpgdec_info->jump_to_time != -1) | |
922 g_usleep(10000); | |
923 } | |
924 | |
925 static void | |
926 do_pause(short p) | |
927 { | |
928 if (output_opened) | |
929 mpgdec_ip.output->pause(p); | |
930 else | |
931 dopause = p; | |
932 } | |
933 | |
934 static int | |
935 get_time(void) | |
936 { | |
937 if (audio_error) | |
938 return -2; | |
939 if (!mpgdec_info) | |
940 return -1; | |
941 if (!mpgdec_info->going | |
942 || (mpgdec_info->eof && !mpgdec_ip.output->buffer_playing())) | |
943 return -1; | |
944 return mpgdec_ip.output->output_time(); | |
945 } | |
946 | |
947 static void | |
948 aboutbox(void) | |
949 { | |
950 static GtkWidget *aboutbox; | |
951 | |
952 if (aboutbox != NULL) | |
953 return; | |
954 | |
955 aboutbox = xmms_show_message(_("About MPEG Audio Plugin"), | |
956 _("Audacious decoding engine by William Pitcock <nenolod@nenolod.net>, derived from:\n" | |
957 "mpg123 decoding engine by Michael Hipp <mh@mpg123.de>\n" | |
958 "Derived partially from mpg123 0.59s.mc3 as well.\n" | |
959 "Based on the original XMMS plugin."), | |
960 _("Ok"), | |
961 FALSE, NULL, NULL); | |
962 | |
963 g_signal_connect(G_OBJECT(aboutbox), "destroy", | |
964 G_CALLBACK(gtk_widget_destroyed), &aboutbox); | |
965 } | |
966 | |
967 InputPlugin mpgdec_ip = { | |
968 NULL, | |
969 NULL, | |
970 NULL, /* Description */ | |
971 init, | |
972 aboutbox, | |
973 mpgdec_configure, | |
974 is_our_file, | |
975 NULL, | |
976 play_file, | |
977 stop, | |
978 do_pause, | |
979 seek, | |
980 NULL, | |
981 get_time, | |
982 NULL, NULL, | |
983 cleanup, | |
984 NULL, | |
985 NULL, NULL, NULL, | |
986 get_song_info, | |
987 mpgdec_file_info_box, /* file_info_box */ | |
988 NULL, | |
989 get_song_tuple | |
990 }; | |
991 | |
992 InputPlugin * | |
993 get_iplugin_info(void) | |
994 { | |
995 mpgdec_ip.description = g_strdup_printf(_("MPEG Audio Plugin")); | |
996 return &mpgdec_ip; | |
997 } |