summaryrefslogtreecommitdiff
path: root/apps/codecs
diff options
context:
space:
mode:
authorMagnus Holmgren <magnushol@gmail.com>2006-10-11 17:02:23 +0000
committerMagnus Holmgren <magnushol@gmail.com>2006-10-11 17:02:23 +0000
commit9896fd1adef70e77b2e226d5e44fabd23192266d (patch)
treeb006fed80eadb14e1d8849b8a4cc01263bbc47c2 /apps/codecs
parentca3d872699d56905c7edf875fdec80472c832942 (diff)
downloadrockbox-9896fd1adef70e77b2e226d5e44fabd23192266d.tar.gz
rockbox-9896fd1adef70e77b2e226d5e44fabd23192266d.zip
AAC codec: Improved MP4 file parsing. Should now handle most streamable files. Also some code cleanup and policing.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11187 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs')
-rw-r--r--apps/codecs/aac.c129
-rw-r--r--apps/codecs/libm4a/demux.c155
-rw-r--r--apps/codecs/libm4a/m4a.c380
-rw-r--r--apps/codecs/libm4a/m4a.h32
4 files changed, 448 insertions, 248 deletions
diff --git a/apps/codecs/aac.c b/apps/codecs/aac.c
index 6c86f38372..0c48422a53 100644
--- a/apps/codecs/aac.c
+++ b/apps/codecs/aac.c
@@ -29,6 +29,8 @@ CODEC_HEADER
29extern char iramcopy[]; 29extern char iramcopy[];
30extern char iramstart[]; 30extern char iramstart[];
31extern char iramend[]; 31extern char iramend[];
32extern char iedata[];
33extern char iend[];
32#endif 34#endif
33 35
34struct codec_api* rb; 36struct codec_api* rb;
@@ -37,27 +39,35 @@ struct codec_api* ci;
37/* this is the codec entry point */ 39/* this is the codec entry point */
38enum codec_status codec_start(struct codec_api* api) 40enum codec_status codec_start(struct codec_api* api)
39{ 41{
42 /* Note that when dealing with QuickTime/MPEG4 files, terminology is
43 * a bit confusing. Files with sound are split up in chunks, where
44 * each chunk contains one or more samples. Each sample in turn
45 * contains a number of "sound samples" (the kind you refer to with
46 * the sampling frequency).
47 */
40 size_t n; 48 size_t n;
41 static demux_res_t demux_res; 49 static demux_res_t demux_res;
42 stream_t input_stream; 50 stream_t input_stream;
43 uint32_t samplesdone; 51 uint32_t sound_samples_done;
44 uint32_t elapsedtime; 52 uint32_t elapsed_time;
45 uint32_t sample_duration; 53 uint32_t sample_duration;
46 uint32_t sample_byte_size; 54 uint32_t sample_byte_size;
47 int samplesdecoded; 55 int file_offset;
48 unsigned int i; 56 unsigned int i;
49 unsigned char* buffer; 57 unsigned char* buffer;
50 static NeAACDecFrameInfo frameInfo; 58 static NeAACDecFrameInfo frame_info;
51 NeAACDecHandle hDecoder; 59 NeAACDecHandle decoder;
52 int err; 60 int err;
53 int16_t* decodedbuffer; 61 uint32_t s = 0;
62 unsigned char c = 0;
54 63
55 /* Generic codec initialisation */ 64 /* Generic codec initialisation */
56 rb = api; 65 rb = api;
57 ci = api; 66 ci = api;
58 67
59#ifndef SIMULATOR 68#ifndef SIMULATOR
60 rb->memcpy(iramstart, iramcopy, iramend-iramstart); 69 ci->memcpy(iramstart, iramcopy, iramend-iramstart);
70 ci->memset(iedata, 0, iend - iedata);
61#endif 71#endif
62 72
63 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*16)); 73 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*16));
@@ -68,9 +78,10 @@ enum codec_status codec_start(struct codec_api* api)
68 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(29)); 78 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(29));
69 79
70next_track: 80next_track:
81 err = CODEC_OK;
71 82
72 if (codec_init(api)) { 83 if (codec_init(api)) {
73 LOGF("FAAD: Error initialising codec\n"); 84 LOGF("FAAD: Codec init error\n");
74 err = CODEC_ERROR; 85 err = CODEC_ERROR;
75 goto exit; 86 goto exit;
76 } 87 }
@@ -78,7 +89,7 @@ next_track:
78 while (!*ci->taginfo_ready && !ci->stop_codec) 89 while (!*ci->taginfo_ready && !ci->stop_codec)
79 ci->sleep(1); 90 ci->sleep(1);
80 91
81 samplesdone = ci->id3->offset; 92 sound_samples_done = ci->id3->offset;
82 93
83 ci->configure(DSP_SET_FREQUENCY, (long *)(rb->id3->frequency)); 94 ci->configure(DSP_SET_FREQUENCY, (long *)(rb->id3->frequency));
84 95
@@ -87,52 +98,49 @@ next_track:
87 /* if qtmovie_read returns successfully, the stream is up to 98 /* if qtmovie_read returns successfully, the stream is up to
88 * the movie data, which can be used directly by the decoder */ 99 * the movie data, which can be used directly by the decoder */
89 if (!qtmovie_read(&input_stream, &demux_res)) { 100 if (!qtmovie_read(&input_stream, &demux_res)) {
90 LOGF("FAAD: Error initialising file\n"); 101 LOGF("FAAD: File init error\n");
91 err = CODEC_ERROR; 102 err = CODEC_ERROR;
92 goto done; 103 goto done;
93 } 104 }
94 105
95 /* initialise the sound converter */ 106 /* initialise the sound converter */
96 hDecoder = NULL; 107 decoder = NeAACDecOpen();
97 hDecoder = NeAACDecOpen();
98 108
99 if (!hDecoder) { 109 if (!decoder) {
100 LOGF("FAAD: Error opening decoder\n"); 110 LOGF("FAAD: Decode open error\n");
101 err = CODEC_ERROR; 111 err = CODEC_ERROR;
102 goto done; 112 goto done;
103 } 113 }
104 114
105 NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(hDecoder); 115 NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder);
106 conf->outputFormat = FAAD_FMT_24BIT; /* irrelevant, we don't convert */ 116 conf->outputFormat = FAAD_FMT_24BIT; /* irrelevant, we don't convert */
107 NeAACDecSetConfiguration(hDecoder, conf); 117 NeAACDecSetConfiguration(decoder, conf);
108
109 uint32_t s=0;
110 unsigned char c=0;
111 118
112 err = NeAACDecInit2(hDecoder, demux_res.codecdata,demux_res.codecdata_len, &s, &c); 119 err = NeAACDecInit2(decoder, demux_res.codecdata, demux_res.codecdata_len, &s, &c);
113 if (err) { 120 if (err) {
114 LOGF("FAAD: Error initialising decoder: %d, type=%d\n", err,hDecoder->object_type); 121 LOGF("FAAD: DecInit: %d, %d\n", err, decoder->object_type);
115 err = CODEC_ERROR; 122 err = CODEC_ERROR;
116 goto done; 123 goto done;
117 } 124 }
118 125
119 ci->id3->frequency=s; 126 ci->id3->frequency = s;
120 127
121 i=0; 128 i = 0;
122 129
123 if (samplesdone > 0) { 130 if (sound_samples_done > 0) {
124 if (alac_seek_raw(&demux_res, &input_stream, samplesdone, 131 if (alac_seek_raw(&demux_res, &input_stream, sound_samples_done,
125 &samplesdone, (int *)&i)) { 132 &sound_samples_done, (int*) &i)) {
126 elapsedtime=(samplesdone*10)/(ci->id3->frequency/100); 133 elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100);
127 ci->set_elapsed(elapsedtime); 134 ci->set_elapsed(elapsed_time);
128 } else { 135 } else {
129 samplesdone=0; 136 sound_samples_done = 0;
130 } 137 }
131 } 138 }
132 139
133 /* The main decoding loop */ 140 /* The main decoding loop */
134 while (i < demux_res.num_sample_byte_sizes) { 141 while (i < demux_res.num_sample_byte_sizes) {
135 rb->yield(); 142 rb->yield();
143
136 if (ci->stop_codec || ci->new_track) { 144 if (ci->stop_codec || ci->new_track) {
137 break; 145 break;
138 } 146 }
@@ -140,10 +148,10 @@ next_track:
140 /* Deal with any pending seek requests */ 148 /* Deal with any pending seek requests */
141 if (ci->seek_time) { 149 if (ci->seek_time) {
142 if (alac_seek(&demux_res, &input_stream, 150 if (alac_seek(&demux_res, &input_stream,
143 ((ci->seek_time-1)/10) * (ci->id3->frequency/100), 151 ((ci->seek_time-1)/10)*(ci->id3->frequency/100),
144 &samplesdone, (int *)&i)) { 152 &sound_samples_done, (int*) &i)) {
145 elapsedtime=(samplesdone*10)/(ci->id3->frequency/100); 153 elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100);
146 ci->set_elapsed(elapsedtime); 154 ci->set_elapsed(elapsed_time);
147 } 155 }
148 ci->seek_complete(); 156 ci->seek_complete();
149 } 157 }
@@ -151,52 +159,65 @@ next_track:
151 /* Lookup the length (in samples and bytes) of block i */ 159 /* Lookup the length (in samples and bytes) of block i */
152 if (!get_sample_info(&demux_res, i, &sample_duration, 160 if (!get_sample_info(&demux_res, i, &sample_duration,
153 &sample_byte_size)) { 161 &sample_byte_size)) {
154 LOGF("AAC: Error in get_sample_info\n"); 162 LOGF("AAC: get_sample_info error\n");
155 err = CODEC_ERROR; 163 err = CODEC_ERROR;
156 goto done; 164 goto done;
157 } 165 }
158 166
167 /* There can be gaps between chunks, so skip ahead if needed. It
168 * doesn't seem to happen much, but it probably means that a
169 * "proper" file can have chunks out of order. Why one would want
170 * that an good question (but files with gaps do exist, so who
171 * knows?), so we don't support that - for now, at least.
172 */
173 file_offset = get_sample_offset(&demux_res, i);
174
175 if (file_offset > ci->curpos)
176 {
177 ci->advance_buffer(file_offset - ci->curpos);
178 }
179
159 /* Request the required number of bytes from the input buffer */ 180 /* Request the required number of bytes from the input buffer */
160 buffer=ci->request_buffer(&n,sample_byte_size); 181 buffer=ci->request_buffer(&n,sample_byte_size);
161 182
162 /* Decode one block - returned samples will be host-endian */ 183 /* Decode one block - returned samples will be host-endian */
163 rb->yield(); 184 NeAACDecDecode(decoder, &frame_info, buffer, n);
164 decodedbuffer = NeAACDecDecode(hDecoder, &frameInfo, buffer, n); 185 /* Ignore return value, we access samples in the decoder struct
165 /* ignore decodedbuffer return value, we access samples in the 186 * directly.
166 decoder struct directly */ 187 */
167 if (frameInfo.error > 0) { 188 if (frame_info.error > 0) {
168 LOGF("FAAD: decoding error \"%s\"\n", NeAACDecGetErrorMessage(frameInfo.error)); 189 LOGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error));
169 err = CODEC_ERROR; 190 err = CODEC_ERROR;
170 goto done; 191 goto done;
171 } 192 }
172 193
173 /* Get the number of decoded samples */
174 samplesdecoded=frameInfo.samples;
175
176 /* Advance codec buffer */ 194 /* Advance codec buffer */
177 ci->advance_buffer(n); 195 ci->advance_buffer(n);
178 196
179 /* Output the audio */ 197 /* Output the audio */
180 rb->yield(); 198 rb->yield();
181 while (!rb->pcmbuf_insert_split(hDecoder->time_out[0], 199 while (!rb->pcmbuf_insert_split(decoder->time_out[0],
182 hDecoder->time_out[1], 200 decoder->time_out[1],
183 frameInfo.samples*2)) 201 frame_info.samples * 2))
184 rb->yield(); 202 {
203 rb->sleep(1);
204 }
185 205
186 /* Update the elapsed-time indicator */ 206 /* Update the elapsed-time indicator */
187 samplesdone+=sample_duration; 207 sound_samples_done += sample_duration;
188 elapsedtime=(samplesdone*10)/(ci->id3->frequency/100); 208 elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100);
189 ci->set_elapsed(elapsedtime); 209 ci->set_elapsed(elapsed_time);
190 210
191 /* Keep track of current position - for resuming */ 211 /* Keep track of current position - for resuming */
192 ci->set_offset(elapsedtime); 212 ci->set_offset(elapsed_time);
193 213
194 i++; 214 i++;
195 } 215 }
216
196 err = CODEC_OK; 217 err = CODEC_OK;
197 218
198done: 219done:
199 LOGF("AAC: Decoded %d samples\n",samplesdone); 220 LOGF("AAC: Decoded %d samples, %d frames\n", sound_samples_done);
200 221
201 if (ci->request_next_track()) 222 if (ci->request_next_track())
202 goto next_track; 223 goto next_track;
diff --git a/apps/codecs/libm4a/demux.c b/apps/codecs/libm4a/demux.c
index 1beeced8e6..44261fdef6 100644
--- a/apps/codecs/libm4a/demux.c
+++ b/apps/codecs/libm4a/demux.c
@@ -55,12 +55,14 @@ static void read_chunk_ftyp(qtmovie_t *qtmovie, size_t chunk_len)
55{ 55{
56 fourcc_t type; 56 fourcc_t type;
57 uint32_t minor_ver; 57 uint32_t minor_ver;
58 size_t size_remaining = chunk_len - 8; /* FIXME: can't hardcode 8, size may be 64bit */ 58 size_t size_remaining = chunk_len - 8;
59 59
60 type = stream_read_uint32(qtmovie->stream); 60 type = stream_read_uint32(qtmovie->stream);
61 size_remaining-=4; 61 size_remaining-=4;
62 if ((type != MAKEFOURCC('M','4','A',' ')) && 62 if ((type != MAKEFOURCC('M','4','A',' ')) &&
63 (type != MAKEFOURCC('m','p','4','2'))) 63 (type != MAKEFOURCC('m','p','4','2')) &&
64 (type != MAKEFOURCC('3','g','p','6')) &&
65 (type != MAKEFOURCC('q','t',' ',' ')))
64 { 66 {
65 DEBUGF("not M4A file\n"); 67 DEBUGF("not M4A file\n");
66 return; 68 return;
@@ -80,7 +82,7 @@ static void read_chunk_ftyp(qtmovie_t *qtmovie, size_t chunk_len)
80static void read_chunk_tkhd(qtmovie_t *qtmovie, size_t chunk_len) 82static void read_chunk_tkhd(qtmovie_t *qtmovie, size_t chunk_len)
81{ 83{
82 /* don't need anything from here atm, skip */ 84 /* don't need anything from here atm, skip */
83 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 85 size_t size_remaining = chunk_len - 8;
84 86
85 stream_skip(qtmovie->stream, size_remaining); 87 stream_skip(qtmovie->stream, size_remaining);
86} 88}
@@ -88,7 +90,7 @@ static void read_chunk_tkhd(qtmovie_t *qtmovie, size_t chunk_len)
88static void read_chunk_mdhd(qtmovie_t *qtmovie, size_t chunk_len) 90static void read_chunk_mdhd(qtmovie_t *qtmovie, size_t chunk_len)
89{ 91{
90 /* don't need anything from here atm, skip */ 92 /* don't need anything from here atm, skip */
91 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 93 size_t size_remaining = chunk_len - 8;
92 94
93 stream_skip(qtmovie->stream, size_remaining); 95 stream_skip(qtmovie->stream, size_remaining);
94} 96}
@@ -97,7 +99,7 @@ static void read_chunk_mdhd(qtmovie_t *qtmovie, size_t chunk_len)
97static void read_chunk_hdlr(qtmovie_t *qtmovie, size_t chunk_len) 99static void read_chunk_hdlr(qtmovie_t *qtmovie, size_t chunk_len)
98{ 100{
99 fourcc_t comptype, compsubtype; 101 fourcc_t comptype, compsubtype;
100 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 102 size_t size_remaining = chunk_len - 8;
101 103
102 int strlen; 104 int strlen;
103 char str[256] = {0}; 105 char str[256] = {0};
@@ -196,7 +198,6 @@ static bool read_chunk_esds(qtmovie_t *qtmovie, size_t chunk_len)
196 temp=stream_read_int32(qtmovie->stream);//0x15000414 ???? 198 temp=stream_read_int32(qtmovie->stream);//0x15000414 ????
197 maxBitrate = stream_read_int32(qtmovie->stream); 199 maxBitrate = stream_read_int32(qtmovie->stream);
198 avgBitrate = stream_read_int32(qtmovie->stream); 200 avgBitrate = stream_read_int32(qtmovie->stream);
199
200 DEBUGF("audioType=%d, maxBitrate=%d, avgBitrate=%d\n",audioType,maxBitrate,avgBitrate); 201 DEBUGF("audioType=%d, maxBitrate=%d, avgBitrate=%d\n",audioType,maxBitrate,avgBitrate);
201 202
202 /* get and verify DecSpecificInfoTag */ 203 /* get and verify DecSpecificInfoTag */
@@ -224,7 +225,7 @@ static bool read_chunk_stsd(qtmovie_t *qtmovie, size_t chunk_len)
224 unsigned int i; 225 unsigned int i;
225 int j; 226 int j;
226 uint32_t numentries; 227 uint32_t numentries;
227 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 228 size_t size_remaining = chunk_len - 8;
228 229
229 /* version */ 230 /* version */
230 stream_read_uint8(qtmovie->stream); 231 stream_read_uint8(qtmovie->stream);
@@ -247,7 +248,6 @@ static bool read_chunk_stsd(qtmovie_t *qtmovie, size_t chunk_len)
247 for (i = 0; i < numentries; i++) 248 for (i = 0; i < numentries; i++)
248 { 249 {
249 uint32_t entry_size; 250 uint32_t entry_size;
250 uint16_t version;
251 251
252 uint32_t entry_remaining; 252 uint32_t entry_remaining;
253 253
@@ -259,43 +259,20 @@ static bool read_chunk_stsd(qtmovie_t *qtmovie, size_t chunk_len)
259 259
260 /* sound info: */ 260 /* sound info: */
261 261
262 stream_skip(qtmovie->stream, 6); /* reserved */ 262 /* reserved + data reference index + sound version + reserved */
263 entry_remaining -= 6; 263 stream_skip(qtmovie->stream, 6 + 2 + 2 + 6);
264 264 entry_remaining -= 6 + 2 + 2 + 6;
265 version = stream_read_uint16(qtmovie->stream);
266 // if (version != 1)
267 //fprintf(stderr, "unknown version??\n");
268 entry_remaining -= 2;
269
270 /* revision level */
271 stream_read_uint16(qtmovie->stream);
272 /* vendor */
273 stream_read_uint32(qtmovie->stream);
274 entry_remaining -= 6;
275
276 /* EH?? spec doesn't say theres an extra 16 bits here.. but there is! */
277 stream_read_uint16(qtmovie->stream);
278 entry_remaining -= 2;
279 265
280 qtmovie->res->num_channels = stream_read_uint16(qtmovie->stream); 266 qtmovie->res->num_channels = stream_read_uint16(qtmovie->stream);
281 267 qtmovie->res->sound_sample_size = stream_read_uint16(qtmovie->stream);
282 qtmovie->res->sample_size = stream_read_uint16(qtmovie->stream);
283 entry_remaining -= 4; 268 entry_remaining -= 4;
284 269
285 /* compression id */
286 stream_read_uint16(qtmovie->stream);
287 /* packet size */ 270 /* packet size */
288 stream_read_uint16(qtmovie->stream);
289 entry_remaining -= 4;
290
291 /* sample rate - 32bit fixed point = 16bit?? */
292 qtmovie->res->sample_rate = stream_read_uint16(qtmovie->stream);
293 entry_remaining -= 2;
294
295 /* skip 2 */
296 stream_skip(qtmovie->stream, 2); 271 stream_skip(qtmovie->stream, 2);
297 entry_remaining -= 2; 272 qtmovie->res->sound_sample_rate = stream_read_uint32(qtmovie->stream);
298 273 /* reserved size */
274 stream_skip(qtmovie->stream, 2);
275 entry_remaining -= 8;
299 276
300 /* remaining is codec data */ 277 /* remaining is codec data */
301 278
@@ -372,7 +349,7 @@ static void read_chunk_stts(qtmovie_t *qtmovie, size_t chunk_len)
372{ 349{
373 unsigned int i; 350 unsigned int i;
374 uint32_t numentries; 351 uint32_t numentries;
375 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 352 size_t size_remaining = chunk_len - 8;
376 353
377 /* version */ 354 /* version */
378 stream_read_uint8(qtmovie->stream); 355 stream_read_uint8(qtmovie->stream);
@@ -407,7 +384,7 @@ static void read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len)
407{ 384{
408 unsigned int i; 385 unsigned int i;
409 uint32_t numentries; 386 uint32_t numentries;
410 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 387 size_t size_remaining = chunk_len - 8;
411 388
412 /* version */ 389 /* version */
413 stream_read_uint8(qtmovie->stream); 390 stream_read_uint8(qtmovie->stream);
@@ -447,9 +424,73 @@ static void read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len)
447 } 424 }
448} 425}
449 426
427static void read_chunk_stsc(qtmovie_t *qtmovie, size_t chunk_len)
428{
429 unsigned int i;
430 uint32_t numentries;
431 size_t size_remaining = chunk_len - 8;
432
433 /* version + flags */
434 stream_read_uint32(qtmovie->stream);
435 size_remaining -= 4;
436
437 numentries = stream_read_uint32(qtmovie->stream);
438 size_remaining -= 4;
439
440 qtmovie->res->num_sample_to_chunks = numentries;
441 qtmovie->res->sample_to_chunk = malloc(numentries *
442 sizeof(*qtmovie->res->sample_to_chunk));
443
444 for (i = 0; i < numentries; i++)
445 {
446 qtmovie->res->sample_to_chunk[i].first_chunk =
447 stream_read_uint32(qtmovie->stream);
448 qtmovie->res->sample_to_chunk[i].num_samples =
449 stream_read_uint32(qtmovie->stream);
450 stream_read_uint32(qtmovie->stream);
451 size_remaining -= 12;
452 }
453
454 if (size_remaining)
455 {
456 DEBUGF("ehm, size remianing?\n");
457 stream_skip(qtmovie->stream, size_remaining);
458 }
459}
460
461static void read_chunk_stco(qtmovie_t *qtmovie, size_t chunk_len)
462{
463 unsigned int i;
464 uint32_t numentries;
465 size_t size_remaining = chunk_len - 8;
466
467 /* version + flags */
468 stream_read_uint32(qtmovie->stream);
469 size_remaining -= 4;
470
471 numentries = stream_read_uint32(qtmovie->stream);
472 size_remaining -= 4;
473
474 qtmovie->res->num_chunk_offsets = numentries;
475 qtmovie->res->chunk_offset = malloc(numentries *
476 sizeof(*qtmovie->res->chunk_offset));
477
478 for (i = 0; i < numentries; i++)
479 {
480 qtmovie->res->chunk_offset[i] = stream_read_uint32(qtmovie->stream);
481 size_remaining -= 4;
482 }
483
484 if (size_remaining)
485 {
486 DEBUGF("ehm, size remianing?\n");
487 stream_skip(qtmovie->stream, size_remaining);
488 }
489}
490
450static bool read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len) 491static bool read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len)
451{ 492{
452 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 493 size_t size_remaining = chunk_len - 8;
453 494
454 while (size_remaining) 495 while (size_remaining)
455 { 496 {
@@ -479,14 +520,15 @@ static bool read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len)
479 read_chunk_stsz(qtmovie, sub_chunk_len); 520 read_chunk_stsz(qtmovie, sub_chunk_len);
480 break; 521 break;
481 case MAKEFOURCC('s','t','s','c'): 522 case MAKEFOURCC('s','t','s','c'):
523 read_chunk_stsc(qtmovie, sub_chunk_len);
524 break;
482 case MAKEFOURCC('s','t','c','o'): 525 case MAKEFOURCC('s','t','c','o'):
483 /* skip these, no indexing for us! */ 526 read_chunk_stco(qtmovie, sub_chunk_len);
484 stream_skip(qtmovie->stream, sub_chunk_len - 8);
485 break; 527 break;
486 default: 528 default:
487 DEBUGF("(stbl) unknown chunk id: %c%c%c%c\n", 529 DEBUGF("(stbl) unknown chunk id: %c%c%c%c\n",
488 SPLITFOURCC(sub_chunk_id)); 530 SPLITFOURCC(sub_chunk_id));
489 stream_skip(qtmovie->stream, sub_chunk_len - 8); /* FIXME not 8 */ 531 stream_skip(qtmovie->stream, sub_chunk_len - 8);
490 } 532 }
491 533
492 size_remaining -= sub_chunk_len; 534 size_remaining -= sub_chunk_len;
@@ -497,7 +539,7 @@ static bool read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len)
497static bool read_chunk_minf(qtmovie_t *qtmovie, size_t chunk_len) 539static bool read_chunk_minf(qtmovie_t *qtmovie, size_t chunk_len)
498{ 540{
499 size_t dinf_size, stbl_size; 541 size_t dinf_size, stbl_size;
500 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 542 size_t size_remaining = chunk_len - 8;
501 uint32_t i; 543 uint32_t i;
502 544
503 /**** SOUND HEADER CHUNK ****/ 545 /**** SOUND HEADER CHUNK ****/
@@ -553,7 +595,7 @@ static bool read_chunk_minf(qtmovie_t *qtmovie, size_t chunk_len)
553 595
554static bool read_chunk_mdia(qtmovie_t *qtmovie, size_t chunk_len) 596static bool read_chunk_mdia(qtmovie_t *qtmovie, size_t chunk_len)
555{ 597{
556 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 598 size_t size_remaining = chunk_len - 8;
557 599
558 while (size_remaining) 600 while (size_remaining)
559 { 601 {
@@ -597,7 +639,7 @@ static bool read_chunk_mdia(qtmovie_t *qtmovie, size_t chunk_len)
597/* 'trak' - a movie track - contains other atoms */ 639/* 'trak' - a movie track - contains other atoms */
598static bool read_chunk_trak(qtmovie_t *qtmovie, size_t chunk_len) 640static bool read_chunk_trak(qtmovie_t *qtmovie, size_t chunk_len)
599{ 641{
600 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 642 size_t size_remaining = chunk_len - 8;
601 643
602 while (size_remaining) 644 while (size_remaining)
603 { 645 {
@@ -639,7 +681,7 @@ static bool read_chunk_trak(qtmovie_t *qtmovie, size_t chunk_len)
639static void read_chunk_mvhd(qtmovie_t *qtmovie, size_t chunk_len) 681static void read_chunk_mvhd(qtmovie_t *qtmovie, size_t chunk_len)
640{ 682{
641 /* don't need anything from here atm, skip */ 683 /* don't need anything from here atm, skip */
642 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 684 size_t size_remaining = chunk_len - 8;
643 685
644 stream_skip(qtmovie->stream, size_remaining); 686 stream_skip(qtmovie->stream, size_remaining);
645} 687}
@@ -648,7 +690,7 @@ static void read_chunk_mvhd(qtmovie_t *qtmovie, size_t chunk_len)
648static void read_chunk_udta(qtmovie_t *qtmovie, size_t chunk_len) 690static void read_chunk_udta(qtmovie_t *qtmovie, size_t chunk_len)
649{ 691{
650 /* don't need anything from here atm, skip */ 692 /* don't need anything from here atm, skip */
651 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 693 size_t size_remaining = chunk_len - 8;
652 694
653 stream_skip(qtmovie->stream, size_remaining); 695 stream_skip(qtmovie->stream, size_remaining);
654} 696}
@@ -656,7 +698,7 @@ static void read_chunk_udta(qtmovie_t *qtmovie, size_t chunk_len)
656/* 'moov' movie atom - contains other atoms */ 698/* 'moov' movie atom - contains other atoms */
657static bool read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len) 699static bool read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len)
658{ 700{
659 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 701 size_t size_remaining = chunk_len - 8;
660 702
661 while (size_remaining) 703 while (size_remaining)
662 { 704 {
@@ -688,7 +730,7 @@ static bool read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len)
688 default: 730 default:
689 DEBUGF("(moov) unknown chunk id: %c%c%c%c\n", 731 DEBUGF("(moov) unknown chunk id: %c%c%c%c\n",
690 SPLITFOURCC(sub_chunk_id)); 732 SPLITFOURCC(sub_chunk_id));
691 stream_skip(qtmovie->stream, sub_chunk_len - 8); /* FIXME not 8 */ 733 stream_skip(qtmovie->stream, sub_chunk_len - 8);
692 } 734 }
693 735
694 size_remaining -= sub_chunk_len; 736 size_remaining -= sub_chunk_len;
@@ -698,14 +740,9 @@ static bool read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len)
698 740
699static void read_chunk_mdat(qtmovie_t *qtmovie, size_t chunk_len) 741static void read_chunk_mdat(qtmovie_t *qtmovie, size_t chunk_len)
700{ 742{
701 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 743 size_t size_remaining = chunk_len - 8;
702 744
703 qtmovie->res->mdat_len = size_remaining; 745 qtmovie->res->mdat_len = size_remaining;
704#if 0
705 qtmovie->res->mdat = malloc(size_remaining);
706
707 stream_read(qtmovie->stream, size_remaining, qtmovie->res->mdat);
708#endif
709} 746}
710 747
711int qtmovie_read(stream_t *file, demux_res_t *demux_res) 748int qtmovie_read(stream_t *file, demux_res_t *demux_res)
@@ -760,7 +797,7 @@ int qtmovie_read(stream_t *file, demux_res_t *demux_res)
760 797
761 /* these following atoms can be skipped !!!! */ 798 /* these following atoms can be skipped !!!! */
762 case MAKEFOURCC('f','r','e','e'): 799 case MAKEFOURCC('f','r','e','e'):
763 stream_skip(qtmovie.stream, chunk_len - 8); /* FIXME not 8 */ 800 stream_skip(qtmovie.stream, chunk_len - 8);
764 break; 801 break;
765 default: 802 default:
766 //DEBUGF("(top) unknown chunk id: %c%c%c%c\n",SPLITFOURCC(chunk_id)); 803 //DEBUGF("(top) unknown chunk id: %c%c%c%c\n",SPLITFOURCC(chunk_id));
diff --git a/apps/codecs/libm4a/m4a.c b/apps/codecs/libm4a/m4a.c
index f914f4e4d1..0a87ec35ea 100644
--- a/apps/codecs/libm4a/m4a.c
+++ b/apps/codecs/libm4a/m4a.c
@@ -21,6 +21,13 @@
21#include <inttypes.h> 21#include <inttypes.h>
22#include "m4a.h" 22#include "m4a.h"
23 23
24#if defined(DEBUG) || defined(SIMULATOR)
25extern struct codec_api* rb;
26#define DEBUGF rb->debugf
27#else
28#define DEBUGF(...)
29#endif
30
24/* Implementation of the stream.h functions used by libalac */ 31/* Implementation of the stream.h functions used by libalac */
25 32
26#define _Swap32(v) do { \ 33#define _Swap32(v) do { \
@@ -101,15 +108,7 @@ uint8_t stream_read_uint8(stream_t *stream)
101 108
102void stream_skip(stream_t *stream, size_t skip) 109void stream_skip(stream_t *stream, size_t skip)
103{ 110{
104 (void)stream; 111 stream->ci->advance_buffer(skip);
105#if 1
106 char buf;
107 while (skip > 0) {
108 stream->ci->read_filebuf(&buf,1);
109 skip--;
110 }
111#endif
112 //stream->ci->advance_buffer(skip);
113} 112}
114 113
115int stream_eof(stream_t *stream) 114int stream_eof(stream_t *stream)
@@ -158,136 +157,273 @@ int get_sample_info(demux_res_t *demux_res, uint32_t samplenum,
158 return 1; 157 return 1;
159} 158}
160 159
161/* Seek to sample_loc (or close to it). Return 1 on success (and 160unsigned int get_sample_offset(demux_res_t *demux_res, uint32_t sample)
162 modify samplesdone and currentblock), 0 if failed 161{
162 uint32_t chunk = 1;
163 uint32_t range_samples = 0;
164 uint32_t total_samples = 0;
165 uint32_t chunk_sample;
166 uint32_t prev_chunk;
167 uint32_t prev_chunk_samples;
168 uint32_t file_offset;
169 uint32_t i;
170
171 /* First check we have the appropriate metadata - we should always
172 * have it.
173 */
174
175 if (sample >= demux_res->num_sample_byte_sizes ||
176 !demux_res->num_sample_to_chunks ||
177 !demux_res->num_chunk_offsets)
178 {
179 return 0;
180 }
163 181
164 Seeking uses the following two arrays: 182 /* Locate the chunk containing the sample */
183
184 prev_chunk = demux_res->sample_to_chunk[0].first_chunk;
185 prev_chunk_samples = demux_res->sample_to_chunk[0].num_samples;
165 186
166 1) the sample_byte_size array contains the length in bytes of 187 for (i = 1; i < demux_res->num_sample_to_chunks; i++)
167 each block ("sample" in Applespeak). 188 {
189 chunk = demux_res->sample_to_chunk[i].first_chunk;
190 range_samples = (chunk - prev_chunk) * prev_chunk_samples;
168 191
169 2) the time_to_sample array contains the duration (in samples) of 192 if (sample < total_samples + range_samples)
170 each block of data. 193 {
194 break;
195 }
171 196
172 So we just find the block number we are going to seek to (using 197 total_samples += range_samples;
173 time_to_sample) and then find the offset in the file (using 198 prev_chunk = demux_res->sample_to_chunk[i].first_chunk;
174 sample_byte_size). 199 prev_chunk_samples = demux_res->sample_to_chunk[i].num_samples;
200 }
175 201
176 Each ALAC block seems to be independent of all the others. 202 if (demux_res->num_sample_to_chunks > 1)
177 */ 203 {
204 chunk = prev_chunk + (sample - total_samples) / prev_chunk_samples;
205 }
206 else
207 {
208 chunk = 1;
209 }
210
211 /* Get sample of the first sample in the chunk */
212
213 chunk_sample = total_samples + (chunk - prev_chunk) * prev_chunk_samples;
214
215 /* Get offset in file */
216
217 if (chunk > demux_res->num_chunk_offsets)
218 {
219 file_offset = demux_res->chunk_offset[demux_res->num_chunk_offsets - 1];
220 }
221 else
222 {
223 file_offset = demux_res->chunk_offset[chunk - 1];
224 }
225
226 if (chunk_sample > sample) {
227 return 0;
228 }
229
230 for (i = chunk_sample; i < sample; i++)
231 {
232 file_offset += demux_res->sample_byte_size[i];
233 }
234
235 if (file_offset > demux_res->mdat_offset + demux_res->mdat_len)
236 {
237 return 0;
238 }
239
240 return file_offset;
241}
178 242
179unsigned int alac_seek (demux_res_t* demux_res, 243/* Seek to the sample containing sound_sample_loc. Return 1 on success
180 stream_t* stream, 244 * (and modify sound_samples_done and current_sample), 0 if failed.
181 unsigned int sample_loc, 245 *
182 uint32_t* samplesdone, int* currentblock) 246 * Seeking uses the following arrays:
247 *
248 * 1) the time_to_sample array contains the duration (in sound samples)
249 * of each sample of data.
250 *
251 * 2) the sample_byte_size array contains the length in bytes of each
252 * sample.
253 *
254 * 3) the sample_to_chunk array contains information about which chunk
255 * of samples each sample belongs to.
256 *
257 * 4) the chunk_offset array contains the file offset of each chunk.
258 *
259 * So find the sample number we are going to seek to (using time_to_sample)
260 * and then find the offset in the file (using sample_to_chunk,
261 * chunk_offset sample_byte_size, in that order.).
262 *
263 */
264unsigned int alac_seek(demux_res_t* demux_res, stream_t* stream,
265 uint32_t sound_sample_loc, uint32_t* sound_samples_done,
266 int* current_sample)
183{ 267{
184 int flag; 268 uint32_t i;
185 unsigned int i,j; 269 uint32_t j;
186 unsigned int newblock; 270 uint32_t new_sample;
187 unsigned int newsample; 271 uint32_t new_sound_sample;
188 unsigned int newpos; 272 uint32_t new_pos;
189 273
190 /* First check we have the appropriate metadata - we should always 274 /* First check we have the appropriate metadata - we should always
191 have it. */ 275 * have it.
192 if ((demux_res->num_time_to_samples==0) || 276 */
193 (demux_res->num_sample_byte_sizes==0)) { return 0; } 277
194 278 if ((demux_res->num_time_to_samples==0) ||
195 /* Find the destination block from time_to_sample array */ 279 (demux_res->num_sample_byte_sizes==0))
196 i=0; 280 {
197 newblock=0; 281 return 0;
198 newsample=0; 282 }
199 flag=0; 283
200 284 /* Find the destination block from time_to_sample array */
201 while ((i<demux_res->num_time_to_samples) && (flag==0) &&
202 (newsample < sample_loc)) {
203 j=(sample_loc-newsample) /
204 demux_res->time_to_sample[i].sample_duration;
205 285
206 if (j <= demux_res->time_to_sample[i].sample_count) { 286 i = 0;
207 newblock+=j; 287 new_sample = 0;
208 newsample+=j*demux_res->time_to_sample[i].sample_duration; 288 new_sound_sample = 0;
209 flag=1; 289
210 } else { 290 while ((i < demux_res->num_time_to_samples) &&
211 newsample+=(demux_res->time_to_sample[i].sample_duration 291 (new_sound_sample < sound_sample_loc))
212 * demux_res->time_to_sample[i].sample_count); 292 {
213 newblock+=demux_res->time_to_sample[i].sample_count; 293 j = (sound_sample_loc - new_sound_sample) /
214 i++; 294 demux_res->time_to_sample[i].sample_duration;
295
296 if (j <= demux_res->time_to_sample[i].sample_count)
297 {
298 new_sample += j;
299 new_sound_sample += j *
300 demux_res->time_to_sample[i].sample_duration;
301 break;
302 }
303 else
304 {
305 new_sound_sample += (demux_res->time_to_sample[i].sample_duration
306 * demux_res->time_to_sample[i].sample_count);
307 new_sample += demux_res->time_to_sample[i].sample_count;
308 i++;
309 }
215 } 310 }
216 } 311
217 312 /* We know the new block, now calculate the file position. */
218 /* We know the new block, now calculate the file position */ 313
219 newpos=demux_res->mdat_offset; 314 new_pos = get_sample_offset(demux_res, new_sample);
220 for (i=0;i<newblock;i++) { 315
221 newpos+=demux_res->sample_byte_size[i]; 316 /* We know the new file position, so let's try to seek to it */
222 } 317
223 318 if (stream->ci->seek_buffer(new_pos))
224 /* We know the new file position, so let's try to seek to it */ 319 {
225 if (stream->ci->seek_buffer(newpos)) { 320 *sound_samples_done = new_sound_sample;
226 *samplesdone=newsample; 321 *current_sample = new_sample;
227 *currentblock=newblock; 322 return 1;
228 return 1; 323 }
229 } else { 324
230 return 0; 325 return 0;
231 }
232} 326}
233 327
234/* Seek to file_loc (or close to it). Return 1 on success (and 328/* Seek to the sample containing file_loc. Return 1 on success (and modify
235 modify samplesdone and currentblock), 0 if failed 329 * sound_samples_done and current_sample), 0 if failed.
236 330 *
237 Seeking uses the following array: 331 * Seeking uses the following arrays:
332 *
333 * 1) the chunk_offset array contains the file offset of each chunk.
334 *
335 * 2) the sample_to_chunk array contains information about which chunk
336 * of samples each sample belongs to.
337 *
338 * 3) the sample_byte_size array contains the length in bytes of each
339 * sample.
340 *
341 * 4) the time_to_sample array contains the duration (in sound samples)
342 * of each sample of data.
343 *
344 * Locate the chunk containing location (using chunk_offset), find the
345 * sample of that chunk (using sample_to_chunk) and finally the location
346 * of that sample (using sample_byte_size). Then use time_to_sample to
347 * calculate the sound_samples_done value.
348 */
349unsigned int alac_seek_raw(demux_res_t* demux_res, stream_t* stream,
350 uint32_t file_loc, uint32_t* sound_samples_done,
351 int* current_sample)
352{
353 uint32_t chunk_sample = 0;
354 uint32_t total_samples = 0;
355 uint32_t new_sound_sample = 0;
356 uint32_t new_pos;
357 uint32_t chunk;
358 uint32_t i;
359
360 if (!demux_res->num_chunk_offsets ||
361 !demux_res->num_sample_to_chunks)
362 {
363 return 0;
364 }
238 365
239 the sample_byte_size array contains the length in bytes of 366 /* Locate the chunk containing file_loc. */
240 each block ("sample" in Applespeak).
241 367
242 So we just find the last block before (or at) the requested position. 368 for (i = 0; i < demux_res->num_chunk_offsets &&
369 file_loc < demux_res->chunk_offset[i]; i++)
370 {
371 }
372
373 chunk = i + 1;
374 new_pos = demux_res->chunk_offset[chunk - 1];
243 375
244 Each ALAC block seems to be independent of all the others. 376 /* Get the first sample of the chunk. */
245 */ 377
378 for (i = 1; i < demux_res->num_sample_to_chunks &&
379 chunk < demux_res->sample_to_chunk[i - 1].first_chunk; i++)
380 {
381 chunk_sample += demux_res->sample_to_chunk[i - 1].num_samples *
382 (demux_res->sample_to_chunk[i].first_chunk -
383 demux_res->sample_to_chunk[i - 1].first_chunk);
384 }
385
386 chunk_sample += (chunk - demux_res->sample_to_chunk[i - 1].first_chunk) *
387 demux_res->sample_to_chunk[i - 1].num_samples;
246 388
247unsigned int alac_seek_raw (demux_res_t* demux_res, 389 /* Get the position within the chunk. */
248 stream_t* stream, 390
249 unsigned int file_loc, 391 for (; chunk_sample < demux_res->num_sample_byte_sizes; chunk_sample++)
250 uint32_t* samplesdone, int* currentblock) 392 {
251{ 393 if (file_loc < new_pos + demux_res->sample_byte_size[chunk_sample])
252 unsigned int i; 394 {
253 unsigned int j; 395 break;
254 unsigned int newblock; 396 }
255 unsigned int newsample; 397
256 unsigned int newpos; 398 new_pos += demux_res->sample_byte_size[chunk_sample];
257 399 }
258 /* First check we have the appropriate metadata - we should always 400
259 have it. */ 401 /* Get sound sample offset. */
260 if ((demux_res->num_time_to_samples==0) || 402
261 (demux_res->num_sample_byte_sizes==0)) { return 0; } 403 for (i = 0; i < demux_res->num_time_to_samples; i++)
262 404 {
263 /* Find the destination block from the sample_byte_size array. */ 405 if (chunk_sample <
264 newpos=demux_res->mdat_offset; 406 total_samples + demux_res->time_to_sample[i].sample_count)
265 for (i=0;(i<demux_res->num_sample_byte_sizes) && 407 {
266 (newpos+demux_res->sample_byte_size[i]<=file_loc);i++) { 408 break;
267 newpos+=demux_res->sample_byte_size[i]; 409 }
268 } 410
269 411 total_samples += demux_res->time_to_sample[i].sample_count;
270 newblock=i; 412 new_sound_sample += demux_res->time_to_sample[i].sample_count
271 newsample=0; 413 * demux_res->time_to_sample[i].sample_duration;
272
273 /* Get the sample offset of the block */
274 for (i=0,j=0;(i<demux_res->num_time_to_samples) && (j<newblock);
275 i++,j+=demux_res->time_to_sample[i].sample_count) {
276 if (newblock-j < demux_res->time_to_sample[i].sample_count) {
277 newsample+=(newblock-j)*demux_res->time_to_sample[i].sample_duration;
278 break;
279 } else {
280 newsample+=(demux_res->time_to_sample[i].sample_duration
281 * demux_res->time_to_sample[i].sample_count);
282 } 414 }
283 } 415
416 new_sound_sample += (chunk_sample - total_samples)
417 * demux_res->time_to_sample[i].sample_duration;
418
419 /* Go to the new file position. */
420
421 if (stream->ci->seek_buffer(new_pos))
422 {
423 *sound_samples_done = new_sound_sample;
424 *current_sample = chunk_sample;
425 return 1;
426 }
284 427
285 /* We know the new file position, so let's try to seek to it */
286 if (stream->ci->seek_buffer(newpos)) {
287 *samplesdone=newsample;
288 *currentblock=newblock;
289 return 1;
290 } else {
291 return 0; 428 return 0;
292 }
293} 429}
diff --git a/apps/codecs/libm4a/m4a.h b/apps/codecs/libm4a/m4a.h
index 7fea37513d..17f54c0146 100644
--- a/apps/codecs/libm4a/m4a.h
+++ b/apps/codecs/libm4a/m4a.h
@@ -33,12 +33,21 @@ typedef uint32_t fourcc_t;
33typedef struct 33typedef struct
34{ 34{
35 uint16_t num_channels; 35 uint16_t num_channels;
36 uint16_t sample_size; 36 uint16_t sound_sample_size;
37 uint32_t sample_rate; 37 uint32_t sound_sample_rate;
38 fourcc_t format; 38 fourcc_t format;
39 void *buf; 39 void *buf;
40 40
41 struct { 41 struct {
42 uint32_t first_chunk;
43 uint32_t num_samples;
44 } *sample_to_chunk;
45 uint32_t num_sample_to_chunks;
46
47 uint32_t *chunk_offset;
48 uint32_t num_chunk_offsets;
49
50 struct {
42 uint32_t sample_count; 51 uint32_t sample_count;
43 uint32_t sample_duration; 52 uint32_t sample_duration;
44 } *time_to_sample; 53 } *time_to_sample;
@@ -93,16 +102,13 @@ void stream_skip(stream_t *stream, size_t skip);
93int stream_eof(stream_t *stream); 102int stream_eof(stream_t *stream);
94 103
95void stream_create(stream_t *stream,struct codec_api* ci); 104void stream_create(stream_t *stream,struct codec_api* ci);
96int get_sample_info(demux_res_t *demux_res, uint32_t samplenum, 105int get_sample_info(demux_res_t *demux_res, uint32_t sample,
97 uint32_t *sample_duration, 106 uint32_t *sample_duration, uint32_t *sample_byte_size);
98 uint32_t *sample_byte_size); 107unsigned int get_sample_offset(demux_res_t *demux_res, uint32_t sample);
99unsigned int alac_seek (demux_res_t* demux_res, 108unsigned int alac_seek (demux_res_t* demux_res, stream_t* stream,
100 stream_t* stream, 109 uint32_t sound_sample_loc, uint32_t* sound_samples_done,
101 unsigned int sample_loc, 110 int* current_sample);
102 uint32_t* samplesdone, int* currentblock); 111unsigned int alac_seek_raw (demux_res_t* demux_res, stream_t* stream,
103unsigned int alac_seek_raw (demux_res_t* demux_res, 112 uint32_t file_loc, uint32_t* sound_samples_done, int* current_sample);
104 stream_t* stream,
105 unsigned int file_loc,
106 uint32_t* samplesdone, int* currentblock);
107 113
108#endif /* STREAM_H */ 114#endif /* STREAM_H */