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/flac.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/flac.c')
-rw-r--r-- | lib/rbcodec/codecs/flac.c | 536 |
1 files changed, 536 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/flac.c b/lib/rbcodec/codecs/flac.c new file mode 100644 index 0000000000..e10403819c --- /dev/null +++ b/lib/rbcodec/codecs/flac.c | |||
@@ -0,0 +1,536 @@ | |||
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 <codecs/libffmpegFLAC/decoder.h> | ||
24 | |||
25 | CODEC_HEADER | ||
26 | |||
27 | static FLACContext fc IBSS_ATTR_FLAC; | ||
28 | |||
29 | /* The output buffers containing the decoded samples (channels 0 and 1) */ | ||
30 | static int32_t decoded0[MAX_BLOCKSIZE] IBSS_ATTR_FLAC; | ||
31 | static int32_t decoded1[MAX_BLOCKSIZE] IBSS_ATTR_FLAC; | ||
32 | static int32_t decoded2[MAX_BLOCKSIZE] IBSS_ATTR_FLAC_LARGE_IRAM; | ||
33 | static int32_t decoded3[MAX_BLOCKSIZE] IBSS_ATTR_FLAC_LARGE_IRAM; | ||
34 | static int32_t decoded4[MAX_BLOCKSIZE] IBSS_ATTR_FLAC_XLARGE_IRAM; | ||
35 | static int32_t decoded5[MAX_BLOCKSIZE] IBSS_ATTR_FLAC_XLARGE_IRAM; | ||
36 | |||
37 | #define MAX_SUPPORTED_SEEKTABLE_SIZE 5000 | ||
38 | |||
39 | /* Notes about seeking: | ||
40 | |||
41 | The full seek table consists of: | ||
42 | uint64_t sample (only 36 bits are used) | ||
43 | uint64_t offset | ||
44 | uint32_t blocksize | ||
45 | |||
46 | We also limit the sample and offset values to 32-bits - Rockbox doesn't | ||
47 | support files bigger than 2GB on FAT32 filesystems. | ||
48 | |||
49 | The reference FLAC encoder produces a seek table with points every | ||
50 | 10 seconds, but this can be overridden by the user when encoding a file. | ||
51 | |||
52 | With the default settings, a typical 4 minute track will contain | ||
53 | 24 seek points. | ||
54 | |||
55 | Taking the extreme case of a Rockbox supported file to be a 2GB (compressed) | ||
56 | 16-bit/44.1KHz mono stream with a likely uncompressed size of 4GB: | ||
57 | Total duration is: 48694 seconds (about 810 minutes - 13.5 hours) | ||
58 | Total number of seek points: 4869 | ||
59 | |||
60 | Therefore we limit the number of seek points to 5000. This is a | ||
61 | very extreme case, and requires 5000*8=40000 bytes of storage. | ||
62 | |||
63 | If we come across a FLAC file with more than this number of seekpoints, we | ||
64 | just use the first 5000. | ||
65 | |||
66 | */ | ||
67 | |||
68 | struct FLACseekpoints { | ||
69 | uint32_t sample; | ||
70 | uint32_t offset; | ||
71 | uint16_t blocksize; | ||
72 | }; | ||
73 | |||
74 | static struct FLACseekpoints seekpoints[MAX_SUPPORTED_SEEKTABLE_SIZE]; | ||
75 | static int nseekpoints; | ||
76 | |||
77 | static int8_t *bit_buffer; | ||
78 | static size_t buff_size; | ||
79 | |||
80 | static bool flac_init(FLACContext* fc, int first_frame_offset) | ||
81 | { | ||
82 | unsigned char buf[255]; | ||
83 | bool found_streaminfo=false; | ||
84 | uint32_t seekpoint_hi,seekpoint_lo; | ||
85 | uint32_t offset_hi,offset_lo; | ||
86 | uint16_t blocksize; | ||
87 | int endofmetadata=0; | ||
88 | uint32_t blocklength; | ||
89 | |||
90 | ci->memset(fc,0,sizeof(FLACContext)); | ||
91 | nseekpoints=0; | ||
92 | |||
93 | fc->sample_skip = 0; | ||
94 | |||
95 | /* Reset sample buffers */ | ||
96 | memset(decoded0, 0, sizeof(decoded0)); | ||
97 | memset(decoded1, 0, sizeof(decoded1)); | ||
98 | memset(decoded2, 0, sizeof(decoded2)); | ||
99 | memset(decoded3, 0, sizeof(decoded3)); | ||
100 | memset(decoded4, 0, sizeof(decoded4)); | ||
101 | memset(decoded5, 0, sizeof(decoded5)); | ||
102 | |||
103 | /* Set sample buffers in decoder structure */ | ||
104 | fc->decoded[0] = decoded0; | ||
105 | fc->decoded[1] = decoded1; | ||
106 | fc->decoded[2] = decoded2; | ||
107 | fc->decoded[3] = decoded3; | ||
108 | fc->decoded[4] = decoded4; | ||
109 | fc->decoded[5] = decoded5; | ||
110 | |||
111 | |||
112 | /* Skip any foreign tags at start of file */ | ||
113 | ci->seek_buffer(first_frame_offset); | ||
114 | |||
115 | fc->metadatalength = first_frame_offset; | ||
116 | |||
117 | if (ci->read_filebuf(buf, 4) < 4) | ||
118 | { | ||
119 | return false; | ||
120 | } | ||
121 | |||
122 | if (ci->memcmp(buf,"fLaC",4) != 0) | ||
123 | { | ||
124 | return false; | ||
125 | } | ||
126 | fc->metadatalength += 4; | ||
127 | |||
128 | while (!endofmetadata) { | ||
129 | if (ci->read_filebuf(buf, 4) < 4) | ||
130 | { | ||
131 | return false; | ||
132 | } | ||
133 | |||
134 | endofmetadata=(buf[0]&0x80); | ||
135 | blocklength = (buf[1] << 16) | (buf[2] << 8) | buf[3]; | ||
136 | fc->metadatalength+=blocklength+4; | ||
137 | |||
138 | if ((buf[0] & 0x7f) == 0) /* 0 is the STREAMINFO block */ | ||
139 | { | ||
140 | if (ci->read_filebuf(buf, blocklength) < blocklength) return false; | ||
141 | |||
142 | fc->filesize = ci->filesize; | ||
143 | fc->min_blocksize = (buf[0] << 8) | buf[1]; | ||
144 | int max_blocksize = (buf[2] << 8) | buf[3]; | ||
145 | if (max_blocksize > MAX_BLOCKSIZE) | ||
146 | { | ||
147 | LOGF("FLAC: Maximum blocksize is too large (%d > %d)\n", | ||
148 | max_blocksize, MAX_BLOCKSIZE); | ||
149 | return false; | ||
150 | } | ||
151 | fc->max_blocksize = max_blocksize; | ||
152 | fc->min_framesize = (buf[4] << 16) | (buf[5] << 8) | buf[6]; | ||
153 | fc->max_framesize = (buf[7] << 16) | (buf[8] << 8) | buf[9]; | ||
154 | fc->samplerate = (buf[10] << 12) | (buf[11] << 4) | ||
155 | | ((buf[12] & 0xf0) >> 4); | ||
156 | fc->channels = ((buf[12]&0x0e)>>1) + 1; | ||
157 | fc->bps = (((buf[12]&0x01) << 4) | ((buf[13]&0xf0)>>4) ) + 1; | ||
158 | |||
159 | /* totalsamples is a 36-bit field, but we assume <= 32 bits are | ||
160 | used */ | ||
161 | fc->totalsamples = (buf[14] << 24) | (buf[15] << 16) | ||
162 | | (buf[16] << 8) | buf[17]; | ||
163 | |||
164 | /* Calculate track length (in ms) and estimate the bitrate | ||
165 | (in kbit/s) */ | ||
166 | fc->length = ((int64_t) fc->totalsamples * 1000) / fc->samplerate; | ||
167 | |||
168 | found_streaminfo=true; | ||
169 | } else if ((buf[0] & 0x7f) == 3) { /* 3 is the SEEKTABLE block */ | ||
170 | while ((nseekpoints < MAX_SUPPORTED_SEEKTABLE_SIZE) && | ||
171 | (blocklength >= 18)) { | ||
172 | if (ci->read_filebuf(buf,18) < 18) return false; | ||
173 | blocklength-=18; | ||
174 | |||
175 | seekpoint_hi=(buf[0] << 24) | (buf[1] << 16) | | ||
176 | (buf[2] << 8) | buf[3]; | ||
177 | seekpoint_lo=(buf[4] << 24) | (buf[5] << 16) | | ||
178 | (buf[6] << 8) | buf[7]; | ||
179 | offset_hi=(buf[8] << 24) | (buf[9] << 16) | | ||
180 | (buf[10] << 8) | buf[11]; | ||
181 | offset_lo=(buf[12] << 24) | (buf[13] << 16) | | ||
182 | (buf[14] << 8) | buf[15]; | ||
183 | |||
184 | blocksize=(buf[16] << 8) | buf[17]; | ||
185 | |||
186 | /* Only store seekpoints where the high 32 bits are zero */ | ||
187 | if ((seekpoint_hi == 0) && (seekpoint_lo != 0xffffffff) && | ||
188 | (offset_hi == 0)) { | ||
189 | seekpoints[nseekpoints].sample=seekpoint_lo; | ||
190 | seekpoints[nseekpoints].offset=offset_lo; | ||
191 | seekpoints[nseekpoints].blocksize=blocksize; | ||
192 | nseekpoints++; | ||
193 | } | ||
194 | } | ||
195 | /* Skip any unread seekpoints */ | ||
196 | if (blocklength > 0) | ||
197 | ci->advance_buffer(blocklength); | ||
198 | } else { | ||
199 | /* Skip to next metadata block */ | ||
200 | ci->advance_buffer(blocklength); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | if (found_streaminfo) { | ||
205 | fc->bitrate = ((int64_t) (fc->filesize-fc->metadatalength) * 8) | ||
206 | / fc->length; | ||
207 | return true; | ||
208 | } else { | ||
209 | return false; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | /* Synchronize to next frame in stream - adapted from libFLAC 1.1.3b2 */ | ||
214 | static bool frame_sync(FLACContext* fc) { | ||
215 | unsigned int x = 0; | ||
216 | bool cached = false; | ||
217 | |||
218 | /* Make sure we're byte aligned. */ | ||
219 | align_get_bits(&fc->gb); | ||
220 | |||
221 | while(1) { | ||
222 | if(fc->gb.size_in_bits - get_bits_count(&fc->gb) < 8) { | ||
223 | /* Error, end of bitstream, a valid stream should never reach here | ||
224 | * since the buffer should contain at least one frame header. | ||
225 | */ | ||
226 | return false; | ||
227 | } | ||
228 | |||
229 | if(cached) | ||
230 | cached = false; | ||
231 | else | ||
232 | x = get_bits(&fc->gb, 8); | ||
233 | |||
234 | if(x == 0xff) { /* MAGIC NUMBER for first 8 frame sync bits. */ | ||
235 | x = get_bits(&fc->gb, 8); | ||
236 | /* We have to check if we just read two 0xff's in a row; the second | ||
237 | * may actually be the beginning of the sync code. | ||
238 | */ | ||
239 | if(x == 0xff) { /* MAGIC NUMBER for first 8 frame sync bits. */ | ||
240 | cached = true; | ||
241 | } | ||
242 | else if(x >> 2 == 0x3e) { /* MAGIC NUMBER for last 6 sync bits. */ | ||
243 | /* Succesfully synced. */ | ||
244 | break; | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | |||
249 | /* Advance and init bit buffer to the new frame. */ | ||
250 | ci->advance_buffer((get_bits_count(&fc->gb)-16)>>3); /* consumed bytes */ | ||
251 | bit_buffer = ci->request_buffer(&buff_size, MAX_FRAMESIZE+16); | ||
252 | init_get_bits(&fc->gb, bit_buffer, buff_size*8); | ||
253 | |||
254 | /* Decode the frame to verify the frame crc and | ||
255 | * fill fc with its metadata. | ||
256 | */ | ||
257 | if(flac_decode_frame(fc, | ||
258 | bit_buffer, buff_size, ci->yield) < 0) { | ||
259 | return false; | ||
260 | } | ||
261 | |||
262 | return true; | ||
263 | } | ||
264 | |||
265 | /* Seek to sample - adapted from libFLAC 1.1.3b2+ */ | ||
266 | static bool flac_seek(FLACContext* fc, uint32_t target_sample) { | ||
267 | off_t orig_pos = ci->curpos; | ||
268 | off_t pos = -1; | ||
269 | unsigned long lower_bound, upper_bound; | ||
270 | unsigned long lower_bound_sample, upper_bound_sample; | ||
271 | int i; | ||
272 | unsigned approx_bytes_per_frame; | ||
273 | uint32_t this_frame_sample = fc->samplenumber; | ||
274 | unsigned this_block_size = fc->blocksize; | ||
275 | bool needs_seek = true, first_seek = true; | ||
276 | |||
277 | /* We are just guessing here. */ | ||
278 | if(fc->max_framesize > 0) | ||
279 | approx_bytes_per_frame = (fc->max_framesize + fc->min_framesize)/2 + 1; | ||
280 | /* Check if it's a known fixed-blocksize stream. */ | ||
281 | else if(fc->min_blocksize == fc->max_blocksize && fc->min_blocksize > 0) | ||
282 | approx_bytes_per_frame = fc->min_blocksize*fc->channels*fc->bps/8 + 64; | ||
283 | else | ||
284 | approx_bytes_per_frame = 4608 * fc->channels * fc->bps/8 + 64; | ||
285 | |||
286 | /* Set an upper and lower bound on where in the stream we will search. */ | ||
287 | lower_bound = fc->metadatalength; | ||
288 | lower_bound_sample = 0; | ||
289 | upper_bound = fc->filesize; | ||
290 | upper_bound_sample = fc->totalsamples>0 ? fc->totalsamples : target_sample; | ||
291 | |||
292 | /* Refine the bounds if we have a seektable with suitable points. */ | ||
293 | if(nseekpoints > 0) { | ||
294 | /* Find the closest seek point <= target_sample, if it exists. */ | ||
295 | for(i = nseekpoints-1; i >= 0; i--) { | ||
296 | if(seekpoints[i].sample <= target_sample) | ||
297 | break; | ||
298 | } | ||
299 | if(i >= 0) { /* i.e. we found a suitable seek point... */ | ||
300 | lower_bound = fc->metadatalength + seekpoints[i].offset; | ||
301 | lower_bound_sample = seekpoints[i].sample; | ||
302 | } | ||
303 | |||
304 | /* Find the closest seek point > target_sample, if it exists. */ | ||
305 | for(i = 0; i < nseekpoints; i++) { | ||
306 | if(seekpoints[i].sample > target_sample) | ||
307 | break; | ||
308 | } | ||
309 | if(i < nseekpoints) { /* i.e. we found a suitable seek point... */ | ||
310 | upper_bound = fc->metadatalength + seekpoints[i].offset; | ||
311 | upper_bound_sample = seekpoints[i].sample; | ||
312 | } | ||
313 | } | ||
314 | |||
315 | while(1) { | ||
316 | /* Check if bounds are still ok. */ | ||
317 | if(lower_bound_sample >= upper_bound_sample || | ||
318 | lower_bound > upper_bound) { | ||
319 | return false; | ||
320 | } | ||
321 | |||
322 | /* Calculate new seek position */ | ||
323 | if(needs_seek) { | ||
324 | pos = (off_t)(lower_bound + | ||
325 | (((target_sample - lower_bound_sample) * | ||
326 | (int64_t)(upper_bound - lower_bound)) / | ||
327 | (upper_bound_sample - lower_bound_sample)) - | ||
328 | approx_bytes_per_frame); | ||
329 | |||
330 | if(pos >= (off_t)upper_bound) | ||
331 | pos = (off_t)upper_bound-1; | ||
332 | if(pos < (off_t)lower_bound) | ||
333 | pos = (off_t)lower_bound; | ||
334 | } | ||
335 | |||
336 | if(!ci->seek_buffer(pos)) | ||
337 | return false; | ||
338 | |||
339 | bit_buffer = ci->request_buffer(&buff_size, MAX_FRAMESIZE+16); | ||
340 | init_get_bits(&fc->gb, bit_buffer, buff_size*8); | ||
341 | |||
342 | /* Now we need to get a frame. It is possible for our seek | ||
343 | * to land in the middle of audio data that looks exactly like | ||
344 | * a frame header from a future version of an encoder. When | ||
345 | * that happens, frame_sync() will return false. | ||
346 | * But there is a remote possibility that it is properly | ||
347 | * synced at such a "future-codec frame", so to make sure, | ||
348 | * we wait to see several "unparseable" errors in a row before | ||
349 | * bailing out. | ||
350 | */ | ||
351 | { | ||
352 | unsigned unparseable_count; | ||
353 | bool got_a_frame = false; | ||
354 | for(unparseable_count = 0; !got_a_frame | ||
355 | && unparseable_count < 10; unparseable_count++) { | ||
356 | if(frame_sync(fc)) | ||
357 | got_a_frame = true; | ||
358 | } | ||
359 | if(!got_a_frame) { | ||
360 | ci->seek_buffer(orig_pos); | ||
361 | return false; | ||
362 | } | ||
363 | } | ||
364 | |||
365 | this_frame_sample = fc->samplenumber; | ||
366 | this_block_size = fc->blocksize; | ||
367 | |||
368 | if(target_sample >= this_frame_sample | ||
369 | && target_sample < this_frame_sample+this_block_size) { | ||
370 | /* Found the frame containing the target sample. */ | ||
371 | fc->sample_skip = target_sample - this_frame_sample; | ||
372 | break; | ||
373 | } | ||
374 | |||
375 | if(this_frame_sample + this_block_size >= upper_bound_sample && | ||
376 | !first_seek) { | ||
377 | if(pos == (off_t)lower_bound || !needs_seek) { | ||
378 | ci->seek_buffer(orig_pos); | ||
379 | return false; | ||
380 | } | ||
381 | /* Our last move backwards wasn't big enough, try again. */ | ||
382 | approx_bytes_per_frame *= 2; | ||
383 | continue; | ||
384 | } | ||
385 | /* Allow one seek over upper bound, | ||
386 | * required for streams with unknown total samples. | ||
387 | */ | ||
388 | first_seek = false; | ||
389 | |||
390 | /* Make sure we are not seeking in a corrupted stream */ | ||
391 | if(this_frame_sample < lower_bound_sample) { | ||
392 | ci->seek_buffer(orig_pos); | ||
393 | return false; | ||
394 | } | ||
395 | |||
396 | approx_bytes_per_frame = this_block_size*fc->channels*fc->bps/8 + 64; | ||
397 | |||
398 | /* We need to narrow the search. */ | ||
399 | if(target_sample < this_frame_sample) { | ||
400 | upper_bound_sample = this_frame_sample; | ||
401 | upper_bound = ci->curpos; | ||
402 | } | ||
403 | else { /* Target is beyond this frame. */ | ||
404 | /* We are close, continue in decoding next frames. */ | ||
405 | if(target_sample < this_frame_sample + 4*this_block_size) { | ||
406 | pos = ci->curpos + fc->framesize; | ||
407 | needs_seek = false; | ||
408 | } | ||
409 | |||
410 | lower_bound_sample = this_frame_sample + this_block_size; | ||
411 | lower_bound = ci->curpos + fc->framesize; | ||
412 | } | ||
413 | } | ||
414 | |||
415 | return true; | ||
416 | } | ||
417 | |||
418 | /* Seek to file offset */ | ||
419 | static bool flac_seek_offset(FLACContext* fc, uint32_t offset) { | ||
420 | unsigned unparseable_count; | ||
421 | bool got_a_frame = false; | ||
422 | |||
423 | if(!ci->seek_buffer(offset)) | ||
424 | return false; | ||
425 | |||
426 | bit_buffer = ci->request_buffer(&buff_size, MAX_FRAMESIZE); | ||
427 | init_get_bits(&fc->gb, bit_buffer, buff_size*8); | ||
428 | |||
429 | for(unparseable_count = 0; !got_a_frame | ||
430 | && unparseable_count < 10; unparseable_count++) { | ||
431 | if(frame_sync(fc)) | ||
432 | got_a_frame = true; | ||
433 | } | ||
434 | |||
435 | if(!got_a_frame) { | ||
436 | ci->seek_buffer(fc->metadatalength); | ||
437 | return false; | ||
438 | } | ||
439 | |||
440 | return true; | ||
441 | } | ||
442 | |||
443 | /* this is the codec entry point */ | ||
444 | enum codec_status codec_main(enum codec_entry_call_reason reason) | ||
445 | { | ||
446 | if (reason == CODEC_LOAD) { | ||
447 | /* Generic codec initialisation */ | ||
448 | ci->configure(DSP_SET_SAMPLE_DEPTH, FLAC_OUTPUT_DEPTH-1); | ||
449 | } | ||
450 | |||
451 | return CODEC_OK; | ||
452 | } | ||
453 | |||
454 | /* this is called for each file to process */ | ||
455 | enum codec_status codec_run(void) | ||
456 | { | ||
457 | int8_t *buf; | ||
458 | uint32_t samplesdone; | ||
459 | uint32_t elapsedtime; | ||
460 | size_t bytesleft; | ||
461 | int consumed; | ||
462 | int res; | ||
463 | int frame; | ||
464 | intptr_t param; | ||
465 | |||
466 | if (codec_init()) { | ||
467 | LOGF("FLAC: Error initialising codec\n"); | ||
468 | return CODEC_ERROR; | ||
469 | } | ||
470 | |||
471 | /* Need to save offset for later use (cleared indirectly by flac_init) */ | ||
472 | samplesdone = ci->id3->offset; | ||
473 | |||
474 | if (!flac_init(&fc,ci->id3->first_frame_offset)) { | ||
475 | LOGF("FLAC: Error initialising codec\n"); | ||
476 | return CODEC_ERROR; | ||
477 | } | ||
478 | |||
479 | ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); | ||
480 | ci->configure(DSP_SET_STEREO_MODE, fc.channels == 1 ? | ||
481 | STEREO_MONO : STEREO_NONINTERLEAVED); | ||
482 | codec_set_replaygain(ci->id3); | ||
483 | |||
484 | flac_seek_offset(&fc, samplesdone); | ||
485 | samplesdone=fc.samplenumber+fc.blocksize; | ||
486 | elapsedtime=(samplesdone*10)/(ci->id3->frequency/100); | ||
487 | ci->set_elapsed(elapsedtime); | ||
488 | |||
489 | /* The main decoding loop */ | ||
490 | frame=0; | ||
491 | buf = ci->request_buffer(&bytesleft, MAX_FRAMESIZE); | ||
492 | while (bytesleft) { | ||
493 | enum codec_command_action action = ci->get_command(¶m); | ||
494 | |||
495 | if (action == CODEC_ACTION_HALT) | ||
496 | break; | ||
497 | |||
498 | /* Deal with any pending seek requests */ | ||
499 | if (action == CODEC_ACTION_SEEK_TIME) { | ||
500 | if (flac_seek(&fc,(uint32_t)(((uint64_t)param | ||
501 | *ci->id3->frequency)/1000))) { | ||
502 | /* Refill the input buffer */ | ||
503 | buf = ci->request_buffer(&bytesleft, MAX_FRAMESIZE); | ||
504 | } | ||
505 | |||
506 | ci->set_elapsed(param); | ||
507 | ci->seek_complete(); | ||
508 | } | ||
509 | |||
510 | if((res=flac_decode_frame(&fc,buf, | ||
511 | bytesleft,ci->yield)) < 0) { | ||
512 | LOGF("FLAC: Frame %d, error %d\n",frame,res); | ||
513 | return CODEC_ERROR; | ||
514 | } | ||
515 | consumed=fc.gb.index/8; | ||
516 | frame++; | ||
517 | |||
518 | ci->yield(); | ||
519 | ci->pcmbuf_insert(&fc.decoded[0][fc.sample_skip], &fc.decoded[1][fc.sample_skip], | ||
520 | fc.blocksize - fc.sample_skip); | ||
521 | |||
522 | fc.sample_skip = 0; | ||
523 | |||
524 | /* Update the elapsed-time indicator */ | ||
525 | samplesdone=fc.samplenumber+fc.blocksize; | ||
526 | elapsedtime=(samplesdone*10)/(ci->id3->frequency/100); | ||
527 | ci->set_elapsed(elapsedtime); | ||
528 | |||
529 | ci->advance_buffer(consumed); | ||
530 | |||
531 | buf = ci->request_buffer(&bytesleft, MAX_FRAMESIZE); | ||
532 | } | ||
533 | |||
534 | LOGF("FLAC: Decoded %lu samples\n",(unsigned long)samplesdone); | ||
535 | return CODEC_OK; | ||
536 | } | ||