Mercurial > audlegacy
annotate Plugins/Input/mpg123/mpg123.c @ 361:db298f2d3dd9 trunk
[svn] Detect files by content; remove quick detect.
author | chainsaw |
---|---|
date | Fri, 30 Dec 2005 17:56:32 -0800 |
parents | e2775c9b8b13 |
children | 3fb3657d2e14 |
rev | line source |
---|---|
61 | 1 #include "mpg123.h" |
354
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
2 #include "common.h" |
61 | 3 |
4 #include <glib.h> | |
5 #include <glib/gi18n.h> | |
6 #include <gtk/gtk.h> | |
7 #include <stdlib.h> | |
8 #include <string.h> | |
354
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
9 #include <unistd.h> |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
10 |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
11 #include <fcntl.h> |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
12 #include <unistd.h> |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
13 #include <errno.h> |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
14 #include <sys/types.h> |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
15 #include <sys/socket.h> |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
16 #include <sys/time.h> |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
17 #include <netinet/in.h> |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
18 #include <arpa/inet.h> |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
19 #include <netdb.h> |
61 | 20 |
21 #include <libaudacious/util.h> | |
22 #include <libaudacious/configdb.h> | |
23 #include <libaudacious/vfs.h> | |
24 #include <libaudacious/titlestring.h> | |
25 | |
26 #include "audacious/util.h" | |
27 | |
28 static const long outscale = 32768; | |
29 | |
354
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
30 #define BUFSIZE_X 2048 |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
31 |
61 | 32 static struct frame fr, temp_fr; |
33 | |
34 PlayerInfo *mpg123_info = NULL; | |
35 static GThread *decode_thread; | |
36 | |
37 static gboolean audio_error = FALSE, output_opened = FALSE, dopause = FALSE; | |
38 gint mpg123_bitrate, mpg123_frequency, mpg123_length, mpg123_layer, | |
39 mpg123_lsf; | |
40 gchar *mpg123_title = NULL, *mpg123_filename = NULL; | |
41 static int disp_bitrate, skip_frames = 0; | |
42 static int cpu_fflags, cpu_efflags; | |
43 gboolean mpg123_stereo, mpg123_mpeg25; | |
44 int mpg123_mode; | |
45 | |
46 gchar **mpg123_id3_encoding_list = NULL; | |
47 | |
48 const char *mpg123_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 mpg123_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 /= mpg123_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) (real *, int, unsigned char *, int *); | |
109 typedef int (*func_mono) (real *, unsigned char *, int *); | |
110 typedef void (*func_dct36) (real *, real *, real *, real *, real *); | |
111 | |
112 int ds = fr->down_sample; | |
113 int p8 = 0; | |
114 | |
115 static func funcs[][3] = { | |
116 {mpg123_synth_1to1, | |
117 mpg123_synth_2to1, | |
118 mpg123_synth_4to1}, | |
119 {mpg123_synth_1to1_8bit, | |
120 mpg123_synth_2to1_8bit, | |
121 mpg123_synth_4to1_8bit}, | |
122 }; | |
123 | |
124 static func_mono funcs_mono[2][4] = { | |
125 {mpg123_synth_1to1_mono, | |
126 mpg123_synth_2to1_mono, | |
127 mpg123_synth_4to1_mono}, | |
128 {mpg123_synth_1to1_8bit_mono, | |
129 mpg123_synth_2to1_8bit_mono, | |
130 mpg123_synth_4to1_8bit_mono} | |
131 }; | |
132 | |
133 if (mpg123_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 mpg123_make_conv16to8_table(); | |
141 } | |
142 } | |
143 | |
144 static void | |
145 init(void) | |
146 { | |
147 ConfigDb *db; | |
148 | |
149 mpg123_make_decode_tables(outscale); | |
150 | |
151 mpg123_cfg.resolution = 16; | |
152 mpg123_cfg.channels = 2; | |
153 mpg123_cfg.downsample = 0; | |
154 mpg123_cfg.http_buffer_size = 128; | |
155 mpg123_cfg.http_prebuffer = 25; | |
156 mpg123_cfg.proxy_port = 8080; | |
157 mpg123_cfg.proxy_use_auth = FALSE; | |
158 mpg123_cfg.proxy_user = NULL; | |
159 mpg123_cfg.proxy_pass = NULL; | |
160 mpg123_cfg.use_udp_channel = TRUE; | |
161 mpg123_cfg.title_override = FALSE; | |
162 mpg123_cfg.disable_id3v2 = FALSE; | |
163 mpg123_cfg.detect_by = DETECT_EXTENSION; | |
164 mpg123_cfg.default_synth = SYNTH_AUTO; | |
165 | |
166 mpg123_cfg.title_encoding_enabled = FALSE; | |
167 mpg123_cfg.title_encoding = NULL; | |
168 | |
169 db = bmp_cfg_db_open(); | |
170 | |
171 bmp_cfg_db_get_int(db, "MPG123", "resolution", &mpg123_cfg.resolution); | |
172 bmp_cfg_db_get_int(db, "MPG123", "channels", &mpg123_cfg.channels); | |
173 bmp_cfg_db_get_int(db, "MPG123", "downsample", &mpg123_cfg.downsample); | |
174 bmp_cfg_db_get_int(db, "MPG123", "http_buffer_size", | |
175 &mpg123_cfg.http_buffer_size); | |
176 bmp_cfg_db_get_int(db, "MPG123", "http_prebuffer", | |
177 &mpg123_cfg.http_prebuffer); | |
178 bmp_cfg_db_get_bool(db, "MPG123", "save_http_stream", | |
179 &mpg123_cfg.save_http_stream); | |
180 if (!bmp_cfg_db_get_string | |
181 (db, "MPG123", "save_http_path", &mpg123_cfg.save_http_path)) | |
182 mpg123_cfg.save_http_path = g_strdup(g_get_home_dir()); | |
183 | |
184 bmp_cfg_db_get_bool(db, "MPG123", "use_udp_channel", | |
185 &mpg123_cfg.use_udp_channel); | |
186 | |
187 bmp_cfg_db_get_bool(db, "MPG123", "use_proxy", &mpg123_cfg.use_proxy); | |
188 if (!bmp_cfg_db_get_string | |
189 (db, "MPG123", "proxy_host", &mpg123_cfg.proxy_host)) | |
190 mpg123_cfg.proxy_host = g_strdup("localhost"); | |
191 bmp_cfg_db_get_int(db, "MPG123", "proxy_port", &mpg123_cfg.proxy_port); | |
192 bmp_cfg_db_get_bool(db, "MPG123", "proxy_use_auth", | |
193 &mpg123_cfg.proxy_use_auth); | |
194 bmp_cfg_db_get_string(db, "MPG123", "proxy_user", &mpg123_cfg.proxy_user); | |
195 bmp_cfg_db_get_string(db, "MPG123", "proxy_pass", &mpg123_cfg.proxy_pass); | |
196 | |
197 bmp_cfg_db_get_bool(db, "MPG123", "title_override", | |
198 &mpg123_cfg.title_override); | |
199 bmp_cfg_db_get_bool(db, "MPG123", "disable_id3v2", | |
200 &mpg123_cfg.disable_id3v2); | |
201 if (!bmp_cfg_db_get_string | |
202 (db, "MPG123", "id3_format", &mpg123_cfg.id3_format)) | |
203 mpg123_cfg.id3_format = g_strdup("%p - %t"); | |
204 bmp_cfg_db_get_int(db, "MPG123", "detect_by", &mpg123_cfg.detect_by); | |
205 bmp_cfg_db_get_int(db, "MPG123", "default_synth", | |
206 &mpg123_cfg.default_synth); | |
207 | |
208 bmp_cfg_db_get_bool(db, "MPG123", "title_encoding_enabled", &mpg123_cfg.title_encoding_enabled); | |
209 bmp_cfg_db_get_string(db, "MPG123", "title_encoding", &mpg123_cfg.title_encoding); | |
210 if (mpg123_cfg.title_encoding_enabled) | |
211 mpg123_id3_encoding_list = g_strsplit_set(mpg123_cfg.title_encoding, ENCODING_SEPARATOR, 0); | |
212 | |
213 bmp_cfg_db_close(db); | |
214 | |
215 if (mpg123_cfg.resolution != 16 && mpg123_cfg.resolution != 8) | |
216 mpg123_cfg.resolution = 16; | |
217 | |
218 mpg123_cfg.channels = CLAMP(mpg123_cfg.channels, 0, 2); | |
219 mpg123_cfg.downsample = CLAMP(mpg123_cfg.downsample, 0, 2); | |
220 mpg123_getcpuflags(&cpu_fflags, &cpu_efflags); | |
221 } | |
222 | |
223 static void | |
224 cleanup(void) | |
225 { | |
226 g_strfreev(mpg123_id3_encoding_list); | |
227 } | |
228 | |
229 /* needed for is_our_file() */ | |
230 static int | |
231 read_n_bytes(VFSFile * file, guint8 * buf, int n) | |
232 { | |
233 | |
234 if (vfs_fread(buf, 1, n, file) != n) { | |
235 return FALSE; | |
236 } | |
237 return TRUE; | |
238 } | |
239 | |
240 static guint32 | |
241 convert_to_header(guint8 * buf) | |
242 { | |
243 | |
244 return (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]; | |
245 } | |
246 | |
247 static guint32 | |
248 convert_to_long(guint8 * buf) | |
249 { | |
250 | |
251 return (buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + buf[0]; | |
252 } | |
253 | |
254 static guint16 | |
255 read_wav_id(char *filename) | |
256 { | |
257 VFSFile *file; | |
258 guint16 wavid; | |
259 guint8 buf[4]; | |
260 guint32 head; | |
261 long seek; | |
262 | |
263 if (!(file = vfs_fopen(filename, "rb"))) { /* Could not open file */ | |
264 return 0; | |
265 } | |
266 if (!(read_n_bytes(file, buf, 4))) { | |
267 vfs_fclose(file); | |
268 return 0; | |
269 } | |
270 head = convert_to_header(buf); | |
271 if (head == ('R' << 24) + ('I' << 16) + ('F' << 8) + 'F') { /* Found a riff -- maybe WAVE */ | |
272 if (vfs_fseek(file, 4, SEEK_CUR) != 0) { /* some error occured */ | |
273 vfs_fclose(file); | |
274 return 0; | |
275 } | |
276 if (!(read_n_bytes(file, buf, 4))) { | |
277 vfs_fclose(file); | |
278 return 0; | |
279 } | |
280 head = convert_to_header(buf); | |
281 if (head == ('W' << 24) + ('A' << 16) + ('V' << 8) + 'E') { /* Found a WAVE */ | |
282 seek = 0; | |
283 do { | |
284 /* we'll be looking for the fmt-chunk which comes before the data-chunk */ | |
285 /* A chunk consists of an header identifier (4 bytes), the length of the chunk | |
286 (4 bytes), and the chunkdata itself, padded to be an even number of bytes. | |
287 We'll skip all chunks until we find the "data"-one which could contain | |
288 mpeg-data */ | |
289 if (seek != 0) { | |
290 if (vfs_fseek(file, seek, SEEK_CUR) != 0) { /* some error occured */ | |
291 vfs_fclose(file); | |
292 return 0; | |
293 } | |
294 } | |
295 if (!(read_n_bytes(file, buf, 4))) { | |
296 vfs_fclose(file); | |
297 return 0; | |
298 } | |
299 head = convert_to_header(buf); | |
300 if (!(read_n_bytes(file, buf, 4))) { | |
301 vfs_fclose(file); | |
302 return 0; | |
303 } | |
304 seek = convert_to_long(buf); | |
305 seek = seek + (seek % 2); /* Has to be even (padding) */ | |
306 if (seek >= 2 | |
307 && head == ('f' << 24) + ('m' << 16) + ('t' << 8) + ' ') { | |
308 if (!(read_n_bytes(file, buf, 2))) { | |
309 vfs_fclose(file); | |
310 return 0; | |
311 } | |
312 wavid = buf[0] + 256 * buf[1]; | |
313 seek -= 2; | |
314 /* we could go on looking for | |
315 other things, but all we | |
316 wanted was the wavid */ | |
317 vfs_fclose(file); | |
318 return wavid; | |
319 } | |
320 } | |
321 while (head != ('d' << 24) + ('a' << 16) + ('t' << 8) + 'a'); | |
322 /* it's RIFF WAVE */ | |
323 } | |
324 /* it's RIFF */ | |
325 } | |
326 /* it's not even RIFF */ | |
327 vfs_fclose(file); | |
328 return 0; | |
329 } | |
330 | |
331 #define DET_BUF_SIZE 1024 | |
332 | |
333 static gboolean | |
334 mpg123_detect_by_content(char *filename) | |
335 { | |
336 VFSFile *file; | |
337 guchar tmp[4]; | |
338 guint32 head; | |
339 struct frame fr; | |
340 guchar buf[DET_BUF_SIZE]; | |
341 int in_buf, i; | |
342 gboolean ret = FALSE; | |
343 | |
344 if ((file = vfs_fopen(filename, "rb")) == NULL) | |
345 return FALSE; | |
346 if (vfs_fread(tmp, 1, 4, file) != 4) | |
347 goto done; | |
348 head = convert_to_header(tmp); | |
349 while (!mpg123_head_check(head)) { | |
350 /* | |
351 * The mpeg-stream can start anywhere in the file, | |
352 * so we check the entire file | |
353 */ | |
354 /* Optimize this */ | |
355 in_buf = vfs_fread(buf, 1, DET_BUF_SIZE, file); | |
356 if (in_buf == 0) | |
357 goto done; | |
358 | |
359 for (i = 0; i < in_buf; i++) { | |
360 head <<= 8; | |
361 head |= buf[i]; | |
362 if (mpg123_head_check(head)) { | |
363 vfs_fseek(file, i + 1 - in_buf, SEEK_CUR); | |
364 break; | |
365 } | |
366 } | |
367 } | |
368 if (mpg123_decode_header(&fr, head)) { | |
369 /* | |
370 * We found something which looks like a MPEG-header. | |
371 * We check the next frame too, to be sure | |
372 */ | |
373 | |
374 if (vfs_fseek(file, fr.framesize, SEEK_CUR) != 0) | |
375 goto done; | |
376 if (vfs_fread(tmp, 1, 4, file) != 4) | |
377 goto done; | |
378 head = convert_to_header(tmp); | |
379 if (mpg123_head_check(head) && mpg123_decode_header(&fr, head)) | |
380 ret = TRUE; | |
381 } | |
382 | |
383 done: | |
384 vfs_fclose(file); | |
385 return ret; | |
386 } | |
387 | |
354
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
388 static gboolean |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
389 mpg123_detect_by_content_stream(gchar *url) |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
390 { |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
391 gchar *buf, inbuf[BUFSIZE_X]; |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
392 struct hostent *hp; |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
393 struct sockaddr_in sa; |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
394 gint s, i, y = 0; |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
395 gchar *user, *pass, *host, *filename; |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
396 gint port; |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
397 |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
398 g_strstrip(url); |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
399 |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
400 parse_url(url, &user, &pass, &host, &port, &filename); |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
401 |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
402 if (!(s = socket(AF_INET, SOCK_STREAM, 0))) |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
403 { |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
404 perror("socket"); |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
405 return FALSE; |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
406 } |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
407 |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
408 if ((hp = gethostbyname(host)) == NULL) |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
409 { |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
410 g_print("[stream detect] Unable to resolve %s\n", host); |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
411 close(s); |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
412 return FALSE; |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
413 } |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
414 |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
415 memset(&sa, '\0', sizeof(sa)); |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
416 sa.sin_family = AF_INET; |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
417 sa.sin_port = htons(port); |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
418 memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
419 |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
420 if (connect(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
421 { |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
422 perror("connect"); |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
423 return FALSE; |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
424 } |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
425 |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
426 g_print("[stream detect] connected to %s, port %d\n", host, port); |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
427 |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
428 buf = g_strdup_printf("GET /%s HTTP/1.0\r\nUser-Agent: " PACKAGE "/" PACKAGE_VERSION "\r\n\r\n", filename ? filename : ""); |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
429 i = write(s, buf, strlen(buf)); |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
430 g_free(buf); |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
431 |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
432 if (i == -1) |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
433 { |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
434 perror("write"); |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
435 return FALSE; |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
436 } |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
437 |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
438 /* don't ask. --nenolod */ |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
439 while ((i = read(s, inbuf + y, BUFSIZE_X - y)) != 0 && y < BUFSIZE_X) |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
440 { |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
441 inbuf[y + i] = '\0'; |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
442 y += i; |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
443 } |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
444 |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
445 close(s); |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
446 |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
447 buf = strtok(inbuf, "\n"); |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
448 while ((buf = strtok(NULL, "\n")) != NULL) |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
449 { |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
450 if (!g_strncasecmp("content-type:audio/mpeg", buf, 23) || |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
451 !g_strncasecmp("icy-br:", buf, 7) || /* XXX ShoutCAST sometimes doesnt send the content-type header */ |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
452 !g_strncasecmp("Content-Type: audio/mpeg", buf, 24)) |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
453 { |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
454 g_print("[stream detect] server is providing audio/mpeg stream\n"); |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
455 return TRUE; |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
456 } |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
457 } |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
458 |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
459 g_print("[stream detect] server is NOT providing audio/mpeg stream\n"); |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
460 return FALSE; |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
461 } |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
462 |
61 | 463 static int |
464 is_our_file(char *filename) | |
465 { | |
466 char *ext; | |
467 guint16 wavid; | |
468 | |
469 /* FIXME: wtf? */ | |
470 /* We assume all http:// (except those ending in .ogg) are mpeg -- | |
471 * why do we do that? */ | |
472 if (!strncasecmp(filename, "http://", 7)) { | |
354
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
473 #ifdef NOTYET |
61 | 474 ext = strrchr(filename, '.'); |
475 if (ext) { | |
476 if (!strncasecmp(ext, ".ogg", 4)) | |
477 return FALSE; | |
478 if (!strncasecmp(ext, ".rm", 3) || | |
479 !strncasecmp(ext, ".ra", 3) || | |
480 !strncasecmp(ext, ".rpm", 4) || | |
481 !strncasecmp(ext, ".ram", 4)) | |
482 return FALSE; | |
483 } | |
484 return TRUE; | |
354
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
485 #else |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
486 return mpg123_detect_by_content_stream(filename); |
e2775c9b8b13
[svn] very rudementary http stream detection support for mpg123-clone.
nenolod
parents:
353
diff
changeset
|
487 #endif |
61 | 488 } |
489 if (mpg123_cfg.detect_by == DETECT_CONTENT) | |
490 return (mpg123_detect_by_content(filename)); | |
491 | |
492 ext = strrchr(filename, '.'); | |
493 if (ext) { | |
353
18f881216679
[svn] mpg123-clone: Add '.mp3.part' to list of allowed extension types.
nenolod
parents:
352
diff
changeset
|
494 if (!strncasecmp(ext, ".mp2", 4) || !strncasecmp(ext, ".mp3", 4) || !strncasecmp((ext - 4), ".mp3.part", 9) ) { |
61 | 495 return TRUE; |
496 } | |
497 if (!strncasecmp(ext, ".wav", 4)) { | |
498 wavid = read_wav_id(filename); | |
499 if (wavid == 85 || wavid == 80) { /* Microsoft says 80, files say 85... */ | |
500 return TRUE; | |
501 } | |
502 } | |
503 } | |
504 | |
505 if (mpg123_cfg.detect_by == DETECT_BOTH) | |
506 return (mpg123_detect_by_content(filename)); | |
507 return FALSE; | |
508 } | |
509 | |
510 static void | |
511 play_frame(struct frame *fr) | |
512 { | |
513 if (fr->error_protection) { | |
514 bsi.wordpointer += 2; | |
515 /* mpg123_getbits(16); *//* skip crc */ | |
516 } | |
517 if (!fr->do_layer(fr)) { | |
518 skip_frames = 2; | |
519 mpg123_info->output_audio = FALSE; | |
520 } | |
521 else { | |
522 if (!skip_frames) | |
523 mpg123_info->output_audio = TRUE; | |
524 else | |
525 skip_frames--; | |
526 } | |
527 } | |
528 | |
529 static const char * | |
530 get_id3_genre(unsigned char genre_code) | |
531 { | |
532 if (genre_code < GENRE_MAX) | |
533 return gettext(mpg123_id3_genres[genre_code]); | |
534 | |
535 return ""; | |
536 } | |
537 | |
538 guint | |
539 mpg123_strip_spaces(char *src, size_t n) | |
540 { | |
541 gchar *space = NULL, /* last space in src */ | |
542 *start = src; | |
543 | |
544 while (n--) | |
545 switch (*src++) { | |
546 case '\0': | |
547 n = 0; /* breaks out of while loop */ | |
548 | |
549 src--; | |
550 break; | |
551 case ' ': | |
552 if (space == NULL) | |
553 space = src - 1; | |
554 break; | |
555 default: | |
556 space = NULL; /* don't terminate intermediate spaces */ | |
557 | |
558 break; | |
559 } | |
560 if (space != NULL) { | |
561 src = space; | |
562 *src = '\0'; | |
563 } | |
564 return src - start; | |
565 } | |
566 | |
567 /* | |
568 * Function extname (filename) | |
569 * | |
570 * Return pointer within filename to its extenstion, or NULL if | |
571 * filename has no extension. | |
572 * | |
573 */ | |
574 static gchar * | |
575 extname(const char *filename) | |
576 { | |
577 gchar *ext = strrchr(filename, '.'); | |
578 | |
579 if (ext != NULL) | |
580 ++ext; | |
581 | |
582 return ext; | |
583 } | |
584 | |
585 /* | |
586 * Function id3v1_to_id3v2 (v1, v2) | |
587 * | |
588 * Convert ID3v1 tag `v1' to ID3v2 tag `v2'. | |
589 * | |
590 */ | |
591 void | |
592 mpg123_id3v1_to_id3v2(struct id3v1tag_t *v1, struct id3tag_t *v2) | |
593 { | |
594 memset(v2, 0, sizeof(struct id3tag_t)); | |
595 strncpy(v2->title, v1->title, 30); | |
596 strncpy(v2->artist, v1->artist, 30); | |
597 strncpy(v2->album, v1->album, 30); | |
598 strncpy(v2->comment, v1->u.v1_0.comment, 30); | |
599 strncpy(v2->genre, get_id3_genre(v1->genre), sizeof(v2->genre)); | |
600 g_strstrip(v2->title); | |
601 g_strstrip(v2->artist); | |
602 g_strstrip(v2->album); | |
603 g_strstrip(v2->comment); | |
604 g_strstrip(v2->genre); | |
605 v2->year = atoi(v1->year); | |
606 | |
607 /* Check for v1.1 tags. */ | |
608 if (v1->u.v1_1.__zero == 0) | |
609 v2->track_number = v1->u.v1_1.track_number; | |
610 else | |
611 v2->track_number = 0; | |
612 } | |
613 | |
614 static char * | |
615 mpg123_getstr(char *str) | |
616 { | |
617 if (str && strlen(str) > 0) | |
618 return str; | |
619 return NULL; | |
620 } | |
621 | |
622 static gchar * | |
623 convert_id3_title(gchar * title) | |
624 { | |
625 gchar **encoding = mpg123_id3_encoding_list; | |
626 gchar *new_title = NULL; | |
627 | |
628 if (g_utf8_validate(title, -1, NULL)) | |
629 return title; | |
630 | |
631 while (*encoding && !new_title) { | |
632 new_title = g_convert(title, strlen(title), "UTF-8", *encoding++, | |
633 NULL, NULL, NULL); | |
634 } | |
635 | |
636 if (new_title) { | |
637 g_free(title); | |
638 return new_title; | |
639 } | |
640 | |
641 /* FIXME: We're relying on BMP core to provide fallback | |
642 * conversion */ | |
643 return title; | |
644 } | |
645 | |
646 /* | |
647 * Function mpg123_format_song_title (tag, filename) | |
648 * | |
649 * Create song title according to `tag' and/or `filename' and | |
650 * return it. The title must be subsequently freed using g_free(). | |
651 * | |
652 */ | |
653 gchar * | |
654 mpg123_format_song_title(struct id3tag_t * tag, gchar * filename) | |
655 { | |
656 gchar *title = NULL; | |
657 TitleInput *input; | |
658 | |
659 input = bmp_title_input_new(); | |
660 | |
661 if (tag) { | |
662 input->performer = mpg123_getstr(tag->artist); | |
663 input->album_name = mpg123_getstr(tag->album); | |
664 input->track_name = mpg123_getstr(tag->title); | |
665 input->year = tag->year; | |
666 input->track_number = tag->track_number; | |
667 input->genre = mpg123_getstr(tag->genre); | |
668 input->comment = mpg123_getstr(tag->comment); | |
669 } | |
670 | |
671 input->file_name = g_path_get_basename(filename); | |
672 input->file_path = g_path_get_dirname(filename); | |
673 input->file_ext = extname(filename); | |
674 | |
675 title = xmms_get_titlestring(mpg123_cfg.title_override ? | |
676 mpg123_cfg.id3_format : | |
677 xmms_get_gentitle_format(), input); | |
678 | |
679 if (!title) { | |
680 /* Format according to filename. */ | |
681 title = g_path_get_basename(filename); | |
682 if (extname(title)) | |
683 *(extname(title) - 1) = '\0'; /* removes period */ | |
684 } | |
685 | |
686 g_free(input->file_path); | |
687 g_free(input->file_name); | |
688 g_free(input); | |
689 | |
690 if (mpg123_cfg.title_encoding_enabled) | |
691 title = convert_id3_title(title); | |
692 | |
693 return title; | |
694 } | |
695 | |
696 /* | |
697 * Function mpg123_get_id3v2 (id3d, tag) | |
698 * | |
699 * Get desired contents from the indicated id3tag and store it in | |
700 * `tag'. | |
701 * | |
702 */ | |
703 void | |
704 mpg123_get_id3v2(struct id3_tag *id3d, struct id3tag_t *tag) | |
705 { | |
706 struct id3_frame *id3frm; | |
707 gchar *txt; | |
708 gint tlen, num; | |
709 | |
710 #define ID3_SET(_tid,_fld) \ | |
711 { \ | |
712 id3frm = id3_get_frame( id3d, _tid, 1 ); \ | |
713 if (id3frm) { \ | |
714 txt = _tid == ID3_TCON ? id3_get_content(id3frm) \ | |
715 : id3_get_text(id3frm); \ | |
716 if(txt) \ | |
717 { \ | |
718 tlen = strlen(txt); \ | |
719 if ( tlen >= sizeof(tag->_fld) ) \ | |
720 tlen = sizeof(tag->_fld)-1; \ | |
721 strncpy( tag->_fld, txt, tlen ); \ | |
722 tag->_fld[tlen] = 0; \ | |
723 g_free(txt); \ | |
724 } \ | |
725 else \ | |
726 tag->_fld[0] = 0; \ | |
727 } else { \ | |
728 tag->_fld[0] = 0; \ | |
729 } \ | |
730 } | |
731 | |
732 #define ID3_SET_NUM(_tid,_fld) \ | |
733 { \ | |
734 id3frm = id3_get_frame(id3d, _tid, 1); \ | |
735 if (id3frm) { \ | |
736 num = id3_get_text_number(id3frm); \ | |
737 tag->_fld = num >= 0 ? num : 0; \ | |
738 } else \ | |
739 tag->_fld = 0; \ | |
740 } | |
741 | |
742 ID3_SET(ID3_TIT2, title); | |
743 ID3_SET(ID3_TPE1, artist); | |
744 if (strlen(tag->artist) == 0) | |
745 ID3_SET(ID3_TPE2, artist); | |
746 ID3_SET(ID3_TALB, album); | |
747 ID3_SET_NUM(ID3_TYER, year); | |
748 ID3_SET_NUM(ID3_TRCK, track_number); | |
749 ID3_SET(ID3_COMM, comment); | |
750 ID3_SET(ID3_TCON, genre); | |
751 } | |
752 | |
753 | |
754 /* | |
755 * Function get_song_title (fd, filename) | |
756 * | |
757 * Get song title of file. File position of `fd' will be | |
758 * clobbered. `fd' may be NULL, in which case `filename' is opened | |
759 * separately. The returned song title must be subsequently freed | |
760 * using g_free(). | |
761 * | |
762 */ | |
763 static gchar * | |
764 get_song_title(VFSFile * fd, char *filename) | |
765 { | |
766 VFSFile *file = fd; | |
767 char *ret = NULL; | |
768 struct id3v1tag_t id3v1tag; | |
769 struct id3tag_t id3tag; | |
770 | |
771 if (file || (file = vfs_fopen(filename, "rb")) != 0) { | |
772 struct id3_tag *id3 = NULL; | |
773 | |
774 /* | |
775 * Try reading ID3v2 tag. | |
776 */ | |
777 if (!mpg123_cfg.disable_id3v2) { | |
778 vfs_fseek(file, 0, SEEK_SET); | |
779 id3 = id3_open_fp(file, 0); | |
780 if (id3) { | |
781 mpg123_get_id3v2(id3, &id3tag); | |
782 ret = mpg123_format_song_title(&id3tag, filename); | |
783 id3_close(id3); | |
784 } | |
785 } | |
786 | |
787 /* | |
788 * Try reading ID3v1 tag. | |
789 */ | |
790 if (!id3 && (vfs_fseek(file, -1 * sizeof(id3v1tag), SEEK_END) == 0) && | |
791 (vfs_fread(&id3v1tag, 1, sizeof(id3v1tag), file) == | |
792 sizeof(id3v1tag)) && (strncmp(id3v1tag.tag, "TAG", 3) == 0)) { | |
793 mpg123_id3v1_to_id3v2(&id3v1tag, &id3tag); | |
794 ret = mpg123_format_song_title(&id3tag, filename); | |
795 } | |
796 | |
797 if (!fd) | |
798 /* | |
799 * File was opened in this function. | |
800 */ | |
801 vfs_fclose(file); | |
802 } | |
803 | |
804 if (ret == NULL) | |
805 /* | |
806 * Unable to get ID3 tag. | |
807 */ | |
808 ret = mpg123_format_song_title(NULL, filename); | |
809 | |
810 return ret; | |
811 } | |
812 | |
813 static long | |
814 get_song_length(VFSFile * file) | |
815 { | |
816 int len; | |
817 char tmp[4]; | |
818 | |
819 vfs_fseek(file, 0, SEEK_END); | |
820 len = vfs_ftell(file); | |
821 vfs_fseek(file, -128, SEEK_END); | |
822 vfs_fread(tmp, 1, 3, file); | |
823 if (!strncmp(tmp, "TAG", 3)) | |
824 len -= 128; | |
825 return len; | |
826 } | |
827 | |
828 | |
829 static guint | |
830 get_song_time(VFSFile * file) | |
831 { | |
832 guint32 head; | |
833 guchar tmp[4], *buf; | |
834 struct frame frm; | |
835 xing_header_t xing_header; | |
836 double tpf, bpf; | |
837 guint32 len; | |
838 | |
839 if (!file) | |
840 return -1; | |
841 | |
842 vfs_fseek(file, 0, SEEK_SET); | |
843 if (vfs_fread(tmp, 1, 4, file) != 4) | |
844 return 0; | |
845 head = convert_to_header(tmp); | |
846 while (!mpg123_head_check(head)) { | |
847 head <<= 8; | |
848 if (vfs_fread(tmp, 1, 1, file) != 1) | |
849 return 0; | |
850 head |= tmp[0]; | |
851 } | |
852 if (mpg123_decode_header(&frm, head)) { | |
853 buf = g_malloc(frm.framesize + 4); | |
854 vfs_fseek(file, -4, SEEK_CUR); | |
855 vfs_fread(buf, 1, frm.framesize + 4, file); | |
856 tpf = mpg123_compute_tpf(&frm); | |
857 if (mpg123_get_xing_header(&xing_header, buf)) { | |
858 g_free(buf); | |
859 if (xing_header.bytes == 0) | |
860 xing_header.bytes = get_song_length(file); | |
861 return (tpf * xing_header.frames * 1000); | |
862 } | |
863 g_free(buf); | |
864 bpf = mpg123_compute_bpf(&frm); | |
865 len = get_song_length(file); | |
866 return ((guint) (len / bpf) * tpf * 1000); | |
867 } | |
868 return 0; | |
869 } | |
870 | |
871 static void | |
872 get_song_info(char *filename, char **title_real, int *len_real) | |
873 { | |
874 VFSFile *file; | |
875 | |
876 (*len_real) = -1; | |
877 (*title_real) = NULL; | |
878 | |
879 /* | |
880 * TODO: Getting song info from http streams. | |
881 */ | |
882 if (!strncasecmp(filename, "http://", 7)) | |
883 return; | |
884 | |
885 if ((file = vfs_fopen(filename, "rb")) != NULL) { | |
886 (*len_real) = get_song_time(file); | |
887 (*title_real) = get_song_title(file, filename); | |
888 vfs_fclose(file); | |
889 } | |
890 } | |
891 | |
892 static int | |
893 open_output(void) | |
894 { | |
895 int r; | |
896 AFormat fmt = mpg123_cfg.resolution == 16 ? FMT_S16_NE : FMT_U8; | |
897 int freq = mpg123_freqs[fr.sampling_frequency] >> mpg123_cfg.downsample; | |
898 int channels = mpg123_cfg.channels == 2 ? fr.stereo : 1; | |
899 r = mpg123_ip.output->open_audio(fmt, freq, channels); | |
900 | |
901 if (r && dopause) { | |
902 mpg123_ip.output->pause(TRUE); | |
903 dopause = FALSE; | |
904 } | |
905 | |
906 return r; | |
907 } | |
908 | |
909 | |
910 static int | |
911 mpg123_seek(struct frame *fr, xing_header_t * xh, gboolean vbr, int time) | |
912 { | |
913 int jumped = -1; | |
914 | |
915 if (xh) { | |
916 int percent = ((double) time * 100.0) / | |
917 (mpg123_info->num_frames * mpg123_info->tpf); | |
918 int byte = mpg123_seek_point(xh, percent); | |
919 jumped = mpg123_stream_jump_to_byte(fr, byte); | |
920 } | |
921 else if (vbr && mpg123_length > 0) { | |
922 int byte = ((guint64) time * 1000 * mpg123_info->filesize) / | |
923 mpg123_length; | |
924 jumped = mpg123_stream_jump_to_byte(fr, byte); | |
925 } | |
926 else { | |
927 int frame = time / mpg123_info->tpf; | |
928 jumped = mpg123_stream_jump_to_frame(fr, frame); | |
929 } | |
930 | |
931 return jumped; | |
932 } | |
933 | |
934 | |
935 static void * | |
936 decode_loop(void *arg) | |
937 { | |
938 gboolean have_xing_header = FALSE, vbr = FALSE; | |
939 int disp_count = 0, temp_time; | |
940 char *filename = arg; | |
941 xing_header_t xing_header; | |
942 | |
943 /* This is used by fileinfo on http streams */ | |
944 mpg123_bitrate = 0; | |
945 | |
946 mpg123_pcm_sample = g_malloc0(32768); | |
947 mpg123_pcm_point = 0; | |
948 mpg123_filename = filename; | |
949 | |
950 mpg123_read_frame_init(); | |
951 | |
952 mpg123_open_stream(filename, -1); | |
953 | |
954 if (mpg123_info->eof || !mpg123_read_frame(&fr)) | |
955 mpg123_info->eof = TRUE; | |
956 | |
957 if (!mpg123_info->eof && mpg123_info->going) { | |
958 if (mpg123_cfg.channels == 2) | |
959 fr.single = -1; | |
960 else | |
961 fr.single = 3; | |
962 | |
963 fr.down_sample = mpg123_cfg.downsample; | |
964 fr.down_sample_sblimit = SBLIMIT >> mpg123_cfg.downsample; | |
965 set_synth_functions(&fr); | |
966 mpg123_init_layer3(fr.down_sample_sblimit); | |
967 | |
968 mpg123_info->tpf = mpg123_compute_tpf(&fr); | |
969 if (strncasecmp(filename, "http://", 7)) { | |
970 if (mpg123_stream_check_for_xing_header(&fr, &xing_header)) { | |
971 mpg123_info->num_frames = xing_header.frames; | |
972 have_xing_header = TRUE; | |
973 mpg123_read_frame(&fr); | |
974 } | |
975 } | |
976 | |
977 for (;;) { | |
978 memcpy(&temp_fr, &fr, sizeof(struct frame)); | |
979 if (!mpg123_read_frame(&temp_fr)) { | |
980 mpg123_info->eof = TRUE; | |
981 break; | |
982 } | |
983 if (fr.lay != temp_fr.lay || | |
984 fr.sampling_frequency != temp_fr.sampling_frequency || | |
985 fr.stereo != temp_fr.stereo || fr.lsf != temp_fr.lsf) | |
986 memcpy(&fr, &temp_fr, sizeof(struct frame)); | |
987 else | |
988 break; | |
989 } | |
990 | |
991 if (!have_xing_header && strncasecmp(filename, "http://", 7)) | |
992 mpg123_info->num_frames = mpg123_calc_numframes(&fr); | |
993 | |
994 memcpy(&fr, &temp_fr, sizeof(struct frame)); | |
995 mpg123_bitrate = tabsel_123[fr.lsf][fr.lay - 1][fr.bitrate_index]; | |
996 disp_bitrate = mpg123_bitrate; | |
997 mpg123_frequency = mpg123_freqs[fr.sampling_frequency]; | |
998 mpg123_stereo = fr.stereo; | |
999 mpg123_layer = fr.lay; | |
1000 mpg123_lsf = fr.lsf; | |
1001 mpg123_mpeg25 = fr.mpeg25; | |
1002 mpg123_mode = fr.mode; | |
1003 | |
1004 if (strncasecmp(filename, "http://", 7)) { | |
1005 mpg123_length = mpg123_info->num_frames * mpg123_info->tpf * 1000; | |
1006 if (!mpg123_title) | |
1007 mpg123_title = get_song_title(NULL, filename); | |
1008 } | |
1009 else { | |
1010 if (!mpg123_title) | |
1011 mpg123_title = mpg123_http_get_title(filename); | |
1012 mpg123_length = -1; | |
1013 } | |
1014 | |
1015 mpg123_ip.set_info(mpg123_title, mpg123_length, | |
1016 mpg123_bitrate * 1000, | |
1017 mpg123_freqs[fr.sampling_frequency], fr.stereo); | |
1018 | |
1019 output_opened = TRUE; | |
1020 | |
1021 if (!open_output()) { | |
1022 audio_error = TRUE; | |
1023 mpg123_info->eof = TRUE; | |
1024 } | |
1025 else | |
1026 play_frame(&fr); | |
1027 } | |
1028 | |
1029 mpg123_info->first_frame = FALSE; | |
1030 while (mpg123_info->going) { | |
1031 if (mpg123_info->jump_to_time != -1) { | |
1032 void *xp = NULL; | |
1033 if (have_xing_header) | |
1034 xp = &xing_header; | |
1035 if (mpg123_seek(&fr, xp, vbr, mpg123_info->jump_to_time) > -1) { | |
1036 mpg123_ip.output->flush(mpg123_info->jump_to_time * 1000); | |
1037 mpg123_info->eof = FALSE; | |
1038 } | |
1039 mpg123_info->jump_to_time = -1; | |
1040 } | |
1041 if (!mpg123_info->eof) { | |
1042 if (mpg123_read_frame(&fr) != 0) { | |
1043 if (fr.lay != mpg123_layer || fr.lsf != mpg123_lsf) { | |
1044 memcpy(&temp_fr, &fr, sizeof(struct frame)); | |
1045 if (mpg123_read_frame(&temp_fr) != 0) { | |
1046 if (fr.lay == temp_fr.lay && fr.lsf == temp_fr.lsf) { | |
1047 mpg123_layer = fr.lay; | |
1048 mpg123_lsf = fr.lsf; | |
1049 memcpy(&fr, &temp_fr, sizeof(struct frame)); | |
1050 } | |
1051 else { | |
1052 memcpy(&fr, &temp_fr, sizeof(struct frame)); | |
1053 skip_frames = 2; | |
1054 mpg123_info->output_audio = FALSE; | |
1055 continue; | |
1056 } | |
1057 | |
1058 } | |
1059 } | |
1060 if (mpg123_freqs[fr.sampling_frequency] != mpg123_frequency | |
1061 || mpg123_stereo != fr.stereo) { | |
1062 memcpy(&temp_fr, &fr, sizeof(struct frame)); | |
1063 if (mpg123_read_frame(&temp_fr) != 0) { | |
1064 if (fr.sampling_frequency == | |
1065 temp_fr.sampling_frequency | |
1066 && temp_fr.stereo == fr.stereo) { | |
1067 mpg123_ip.output->buffer_free(); | |
1068 mpg123_ip.output->buffer_free(); | |
1069 while (mpg123_ip.output->buffer_playing() | |
1070 && mpg123_info->going | |
1071 && mpg123_info->jump_to_time == -1) | |
1072 xmms_usleep(20000); | |
1073 if (!mpg123_info->going) | |
1074 break; | |
1075 temp_time = mpg123_ip.output->output_time(); | |
1076 mpg123_ip.output->close_audio(); | |
1077 mpg123_frequency = | |
1078 mpg123_freqs[fr.sampling_frequency]; | |
1079 mpg123_stereo = fr.stereo; | |
1080 if (!mpg123_ip.output-> | |
1081 open_audio(mpg123_cfg.resolution == | |
1082 16 ? FMT_S16_NE : FMT_U8, | |
1083 mpg123_freqs[fr.sampling_frequency] | |
1084 >> mpg123_cfg.downsample, | |
1085 mpg123_cfg.channels == | |
1086 2 ? fr.stereo : 1)) { | |
1087 audio_error = TRUE; | |
1088 mpg123_info->eof = TRUE; | |
1089 } | |
1090 mpg123_ip.output->flush(temp_time); | |
1091 mpg123_ip.set_info(mpg123_title, mpg123_length, | |
1092 mpg123_bitrate * 1000, | |
1093 mpg123_frequency, | |
1094 mpg123_stereo); | |
1095 memcpy(&fr, &temp_fr, sizeof(struct frame)); | |
1096 } | |
1097 else { | |
1098 memcpy(&fr, &temp_fr, sizeof(struct frame)); | |
1099 skip_frames = 2; | |
1100 mpg123_info->output_audio = FALSE; | |
1101 continue; | |
1102 } | |
1103 } | |
1104 } | |
1105 | |
1106 if (tabsel_123[fr.lsf][fr.lay - 1][fr.bitrate_index] != | |
1107 mpg123_bitrate) | |
1108 mpg123_bitrate = | |
1109 tabsel_123[fr.lsf][fr.lay - 1][fr.bitrate_index]; | |
1110 | |
1111 if (!disp_count) { | |
1112 disp_count = 20; | |
1113 if (mpg123_bitrate != disp_bitrate) { | |
1114 /* FIXME networks streams */ | |
1115 disp_bitrate = mpg123_bitrate; | |
1116 if (!have_xing_header | |
1117 && strncasecmp(filename, "http://", 7)) { | |
1118 double rel = mpg123_relative_pos(); | |
1119 if (rel) { | |
1120 mpg123_length = | |
1121 mpg123_ip.output->written_time() / rel; | |
1122 vbr = TRUE; | |
1123 } | |
1124 | |
1125 if (rel == 0 || !(mpg123_length > 0)) { | |
1126 mpg123_info->num_frames = | |
1127 mpg123_calc_numframes(&fr); | |
1128 mpg123_info->tpf = mpg123_compute_tpf(&fr); | |
1129 mpg123_length = | |
1130 mpg123_info->num_frames * | |
1131 mpg123_info->tpf * 1000; | |
1132 } | |
1133 | |
1134 | |
1135 } | |
1136 mpg123_ip.set_info(mpg123_title, mpg123_length, | |
1137 mpg123_bitrate * 1000, | |
1138 mpg123_frequency, mpg123_stereo); | |
1139 } | |
1140 } | |
1141 else | |
1142 disp_count--; | |
1143 play_frame(&fr); | |
1144 } | |
1145 else { | |
1146 mpg123_ip.output->buffer_free(); | |
1147 mpg123_ip.output->buffer_free(); | |
1148 mpg123_info->eof = TRUE; | |
1149 xmms_usleep(10000); | |
1150 } | |
1151 } | |
1152 else { | |
1153 xmms_usleep(10000); | |
1154 } | |
1155 } | |
1156 g_free(mpg123_title); | |
1157 mpg123_title = NULL; | |
1158 mpg123_stream_close(); | |
1159 if (output_opened && !audio_error) | |
1160 mpg123_ip.output->close_audio(); | |
1161 g_free(mpg123_pcm_sample); | |
1162 mpg123_filename = NULL; | |
1163 g_free(filename); | |
1164 | |
1165 return NULL; | |
1166 } | |
1167 | |
1168 static void | |
1169 play_file(char *filename) | |
1170 { | |
1171 memset(&fr, 0, sizeof(struct frame)); | |
1172 memset(&temp_fr, 0, sizeof(struct frame)); | |
1173 | |
1174 mpg123_info = g_malloc0(sizeof(PlayerInfo)); | |
1175 mpg123_info->going = 1; | |
1176 mpg123_info->first_frame = TRUE; | |
1177 mpg123_info->output_audio = TRUE; | |
1178 mpg123_info->jump_to_time = -1; | |
1179 skip_frames = 0; | |
1180 audio_error = FALSE; | |
1181 output_opened = FALSE; | |
1182 dopause = FALSE; | |
1183 | |
1184 decode_thread = g_thread_create(decode_loop, g_strdup(filename), TRUE, | |
1185 NULL); | |
1186 } | |
1187 | |
1188 static void | |
1189 stop(void) | |
1190 { | |
1191 if (mpg123_info && mpg123_info->going) { | |
1192 mpg123_info->going = FALSE; | |
1193 g_thread_join(decode_thread); | |
1194 g_free(mpg123_info); | |
1195 mpg123_info = NULL; | |
1196 } | |
1197 } | |
1198 | |
1199 static void | |
1200 seek(int time) | |
1201 { | |
1202 mpg123_info->jump_to_time = time; | |
1203 | |
1204 while (mpg123_info->jump_to_time != -1) | |
1205 xmms_usleep(10000); | |
1206 } | |
1207 | |
1208 static void | |
1209 do_pause(short p) | |
1210 { | |
1211 if (output_opened) | |
1212 mpg123_ip.output->pause(p); | |
1213 else | |
1214 dopause = p; | |
1215 } | |
1216 | |
1217 static int | |
1218 get_time(void) | |
1219 { | |
1220 if (audio_error) | |
1221 return -2; | |
1222 if (!mpg123_info) | |
1223 return -1; | |
1224 if (!mpg123_info->going | |
1225 || (mpg123_info->eof && !mpg123_ip.output->buffer_playing())) | |
1226 return -1; | |
1227 return mpg123_ip.output->output_time(); | |
1228 } | |
1229 | |
1230 static void | |
1231 aboutbox(void) | |
1232 { | |
1233 static GtkWidget *aboutbox; | |
1234 | |
1235 if (aboutbox != NULL) | |
1236 return; | |
1237 | |
1238 aboutbox = xmms_show_message(_("About MPEG Audio Plugin"), | |
223
e7e9a86c0c01
[svn] Update credits on here reflecting audacious-decoder changes.
nenolod
parents:
177
diff
changeset
|
1239 _("Audacious decoding engine by William Pitcock <nenolod@nenolod.net>, derived from:\n" |
e7e9a86c0c01
[svn] Update credits on here reflecting audacious-decoder changes.
nenolod
parents:
177
diff
changeset
|
1240 "mpg123 decoding engine by Michael Hipp <mh@mpg123.de>\n" |
e7e9a86c0c01
[svn] Update credits on here reflecting audacious-decoder changes.
nenolod
parents:
177
diff
changeset
|
1241 "Derived partially from mpg123 0.59s.mc3 as well.\n" |
129
ce9d4aa5889a
[svn] Update the credits to note the code sync that occured.
nenolod
parents:
61
diff
changeset
|
1242 "Based on the original XMMS plugin."), |
ce9d4aa5889a
[svn] Update the credits to note the code sync that occured.
nenolod
parents:
61
diff
changeset
|
1243 _("Ok"), |
ce9d4aa5889a
[svn] Update the credits to note the code sync that occured.
nenolod
parents:
61
diff
changeset
|
1244 FALSE, NULL, NULL); |
61 | 1245 |
1246 g_signal_connect(G_OBJECT(aboutbox), "destroy", | |
1247 G_CALLBACK(gtk_widget_destroyed), &aboutbox); | |
1248 } | |
1249 | |
1250 InputPlugin mpg123_ip = { | |
1251 NULL, | |
1252 NULL, | |
1253 NULL, /* Description */ | |
1254 init, | |
1255 aboutbox, | |
1256 mpg123_configure, | |
1257 is_our_file, | |
1258 NULL, | |
1259 play_file, | |
1260 stop, | |
1261 do_pause, | |
1262 seek, | |
1263 mpg123_set_eq, | |
1264 get_time, | |
1265 NULL, NULL, | |
1266 cleanup, | |
1267 NULL, | |
1268 NULL, NULL, NULL, | |
1269 get_song_info, | |
1270 mpg123_file_info_box, /* file_info_box */ | |
1271 NULL | |
1272 }; | |
1273 | |
1274 InputPlugin * | |
1275 get_iplugin_info(void) | |
1276 { | |
1277 mpg123_ip.description = g_strdup_printf(_("MPEG Audio Plugin")); | |
1278 return &mpg123_ip; | |
1279 } |