diff options
Diffstat (limited to 'lib/rbcodec/codecs/a52_rm.c')
-rw-r--r-- | lib/rbcodec/codecs/a52_rm.c | 109 |
1 files changed, 81 insertions, 28 deletions
diff --git a/lib/rbcodec/codecs/a52_rm.c b/lib/rbcodec/codecs/a52_rm.c index bbfd1c735f..e5204762f4 100644 --- a/lib/rbcodec/codecs/a52_rm.c +++ b/lib/rbcodec/codecs/a52_rm.c | |||
@@ -44,6 +44,14 @@ static void init_rm(RMContext *rmctx) | |||
44 | 44 | ||
45 | /* used outside liba52 */ | 45 | /* used outside liba52 */ |
46 | static uint8_t buf[3840] IBSS_ATTR; | 46 | static uint8_t buf[3840] IBSS_ATTR; |
47 | static uint8_t *bufptr = buf; | ||
48 | static uint8_t *bufpos = buf + 7; | ||
49 | |||
50 | static void a52_decoder_reset(void) | ||
51 | { | ||
52 | bufptr = buf; | ||
53 | bufpos = buf + 7; | ||
54 | } | ||
47 | 55 | ||
48 | /* The following two functions, a52_decode_data and output_audio are taken from a52.c */ | 56 | /* The following two functions, a52_decode_data and output_audio are taken from a52.c */ |
49 | static inline void output_audio(sample_t *samples) | 57 | static inline void output_audio(sample_t *samples) |
@@ -52,10 +60,8 @@ static inline void output_audio(sample_t *samples) | |||
52 | ci->pcmbuf_insert(&samples[0], &samples[256], 256); | 60 | ci->pcmbuf_insert(&samples[0], &samples[256], 256); |
53 | } | 61 | } |
54 | 62 | ||
55 | static void a52_decode_data(uint8_t *start, uint8_t *end) | 63 | static size_t a52_decode_data(uint8_t *start, uint8_t *end) |
56 | { | 64 | { |
57 | static uint8_t *bufptr = buf; | ||
58 | static uint8_t *bufpos = buf + 7; | ||
59 | /* | 65 | /* |
60 | * sample_rate and flags are static because this routine could | 66 | * sample_rate and flags are static because this routine could |
61 | * exit between the a52_syncinfo() and the ao_setup(), and we want | 67 | * exit between the a52_syncinfo() and the ao_setup(), and we want |
@@ -65,6 +71,7 @@ static void a52_decode_data(uint8_t *start, uint8_t *end) | |||
65 | static int flags; | 71 | static int flags; |
66 | int bit_rate; | 72 | int bit_rate; |
67 | int len; | 73 | int len; |
74 | size_t consumed = 0; | ||
68 | 75 | ||
69 | while (1) { | 76 | while (1) { |
70 | len = end - start; | 77 | len = end - start; |
@@ -75,6 +82,7 @@ static void a52_decode_data(uint8_t *start, uint8_t *end) | |||
75 | memcpy(bufptr, start, len); | 82 | memcpy(bufptr, start, len); |
76 | bufptr += len; | 83 | bufptr += len; |
77 | start += len; | 84 | start += len; |
85 | consumed += len; | ||
78 | if (bufptr == bufpos) { | 86 | if (bufptr == bufpos) { |
79 | if (bufpos == buf + 7) { | 87 | if (bufpos == buf + 7) { |
80 | int length; | 88 | int length; |
@@ -114,7 +122,7 @@ static void a52_decode_data(uint8_t *start, uint8_t *end) | |||
114 | ci->set_elapsed(samplesdone/(frequency/1000)); | 122 | ci->set_elapsed(samplesdone/(frequency/1000)); |
115 | bufptr = buf; | 123 | bufptr = buf; |
116 | bufpos = buf + 7; | 124 | bufpos = buf + 7; |
117 | continue; | 125 | break; |
118 | error: | 126 | error: |
119 | //logf("Error decoding A52 stream\n"); | 127 | //logf("Error decoding A52 stream\n"); |
120 | bufptr = buf; | 128 | bufptr = buf; |
@@ -122,6 +130,7 @@ static void a52_decode_data(uint8_t *start, uint8_t *end) | |||
122 | } | 130 | } |
123 | } | 131 | } |
124 | } | 132 | } |
133 | return consumed; | ||
125 | } | 134 | } |
126 | 135 | ||
127 | /* this is the codec entry point */ | 136 | /* this is the codec entry point */ |
@@ -143,11 +152,13 @@ enum codec_status codec_main(enum codec_entry_call_reason reason) | |||
143 | /* this is called for each file to process */ | 152 | /* this is called for each file to process */ |
144 | enum codec_status codec_run(void) | 153 | enum codec_status codec_run(void) |
145 | { | 154 | { |
146 | size_t n; | 155 | size_t consumed = 0, n = 0; |
147 | uint8_t *filebuf; | 156 | uint8_t *filebuf; |
148 | int consumed, packet_offset; | 157 | int packet_offset; |
149 | int playback_on = -1; | 158 | int playback_on = -1; |
150 | size_t resume_offset; | 159 | size_t resume_offset; |
160 | size_t data_offset; | ||
161 | size_t packet_size; | ||
151 | long action; | 162 | long action; |
152 | intptr_t param; | 163 | intptr_t param; |
153 | 164 | ||
@@ -162,21 +173,28 @@ enum codec_status codec_run(void) | |||
162 | ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); | 173 | ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); |
163 | codec_set_replaygain(ci->id3); | 174 | codec_set_replaygain(ci->id3); |
164 | 175 | ||
165 | ci->seek_buffer(ci->id3->first_frame_offset); | 176 | ci->seek_buffer(0); |
166 | 177 | ||
167 | /* Intializations */ | 178 | /* Initializations */ |
168 | state = a52_init(0); | 179 | state = a52_init(0); |
169 | ci->memset(&rmctx,0,sizeof(RMContext)); | 180 | ci->memset(&rmctx,0,sizeof(RMContext)); |
170 | ci->memset(&pkt,0,sizeof(RMPacket)); | 181 | ci->memset(&pkt,0,sizeof(RMPacket)); |
171 | init_rm(&rmctx); | 182 | init_rm(&rmctx); |
183 | data_offset = rmctx.data_offset + | ||
184 | ((rmctx.flags & RM_RAW_DATASTREAM) ? 0 : DATA_HEADER_SIZE); | ||
185 | packet_size = rmctx.block_align + | ||
186 | ((rmctx.flags & RM_RAW_DATASTREAM) ? | ||
187 | 0 : | ||
188 | (PACKET_HEADER_SIZE + | ||
189 | ((rmctx.flags & RM_PKT_V1) ? 1 : 0))); | ||
172 | 190 | ||
173 | samplesdone = 0; | 191 | samplesdone = 0; |
174 | 192 | ||
175 | /* check for a mid-track resume and force a seek time accordingly */ | 193 | /* check for a mid-track resume and force a seek time accordingly */ |
176 | if (resume_offset) { | 194 | if (resume_offset) { |
177 | resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); | 195 | resume_offset -= MIN(resume_offset, data_offset); |
178 | /* put number of subpackets to skip in resume_offset */ | 196 | /* put number of subpackets to skip in resume_offset */ |
179 | resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE); | 197 | resume_offset /= packet_size; |
180 | param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate); | 198 | param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate); |
181 | } | 199 | } |
182 | 200 | ||
@@ -186,11 +204,11 @@ enum codec_status codec_run(void) | |||
186 | else { | 204 | else { |
187 | /* Seek to the first packet */ | 205 | /* Seek to the first packet */ |
188 | ci->set_elapsed(0); | 206 | ci->set_elapsed(0); |
189 | ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE ); | 207 | ci->advance_buffer(data_offset); |
190 | } | 208 | } |
191 | 209 | ||
192 | /* The main decoding loop */ | 210 | /* The main decoding loop */ |
193 | while((unsigned)rmctx.audio_pkt_cnt < rmctx.nb_packets) { | 211 | while ((rmctx.flags & RM_RAW_DATASTREAM) || (unsigned)rmctx.audio_pkt_cnt < rmctx.nb_packets) { |
194 | if (action == CODEC_ACTION_NULL) | 212 | if (action == CODEC_ACTION_NULL) |
195 | action = ci->get_command(¶m); | 213 | action = ci->get_command(¶m); |
196 | 214 | ||
@@ -198,34 +216,69 @@ enum codec_status codec_run(void) | |||
198 | break; | 216 | break; |
199 | 217 | ||
200 | if (action == CODEC_ACTION_SEEK_TIME) { | 218 | if (action == CODEC_ACTION_SEEK_TIME) { |
219 | /* Do not allow seeking beyond the file's length */ | ||
220 | if ((unsigned) param > ci->id3->length) { | ||
221 | ci->set_elapsed(ci->id3->length); | ||
222 | ci->seek_complete(); | ||
223 | break; | ||
224 | } | ||
225 | |||
226 | if (n) | ||
227 | rm_ac3_swap_bytes(filebuf, (rmctx.flags & RM_RAW_DATASTREAM) ? n : rmctx.block_align); | ||
201 | packet_offset = param / ((rmctx.block_align*8*1000)/rmctx.bit_rate); | 228 | packet_offset = param / ((rmctx.block_align*8*1000)/rmctx.bit_rate); |
202 | ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + | 229 | ci->seek_buffer(data_offset + packet_offset * packet_size); |
203 | packet_offset*(rmctx.block_align + PACKET_HEADER_SIZE)); | ||
204 | rmctx.audio_pkt_cnt = packet_offset; | 230 | rmctx.audio_pkt_cnt = packet_offset; |
205 | samplesdone = (rmctx.sample_rate/1000 * param); | 231 | samplesdone = packet_offset * A52_SAMPLESPERFRAME; |
206 | ci->set_elapsed(samplesdone/(frequency/1000)); | 232 | ci->set_elapsed(samplesdone/(ci->id3->frequency/1000)); |
207 | ci->seek_complete(); | 233 | ci->seek_complete(); |
234 | a52_decoder_reset(); | ||
235 | consumed = 0; | ||
236 | n = 0; | ||
208 | } | 237 | } |
209 | 238 | ||
210 | action = CODEC_ACTION_NULL; | 239 | action = CODEC_ACTION_NULL; |
211 | 240 | ||
212 | filebuf = ci->request_buffer(&n, rmctx.block_align + PACKET_HEADER_SIZE); | 241 | if (rmctx.flags & RM_RAW_DATASTREAM) { |
213 | consumed = rm_get_packet(&filebuf, &rmctx, &pkt); | 242 | if (n > consumed) { |
214 | 243 | consumed += a52_decode_data(filebuf + consumed, filebuf + n); | |
215 | if(consumed < 0 && playback_on != 0) { | 244 | ci->set_offset(ci->curpos + consumed); |
216 | if(playback_on == -1) { | ||
217 | /* Error only if packet-parsing failed and playback hadn't started */ | ||
218 | DEBUGF("rm_get_packet failed\n"); | ||
219 | return CODEC_ERROR; | ||
220 | } | 245 | } |
221 | else { | 246 | else { |
222 | break; | 247 | if (n) { |
248 | rm_ac3_swap_bytes(filebuf, n); | ||
249 | ci->advance_buffer(n); | ||
250 | } | ||
251 | filebuf = ci->request_buffer(&n, BUFFER_SIZE); | ||
252 | if (n == 0) | ||
253 | break; | ||
254 | rm_ac3_swap_bytes(filebuf, n); | ||
255 | consumed = 0; | ||
223 | } | 256 | } |
224 | } | 257 | } |
258 | else { | ||
259 | filebuf = ci->request_buffer(&n, packet_size); | ||
260 | |||
261 | if (n == 0) | ||
262 | break; | ||
263 | |||
264 | if (rm_get_packet(&filebuf, &rmctx, &pkt) < 0 && playback_on != 0) { | ||
265 | if(playback_on == -1) { | ||
266 | /* Error only if packet-parsing failed and playback hadn't started */ | ||
267 | DEBUGF("rm_get_packet failed\n"); | ||
268 | return CODEC_ERROR; | ||
269 | } | ||
270 | else { | ||
271 | break; | ||
272 | } | ||
273 | } | ||
225 | 274 | ||
226 | playback_on = 1; | 275 | playback_on = 1; |
227 | a52_decode_data(filebuf, filebuf + rmctx.block_align); | 276 | consumed = 0; |
228 | ci->advance_buffer(pkt.length); | 277 | while (consumed < rmctx.block_align) |
278 | consumed += a52_decode_data(filebuf + consumed, filebuf + rmctx.block_align); | ||
279 | rm_ac3_swap_bytes(filebuf, rmctx.block_align); | ||
280 | ci->advance_buffer(pkt.length); | ||
281 | } | ||
229 | } | 282 | } |
230 | 283 | ||
231 | return CODEC_OK; | 284 | return CODEC_OK; |