comparison Plugins/Input/aac/src/libmp4.c @ 61:fa848bd484d8 trunk

[svn] Move plugins to Plugins/
author nenolod
date Fri, 28 Oct 2005 22:58:11 -0700
parents
children 0a2ad94e8607
comparison
equal deleted inserted replaced
60:1771f253e1b2 61:fa848bd484d8
1 /*
2 * MP4/AAC decoder for xmms
3 *
4 * This decoding source code is completly independent of the faad2
5 * package.
6 * This package exist for people who don't want to install
7 * faad2 and mpeg4ip project files.
8 *
9 * OPTIONNAL need
10 * --------------
11 * libid3 (3.8.x - www.id3.org)
12 */
13
14 #include <pthread.h>
15 #include <gtk/gtk.h>
16 #include "faad.h"
17 #include "mp4.h"
18
19 #include <audacious/plugin.h>
20 #include <libaudacious/util.h>
21 #include <libaudacious/configfile.h>
22 #include <libaudacious/titlestring.h>
23
24 #define MP4_DESCRIPTION "MP4 & MPEG2/4-AAC audio player - 1.2.x"
25 #define MP4_VERSION "ver. 0.4 - 24 November 2003"
26 #define LIBMP4V2_VERSION "0.9.7"
27 #define MP4_ABOUT "Written by ciberfred"
28 #define BUFFER_SIZE FAAD_MIN_STREAMSIZE*64
29
30 static void mp4_init(void);
31 static void mp4_about(void);
32 static void mp4_play(char *);
33 static void mp4_stop(void);
34 static void mp4_pause(short);
35 static void mp4_seek(int);
36 static int mp4_getTime(void);
37 static void mp4_cleanup(void);
38 static void mp4_getSongInfo(char *);
39 static int mp4_isFile(char *);
40 static void* mp4Decode(void *);
41
42 InputPlugin mp4_ip =
43 {
44 0, // handle
45 0, // filename
46 MP4_DESCRIPTION,
47 mp4_init,
48 mp4_about,
49 0, // configuration
50 mp4_isFile,
51 0, //scandir
52 mp4_play,
53 mp4_stop,
54 mp4_pause,
55 mp4_seek,
56 0, // set equalizer
57 mp4_getTime,
58 0, // get volume
59 0,
60 mp4_cleanup,
61 0, // obsolete
62 0, // send visualisation data
63 0, // set player window info
64 0, // set song title text
65 0, // get song title text
66 mp4_getSongInfo, // info box
67 0, // to output plugin
68 };
69
70 typedef struct _mp4cfg{
71 gshort file_type;
72 #define FILE_UNKNOW 0
73 #define FILE_MP4 1
74 #define FILE_AAC 2
75 } Mp4Config;
76
77 static Mp4Config mp4cfg;
78 static gboolean bPlaying = FALSE;
79 static pthread_t decodeThread;
80 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
81 static int seekPosition = -1;
82
83
84 InputPlugin *get_iplugin_info(void)
85 {
86 return(&mp4_ip);
87 }
88
89 static void mp4_init(void)
90 {
91 memset(&decodeThread, 0, sizeof(pthread_t));
92 mp4cfg.file_type = FILE_UNKNOW;
93 seekPosition = -1;
94 return;
95 }
96
97 static void mp4_play(char *filename)
98 {
99 bPlaying = TRUE;
100 pthread_create(&decodeThread, 0, mp4Decode, g_strdup(filename));
101 return;
102 }
103
104 static void mp4_stop(void)
105 {
106 if(bPlaying){
107 bPlaying = FALSE;
108 pthread_join(decodeThread, NULL);
109 memset(&decodeThread, 0, sizeof(pthread_t));
110 mp4_ip.output->close_audio();
111 }
112 }
113
114 static int mp4_isFile(char *filename)
115 {
116 char *ext;
117
118 if(filename){
119 ext = strrchr(filename, '.');
120 if (ext && (!strncasecmp(ext, ".mp4", 4) || // official extention
121 !strncasecmp(ext, ".m4a", 4) || // Apple mp4 extention
122 !strncasecmp(ext, ".aac", 4) // old MPEG2/4-AAC extention
123 )){
124 return (1);
125 }
126 }
127 return(0);
128 }
129
130 static void mp4_about(void)
131 {
132 static GtkWidget *aboutbox;
133
134 if(aboutbox!=NULL)
135 return;
136 aboutbox = xmms_show_message("About MP4 AAC player plugin",
137 "libfaad2-" FAAD2_VERSION "\n"
138 "libmp4v2-" LIBMP4V2_VERSION "\n"
139 "plugin version: " MP4_VERSION "\n"
140 MP4_ABOUT,
141 "Ok", FALSE, NULL, NULL);
142 gtk_signal_connect(GTK_OBJECT(aboutbox), "destroy",
143 GTK_SIGNAL_FUNC(gtk_widget_destroyed),
144 &aboutbox);
145 }
146
147 static void mp4_pause(short flag)
148 {
149 mp4_ip.output->pause(flag);
150 }
151
152 static void mp4_seek(int time)
153 {
154 seekPosition = time;
155 while(bPlaying && seekPosition!=-1)
156 xmms_usleep(10000);
157 }
158
159 static int mp4_getTime(void)
160 {
161 if(!bPlaying)
162 return (-1);
163 else
164 return (mp4_ip.output->output_time());
165 }
166
167 static void mp4_cleanup(void)
168 {
169 }
170
171 static void mp4_getSongInfo(char *filename)
172 {
173 if(mp4cfg.file_type == FILE_MP4)
174 getMP4info(filename);
175 else if(mp4cfg.file_type == FILE_AAC)
176 ;
177 }
178
179 static void *mp4Decode(void *args)
180 {
181 MP4FileHandle mp4file;
182
183 pthread_mutex_lock(&mutex);
184 seekPosition = -1;
185 bPlaying = TRUE;
186 if(!(mp4file = MP4Read(args, 0))){
187 mp4cfg.file_type = FILE_AAC;
188 MP4Close(mp4file);
189 }else{
190 mp4cfg.file_type = FILE_MP4;
191 }
192
193 if(mp4cfg.file_type == FILE_MP4){
194 // We are reading a MP4 file
195 gint mp4track;
196
197 if((mp4track = getAACTrack(mp4file)) < 0){
198 //TODO: check here for others Audio format.....
199 g_print("Unsupported Audio track type\n");
200 g_free(args);
201 MP4Close(mp4file);
202 bPlaying = FALSE;
203 pthread_mutex_unlock(&mutex);
204 pthread_exit(NULL);
205 }else{
206 faacDecHandle decoder;
207 unsigned char *buffer = NULL;
208 guint bufferSize = 0;
209 gulong samplerate;
210 guchar channels;
211 guint avgBitrate;
212 MP4Duration duration;
213 gulong msDuration;
214 MP4SampleId numSamples;
215 MP4SampleId sampleID = 1;
216
217 decoder = faacDecOpen();
218 MP4GetTrackESConfiguration(mp4file, mp4track, &buffer, &bufferSize);
219 if(!buffer){
220 g_free(args);
221 faacDecClose(decoder);
222 MP4Close(mp4file);
223 bPlaying = FALSE;
224 pthread_mutex_unlock(&mutex);
225 pthread_exit(NULL);
226 }
227 if(faacDecInit2(decoder, buffer, bufferSize, &samplerate, &channels)<0){
228 g_free(args);
229 faacDecClose(decoder);
230 MP4Close(mp4file);
231 bPlaying = FALSE;
232 pthread_mutex_unlock(&mutex);
233 pthread_exit(NULL);
234 }
235 g_free(buffer);
236 if(channels == 0){
237 g_print("Number of Channels not supported\n");
238 g_free(args);
239 faacDecClose(decoder);
240 MP4Close(mp4file);
241 bPlaying = FALSE;
242 pthread_mutex_unlock(&mutex);
243 pthread_exit(NULL);
244 }
245 duration = MP4GetTrackDuration(mp4file, mp4track);
246 msDuration = MP4ConvertFromTrackDuration(mp4file, mp4track, duration,
247 MP4_MSECS_TIME_SCALE);
248 numSamples = MP4GetTrackNumberOfSamples(mp4file, mp4track);
249 mp4_ip.output->open_audio(FMT_S16_NE, samplerate, channels);
250 mp4_ip.output->flush(0);
251 mp4_ip.set_info(args, msDuration, -1, samplerate/1000, channels);
252 g_print("MP4 - %d channels @ %d Hz\n", channels, samplerate);
253
254 while(bPlaying){
255 void* sampleBuffer;
256 faacDecFrameInfo frameInfo;
257 gint rc;
258
259 if(seekPosition!=-1){
260 duration = MP4ConvertToTrackDuration(mp4file,
261 mp4track,
262 seekPosition*1000,
263 MP4_MSECS_TIME_SCALE);
264 sampleID = MP4GetSampleIdFromTime(mp4file, mp4track, duration, 0);
265 mp4_ip.output->flush(seekPosition*1000);
266 seekPosition = -1;
267 }
268 buffer=NULL;
269 bufferSize=0;
270 if(sampleID > numSamples){
271 mp4_ip.output->close_audio();
272 g_free(args);
273 faacDecClose(decoder);
274 MP4Close(mp4file);
275 bPlaying = FALSE;
276 pthread_mutex_unlock(&mutex);
277 pthread_exit(NULL);
278 }
279 rc = MP4ReadSample(mp4file, mp4track, sampleID++, &buffer, &bufferSize,
280 NULL, NULL, NULL, NULL);
281 //g_print("%d/%d\n", sampleID-1, numSamples);
282 if((rc==0) || (buffer== NULL)){
283 g_print("MP4: read error\n");
284 sampleBuffer = NULL;
285 sampleID=0;
286 mp4_ip.output->buffer_free();
287 mp4_ip.output->close_audio();
288 g_free(args);
289 faacDecClose(decoder);
290 MP4Close(mp4file);
291 bPlaying = FALSE;
292 pthread_mutex_unlock(&mutex);
293 pthread_exit(NULL);
294 }else{
295 sampleBuffer = faacDecDecode(decoder, &frameInfo, buffer, bufferSize);
296 if(frameInfo.error > 0){
297 g_print("MP4: %s\n",
298 faacDecGetErrorMessage(frameInfo.error));
299 mp4_ip.output->close_audio();
300 g_free(args);
301 faacDecClose(decoder);
302 MP4Close(mp4file);
303 bPlaying = FALSE;
304 pthread_mutex_unlock(&mutex);
305 pthread_exit(NULL);
306 }
307 if(buffer){
308 g_free(buffer); buffer=NULL; bufferSize=0;
309 }
310 while(bPlaying && mp4_ip.output->buffer_free()<frameInfo.samples<<1)
311 xmms_usleep(30000);
312 }
313 mp4_ip.add_vis_pcm(mp4_ip.output->written_time(),
314 FMT_S16_NE,
315 channels,
316 frameInfo.samples<<1,
317 sampleBuffer);
318 mp4_ip.output->write_audio(sampleBuffer, frameInfo.samples<<1);
319 }
320 while(bPlaying && mp4_ip.output->buffer_free()){
321 xmms_usleep(10000);
322 }
323 mp4_ip.output->close_audio();
324 g_free(args);
325 faacDecClose(decoder);
326 MP4Close(mp4file);
327 bPlaying = FALSE;
328 pthread_mutex_unlock(&mutex);
329 pthread_exit(NULL);
330 }
331 } else{
332 // WE ARE READING AN AAC FILE
333 FILE *file = NULL;
334 faacDecHandle decoder = 0;
335 guchar *buffer = 0;
336 gulong bufferconsumed = 0;
337 gulong samplerate = 0;
338 guchar channels;
339 gulong buffervalid = 0;
340 TitleInput* input;
341 gchar *temp = g_strdup(args);
342 gchar *ext = strrchr(temp, '.');
343 gchar *xmmstitle = NULL;
344 faacDecConfigurationPtr config;
345
346 if((file = fopen(args, "rb")) == 0){
347 g_print("AAC: can't find file %s\n", args);
348 bPlaying = FALSE;
349 pthread_mutex_unlock(&mutex);
350 pthread_exit(NULL);
351 }
352 if((decoder = faacDecOpen()) == NULL){
353 g_print("AAC: Open Decoder Error\n");
354 fclose(file);
355 bPlaying = FALSE;
356 pthread_mutex_unlock(&mutex);
357 pthread_exit(NULL);
358 }
359 config = faacDecGetCurrentConfiguration(decoder);
360 config->useOldADTSFormat = 0;
361 faacDecSetConfiguration(decoder, config);
362 if((buffer = g_malloc(BUFFER_SIZE)) == NULL){
363 g_print("AAC: error g_malloc\n");
364 fclose(file);
365 bPlaying = FALSE;
366 faacDecClose(decoder);
367 pthread_mutex_unlock(&mutex);
368 pthread_exit(NULL);
369 }
370 if((buffervalid = fread(buffer, 1, BUFFER_SIZE, file))==0){
371 g_print("AAC: Error reading file\n");
372 g_free(buffer);
373 fclose(file);
374 bPlaying = FALSE;
375 faacDecClose(decoder);
376 pthread_mutex_unlock(&mutex);
377 pthread_exit(NULL);
378 }
379 XMMS_NEW_TITLEINPUT(input);
380 input->file_name = g_basename(temp);
381 input->file_ext = ext ? ext+1 : NULL;
382 input->file_path = temp;
383 if(!strncmp(buffer, "ID3", 3)){
384 gint size = 0;
385
386 fseek(file, 0, SEEK_SET);
387 size = (buffer[6]<<21) | (buffer[7]<<14) | (buffer[8]<<7) | buffer[9];
388 size+=10;
389 fread(buffer, 1, size, file);
390 buffervalid = fread(buffer, 1, BUFFER_SIZE, file);
391 }
392 xmmstitle = xmms_get_titlestring(xmms_get_gentitle_format(), input);
393 if(xmmstitle == NULL)
394 xmmstitle = g_strdup(input->file_name);
395 if(temp) g_free(temp);
396 if(input->performer) g_free(input->performer);
397 if(input->album_name) g_free(input->album_name);
398 if(input->track_name) g_free(input->track_name);
399 if(input->genre) g_free(input->genre);
400 g_free(input);
401 bufferconsumed = faacDecInit(decoder,
402 buffer,
403 buffervalid,
404 &samplerate,
405 &channels);
406 if(mp4_ip.output->open_audio(FMT_S16_NE,samplerate,channels) == FALSE){
407 g_print("AAC: Output Error\n");
408 g_free(buffer); buffer=0;
409 faacDecClose(decoder);
410 fclose(file);
411 mp4_ip.output->close_audio();
412 /*
413 if(positionTable){
414 g_free(positionTable); positionTable=0;
415 }
416 */
417 g_free(xmmstitle);
418 bPlaying = FALSE;
419 pthread_mutex_unlock(&mutex);
420 pthread_exit(NULL);
421 }
422 //if(bSeek){
423 //mp4_ip.set_info(xmmstitle, lenght*1000, -1, samplerate, channels);
424 //}else{
425 mp4_ip.set_info(xmmstitle, -1, -1, samplerate, channels);
426 //}
427 mp4_ip.output->flush(0);
428
429 while(bPlaying && buffervalid > 0){
430 faacDecFrameInfo finfo;
431 unsigned long samplesdecoded;
432 char* sample_buffer = NULL;
433 /*
434 if(bSeek && seekPosition!=-1){
435 fseek(file, positionTable[seekPosition], SEEK_SET);
436 bufferconsumed=0;
437 buffervalid = fread(buffer, 1, BUFFER_SIZE, file);
438 aac_ip.output->flush(seekPosition*1000);
439 seekPosition=-1;
440 }
441 */
442 if(bufferconsumed > 0){
443 memmove(buffer, &buffer[bufferconsumed], buffervalid-bufferconsumed);
444 buffervalid -= bufferconsumed;
445 buffervalid += fread(&buffer[buffervalid], 1,
446 BUFFER_SIZE-buffervalid, file);
447 bufferconsumed = 0;
448 }
449 sample_buffer = faacDecDecode(decoder, &finfo, buffer, buffervalid);
450 if(finfo.error){
451 config = faacDecGetCurrentConfiguration(decoder);
452 if(config->useOldADTSFormat != 1){
453 faacDecClose(decoder);
454 decoder = faacDecOpen();
455 config = faacDecGetCurrentConfiguration(decoder);
456 config->useOldADTSFormat = 1;
457 faacDecSetConfiguration(decoder, config);
458 finfo.bytesconsumed=0;
459 finfo.samples = 0;
460 faacDecInit(decoder,
461 buffer,
462 buffervalid,
463 &samplerate,
464 &channels);
465 }else{
466 g_print("FAAD2 Warning %s\n", faacDecGetErrorMessage(finfo.error));
467 buffervalid = 0;
468 }
469 }
470 bufferconsumed += finfo.bytesconsumed;
471 samplesdecoded = finfo.samples;
472 if((samplesdecoded<=0) && !sample_buffer){
473 g_print("AAC: error sample decoding\n");
474 continue;
475 }
476 while(bPlaying && mp4_ip.output->buffer_free() < (samplesdecoded<<1)){
477 xmms_usleep(10000);
478 }
479 mp4_ip.add_vis_pcm(mp4_ip.output->written_time(),
480 FMT_S16_LE, channels,
481 samplesdecoded<<1, sample_buffer);
482 mp4_ip.output->write_audio(sample_buffer, samplesdecoded<<1);
483 }
484 while(bPlaying && mp4_ip.output->buffer_playing()){
485 xmms_usleep(10000);
486 }
487 mp4_ip.output->buffer_free();
488 mp4_ip.output->close_audio();
489 bPlaying = FALSE;
490 g_free(buffer);
491 faacDecClose(decoder);
492 g_free(xmmstitle);
493 fclose(file);
494 seekPosition = -1;
495 /*
496 if(positionTable){
497 g_free(positionTable); positionTable=0;
498 }
499 */
500 bPlaying = FALSE;
501 pthread_mutex_unlock(&mutex);
502 pthread_exit(NULL);
503
504 }
505 }