Initial revision 6759
[qball-mpd.git] / src / inputPlugins / .svn / text-base / aac_plugin.c.svn-base
blob89095ef823e1f320b17e535bec219e203f3e7f1a
1 /* the Music Player Daemon (MPD)
2  * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
3  * This project's homepage is: http://www.musicpd.org
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (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  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
19 #include "../inputPlugin.h"
21 #ifdef HAVE_FAAD
23 #define AAC_MAX_CHANNELS        6
25 #include "../utils.h"
26 #include "../audio.h"
27 #include "../log.h"
28 #include "../inputStream.h"
29 #include "../outputBuffer.h"
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <faad.h>
37 /* all code here is either based on or copied from FAAD2's frontend code */
38 typedef struct {
39         InputStream *inStream;
40         long bytesIntoBuffer;
41         long bytesConsumed;
42         long fileOffset;
43         unsigned char *buffer;
44         int atEof;
45 } AacBuffer;
47 static void fillAacBuffer(AacBuffer * b)
49         if (b->bytesConsumed > 0) {
50                 int bread;
52                 if (b->bytesIntoBuffer) {
53                         memmove((void *)b->buffer, (void *)(b->buffer +
54                                                             b->bytesConsumed),
55                                 b->bytesIntoBuffer);
56                 }
58                 if (!b->atEof) {
59                         bread = readFromInputStream(b->inStream,
60                                                     (void *)(b->buffer +
61                                                              b->
62                                                              bytesIntoBuffer),
63                                                     1, b->bytesConsumed);
64                         if (bread != b->bytesConsumed)
65                                 b->atEof = 1;
66                         b->bytesIntoBuffer += bread;
67                 }
69                 b->bytesConsumed = 0;
71                 if (b->bytesIntoBuffer > 3) {
72                         if (memcmp(b->buffer, "TAG", 3) == 0)
73                                 b->bytesIntoBuffer = 0;
74                 }
75                 if (b->bytesIntoBuffer > 11) {
76                         if (memcmp(b->buffer, "LYRICSBEGIN", 11) == 0) {
77                                 b->bytesIntoBuffer = 0;
78                         }
79                 }
80                 if (b->bytesIntoBuffer > 8) {
81                         if (memcmp(b->buffer, "APETAGEX", 8) == 0) {
82                                 b->bytesIntoBuffer = 0;
83                         }
84                 }
85         }
88 static void advanceAacBuffer(AacBuffer * b, int bytes)
90         b->fileOffset += bytes;
91         b->bytesConsumed = bytes;
92         b->bytesIntoBuffer -= bytes;
95 static int adtsSampleRates[] =
96     { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
97         16000, 12000, 11025, 8000, 7350, 0, 0, 0
100 static int adtsParse(AacBuffer * b, float *length)
102         int frames, frameLength;
103         int tFrameLength = 0;
104         int sampleRate = 0;
105         float framesPerSec, bytesPerFrame;
107         /* Read all frames to ensure correct time and bitrate */
108         for (frames = 0;; frames++) {
109                 fillAacBuffer(b);
111                 if (b->bytesIntoBuffer > 7) {
112                         /* check syncword */
113                         if (!((b->buffer[0] == 0xFF) &&
114                               ((b->buffer[1] & 0xF6) == 0xF0))) {
115                                 break;
116                         }
118                         if (frames == 0) {
119                                 sampleRate = adtsSampleRates[(b->
120                                                               buffer[2] & 0x3c)
121                                                              >> 2];
122                         }
124                         frameLength = ((((unsigned int)b->buffer[3] & 0x3))
125                                        << 11) | (((unsigned int)b->buffer[4])
126                                                  << 3) | (b->buffer[5] >> 5);
128                         tFrameLength += frameLength;
130                         if (frameLength > b->bytesIntoBuffer)
131                                 break;
133                         advanceAacBuffer(b, frameLength);
134                 } else
135                         break;
136         }
138         framesPerSec = (float)sampleRate / 1024.0;
139         if (frames != 0) {
140                 bytesPerFrame = (float)tFrameLength / (float)(frames * 1000);
141         } else
142                 bytesPerFrame = 0;
143         if (framesPerSec != 0)
144                 *length = (float)frames / framesPerSec;
146         return 1;
149 static void initAacBuffer(InputStream * inStream, AacBuffer * b, float *length,
150                           size_t * retFileread, size_t * retTagsize)
152         size_t fileread;
153         size_t bread;
154         size_t tagsize;
156         if (length)
157                 *length = -1;
159         memset(b, 0, sizeof(AacBuffer));
161         b->inStream = inStream;
163         fileread = inStream->size;
165         b->buffer = xmalloc(FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS);
166         memset(b->buffer, 0, FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS);
168         bread = readFromInputStream(inStream, b->buffer, 1,
169                                     FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS);
170         b->bytesIntoBuffer = bread;
171         b->bytesConsumed = 0;
172         b->fileOffset = 0;
174         if (bread != FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS)
175                 b->atEof = 1;
177         tagsize = 0;
178         if (!memcmp(b->buffer, "ID3", 3)) {
179                 tagsize = (b->buffer[6] << 21) | (b->buffer[7] << 14) |
180                     (b->buffer[8] << 7) | (b->buffer[9] << 0);
182                 tagsize += 10;
183                 advanceAacBuffer(b, tagsize);
184                 fillAacBuffer(b);
185         }
187         if (retFileread)
188                 *retFileread = fileread;
189         if (retTagsize)
190                 *retTagsize = tagsize;
192         if (length == NULL)
193                 return;
195         if ((b->buffer[0] == 0xFF) && ((b->buffer[1] & 0xF6) == 0xF0)) {
196                 adtsParse(b, length);
197                 seekInputStream(b->inStream, tagsize, SEEK_SET);
199                 bread = readFromInputStream(b->inStream, b->buffer, 1,
200                                             FAAD_MIN_STREAMSIZE *
201                                             AAC_MAX_CHANNELS);
202                 if (bread != FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS)
203                         b->atEof = 1;
204                 else
205                         b->atEof = 0;
206                 b->bytesIntoBuffer = bread;
207                 b->bytesConsumed = 0;
208                 b->fileOffset = tagsize;
209         } else if (memcmp(b->buffer, "ADIF", 4) == 0) {
210                 int bitRate;
211                 int skipSize = (b->buffer[4] & 0x80) ? 9 : 0;
212                 bitRate =
213                     ((unsigned int)(b->
214                                     buffer[4 +
215                                            skipSize] & 0x0F) << 19) | ((unsigned
216                                                                         int)b->
217                                                                        buffer[5
218                                                                               +
219                                                                               skipSize]
220                                                                        << 11) |
221                     ((unsigned int)b->
222                      buffer[6 + skipSize] << 3) | ((unsigned int)b->buffer[7 +
223                                                                            skipSize]
224                                                    & 0xE0);
226                 if (fileread != 0 && bitRate != 0)
227                         *length = fileread * 8.0 / bitRate;
228                 else
229                         *length = fileread;
230         }
233 static float getAacFloatTotalTime(char *file)
235         AacBuffer b;
236         float length;
237         size_t fileread, tagsize;
238         faacDecHandle decoder;
239         faacDecConfigurationPtr config;
240         unsigned long sampleRate;
241         unsigned char channels;
242         InputStream inStream;
243         long bread;
245         if (openInputStream(&inStream, file) < 0)
246                 return -1;
248         initAacBuffer(&inStream, &b, &length, &fileread, &tagsize);
250         if (length < 0) {
251                 decoder = faacDecOpen();
253                 config = faacDecGetCurrentConfiguration(decoder);
254                 config->outputFormat = FAAD_FMT_16BIT;
255                 faacDecSetConfiguration(decoder, config);
257                 fillAacBuffer(&b);
258 #ifdef HAVE_FAAD_BUFLEN_FUNCS
259                 bread = faacDecInit(decoder, b.buffer, b.bytesIntoBuffer,
260                                     &sampleRate, &channels);
261 #else
262                 bread = faacDecInit(decoder, b.buffer, &sampleRate, &channels);
263 #endif
264                 if (bread >= 0 && sampleRate > 0 && channels > 0)
265                         length = 0;
267                 faacDecClose(decoder);
268         }
270         if (b.buffer)
271                 free(b.buffer);
272         closeInputStream(&inStream);
274         return length;
277 static int getAacTotalTime(char *file)
279         int time = -1;
280         float length;
282         if ((length = getAacFloatTotalTime(file)) >= 0)
283                 time = length + 0.5;
285         return time;
288 static int aac_decode(OutputBuffer * cb, DecoderControl * dc, char *path)
290         float time;
291         float totalTime;
292         faacDecHandle decoder;
293         faacDecFrameInfo frameInfo;
294         faacDecConfigurationPtr config;
295         long bread;
296         unsigned long sampleRate;
297         unsigned char channels;
298         int eof = 0;
299         unsigned int sampleCount;
300         char *sampleBuffer;
301         size_t sampleBufferLen;
302         /*float * seekTable;
303            long seekTableEnd = -1;
304            int seekPositionFound = 0; */
305         mpd_uint16 bitRate = 0;
306         AacBuffer b;
307         InputStream inStream;
309         if ((totalTime = getAacFloatTotalTime(path)) < 0)
310                 return -1;
312         if (openInputStream(&inStream, path) < 0)
313                 return -1;
315         initAacBuffer(&inStream, &b, NULL, NULL, NULL);
317         decoder = faacDecOpen();
319         config = faacDecGetCurrentConfiguration(decoder);
320         config->outputFormat = FAAD_FMT_16BIT;
321 #ifdef HAVE_FAACDECCONFIGURATION_DOWNMATRIX
322         config->downMatrix = 1;
323 #endif
324 #ifdef HAVE_FAACDECCONFIGURATION_DONTUPSAMPLEIMPLICITSBR
325         config->dontUpSampleImplicitSBR = 0;
326 #endif
327         faacDecSetConfiguration(decoder, config);
329         fillAacBuffer(&b);
331 #ifdef HAVE_FAAD_BUFLEN_FUNCS
332         bread = faacDecInit(decoder, b.buffer, b.bytesIntoBuffer,
333                             &sampleRate, &channels);
334 #else
335         bread = faacDecInit(decoder, b.buffer, &sampleRate, &channels);
336 #endif
337         if (bread < 0) {
338                 ERROR("Error not a AAC stream.\n");
339                 faacDecClose(decoder);
340                 closeInputStream(b.inStream);
341                 if (b.buffer)
342                         free(b.buffer);
343                 return -1;
344         }
346         dc->audioFormat.bits = 16;
348         dc->totalTime = totalTime;
350         time = 0.0;
352         advanceAacBuffer(&b, bread);
354         while (!eof) {
355                 fillAacBuffer(&b);
357                 if (b.bytesIntoBuffer == 0) {
358                         eof = 1;
359                         break;
360                 }
361 #ifdef HAVE_FAAD_BUFLEN_FUNCS
362                 sampleBuffer = faacDecDecode(decoder, &frameInfo, b.buffer,
363                                              b.bytesIntoBuffer);
364 #else
365                 sampleBuffer = faacDecDecode(decoder, &frameInfo, b.buffer);
366 #endif
368                 if (frameInfo.error > 0) {
369                         ERROR("error decoding AAC file: %s\n", path);
370                         ERROR("faad2 error: %s\n",
371                               faacDecGetErrorMessage(frameInfo.error));
372                         eof = 1;
373                         break;
374                 }
375 #ifdef HAVE_FAACDECFRAMEINFO_SAMPLERATE
376                 sampleRate = frameInfo.samplerate;
377 #endif
379                 if (dc->state != DECODE_STATE_DECODE) {
380                         dc->audioFormat.channels = frameInfo.channels;
381                         dc->audioFormat.sampleRate = sampleRate;
382                         getOutputAudioFormat(&(dc->audioFormat),
383                                              &(cb->audioFormat));
384                         dc->state = DECODE_STATE_DECODE;
385                 }
387                 advanceAacBuffer(&b, frameInfo.bytesconsumed);
389                 sampleCount = (unsigned long)(frameInfo.samples);
391                 if (sampleCount > 0) {
392                         bitRate = frameInfo.bytesconsumed * 8.0 *
393                             frameInfo.channels * sampleRate /
394                             frameInfo.samples / 1000 + 0.5;
395                         time +=
396                             (float)(frameInfo.samples) / frameInfo.channels /
397                             sampleRate;
398                 }
400                 sampleBufferLen = sampleCount * 2;
402                 sendDataToOutputBuffer(cb, NULL, dc, 0, sampleBuffer,
403                                        sampleBufferLen, time, bitRate, NULL);
404                 if (dc->seek) {
405                         dc->seekError = 1;
406                         dc->seek = 0;
407                 } else if (dc->stop) {
408                         eof = 1;
409                         break;
410                 }
411         }
413         flushOutputBuffer(cb);
415         faacDecClose(decoder);
416         closeInputStream(b.inStream);
417         if (b.buffer)
418                 free(b.buffer);
420         if (dc->state != DECODE_STATE_DECODE)
421                 return -1;
423         if (dc->seek) {
424                 dc->seekError = 1;
425                 dc->seek = 0;
426         }
428         if (dc->stop) {
429                 dc->state = DECODE_STATE_STOP;
430                 dc->stop = 0;
431         } else
432                 dc->state = DECODE_STATE_STOP;
434         return 0;
437 static MpdTag *aacTagDup(char *file)
439         MpdTag *ret = NULL;
440         int time;
442         time = getAacTotalTime(file);
444         if (time >= 0) {
445                 if ((ret = id3Dup(file)) == NULL)
446                         ret = newMpdTag();
447                 ret->time = time;
448         } else {
449                 DEBUG("aacTagDup: Failed to get total song time from: %s\n",
450                       file);
451         }
453         return ret;
456 static char *aac_suffixes[] = { "aac", NULL };
457 static char *aac_mimeTypes[] = { "audio/aac", "audio/aacp", NULL };
459 InputPlugin aacPlugin = {
460         "aac",
461         NULL,
462         NULL,
463         NULL,
464         NULL,
465         aac_decode,
466         aacTagDup,
467         INPUT_PLUGIN_STREAM_FILE,
468         aac_suffixes,
469         aac_mimeTypes
472 #else
474 InputPlugin aacPlugin;
476 #endif /* HAVE_FAAD */