Dave Chapman | cea6d0c | 2005-10-31 20:56:29 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * $Id$ |
| 9 | * |
| 10 | * Copyright (C) 2005 Dave Chapman |
| 11 | * |
Daniel Stenberg | 2acc0ac | 2008-06-28 18:10:04 +0000 | [diff] [blame^] | 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. |
Dave Chapman | cea6d0c | 2005-10-31 20:56:29 +0000 | [diff] [blame] | 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 | |
Jens Arnold | b8749fd | 2006-01-18 00:05:14 +0000 | [diff] [blame] | 28 | CODEC_HEADER |
| 29 | |
Dave Chapman | cea6d0c | 2005-10-31 20:56:29 +0000 | [diff] [blame] | 30 | /* this is the codec entry point */ |
Tomasz Malesinski | 80da8b1 | 2006-11-26 18:31:41 +0000 | [diff] [blame] | 31 | enum codec_status codec_main(void) |
Dave Chapman | cea6d0c | 2005-10-31 20:56:29 +0000 | [diff] [blame] | 32 | { |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 33 | /* Note that when dealing with QuickTime/MPEG4 files, terminology is |
| 34 | * a bit confusing. Files with sound are split up in chunks, where |
| 35 | * each chunk contains one or more samples. Each sample in turn |
| 36 | * contains a number of "sound samples" (the kind you refer to with |
| 37 | * the sampling frequency). |
| 38 | */ |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 39 | size_t n; |
| 40 | static demux_res_t demux_res; |
| 41 | stream_t input_stream; |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 42 | uint32_t sound_samples_done; |
| 43 | uint32_t elapsed_time; |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 44 | uint32_t sample_duration; |
| 45 | uint32_t sample_byte_size; |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 46 | int file_offset; |
Magnus Holmgren | c3206a4 | 2007-06-16 13:00:52 +0000 | [diff] [blame] | 47 | int framelength; |
| 48 | int lead_trim = 0; |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 49 | unsigned int i; |
| 50 | unsigned char* buffer; |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 51 | static NeAACDecFrameInfo frame_info; |
| 52 | NeAACDecHandle decoder; |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 53 | int err; |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 54 | uint32_t s = 0; |
| 55 | unsigned char c = 0; |
Dave Chapman | cea6d0c | 2005-10-31 20:56:29 +0000 | [diff] [blame] | 56 | |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 57 | /* Generic codec initialisation */ |
Michael Sevakis | 97f369a | 2007-02-10 16:34:16 +0000 | [diff] [blame] | 58 | ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512); |
Dave Chapman | cea6d0c | 2005-10-31 20:56:29 +0000 | [diff] [blame] | 59 | |
Michael Sevakis | 97f369a | 2007-02-10 16:34:16 +0000 | [diff] [blame] | 60 | ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); |
| 61 | ci->configure(DSP_SET_SAMPLE_DEPTH, 29); |
Dave Chapman | cea6d0c | 2005-10-31 20:56:29 +0000 | [diff] [blame] | 62 | |
Brandon Low | ebadcc6 | 2006-04-15 02:03:11 +0000 | [diff] [blame] | 63 | next_track: |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 64 | err = CODEC_OK; |
Dave Chapman | cea6d0c | 2005-10-31 20:56:29 +0000 | [diff] [blame] | 65 | |
Tomasz Malesinski | 80da8b1 | 2006-11-26 18:31:41 +0000 | [diff] [blame] | 66 | if (codec_init()) { |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 67 | LOGF("FAAD: Codec init error\n"); |
Brandon Low | 1060e44 | 2006-01-18 20:22:03 +0000 | [diff] [blame] | 68 | err = CODEC_ERROR; |
| 69 | goto exit; |
Dave Chapman | cea6d0c | 2005-10-31 20:56:29 +0000 | [diff] [blame] | 70 | } |
| 71 | |
Magnus Holmgren | 9f09a39 | 2006-08-23 13:10:48 +0000 | [diff] [blame] | 72 | while (!*ci->taginfo_ready && !ci->stop_codec) |
| 73 | ci->sleep(1); |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 74 | |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 75 | sound_samples_done = ci->id3->offset; |
Magnus Holmgren | 9f09a39 | 2006-08-23 13:10:48 +0000 | [diff] [blame] | 76 | |
Michael Sevakis | 97f369a | 2007-02-10 16:34:16 +0000 | [diff] [blame] | 77 | ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); |
Tomasz Malesinski | 80da8b1 | 2006-11-26 18:31:41 +0000 | [diff] [blame] | 78 | codec_set_replaygain(ci->id3); |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 79 | |
| 80 | stream_create(&input_stream,ci); |
| 81 | |
| 82 | /* if qtmovie_read returns successfully, the stream is up to |
| 83 | * the movie data, which can be used directly by the decoder */ |
| 84 | if (!qtmovie_read(&input_stream, &demux_res)) { |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 85 | LOGF("FAAD: File init error\n"); |
Brandon Low | 1060e44 | 2006-01-18 20:22:03 +0000 | [diff] [blame] | 86 | err = CODEC_ERROR; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 87 | goto done; |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 88 | } |
| 89 | |
| 90 | /* initialise the sound converter */ |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 91 | decoder = NeAACDecOpen(); |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 92 | |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 93 | if (!decoder) { |
| 94 | LOGF("FAAD: Decode open error\n"); |
Brandon Low | 1060e44 | 2006-01-18 20:22:03 +0000 | [diff] [blame] | 95 | err = CODEC_ERROR; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 96 | goto done; |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 97 | } |
| 98 | |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 99 | NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder); |
Thom Johansen | 0263ece | 2005-11-02 19:43:52 +0000 | [diff] [blame] | 100 | conf->outputFormat = FAAD_FMT_24BIT; /* irrelevant, we don't convert */ |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 101 | NeAACDecSetConfiguration(decoder, conf); |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 102 | |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 103 | err = NeAACDecInit2(decoder, demux_res.codecdata, demux_res.codecdata_len, &s, &c); |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 104 | if (err) { |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 105 | LOGF("FAAD: DecInit: %d, %d\n", err, decoder->object_type); |
Brandon Low | 1060e44 | 2006-01-18 20:22:03 +0000 | [diff] [blame] | 106 | err = CODEC_ERROR; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 107 | goto done; |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 108 | } |
| 109 | |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 110 | ci->id3->frequency = s; |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 111 | |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 112 | i = 0; |
Magnus Holmgren | 9f09a39 | 2006-08-23 13:10:48 +0000 | [diff] [blame] | 113 | |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 114 | if (sound_samples_done > 0) { |
| 115 | if (alac_seek_raw(&demux_res, &input_stream, sound_samples_done, |
| 116 | &sound_samples_done, (int*) &i)) { |
| 117 | elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); |
| 118 | ci->set_elapsed(elapsed_time); |
Magnus Holmgren | 9f09a39 | 2006-08-23 13:10:48 +0000 | [diff] [blame] | 119 | } else { |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 120 | sound_samples_done = 0; |
Magnus Holmgren | 9f09a39 | 2006-08-23 13:10:48 +0000 | [diff] [blame] | 121 | } |
| 122 | } |
Magnus Holmgren | c3206a4 | 2007-06-16 13:00:52 +0000 | [diff] [blame] | 123 | |
| 124 | if (i == 0) |
| 125 | { |
| 126 | lead_trim = ci->id3->lead_trim; |
| 127 | } |
Magnus Holmgren | 9f09a39 | 2006-08-23 13:10:48 +0000 | [diff] [blame] | 128 | |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 129 | /* The main decoding loop */ |
| 130 | while (i < demux_res.num_sample_byte_sizes) { |
Tomasz Malesinski | 80da8b1 | 2006-11-26 18:31:41 +0000 | [diff] [blame] | 131 | ci->yield(); |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 132 | |
Brandon Low | ebadcc6 | 2006-04-15 02:03:11 +0000 | [diff] [blame] | 133 | if (ci->stop_codec || ci->new_track) { |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 134 | break; |
| 135 | } |
| 136 | |
| 137 | /* Deal with any pending seek requests */ |
| 138 | if (ci->seek_time) { |
Daniel Stenberg | 76667e2 | 2005-12-02 08:42:48 +0000 | [diff] [blame] | 139 | if (alac_seek(&demux_res, &input_stream, |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 140 | ((ci->seek_time-1)/10)*(ci->id3->frequency/100), |
| 141 | &sound_samples_done, (int*) &i)) { |
| 142 | elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); |
| 143 | ci->set_elapsed(elapsed_time); |
Magnus Holmgren | c3206a4 | 2007-06-16 13:00:52 +0000 | [diff] [blame] | 144 | |
| 145 | if (i == 0) |
| 146 | { |
| 147 | lead_trim = ci->id3->lead_trim; |
| 148 | } |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 149 | } |
Dave Chapman | 5006d15 | 2005-11-02 00:09:42 +0000 | [diff] [blame] | 150 | ci->seek_complete(); |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 151 | } |
| 152 | |
| 153 | /* Lookup the length (in samples and bytes) of block i */ |
| 154 | if (!get_sample_info(&demux_res, i, &sample_duration, |
| 155 | &sample_byte_size)) { |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 156 | LOGF("AAC: get_sample_info error\n"); |
Brandon Low | 1060e44 | 2006-01-18 20:22:03 +0000 | [diff] [blame] | 157 | err = CODEC_ERROR; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 158 | goto done; |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 159 | } |
| 160 | |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 161 | /* There can be gaps between chunks, so skip ahead if needed. It |
| 162 | * doesn't seem to happen much, but it probably means that a |
| 163 | * "proper" file can have chunks out of order. Why one would want |
| 164 | * that an good question (but files with gaps do exist, so who |
| 165 | * knows?), so we don't support that - for now, at least. |
| 166 | */ |
| 167 | file_offset = get_sample_offset(&demux_res, i); |
| 168 | |
| 169 | if (file_offset > ci->curpos) |
| 170 | { |
| 171 | ci->advance_buffer(file_offset - ci->curpos); |
| 172 | } |
Magnus Holmgren | fc1efc7 | 2007-01-30 21:42:36 +0000 | [diff] [blame] | 173 | else if (file_offset == 0) |
| 174 | { |
| 175 | LOGF("AAC: get_sample_offset error\n"); |
| 176 | err = CODEC_ERROR; |
| 177 | goto done; |
| 178 | } |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 179 | |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 180 | /* Request the required number of bytes from the input buffer */ |
Brandon Low | c76904b | 2006-03-24 14:02:27 +0000 | [diff] [blame] | 181 | buffer=ci->request_buffer(&n,sample_byte_size); |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 182 | |
| 183 | /* Decode one block - returned samples will be host-endian */ |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 184 | NeAACDecDecode(decoder, &frame_info, buffer, n); |
| 185 | /* Ignore return value, we access samples in the decoder struct |
| 186 | * directly. |
| 187 | */ |
| 188 | if (frame_info.error > 0) { |
| 189 | LOGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error)); |
| 190 | err = CODEC_ERROR; |
| 191 | goto done; |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 192 | } |
| 193 | |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 194 | /* Advance codec buffer */ |
| 195 | ci->advance_buffer(n); |
| 196 | |
| 197 | /* Output the audio */ |
Tomasz Malesinski | 80da8b1 | 2006-11-26 18:31:41 +0000 | [diff] [blame] | 198 | ci->yield(); |
Magnus Holmgren | c3206a4 | 2007-06-16 13:00:52 +0000 | [diff] [blame] | 199 | |
| 200 | framelength = (frame_info.samples >> 1) - lead_trim; |
| 201 | |
| 202 | if (i == demux_res.num_sample_byte_sizes - 1 && framelength > 0) |
| 203 | { |
| 204 | /* Currently limited to at most one frame of tail_trim. |
| 205 | * Seems to be enough. |
| 206 | */ |
| 207 | if (ci->id3->tail_trim == 0 |
| 208 | && sample_duration < (frame_info.samples >> 1)) |
| 209 | { |
| 210 | /* Subtract lead_trim just in case we decode a file with |
| 211 | * only one audio frame with actual data. |
| 212 | */ |
| 213 | framelength = sample_duration - lead_trim; |
| 214 | } |
| 215 | else |
| 216 | { |
| 217 | framelength -= ci->id3->tail_trim; |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | if (framelength > 0) |
| 222 | { |
| 223 | ci->pcmbuf_insert(&decoder->time_out[0][lead_trim], |
| 224 | &decoder->time_out[1][lead_trim], |
| 225 | framelength); |
| 226 | } |
| 227 | |
| 228 | if (lead_trim > 0) |
| 229 | { |
| 230 | /* frame_info.samples can be 0 for the first frame */ |
| 231 | lead_trim -= (i > 0 || frame_info.samples) |
| 232 | ? (frame_info.samples >> 1) : sample_duration; |
| 233 | |
| 234 | if (lead_trim < 0 || ci->id3->lead_trim == 0) |
| 235 | { |
| 236 | lead_trim = 0; |
| 237 | } |
| 238 | } |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 239 | |
| 240 | /* Update the elapsed-time indicator */ |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 241 | sound_samples_done += sample_duration; |
| 242 | elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); |
| 243 | ci->set_elapsed(elapsed_time); |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 244 | |
| 245 | /* Keep track of current position - for resuming */ |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 246 | ci->set_offset(elapsed_time); |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 247 | |
| 248 | i++; |
Dave Chapman | cea6d0c | 2005-10-31 20:56:29 +0000 | [diff] [blame] | 249 | } |
Magnus Holmgren | 9896fd1 | 2006-10-11 17:02:23 +0000 | [diff] [blame] | 250 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 251 | err = CODEC_OK; |
Dave Chapman | cea6d0c | 2005-10-31 20:56:29 +0000 | [diff] [blame] | 252 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 253 | done: |
Michael Sevakis | 3354531 | 2007-03-20 13:53:23 +0000 | [diff] [blame] | 254 | LOGF("AAC: Decoded %lu samples\n", sound_samples_done); |
Dave Chapman | cea6d0c | 2005-10-31 20:56:29 +0000 | [diff] [blame] | 255 | |
Dave Chapman | b08a942 | 2005-10-31 23:34:14 +0000 | [diff] [blame] | 256 | if (ci->request_next_track()) |
| 257 | goto next_track; |
Dave Chapman | cea6d0c | 2005-10-31 20:56:29 +0000 | [diff] [blame] | 258 | |
Brandon Low | 1060e44 | 2006-01-18 20:22:03 +0000 | [diff] [blame] | 259 | exit: |
| 260 | return err; |
Dave Chapman | cea6d0c | 2005-10-31 20:56:29 +0000 | [diff] [blame] | 261 | } |