diff options
author | Sean Bartell <wingedtachikoma@gmail.com> | 2011-06-25 21:32:25 -0400 |
---|---|---|
committer | Nils Wallménius <nils@rockbox.org> | 2012-04-25 22:13:20 +0200 |
commit | f40bfc9267b13b54e6379dfe7539447662879d24 (patch) | |
tree | 9b20069d5e62809ff434061ad730096836f916f2 /lib/rbcodec/codecs/aac.c | |
parent | a0009907de7a0107d49040d8a180f140e2eff299 (diff) | |
download | rockbox-f40bfc9267b13b54e6379dfe7539447662879d24.tar.gz rockbox-f40bfc9267b13b54e6379dfe7539447662879d24.zip |
Add codecs to librbcodec.
Change-Id: Id7f4717d51ed02d67cb9f9cb3c0ada4a81843f97
Reviewed-on: http://gerrit.rockbox.org/137
Reviewed-by: Nils Wallménius <nils@rockbox.org>
Tested-by: Nils Wallménius <nils@rockbox.org>
Diffstat (limited to 'lib/rbcodec/codecs/aac.c')
-rw-r--r-- | lib/rbcodec/codecs/aac.c | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/aac.c b/lib/rbcodec/codecs/aac.c new file mode 100644 index 0000000000..365dca804d --- /dev/null +++ b/lib/rbcodec/codecs/aac.c | |||
@@ -0,0 +1,297 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2005 Dave Chapman | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "codeclib.h" | ||
23 | #include "libm4a/m4a.h" | ||
24 | #include "libfaad/common.h" | ||
25 | #include "libfaad/structs.h" | ||
26 | #include "libfaad/decoder.h" | ||
27 | |||
28 | CODEC_HEADER | ||
29 | |||
30 | /* The maximum buffer size handled by faad. 12 bytes are required by libfaad | ||
31 | * as headroom (see libfaad/bits.c). FAAD_BYTE_BUFFER_SIZE bytes are buffered | ||
32 | * for each frame. */ | ||
33 | #define FAAD_BYTE_BUFFER_SIZE (2048-12) | ||
34 | |||
35 | /* this is the codec entry point */ | ||
36 | enum codec_status codec_main(enum codec_entry_call_reason reason) | ||
37 | { | ||
38 | if (reason == CODEC_LOAD) { | ||
39 | /* Generic codec initialisation */ | ||
40 | ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); | ||
41 | ci->configure(DSP_SET_SAMPLE_DEPTH, 29); | ||
42 | } | ||
43 | |||
44 | return CODEC_OK; | ||
45 | } | ||
46 | |||
47 | /* this is called for each file to process */ | ||
48 | enum codec_status codec_run(void) | ||
49 | { | ||
50 | /* Note that when dealing with QuickTime/MPEG4 files, terminology is | ||
51 | * a bit confusing. Files with sound are split up in chunks, where | ||
52 | * each chunk contains one or more samples. Each sample in turn | ||
53 | * contains a number of "sound samples" (the kind you refer to with | ||
54 | * the sampling frequency). | ||
55 | */ | ||
56 | size_t n; | ||
57 | demux_res_t demux_res; | ||
58 | stream_t input_stream; | ||
59 | uint32_t sound_samples_done; | ||
60 | uint32_t elapsed_time; | ||
61 | int file_offset; | ||
62 | int framelength; | ||
63 | int lead_trim = 0; | ||
64 | unsigned int frame_samples; | ||
65 | unsigned int i; | ||
66 | unsigned char* buffer; | ||
67 | NeAACDecFrameInfo frame_info; | ||
68 | NeAACDecHandle decoder; | ||
69 | int err; | ||
70 | uint32_t seek_idx = 0; | ||
71 | uint32_t s = 0; | ||
72 | uint32_t sbr_fac = 1; | ||
73 | unsigned char c = 0; | ||
74 | void *ret; | ||
75 | intptr_t param; | ||
76 | bool empty_first_frame = false; | ||
77 | |||
78 | /* Clean and initialize decoder structures */ | ||
79 | memset(&demux_res , 0, sizeof(demux_res)); | ||
80 | if (codec_init()) { | ||
81 | LOGF("FAAD: Codec init error\n"); | ||
82 | return CODEC_ERROR; | ||
83 | } | ||
84 | |||
85 | file_offset = ci->id3->offset; | ||
86 | |||
87 | ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); | ||
88 | codec_set_replaygain(ci->id3); | ||
89 | |||
90 | stream_create(&input_stream,ci); | ||
91 | |||
92 | ci->seek_buffer(ci->id3->first_frame_offset); | ||
93 | |||
94 | /* if qtmovie_read returns successfully, the stream is up to | ||
95 | * the movie data, which can be used directly by the decoder */ | ||
96 | if (!qtmovie_read(&input_stream, &demux_res)) { | ||
97 | LOGF("FAAD: File init error\n"); | ||
98 | return CODEC_ERROR; | ||
99 | } | ||
100 | |||
101 | /* initialise the sound converter */ | ||
102 | decoder = NeAACDecOpen(); | ||
103 | |||
104 | if (!decoder) { | ||
105 | LOGF("FAAD: Decode open error\n"); | ||
106 | return CODEC_ERROR; | ||
107 | } | ||
108 | |||
109 | NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder); | ||
110 | conf->outputFormat = FAAD_FMT_24BIT; /* irrelevant, we don't convert */ | ||
111 | NeAACDecSetConfiguration(decoder, conf); | ||
112 | |||
113 | err = NeAACDecInit2(decoder, demux_res.codecdata, demux_res.codecdata_len, &s, &c); | ||
114 | if (err) { | ||
115 | LOGF("FAAD: DecInit: %d, %d\n", err, decoder->object_type); | ||
116 | return CODEC_ERROR; | ||
117 | } | ||
118 | |||
119 | #ifdef SBR_DEC | ||
120 | /* Check for need of special handling for seek/resume and elapsed time. */ | ||
121 | if (ci->id3->needs_upsampling_correction) { | ||
122 | sbr_fac = 2; | ||
123 | } else { | ||
124 | sbr_fac = 1; | ||
125 | } | ||
126 | #endif | ||
127 | |||
128 | i = 0; | ||
129 | |||
130 | if (file_offset > 0) { | ||
131 | /* Resume the desired (byte) position. Important: When resuming SBR | ||
132 | * upsampling files the resulting sound_samples_done must be expanded | ||
133 | * by a factor of 2. This is done via using sbr_fac. */ | ||
134 | if (m4a_seek_raw(&demux_res, &input_stream, file_offset, | ||
135 | &sound_samples_done, (int*) &i)) { | ||
136 | sound_samples_done *= sbr_fac; | ||
137 | } else { | ||
138 | sound_samples_done = 0; | ||
139 | } | ||
140 | NeAACDecPostSeekReset(decoder, i); | ||
141 | } else { | ||
142 | sound_samples_done = 0; | ||
143 | } | ||
144 | |||
145 | elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); | ||
146 | ci->set_elapsed(elapsed_time); | ||
147 | |||
148 | if (i == 0) | ||
149 | { | ||
150 | lead_trim = ci->id3->lead_trim; | ||
151 | } | ||
152 | |||
153 | /* The main decoding loop */ | ||
154 | while (i < demux_res.num_sample_byte_sizes) { | ||
155 | enum codec_command_action action = ci->get_command(¶m); | ||
156 | |||
157 | if (action == CODEC_ACTION_HALT) | ||
158 | break; | ||
159 | |||
160 | /* Deal with any pending seek requests */ | ||
161 | if (action == CODEC_ACTION_SEEK_TIME) { | ||
162 | /* Seek to the desired time position. Important: When seeking in SBR | ||
163 | * upsampling files the seek_time must be divided by 2 when calling | ||
164 | * m4a_seek and the resulting sound_samples_done must be expanded | ||
165 | * by a factor 2. This is done via using sbr_fac. */ | ||
166 | if (m4a_seek(&demux_res, &input_stream, | ||
167 | (param/10/sbr_fac)*(ci->id3->frequency/100), | ||
168 | &sound_samples_done, (int*) &i)) { | ||
169 | sound_samples_done *= sbr_fac; | ||
170 | elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); | ||
171 | ci->set_elapsed(elapsed_time); | ||
172 | seek_idx = 0; | ||
173 | |||
174 | if (i == 0) | ||
175 | { | ||
176 | lead_trim = ci->id3->lead_trim; | ||
177 | } | ||
178 | } | ||
179 | NeAACDecPostSeekReset(decoder, i); | ||
180 | ci->seek_complete(); | ||
181 | } | ||
182 | |||
183 | /* There can be gaps between chunks, so skip ahead if needed. It | ||
184 | * doesn't seem to happen much, but it probably means that a | ||
185 | * "proper" file can have chunks out of order. Why one would want | ||
186 | * that an good question (but files with gaps do exist, so who | ||
187 | * knows?), so we don't support that - for now, at least. | ||
188 | */ | ||
189 | file_offset = m4a_check_sample_offset(&demux_res, i, &seek_idx); | ||
190 | |||
191 | if (file_offset > ci->curpos) | ||
192 | { | ||
193 | ci->advance_buffer(file_offset - ci->curpos); | ||
194 | } | ||
195 | else if (file_offset == 0) | ||
196 | { | ||
197 | LOGF("AAC: get_sample_offset error\n"); | ||
198 | return CODEC_ERROR; | ||
199 | } | ||
200 | |||
201 | /* Request the required number of bytes from the input buffer */ | ||
202 | buffer=ci->request_buffer(&n, FAAD_BYTE_BUFFER_SIZE); | ||
203 | |||
204 | /* Decode one block - returned samples will be host-endian */ | ||
205 | ret = NeAACDecDecode(decoder, &frame_info, buffer, n); | ||
206 | |||
207 | /* NeAACDecDecode may sometimes return NULL without setting error. */ | ||
208 | if (ret == NULL || frame_info.error > 0) { | ||
209 | LOGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error)); | ||
210 | return CODEC_ERROR; | ||
211 | } | ||
212 | |||
213 | /* Advance codec buffer (no need to call set_offset because of this) */ | ||
214 | ci->advance_buffer(frame_info.bytesconsumed); | ||
215 | |||
216 | /* Output the audio */ | ||
217 | ci->yield(); | ||
218 | |||
219 | frame_samples = frame_info.samples >> 1; | ||
220 | |||
221 | if (empty_first_frame) | ||
222 | { | ||
223 | /* Remove the first frame from lead_trim, under the assumption | ||
224 | * that it had the same size as this frame | ||
225 | */ | ||
226 | empty_first_frame = false; | ||
227 | lead_trim -= frame_samples; | ||
228 | |||
229 | if (lead_trim < 0) | ||
230 | { | ||
231 | lead_trim = 0; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | /* Gather number of samples for the decoded frame. */ | ||
236 | framelength = frame_samples - lead_trim; | ||
237 | |||
238 | if (i == demux_res.num_sample_byte_sizes - 1) | ||
239 | { | ||
240 | // Size of the last frame | ||
241 | const uint32_t sample_duration = (demux_res.num_time_to_samples > 0) ? | ||
242 | demux_res.time_to_sample[demux_res.num_time_to_samples - 1].sample_duration : | ||
243 | frame_samples; | ||
244 | |||
245 | /* Currently limited to at most one frame of tail_trim. | ||
246 | * Seems to be enough. | ||
247 | */ | ||
248 | if (ci->id3->tail_trim == 0 && sample_duration < frame_samples) | ||
249 | { | ||
250 | /* Subtract lead_trim just in case we decode a file with only | ||
251 | * one audio frame with actual data (lead_trim is usually zero | ||
252 | * here). | ||
253 | */ | ||
254 | framelength = sample_duration - lead_trim; | ||
255 | } | ||
256 | else | ||
257 | { | ||
258 | framelength -= ci->id3->tail_trim; | ||
259 | } | ||
260 | } | ||
261 | |||
262 | if (framelength > 0) | ||
263 | { | ||
264 | ci->pcmbuf_insert(&decoder->time_out[0][lead_trim], | ||
265 | &decoder->time_out[1][lead_trim], | ||
266 | framelength); | ||
267 | sound_samples_done += framelength; | ||
268 | /* Update the elapsed-time indicator */ | ||
269 | elapsed_time = ((uint64_t) sound_samples_done * 1000) / | ||
270 | ci->id3->frequency; | ||
271 | ci->set_elapsed(elapsed_time); | ||
272 | } | ||
273 | |||
274 | if (lead_trim > 0) | ||
275 | { | ||
276 | /* frame_info.samples can be 0 for frame 0. We still want to | ||
277 | * remove it from lead_trim, so do that during frame 1. | ||
278 | */ | ||
279 | if (0 == i && 0 == frame_info.samples) | ||
280 | { | ||
281 | empty_first_frame = true; | ||
282 | } | ||
283 | |||
284 | lead_trim -= frame_samples; | ||
285 | |||
286 | if (lead_trim < 0) | ||
287 | { | ||
288 | lead_trim = 0; | ||
289 | } | ||
290 | } | ||
291 | |||
292 | ++i; | ||
293 | } | ||
294 | |||
295 | LOGF("AAC: Decoded %lu samples\n", (unsigned long)sound_samples_done); | ||
296 | return CODEC_OK; | ||
297 | } | ||