1 /*                                                     -*- linux-c -*-
2     Copyright (C) 2004 Tom Szilagyi
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18     $Id: file_decoder.c 1245 2012-02-04 10:33:30Z assworth $
19 */
20 
21 #include <config.h>
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <strings.h>
27 
28 #include "../httpc.h"
29 #include "../metadata.h"
30 #include "../options.h"
31 #include "dec_null.h"
32 #ifdef HAVE_CDDA
33 #include "dec_cdda.h"
34 #endif /* HAVE_CDDA */
35 #ifdef HAVE_SNDFILE
36 #include "dec_sndfile.h"
37 #endif /* HAVE_SNDFILE */
38 #ifdef HAVE_FLAC
39 #include "dec_flac.h"
40 #endif /* HAVE_FLAC */
41 #ifdef HAVE_VORBIS
42 #include "dec_vorbis.h"
43 #endif /* HAVE_VORBIS */
44 #ifdef HAVE_SPEEX
45 #include "dec_speex.h"
46 #endif /* HAVE_SPEEX */
47 #ifdef HAVE_MPC
48 #include "dec_mpc.h"
49 #endif /* HAVE_MPC */
50 #ifdef HAVE_MPEG
51 #include "dec_mpeg.h"
52 #endif /* HAVE_MPEG */
53 #ifdef HAVE_MOD
54 #include "dec_mod.h"
55 #endif /* HAVE_MOD */
56 #ifdef HAVE_MAC
57 #include "dec_mac.h"
58 #endif /* HAVE_MAC */
59 #ifdef HAVE_LAVC
60 #include <libavformat/avformat.h>
61 #include "dec_lavc.h"
62 #endif /* HAVE_LAVC */
63 #ifdef HAVE_WAVPACK
64 #include "dec_wavpack.h"
65 #endif /* HAVE_WAVPACK */
66 #include "file_decoder.h"
67 
68 
69 extern options_t options;
70 
71 typedef decoder_t * decoder_init_t(file_decoder_t * fdec);
72 
73 /* this controls the order in which decoders are probed for a file */
74 static decoder_init_t * decoder_init_v[] = {
75 	null_decoder_init,
76 #ifdef HAVE_CDDA
77 	cdda_decoder_init,
78 #endif /* HAVE_CDDA */
79 #ifdef HAVE_SNDFILE
80 	sndfile_decoder_init,
81 #endif /* HAVE_SNDFILE */
82 #ifdef HAVE_FLAC
83 	flac_decoder_init,
84 #endif /* HAVE_FLAC */
85 #ifdef HAVE_VORBIS
86 	vorbis_decoder_init,
87 #endif /* HAVE_VORBIS */
88 #ifdef HAVE_SPEEX
89 	speex_dec_init,
90 #endif /* HAVE_SPEEX */
91 #ifdef HAVE_MPC
92 	mpc_decoder_init_func,
93 #endif /* HAVE_MPC */
94 #ifdef HAVE_MAC
95 	mac_decoder_init,
96 #endif /* HAVE_MAC */
97 #ifdef HAVE_MPEG
98 	mpeg_decoder_init,
99 #endif /* HAVE_MPEG */
100 #ifdef HAVE_WAVPACK
101 	wavpack_decoder_init,
102 #endif /* HAVE_WAVPACK */
103 #ifdef HAVE_MOD
104 	mod_decoder_init,
105 #endif /* HAVE_MOD */
106 #ifdef HAVE_LAVC
107 	lavc_decoder_init,
108 #endif /* HAVE_LAVC */
109 	NULL
110 };
111 
112 
113 /* utility function used by some decoders to check file extension */
114 int
is_valid_extension(char ** valid_extensions,char * filename,int module)115 is_valid_extension(char ** valid_extensions, char * filename, int module) {
116 
117 	int i;
118 	char * c = NULL, * d = NULL;
119         char *ext;
120 
121         /* post ext */
122         i = 0;
123 
124 	if ((c = strrchr(filename, '.')) != NULL) {
125 
126                 ++c;
127 
128                 while (valid_extensions[i] != NULL) {
129 
130                         if (strcasecmp(c, valid_extensions[i]) == 0) {
131                                 return 1;
132                         }
133                         ++i;
134                 }
135 	}
136 
137         if (module) {      /* checking mod pre file extension */
138                            /* lots of amiga modules has EXT.NAME filename format */
139 
140                 /* pre ext */
141                 i = 0;
142                 ext = strdup(filename);
143 
144                 if (ext && (c = strrchr(ext, '/')) != NULL) {
145 
146                         ++c;
147 
148                         if ((d = strchr(ext, '.')) != NULL) {
149 
150                                 *d = '\0';
151 
152                                 while (valid_extensions[i] != NULL) {
153 
154                                         if (strcasecmp(c, valid_extensions[i]) == 0) {
155                                                 free(ext);
156                                                 return 1;
157                                         }
158                                         ++i;
159                                 }
160                         }
161                 }
162 
163                 free(ext);
164         }
165 
166 	return 0;
167 }
168 
169 
170 /* call this first before using file_decoder in program */
171 void
file_decoder_init(void)172 file_decoder_init(void) {
173 
174 #ifdef HAVE_LAVC
175 	av_register_all();
176 #endif /* HAVE_LAVC */
177 }
178 
179 
180 file_decoder_t *
file_decoder_new(void)181 file_decoder_new(void) {
182 
183 	file_decoder_t * fdec = NULL;
184 
185 	if ((fdec = calloc(1, sizeof(file_decoder_t))) == NULL) {
186 		fprintf(stderr, "file_decoder.c: file_decoder_new() failed: calloc error\n");
187 		return NULL;
188 	}
189 
190 	fdec->file_open = 0;
191 
192 	fdec->voladj_db = 0.0f;
193 	fdec->voladj_lin = 1.0f;
194 
195 	fdec->pdec = NULL;
196 
197 	return fdec;
198 }
199 
200 
201 void
file_decoder_delete(file_decoder_t * fdec)202 file_decoder_delete(file_decoder_t * fdec) {
203 
204 	if (fdec->file_open) {
205 		file_decoder_close(fdec);
206 	}
207 
208 	free(fdec);
209 }
210 
211 
212 int
file_decoder_finalize_open(file_decoder_t * fdec,decoder_t * dec,char * filename)213 file_decoder_finalize_open(file_decoder_t * fdec, decoder_t * dec, char * filename) {
214 
215 	if (fdec->fileinfo.channels == 1) {
216 		fdec->fileinfo.is_mono = 1;
217 		goto ok_open;
218 
219 	} else if (fdec->fileinfo.channels == 2) {
220 		fdec->fileinfo.is_mono = 0;
221 		goto ok_open;
222 
223 	} else {
224 		fprintf(stderr, "file_decoder_open: programmer error: "
225 			"soundfile with %d\n channels is unsupported.\n",
226 			fdec->fileinfo.channels);
227 		goto no_open;
228 	}
229 
230  ok_open:
231 	fdec->file_open = 1;
232 	fdec->samples_left = fdec->fileinfo.total_samples;
233 	fdec->fileinfo.format_str = dec->format_str;
234 	fdec->fileinfo.format_flags = dec->format_flags;
235 	return 0;
236 
237  no_open:
238 	fprintf(stderr, "file_decoder_open: unable to open %s\n", filename);
239 	return 1;
240 }
241 
242 
243 int
stream_decoder_open(file_decoder_t * fdec,char * URL)244 stream_decoder_open(file_decoder_t * fdec, char * URL) {
245 
246 	int ret;
247 	decoder_t * dec;
248 	http_session_t * session = httpc_new();
249 
250     	if ((ret = httpc_init(session, fdec, URL,
251 			      options.inet_use_proxy,
252 			      options.inet_proxy,
253 			      options.inet_proxy_port,
254 			      options.inet_noproxy_domains, 0L)) != HTTPC_OK) {
255 		fprintf(stderr, "stream_decoder_open: httpc_init failed, ret = %d\n", ret);
256 		httpc_del(session);
257 		return DECODER_OPEN_FERROR;
258 	}
259 
260 #ifdef HAVE_MPEG
261 	if ((session->headers.content_type == NULL) ||
262 	    (strcasecmp(session->headers.content_type, "audio/mp3") == 0) ||
263 	    (strcasecmp(session->headers.content_type, "audio/mpeg") == 0) ||
264 	    (strcasecmp(session->headers.content_type, "application/mp3") == 0) ||
265 	    (strcasecmp(session->headers.content_type, "application/mpeg") == 0)) {
266 		int ret;
267 
268 		if (session->headers.content_type == NULL) {
269 			fprintf(stderr, "Warning: no Content-Type, assuming audio/mpeg\n");
270 		}
271 
272 		dec = mpeg_decoder_init(fdec);
273 		if (!dec)
274 			return DECODER_OPEN_FERROR;
275 
276 		ret = mpeg_stream_decoder_open(dec, session);
277 		if (ret == DECODER_OPEN_FERROR) {
278 			dec->destroy(dec);
279 			return ret;
280 		}
281 		fdec->pdec = (void *)dec;
282 		return file_decoder_finalize_open(fdec, dec, URL);
283 	}
284 #else
285 	if (session->headers.content_type == NULL) {
286 		fprintf(stderr, "stream_decoder_open: error: no Content-Type found\n");
287 		httpc_close(session);
288 		httpc_del(session);
289 		return DECODER_OPEN_FERROR;
290 	}
291 #endif /* HAVE_MPEG */
292 
293 #ifdef HAVE_VORBIS
294 	if ((strcasecmp(session->headers.content_type, "application/ogg") == 0) ||
295 	    (strcasecmp(session->headers.content_type, "audio/ogg") == 0) ||
296 	    (strcasecmp(session->headers.content_type, "audio/x-vorbis") == 0)) {
297 
298 		int ret;
299 
300 		dec = vorbis_decoder_init(fdec);
301 		if (!dec)
302 			return DECODER_OPEN_FERROR;
303 
304 		ret = vorbis_stream_decoder_open(dec, session);
305 		if (ret == DECODER_OPEN_FERROR) {
306 			dec->destroy(dec);
307 			return ret;
308 		}
309 		fdec->pdec = (void *)dec;
310 		return file_decoder_finalize_open(fdec, dec, URL);
311 	}
312 #endif /* HAVE_VORBIS */
313 
314 	fprintf(stderr, "Sorry, no handler for Content-Type: %s\n",
315 		session->headers.content_type);
316 	httpc_close(session);
317 	httpc_del(session);
318 	return 1;
319 }
320 
321 
322 /* return: 0 is OK, >0 is error */
323 int
file_decoder_open(file_decoder_t * fdec,char * filename)324 file_decoder_open(file_decoder_t * fdec, char * filename) {
325 
326 	int i, ret;
327 	decoder_t * dec;
328 
329 	if (filename == NULL) {
330 		fprintf(stderr, "Warning: filename == NULL passed to file_decoder_open()\n");
331 		fprintf(stderr, "This is likely to be a programmer error, please report.\n");
332 		return 1;
333 	}
334 	fdec->filename = strdup(filename);
335 
336 	if (httpc_is_url(filename))
337 		return stream_decoder_open(fdec, filename);
338 
339 	for (i = 0; decoder_init_v[i] != NULL; i++) {
340 		dec = decoder_init_v[i](fdec);
341 		if (!dec) {
342 			continue;
343 		}
344 		fdec->pdec = (void *)dec;
345 		ret = dec->open(dec, filename);
346 		if (ret == DECODER_OPEN_FERROR) {
347 			dec->destroy(dec);
348 			goto no_open;
349 		} else if (ret == DECODER_OPEN_BADLIB) {
350 			dec->destroy(dec);
351 			continue;
352 		} else if (ret != DECODER_OPEN_SUCCESS) {
353 			printf("programmer error, please report: "
354 			       "illegal retvalue %d from dec->open() at %d\n", ret, i);
355 			return 1;
356 		}
357 
358 		break;
359 	}
360 
361 	if (decoder_init_v[i] == NULL) {
362 	        goto no_open;
363 	}
364 
365 	if (fdec->fileinfo.channels == 1) {
366 		fdec->fileinfo.is_mono = 1;
367 		goto ok_open;
368 
369 	} else if (fdec->fileinfo.channels == 2) {
370 		fdec->fileinfo.is_mono = 0;
371 		goto ok_open;
372 
373 	} else {
374 		fprintf(stderr, "file_decoder_open: programmer error: "
375 			"soundfile with %d\n channels is unsupported.\n",
376 			fdec->fileinfo.channels);
377 		goto no_open;
378 	}
379 
380  ok_open:
381 	fdec->file_open = 1;
382 	fdec->samples_left = fdec->fileinfo.total_samples;
383 	fdec->fileinfo.format_str = dec->format_str;
384 	fdec->fileinfo.format_flags = dec->format_flags;
385 	return 0;
386 
387  no_open:
388 	fprintf(stderr, "file_decoder_open: unable to open %s\n", filename);
389 	return 1;
390 }
391 
392 
393 void
file_decoder_send_metadata(file_decoder_t * fdec)394 file_decoder_send_metadata(file_decoder_t * fdec) {
395 
396 	decoder_t * dec = (decoder_t *)(fdec->pdec);
397 
398 	return dec->send_metadata(dec);
399 }
400 
401 void
file_decoder_set_rva(file_decoder_t * fdec,float voladj)402 file_decoder_set_rva(file_decoder_t * fdec, float voladj) {
403 
404 	fdec->voladj_db = voladj;
405 	fdec->voladj_lin = db2lin(voladj);
406 }
407 
408 
409 void
file_decoder_set_meta_cb(file_decoder_t * fdec,void (* meta_cb)(metadata_t * meta,void * data),void * data)410 file_decoder_set_meta_cb(file_decoder_t * fdec,
411 			 void (* meta_cb)(metadata_t * meta, void * data),
412 			 void * data) {
413 
414 	fdec->meta_cb = meta_cb;
415 	fdec->meta_cbdata = data;
416 }
417 
418 
419 void
file_decoder_close(file_decoder_t * fdec)420 file_decoder_close(file_decoder_t * fdec) {
421 
422 	decoder_t * dec;
423 
424 	if (!fdec->file_open) {
425 		return;
426 	}
427 
428 	dec = (decoder_t *)(fdec->pdec);
429 	dec->close(dec);
430 	dec->destroy(dec);
431 	fdec->pdec = NULL;
432 	fdec->file_open = 0;
433 	fdec->file_lib = 0;
434 	if (fdec->filename != NULL) {
435 		free(fdec->filename);
436 		fdec->filename = NULL;
437 	}
438 	if (fdec->meta != NULL) {
439 		metadata_free(fdec->meta);
440 		fdec->meta = NULL;
441 	}
442 }
443 
444 
445 unsigned int
file_decoder_read(file_decoder_t * fdec,float * dest,int num)446 file_decoder_read(file_decoder_t * fdec, float * dest, int num) {
447 
448 	decoder_t * dec = (decoder_t *)(fdec->pdec);
449 
450 	return dec->read(dec, dest, num);
451 }
452 
453 
454 void
file_decoder_seek(file_decoder_t * fdec,unsigned long long seek_to_pos)455 file_decoder_seek(file_decoder_t * fdec, unsigned long long seek_to_pos) {
456 
457 	decoder_t * dec = (decoder_t *)(fdec->pdec);
458 
459 	dec->seek(dec, seek_to_pos);
460 }
461 
462 
463 void
file_decoder_pause(file_decoder_t * fdec)464 file_decoder_pause(file_decoder_t * fdec) {
465 
466 	decoder_t * dec = (decoder_t *)(fdec->pdec);
467 	if (dec->pause != NULL)
468 		dec->pause(dec);
469 }
470 
471 
472 void
file_decoder_resume(file_decoder_t * fdec)473 file_decoder_resume(file_decoder_t * fdec) {
474 
475 	decoder_t * dec = (decoder_t *)(fdec->pdec);
476 	if (dec->resume != NULL)
477 		dec->resume(dec);
478 }
479 
480 
481 float
get_file_duration(char * file)482 get_file_duration(char * file) {
483 
484 	file_decoder_t * fdec;
485 	float duration;
486 
487 	if ((fdec = file_decoder_new()) == NULL) {
488                 fprintf(stderr, "get_file_duration: error: file_decoder_new() returned NULL\n");
489                 return -1.0f;
490         }
491 
492         if (file_decoder_open(fdec, file)) {
493                 fprintf(stderr, "file_decoder_open() failed on %s\n", file);
494 		file_decoder_delete(fdec);
495                 return -1.0f;
496         }
497 
498 	duration = (float)fdec->fileinfo.total_samples / fdec->fileinfo.sample_rate;
499 
500         file_decoder_close(fdec);
501         file_decoder_delete(fdec);
502 
503 	return duration;
504 }
505 
506 /* taken from cdparanoia source */
507 int
bigendianp(void)508 bigendianp(void) {
509 
510 	int test=1;
511 	char *hack=(char *)(&test);
512 	if(hack[0])return(0);
513 	return(1);
514 }
515 
516 
517 // vim: shiftwidth=8:tabstop=8:softtabstop=8 :
518 
519