summaryrefslogtreecommitdiff
path: root/apps/codecs/libm4a/m4a.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/libm4a/m4a.c')
-rw-r--r--apps/codecs/libm4a/m4a.c237
1 files changed, 51 insertions, 186 deletions
diff --git a/apps/codecs/libm4a/m4a.c b/apps/codecs/libm4a/m4a.c
index 8c4b172bc2..836cdafda3 100644
--- a/apps/codecs/libm4a/m4a.c
+++ b/apps/codecs/libm4a/m4a.c
@@ -7,7 +7,7 @@
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2005 Dave Chapman 10 * Copyright (C) 2005 Dave Chapman, 2011 Andree Buschmann
11 * 11 *
12 * This program is free software; you can redistribute it and/or 12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 13 * modify it under the terms of the GNU General Public License
@@ -122,148 +122,46 @@ void stream_create(stream_t *stream,struct codec_api* ci)
122 stream->eof=0; 122 stream->eof=0;
123} 123}
124 124
125/* This function was part of the original alac decoder implementation */ 125/* Check if there is a dedicated byte position contained for the given frame.
126 126 * Return this byte position in case of success or return -1. This allows to
127int get_sample_info(demux_res_t *demux_res, uint32_t samplenum, 127 * skip empty samples. */
128 uint32_t *sample_duration, 128int m4a_check_sample_offset(demux_res_t *demux_res, uint32_t frame)
129 uint32_t *sample_byte_size)
130{ 129{
131 unsigned int duration_index_accum = 0; 130 uint32_t i = 0;
132 unsigned int duration_cur_index = 0; 131 for (i=0; i<demux_res->num_lookup_table; ++i)
133 132 {
134 if (samplenum >= demux_res->num_sample_byte_sizes) { 133 if (demux_res->lookup_table[i].sample > frame ||
135 return 0; 134 demux_res->lookup_table[i].offset == 0)
136 } 135 return -1;
137 136 if (demux_res->lookup_table[i].sample == frame)
138 if (!demux_res->num_time_to_samples) { 137 break;
139 return 0;
140 }
141
142 while ((demux_res->time_to_sample[duration_cur_index].sample_count
143 + duration_index_accum) <= samplenum) {
144 duration_index_accum +=
145 demux_res->time_to_sample[duration_cur_index].sample_count;
146
147 duration_cur_index++;
148 if (duration_cur_index >= demux_res->num_time_to_samples) {
149 return 0;
150 }
151 } 138 }
152 139 return demux_res->lookup_table[i].offset;
153 *sample_duration =
154 demux_res->time_to_sample[duration_cur_index].sample_duration;
155 *sample_byte_size = demux_res->sample_byte_size[samplenum];
156
157 return 1;
158} 140}
159 141
160unsigned int get_sample_offset(demux_res_t *demux_res, uint32_t sample) 142/* Find the exact or preceding frame in lookup_table[]. Return both frame
143 * and byte position of this match. */
144static void gather_offset(demux_res_t *demux_res, uint32_t *frame, uint32_t *offset)
161{ 145{
162 uint32_t chunk = 1; 146 uint32_t i = 0;
163 uint32_t range_samples = 0; 147 for (i=0; i<demux_res->num_lookup_table; ++i)
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 }
181
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;
186
187 for (i = 1; i < demux_res->num_sample_to_chunks; i++)
188 { 148 {
189 chunk = demux_res->sample_to_chunk[i].first_chunk; 149 if (demux_res->lookup_table[i].offset == 0)
190 range_samples = (chunk - prev_chunk) * prev_chunk_samples; 150 break;
191 151 if (demux_res->lookup_table[i].sample > *frame)
192 if (sample < total_samples + range_samples)
193 {
194 break; 152 break;
195 }
196
197 total_samples += range_samples;
198 prev_chunk = demux_res->sample_to_chunk[i].first_chunk;
199 prev_chunk_samples = demux_res->sample_to_chunk[i].num_samples;
200 }
201
202 if (prev_chunk_samples > 0 &&
203 sample >= demux_res->sample_to_chunk[0].num_samples)
204 {
205 chunk = prev_chunk + (sample - total_samples) / prev_chunk_samples;
206 }
207 else
208 {
209 chunk = 1;
210 }
211
212 /* Get sample of the first sample in the chunk */
213
214 chunk_sample = total_samples + (chunk - prev_chunk) * prev_chunk_samples;
215
216 /* Get offset in file */
217
218 if (chunk > demux_res->num_chunk_offsets)
219 {
220 file_offset = demux_res->chunk_offset[demux_res->num_chunk_offsets - 1];
221 }
222 else
223 {
224 file_offset = demux_res->chunk_offset[chunk - 1];
225 }
226
227 if (chunk_sample > sample)
228 {
229 return 0;
230 }
231
232 for (i = chunk_sample; i < sample; i++)
233 {
234 file_offset += demux_res->sample_byte_size[i];
235 }
236
237 if (file_offset > demux_res->mdat_offset + demux_res->mdat_len)
238 {
239 return 0;
240 } 153 }
241 154 i = (i>0) ? i-1 : 0; /* We want the last chunk _before_ *frame. */
242 return file_offset; 155 *frame = demux_res->lookup_table[i].sample;
156 *offset = demux_res->lookup_table[i].offset;
243} 157}
244 158
245/* Seek to the sample containing sound_sample_loc. Return 1 on success 159/* Seek to desired sound sample location. Return 1 on success (and modify
246 * (and modify sound_samples_done and current_sample), 0 if failed. 160 * sound_samples_done and current_sample), 0 if failed.
247 *
248 * Seeking uses the following arrays:
249 *
250 * 1) the time_to_sample array contains the duration (in sound samples)
251 * of each sample of data.
252 *
253 * 2) the sample_byte_size array contains the length in bytes of each
254 * sample.
255 *
256 * 3) the sample_to_chunk array contains information about which chunk
257 * of samples each sample belongs to.
258 *
259 * 4) the chunk_offset array contains the file offset of each chunk.
260 *
261 * So find the sample number we are going to seek to (using time_to_sample)
262 * and then find the offset in the file (using sample_to_chunk,
263 * chunk_offset sample_byte_size, in that order.).
264 * 161 *
265 */ 162 * Find the sample (=frame) that contains the given sound sample, find a best
266unsigned int alac_seek(demux_res_t* demux_res, stream_t* stream, 163 * fit for this sample in the lookup_table[], seek to the byte position. */
164unsigned int m4a_seek(demux_res_t* demux_res, stream_t* stream,
267 uint32_t sound_sample_loc, uint32_t* sound_samples_done, 165 uint32_t sound_sample_loc, uint32_t* sound_samples_done,
268 int* current_sample) 166 int* current_sample)
269{ 167{
@@ -300,8 +198,8 @@ unsigned int alac_seek(demux_res_t* demux_res, stream_t* stream,
300 ++i; 198 ++i;
301 } 199 }
302 200
303 /* We know the new block, now calculate the file position. */ 201 /* We know the new sample (=frame), now calculate the file position. */
304 new_pos = get_sample_offset(demux_res, new_sample); 202 gather_offset(demux_res, &new_sample, &new_pos);
305 203
306 /* We know the new file position, so let's try to seek to it */ 204 /* We know the new file position, so let's try to seek to it */
307 if (stream->ci->seek_buffer(new_pos)) 205 if (stream->ci->seek_buffer(new_pos))
@@ -319,71 +217,38 @@ unsigned int alac_seek(demux_res_t* demux_res, stream_t* stream,
319 * 217 *
320 * Seeking uses the following arrays: 218 * Seeking uses the following arrays:
321 * 219 *
322 * 1) the chunk_offset array contains the file offset of each chunk. 220 * 1) the lookup_table array contains the file offset for the first sample
323 * 221 * of each chunk.
324 * 2) the sample_to_chunk array contains information about which chunk
325 * of samples each sample belongs to.
326 *
327 * 3) the sample_byte_size array contains the length in bytes of each
328 * sample.
329 * 222 *
330 * 4) the time_to_sample array contains the duration (in sound samples) 223 * 2) the time_to_sample array contains the duration (in sound samples)
331 * of each sample of data. 224 * of each sample of data.
332 * 225 *
333 * Locate the chunk containing location (using chunk_offset), find the 226 * Locate the chunk containing location (using lookup_table), find the first
334 * sample of that chunk (using sample_to_chunk) and finally the location 227 * sample of that chunk (using lookup_table). Then use time_to_sample to
335 * of that sample (using sample_byte_size). Then use time_to_sample to
336 * calculate the sound_samples_done value. 228 * calculate the sound_samples_done value.
337 */ 229 */
338unsigned int alac_seek_raw(demux_res_t* demux_res, stream_t* stream, 230unsigned int m4a_seek_raw(demux_res_t* demux_res, stream_t* stream,
339 uint32_t file_loc, uint32_t* sound_samples_done, 231 uint32_t file_loc, uint32_t* sound_samples_done,
340 int* current_sample) 232 int* current_sample)
341{ 233{
342 uint32_t chunk_sample = 0; /* Holds the chunk/frame index. */ 234 uint32_t i;
343 uint32_t total_samples = 0; /* Sums up total amount of chunks/frames. */ 235 uint32_t chunk_sample = 0;
344 uint32_t new_sound_sample = 0; /* Sums up total amount of samples. */ 236 uint32_t total_samples = 0;
237 uint32_t new_sound_sample = 0;
238 uint32_t tmp_dur;
239 uint32_t tmp_cnt;
345 uint32_t new_pos; 240 uint32_t new_pos;
346 uint32_t chunk;
347 uint32_t i, tmp_dur, tmp_cnt;
348
349 /* There is no metadata available to perform raw seek. */
350 if (!demux_res->num_chunk_offsets || !demux_res->num_sample_to_chunks)
351 {
352 return 0;
353 }
354
355 /* Locate the chunk containing file_loc. */
356 chunk = 0;
357 while (chunk < demux_res->num_chunk_offsets)
358 {
359 if (file_loc < demux_res->chunk_offset[chunk])
360 {
361 break;
362 }
363 ++chunk;
364 }
365 new_pos = demux_res->chunk_offset[chunk > 0 ? chunk - 1 : 0];
366 241
367 /* Get the first sample of the chunk. */ 242 /* We know the desired byte offset, search for the chunk right before.
368 i = 1; 243 * Return the associated sample to this chunk as chunk_sample. */
369 sample_to_chunk_t *tab1 = demux_res->sample_to_chunk; 244 for (i=0; i < demux_res->num_lookup_table; ++i)
370 while (i < demux_res->num_sample_to_chunks)
371 { 245 {
372 if (chunk <= tab1[i].first_chunk) 246 if (demux_res->lookup_table[i].offset > file_loc)
373 {
374 break; 247 break;
375 }
376 chunk_sample += tab1[i-1].num_samples * (tab1[i].first_chunk - tab1[i-1].first_chunk);
377 ++i;
378 }
379 chunk_sample += (chunk - tab1[i-1].first_chunk) * tab1[i-1].num_samples;
380
381 /* Get the position within the chunk. */
382 while (chunk_sample < demux_res->num_sample_byte_sizes &&
383 file_loc >= new_pos + demux_res->sample_byte_size[chunk_sample])
384 {
385 new_pos += demux_res->sample_byte_size[chunk_sample++];
386 } 248 }
249 i = (i>0) ? i-1 : 0; /* We want the last chunk _before_ file_loc. */
250 chunk_sample = demux_res->lookup_table[i].sample;
251 new_pos = demux_res->lookup_table[i].offset;
387 252
388 /* Get sound sample offset. */ 253 /* Get sound sample offset. */
389 i = 0; 254 i = 0;