summaryrefslogtreecommitdiff
path: root/apps/codecs/libm4a
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/libm4a
parentca3d872699d56905c7edf875fdec80472c832942 (diff)
downloadrockbox-9896fd1adef70e77b2e226d5e44fabd23192266d.zip
rockbox-9896fd1adef70e77b2e226d5e44fabd23192266d.tar.gz
rockbox-9896fd1adef70e77b2e226d5e44fabd23192266d.tar.bz2
rockbox-9896fd1adef70e77b2e226d5e44fabd23192266d.tar.xz
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/libm4a')
-rw-r--r--apps/codecs/libm4a/demux.c155
-rw-r--r--apps/codecs/libm4a/m4a.c380
-rw-r--r--apps/codecs/libm4a/m4a.h32
3 files changed, 373 insertions, 194 deletions
diff --git a/apps/codecs/libm4a/demux.c b/apps/codecs/libm4a/demux.c
index 1beeced..44261fd 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)
{
fourcc_t type;
uint32_t minor_ver;
- size_t size_remaining = chunk_len - 8; /* FIXME: can't hardcode 8, size may be 64bit */
+ size_t size_remaining = chunk_len - 8;
type = stream_read_uint32(qtmovie->stream);
size_remaining-=4;
if ((type != MAKEFOURCC('M','4','A',' ')) &&
- (type != MAKEFOURCC('m','p','4','2')))
+ (type != MAKEFOURCC('m','p','4','2')) &&
+ (type != MAKEFOURCC('3','g','p','6')) &&
+ (type != MAKEFOURCC('q','t',' ',' ')))
{
DEBUGF("not M4A file\n");
return;
@@ -80,7 +82,7 @@ static void read_chunk_ftyp(qtmovie_t *qtmovie, size_t chunk_len)
static void read_chunk_tkhd(qtmovie_t *qtmovie, size_t chunk_len)
{
/* don't need anything from here atm, skip */
- size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
+ size_t size_remaining = chunk_len - 8;
stream_skip(qtmovie->stream, size_remaining);
}
@@ -88,7 +90,7 @@ static void read_chunk_tkhd(qtmovie_t *qtmovie, size_t chunk_len)
static void read_chunk_mdhd(qtmovie_t *qtmovie, size_t chunk_len)
{
/* don't need anything from here atm, skip */
- size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
+ size_t size_remaining = chunk_len - 8;
stream_skip(qtmovie->stream, size_remaining);
}
@@ -97,7 +99,7 @@ static void read_chunk_mdhd(qtmovie_t *qtmovie, size_t chunk_len)
static void read_chunk_hdlr(qtmovie_t *qtmovie, size_t chunk_len)
{
fourcc_t comptype, compsubtype;
- size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
+ size_t size_remaining = chunk_len - 8;
int strlen;
char str[256] = {0};
@@ -196,7 +198,6 @@ static bool read_chunk_esds(qtmovie_t *qtmovie, size_t chunk_len)
temp=stream_read_int32(qtmovie->stream);//0x15000414 ????
maxBitrate = stream_read_int32(qtmovie->stream);
avgBitrate = stream_read_int32(qtmovie->stream);
-
DEBUGF("audioType=%d, maxBitrate=%d, avgBitrate=%d\n",audioType,maxBitrate,avgBitrate);
/* get and verify DecSpecificInfoTag */
@@ -224,7 +225,7 @@ static bool read_chunk_stsd(qtmovie_t *qtmovie, size_t chunk_len)
unsigned int i;
int j;
uint32_t numentries;
- size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
+ size_t size_remaining = chunk_len - 8;
/* version */
stream_read_uint8(qtmovie->stream);
@@ -247,7 +248,6 @@ static bool read_chunk_stsd(qtmovie_t *qtmovie, size_t chunk_len)
for (i = 0; i < numentries; i++)
{
uint32_t entry_size;
- uint16_t version;
uint32_t entry_remaining;
@@ -259,43 +259,20 @@ static bool read_chunk_stsd(qtmovie_t *qtmovie, size_t chunk_len)
/* sound info: */
- stream_skip(qtmovie->stream, 6); /* reserved */
- entry_remaining -= 6;
-
- version = stream_read_uint16(qtmovie->stream);
- // if (version != 1)
- //fprintf(stderr, "unknown version??\n");
- entry_remaining -= 2;
-
- /* revision level */
- stream_read_uint16(qtmovie->stream);
- /* vendor */
- stream_read_uint32(qtmovie->stream);
- entry_remaining -= 6;
-
- /* EH?? spec doesn't say theres an extra 16 bits here.. but there is! */
- stream_read_uint16(qtmovie->stream);
- entry_remaining -= 2;
+ /* reserved + data reference index + sound version + reserved */
+ stream_skip(qtmovie->stream, 6 + 2 + 2 + 6);
+ entry_remaining -= 6 + 2 + 2 + 6;
qtmovie->res->num_channels = stream_read_uint16(qtmovie->stream);
-
- qtmovie->res->sample_size = stream_read_uint16(qtmovie->stream);
+ qtmovie->res->sound_sample_size = stream_read_uint16(qtmovie->stream);
entry_remaining -= 4;
- /* compression id */
- stream_read_uint16(qtmovie->stream);
/* packet size */
- stream_read_uint16(qtmovie->stream);
- entry_remaining -= 4;
-
- /* sample rate - 32bit fixed point = 16bit?? */
- qtmovie->res->sample_rate = stream_read_uint16(qtmovie->stream);
- entry_remaining -= 2;
-
- /* skip 2 */
stream_skip(qtmovie->stream, 2);
- entry_remaining -= 2;
-
+ qtmovie->res->sound_sample_rate = stream_read_uint32(qtmovie->stream);
+ /* reserved size */
+ stream_skip(qtmovie->stream, 2);
+ entry_remaining -= 8;
/* remaining is codec data */
@@ -372,7 +349,7 @@ static void read_chunk_stts(qtmovie_t *qtmovie, size_t chunk_len)
{
unsigned int i;
uint32_t numentries;
- size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
+ size_t size_remaining = chunk_len - 8;
/* version */
stream_read_uint8(qtmovie->stream);
@@ -407,7 +384,7 @@ static void read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len)
{
unsigned int i;
uint32_t numentries;
- size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
+ size_t size_remaining = chunk_len - 8;
/* version */
stream_read_uint8(qtmovie->stream);
@@ -447,9 +424,73 @@ static void read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len)
}
}
+static void read_chunk_stsc(qtmovie_t *qtmovie, size_t chunk_len)
+{
+ unsigned int i;
+ uint32_t numentries;
+ size_t size_remaining = chunk_len - 8;
+
+ /* version + flags */
+ stream_read_uint32(qtmovie->stream);
+ size_remaining -= 4;
+
+ numentries = stream_read_uint32(qtmovie->stream);
+ size_remaining -= 4;
+
+ qtmovie->res->num_sample_to_chunks = numentries;
+ qtmovie->res->sample_to_chunk = malloc(numentries *
+ sizeof(*qtmovie->res->sample_to_chunk));
+
+ for (i = 0; i < numentries; i++)
+ {
+ qtmovie->res->sample_to_chunk[i].first_chunk =
+ stream_read_uint32(qtmovie->stream);
+ qtmovie->res->sample_to_chunk[i].num_samples =
+ stream_read_uint32(qtmovie->stream);
+ stream_read_uint32(qtmovie->stream);
+ size_remaining -= 12;
+ }
+
+ if (size_remaining)
+ {
+ DEBUGF("ehm, size remianing?\n");
+ stream_skip(qtmovie->stream, size_remaining);
+ }
+}
+
+static void read_chunk_stco(qtmovie_t *qtmovie, size_t chunk_len)
+{
+ unsigned int i;
+ uint32_t numentries;
+ size_t size_remaining = chunk_len - 8;
+
+ /* version + flags */
+ stream_read_uint32(qtmovie->stream);
+ size_remaining -= 4;
+
+ numentries = stream_read_uint32(qtmovie->stream);
+ size_remaining -= 4;
+
+ qtmovie->res->num_chunk_offsets = numentries;
+ qtmovie->res->chunk_offset = malloc(numentries *
+ sizeof(*qtmovie->res->chunk_offset));
+
+ for (i = 0; i < numentries; i++)
+ {
+ qtmovie->res->chunk_offset[i] = stream_read_uint32(qtmovie->stream);
+ size_remaining -= 4;
+ }
+
+ if (size_remaining)
+ {
+ DEBUGF("ehm, size remianing?\n");
+ stream_skip(qtmovie->stream, size_remaining);
+ }
+}
+
static bool read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len)
{
- size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
+ size_t size_remaining = chunk_len - 8;
while (size_remaining)
{
@@ -479,14 +520,15 @@ static bool read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len)
read_chunk_stsz(qtmovie, sub_chunk_len);
break;
case MAKEFOURCC('s','t','s','c'):
+ read_chunk_stsc(qtmovie, sub_chunk_len);
+ break;
case MAKEFOURCC('s','t','c','o'):
- /* skip these, no indexing for us! */
- stream_skip(qtmovie->stream, sub_chunk_len - 8);
+ read_chunk_stco(qtmovie, sub_chunk_len);
break;
default:
DEBUGF("(stbl) unknown chunk id: %c%c%c%c\n",
SPLITFOURCC(sub_chunk_id));
- stream_skip(qtmovie->stream, sub_chunk_len - 8); /* FIXME not 8 */
+ stream_skip(qtmovie->stream, sub_chunk_len - 8);
}
size_remaining -= sub_chunk_len;
@@ -497,7 +539,7 @@ static bool read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len)
static bool read_chunk_minf(qtmovie_t *qtmovie, size_t chunk_len)
{
size_t dinf_size, stbl_size;
- size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
+ size_t size_remaining = chunk_len - 8;
uint32_t i;
/**** SOUND HEADER CHUNK ****/
@@ -553,7 +595,7 @@ static bool read_chunk_minf(qtmovie_t *qtmovie, size_t chunk_len)
static bool read_chunk_mdia(qtmovie_t *qtmovie, size_t chunk_len)
{
- size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
+ size_t size_remaining = chunk_len - 8;
while (size_remaining)
{
@@ -597,7 +639,7 @@ static bool read_chunk_mdia(qtmovie_t *qtmovie, size_t chunk_len)
/* 'trak' - a movie track - contains other atoms */
static bool read_chunk_trak(qtmovie_t *qtmovie, size_t chunk_len)
{
- size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
+ size_t size_remaining = chunk_len - 8;
while (size_remaining)
{
@@ -639,7 +681,7 @@ static bool read_chunk_trak(qtmovie_t *qtmovie, size_t chunk_len)
static void read_chunk_mvhd(qtmovie_t *qtmovie, size_t chunk_len)
{
/* don't need anything from here atm, skip */
- size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
+ size_t size_remaining = chunk_len - 8;
stream_skip(qtmovie->stream, size_remaining);
}
@@ -648,7 +690,7 @@ static void read_chunk_mvhd(qtmovie_t *qtmovie, size_t chunk_len)
static void read_chunk_udta(qtmovie_t *qtmovie, size_t chunk_len)
{
/* don't need anything from here atm, skip */
- size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
+ size_t size_remaining = chunk_len - 8;
stream_skip(qtmovie->stream, size_remaining);
}
@@ -656,7 +698,7 @@ static void read_chunk_udta(qtmovie_t *qtmovie, size_t chunk_len)
/* 'moov' movie atom - contains other atoms */
static bool read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len)
{
- size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
+ size_t size_remaining = chunk_len - 8;
while (size_remaining)
{
@@ -688,7 +730,7 @@ static bool read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len)
default:
DEBUGF("(moov) unknown chunk id: %c%c%c%c\n",
SPLITFOURCC(sub_chunk_id));
- stream_skip(qtmovie->stream, sub_chunk_len - 8); /* FIXME not 8 */
+ stream_skip(qtmovie->stream, sub_chunk_len - 8);
}
size_remaining -= sub_chunk_len;
@@ -698,14 +740,9 @@ static bool read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len)
static void read_chunk_mdat(qtmovie_t *qtmovie, size_t chunk_len)
{
- size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
+ size_t size_remaining = chunk_len - 8;
qtmovie->res->mdat_len = size_remaining;
-#if 0
- qtmovie->res->mdat = malloc(size_remaining);
-
- stream_read(qtmovie->stream, size_remaining, qtmovie->res->mdat);
-#endif
}
int 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)
/* these following atoms can be skipped !!!! */
case MAKEFOURCC('f','r','e','e'):
- stream_skip(qtmovie.stream, chunk_len - 8); /* FIXME not 8 */
+ stream_skip(qtmovie.stream, chunk_len - 8);
break;
default:
//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 f914f4e..0a87ec3 100644
--- a/apps/codecs/libm4a/m4a.c
+++ b/apps/codecs/libm4a/m4a.c
@@ -21,6 +21,13 @@
#include <inttypes.h>
#include "m4a.h"
+#if defined(DEBUG) || defined(SIMULATOR)
+extern struct codec_api* rb;
+#define DEBUGF rb->debugf
+#else
+#define DEBUGF(...)
+#endif
+
/* Implementation of the stream.h functions used by libalac */
#define _Swap32(v) do { \
@@ -101,15 +108,7 @@ uint8_t stream_read_uint8(stream_t *stream)
void stream_skip(stream_t *stream, size_t skip)
{
- (void)stream;
-#if 1
- char buf;
- while (skip > 0) {
- stream->ci->read_filebuf(&buf,1);
- skip--;
- }
-#endif
- //stream->ci->advance_buffer(skip);
+ stream->ci->advance_buffer(skip);
}
int stream_eof(stream_t *stream)
@@ -158,136 +157,273 @@ int get_sample_info(demux_res_t *demux_res, uint32_t samplenum,
return 1;
}
-/* Seek to sample_loc (or close to it). Return 1 on success (and
- modify samplesdone and currentblock), 0 if failed
+unsigned int get_sample_offset(demux_res_t *demux_res, uint32_t sample)
+{
+ 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;
+ }
- Seeking uses the following two arrays:
+ /* 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;
- 1) the sample_byte_size array contains the length in bytes of
- each block ("sample" in Applespeak).
+ for (i = 1; i < demux_res->num_sample_to_chunks; i++)
+ {
+ chunk = demux_res->sample_to_chunk[i].first_chunk;
+ range_samples = (chunk - prev_chunk) * prev_chunk_samples;
- 2) the time_to_sample array contains the duration (in samples) of
- each block of data.
+ if (sample < total_samples + range_samples)
+ {
+ break;
+ }
- So we just find the block number we are going to seek to (using
- time_to_sample) and then find the offset in the file (using
- sample_byte_size).
+ 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;
+ }
- Each ALAC block seems to be independent of all the others.
- */
+ if (demux_res->num_sample_to_chunks > 1)
+ {
+ 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;
+}
-unsigned int alac_seek (demux_res_t* demux_res,
- stream_t* stream,
- unsigned int sample_loc,
- uint32_t* samplesdone, int* currentblock)
+/* 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.).
+ *
+ */
+unsigned int alac_seek(demux_res_t* demux_res, stream_t* stream,
+ uint32_t sound_sample_loc, uint32_t* sound_samples_done,
+ int* current_sample)
{
- int flag;
- unsigned int i,j;
- unsigned int newblock;
- unsigned int newsample;
- unsigned int newpos;
-
- /* First check we have the appropriate metadata - we should always
- have it. */
- if ((demux_res->num_time_to_samples==0) ||
- (demux_res->num_sample_byte_sizes==0)) { return 0; }
-
- /* Find the destination block from time_to_sample array */
- i=0;
- newblock=0;
- newsample=0;
- flag=0;
-
- while ((i<demux_res->num_time_to_samples) && (flag==0) &&
- (newsample < sample_loc)) {
- j=(sample_loc-newsample) /
- demux_res->time_to_sample[i].sample_duration;
+ uint32_t i;
+ uint32_t j;
+ uint32_t new_sample;
+ uint32_t new_sound_sample;
+ uint32_t new_pos;
+
+ /* First check we have the appropriate metadata - we should always
+ * have it.
+ */
+
+ if ((demux_res->num_time_to_samples==0) ||
+ (demux_res->num_sample_byte_sizes==0))
+ {
+ return 0;
+ }
+
+ /* Find the destination block from time_to_sample array */
- if (j <= demux_res->time_to_sample[i].sample_count) {
- newblock+=j;
- newsample+=j*demux_res->time_to_sample[i].sample_duration;
- flag=1;
- } else {
- newsample+=(demux_res->time_to_sample[i].sample_duration
- * demux_res->time_to_sample[i].sample_count);
- newblock+=demux_res->time_to_sample[i].sample_count;
- i++;
+ i = 0;
+ new_sample = 0;
+ new_sound_sample = 0;
+
+ while ((i < demux_res->num_time_to_samples) &&
+ (new_sound_sample < sound_sample_loc))
+ {
+ j = (sound_sample_loc - new_sound_sample) /
+ demux_res->time_to_sample[i].sample_duration;
+
+ if (j <= demux_res->time_to_sample[i].sample_count)
+ {
+ new_sample += j;
+ new_sound_sample += j *
+ demux_res->time_to_sample[i].sample_duration;
+ break;
+ }
+ else
+ {
+ new_sound_sample += (demux_res->time_to_sample[i].sample_duration
+ * demux_res->time_to_sample[i].sample_count);
+ new_sample += demux_res->time_to_sample[i].sample_count;
+ i++;
+ }
}
- }
-
- /* We know the new block, now calculate the file position */
- newpos=demux_res->mdat_offset;
- for (i=0;i<newblock;i++) {
- newpos+=demux_res->sample_byte_size[i];
- }
-
- /* We know the new file position, so let's try to seek to it */
- if (stream->ci->seek_buffer(newpos)) {
- *samplesdone=newsample;
- *currentblock=newblock;
- return 1;
- } else {
+
+ /* We know the new block, now calculate the file position. */
+
+ new_pos = get_sample_offset(demux_res, new_sample);
+
+ /* We know the new file position, so let's try to seek to it */
+
+ if (stream->ci->seek_buffer(new_pos))
+ {
+ *sound_samples_done = new_sound_sample;
+ *current_sample = new_sample;
+ return 1;
+ }
+
return 0;
- }
}
-/* Seek to file_loc (or close to it). Return 1 on success (and
- modify samplesdone and currentblock), 0 if failed
-
- Seeking uses the following array:
+/* Seek to the sample containing file_loc. Return 1 on success (and modify
+ * sound_samples_done and current_sample), 0 if failed.
+ *
+ * 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.
+ *
+ * 4) 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
+ * calculate the sound_samples_done value.
+ */
+unsigned int alac_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;
+ uint32_t total_samples = 0;
+ uint32_t new_sound_sample = 0;
+ uint32_t new_pos;
+ uint32_t chunk;
+ uint32_t i;
+
+ if (!demux_res->num_chunk_offsets ||
+ !demux_res->num_sample_to_chunks)
+ {
+ return 0;
+ }
- the sample_byte_size array contains the length in bytes of
- each block ("sample" in Applespeak).
+ /* Locate the chunk containing file_loc. */
- So we just find the last block before (or at) the requested position.
+ for (i = 0; i < demux_res->num_chunk_offsets &&
+ file_loc < demux_res->chunk_offset[i]; i++)
+ {
+ }
+
+ chunk = i + 1;
+ new_pos = demux_res->chunk_offset[chunk - 1];
- Each ALAC block seems to be independent of all the others.
- */
+ /* Get the first sample of the chunk. */
+
+ for (i = 1; i < demux_res->num_sample_to_chunks &&
+ chunk < demux_res->sample_to_chunk[i - 1].first_chunk; i++)
+ {
+ chunk_sample += demux_res->sample_to_chunk[i - 1].num_samples *
+ (demux_res->sample_to_chunk[i].first_chunk -
+ demux_res->sample_to_chunk[i - 1].first_chunk);
+ }
+
+ chunk_sample += (chunk - demux_res->sample_to_chunk[i - 1].first_chunk) *
+ demux_res->sample_to_chunk[i - 1].num_samples;
-unsigned int alac_seek_raw (demux_res_t* demux_res,
- stream_t* stream,
- unsigned int file_loc,
- uint32_t* samplesdone, int* currentblock)
-{
- unsigned int i;
- unsigned int j;
- unsigned int newblock;
- unsigned int newsample;
- unsigned int newpos;
-
- /* First check we have the appropriate metadata - we should always
- have it. */
- if ((demux_res->num_time_to_samples==0) ||
- (demux_res->num_sample_byte_sizes==0)) { return 0; }
-
- /* Find the destination block from the sample_byte_size array. */
- newpos=demux_res->mdat_offset;
- for (i=0;(i<demux_res->num_sample_byte_sizes) &&
- (newpos+demux_res->sample_byte_size[i]<=file_loc);i++) {
- newpos+=demux_res->sample_byte_size[i];
- }
-
- newblock=i;
- newsample=0;
-
- /* Get the sample offset of the block */
- for (i=0,j=0;(i<demux_res->num_time_to_samples) && (j<newblock);
- i++,j+=demux_res->time_to_sample[i].sample_count) {
- if (newblock-j < demux_res->time_to_sample[i].sample_count) {
- newsample+=(newblock-j)*demux_res->time_to_sample[i].sample_duration;
- break;
- } else {
- newsample+=(demux_res->time_to_sample[i].sample_duration
- * demux_res->time_to_sample[i].sample_count);
+ /* Get the position within the chunk. */
+
+ for (; chunk_sample < demux_res->num_sample_byte_sizes; chunk_sample++)
+ {
+ if (file_loc < new_pos + demux_res->sample_byte_size[chunk_sample])
+ {
+ break;
+ }
+
+ new_pos += demux_res->sample_byte_size[chunk_sample];
+ }
+
+ /* Get sound sample offset. */
+
+ for (i = 0; i < demux_res->num_time_to_samples; i++)
+ {
+ if (chunk_sample <
+ total_samples + demux_res->time_to_sample[i].sample_count)
+ {
+ break;
+ }
+
+ total_samples += demux_res->time_to_sample[i].sample_count;
+ new_sound_sample += demux_res->time_to_sample[i].sample_count
+ * demux_res->time_to_sample[i].sample_duration;
}
- }
+
+ new_sound_sample += (chunk_sample - total_samples)
+ * demux_res->time_to_sample[i].sample_duration;
+
+ /* Go to the new file position. */
+
+ if (stream->ci->seek_buffer(new_pos))
+ {
+ *sound_samples_done = new_sound_sample;
+ *current_sample = chunk_sample;
+ return 1;
+ }
- /* We know the new file position, so let's try to seek to it */
- if (stream->ci->seek_buffer(newpos)) {
- *samplesdone=newsample;
- *currentblock=newblock;
- return 1;
- } else {
return 0;
- }
}
diff --git a/apps/codecs/libm4a/m4a.h b/apps/codecs/libm4a/m4a.h
index 7fea375..17f54c0 100644
--- a/apps/codecs/libm4a/m4a.h
+++ b/apps/codecs/libm4a/m4a.h
@@ -33,12 +33,21 @@ typedef uint32_t fourcc_t;
typedef struct
{
uint16_t num_channels;
- uint16_t sample_size;
- uint32_t sample_rate;
+ uint16_t sound_sample_size;
+ uint32_t sound_sample_rate;
fourcc_t format;
void *buf;
struct {
+ uint32_t first_chunk;
+ uint32_t num_samples;
+ } *sample_to_chunk;
+ uint32_t num_sample_to_chunks;
+
+ uint32_t *chunk_offset;
+ uint32_t num_chunk_offsets;
+
+ struct {
uint32_t sample_count;
uint32_t sample_duration;
} *time_to_sample;
@@ -93,16 +102,13 @@ void stream_skip(stream_t *stream, size_t skip);
int stream_eof(stream_t *stream);
void stream_create(stream_t *stream,struct codec_api* ci);
-int get_sample_info(demux_res_t *demux_res, uint32_t samplenum,
- uint32_t *sample_duration,
- uint32_t *sample_byte_size);
-unsigned int alac_seek (demux_res_t* demux_res,
- stream_t* stream,
- unsigned int sample_loc,
- uint32_t* samplesdone, int* currentblock);
-unsigned int alac_seek_raw (demux_res_t* demux_res,
- stream_t* stream,
- unsigned int file_loc,
- uint32_t* samplesdone, int* currentblock);
+int get_sample_info(demux_res_t *demux_res, uint32_t sample,
+ uint32_t *sample_duration, uint32_t *sample_byte_size);
+unsigned int get_sample_offset(demux_res_t *demux_res, uint32_t sample);
+unsigned int alac_seek (demux_res_t* demux_res, stream_t* stream,
+ uint32_t sound_sample_loc, uint32_t* sound_samples_done,
+ int* current_sample);
+unsigned int alac_seek_raw (demux_res_t* demux_res, stream_t* stream,
+ uint32_t file_loc, uint32_t* sound_samples_done, int* current_sample);
#endif /* STREAM_H */