Initial revision 6759
[qball-mpd.git] / src / inputPlugins / aac_plugin.c
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.
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"
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);
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;
69 b->bytesConsumed = 0;
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;
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;
118 if (frames == 0) {
119 sampleRate = adtsSampleRates[(b->
120 buffer[2] & 0x3c)
121 >> 2];
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;
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);
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
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;
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);
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;
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;
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;
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;
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;
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;
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;
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);
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 */