diff options
author | Mohamed Tarek <mt@rockbox.org> | 2009-07-25 15:47:13 +0000 |
---|---|---|
committer | Mohamed Tarek <mt@rockbox.org> | 2009-07-25 15:47:13 +0000 |
commit | b8cccb5ae18f35ea7d210c513bafe10b19fafbd7 (patch) | |
tree | 901a2d75ad40134a005c3bbb68949f551fc9c50e /apps/codecs/raac.c | |
parent | 8f572ca525bf3812799e627a4a716300e412c244 (diff) | |
download | rockbox-b8cccb5ae18f35ea7d210c513bafe10b19fafbd7.tar.gz rockbox-b8cccb5ae18f35ea7d210c513bafe10b19fafbd7.zip |
Adding support for playback of aac audio in rm container, with seeking.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@22031 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/raac.c')
-rw-r--r-- | apps/codecs/raac.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/apps/codecs/raac.c b/apps/codecs/raac.c new file mode 100644 index 0000000000..cfc5b4a460 --- /dev/null +++ b/apps/codecs/raac.c | |||
@@ -0,0 +1,176 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: aac.c 19743 2009-01-10 21:10:56Z zagor $ | ||
9 | * | ||
10 | * Copyright (C) 2009 Mohamed Tarek | ||
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 "librm/rm.h" | ||
24 | #include "libfaad/common.h" | ||
25 | #include "libfaad/structs.h" | ||
26 | #include "libfaad/decoder.h" | ||
27 | #include "libfaad/output.h" | ||
28 | |||
29 | CODEC_HEADER | ||
30 | #define DATA_HEADER_SIZE 18 | ||
31 | static void init_rm(RMContext *rmctx) | ||
32 | { | ||
33 | memcpy(rmctx, (void*)(( (intptr_t)ci->id3->id3v2buf + 3 ) &~ 3), sizeof(RMContext)); | ||
34 | } | ||
35 | |||
36 | RMContext rmctx; | ||
37 | RMPacket pkt; | ||
38 | /* this is the codec entry point */ | ||
39 | enum codec_status codec_main(void) | ||
40 | { | ||
41 | static NeAACDecFrameInfo frame_info; | ||
42 | NeAACDecHandle decoder; | ||
43 | size_t n; | ||
44 | int32_t *output; | ||
45 | unsigned int i; | ||
46 | unsigned char* buffer; | ||
47 | int err, consumed, pkt_offset, skipped = 0; | ||
48 | uint32_t s = 0; /* sample rate */ | ||
49 | unsigned char c = 0; /* channels */ | ||
50 | /* Generic codec initialisation */ | ||
51 | ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); | ||
52 | ci->configure(DSP_SET_SAMPLE_DEPTH, 16); | ||
53 | |||
54 | next_track: | ||
55 | err = CODEC_OK; | ||
56 | |||
57 | if (codec_init()) { | ||
58 | DEBUGF("FAAD: Codec init error\n"); | ||
59 | return CODEC_ERROR; | ||
60 | } | ||
61 | |||
62 | while (!*ci->taginfo_ready && !ci->stop_codec) | ||
63 | ci->sleep(1); | ||
64 | |||
65 | ci->memset(&rmctx,0,sizeof(RMContext)); | ||
66 | ci->memset(&pkt,0,sizeof(RMPacket)); | ||
67 | init_rm(&rmctx); | ||
68 | ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); | ||
69 | codec_set_replaygain(ci->id3); | ||
70 | |||
71 | /* initialise the sound converter */ | ||
72 | decoder = NeAACDecOpen(); | ||
73 | |||
74 | if (!decoder) { | ||
75 | DEBUGF("FAAD: Decode open error\n"); | ||
76 | err = CODEC_ERROR; | ||
77 | goto done; | ||
78 | } | ||
79 | NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder); | ||
80 | conf->outputFormat = FAAD_FMT_16BIT; | ||
81 | NeAACDecSetConfiguration(decoder, conf); | ||
82 | |||
83 | decoder->config.defObjectType = rmctx.codec_extradata[0]; | ||
84 | decoder->config.defSampleRate = rmctx.sample_rate; | ||
85 | err = NeAACDecInit(decoder, NULL, 0, &s, &c); | ||
86 | |||
87 | if (err) { | ||
88 | DEBUGF("FAAD: DecInit: %d, %d\n", err, decoder->object_type); | ||
89 | err = CODEC_ERROR; | ||
90 | goto done; | ||
91 | } | ||
92 | ci->id3->frequency = s; | ||
93 | ci->set_elapsed(0); | ||
94 | ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE); | ||
95 | |||
96 | /* The main decoding loop */ | ||
97 | seek_start: | ||
98 | while (1) { | ||
99 | ci->yield(); | ||
100 | if (ci->stop_codec || ci->new_track) { | ||
101 | break; | ||
102 | } | ||
103 | |||
104 | if (ci->seek_time) { | ||
105 | |||
106 | /* Do not allow seeking beyond the file's length */ | ||
107 | if ((unsigned) ci->seek_time > ci->id3->length) { | ||
108 | ci->seek_complete(); | ||
109 | goto done; | ||
110 | } | ||
111 | |||
112 | ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE); | ||
113 | |||
114 | /* Seek to the start of the track */ | ||
115 | if (ci->seek_time == 1) { | ||
116 | ci->set_elapsed(0); | ||
117 | ci->seek_complete(); | ||
118 | goto seek_start; | ||
119 | } | ||
120 | |||
121 | skipped = 0; | ||
122 | while(1) { | ||
123 | buffer = ci->request_buffer(&n,rmctx.audio_framesize + 1000); | ||
124 | pkt_offset = skipped - pkt.length; | ||
125 | consumed = rm_get_packet(&buffer, &rmctx, &pkt); | ||
126 | if(consumed < 0) { | ||
127 | DEBUGF("rm_get_packet failed\n"); | ||
128 | return CODEC_ERROR; | ||
129 | } | ||
130 | skipped += pkt.length; | ||
131 | if(pkt.timestamp > (unsigned)ci->seek_time) break; | ||
132 | ci->advance_buffer(pkt.length); | ||
133 | } | ||
134 | ci->seek_buffer(pkt_offset + rmctx.data_offset + DATA_HEADER_SIZE); | ||
135 | buffer = ci->request_buffer(&n,rmctx.audio_framesize + 1000); | ||
136 | ci->seek_complete(); | ||
137 | } | ||
138 | |||
139 | /* Request the required number of bytes from the input buffer */ | ||
140 | buffer=ci->request_buffer(&n,rmctx.audio_framesize + 1000); | ||
141 | consumed = rm_get_packet(&buffer, &rmctx, &pkt); | ||
142 | if(consumed < 0) { | ||
143 | DEBUGF("rm_get_packet failed\n"); | ||
144 | return CODEC_ERROR; | ||
145 | } | ||
146 | |||
147 | if (pkt.timestamp >= ci->id3->length) | ||
148 | goto done; | ||
149 | /* Decode one block - returned samples will be host-endian */ | ||
150 | for(i = 0; i < rmctx.sub_packet_cnt; i++) { | ||
151 | output = (int32_t *)NeAACDecDecode(decoder, &frame_info, buffer, rmctx.sub_packet_lengths[i]); | ||
152 | buffer += rmctx.sub_packet_lengths[i]; | ||
153 | if (frame_info.error > 0) { | ||
154 | DEBUGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error)); | ||
155 | err = CODEC_ERROR; | ||
156 | goto exit; | ||
157 | } | ||
158 | output = (int32_t *) output_to_PCM(decoder, decoder->time_out, output, | ||
159 | rmctx.nb_channels, decoder->frameLength, decoder->config.outputFormat); | ||
160 | ci->pcmbuf_insert(output, NULL, frame_info.samples/rmctx.nb_channels); | ||
161 | ci->set_elapsed(pkt.timestamp); | ||
162 | } | ||
163 | |||
164 | ci->advance_buffer(pkt.length); | ||
165 | } | ||
166 | |||
167 | err = CODEC_OK; | ||
168 | |||
169 | done: | ||
170 | if (ci->request_next_track()) | ||
171 | goto next_track; | ||
172 | |||
173 | exit: | ||
174 | return err; | ||
175 | } | ||
176 | |||