diff options
Diffstat (limited to 'apps/codecs/flac.c')
-rw-r--r-- | apps/codecs/flac.c | 405 |
1 files changed, 124 insertions, 281 deletions
diff --git a/apps/codecs/flac.c b/apps/codecs/flac.c index 45fc21466c..b9a3a8a249 100644 --- a/apps/codecs/flac.c +++ b/apps/codecs/flac.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id$ | 8 | * $Id$ |
9 | * | 9 | * |
10 | * Copyright (C) 2002 Björn Stenberg | 10 | * Copyright (C) 2005 Dave Chapman |
11 | * | 11 | * |
12 | * All files in this archive are subject to the GNU General Public License. | 12 | * All files in this archive are subject to the GNU General Public License. |
13 | * See the file COPYING in the source tree root for full license agreement. | 13 | * See the file COPYING in the source tree root for full license agreement. |
@@ -18,156 +18,7 @@ | |||
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | 19 | ||
20 | #include "codeclib.h" | 20 | #include "codeclib.h" |
21 | #include <codecs/libFLAC/include/FLAC/seekable_stream_decoder.h> | 21 | #include <codecs/libffmpegFLAC/decoder.h> |
22 | #include <codecs/libFLAC/include/FLAC/format.h> | ||
23 | #include <codecs/libFLAC/include/FLAC/metadata.h> | ||
24 | |||
25 | #define FLAC_MAX_SUPPORTED_BLOCKSIZE 4608 | ||
26 | #define FLAC_MAX_SUPPORTED_CHANNELS 2 | ||
27 | |||
28 | static uint32_t samplesdone; | ||
29 | |||
30 | static FLAC__StreamMetadata *stream_info; | ||
31 | static FLAC__StreamMetadata *seek_table; | ||
32 | unsigned int metadata_length; | ||
33 | |||
34 | /* Called when the FLAC decoder needs some FLAC data to decode */ | ||
35 | FLAC__SeekableStreamDecoderReadStatus flac_read_handler(const FLAC__SeekableStreamDecoder *dec, | ||
36 | FLAC__byte buffer[], unsigned *bytes, void *data) | ||
37 | { | ||
38 | struct codec_api* ci = (struct codec_api*)data; | ||
39 | (void)dec; | ||
40 | |||
41 | *bytes=(unsigned)(ci->read_filebuf(buffer,*bytes)); | ||
42 | |||
43 | if (*bytes==0) { | ||
44 | return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; | ||
45 | } else { | ||
46 | return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; | ||
47 | } | ||
48 | } | ||
49 | |||
50 | static unsigned char pcmbuf[FLAC_MAX_SUPPORTED_BLOCKSIZE*FLAC_MAX_SUPPORTED_CHANNELS*2] IDATA_ATTR; | ||
51 | |||
52 | /* Called when the FLAC decoder has some decoded PCM data to write */ | ||
53 | FLAC__StreamDecoderWriteStatus flac_write_handler(const FLAC__SeekableStreamDecoder *dec, | ||
54 | const FLAC__Frame *frame, | ||
55 | const FLAC__int32 * const buf[], | ||
56 | void *data) | ||
57 | { | ||
58 | struct codec_api* ci = (struct codec_api*)data; | ||
59 | (void)dec; | ||
60 | unsigned int c_samp, c_chan, d_samp; | ||
61 | uint32_t data_size = frame->header.blocksize * frame->header.channels * 2; /* Assume 16-bit words */ | ||
62 | uint32_t samples = frame->header.blocksize; | ||
63 | int yieldcounter = 0; | ||
64 | |||
65 | |||
66 | if (samples*frame->header.channels > (FLAC_MAX_SUPPORTED_BLOCKSIZE*FLAC_MAX_SUPPORTED_CHANNELS)) { | ||
67 | // ERROR!!! | ||
68 | // DEBUGF("ERROR: samples*frame->header.channels=%d\n",samples*frame->header.channels); | ||
69 | return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; | ||
70 | } | ||
71 | |||
72 | (void)dec; | ||
73 | for (c_samp = d_samp = 0; c_samp < samples; c_samp++) { | ||
74 | for(c_chan = 0; c_chan < frame->header.channels; c_chan++, d_samp++) { | ||
75 | pcmbuf[d_samp*2] = (buf[c_chan][c_samp]&0xff00)>>8; | ||
76 | pcmbuf[(d_samp*2)+1] = buf[c_chan][c_samp]&0xff; | ||
77 | if (yieldcounter++ == 100) { | ||
78 | ci->yield(); | ||
79 | yieldcounter = 0; | ||
80 | } | ||
81 | } | ||
82 | } | ||
83 | |||
84 | samplesdone+=samples; | ||
85 | ci->set_elapsed(samplesdone/(ci->id3->frequency/1000)); | ||
86 | |||
87 | ci->yield(); | ||
88 | while (!ci->pcmbuf_insert(pcmbuf, data_size)) | ||
89 | ci->yield(); | ||
90 | |||
91 | return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; | ||
92 | } | ||
93 | |||
94 | void flac_metadata_handler(const FLAC__SeekableStreamDecoder *dec, | ||
95 | const FLAC__StreamMetadata *meta, void *data) | ||
96 | { | ||
97 | /* Ignore metadata for now... */ | ||
98 | (void)dec; | ||
99 | (void)data; | ||
100 | |||
101 | metadata_length += meta->length; | ||
102 | |||
103 | if ( meta->type == FLAC__METADATA_TYPE_STREAMINFO ) { | ||
104 | stream_info = FLAC__metadata_object_clone( meta ); | ||
105 | if ( stream_info == NULL ) { | ||
106 | //return CODEC_ERROR; | ||
107 | } | ||
108 | } else if ( meta->type == FLAC__METADATA_TYPE_SEEKTABLE ) { | ||
109 | seek_table = FLAC__metadata_object_clone( meta ); | ||
110 | if ( seek_table == NULL ) { | ||
111 | //return CODEC_ERROR; | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | |||
116 | |||
117 | void flac_error_handler(const FLAC__SeekableStreamDecoder *dec, | ||
118 | FLAC__StreamDecoderErrorStatus status, void *data) | ||
119 | { | ||
120 | (void)dec; | ||
121 | (void)status; | ||
122 | (void)data; | ||
123 | } | ||
124 | |||
125 | FLAC__SeekableStreamDecoderSeekStatus flac_seek_handler(const FLAC__SeekableStreamDecoder *decoder, | ||
126 | FLAC__uint64 absolute_byte_offset, | ||
127 | void *client_data) | ||
128 | { | ||
129 | (void)decoder; | ||
130 | struct codec_api* ci = (struct codec_api*)client_data; | ||
131 | |||
132 | if (ci->seek_buffer(absolute_byte_offset)) { | ||
133 | return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK; | ||
134 | } else { | ||
135 | return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR; | ||
136 | } | ||
137 | } | ||
138 | |||
139 | FLAC__SeekableStreamDecoderTellStatus flac_tell_handler(const FLAC__SeekableStreamDecoder *decoder, | ||
140 | FLAC__uint64 *absolute_byte_offset, void *client_data) | ||
141 | { | ||
142 | struct codec_api* ci = (struct codec_api*)client_data; | ||
143 | |||
144 | (void)decoder; | ||
145 | *absolute_byte_offset = ci->curpos; | ||
146 | return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK; | ||
147 | } | ||
148 | |||
149 | FLAC__SeekableStreamDecoderLengthStatus flac_length_handler(const FLAC__SeekableStreamDecoder *decoder, | ||
150 | FLAC__uint64 *stream_length, void *client_data) | ||
151 | { | ||
152 | struct codec_api* ci = (struct codec_api*)client_data; | ||
153 | |||
154 | (void)decoder; | ||
155 | *stream_length = ci->filesize; | ||
156 | return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK; | ||
157 | } | ||
158 | |||
159 | FLAC__bool flac_eof_handler(const FLAC__SeekableStreamDecoder *decoder, | ||
160 | void *client_data) | ||
161 | { | ||
162 | struct codec_api* ci = (struct codec_api*)client_data; | ||
163 | |||
164 | (void)decoder; | ||
165 | if (ci->curpos >= ci->filesize) { | ||
166 | return true; | ||
167 | } else { | ||
168 | return false; | ||
169 | } | ||
170 | } | ||
171 | 22 | ||
172 | #ifndef SIMULATOR | 23 | #ifndef SIMULATOR |
173 | extern char iramcopy[]; | 24 | extern char iramcopy[]; |
@@ -175,78 +26,101 @@ extern char iramstart[]; | |||
175 | extern char iramend[]; | 26 | extern char iramend[]; |
176 | #endif | 27 | #endif |
177 | 28 | ||
178 | FLAC__uint64 find_sample_number(struct codec_api *ci, size_t offset) | 29 | struct codec_api* rb; |
30 | struct codec_api* ci; | ||
31 | |||
32 | /* The output buffers containing the decoded samples (channels 0 and 1) */ | ||
33 | int32_t decoded0[MAX_BLOCKSIZE] IBSS_ATTR; | ||
34 | int32_t decoded1[MAX_BLOCKSIZE] IBSS_ATTR; | ||
35 | |||
36 | static bool flac_init(FLACContext* fc) | ||
179 | { | 37 | { |
180 | FLAC__StreamMetadata_SeekPoint *points; | 38 | unsigned char buf[255]; |
181 | FLAC__uint64 prev_sample, next_sample; | 39 | bool found_streaminfo=false; |
182 | size_t prev_offset, next_offset; | 40 | int endofmetadata=0; |
183 | int percent; | 41 | int blocklength; |
184 | 42 | ||
185 | if (offset >= (ci->id3->filesize - metadata_length)) { | 43 | if (ci->read_filebuf(buf, 4) < 4) |
186 | return stream_info->data.stream_info.total_samples; | 44 | { |
45 | return false; | ||
187 | } | 46 | } |
188 | 47 | ||
189 | prev_offset = 0; | 48 | if (ci->memcmp(buf,"fLaC",4) != 0) |
190 | prev_sample = 0; | 49 | { |
191 | next_offset = ci->id3->filesize - metadata_length; | 50 | return false; |
192 | next_sample = stream_info->data.stream_info.total_samples; | 51 | } |
193 | 52 | fc->metadatalength = 4; | |
194 | if (seek_table) { | ||
195 | int left, right, middle; | ||
196 | 53 | ||
197 | middle = 0; /* Silence compiler warnings */ | 54 | while (!endofmetadata) { |
198 | points = seek_table->data.seek_table.points; | 55 | if (ci->read_filebuf(buf, 4) < 4) |
199 | left = 0; | 56 | { |
200 | right = seek_table->data.seek_table.num_points - 1; | 57 | return false; |
58 | } | ||
201 | 59 | ||
202 | /* Do a binary search to find the matching seek point */ | 60 | endofmetadata=(buf[0]&0x80); |
203 | while (left <= right) { | 61 | blocklength = (buf[1] << 16) | (buf[2] << 8) | buf[3]; |
204 | middle = (left + right) / 2; | 62 | fc->metadatalength+=blocklength+4; |
205 | 63 | ||
206 | if ((FLAC__uint64)offset < points[middle].stream_offset) { | 64 | if ((buf[0] & 0x7f) == 0) /* 0 is the STREAMINFO block */ |
207 | right = middle - 1; | 65 | { |
208 | } else if ((FLAC__uint64)offset > points[middle].stream_offset) { | 66 | /* FIXME: Don't trust the value of blocklength */ |
209 | left = middle + 1; | 67 | if (ci->read_filebuf(buf, blocklength) < 0) |
210 | } else { | 68 | { |
211 | return points[middle].sample_number; | 69 | return false; |
212 | } | 70 | } |
213 | } | 71 | |
214 | 72 | fc->filesize = ci->filesize; | |
215 | /* Didn't find a matching seek point, so get the sample numbers of the | 73 | fc->min_blocksize = (buf[0] << 8) | buf[1]; |
216 | * seek points to the left and right of offset to make our guess more | 74 | fc->max_blocksize = (buf[2] << 8) | buf[3]; |
217 | * accurate. Accuracy depends on how close these sample numbers are to | 75 | fc->min_framesize = (buf[4] << 16) | (buf[5] << 8) | buf[6]; |
218 | * each other. | 76 | fc->max_framesize = (buf[7] << 16) | (buf[8] << 8) | buf[9]; |
219 | */ | 77 | fc->samplerate = (buf[10] << 12) | (buf[11] << 4) |
220 | if ((unsigned)left >= seek_table->data.seek_table.num_points) { | 78 | | ((buf[12] & 0xf0) >> 4); |
221 | prev_offset = points[middle].stream_offset; | 79 | fc->channels = ((buf[12]&0x0e)>>1) + 1; |
222 | prev_sample = points[middle].sample_number; | 80 | fc->bps = (((buf[12]&0x01) << 4) | ((buf[13]&0xf0)>>4) ) + 1; |
223 | } else if (right < 0) { | 81 | |
224 | next_offset = points[middle].stream_offset; | 82 | /* totalsamples is a 36-bit field, but we assume <= 32 bits are |
225 | next_sample = points[middle].sample_number; | 83 | used */ |
84 | fc->totalsamples = (buf[14] << 24) | (buf[15] << 16) | ||
85 | | (buf[16] << 8) | buf[17]; | ||
86 | |||
87 | /* Calculate track length (in ms) and estimate the bitrate | ||
88 | (in kbit/s) */ | ||
89 | fc->length = (fc->totalsamples / fc->samplerate) * 1000; | ||
90 | |||
91 | found_streaminfo=true; | ||
92 | } else if ((buf[0] & 0x7f) == 3) { /* 3 is the SEEKTABLE block */ | ||
93 | ci->advance_buffer(blocklength); | ||
226 | } else { | 94 | } else { |
227 | middle--; | 95 | /* Skip to next metadata block */ |
228 | prev_offset = points[middle].stream_offset; | 96 | ci->advance_buffer(blocklength); |
229 | prev_sample = points[middle].sample_number; | ||
230 | next_offset = points[middle+1].stream_offset; | ||
231 | next_sample = points[middle+1].sample_number; | ||
232 | } | 97 | } |
233 | } | 98 | } |
234 | 99 | ||
235 | /* Either there's no seek table or we didn't find our seek point, so now we | 100 | if (found_streaminfo) { |
236 | * have to guess. | 101 | fc->bitrate = ((fc->filesize-fc->metadatalength) * 8) / fc->length; |
237 | */ | 102 | return true; |
238 | percent = ((offset - prev_offset) * 100) / (next_offset - prev_offset); | 103 | } else { |
239 | return (FLAC__uint64)(percent * (next_sample - prev_sample) / 100 + prev_sample); | 104 | return false; |
105 | } | ||
240 | } | 106 | } |
241 | 107 | ||
242 | /* this is the codec entry point */ | 108 | /* this is the codec entry point */ |
243 | enum codec_status codec_start(struct codec_api* api) | 109 | enum codec_status codec_start(struct codec_api* api) |
244 | { | 110 | { |
245 | struct codec_api* ci = api; | 111 | size_t n; |
246 | FLAC__SeekableStreamDecoder* flacDecoder; | 112 | static int8_t buf[MAX_FRAMESIZE]; |
247 | FLAC__uint64 offset; | 113 | FLACContext fc; |
114 | uint32_t samplesdone; | ||
115 | uint32_t elapsedtime; | ||
116 | int bytesleft; | ||
117 | int consumed; | ||
248 | 118 | ||
249 | TEST_CODEC_API(ci); | 119 | /* Generic codec initialisation */ |
120 | TEST_CODEC_API(api); | ||
121 | |||
122 | rb = api; | ||
123 | ci = (struct codec_api*)api; | ||
250 | 124 | ||
251 | #ifndef SIMULATOR | 125 | #ifndef SIMULATOR |
252 | ci->memcpy(iramstart, iramcopy, iramend-iramstart); | 126 | ci->memcpy(iramstart, iramcopy, iramend-iramstart); |
@@ -254,19 +128,17 @@ enum codec_status codec_start(struct codec_api* api) | |||
254 | 128 | ||
255 | ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*10)); | 129 | ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*10)); |
256 | ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); | 130 | ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); |
257 | ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*1024)); | 131 | ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128)); |
258 | 132 | ||
259 | ci->configure(CODEC_DSP_ENABLE, (bool *)true); | 133 | ci->configure(CODEC_DSP_ENABLE, (bool *)true); |
260 | ci->configure(DSP_DITHER, (bool *)false); | 134 | ci->configure(DSP_DITHER, (bool *)false); |
261 | ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED); | 135 | ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED); |
262 | ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(16)); | 136 | ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(28)); |
263 | 137 | ||
264 | next_track: | 138 | next_track: |
265 | metadata_length = 0; | ||
266 | seek_table = NULL; | ||
267 | stream_info = NULL; | ||
268 | 139 | ||
269 | if (codec_init(api)) { | 140 | if (!flac_init(&fc)) { |
141 | LOGF("FLAC: Error initialising codec\n"); | ||
270 | return CODEC_ERROR; | 142 | return CODEC_ERROR; |
271 | } | 143 | } |
272 | 144 | ||
@@ -274,87 +146,58 @@ next_track: | |||
274 | ci->yield(); | 146 | ci->yield(); |
275 | 147 | ||
276 | ci->configure(DSP_SET_FREQUENCY, (long *)(ci->id3->frequency)); | 148 | ci->configure(DSP_SET_FREQUENCY, (long *)(ci->id3->frequency)); |
277 | codec_set_replaygain(ci->id3); | ||
278 | |||
279 | /* Create a decoder instance */ | ||
280 | flacDecoder = FLAC__seekable_stream_decoder_new(); | ||
281 | 149 | ||
282 | /* Set up the decoder and the callback functions - this must be done before init */ | 150 | /* The main decoding loop */ |
283 | 151 | bytesleft=ci->read_filebuf(buf,sizeof(buf)); | |
284 | /* The following are required for stream_decoder and higher */ | 152 | while (bytesleft) { |
285 | FLAC__seekable_stream_decoder_set_client_data(flacDecoder,ci); | ||
286 | FLAC__seekable_stream_decoder_set_write_callback(flacDecoder, flac_write_handler); | ||
287 | FLAC__seekable_stream_decoder_set_read_callback(flacDecoder, flac_read_handler); | ||
288 | FLAC__seekable_stream_decoder_set_metadata_callback(flacDecoder, flac_metadata_handler); | ||
289 | FLAC__seekable_stream_decoder_set_error_callback(flacDecoder, flac_error_handler); | ||
290 | FLAC__seekable_stream_decoder_set_metadata_respond_all(flacDecoder); | ||
291 | |||
292 | /* The following are only for the seekable_stream_decoder */ | ||
293 | FLAC__seekable_stream_decoder_set_seek_callback(flacDecoder, flac_seek_handler); | ||
294 | FLAC__seekable_stream_decoder_set_tell_callback(flacDecoder, flac_tell_handler); | ||
295 | FLAC__seekable_stream_decoder_set_length_callback(flacDecoder, flac_length_handler); | ||
296 | FLAC__seekable_stream_decoder_set_eof_callback(flacDecoder, flac_eof_handler); | ||
297 | |||
298 | |||
299 | /* QUESTION: What do we do when the init fails? */ | ||
300 | if (FLAC__seekable_stream_decoder_init(flacDecoder)) { | ||
301 | return CODEC_ERROR; | ||
302 | } | ||
303 | |||
304 | /* The first thing to do is to parse the metadata */ | ||
305 | FLAC__seekable_stream_decoder_process_until_end_of_metadata(flacDecoder); | ||
306 | |||
307 | if (ci->id3->offset && stream_info) { | ||
308 | FLAC__uint64 sample; | ||
309 | |||
310 | sample = find_sample_number(ci, ci->id3->offset - metadata_length); | ||
311 | ci->advance_buffer(ci->id3->offset); | ||
312 | FLAC__seekable_stream_decoder_seek_absolute(flacDecoder, sample); | ||
313 | FLAC__seekable_stream_decoder_get_decode_position(flacDecoder, &offset); | ||
314 | ci->set_offset(offset); | ||
315 | samplesdone = (uint32_t)sample; | ||
316 | ci->set_elapsed(sample/(ci->id3->frequency/1000)); | ||
317 | } else { | ||
318 | samplesdone = 0; | ||
319 | ci->set_elapsed(0); | ||
320 | } | ||
321 | |||
322 | /* The main decoder loop */ | ||
323 | while (FLAC__seekable_stream_decoder_get_state(flacDecoder) != FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) { | ||
324 | ci->yield(); | 153 | ci->yield(); |
325 | if (ci->stop_codec || ci->reload_codec) { | 154 | if (ci->stop_codec || ci->reload_codec) { |
326 | break; | 155 | break; |
327 | } | 156 | } |
328 | 157 | ||
158 | /* Deal with any pending seek requests */ | ||
329 | if (ci->seek_time) { | 159 | if (ci->seek_time) { |
330 | int sample_loc; | 160 | /* We only support seeking to start of track at the moment */ |
161 | if (ci->seek_time==1) { | ||
162 | if (ci->seek_buffer(fc.metadatalength)) { | ||
163 | /* Refill the input buffer */ | ||
164 | bytesleft=ci->read_filebuf(buf,sizeof(buf)); | ||
165 | ci->set_elapsed(0); | ||
166 | } | ||
167 | } | ||
168 | ci->seek_time = 0; | ||
169 | } | ||
331 | 170 | ||
332 | sample_loc = ci->seek_time/1000 * ci->id3->frequency; | 171 | if(flac_decode_frame(&fc,decoded0,decoded1,buf, |
333 | if (FLAC__seekable_stream_decoder_seek_absolute(flacDecoder, sample_loc)) { | 172 | bytesleft,ci->yield) < 0) { |
334 | samplesdone = sample_loc; | 173 | LOGF("FLAC: Decode error, aborting\n"); |
335 | ci->set_elapsed(samplesdone/(ci->id3->frequency/1000)); | 174 | return CODEC_ERROR; |
336 | } | ||
337 | ci->seek_time = 0; | ||
338 | } | 175 | } |
176 | consumed=fc.gb.index/8; | ||
339 | 177 | ||
340 | FLAC__seekable_stream_decoder_process_single(flacDecoder); | 178 | ci->yield(); |
341 | FLAC__seekable_stream_decoder_get_decode_position(flacDecoder, &offset); | 179 | while(!ci->pcmbuf_insert_split((char*)decoded0,(char*)decoded1, |
342 | ci->set_offset(offset); | 180 | fc.blocksize*4)) { |
343 | } | 181 | ci->yield(); |
182 | } | ||
344 | 183 | ||
345 | /* Flush the libFLAC buffers */ | 184 | /* Update the elapsed-time indicator */ |
346 | FLAC__seekable_stream_decoder_finish(flacDecoder); | 185 | samplesdone=fc.samplenumber+fc.blocksize; |
186 | elapsedtime=(samplesdone*10)/(ci->id3->frequency/100); | ||
187 | ci->set_elapsed(elapsedtime); | ||
347 | 188 | ||
348 | if (ci->request_next_track()) { | 189 | memmove(buf,&buf[consumed],bytesleft-consumed); |
349 | if (stream_info) { | 190 | bytesleft-=consumed; |
350 | FLAC__metadata_object_delete(stream_info); | 191 | |
351 | } | 192 | n=ci->read_filebuf(&buf[bytesleft],sizeof(buf)-bytesleft); |
352 | if (seek_table) { | 193 | if (n > 0) { |
353 | FLAC__metadata_object_delete(seek_table); | 194 | bytesleft+=n; |
354 | } | 195 | } |
355 | metadata_length = 0; | ||
356 | goto next_track; | ||
357 | } | 196 | } |
197 | LOGF("FLAC: Decoded %d samples\n",samplesdone); | ||
198 | |||
199 | if (ci->request_next_track()) | ||
200 | goto next_track; | ||
358 | 201 | ||
359 | return CODEC_OK; | 202 | return CODEC_OK; |
360 | } | 203 | } |