diff options
-rw-r--r-- | apps/filetypes.c | 1 | ||||
-rw-r--r-- | lib/rbcodec/SOURCES | 1 | ||||
-rw-r--r-- | lib/rbcodec/codecs/SOURCES | 1 | ||||
-rw-r--r-- | lib/rbcodec/codecs/aac_bsf.c | 157 | ||||
-rw-r--r-- | lib/rbcodec/codecs/codecs.make | 1 | ||||
-rw-r--r-- | lib/rbcodec/metadata/aac.c | 122 | ||||
-rw-r--r-- | lib/rbcodec/metadata/metadata.c | 3 | ||||
-rw-r--r-- | lib/rbcodec/metadata/metadata.h | 1 | ||||
-rw-r--r-- | lib/rbcodec/metadata/metadata_parsers.h | 1 |
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 | |||
63 | metadata/vox.c | 63 | metadata/vox.c |
64 | metadata/wave.c | 64 | metadata/wave.c |
65 | metadata/wavpack.c | 65 | metadata/wavpack.c |
66 | metadata/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 |
43 | kss.c | 43 | kss.c |
44 | #endif | 44 | #endif |
45 | aac_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 | |||
29 | CODEC_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 | |||
36 | static 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 */ | ||
42 | enum 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 */ | ||
54 | enum 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(¶m); | ||
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 | |||
34 | static 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 | |||
42 | static bool check_adts_syncword(int fd) | ||
43 | { | ||
44 | uint16_t syncword; | ||
45 | |||
46 | read_uint16be(fd, &syncword); | ||
47 | return (syncword & 0xFFF6) == 0xFFF0; | ||
48 | } | ||
49 | |||
50 | bool 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); | |||
56 | bool get_sgc_metadata(int fd, struct mp3entry* id3); | 56 | bool get_sgc_metadata(int fd, struct mp3entry* id3); |
57 | bool get_vgm_metadata(int fd, struct mp3entry* id3); | 57 | bool get_vgm_metadata(int fd, struct mp3entry* id3); |
58 | bool get_kss_metadata(int fd, struct mp3entry* id3); | 58 | bool get_kss_metadata(int fd, struct mp3entry* id3); |
59 | bool get_aac_metadata(int fd, struct mp3entry* id3); | ||
59 | #endif /* CONFIG_CODEC == SWCODEC */ | 60 | #endif /* CONFIG_CODEC == SWCODEC */ |