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.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')
-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 6c86f38..0c48422 100644
--- a/apps/codecs/aac.c
+++ b/apps/codecs/aac.c
@@ -29,6 +29,8 @@ CODEC_HEADER
extern char iramcopy[];
extern char iramstart[];
extern char iramend[];
+extern char iedata[];
+extern char iend[];
#endif
struct codec_api* rb;
@@ -37,27 +39,35 @@ struct codec_api* ci;
/* this is the codec entry point */
enum codec_status codec_start(struct codec_api* api)
{
+ /* Note that when dealing with QuickTime/MPEG4 files, terminology is
+ * a bit confusing. Files with sound are split up in chunks, where
+ * each chunk contains one or more samples. Each sample in turn
+ * contains a number of "sound samples" (the kind you refer to with
+ * the sampling frequency).
+ */
size_t n;
static demux_res_t demux_res;
stream_t input_stream;
- uint32_t samplesdone;
- uint32_t elapsedtime;
+ uint32_t sound_samples_done;
+ uint32_t elapsed_time;
uint32_t sample_duration;
uint32_t sample_byte_size;
- int samplesdecoded;
+ int file_offset;
unsigned int i;
unsigned char* buffer;
- static NeAACDecFrameInfo frameInfo;
- NeAACDecHandle hDecoder;
+ static NeAACDecFrameInfo frame_info;
+ NeAACDecHandle decoder;
int err;
- int16_t* decodedbuffer;
+ uint32_t s = 0;
+ unsigned char c = 0;
/* Generic codec initialisation */
rb = api;
ci = api;
#ifndef SIMULATOR
- rb->memcpy(iramstart, iramcopy, iramend-iramstart);
+ ci->memcpy(iramstart, iramcopy, iramend-iramstart);
+ ci->memset(iedata, 0, iend - iedata);
#endif
ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*16));
@@ -68,9 +78,10 @@ enum codec_status codec_start(struct codec_api* api)
ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(29));
next_track:
+ err = CODEC_OK;
if (codec_init(api)) {
- LOGF("FAAD: Error initialising codec\n");
+ LOGF("FAAD: Codec init error\n");
err = CODEC_ERROR;
goto exit;
}
@@ -78,7 +89,7 @@ next_track:
while (!*ci->taginfo_ready && !ci->stop_codec)
ci->sleep(1);
- samplesdone = ci->id3->offset;
+ sound_samples_done = ci->id3->offset;
ci->configure(DSP_SET_FREQUENCY, (long *)(rb->id3->frequency));
@@ -87,52 +98,49 @@ next_track:
/* if qtmovie_read returns successfully, the stream is up to
* the movie data, which can be used directly by the decoder */
if (!qtmovie_read(&input_stream, &demux_res)) {
- LOGF("FAAD: Error initialising file\n");
+ LOGF("FAAD: File init error\n");
err = CODEC_ERROR;
goto done;
}
/* initialise the sound converter */
- hDecoder = NULL;
- hDecoder = NeAACDecOpen();
+ decoder = NeAACDecOpen();
- if (!hDecoder) {
- LOGF("FAAD: Error opening decoder\n");
+ if (!decoder) {
+ LOGF("FAAD: Decode open error\n");
err = CODEC_ERROR;
goto done;
}
- NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(hDecoder);
+ NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder);
conf->outputFormat = FAAD_FMT_24BIT; /* irrelevant, we don't convert */
- NeAACDecSetConfiguration(hDecoder, conf);
-
- uint32_t s=0;
- unsigned char c=0;
+ NeAACDecSetConfiguration(decoder, conf);
- err = NeAACDecInit2(hDecoder, demux_res.codecdata,demux_res.codecdata_len, &s, &c);
+ err = NeAACDecInit2(decoder, demux_res.codecdata, demux_res.codecdata_len, &s, &c);
if (err) {
- LOGF("FAAD: Error initialising decoder: %d, type=%d\n", err,hDecoder->object_type);
+ LOGF("FAAD: DecInit: %d, %d\n", err, decoder->object_type);
err = CODEC_ERROR;
goto done;
}
- ci->id3->frequency=s;
+ ci->id3->frequency = s;
- i=0;
+ i = 0;
- if (samplesdone > 0) {
- if (alac_seek_raw(&demux_res, &input_stream, samplesdone,
- &samplesdone, (int *)&i)) {
- elapsedtime=(samplesdone*10)/(ci->id3->frequency/100);
- ci->set_elapsed(elapsedtime);
+ if (sound_samples_done > 0) {
+ if (alac_seek_raw(&demux_res, &input_stream, sound_samples_done,
+ &sound_samples_done, (int*) &i)) {
+ elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100);
+ ci->set_elapsed(elapsed_time);
} else {
- samplesdone=0;
+ sound_samples_done = 0;
}
}
/* The main decoding loop */
while (i < demux_res.num_sample_byte_sizes) {
rb->yield();
+
if (ci->stop_codec || ci->new_track) {
break;
}
@@ -140,10 +148,10 @@ next_track:
/* Deal with any pending seek requests */
if (ci->seek_time) {
if (alac_seek(&demux_res, &input_stream,
- ((ci->seek_time-1)/10) * (ci->id3->frequency/100),
- &samplesdone, (int *)&i)) {
- elapsedtime=(samplesdone*10)/(ci->id3->frequency/100);
- ci->set_elapsed(elapsedtime);
+ ((ci->seek_time-1)/10)*(ci->id3->frequency/100),
+ &sound_samples_done, (int*) &i)) {
+ elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100);
+ ci->set_elapsed(elapsed_time);
}
ci->seek_complete();
}
@@ -151,52 +159,65 @@ next_track:
/* Lookup the length (in samples and bytes) of block i */
if (!get_sample_info(&demux_res, i, &sample_duration,
&sample_byte_size)) {
- LOGF("AAC: Error in get_sample_info\n");
+ LOGF("AAC: get_sample_info error\n");
err = CODEC_ERROR;
goto done;
}
+ /* There can be gaps between chunks, so skip ahead if needed. It
+ * doesn't seem to happen much, but it probably means that a
+ * "proper" file can have chunks out of order. Why one would want
+ * that an good question (but files with gaps do exist, so who
+ * knows?), so we don't support that - for now, at least.
+ */
+ file_offset = get_sample_offset(&demux_res, i);
+
+ if (file_offset > ci->curpos)
+ {
+ ci->advance_buffer(file_offset - ci->curpos);
+ }
+
/* Request the required number of bytes from the input buffer */
buffer=ci->request_buffer(&n,sample_byte_size);
/* Decode one block - returned samples will be host-endian */
- rb->yield();
- decodedbuffer = NeAACDecDecode(hDecoder, &frameInfo, buffer, n);
- /* ignore decodedbuffer return value, we access samples in the
- decoder struct directly */
- if (frameInfo.error > 0) {
- LOGF("FAAD: decoding error \"%s\"\n", NeAACDecGetErrorMessage(frameInfo.error));
- err = CODEC_ERROR;
- goto done;
+ NeAACDecDecode(decoder, &frame_info, buffer, n);
+ /* Ignore return value, we access samples in the decoder struct
+ * directly.
+ */
+ if (frame_info.error > 0) {
+ LOGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error));
+ err = CODEC_ERROR;
+ goto done;
}
- /* Get the number of decoded samples */
- samplesdecoded=frameInfo.samples;
-
/* Advance codec buffer */
ci->advance_buffer(n);
/* Output the audio */
rb->yield();
- while (!rb->pcmbuf_insert_split(hDecoder->time_out[0],
- hDecoder->time_out[1],
- frameInfo.samples*2))
- rb->yield();
+ while (!rb->pcmbuf_insert_split(decoder->time_out[0],
+ decoder->time_out[1],
+ frame_info.samples * 2))
+ {
+ rb->sleep(1);
+ }
/* Update the elapsed-time indicator */
- samplesdone+=sample_duration;
- elapsedtime=(samplesdone*10)/(ci->id3->frequency/100);
- ci->set_elapsed(elapsedtime);
+ sound_samples_done += sample_duration;
+ elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100);
+ ci->set_elapsed(elapsed_time);
/* Keep track of current position - for resuming */
- ci->set_offset(elapsedtime);
+ ci->set_offset(elapsed_time);
i++;
}
+
err = CODEC_OK;
done:
- LOGF("AAC: Decoded %d samples\n",samplesdone);
+ LOGF("AAC: Decoded %d samples, %d frames\n", sound_samples_done);
if (ci->request_next_track())
goto next_track;
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 */