1 /*
2 DeaDBeeF - The Ultimate Music Player
3 Copyright (C) 2009-2013 Alexey Yakovenko <waker@users.sourceforge.net>
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #include <string.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <neaacdec.h>
24 #ifdef HAVE_CONFIG_H
25 #include "../../config.h"
26 #endif
27 #include <stdlib.h>
28 #include <math.h>
29 #include "../../deadbeef.h"
30 #include "aac_parser.h"
31
32 #include "mp4ff.h"
33
34 #define min(x,y) ((x)<(y)?(x):(y))
35 #define max(x,y) ((x)>(y)?(x):(y))
36
37 //#define trace(...) { fprintf(stderr, __VA_ARGS__); }
38 #define trace(fmt,...)
39
40 static DB_decoder_t plugin;
41 static DB_functions_t *deadbeef;
42
43 //#define AAC_BUFFER_SIZE 50000
44 #define AAC_BUFFER_SIZE (FAAD_MIN_STREAMSIZE * 16)
45 #define OUT_BUFFER_SIZE 100000
46
47 #define MP4FILE mp4ff_t *
48 #define MP4FILE_CB mp4ff_callback_t
49
50
51 // aac channel mapping
52 // 0: Defined in AOT Specifc Config
53 // 1: 1 channel: front-center
54 // 2: 2 channels: front-left, front-right
55 // 3: 3 channels: front-center, front-left, front-right
56 // 4: 4 channels: front-center, front-left, front-right, back-center
57 // 5: 5 channels: front-center, front-left, front-right, back-left, back-right
58 // 6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
59 // 7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
60 // 8-15: Reserved
61
62
63 typedef struct {
64 DB_fileinfo_t info;
65 NeAACDecHandle dec;
66 DB_FILE *file;
67 MP4FILE mp4;
68 MP4FILE_CB mp4reader;
69 NeAACDecFrameInfo frame_info; // last frame info
70 int mp4track;
71 int mp4samples;
72 int mp4sample;
73 int mp4framesize;
74 int skipsamples;
75 int startsample;
76 int endsample;
77 int currentsample;
78 char buffer[AAC_BUFFER_SIZE];
79 int remaining;
80 char out_buffer[OUT_BUFFER_SIZE];
81 int out_remaining;
82 int num_errors;
83 char *samplebuffer;
84 int remap[10];
85 int noremap;
86 int eof;
87 int junk;
88 } aac_info_t;
89
90 // allocate codec control structure
91 static DB_fileinfo_t *
aac_open(uint32_t hints)92 aac_open (uint32_t hints) {
93 DB_fileinfo_t *_info = malloc (sizeof (aac_info_t));
94 aac_info_t *info = (aac_info_t *)_info;
95 memset (info, 0, sizeof (aac_info_t));
96 return _info;
97 }
98
99 static uint32_t
aac_fs_read(void * user_data,void * buffer,uint32_t length)100 aac_fs_read (void *user_data, void *buffer, uint32_t length) {
101 // trace ("aac_fs_read %d\n", length);
102 aac_info_t *info = user_data;
103 return deadbeef->fread (buffer, 1, length, info->file);
104 }
105 static uint32_t
aac_fs_seek(void * user_data,uint64_t position)106 aac_fs_seek (void *user_data, uint64_t position) {
107 aac_info_t *info = user_data;
108 // trace ("aac_fs_seek %lld (%lld)\n", position, position + info->junk);
109 return deadbeef->fseek (info->file, position+info->junk, SEEK_SET);
110 }
111
112
113 static int
parse_aac_stream(DB_FILE * fp,int * psamplerate,int * pchannels,float * pduration,int * ptotalsamples)114 parse_aac_stream(DB_FILE *fp, int *psamplerate, int *pchannels, float *pduration, int *ptotalsamples)
115 {
116 size_t framepos = deadbeef->ftell (fp);
117 size_t initfpos = framepos;
118 int firstframepos = -1;
119 int fsize = -1;
120 int offs = 0;
121 if (!fp->vfs->is_streaming ()) {
122 int skip = deadbeef->junk_get_leading_size (fp);
123 if (skip >= 0) {
124 deadbeef->fseek (fp, skip, SEEK_SET);
125 }
126 int offs = deadbeef->ftell (fp);
127 fsize = deadbeef->fgetlength (fp);
128 if (skip > 0) {
129 fsize -= skip;
130 }
131 }
132
133 uint8_t buf[ADTS_HEADER_SIZE*8];
134
135 int nsamples = 0;
136 int stream_sr = 0;
137 int stream_ch = 0;
138
139 int eof = 0;
140 int bufsize = 0;
141 int remaining = 0;
142
143 int frame = 0;
144 int scanframes = 1000;
145 if (fp->vfs->is_streaming ()) {
146 scanframes = 1;
147 }
148
149 do {
150 int size = sizeof (buf) - bufsize;
151 if (deadbeef->fread (buf + bufsize, 1, size, fp) != size) {
152 trace ("parse_aac_stream: eof\n");
153 break;
154 }
155 bufsize = sizeof (buf);
156
157 int channels, samplerate, bitrate, samples;
158 size = aac_sync (buf, &channels, &samplerate, &bitrate, &samples);
159 if (size == 0) {
160 memmove (buf, buf+1, sizeof (buf)-1);
161 bufsize--;
162 trace ("aac_sync fail, framepos: %d\n", framepos);
163 // if (deadbeef->ftell (fp) - initfpos > 4000) { // how many is enough to make sure?
164 // break;
165 // }
166 framepos++;
167 continue;
168 }
169 else {
170 trace ("aac: frame #%d sync: %dch %d %d %d %d\n", frame, channels, samplerate, bitrate, samples, size);
171 frame++;
172 nsamples += samples;
173 if (!stream_sr) {
174 stream_sr = samplerate;
175 }
176 if (!stream_ch) {
177 stream_ch = channels;
178 }
179 if (firstframepos == -1) {
180 firstframepos = framepos;
181 }
182 // if (fp->vfs->streaming) {
183 // *psamplerate = stream_sr;
184 // *pchannels = stream_ch;
185 // }
186 framepos += size;
187 if (deadbeef->fseek (fp, size-(int)sizeof(buf), SEEK_CUR) == -1) {
188 trace ("parse_aac_stream: invalid seek %d\n", size-sizeof(buf));
189 break;
190 }
191 bufsize = 0;
192 }
193 } while (ptotalsamples || frame < scanframes);
194
195 if (!frame || !stream_sr || !nsamples) {
196 return -1;
197 }
198
199 *psamplerate = stream_sr;
200
201 *pchannels = stream_ch;
202
203 if (ptotalsamples) {
204 *ptotalsamples = nsamples;
205 *pduration = nsamples / (float)stream_sr;
206 trace ("aac: duration=%f (%d samples @ %d Hz), fsize=%d, nframes=%d\n", *pduration, *ptotalsamples, stream_sr, fsize, frame);
207 }
208 else {
209 int pos = deadbeef->ftell (fp);
210 int totalsamples = (double)fsize / (pos-offs) * nsamples;
211 *pduration = totalsamples / (float)stream_sr;
212 trace ("aac: duration=%f (%d samples @ %d Hz), fsize=%d\n", *pduration, totalsamples, stream_sr, fsize);
213 }
214
215 if (*psamplerate <= 24000) {
216 *psamplerate *= 2;
217 if (ptotalsamples) {
218 *ptotalsamples *= 2;
219 }
220 }
221 return firstframepos;
222 }
223
224 static int
mp4_track_get_info(mp4ff_t * mp4,int track,float * duration,int * samplerate,int * channels,int * totalsamples,int * mp4framesize)225 mp4_track_get_info(mp4ff_t *mp4, int track, float *duration, int *samplerate, int *channels, int *totalsamples, int *mp4framesize) {
226 int sr = -1;
227 unsigned char* buff = 0;
228 unsigned int buff_size = 0;
229 mp4AudioSpecificConfig mp4ASC;
230 mp4ff_get_decoder_config(mp4, track, &buff, &buff_size);
231 if (buff) {
232 int rc = AudioSpecificConfig(buff, buff_size, &mp4ASC);
233 sr = mp4ASC.samplingFrequency;
234 if(rc < 0) {
235 free (buff);
236 trace ("aac: AudioSpecificConfig returned result=%d\n", rc);
237 return -1;
238 }
239 }
240
241 unsigned long srate;
242 unsigned char ch;
243 int samples;
244
245 // init mp4 decoding
246 NeAACDecHandle dec = NeAACDecOpen ();
247 if (NeAACDecInit2(dec, buff, buff_size, &srate, &ch) < 0) {
248 trace ("NeAACDecInit2 returned error\n");
249 goto error;
250 }
251 *samplerate = srate;
252 *channels = ch;
253 samples = (int64_t)mp4ff_num_samples(mp4, track);
254
255 NeAACDecClose (dec);
256 dec = NULL;
257
258 if (samples <= 0) {
259 goto error;
260 }
261
262 int i_sample_count = samples;
263 int i_sample;
264
265 int64_t total_dur = 0;
266 for( i_sample = 0; i_sample < i_sample_count; i_sample++ )
267 {
268 total_dur += mp4ff_get_sample_duration (mp4, track, i_sample);
269 }
270 if (totalsamples) {
271 *totalsamples = total_dur * (*samplerate) / mp4ff_time_scale (mp4, track);
272 *mp4framesize = (*totalsamples) / i_sample_count;
273 }
274 *duration = total_dur / (float)mp4ff_time_scale (mp4, track);
275
276 return 0;
277 error:
278 if (dec) {
279 NeAACDecClose (dec);
280 }
281 free (buff);
282 return -1;
283 }
284
285 // returns -1 for error, 0 for aac
286 int
aac_probe(DB_FILE * fp,float * duration,int * samplerate,int * channels,int * totalsamples)287 aac_probe (DB_FILE *fp, float *duration, int *samplerate, int *channels, int *totalsamples) {
288
289 deadbeef->rewind (fp);
290 if (parse_aac_stream (fp, samplerate, channels, duration, totalsamples) == -1) {
291 trace ("aac stream not found\n");
292 return -1;
293 }
294 trace ("found aac stream\n");
295 return 0;
296 }
297
298
299 static int
aac_init(DB_fileinfo_t * _info,DB_playItem_t * it)300 aac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
301 aac_info_t *info = (aac_info_t *)_info;
302
303 deadbeef->pl_lock ();
304 info->file = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
305 deadbeef->pl_unlock ();
306 if (!info->file) {
307 return -1;
308 }
309
310 // probe
311 float duration = -1;
312 int samplerate = -1;
313 int channels = -1;
314 int totalsamples = -1;
315
316 if (!info->file->vfs->is_streaming ()) {
317 info->junk = deadbeef->junk_get_leading_size (info->file);
318 if (info->junk >= 0) {
319 deadbeef->fseek (info->file, info->junk, SEEK_SET);
320 }
321 else {
322 info->junk = 0;
323 }
324 }
325 else {
326 deadbeef->fset_track (info->file, it);
327 }
328
329 info->mp4track = -1;
330 info->mp4reader.read = aac_fs_read;
331 info->mp4reader.write = NULL;
332 info->mp4reader.seek = aac_fs_seek;
333 info->mp4reader.truncate = NULL;
334 info->mp4reader.user_data = info;
335
336 trace ("aac_init: mp4ff_open_read %s\n", deadbeef->pl_find_meta (it, ":URI"));
337 info->mp4 = mp4ff_open_read (&info->mp4reader);
338 if (info->mp4) {
339 int ntracks = mp4ff_total_tracks (info->mp4);
340 for (int i = 0; i < ntracks; i++) {
341 if (mp4ff_get_track_type (info->mp4, i) != TRACK_AUDIO) {
342 continue;
343 }
344 int res = mp4_track_get_info (info->mp4, i, &duration, &samplerate, &channels, &totalsamples, &info->mp4framesize);
345 if (res >= 0 && duration > 0) {
346 info->mp4track = i;
347 break;
348 }
349 }
350 trace ("track: %d\n", info->mp4track);
351 if (info->mp4track >= 0) {
352 // prepare decoder
353 int res = mp4_track_get_info (info->mp4, info->mp4track, &duration, &samplerate, &channels, &totalsamples, &info->mp4framesize);
354 if (res != 0) {
355 trace ("aac: mp4_track_get_info(%d) returned error\n", info->mp4track);
356 return -1;
357 }
358
359 // init mp4 decoding
360 info->mp4samples = mp4ff_num_samples(info->mp4, info->mp4track);
361 info->dec = NeAACDecOpen ();
362 unsigned long srate;
363 unsigned char ch;
364 unsigned char* buff = 0;
365 unsigned int buff_size = 0;
366 mp4AudioSpecificConfig mp4ASC;
367 mp4ff_get_decoder_config (info->mp4, info->mp4track, &buff, &buff_size);
368 if (NeAACDecInit2(info->dec, buff, buff_size, &srate, &ch) < 0) {
369 trace ("NeAACDecInit2 returned error\n");
370 free (buff);
371 return -1;
372 }
373
374 if (buff) {
375 free (buff);
376 }
377 trace ("aac: successfully initialized track %d\n", info->mp4track);
378 _info->fmt.samplerate = samplerate;
379 _info->fmt.channels = channels;
380 }
381 else {
382 trace ("aac: track not found in mp4 container\n");
383 mp4ff_close (info->mp4);
384 info->mp4 = NULL;
385 }
386 }
387
388 if (!info->mp4) {
389 trace ("aac: looking for raw stream...\n");
390 int offs;
391 if (!info->file->vfs->is_streaming ()) {
392 if (info->junk >= 0) {
393 deadbeef->fseek (info->file, info->junk, SEEK_SET);
394 }
395 else {
396 deadbeef->rewind (info->file);
397 }
398 offs = parse_aac_stream (info->file, &samplerate, &channels, &duration, &totalsamples);
399 }
400 else {
401 offs = parse_aac_stream (info->file, &samplerate, &channels, &duration, NULL);
402 }
403 if (offs == -1) {
404 trace ("aac stream not found\n");
405 return -1;
406 }
407 if (offs > info->junk) {
408 info->junk = offs;
409 }
410 if (!info->file->vfs->is_streaming ()) {
411 if (info->junk >= 0) {
412 deadbeef->fseek (info->file, info->junk, SEEK_SET);
413 }
414 else {
415 deadbeef->rewind (info->file);
416 }
417 }
418 else {
419 deadbeef->pl_replace_meta (it, "!FILETYPE", "AAC");
420 }
421 trace ("found aac stream (junk: %d, offs: %d)\n", info->junk, offs);
422
423 _info->fmt.channels = channels;
424 _info->fmt.samplerate = samplerate;
425 }
426
427 _info->fmt.bps = 16;
428 _info->plugin = &plugin;
429
430 if (!info->mp4) {
431 trace ("NeAACDecOpen for raw stream\n");
432 info->dec = NeAACDecOpen ();
433
434 trace ("prepare for NeAACDecInit: fread %d from offs %lld\n", AAC_BUFFER_SIZE, deadbeef->ftell (info->file));
435 info->remaining = deadbeef->fread (info->buffer, 1, AAC_BUFFER_SIZE, info->file);
436
437 NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration (info->dec);
438 // conf->dontUpSampleImplicitSBR = 1;
439 NeAACDecSetConfiguration (info->dec, conf);
440 unsigned long srate;
441 unsigned char ch;
442 trace ("NeAACDecInit (%d bytes)\n", info->remaining);
443 int consumed = NeAACDecInit (info->dec, info->buffer, info->remaining, &srate, &ch);
444 trace ("NeAACDecInit returned samplerate=%d, channels=%d, consumed: %d\n", (int)srate, (int)ch, consumed);
445 if (consumed < 0) {
446 trace ("NeAACDecInit returned %d\n", consumed);
447 return -1;
448 }
449 if (consumed > info->remaining) {
450 trace ("NeAACDecInit consumed more than available! wtf?\n");
451 return -1;
452 }
453 if (consumed == info->remaining) {
454 info->remaining = 0;
455 }
456 else if (consumed > 0) {
457 memmove (info->buffer, info->buffer + consumed, info->remaining - consumed);
458 info->remaining -= consumed;
459 }
460 _info->fmt.channels = ch;
461 _info->fmt.samplerate = srate;
462 }
463
464 if (!info->file->vfs->is_streaming ()) {
465 if (it->endsample > 0) {
466 info->startsample = it->startsample;
467 info->endsample = it->endsample;
468 plugin.seek_sample (_info, 0);
469 }
470 else {
471 info->startsample = 0;
472 info->endsample = totalsamples-1;
473 }
474 }
475 if (_info->fmt.channels == 7) {
476 _info->fmt.channels = 8;
477 }
478
479 trace ("totalsamples: %d, endsample: %d, samples-from-duration: %d, samplerate %d, channels %d\n", totalsamples-1, info->endsample, (int)deadbeef->pl_get_item_duration (it)*44100, _info->fmt.samplerate, _info->fmt.channels);
480
481 for (int i = 0; i < _info->fmt.channels; i++) {
482 _info->fmt.channelmask |= 1 << i;
483 }
484 info->noremap = 0;
485 for (int i = 0; i < sizeof (info->remap) / sizeof (int); i++) {
486 info->remap[i] = -1;
487 }
488
489 trace ("init success\n");
490
491 return 0;
492 }
493
494 static void
aac_free(DB_fileinfo_t * _info)495 aac_free (DB_fileinfo_t *_info) {
496 aac_info_t *info = (aac_info_t *)_info;
497 if (info) {
498 if (info->file) {
499 deadbeef->fclose (info->file);
500 }
501 if (info->mp4) {
502 mp4ff_close (info->mp4);
503 }
504 if (info->dec) {
505 NeAACDecClose (info->dec);
506 }
507 free (info);
508 }
509 }
510
511 static int
aac_read(DB_fileinfo_t * _info,char * bytes,int size)512 aac_read (DB_fileinfo_t *_info, char *bytes, int size) {
513 aac_info_t *info = (aac_info_t *)_info;
514 if (info->eof) {
515 trace ("aac_read: received call after eof\n");
516 return 0;
517 }
518 int samplesize = _info->fmt.channels * _info->fmt.bps / 8;
519 if (!info->file->vfs->is_streaming ()) {
520 if (info->currentsample + size / samplesize > info->endsample) {
521 size = (info->endsample - info->currentsample + 1) * samplesize;
522 if (size <= 0) {
523 trace ("aac_read: eof (current=%d, total=%d)\n", info->currentsample, info->endsample);
524 return 0;
525 }
526 }
527 }
528
529 int initsize = size;
530
531 while (size > 0) {
532 if (info->skipsamples > 0 && info->out_remaining > 0) {
533 int skip = min (info->out_remaining, info->skipsamples);
534 // trace ("skipping %d\n", skip);
535 if (skip < info->out_remaining) {
536 memmove (info->out_buffer, info->out_buffer + skip * samplesize, (info->out_remaining - skip) * samplesize);
537 }
538 info->out_remaining -= skip;
539 info->skipsamples -= skip;
540 }
541 if (info->out_remaining > 0) {
542 int n = size / samplesize;
543 n = min (info->out_remaining, n);
544
545 char *src = info->out_buffer;
546 if (info->noremap) {
547 memcpy (bytes, src, n * samplesize);
548 bytes += n * samplesize;
549 src += n * samplesize;
550 }
551 else {
552 int i, j;
553 if (info->remap[0] == -1) {
554 // build remap mtx
555 // FIXME: should build channelmask 1st; then remap based on channelmask
556 for (i = 0; i < _info->fmt.channels; i++) {
557 switch (info->frame_info.channel_position[i]) {
558 case FRONT_CHANNEL_CENTER:
559 trace ("FC->%d %d\n", i, 2);
560 info->remap[2] = i;
561 break;
562 case FRONT_CHANNEL_LEFT:
563 trace ("FL->%d %d\n", i, 0);
564 info->remap[0] = i;
565 break;
566 case FRONT_CHANNEL_RIGHT:
567 trace ("FR->%d %d\n", i, 1);
568 info->remap[1] = i;
569 break;
570 case SIDE_CHANNEL_LEFT:
571 trace ("SL->%d %d\n", i, 6);
572 info->remap[6] = i;
573 break;
574 case SIDE_CHANNEL_RIGHT:
575 trace ("SR->%d %d\n", i, 7);
576 info->remap[7] = i;
577 break;
578 case BACK_CHANNEL_LEFT:
579 trace ("RL->%d %d\n", i, 4);
580 info->remap[4] = i;
581 break;
582 case BACK_CHANNEL_RIGHT:
583 trace ("RR->%d %d\n", i, 5);
584 info->remap[5] = i;
585 break;
586 case BACK_CHANNEL_CENTER:
587 trace ("BC->%d %d\n", i, 8);
588 info->remap[8] = i;
589 break;
590 case LFE_CHANNEL:
591 trace ("LFE->%d %d\n", i, 3);
592 info->remap[3] = i;
593 break;
594 default:
595 trace ("aac: unknown ch(%d)->%d\n", info->frame_info.channel_position[i], i);
596 break;
597 }
598 }
599 for (i = 0; i < _info->fmt.channels; i++) {
600 trace ("%d ", info->remap[i]);
601 }
602 trace ("\n");
603 if (info->remap[0] == -1) {
604 info->remap[0] = 0;
605 }
606 if ((_info->fmt.channels == 1 && info->remap[0] == FRONT_CHANNEL_CENTER)
607 || (_info->fmt.channels == 2 && info->remap[0] == FRONT_CHANNEL_LEFT && info->remap[1] == FRONT_CHANNEL_RIGHT)) {
608 info->noremap = 1;
609 }
610 }
611
612 for (i = 0; i < n; i++) {
613 for (j = 0; j < _info->fmt.channels; j++) {
614 if (info->remap[j] == -1) {
615 ((int16_t *)bytes)[j] = 0;
616 }
617 else {
618 ((int16_t *)bytes)[j] = ((int16_t *)src)[info->remap[j]];
619 }
620 }
621 src += samplesize;
622 bytes += samplesize;
623 }
624 }
625 size -= n * samplesize;
626
627 if (n == info->out_remaining) {
628 info->out_remaining = 0;
629 }
630 else {
631 memmove (info->out_buffer, src, (info->out_remaining - n) * samplesize);
632 info->out_remaining -= n;
633 }
634 continue;
635 }
636
637 char *samples = NULL;
638
639 if (info->mp4) {
640 if (info->mp4sample >= info->mp4samples) {
641 trace ("aac: finished with the last mp4sample\n");
642 break;
643 }
644
645 unsigned char *buffer = NULL;
646 int buffer_size = 0;
647 int rc = mp4ff_read_sample (info->mp4, info->mp4track, info->mp4sample, &buffer, &buffer_size);
648 if (rc == 0) {
649 trace ("mp4ff_read_sample failed\n");
650 info->eof = 1;
651 break;
652 }
653 info->mp4sample++;
654 samples = NeAACDecDecode(info->dec, &info->frame_info, buffer, buffer_size);
655
656 if (buffer) {
657 free (buffer);
658 }
659 if (!samples) {
660 trace ("aac: NeAACDecDecode returned NULL\n");
661 break;
662 }
663 }
664 else {
665 if (info->remaining < AAC_BUFFER_SIZE) {
666 trace ("fread from offs %lld\n", deadbeef->ftell (info->file));
667 size_t res = deadbeef->fread (info->buffer + info->remaining, 1, AAC_BUFFER_SIZE-info->remaining, info->file);
668 info->remaining += res;
669 trace ("remain: %d\n", info->remaining);
670 if (!info->remaining) {
671 break;
672 }
673 }
674
675 trace ("NeAACDecDecode %d bytes\n", info->remaining)
676 samples = NeAACDecDecode (info->dec, &info->frame_info, info->buffer, info->remaining);
677 trace ("samples =%p\n", samples);
678 if (!samples) {
679 trace ("NeAACDecDecode failed with error %s (%d), consumed=%d\n", NeAACDecGetErrorMessage(info->frame_info.error), (int)info->frame_info.error, (int)info->frame_info.bytesconsumed);
680
681 if (info->num_errors > 10) {
682 trace ("NeAACDecDecode failed %d times, interrupting\n", info->num_errors);
683 break;
684 }
685 info->num_errors++;
686 info->remaining = 0;
687 continue;
688 }
689 info->num_errors=0;
690 int consumed = info->frame_info.bytesconsumed;
691 if (consumed > info->remaining) {
692 trace ("NeAACDecDecode consumed more than available! wtf?\n");
693 break;
694 }
695 if (consumed == info->remaining) {
696 info->remaining = 0;
697 }
698 else if (consumed > 0) {
699 memmove (info->buffer, info->buffer + consumed, info->remaining - consumed);
700 info->remaining -= consumed;
701 }
702 }
703
704 if (info->frame_info.samples > 0) {
705 memcpy (info->out_buffer, samples, info->frame_info.samples * 2);
706 info->out_remaining = info->frame_info.samples / info->frame_info.channels;
707 }
708 }
709
710 info->currentsample += (initsize-size) / samplesize;
711
712 return initsize-size;
713 }
714
715 // returns -1 on error, 0 on success
716 int
seek_raw_aac(aac_info_t * info,int sample)717 seek_raw_aac (aac_info_t *info, int sample) {
718 uint8_t buf[ADTS_HEADER_SIZE*8];
719
720 int nsamples = 0;
721 int stream_sr = 0;
722 int stream_ch = 0;
723
724 int eof = 0;
725 int bufsize = 0;
726 int remaining = 0;
727
728 int frame = 0;
729
730 int frame_samples = 0;
731 int curr_sample = 0;
732
733 do {
734 curr_sample += frame_samples;
735 int size = sizeof (buf) - bufsize;
736 if (deadbeef->fread (buf + bufsize, 1, size, info->file) != size) {
737 trace ("seek_raw_aac: eof\n");
738 break;
739 }
740 bufsize = sizeof (buf);
741
742 int channels, samplerate, bitrate;
743 size = aac_sync (buf, &channels, &samplerate, &bitrate, &frame_samples);
744 if (size == 0) {
745 memmove (buf, buf+1, sizeof (buf)-1);
746 bufsize--;
747 continue;
748 }
749 else {
750 //trace ("aac: frame #%d(%d/%d) sync: %d %d %d %d %d\n", frame, curr_sample, sample, channels, samplerate, bitrate, frame_samples, size);
751 frame++;
752 if (deadbeef->fseek (info->file, size-(int)sizeof(buf), SEEK_CUR) == -1) {
753 trace ("seek_raw_aac: invalid seek %d\n", size-sizeof(buf));
754 break;
755 }
756 bufsize = 0;
757 }
758 if (samplerate <= 24000) {
759 frame_samples *= 2;
760 }
761 } while (curr_sample + frame_samples < sample);
762
763 if (curr_sample + frame_samples < sample) {
764 return -1;
765 }
766
767 return sample - curr_sample;
768 }
769
770 static int
aac_seek_sample(DB_fileinfo_t * _info,int sample)771 aac_seek_sample (DB_fileinfo_t *_info, int sample) {
772 aac_info_t *info = (aac_info_t *)_info;
773
774 trace ("seek: start %d + %d\n", info->startsample, sample);
775
776 sample += info->startsample;
777 if (info->mp4) {
778 int totalsamples = 0;
779 int i;
780 int num_sample_byte_sizes = mp4ff_get_num_sample_byte_sizes (info->mp4, info->mp4track);
781 int scale = _info->fmt.samplerate / mp4ff_time_scale (info->mp4, info->mp4track);
782 for (i = 0; i < num_sample_byte_sizes; i++)
783 {
784 unsigned int thissample_duration = 0;
785 unsigned int thissample_bytesize = 0;
786
787 mp4ff_get_sample_info(info->mp4, info->mp4track, i, &thissample_duration,
788 &thissample_bytesize);
789
790 if (totalsamples + thissample_duration > sample / scale) {
791 info->skipsamples = sample - totalsamples * scale;
792 break;
793 }
794 totalsamples += thissample_duration;
795 }
796 // i = sample / info->mp4framesize;
797 // info->skipsamples = sample - info->mp4sample * info->mp4framesize;
798 info->mp4sample = i;
799 trace ("seek res: frame %d (old: %d*%d), skip %d\n", info->mp4sample, sample / info->mp4framesize, info->mp4framesize, info->skipsamples);
800 }
801 else {
802 int skip = deadbeef->junk_get_leading_size (info->file);
803 if (skip >= 0) {
804 deadbeef->fseek (info->file, skip, SEEK_SET);
805 }
806 else {
807 deadbeef->fseek (info->file, 0, SEEK_SET);
808 }
809
810 int res = seek_raw_aac (info, sample);
811 if (res < 0) {
812 return -1;
813 }
814 info->skipsamples = res;
815 }
816 info->remaining = 0;
817 info->out_remaining = 0;
818 info->currentsample = sample;
819 _info->readpos = (float)(info->currentsample - info->startsample) / _info->fmt.samplerate;
820 return 0;
821 }
822
823 static int
aac_seek(DB_fileinfo_t * _info,float t)824 aac_seek (DB_fileinfo_t *_info, float t) {
825 return aac_seek_sample (_info, t * _info->fmt.samplerate);
826 }
827
828 static const char *metainfo[] = {
829 "artist", "artist",
830 "title", "title",
831 "album", "album",
832 "track", "track",
833 "date", "year",
834 "genre", "genre",
835 "comment", "comment",
836 "performer", "performer",
837 "album_artist", "band",
838 "writer", "composer",
839 "vendor", "vendor",
840 "disc", "disc",
841 "compilation", "compilation",
842 "totaldiscs", "numdiscs",
843 "copyright", "copyright",
844 "totaltracks", "numtracks",
845 "tool", "tool",
846 "MusicBrainz Track Id", "musicbrainz_trackid",
847 NULL
848 };
849
850
851 /* find a metadata item by name */
852 /* returns 0 if item found, 1 if no such item */
853 int32_t mp4ff_meta_find_by_name(const mp4ff_t *f, const char *item, char **value);
854
855
856 void
aac_load_tags(DB_playItem_t * it,mp4ff_t * mp4)857 aac_load_tags (DB_playItem_t *it, mp4ff_t *mp4) {
858 char *s = NULL;
859 int got_itunes_tags = 0;
860
861 int n = mp4ff_meta_get_num_items (mp4);
862 for (int t = 0; t < n; t++) {
863 char *key = NULL;
864 char *value = NULL;
865 int res = mp4ff_meta_get_by_index(mp4, t, &key, &value);
866 if (key && value) {
867 got_itunes_tags = 1;
868 if (strcasecmp (key, "cover")) {
869 if (!strcasecmp (key, "replaygain_track_gain")) {
870 deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKGAIN, atof (value));
871 }
872 else if (!strcasecmp (key, "replaygain_album_gain")) {
873 deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMGAIN, atof (value));
874 }
875 else if (!strcasecmp (key, "replaygain_track_peak")) {
876 deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKPEAK, atof (value));
877 }
878 else if (!strcasecmp (key, "replaygain_album_peak")) {
879 deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMPEAK, atof (value));
880 }
881 else {
882 int i;
883 for (i = 0; metainfo[i]; i += 2) {
884 if (!strcasecmp (metainfo[i], key)) {
885 deadbeef->pl_add_meta (it, metainfo[i+1], value);
886 break;
887 }
888 }
889 if (!metainfo[i]) {
890 deadbeef->pl_add_meta (it, key, value);
891 }
892 }
893 }
894 }
895 if (key) {
896 free (key);
897 }
898 if (value) {
899 free (value);
900 }
901 }
902
903 if (got_itunes_tags) {
904 uint32_t f = deadbeef->pl_get_item_flags (it);
905 f |= DDB_TAG_ITUNES;
906 deadbeef->pl_set_item_flags (it, f);
907 }
908 }
909
910
911 int
aac_read_metadata(DB_playItem_t * it)912 aac_read_metadata (DB_playItem_t *it) {
913 deadbeef->pl_lock ();
914 DB_FILE *fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
915 deadbeef->pl_unlock ();
916 if (!fp) {
917 return -1;
918 }
919
920 if (fp->vfs->is_streaming ()) {
921 deadbeef->fclose (fp);
922 return -1;
923 }
924
925 aac_info_t inf;
926 memset (&inf, 0, sizeof (inf));
927 inf.file = fp;
928 inf.junk = deadbeef->junk_get_leading_size (fp);
929 if (inf.junk >= 0) {
930 deadbeef->fseek (inf.file, inf.junk, SEEK_SET);
931 }
932 else {
933 inf.junk = 0;
934 }
935
936 MP4FILE_CB cb = {
937 .read = aac_fs_read,
938 .write = NULL,
939 .seek = aac_fs_seek,
940 .truncate = NULL,
941 .user_data = &inf
942 };
943
944 deadbeef->pl_delete_all_meta (it);
945
946 mp4ff_t *mp4 = mp4ff_open_read (&cb);
947 if (mp4) {
948 aac_load_tags (it, mp4);
949 mp4ff_close (mp4);
950 }
951 /*int apeerr = */deadbeef->junk_apev2_read (it, fp);
952 /*int v2err = */deadbeef->junk_id3v2_read (it, fp);
953 /*int v1err = */deadbeef->junk_id3v1_read (it, fp);
954 deadbeef->fclose (fp);
955 return 0;
956 }
957
958 typedef struct {
959 char *title;
960 int32_t startsample;
961 int32_t endsample;
962 } aac_chapter_t;
963
964 static aac_chapter_t *
aac_load_itunes_chapters(mp4ff_t * mp4,int * num_chapters,int samplerate)965 aac_load_itunes_chapters (mp4ff_t *mp4, /* out */ int *num_chapters, int samplerate) {
966 *num_chapters = 0;
967 int i_entry_count = mp4ff_chap_get_num_tracks (mp4);
968 int i_tracks = mp4ff_total_tracks (mp4);
969 int i, j;
970 for( i = 0; i < i_entry_count; i++ )
971 {
972 for( j = 0; j < i_tracks; j++ )
973 {
974 int32_t tt = mp4ff_get_track_type (mp4, j);
975 trace ("aac: i_tracks=%d found track id=%d type=%d (expected %d %d)\n", i_tracks, mp4ff_get_track_id (mp4, j), mp4ff_get_track_type (mp4, j), mp4ff_chap_get_track_id (mp4, i), TRACK_TEXT);
976 if(mp4ff_chap_get_track_id (mp4, i) == mp4ff_get_track_id (mp4, j) &&
977 mp4ff_get_track_type (mp4, j) == TRACK_TEXT) {
978 trace ("aac: found subt track\n");
979 break;
980 }
981 }
982 if( j < i_tracks )
983 {
984 int i_sample_count = mp4ff_num_samples (mp4, j);
985 int i_sample;
986
987 aac_chapter_t *chapters = malloc (sizeof (aac_chapter_t) * i_sample_count);
988 memset (chapters, 0, sizeof (aac_chapter_t) * i_sample_count);
989 *num_chapters = 0;
990
991 int64_t total_dur = 0;
992 int64_t curr_sample = 0;
993 for( i_sample = 0; i_sample < i_sample_count; i_sample++ )
994 {
995 #if 0
996 const int64_t i_dts = mp4ff_get_track_dts (mp4, j, i_sample);
997 const int64_t i_pts_delta = mp4ff_get_track_pts_delta(mp4, j, i_sample);
998 trace ("i_dts = %lld, i_pts_delta = %lld\n", i_dts, i_pts_delta);
999 const unsigned int i_size = mp4ff_get_track_sample_size(mp4, j, i_sample);
1000 if (i_size <= 0) {
1001 continue;
1002 }
1003
1004 int64_t i_time_offset = i_dts + max (i_pts_delta, 0);
1005 #endif
1006 int32_t dur = (int64_t)1000 * mp4ff_get_sample_duration (mp4, j, i_sample) / mp4ff_time_scale (mp4, j); // milliseconds
1007 total_dur += dur;
1008 #if 0
1009 trace ("dur: %d %f min // offs: %lld %f (from currsample: %f)\n", dur, dur / 1000.f / 60.f, i_time_offset, i_time_offset / 1000000.f / 60.f, curr_sample * 1000.f/ samplerate);
1010 #else
1011 trace ("dur: %d %f min\n", dur, dur / 1000.f / 60.f);
1012 #endif
1013 unsigned char *buffer = NULL;
1014 int buffer_size = 0;
1015
1016 int rc = mp4ff_read_sample (mp4, j, i_sample, &buffer, &buffer_size);
1017
1018 if (rc == 0 || !buffer) {
1019 continue;
1020 }
1021 int len = (buffer[0] << 8) | buffer[1];
1022 len = min (len, buffer_size - 2);
1023 if (len > 0) {
1024 chapters[*num_chapters].title = strndup (&buffer[2], len);
1025 }
1026 chapters[*num_chapters].startsample = curr_sample;
1027 curr_sample += (int64_t)dur * samplerate / 1000.f;
1028 chapters[*num_chapters].endsample = curr_sample - 1;
1029 trace ("aac: chapter %d: %s, s=%d e=%d\n", *num_chapters, chapters[*num_chapters].title, chapters[*num_chapters].startsample, chapters[*num_chapters].endsample);
1030 if (buffer) {
1031 free (buffer);
1032 }
1033 (*num_chapters)++;
1034 }
1035 trace ("aac: total dur: %lld (%f min)\n", total_dur, total_dur / 1000.f / 60.f);
1036 return chapters;
1037 }
1038 }
1039 return NULL;
1040 }
1041
1042 static DB_playItem_t *
aac_insert_with_chapters(ddb_playlist_t * plt,DB_playItem_t * after,DB_playItem_t * origin,aac_chapter_t * chapters,int num_chapters,int totalsamples,int samplerate)1043 aac_insert_with_chapters (ddb_playlist_t *plt, DB_playItem_t *after, DB_playItem_t *origin, aac_chapter_t *chapters, int num_chapters, int totalsamples, int samplerate) {
1044 deadbeef->pl_lock ();
1045 DB_playItem_t *ins = after;
1046 for (int i = 0; i < num_chapters; i++) {
1047 const char *uri = deadbeef->pl_find_meta_raw (origin, ":URI");
1048 const char *dec = deadbeef->pl_find_meta_raw (origin, ":DECODER");
1049 const char *ftype= "MP4 AAC";//pl_find_meta_raw (origin, ":FILETYPE");
1050
1051 DB_playItem_t *it = deadbeef->pl_item_alloc_init (uri, dec);
1052 deadbeef->pl_set_meta_int (it, ":TRACKNUM", i);
1053 deadbeef->pl_set_meta_int (it, "TRACK", i);
1054 // poor-man utf8 check
1055 if (!chapters[i].title || deadbeef->junk_detect_charset (chapters[i].title)) {
1056 char s[1000];
1057 snprintf (s, sizeof (s), "chapter %d", i+1);
1058 deadbeef->pl_add_meta (it, "title", s);
1059 }
1060 else {
1061 deadbeef->pl_add_meta (it, "title", chapters[i].title);
1062 }
1063 it->startsample = chapters[i].startsample;
1064 it->endsample = chapters[i].endsample;
1065 deadbeef->pl_replace_meta (it, ":FILETYPE", ftype);
1066 deadbeef->plt_set_item_duration (plt, it, (float)(it->endsample - it->startsample + 1) / samplerate);
1067 after = deadbeef->plt_insert_item (plt, after, it);
1068 deadbeef->pl_item_unref (it);
1069 }
1070 deadbeef->pl_item_ref (after);
1071
1072 DB_playItem_t *first = deadbeef->pl_get_next (ins, PL_MAIN);
1073
1074 if (!first) {
1075 first = deadbeef->plt_get_first (plt, PL_MAIN);
1076 }
1077
1078 if (!first) {
1079 deadbeef->pl_unlock ();
1080 return NULL;
1081 }
1082 trace ("aac: split by chapters success\n");
1083 // copy metadata from embedded tags
1084 uint32_t f = deadbeef->pl_get_item_flags (origin);
1085 f |= DDB_IS_SUBTRACK;
1086 deadbeef->pl_set_item_flags (origin, f);
1087 deadbeef->pl_items_copy_junk (origin, first, after);
1088 deadbeef->pl_item_unref (first);
1089
1090 deadbeef->pl_unlock ();
1091 return after;
1092 }
1093
1094 static DB_playItem_t *
aac_insert(ddb_playlist_t * plt,DB_playItem_t * after,const char * fname)1095 aac_insert (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname) {
1096 trace ("adding %s\n", fname);
1097 DB_FILE *fp = deadbeef->fopen (fname);
1098 if (!fp) {
1099 trace ("not found\n");
1100 return NULL;
1101 }
1102 aac_info_t info = {0};
1103 info.junk = deadbeef->junk_get_leading_size (fp);
1104 if (info.junk >= 0) {
1105 trace ("junk: %d\n", info.junk);
1106 deadbeef->fseek (fp, info.junk, SEEK_SET);
1107 }
1108 else {
1109 info.junk = 0;
1110 }
1111
1112 const char *ftype = NULL;
1113 float duration = -1;
1114 int totalsamples = 0;
1115 int samplerate = 0;
1116 int channels = 0;
1117
1118 int mp4track = -1;
1119 MP4FILE mp4 = NULL;
1120
1121 if (fp->vfs->is_streaming ()) {
1122 trace ("streaming aac (%s)\n", fname);
1123 ftype = "RAW AAC";
1124 }
1125 else {
1126
1127 // slowwww!
1128 info.file = fp;
1129 MP4FILE_CB cb = {
1130 .read = aac_fs_read,
1131 .write = NULL,
1132 .seek = aac_fs_seek,
1133 .truncate = NULL,
1134 .user_data = &info
1135 };
1136 mp4ff_t *mp4 = mp4ff_open_read (&cb);
1137 if (mp4) {
1138 int ntracks = mp4ff_total_tracks (mp4);
1139 trace ("aac: numtracks=%d\n", ntracks);
1140 int i;
1141 for (i = 0; i < ntracks; i++) {
1142 if (mp4ff_get_track_type (mp4, i) != TRACK_AUDIO) {
1143 trace ("aac: track %d is not audio\n", i);
1144 continue;
1145 }
1146 int mp4framesize;
1147 int res = mp4_track_get_info (mp4, i, &duration, &samplerate, &channels, &totalsamples, &mp4framesize);
1148 if (res >= 0 && duration > 0) {
1149 trace ("aac: found audio track %d (duration=%f, totalsamples=%d)\n", i, duration, totalsamples);
1150
1151 int num_chapters;
1152 aac_chapter_t *chapters = NULL;
1153 if (mp4ff_chap_get_num_tracks(mp4) > 0) {
1154 chapters = aac_load_itunes_chapters (mp4, &num_chapters, samplerate);
1155 }
1156
1157 DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
1158 ftype = "MP4 AAC";
1159 deadbeef->pl_add_meta (it, ":FILETYPE", ftype);
1160 deadbeef->pl_set_meta_int (it, ":TRACKNUM", i);
1161 deadbeef->plt_set_item_duration (plt, it, duration);
1162 aac_load_tags (it, mp4);
1163 int apeerr = deadbeef->junk_apev2_read (it, fp);
1164 int v2err = deadbeef->junk_id3v2_read (it, fp);
1165 int v1err = deadbeef->junk_id3v1_read (it, fp);
1166
1167 int64_t fsize = deadbeef->fgetlength (fp);
1168
1169 char s[100];
1170 snprintf (s, sizeof (s), "%lld", fsize);
1171 deadbeef->pl_add_meta (it, ":FILE_SIZE", s);
1172 deadbeef->pl_add_meta (it, ":BPS", "16");
1173 snprintf (s, sizeof (s), "%d", channels);
1174 deadbeef->pl_add_meta (it, ":CHANNELS", s);
1175 snprintf (s, sizeof (s), "%d", samplerate);
1176 deadbeef->pl_add_meta (it, ":SAMPLERATE", s);
1177 int br = (int)roundf(fsize / duration * 8 / 1000);
1178 snprintf (s, sizeof (s), "%d", br);
1179 deadbeef->pl_add_meta (it, ":BITRATE", s);
1180
1181 // embedded chapters
1182 deadbeef->pl_lock (); // FIXME: is it needed?
1183 if (chapters && num_chapters > 0) {
1184 DB_playItem_t *cue = aac_insert_with_chapters (plt, after, it, chapters, num_chapters, totalsamples, samplerate);
1185 for (int n = 0; n < num_chapters; n++) {
1186 if (chapters[n].title) {
1187 free (chapters[n].title);
1188 }
1189 }
1190 free (chapters);
1191 if (cue) {
1192 deadbeef->fclose (fp);
1193 mp4ff_close (mp4);
1194 deadbeef->pl_item_unref (it);
1195 deadbeef->pl_item_unref (cue);
1196 deadbeef->pl_unlock ();
1197 return cue;
1198 }
1199 }
1200
1201 // embedded cue
1202 const char *cuesheet = deadbeef->pl_find_meta (it, "cuesheet");
1203 DB_playItem_t *cue = NULL;
1204
1205 if (cuesheet) {
1206 cue = deadbeef->plt_insert_cue_from_buffer (plt, after, it, cuesheet, strlen (cuesheet), totalsamples, samplerate);
1207 if (cue) {
1208 deadbeef->fclose (fp);
1209 mp4ff_close (mp4);
1210 deadbeef->pl_item_unref (it);
1211 deadbeef->pl_item_unref (cue);
1212 deadbeef->pl_unlock ();
1213 return cue;
1214 }
1215 }
1216 deadbeef->pl_unlock ();
1217
1218 cue = deadbeef->plt_insert_cue (plt, after, it, totalsamples, samplerate);
1219 if (cue) {
1220 deadbeef->pl_item_unref (it);
1221 deadbeef->pl_item_unref (cue);
1222 return cue;
1223 }
1224
1225 after = deadbeef->plt_insert_item (plt, after, it);
1226 deadbeef->pl_item_unref (it);
1227 break;
1228 }
1229 }
1230 mp4ff_close (mp4);
1231 if (i < ntracks) {
1232 deadbeef->fclose (fp);
1233 return after;
1234 }
1235 if (ntracks > 0) {
1236 // mp4 container found, but no valid aac tracks in it
1237 deadbeef->fclose (fp);
1238 return NULL;
1239 }
1240 }
1241 }
1242 trace ("aac: mp4 container failed, trying raw aac\n");
1243 int res = aac_probe (fp, &duration, &samplerate, &channels, &totalsamples);
1244 if (res == -1) {
1245 deadbeef->fclose (fp);
1246 return NULL;
1247 }
1248 ftype = "RAW AAC";
1249 DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
1250 deadbeef->pl_add_meta (it, ":FILETYPE", ftype);
1251 deadbeef->plt_set_item_duration (plt, it, duration);
1252 trace ("duration: %f sec\n", duration);
1253
1254 // read tags
1255 int apeerr = deadbeef->junk_apev2_read (it, fp);
1256 int v2err = deadbeef->junk_id3v2_read (it, fp);
1257 int v1err = deadbeef->junk_id3v1_read (it, fp);
1258
1259 int64_t fsize = deadbeef->fgetlength (fp);
1260
1261 deadbeef->fclose (fp);
1262
1263 if (duration > 0) {
1264 char s[100];
1265 snprintf (s, sizeof (s), "%lld", fsize);
1266 deadbeef->pl_add_meta (it, ":FILE_SIZE", s);
1267 deadbeef->pl_add_meta (it, ":BPS", "16");
1268 snprintf (s, sizeof (s), "%d", channels);
1269 deadbeef->pl_add_meta (it, ":CHANNELS", s);
1270 snprintf (s, sizeof (s), "%d", samplerate);
1271 deadbeef->pl_add_meta (it, ":SAMPLERATE", s);
1272 int br = (int)roundf(fsize / duration * 8 / 1000);
1273 snprintf (s, sizeof (s), "%d", br);
1274 deadbeef->pl_add_meta (it, ":BITRATE", s);
1275 // embedded cue
1276 deadbeef->pl_lock ();
1277 const char *cuesheet = deadbeef->pl_find_meta (it, "cuesheet");
1278 DB_playItem_t *cue = NULL;
1279
1280 if (cuesheet) {
1281 cue = deadbeef->plt_insert_cue_from_buffer (plt, after, it, cuesheet, strlen (cuesheet), totalsamples, samplerate);
1282 if (cue) {
1283 deadbeef->pl_item_unref (it);
1284 deadbeef->pl_item_unref (cue);
1285 deadbeef->pl_unlock ();
1286 return cue;
1287 }
1288 }
1289 deadbeef->pl_unlock ();
1290
1291 cue = deadbeef->plt_insert_cue (plt, after, it, totalsamples, samplerate);
1292 if (cue) {
1293 deadbeef->pl_item_unref (it);
1294 deadbeef->pl_item_unref (cue);
1295 return cue;
1296 }
1297 }
1298
1299 after = deadbeef->plt_insert_item (plt, after, it);
1300 deadbeef->pl_item_unref (it);
1301
1302 return after;
1303 }
1304
1305 static const char * exts[] = { "aac", "mp4", "m4a", "m4b", NULL };
1306
1307 // define plugin interface
1308 static DB_decoder_t plugin = {
1309 .plugin.api_vmajor = 1,
1310 .plugin.api_vminor = 0,
1311 .plugin.version_major = 1,
1312 .plugin.version_minor = 0,
1313 .plugin.type = DB_PLUGIN_DECODER,
1314 .plugin.id = "aac",
1315 .plugin.name = "AAC player",
1316 .plugin.descr = "plays aac files, supports raw aac files, as well as mp4 container",
1317 .plugin.copyright =
1318 "Copyright (C) 2009-2013 Alexey Yakovenko <waker@users.sourceforge.net>\n"
1319 "\n"
1320 "Uses modified libmp4ff (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com\n"
1321 "\n"
1322 "This program is free software; you can redistribute it and/or\n"
1323 "modify it under the terms of the GNU General Public License\n"
1324 "as published by the Free Software Foundation; either version 2\n"
1325 "of the License, or (at your option) any later version.\n"
1326 "\n"
1327 "This program is distributed in the hope that it will be useful,\n"
1328 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1329 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1330 "GNU General Public License for more details.\n"
1331 "\n"
1332 "You should have received a copy of the GNU General Public License\n"
1333 "along with this program; if not, write to the Free Software\n"
1334 "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
1335 ,
1336 .plugin.website = "http://deadbeef.sf.net",
1337 .open = aac_open,
1338 .init = aac_init,
1339 .free = aac_free,
1340 .read = aac_read,
1341 .seek = aac_seek,
1342 .seek_sample = aac_seek_sample,
1343 .insert = aac_insert,
1344 .read_metadata = aac_read_metadata,
1345 .exts = exts,
1346 };
1347
1348 DB_plugin_t *
aac_load(DB_functions_t * api)1349 aac_load (DB_functions_t *api) {
1350 deadbeef = api;
1351 return DB_PLUGIN (&plugin);
1352 }
1353