X-Git-Url: http://git.tuebingen.mpg.de/?a=blobdiff_plain;f=mp4.c;h=e5ec9dd13ecd6ab71ef00e3657a7eb5a598a60eb;hb=13273bf45126e8254dabce13bbdcfdfc396868ef;hp=2f9c105dbfec56632556f492b0290a5f575375ff;hpb=6676c08aba77219683f50c02ad7f9b0812a11749;p=paraslash.git diff --git a/mp4.c b/mp4.c index 2f9c105d..e5ec9dd1 100644 --- a/mp4.c +++ b/mp4.c @@ -14,7 +14,6 @@ #include "mp4.h" struct mp4_track { - bool is_audio; uint16_t channelCount; uint16_t sampleRate; @@ -26,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; @@ -57,6 +54,8 @@ struct mp4 { 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; @@ -492,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; } @@ -527,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) @@ -537,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; } @@ -647,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; @@ -870,7 +865,7 @@ static int atom_read(struct mp4 *f, uint64_t size, uint8_t atom_type) } /* parse atoms that are sub atoms of other atoms */ -static int parse_sub_atoms(struct mp4 *f, uint64_t total_size, int meta_only) +static int parse_sub_atoms(struct mp4 *f, uint64_t total_size, bool meta_only) { int ret; uint64_t size; @@ -908,8 +903,7 @@ static int parse_sub_atoms(struct mp4 *f, uint64_t total_size, int meta_only) return 1; } -/* parse root atoms */ -static int parse_atoms(struct mp4 *f, int meta_only) +static int parse_root_atoms(struct mp4 *f, bool meta_only) { int ret; uint64_t size; @@ -921,24 +915,20 @@ static int parse_atoms(struct mp4 *f, int meta_only) while ((ret = atom_read_header(f, &atom_type, &header_size, &size)) > 0) { f->file_size += size; f->last_atom = atom_type; - - if (atom_type == ATOM_MOOV && size > header_size) { - f->moov_offset = get_position(f) - header_size; - f->moov_size = size; - } - - /* 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) { - ret = parse_sub_atoms(f, size - header_size, meta_only); - if (ret <= 0) - return ret; - } else { - /* skip this atom */ + if (atom_type != ATOM_MOOV || size <= header_size) { /* skip */ set_position(f, get_position(f) + size - header_size); + continue; } + f->moov_offset = get_position(f) - header_size; + f->moov_size = size; + ret = parse_sub_atoms(f, size - header_size, meta_only); + if (ret <= 0) + break; } + if (ret < 0) + return ret; + if (!f->audio_track) + return -E_MP4_TRACK; return ret; } @@ -948,7 +938,7 @@ struct mp4 *mp4_open_read(const struct mp4_callback *cb) struct mp4 *f = para_calloc(sizeof(struct mp4)); f->cb = cb; - ret = parse_atoms(f, 0); + ret = parse_root_atoms(f, false); if (ret < 0) { free(f); return NULL; @@ -964,10 +954,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]); } @@ -980,157 +968,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; - - *chunk_sample = 0; - *chunk = 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; + 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; - 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 *t = f->track[track]; - - if (t->stsz_sample_size) - return (sample - chunk_sample) * t->stsz_sample_size; - for (i = chunk_sample, total = 0; i < sample; i++) - total += t->stsz_table[i]; - return total; + 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_get_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; } -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. - * - * \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) -{ - return f->track[track]->is_audio; -} - -int mp4_set_sample_position(struct mp4 *f, uint32_t track, int32_t sample) +int mp4_set_sample_position(struct mp4 *f, int32_t sample) { - const struct mp4_track *t = f->track[track]; + const struct mp4_track *t = f->audio_track; int32_t offset, chunk, chunk_sample; + uint32_t n, srs; /* sample range size */ - if (sample >= t->stsz_sample_count || track >= f->total_tracks) + if (sample >= t->stsz_sample_count) return -ERRNO_TO_PARA_ERROR(EINVAL); - 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); + 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; } @@ -1140,7 +1064,7 @@ struct mp4 *mp4_open_meta(const struct mp4_callback *cb) struct mp4 *f = para_calloc(sizeof(struct mp4)); f->cb = cb; - ret = parse_atoms(f, 1); + ret = parse_root_atoms(f, true); if (ret < 0) { free(f); return NULL;