summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/filetypes.c1
-rw-r--r--lib/rbcodec/SOURCES1
-rw-r--r--lib/rbcodec/codecs/SOURCES1
-rw-r--r--lib/rbcodec/codecs/aac_bsf.c157
-rw-r--r--lib/rbcodec/codecs/codecs.make1
-rw-r--r--lib/rbcodec/metadata/aac.c122
-rw-r--r--lib/rbcodec/metadata/metadata.c3
-rw-r--r--lib/rbcodec/metadata/metadata.h1
-rw-r--r--lib/rbcodec/metadata/metadata_parsers.h1
9 files changed, 288 insertions, 0 deletions
diff --git a/apps/filetypes.c b/apps/filetypes.c
index f1a6c389ba..16a00a423f 100644
--- a/apps/filetypes.c
+++ b/apps/filetypes.c
@@ -120,6 +120,7 @@ static const struct filetype inbuilt_filetypes[] = {
120 { "vgm", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, 120 { "vgm", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
121 { "vgz", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, 121 { "vgz", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
122 { "kss", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, 122 { "kss", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
123 { "aac", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
123#endif 124#endif
124 { "m3u", FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST }, 125 { "m3u", FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST },
125 { "m3u8",FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST }, 126 { "m3u8",FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST },
diff --git a/lib/rbcodec/SOURCES b/lib/rbcodec/SOURCES
index c2a32e9c28..9180237632 100644
--- a/lib/rbcodec/SOURCES
+++ b/lib/rbcodec/SOURCES
@@ -63,4 +63,5 @@ metadata/vorbis.c
63metadata/vox.c 63metadata/vox.c
64metadata/wave.c 64metadata/wave.c
65metadata/wavpack.c 65metadata/wavpack.c
66metadata/aac.c
66#endif 67#endif
diff --git a/lib/rbcodec/codecs/SOURCES b/lib/rbcodec/codecs/SOURCES
index 039772cf9a..f0787d267d 100644
--- a/lib/rbcodec/codecs/SOURCES
+++ b/lib/rbcodec/codecs/SOURCES
@@ -42,6 +42,7 @@ vgm.c
42#if MEMORYSIZE > 2 42#if MEMORYSIZE > 2
43kss.c 43kss.c
44#endif 44#endif
45aac_bsf.c
45 46
46#ifdef HAVE_RECORDING 47#ifdef HAVE_RECORDING
47 48
diff --git a/lib/rbcodec/codecs/aac_bsf.c b/lib/rbcodec/codecs/aac_bsf.c
new file mode 100644
index 0000000000..3bce283958
--- /dev/null
+++ b/lib/rbcodec/codecs/aac_bsf.c
@@ -0,0 +1,157 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Codec for aac files without container
11 *
12 * Written by Igor B. Poretsky
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24#include "codeclib.h"
25#include "libfaad/common.h"
26#include "libfaad/structs.h"
27#include "libfaad/decoder.h"
28
29CODEC_HEADER
30
31/* The maximum buffer size handled by faad. 12 bytes are required by libfaad
32 * as headroom (see libfaad/bits.c). FAAD_BYTE_BUFFER_SIZE bytes are buffered
33 * for each frame. */
34#define FAAD_BYTE_BUFFER_SIZE (2048-12)
35
36static void update_playing_time(void)
37{
38 ci->set_elapsed((unsigned long)((ci->id3->offset - ci->id3->first_frame_offset) * 8LL / ci->id3->bitrate));
39}
40
41/* this is the codec entry point */
42enum codec_status codec_main(enum codec_entry_call_reason reason)
43{
44 if (reason == CODEC_LOAD) {
45 /* Generic codec initialisation */
46 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
47 ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
48 }
49
50 return CODEC_OK;
51}
52
53/* this is called for each file to process */
54enum codec_status codec_run(void)
55{
56 size_t n;
57 int32_t bread;
58 unsigned int frame_samples;
59 uint32_t s = 0;
60 unsigned char c = 0;
61 long action = CODEC_ACTION_NULL;
62 intptr_t param;
63 unsigned char* buffer;
64 NeAACDecFrameInfo frame_info;
65 NeAACDecHandle decoder;
66 NeAACDecConfigurationPtr conf;
67
68 /* Clean and initialize decoder structures */
69 if (codec_init()) {
70 LOGF("FAAD: Codec init error\n");
71 return CODEC_ERROR;
72 }
73
74 ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency);
75 codec_set_replaygain(ci->id3);
76
77 ci->seek_buffer(ci->id3->first_frame_offset);
78
79 /* initialise the sound converter */
80 decoder = NeAACDecOpen();
81
82 if (!decoder) {
83 LOGF("FAAD: Decode open error\n");
84 return CODEC_ERROR;
85 }
86
87 conf = NeAACDecGetCurrentConfiguration(decoder);
88 conf->outputFormat = FAAD_FMT_24BIT; /* irrelevant, we don't convert */
89 NeAACDecSetConfiguration(decoder, conf);
90
91 buffer=ci->request_buffer(&n, FAAD_BYTE_BUFFER_SIZE);
92 bread = NeAACDecInit(decoder, buffer, n, &s, &c);
93 if (bread < 0) {
94 LOGF("FAAD: DecInit: %ld, %d\n", bread, decoder->object_type);
95 return CODEC_ERROR;
96 }
97 ci->advance_buffer(bread);
98
99 if (ci->id3->offset > ci->id3->first_frame_offset) {
100 /* Resume the desired (byte) position. */
101 ci->seek_buffer(ci->id3->offset);
102 NeAACDecPostSeekReset(decoder, 0);
103 update_playing_time();
104 } else if (ci->id3->elapsed) {
105 action = CODEC_ACTION_SEEK_TIME;
106 param = ci->id3->elapsed;
107 } else {
108 ci->set_elapsed(0);
109 ci->set_offset(ci->id3->first_frame_offset);
110 }
111
112 /* The main decoding loop */
113 while (1) {
114 if (action == CODEC_ACTION_NULL)
115 action = ci->get_command(&param);
116
117 if (action == CODEC_ACTION_HALT)
118 break;
119
120 /* Deal with any pending seek requests */
121 if (action == CODEC_ACTION_SEEK_TIME) {
122 /* Seek to the desired time position. */
123 ci->seek_buffer(ci->id3->first_frame_offset + (uint32_t)((uint64_t)param * ci->id3->bitrate / 8));
124 ci->set_elapsed((unsigned long)param);
125 NeAACDecPostSeekReset(decoder, 0);
126 ci->seek_complete();
127 }
128
129 action = CODEC_ACTION_NULL;
130
131 /* Request the required number of bytes from the input buffer */
132 buffer=ci->request_buffer(&n, FAAD_BYTE_BUFFER_SIZE);
133
134 if (n == 0) /* End of Stream */
135 break;
136
137 /* Decode one block - returned samples will be host-endian */
138 if (NeAACDecDecode(decoder, &frame_info, buffer, n) == NULL || frame_info.error > 0) {
139 LOGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error));
140 return CODEC_ERROR;
141 }
142
143 /* Advance codec buffer (no need to call set_offset because of this) */
144 ci->advance_buffer(frame_info.bytesconsumed);
145
146 /* Output the audio */
147 ci->yield();
148 frame_samples = frame_info.samples >> 1;
149 ci->pcmbuf_insert(&decoder->time_out[0][0], &decoder->time_out[1][0], frame_samples);
150
151 /* Update the elapsed-time indicator */
152 update_playing_time();
153 }
154
155 LOGF("AAC: Decoding complete\n");
156 return CODEC_OK;
157}
diff --git a/lib/rbcodec/codecs/codecs.make b/lib/rbcodec/codecs/codecs.make
index 8934272fcf..afb8396938 100644
--- a/lib/rbcodec/codecs/codecs.make
+++ b/lib/rbcodec/codecs/codecs.make
@@ -181,6 +181,7 @@ $(CODECDIR)/sgc.codec : $(CODECDIR)/libsgc.a $(CODECDIR)/libemu2413.a
181$(CODECDIR)/vgm.codec : $(CODECDIR)/libvgm.a $(CODECDIR)/libemu2413.a 181$(CODECDIR)/vgm.codec : $(CODECDIR)/libvgm.a $(CODECDIR)/libemu2413.a
182$(CODECDIR)/kss.codec : $(CODECDIR)/libkss.a $(CODECDIR)/libemu2413.a 182$(CODECDIR)/kss.codec : $(CODECDIR)/libkss.a $(CODECDIR)/libemu2413.a
183$(CODECDIR)/opus.codec : $(CODECDIR)/libopus.a $(TLSFLIB) 183$(CODECDIR)/opus.codec : $(CODECDIR)/libopus.a $(TLSFLIB)
184$(CODECDIR)/aac_bsf.codec : $(CODECDIR)/libfaad.a
184 185
185$(CODECS): $(CODEC_LIBS) # this must be last in codec dependency list 186$(CODECS): $(CODEC_LIBS) # this must be last in codec dependency list
186 187
diff --git a/lib/rbcodec/metadata/aac.c b/lib/rbcodec/metadata/aac.c
new file mode 100644
index 0000000000..82adeacbde
--- /dev/null
+++ b/lib/rbcodec/metadata/aac.c
@@ -0,0 +1,122 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Parsing ADTS and ADIF headers
11 *
12 * Written by Igor B. Poretsky
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24#include <stdlib.h>
25#include <stdbool.h>
26#include <string.h>
27
28#include "platform.h"
29
30#include "metadata.h"
31#include "metadata_common.h"
32#include "metadata_parsers.h"
33
34static const int sample_rates[] =
35{
36 96000, 88200, 64000, 48000,
37 44100, 32000, 24000, 22050,
38 16000, 12000, 11025, 8000,
39 7350, 0, 0, 0
40};
41
42static bool check_adts_syncword(int fd)
43{
44 uint16_t syncword;
45
46 read_uint16be(fd, &syncword);
47 return (syncword & 0xFFF6) == 0xFFF0;
48}
49
50bool get_aac_metadata(int fd, struct mp3entry *entry)
51{
52 unsigned char buf[5];
53
54 entry->title = NULL;
55 entry->tracknum = 0;
56 entry->discnum = 0;
57 entry->id3v1len = 0;
58 entry->id3v2len = getid3v2len(fd);
59 entry->first_frame_offset = entry->id3v2len;
60 entry->filesize = filesize(fd) - entry->first_frame_offset;
61 entry->needs_upsampling_correction = false;
62
63 if (entry->id3v2len)
64 setid3v2title(fd, entry);
65
66 if (-1 == lseek(fd, entry->first_frame_offset, SEEK_SET))
67 return false;
68
69 if (check_adts_syncword(fd))
70 {
71 int frames;
72 int stat_length;
73 uint64_t total;
74 if (read(fd, buf, 5) != 5)
75 return false;
76 entry->frequency = sample_rates[(buf[0] >> 2) & 0x0F];
77 entry->vbr = ((buf[3] & 0x1F) == 0x1F)
78 && ((buf[4] & 0xFC) == 0xFC);
79 stat_length = entry->frequency >> ((entry->vbr) ? 5 : 7);
80 for (frames = 1, total = 0; frames < stat_length; frames++)
81 {
82 unsigned int frame_length = (((unsigned int)buf[1] & 0x3) << 11)
83 | ((unsigned int)buf[2] << 3)
84 | ((unsigned int)buf[3] >> 5);
85 total += frame_length;
86 if (frame_length < 7)
87 break;
88 if (-1 == lseek(fd, frame_length - 7, SEEK_CUR))
89 break;
90 if (!check_adts_syncword(fd))
91 break;
92 if (read(fd, buf, 5) != 5)
93 break;
94 }
95 entry->bitrate = (unsigned int)((total * entry->frequency / frames + 64000) / 128000);
96 if (entry->frequency <= 24000)
97 {
98 entry->frequency <<= 1;
99 entry->needs_upsampling_correction = true;
100 }
101 }
102 else
103 {
104 uint32_t bitrate;
105 if (-1 == lseek(fd, entry->first_frame_offset, SEEK_SET))
106 return false;
107 if (read(fd, buf, 5) != 5)
108 return false;
109 if (memcmp(buf, "ADIF", 4))
110 return false;
111 if (-1 == lseek(fd, (buf[4] & 0x80) ? (entry->first_frame_offset + 9) : entry->first_frame_offset, SEEK_SET))
112 return false;
113 read_uint32be(fd, &bitrate);
114 entry->vbr = (bitrate & 0x10000000) != 0;
115 entry->bitrate = ((bitrate & 0xFFFFFE0) + 16000) / 32000;
116 read_uint32be(fd, (uint32_t*)(&(entry->frequency)));
117 entry->frequency = sample_rates[(entry->frequency >> (entry->vbr ? 23 : 3)) & 0x0F];
118 }
119 entry->length = (unsigned long)((entry->filesize * 8LL + (entry->bitrate >> 1)) / entry->bitrate);
120
121 return true;
122}
diff --git a/lib/rbcodec/metadata/metadata.c b/lib/rbcodec/metadata/metadata.c
index 7ca4b1afd2..c24a27df2b 100644
--- a/lib/rbcodec/metadata/metadata.c
+++ b/lib/rbcodec/metadata/metadata.c
@@ -235,6 +235,9 @@ const struct afmt_entry audio_formats[AFMT_NUM_CODECS] =
235 /* Opus */ 235 /* Opus */
236 [AFMT_OPUS] = 236 [AFMT_OPUS] =
237 AFMT_ENTRY("Opus", "opus", NULL, get_ogg_metadata, "opus\0"), 237 AFMT_ENTRY("Opus", "opus", NULL, get_ogg_metadata, "opus\0"),
238 /* AAC bitstream format */
239 [AFMT_AAC_BSF] =
240 AFMT_ENTRY("AAC", "aac_bsf", NULL, get_aac_metadata, "aac\0"),
238#endif 241#endif
239}; 242};
240 243
diff --git a/lib/rbcodec/metadata/metadata.h b/lib/rbcodec/metadata/metadata.h
index 18cfce7523..a7ebcf16e5 100644
--- a/lib/rbcodec/metadata/metadata.h
+++ b/lib/rbcodec/metadata/metadata.h
@@ -90,6 +90,7 @@ enum
90 AFMT_VGM, /* VGM (Video Game Music Format) */ 90 AFMT_VGM, /* VGM (Video Game Music Format) */
91 AFMT_KSS, /* KSS (MSX computer KSS Music File) */ 91 AFMT_KSS, /* KSS (MSX computer KSS Music File) */
92 AFMT_OPUS, /* Opus (see http://www.opus-codec.org ) */ 92 AFMT_OPUS, /* Opus (see http://www.opus-codec.org ) */
93 AFMT_AAC_BSF,
93#endif 94#endif
94 95
95 /* add new formats at any index above this line to have a sensible order - 96 /* add new formats at any index above this line to have a sensible order -
diff --git a/lib/rbcodec/metadata/metadata_parsers.h b/lib/rbcodec/metadata/metadata_parsers.h
index 304e393538..9f03c79bb5 100644
--- a/lib/rbcodec/metadata/metadata_parsers.h
+++ b/lib/rbcodec/metadata/metadata_parsers.h
@@ -56,4 +56,5 @@ bool get_hes_metadata(int fd, struct mp3entry* id3);
56bool get_sgc_metadata(int fd, struct mp3entry* id3); 56bool get_sgc_metadata(int fd, struct mp3entry* id3);
57bool get_vgm_metadata(int fd, struct mp3entry* id3); 57bool get_vgm_metadata(int fd, struct mp3entry* id3);
58bool get_kss_metadata(int fd, struct mp3entry* id3); 58bool get_kss_metadata(int fd, struct mp3entry* id3);
59bool get_aac_metadata(int fd, struct mp3entry* id3);
59#endif /* CONFIG_CODEC == SWCODEC */ 60#endif /* CONFIG_CODEC == SWCODEC */