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