summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/a52_rm.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/a52_rm.c')
-rw-r--r--lib/rbcodec/codecs/a52_rm.c109
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 */
46static uint8_t buf[3840] IBSS_ATTR; 46static uint8_t buf[3840] IBSS_ATTR;
47static uint8_t *bufptr = buf;
48static uint8_t *bufpos = buf + 7;
49
50static 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 */
49static inline void output_audio(sample_t *samples) 57static 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
55static void a52_decode_data(uint8_t *start, uint8_t *end) 63static 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 */
144enum codec_status codec_run(void) 153enum 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(&param); 213 action = ci->get_command(&param);
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;