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
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.
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
19 #include "../inputPlugin.h"
23 #define AAC_MAX_CHANNELS 6
28 #include "../inputStream.h"
29 #include "../outputBuffer.h"
37 /* all code here is either based on or copied from FAAD2's frontend code */
39 InputStream
*inStream
;
43 unsigned char *buffer
;
47 static void fillAacBuffer(AacBuffer
* b
)
49 if (b
->bytesConsumed
> 0) {
52 if (b
->bytesIntoBuffer
) {
53 memmove((void *)b
->buffer
, (void *)(b
->buffer
+
59 bread
= readFromInputStream(b
->inStream
,
64 if (bread
!= b
->bytesConsumed
)
66 b
->bytesIntoBuffer
+= bread
;
71 if (b
->bytesIntoBuffer
> 3) {
72 if (memcmp(b
->buffer
, "TAG", 3) == 0)
73 b
->bytesIntoBuffer
= 0;
75 if (b
->bytesIntoBuffer
> 11) {
76 if (memcmp(b
->buffer
, "LYRICSBEGIN", 11) == 0) {
77 b
->bytesIntoBuffer
= 0;
80 if (b
->bytesIntoBuffer
> 8) {
81 if (memcmp(b
->buffer
, "APETAGEX", 8) == 0) {
82 b
->bytesIntoBuffer
= 0;
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;
105 float framesPerSec
, bytesPerFrame
;
107 /* Read all frames to ensure correct time and bitrate */
108 for (frames
= 0;; frames
++) {
111 if (b
->bytesIntoBuffer
> 7) {
113 if (!((b
->buffer
[0] == 0xFF) &&
114 ((b
->buffer
[1] & 0xF6) == 0xF0))) {
119 sampleRate
= adtsSampleRates
[(b
->
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
)
133 advanceAacBuffer(b
, frameLength
);
138 framesPerSec
= (float)sampleRate
/ 1024.0;
140 bytesPerFrame
= (float)tFrameLength
/ (float)(frames
* 1000);
143 if (framesPerSec
!= 0)
144 *length
= (float)frames
/ framesPerSec
;
149 static void initAacBuffer(InputStream
* inStream
, AacBuffer
* b
, float *length
,
150 size_t * retFileread
, size_t * retTagsize
)
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;
174 if (bread
!= FAAD_MIN_STREAMSIZE
* AAC_MAX_CHANNELS
)
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);
183 advanceAacBuffer(b
, tagsize
);
188 *retFileread
= fileread
;
190 *retTagsize
= tagsize
;
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
*
202 if (bread
!= FAAD_MIN_STREAMSIZE
* AAC_MAX_CHANNELS
)
206 b
->bytesIntoBuffer
= bread
;
207 b
->bytesConsumed
= 0;
208 b
->fileOffset
= tagsize
;
209 } else if (memcmp(b
->buffer
, "ADIF", 4) == 0) {
211 int skipSize
= (b
->buffer
[4] & 0x80) ? 9 : 0;
215 skipSize
] & 0x0F) << 19) | ((unsigned
222 buffer
[6 + skipSize
] << 3) | ((unsigned int)b
->buffer
[7 +
226 if (fileread
!= 0 && bitRate
!= 0)
227 *length
= fileread
* 8.0 / bitRate
;
233 static float getAacFloatTotalTime(char *file
)
237 size_t fileread
, tagsize
;
238 faacDecHandle decoder
;
239 faacDecConfigurationPtr config
;
240 unsigned long sampleRate
;
241 unsigned char channels
;
242 InputStream inStream
;
245 if (openInputStream(&inStream
, file
) < 0)
248 initAacBuffer(&inStream
, &b
, &length
, &fileread
, &tagsize
);
251 decoder
= faacDecOpen();
253 config
= faacDecGetCurrentConfiguration(decoder
);
254 config
->outputFormat
= FAAD_FMT_16BIT
;
255 faacDecSetConfiguration(decoder
, config
);
258 #ifdef HAVE_FAAD_BUFLEN_FUNCS
259 bread
= faacDecInit(decoder
, b
.buffer
, b
.bytesIntoBuffer
,
260 &sampleRate
, &channels
);
262 bread
= faacDecInit(decoder
, b
.buffer
, &sampleRate
, &channels
);
264 if (bread
>= 0 && sampleRate
> 0 && channels
> 0)
267 faacDecClose(decoder
);
272 closeInputStream(&inStream
);
277 static int getAacTotalTime(char *file
)
282 if ((length
= getAacFloatTotalTime(file
)) >= 0)
288 static int aac_decode(OutputBuffer
* cb
, DecoderControl
* dc
, char *path
)
292 faacDecHandle decoder
;
293 faacDecFrameInfo frameInfo
;
294 faacDecConfigurationPtr config
;
296 unsigned long sampleRate
;
297 unsigned char channels
;
299 unsigned int sampleCount
;
301 size_t sampleBufferLen
;
303 long seekTableEnd = -1;
304 int seekPositionFound = 0; */
305 mpd_uint16 bitRate
= 0;
307 InputStream inStream
;
309 if ((totalTime
= getAacFloatTotalTime(path
)) < 0)
312 if (openInputStream(&inStream
, path
) < 0)
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;
324 #ifdef HAVE_FAACDECCONFIGURATION_DONTUPSAMPLEIMPLICITSBR
325 config
->dontUpSampleImplicitSBR
= 0;
327 faacDecSetConfiguration(decoder
, config
);
331 #ifdef HAVE_FAAD_BUFLEN_FUNCS
332 bread
= faacDecInit(decoder
, b
.buffer
, b
.bytesIntoBuffer
,
333 &sampleRate
, &channels
);
335 bread
= faacDecInit(decoder
, b
.buffer
, &sampleRate
, &channels
);
338 ERROR("Error not a AAC stream.\n");
339 faacDecClose(decoder
);
340 closeInputStream(b
.inStream
);
346 dc
->audioFormat
.bits
= 16;
348 dc
->totalTime
= totalTime
;
352 advanceAacBuffer(&b
, bread
);
357 if (b
.bytesIntoBuffer
== 0) {
361 #ifdef HAVE_FAAD_BUFLEN_FUNCS
362 sampleBuffer
= faacDecDecode(decoder
, &frameInfo
, b
.buffer
,
365 sampleBuffer
= faacDecDecode(decoder
, &frameInfo
, b
.buffer
);
368 if (frameInfo
.error
> 0) {
369 ERROR("error decoding AAC file: %s\n", path
);
370 ERROR("faad2 error: %s\n",
371 faacDecGetErrorMessage(frameInfo
.error
));
375 #ifdef HAVE_FAACDECFRAMEINFO_SAMPLERATE
376 sampleRate
= frameInfo
.samplerate
;
379 if (dc
->state
!= DECODE_STATE_DECODE
) {
380 dc
->audioFormat
.channels
= frameInfo
.channels
;
381 dc
->audioFormat
.sampleRate
= sampleRate
;
382 getOutputAudioFormat(&(dc
->audioFormat
),
384 dc
->state
= DECODE_STATE_DECODE
;
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;
396 (float)(frameInfo
.samples
) / frameInfo
.channels
/
400 sampleBufferLen
= sampleCount
* 2;
402 sendDataToOutputBuffer(cb
, NULL
, dc
, 0, sampleBuffer
,
403 sampleBufferLen
, time
, bitRate
, NULL
);
407 } else if (dc
->stop
) {
413 flushOutputBuffer(cb
);
415 faacDecClose(decoder
);
416 closeInputStream(b
.inStream
);
420 if (dc
->state
!= DECODE_STATE_DECODE
)
429 dc
->state
= DECODE_STATE_STOP
;
432 dc
->state
= DECODE_STATE_STOP
;
437 static MpdTag
*aacTagDup(char *file
)
442 time
= getAacTotalTime(file
);
445 if ((ret
= id3Dup(file
)) == NULL
)
449 DEBUG("aacTagDup: Failed to get total song time from: %s\n",
456 static char *aac_suffixes
[] = { "aac", NULL
};
457 static char *aac_mimeTypes
[] = { "audio/aac", "audio/aacp", NULL
};
459 InputPlugin aacPlugin
= {
467 INPUT_PLUGIN_STREAM_FILE
,
474 InputPlugin aacPlugin
;
476 #endif /* HAVE_FAAD */