summaryrefslogtreecommitdiffstats
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 @@
* \/ \/ \/ \/ \/
* $Id$
*
- * Copyright (C) 2005 Dave Chapman
+ * Copyright (C) 2005 Dave Chapman, 2011 Andree Buschmann
*
* This program is free software; you can redistribute it and/or
* 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)
stream->eof=0;
}
-/* This function was part of the original alac decoder implementation */
-
-int get_sample_info(demux_res_t *demux_res, uint32_t samplenum,
- uint32_t *sample_duration,
- uint32_t *sample_byte_size)
+/* Check if there is a dedicated byte position contained for the given frame.
+ * Return this byte position in case of success or return -1. This allows to
+ * skip empty samples. */
+int m4a_check_sample_offset(demux_res_t *demux_res, uint32_t frame)
{
- unsigned int duration_index_accum = 0;
- unsigned int duration_cur_index = 0;
-
- if (samplenum >= demux_res->num_sample_byte_sizes) {
- return 0;
- }
-
- if (!demux_res->num_time_to_samples) {
- return 0;
- }
-
- while ((demux_res->time_to_sample[duration_cur_index].sample_count
- + duration_index_accum) <= samplenum) {
- duration_index_accum +=
- demux_res->time_to_sample[duration_cur_index].sample_count;
-
- duration_cur_index++;
- if (duration_cur_index >= demux_res->num_time_to_samples) {
- return 0;
- }
+ uint32_t i = 0;
+ for (i=0; i<demux_res->num_lookup_table; ++i)
+ {
+ if (demux_res->lookup_table[i].sample > frame ||
+ demux_res->lookup_table[i].offset == 0)
+ return -1;
+ if (demux_res->lookup_table[i].sample == frame)
+ break;
}
-
- *sample_duration =
- demux_res->time_to_sample[duration_cur_index].sample_duration;
- *sample_byte_size = demux_res->sample_byte_size[samplenum];
-
- return 1;
+ return demux_res->lookup_table[i].offset;
}
-unsigned int get_sample_offset(demux_res_t *demux_res, uint32_t sample)
+/* Find the exact or preceding frame in lookup_table[]. Return both frame
+ * and byte position of this match. */
+static void gather_offset(demux_res_t *demux_res, uint32_t *frame, uint32_t *offset)
{
- uint32_t chunk = 1;
- uint32_t range_samples = 0;
- uint32_t total_samples = 0;
- uint32_t chunk_sample;
- uint32_t prev_chunk;
- uint32_t prev_chunk_samples;
- uint32_t file_offset;
- uint32_t i;
-
- /* First check we have the appropriate metadata - we should always
- * have it.
- */
-
- if (sample >= demux_res->num_sample_byte_sizes ||
- !demux_res->num_sample_to_chunks ||
- !demux_res->num_chunk_offsets)
- {
- return 0;
- }
-
- /* Locate the chunk containing the sample */
-
- prev_chunk = demux_res->sample_to_chunk[0].first_chunk;
- prev_chunk_samples = demux_res->sample_to_chunk[0].num_samples;
-
- for (i = 1; i < demux_res->num_sample_to_chunks; i++)
+ uint32_t i = 0;
+ for (i=0; i<demux_res->num_lookup_table; ++i)
{
- chunk = demux_res->sample_to_chunk[i].first_chunk;
- range_samples = (chunk - prev_chunk) * prev_chunk_samples;
-
- if (sample < total_samples + range_samples)
- {
+ if (demux_res->lookup_table[i].offset == 0)
+ break;
+ if (demux_res->lookup_table[i].sample > *frame)
break;
- }
-
- total_samples += range_samples;
- prev_chunk = demux_res->sample_to_chunk[i].first_chunk;
- prev_chunk_samples = demux_res->sample_to_chunk[i].num_samples;
- }
-
- if (prev_chunk_samples > 0 &&
- sample >= demux_res->sample_to_chunk[0].num_samples)
- {
- chunk = prev_chunk + (sample - total_samples) / prev_chunk_samples;
- }
- else
- {
- chunk = 1;
- }
-
- /* Get sample of the first sample in the chunk */
-
- chunk_sample = total_samples + (chunk - prev_chunk) * prev_chunk_samples;
-
- /* Get offset in file */
-
- if (chunk > demux_res->num_chunk_offsets)
- {
- file_offset = demux_res->chunk_offset[demux_res->num_chunk_offsets - 1];
- }
- else
- {
- file_offset = demux_res->chunk_offset[chunk - 1];
- }
-
- if (chunk_sample > sample)
- {
- return 0;
- }
-
- for (i = chunk_sample; i < sample; i++)
- {
- file_offset += demux_res->sample_byte_size[i];
- }
-
- if (file_offset > demux_res->mdat_offset + demux_res->mdat_len)
- {
- return 0;
}
-
- return file_offset;
+ i = (i>0) ? i-1 : 0; /* We want the last chunk _before_ *frame. */
+ *frame = demux_res->lookup_table[i].sample;
+ *offset = demux_res->lookup_table[i].offset;
}
-/* Seek to the sample containing sound_sample_loc. Return 1 on success
- * (and modify sound_samples_done and current_sample), 0 if failed.
- *
- * Seeking uses the following arrays:
- *
- * 1) the time_to_sample array contains the duration (in sound samples)
- * of each sample of data.
- *
- * 2) the sample_byte_size array contains the length in bytes of each
- * sample.
- *
- * 3) the sample_to_chunk array contains information about which chunk
- * of samples each sample belongs to.
- *
- * 4) the chunk_offset array contains the file offset of each chunk.
- *
- * So find the sample number we are going to seek to (using time_to_sample)
- * and then find the offset in the file (using sample_to_chunk,
- * chunk_offset sample_byte_size, in that order.).
+/* Seek to desired sound sample location. Return 1 on success (and modify
+ * sound_samples_done and current_sample), 0 if failed.
*
- */
-unsigned int alac_seek(demux_res_t* demux_res, stream_t* stream,
+ * Find the sample (=frame) that contains the given sound sample, find a best
+ * fit for this sample in the lookup_table[], seek to the byte position. */
+unsigned int m4a_seek(demux_res_t* demux_res, stream_t* stream,
uint32_t sound_sample_loc, uint32_t* sound_samples_done,
int* current_sample)
{
@@ -300,8 +198,8 @@ unsigned int alac_seek(demux_res_t* demux_res, stream_t* stream,
++i;
}
- /* We know the new block, now calculate the file position. */
- new_pos = get_sample_offset(demux_res, new_sample);
+ /* We know the new sample (=frame), now calculate the file position. */
+ gather_offset(demux_res, &new_sample, &new_pos);
/* We know the new file position, so let's try to seek to it */
if (stream->ci->seek_buffer(new_pos))
@@ -319,71 +217,38 @@ unsigned int alac_seek(demux_res_t* demux_res, stream_t* stream,
*
* Seeking uses the following arrays:
*
- * 1) the chunk_offset array contains the file offset of each chunk.
- *
- * 2) the sample_to_chunk array contains information about which chunk
- * of samples each sample belongs to.
- *
- * 3) the sample_byte_size array contains the length in bytes of each
- * sample.
+ * 1) the lookup_table array contains the file offset for the first sample
+ * of each chunk.
*
- * 4) the time_to_sample array contains the duration (in sound samples)
+ * 2) the time_to_sample array contains the duration (in sound samples)
* of each sample of data.
*
- * Locate the chunk containing location (using chunk_offset), find the
- * sample of that chunk (using sample_to_chunk) and finally the location
- * of that sample (using sample_byte_size). Then use time_to_sample to
+ * Locate the chunk containing location (using lookup_table), find the first
+ * sample of that chunk (using lookup_table). Then use time_to_sample to
* calculate the sound_samples_done value.
*/
-unsigned int alac_seek_raw(demux_res_t* demux_res, stream_t* stream,
+unsigned int m4a_seek_raw(demux_res_t* demux_res, stream_t* stream,
uint32_t file_loc, uint32_t* sound_samples_done,
int* current_sample)
{
- uint32_t chunk_sample = 0; /* Holds the chunk/frame index. */
- uint32_t total_samples = 0; /* Sums up total amount of chunks/frames. */
- uint32_t new_sound_sample = 0; /* Sums up total amount of samples. */
+ uint32_t i;
+ uint32_t chunk_sample = 0;
+ uint32_t total_samples = 0;
+ uint32_t new_sound_sample = 0;
+ uint32_t tmp_dur;
+ uint32_t tmp_cnt;
uint32_t new_pos;
- uint32_t chunk;
- uint32_t i, tmp_dur, tmp_cnt;
-
- /* There is no metadata available to perform raw seek. */
- if (!demux_res->num_chunk_offsets || !demux_res->num_sample_to_chunks)
- {
- return 0;
- }
-
- /* Locate the chunk containing file_loc. */
- chunk = 0;
- while (chunk < demux_res->num_chunk_offsets)
- {
- if (file_loc < demux_res->chunk_offset[chunk])
- {
- break;
- }
- ++chunk;
- }
- new_pos = demux_res->chunk_offset[chunk > 0 ? chunk - 1 : 0];
- /* Get the first sample of the chunk. */
- i = 1;
- sample_to_chunk_t *tab1 = demux_res->sample_to_chunk;
- while (i < demux_res->num_sample_to_chunks)
+ /* We know the desired byte offset, search for the chunk right before.
+ * Return the associated sample to this chunk as chunk_sample. */
+ for (i=0; i < demux_res->num_lookup_table; ++i)
{
- if (chunk <= tab1[i].first_chunk)
- {
+ if (demux_res->lookup_table[i].offset > file_loc)
break;
- }
- chunk_sample += tab1[i-1].num_samples * (tab1[i].first_chunk - tab1[i-1].first_chunk);
- ++i;
- }
- chunk_sample += (chunk - tab1[i-1].first_chunk) * tab1[i-1].num_samples;
-
- /* Get the position within the chunk. */
- while (chunk_sample < demux_res->num_sample_byte_sizes &&
- file_loc >= new_pos + demux_res->sample_byte_size[chunk_sample])
- {
- new_pos += demux_res->sample_byte_size[chunk_sample++];
}
+ i = (i>0) ? i-1 : 0; /* We want the last chunk _before_ file_loc. */
+ chunk_sample = demux_res->lookup_table[i].sample;
+ new_pos = demux_res->lookup_table[i].offset;
/* Get sound sample offset. */
i = 0;