X-Git-Url: http://git.tuebingen.mpg.de/?a=blobdiff_plain;ds=sidebyside;f=mp4.c;h=c77cedd2bd2fb586a715b12c5808f7691bc35c57;hb=8e2a58f85f68077944bb5739f2327353a502ed70;hp=c40fbe0b6cce2e1e7a87436b941555d7d780176b;hpb=662fbe85190d071f2d4b839d0ab8440920e8d47d;p=paraslash.git diff --git a/mp4.c b/mp4.c index c40fbe0b..c77cedd2 100644 --- a/mp4.c +++ b/mp4.c @@ -8,12 +8,12 @@ #include #include "para.h" +#include "error.h" #include "portable_io.h" #include "string.h" #include "mp4.h" struct mp4_track { - bool is_audio; uint16_t channelCount; uint16_t sampleRate; @@ -25,13 +25,11 @@ struct mp4_track { /* stts */ uint32_t stts_entry_count; uint32_t *stts_sample_count; - uint32_t *stts_sample_delta; /* stsc */ uint32_t stsc_entry_count; uint32_t *stsc_first_chunk; uint32_t *stsc_samples_per_chunk; - uint32_t *stsc_sample_desc_index; /* stsc */ uint32_t stco_entry_count; @@ -52,23 +50,17 @@ struct mp4 { 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]; + /* the first audio track found */ + struct mp4_track *audio_track; /* metadata */ 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. @@ -445,18 +437,6 @@ static int32_t set_position(struct mp4 *f, int64_t position) 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; @@ -511,13 +491,11 @@ static int read_stts(struct mp4 *f) return ret; t->stts_sample_count = para_malloc(t->stts_entry_count * sizeof(int32_t)); - t->stts_sample_delta = para_malloc(t->stts_entry_count - * sizeof (int32_t)); for (i = 0; i < t->stts_entry_count; i++) { ret = read_int32(f, &t->stts_sample_count[i]); if (ret <= 0) return ret; - ret = read_int32(f, &t->stts_sample_delta[i]); + ret = read_int32(f, NULL); /* sample delta */ if (ret <= 0) return ret; } @@ -546,9 +524,6 @@ static int read_stsc(struct mp4 *f) t->stsc_first_chunk = para_malloc(t->stsc_entry_count * sizeof(int32_t)); t->stsc_samples_per_chunk = para_malloc(t->stsc_entry_count * sizeof (int32_t)); - t->stsc_sample_desc_index = para_malloc(t->stsc_entry_count * - sizeof (int32_t)); - for (i = 0; i < t->stsc_entry_count; i++) { ret = read_int32(f, &t->stsc_first_chunk[i]); if (ret <= 0) @@ -556,7 +531,7 @@ static int read_stsc(struct mp4 *f) ret = read_int32(f, &t->stsc_samples_per_chunk[i]); if (ret <= 0) return ret; - ret = read_int32(f, &t->stsc_sample_desc_index[i]); + ret = read_int32(f, NULL); /* sample desc index */ if (ret <= 0) return ret; } @@ -666,9 +641,10 @@ static int read_stsd(struct mp4 *f) if (ret <= 0) return ret; skip += size; - t->is_audio = atom_type == ATOM_MP4A; - if (t->is_audio) + if (!f->audio_track && atom_type == ATOM_MP4A) { + f->audio_track = t; read_mp4a(f); + } set_position(f, skip); } return 1; @@ -904,11 +880,13 @@ static int parse_sub_atoms(struct mp4 *f, uint64_t total_size, int meta_only) 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); @@ -950,12 +928,16 @@ static int parse_atoms(struct mp4 *f, int meta_only) } else if (atom_type < SUBATOMIC) { ret = parse_sub_atoms(f, size - header_size, meta_only); if (ret <= 0) - return ret; + break; } else { /* skip this atom */ set_position(f, get_position(f) + size - header_size); } } + if (ret < 0) + return ret; + if (!f->audio_track) + return -E_MP4_TRACK; return ret; } @@ -966,7 +948,7 @@ struct mp4 *mp4_open_read(const struct mp4_callback *cb) f->cb = cb; ret = parse_atoms(f, 0); - if (ret < 0 || f->error) { + if (ret < 0) { free(f); return NULL; } @@ -981,10 +963,8 @@ void mp4_close(struct mp4 *f) if (f->track[i]) { free(f->track[i]->stsz_table); free(f->track[i]->stts_sample_count); - free(f->track[i]->stts_sample_delta); free(f->track[i]->stsc_first_chunk); free(f->track[i]->stsc_samples_per_chunk); - free(f->track[i]->stsc_sample_desc_index); free(f->track[i]->stco_chunk_offset); free(f->track[i]); } @@ -997,167 +977,93 @@ void mp4_close(struct mp4 *f) free(f); } -static int32_t chunk_of_sample(const struct mp4 *f, int32_t track, - int32_t sample, int32_t *chunk_sample, int32_t *chunk) +static int32_t chunk_of_sample(const struct mp4 *f, int32_t sample, + int32_t *chunk) { - int32_t total_entries = 0; - int32_t chunk2entry; - int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0; + const struct mp4_track *t = f->audio_track; + uint32_t *fc = t->stsc_first_chunk, *spc = t->stsc_samples_per_chunk; + int32_t chunk1, chunk1samples, n, total, i; - *chunk_sample = 0; - *chunk = 1; - if (f->track[track] == NULL) { - return -1; - } - - total_entries = f->track[track]->stsc_entry_count; - - chunk1 = 1; - chunk1samples = 0; - chunk2entry = 0; - - do { - chunk2 = f->track[track]->stsc_first_chunk[chunk2entry]; - *chunk = chunk2 - chunk1; - range_samples = *chunk * chunk1samples; - - if (sample < total + range_samples) + for (i = 1, total = 0; i < t->stsc_entry_count; i++, total += n) { + n = (fc[i] - fc[i - 1]) * spc[i - 1]; /* number of samples */ + if (sample < total + n) break; - - chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry]; - chunk1 = chunk2; - - if (chunk2entry < total_entries) { - chunk2entry++; - total += range_samples; - } - } while (chunk2entry < total_entries); - - if (chunk1samples) + } + chunk1 = fc[i - 1]; + chunk1samples = spc[i - 1]; + if (chunk1samples != 0) *chunk = (sample - total) / chunk1samples + chunk1; else *chunk = 1; - - *chunk_sample = total + (*chunk - chunk1) * chunk1samples; - - return 0; -} - -static int32_t chunk_to_offset(const struct mp4 *f, int32_t track, - int32_t chunk) -{ - const struct mp4_track *p_track = f->track[track]; - - if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) { - return p_track->stco_chunk_offset[p_track->stco_entry_count - - 1]; - } else if (p_track->stco_entry_count) { - return p_track->stco_chunk_offset[chunk - 1]; - } else { - return 8; - } - - return 0; -} - -static int32_t sample_range_size(const struct mp4 *f, int32_t track, - int32_t chunk_sample, int32_t sample) -{ - int32_t i, total; - const struct mp4_track *p_track = f->track[track]; - - if (p_track->stsz_sample_size) { - return (sample - chunk_sample) * p_track->stsz_sample_size; - } else { - if (sample >= p_track->stsz_sample_count) - return 0; //error - - for (i = chunk_sample, total = 0; i < sample; i++) { - total += p_track->stsz_table[i]; - } - } - - 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 total + (*chunk - chunk1) * chunk1samples; } /** - * Return the number of milliseconds of the given track. + * Return the number of milliseconds of the audio 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(). - * - * The function returns zero if the audio file is of zero length or contains a - * corrupt track header. */ -uint64_t mp4_get_duration(const struct mp4 *f, int32_t track) +uint64_t mp4_get_duration(const struct mp4 *f) { - const struct mp4_track *t = f->track[track]; + const struct mp4_track *t = f->audio_track; if (t->timeScale == 0) return 0; return t->duration * 1000 / t->timeScale; } -/** - * Check whether the given track number corresponds to an audio track. - * - * \param f See \ref mp4_get_duration(). - * \param track See \ref mp4_get_duration(). - * - * Besides audio tracks, an mp4 file may contain video and system tracks. For - * those the function returns false. - */ -bool mp4_is_audio_track(const struct mp4 *f, int32_t track) +int mp4_set_sample_position(struct mp4 *f, int32_t sample) { - return f->track[track]->is_audio; -} + const struct mp4_track *t = f->audio_track; + int32_t offset, chunk, chunk_sample; + uint32_t n, srs; /* sample range size */ -void mp4_set_sample_position(struct mp4 *f, int32_t track, int32_t sample) -{ - int32_t offset = sample_to_offset(f, track, sample); - set_position(f, offset); + if (sample >= t->stsz_sample_count) + return -ERRNO_TO_PARA_ERROR(EINVAL); + chunk_sample = chunk_of_sample(f, sample, &chunk); + if (t->stsz_sample_size > 0) + srs = (sample - chunk_sample) * t->stsz_sample_size; + else { + for (srs = 0, n = chunk_sample; n < sample; n++) + srs += t->stsz_table[n]; + } + if (t->stco_entry_count > 0 && chunk > t->stco_entry_count) + offset = t->stco_chunk_offset[t->stco_entry_count - 1]; + else if (t->stco_entry_count > 0) + offset = t->stco_chunk_offset[chunk - 1]; + else + offset = 8; + set_position(f, offset + srs); + return 1; } -int32_t mp4_get_sample_size(const struct mp4 *f, int track, int sample) +int32_t mp4_get_sample_size(const struct mp4 *f, int sample) { - const struct mp4_track *t = f->track[track]; + const struct mp4_track *t = f->audio_track; if (t->stsz_sample_size != 0) return t->stsz_sample_size; return t->stsz_table[sample]; } -uint32_t mp4_get_sample_rate(const struct mp4 *f, int32_t track) +uint32_t mp4_get_sample_rate(const struct mp4 *f) { - return f->track[track]->sampleRate; + return f->audio_track->sampleRate; } -uint32_t mp4_get_channel_count(const struct mp4 *f, int32_t track) +uint32_t mp4_get_channel_count(const struct mp4 *f) { - return f->track[track]->channelCount; + return f->audio_track->channelCount ; } -int32_t mp4_num_samples(const struct mp4 *f, int32_t track) +int32_t mp4_num_samples(const struct mp4 *f) { + const struct mp4_track *t = f->audio_track; int32_t i; int32_t total = 0; - for (i = 0; i < f->track[track]->stts_entry_count; i++) { - total += f->track[track]->stts_sample_count[i]; - } + for (i = 0; i < t->stts_entry_count; i++) + total += t->stts_sample_count[i]; return total; } @@ -1168,7 +1074,7 @@ struct mp4 *mp4_open_meta(const struct mp4_callback *cb) f->cb = cb; ret = parse_atoms(f, 1); - if (ret < 0 || f->error) { + if (ret < 0) { free(f); return NULL; }