uint8_t last_atom;
uint64_t file_size;
- uint32_t error;
-
/* incremental track index while reading the file */
int32_t total_tracks;
-
/* track data */
struct mp4_track *track[MAX_TRACKS];
struct mp4_metadata meta;
};
-int32_t mp4_total_tracks(const struct mp4 *f)
-{
- return f->total_tracks;
-}
-
/*
* Returns -1, 0, or 1 on errors/EOF/success. Partial reads followed by EOF or
* read errors are treated as errors.
ATOM_MVHD = 131,
ATOM_TKHD = 132,
ATOM_TREF = 133,
- ATOM_MDHD = 134,
+ ATOM_MDHD = 134, /* track header */
ATOM_VMHD = 135,
ATOM_SMHD = 136,
ATOM_HMHD = 137,
- ATOM_STSD = 138,
- ATOM_STTS = 139,
- ATOM_STSZ = 140,
+ ATOM_STSD = 138, /* sample description box */
+ ATOM_STTS = 139, /* time to sample box */
+ ATOM_STSZ = 140, /* sample size box */
ATOM_STZ2 = 141,
- ATOM_STCO = 142,
- ATOM_STSC = 143,
+ ATOM_STCO = 142, /* chunk offset box */
+ ATOM_STSC = 143, /* sample to chunk box */
ATOM_MP4A = 144,
ATOM_MP4V = 145,
ATOM_MP4S = 146,
return 0;
}
-static void track_add(struct mp4 *f)
-{
- f->total_tracks++;
-
- if (f->total_tracks > MAX_TRACKS) {
- f->total_tracks = 0;
- f->error++;
- return;
- }
- f->track[f->total_tracks - 1] = para_calloc(sizeof(struct mp4_track));
-}
-
static int read_stsz(struct mp4 *f)
{
int ret;
return 1;
}
-static int32_t atom_read(struct mp4 *f, int32_t size, uint8_t atom_type)
+static int atom_read(struct mp4 *f, uint64_t size, uint8_t atom_type)
{
uint64_t dest_position = get_position(f) + size - 8;
- if (atom_type == ATOM_STSZ) {
- /* sample size box */
- read_stsz(f);
- } else if (atom_type == ATOM_STTS) {
- /* time to sample box */
- read_stts(f);
- } else if (atom_type == ATOM_STSC) {
- /* sample to chunk box */
- read_stsc(f);
- } else if (atom_type == ATOM_STCO) {
- /* chunk offset box */
- read_stco(f);
- } else if (atom_type == ATOM_STSD) {
- /* sample description box */
- read_stsd(f);
- } else if (atom_type == ATOM_MDHD) {
- /* track header */
- read_mdhd(f);
- } else if (atom_type == ATOM_META) {
- /* iTunes Metadata box */
- read_meta(f, size);
- }
+ int ret = 1; /* return success for atoms we don't care about */
+ switch (atom_type) {
+ case ATOM_STSZ: ret = read_stsz(f); break;
+ case ATOM_STTS: ret = read_stts(f); break;
+ case ATOM_STSC: ret = read_stsc(f); break;
+ case ATOM_STCO: ret = read_stco(f); break;
+ case ATOM_STSD: ret = read_stsd(f); break;
+ case ATOM_MDHD: ret = read_mdhd(f); break;
+ case ATOM_META: ret = read_meta(f, size); break;
+ }
set_position(f, dest_position);
- return 0;
+ return ret;
}
/* parse atoms that are sub atoms of other atoms */
if (size == 0)
return -1;
counted_size += size;
- /* we're starting to read a new track, update index,
- * so that all data and tables get written in the right place
- */
- if (atom_type == ATOM_TRAK)
- track_add(f);
+ if (atom_type == ATOM_TRAK) {
+ if (f->total_tracks >= MAX_TRACKS)
+ return -1;
+ f->total_tracks++;
+ f->track[f->total_tracks - 1] = para_calloc(
+ sizeof(struct mp4_track));
+ }
/* parse subatoms */
if (meta_only && !need_parse_when_meta_only(atom_type)) {
set_position(f, get_position(f) + size - header_size);
} else if (atom_type < SUBATOMIC) {
- parse_sub_atoms(f, size - header_size, meta_only);
+ ret = parse_sub_atoms(f, size - header_size, meta_only);
+ if (ret <= 0)
+ return ret;
} else {
- atom_read(f, (uint32_t) size, atom_type);
+ ret = atom_read(f, size, atom_type);
+ if (ret <= 0)
+ return ret;
}
}
return 1;
}
/* parse root atoms */
-static int32_t parse_atoms(struct mp4 *f, int meta_only)
+static int parse_atoms(struct mp4 *f, int meta_only)
{
int ret;
uint64_t size;
if (meta_only && !need_parse_when_meta_only(atom_type)) {
set_position(f, get_position(f) + size - header_size);
} else if (atom_type < SUBATOMIC) {
- parse_sub_atoms(f, size - header_size, meta_only);
+ ret = parse_sub_atoms(f, size - header_size, meta_only);
+ if (ret <= 0)
+ return ret;
} else {
/* skip this atom */
set_position(f, get_position(f) + size - header_size);
struct mp4 *mp4_open_read(const struct mp4_callback *cb)
{
+ int ret;
struct mp4 *f = para_calloc(sizeof(struct mp4));
f->cb = cb;
- parse_atoms(f, 0);
- if (f->error) {
+ ret = parse_atoms(f, 0);
+ if (ret < 0) {
free(f);
- f = NULL;
+ return NULL;
}
return f;
}
return total;
}
-static int32_t sample_to_offset(const struct mp4 *f, int32_t track,
- int32_t sample)
-{
- int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
-
- chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
-
- chunk_offset1 = chunk_to_offset(f, track, chunk);
- chunk_offset2 = chunk_offset1 + sample_range_size(f,
- track, chunk_sample, sample);
- return chunk_offset2;
-}
-
/**
* Return the number of milliseconds of the given track.
*
* \param f As returned by \ref mp4_open_read(), must not be NULL.
- * \param track Between zero and the value returned by \ref mp4_total_tracks().
+ * \param track Between zero and the value returned by \ref mp4_get_total_tracks().
*
* The function returns zero if the audio file is of zero length or contains a
* corrupt track header.
return t->duration * 1000 / t->timeScale;
}
+int32_t mp4_get_total_tracks(const struct mp4 *f)
+{
+ return f->total_tracks;
+}
+
/**
* Check whether the given track number corresponds to an audio track.
*
void mp4_set_sample_position(struct mp4 *f, int32_t track, int32_t sample)
{
- int32_t offset = sample_to_offset(f, track, sample);
+ int32_t offset, chunk, chunk_sample;
+
+ chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
+ offset = chunk_to_offset(f, track, chunk)
+ + sample_range_size(f, track, chunk_sample, sample);
set_position(f, offset);
}
struct mp4 *mp4_open_meta(const struct mp4_callback *cb)
{
+ int ret;
struct mp4 *f = para_calloc(sizeof(struct mp4));
f->cb = cb;
- parse_atoms(f, 1);
- if (f->error) {
+ ret = parse_atoms(f, 1);
+ if (ret < 0) {
free(f);
- f = NULL;
+ return NULL;
}
return f;
}