X-Git-Url: http://git.tuebingen.mpg.de/?a=blobdiff_plain;f=mp4.c;h=d9f86fc7414685c5448252f8e8048c2979935d88;hb=30ce255fc5db519c06240951c1a36956ade789fc;hp=548f78ec391e95f892fdba61cf2140db25a473d0;hpb=05ffeb76c9640ff36722d8f4e9787e3ef1b187d3;p=paraslash.git diff --git a/mp4.c b/mp4.c index 548f78ec..d9f86fc7 100644 --- a/mp4.c +++ b/mp4.c @@ -12,7 +12,7 @@ #include "string.h" #include "mp4.h" -struct mp4ff_track { +struct mp4_track { int32_t type; int32_t channelCount; int32_t sampleSize; @@ -60,9 +60,9 @@ struct mp4ff_track { #define MAX_TRACKS 1024 -struct mp4ff { +struct mp4 { /* stream to read from */ - struct mp4ff_callback *stream; + struct mp4_callback *stream; int64_t current_position; uint64_t moov_offset; @@ -79,18 +79,18 @@ struct mp4ff { int32_t total_tracks; /* track data */ - struct mp4ff_track *track[MAX_TRACKS]; + struct mp4_track *track[MAX_TRACKS]; /* metadata */ - struct mp4ff_metadata tags; + struct mp4_metadata tags; }; -int32_t mp4ff_total_tracks(const struct mp4ff *f) +int32_t mp4_total_tracks(const struct mp4 *f) { return f->total_tracks; } -static int32_t read_data(struct mp4ff *f, void *data, uint32_t size) +static int32_t read_data(struct mp4 *f, void *data, uint32_t size) { int32_t result = 1; @@ -104,7 +104,7 @@ static int32_t read_data(struct mp4ff *f, void *data, uint32_t size) return result; } -static uint64_t read_int64(struct mp4ff *f) +static uint64_t read_int64(struct mp4 *f) { uint8_t data[8]; @@ -368,7 +368,7 @@ static uint8_t atom_name_to_type(int8_t a, int8_t b, int8_t c, int8_t d) } /* read atom header, return atom size, atom size is with header included */ -static uint64_t atom_read_header(struct mp4ff *f, uint8_t * atom_type, +static uint64_t atom_read_header(struct mp4 *f, uint8_t * atom_type, uint8_t * header_size) { uint64_t size; @@ -392,7 +392,7 @@ static uint64_t atom_read_header(struct mp4ff *f, uint8_t * atom_type, return size; } -static int64_t get_position(const struct mp4ff *f) +static int64_t get_position(const struct mp4 *f) { return f->current_position; } @@ -418,7 +418,7 @@ static int need_parse_when_meta_only(uint8_t atom_type) } } -static int32_t set_position(struct mp4ff *f, int64_t position) +static int32_t set_position(struct mp4 *f, int64_t position) { f->stream->seek(f->stream->user_data, position); f->current_position = position; @@ -426,7 +426,7 @@ static int32_t set_position(struct mp4ff *f, int64_t position) return 0; } -static void track_add(struct mp4ff *f) +static void track_add(struct mp4 *f) { f->total_tracks++; @@ -435,17 +435,17 @@ static void track_add(struct mp4ff *f) f->error++; return; } - f->track[f->total_tracks - 1] = para_calloc(sizeof(struct mp4ff_track)); + f->track[f->total_tracks - 1] = para_calloc(sizeof(struct mp4_track)); } -static uint8_t read_char(struct mp4ff *f) +static uint8_t read_char(struct mp4 *f) { uint8_t output; read_data(f, &output, 1); return output; } -static uint32_t read_int24(struct mp4ff *f) +static uint32_t read_int24(struct mp4 *f) { int8_t data[4]; @@ -453,7 +453,7 @@ static uint32_t read_int24(struct mp4ff *f) return read_u24_be(data); } -static uint32_t read_int32(struct mp4ff *f) +static uint32_t read_int32(struct mp4 *f) { int8_t data[4]; @@ -461,10 +461,10 @@ static uint32_t read_int32(struct mp4ff *f) return read_u32_be(data); } -static int32_t read_stsz(struct mp4ff *f) +static int32_t read_stsz(struct mp4 *f) { int32_t i; - struct mp4ff_track *t; + struct mp4_track *t; if (f->total_tracks == 0) return f->error++; @@ -481,10 +481,10 @@ static int32_t read_stsz(struct mp4ff *f) return 0; } -static int32_t read_stts(struct mp4ff *f) +static int32_t read_stts(struct mp4 *f) { int32_t i; - struct mp4ff_track *t; + struct mp4_track *t; /* CVE-2017-9223 */ if (f->total_tracks == 0) @@ -508,10 +508,10 @@ static int32_t read_stts(struct mp4ff *f) return 1; } -static int32_t read_ctts(struct mp4ff *f) +static int32_t read_ctts(struct mp4 *f) { int32_t i; - struct mp4ff_track *t; + struct mp4_track *t; if (f->total_tracks == 0) return f->error++; @@ -536,10 +536,10 @@ static int32_t read_ctts(struct mp4ff *f) return 1; } -static int32_t read_stsc(struct mp4ff *f) +static int32_t read_stsc(struct mp4 *f) { int32_t i; - struct mp4ff_track *t; + struct mp4_track *t; if (f->total_tracks == 0) return f->error++; @@ -563,10 +563,10 @@ static int32_t read_stsc(struct mp4ff *f) return 0; } -static int32_t read_stco(struct mp4ff *f) +static int32_t read_stco(struct mp4 *f) { int32_t i; - struct mp4ff_track *t; + struct mp4_track *t; if (f->total_tracks == 0) return f->error++; @@ -583,7 +583,7 @@ static int32_t read_stco(struct mp4ff *f) return 0; } -static uint16_t read_int16(struct mp4ff *f) +static uint16_t read_int16(struct mp4 *f) { int8_t data[2]; @@ -591,7 +591,7 @@ static uint16_t read_int16(struct mp4ff *f) return read_u16_be(data); } -static uint32_t read_mp4_descr_length(struct mp4ff *f) +static uint32_t read_mp4_descr_length(struct mp4 *f) { uint8_t b; uint8_t numBytes = 0; @@ -605,11 +605,11 @@ static uint32_t read_mp4_descr_length(struct mp4ff *f) return length; } -static int32_t read_esds(struct mp4ff *f) +static int32_t read_esds(struct mp4 *f) { uint8_t tag; uint32_t temp; - struct mp4ff_track *t; + struct mp4_track *t; if (f->total_tracks == 0) return f->error++; @@ -659,12 +659,12 @@ static int32_t read_esds(struct mp4ff *f) return 0; } -static int32_t read_mp4a(struct mp4ff *f) +static int32_t read_mp4a(struct mp4 *f) { int32_t i; uint8_t atom_type = 0; uint8_t header_size = 0; - struct mp4ff_track *t; + struct mp4_track *t; if (f->total_tracks == 0) return f->error++; @@ -694,11 +694,11 @@ static int32_t read_mp4a(struct mp4ff *f) return 0; } -static int32_t read_stsd(struct mp4ff *f) +static int32_t read_stsd(struct mp4 *f) { int32_t i; uint8_t header_size = 0; - struct mp4ff_track *t; + struct mp4_track *t; /* CVE-2017-9218 */ if (f->total_tracks == 0) @@ -734,7 +734,7 @@ static int32_t read_stsd(struct mp4ff *f) return 0; } -static int32_t read_mvhd(struct mp4ff *f) +static int32_t read_mvhd(struct mp4 *f) { int32_t i; @@ -760,14 +760,13 @@ static int32_t read_mvhd(struct mp4ff *f) return 0; } -static int32_t tag_add_field(struct mp4ff_metadata *tags, const char *item, +static int32_t tag_add_field(struct mp4_metadata *tags, const char *item, const char *value, int32_t len) { if (!item || (item && !*item) || !value) return 0; - tags->tags = para_realloc(tags->tags, - (tags->count + 1) * sizeof(struct mp4ff_tag)); + (tags->count + 1) * sizeof(struct mp4_tag)); tags->tags[tags->count].item = para_strdup(item); tags->tags[tags->count].len = len; if (len >= 0) { @@ -821,7 +820,7 @@ static const char *meta_index_to_genre(uint32_t idx) } } -static char *read_string(struct mp4ff *f, uint32_t length) +static char *read_string(struct mp4 *f, uint32_t length) { char *str = para_malloc(length + 1); if ((uint32_t)read_data(f, str, length) != length) { @@ -969,7 +968,7 @@ static uint32_t min_body_size(uint8_t atom_type) } } -static int32_t parse_tag(struct mp4ff *f, uint8_t parent, int32_t size) +static int32_t parse_tag(struct mp4 *f, uint8_t parent, int32_t size) { uint8_t atom_type; uint8_t header_size = 0; @@ -1060,10 +1059,10 @@ static int32_t parse_tag(struct mp4ff *f, uint8_t parent, int32_t size) return 1; } -static int32_t read_mdhd(struct mp4ff *f) +static int32_t read_mdhd(struct mp4 *f) { uint32_t version; - struct mp4ff_track *t; + struct mp4_track *t; /* CVE-2017-9221 */ if (f->total_tracks == 0) @@ -1091,7 +1090,7 @@ static int32_t read_mdhd(struct mp4ff *f) return 1; } -static int32_t parse_metadata(struct mp4ff *f, int32_t size) +static int32_t parse_metadata(struct mp4 *f, int32_t size) { uint64_t subsize, sumsize = 0; uint8_t atom_type; @@ -1108,7 +1107,7 @@ static int32_t parse_metadata(struct mp4ff *f, int32_t size) return 0; } -static int32_t read_meta(struct mp4ff *f, uint64_t size) +static int32_t read_meta(struct mp4 *f, uint64_t size) { uint64_t subsize, sumsize = 0; uint8_t atom_type; @@ -1132,7 +1131,7 @@ static int32_t read_meta(struct mp4ff *f, uint64_t size) return 0; } -static int32_t atom_read(struct mp4ff *f, int32_t size, uint8_t atom_type) +static int32_t atom_read(struct mp4 *f, int32_t size, uint8_t atom_type) { uint64_t dest_position = get_position(f) + size - 8; if (atom_type == ATOM_STSZ) { @@ -1169,7 +1168,7 @@ static int32_t atom_read(struct mp4ff *f, int32_t size, uint8_t atom_type) } /* parse atoms that are sub atoms of other atoms */ -static int32_t parse_sub_atoms(struct mp4ff *f, uint64_t total_size, int meta_only) +static int32_t parse_sub_atoms(struct mp4 *f, uint64_t total_size, int meta_only) { uint64_t size; uint8_t atom_type = 0; @@ -1203,7 +1202,7 @@ static int32_t parse_sub_atoms(struct mp4ff *f, uint64_t total_size, int meta_on } /* parse root atoms */ -static int32_t parse_atoms(struct mp4ff *f, int meta_only) +static int32_t parse_atoms(struct mp4 *f, int meta_only) { uint64_t size; uint8_t atom_type = 0; @@ -1236,7 +1235,7 @@ static int32_t parse_atoms(struct mp4ff *f, int meta_only) return 0; } -void mp4ff_get_decoder_config(const struct mp4ff *f, int track, +void mp4_get_decoder_config(const struct mp4 *f, int track, unsigned char **ppBuf, unsigned int *pBufSize) { if (track >= f->total_tracks) { @@ -1257,9 +1256,9 @@ void mp4ff_get_decoder_config(const struct mp4ff *f, int track, } } -struct mp4ff *mp4ff_open_read(struct mp4ff_callback *f) +struct mp4 *mp4_open_read(struct mp4_callback *f) { - struct mp4ff *ff = para_calloc(sizeof(struct mp4ff)); + struct mp4 *ff = para_calloc(sizeof(struct mp4)); ff->stream = f; @@ -1273,7 +1272,7 @@ struct mp4ff *mp4ff_open_read(struct mp4ff_callback *f) return ff; } -static int32_t tag_delete(struct mp4ff_metadata *tags) +static int32_t tag_delete(struct mp4_metadata *tags) { uint32_t i; @@ -1288,7 +1287,7 @@ static int32_t tag_delete(struct mp4ff_metadata *tags) return 0; } -void mp4ff_close(struct mp4ff *ff) +void mp4_close(struct mp4 *ff) { int32_t i; @@ -1312,7 +1311,7 @@ void mp4ff_close(struct mp4ff *ff) free(ff); } -static int32_t chunk_of_sample(const struct mp4ff *f, int32_t track, +static int32_t chunk_of_sample(const struct mp4 *f, int32_t track, int32_t sample, int32_t *chunk_sample, int32_t *chunk) { int32_t total_entries = 0; @@ -1358,10 +1357,10 @@ static int32_t chunk_of_sample(const struct mp4ff *f, int32_t track, return 0; } -static int32_t chunk_to_offset(const struct mp4ff *f, int32_t track, +static int32_t chunk_to_offset(const struct mp4 *f, int32_t track, int32_t chunk) { - const struct mp4ff_track *p_track = f->track[track]; + 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 - @@ -1375,11 +1374,11 @@ static int32_t chunk_to_offset(const struct mp4ff *f, int32_t track, return 0; } -static int32_t sample_range_size(const struct mp4ff *f, int32_t track, +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 mp4ff_track *p_track = f->track[track]; + const struct mp4_track *p_track = f->track[track]; if (p_track->stsz_sample_size) { return (sample - chunk_sample) * p_track->stsz_sample_size; @@ -1395,7 +1394,7 @@ static int32_t sample_range_size(const struct mp4ff *f, int32_t track, return total; } -static int32_t sample_to_offset(const struct mp4ff *f, int32_t track, +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; @@ -1408,32 +1407,50 @@ static int32_t sample_to_offset(const struct mp4ff *f, int32_t track, return chunk_offset2; } -void mp4ff_set_sample_position(struct mp4ff *f, int32_t track, int32_t sample) +/** + * 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(). + * + * 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) +{ + const struct mp4_track *t = f->track[track]; + + if (t->timeScale == 0) + return 0; + return t->duration * 1000 / t->timeScale; +} + +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); } -int32_t mp4ff_get_sample_size(const struct mp4ff *f, int track, int sample) +int32_t mp4_get_sample_size(const struct mp4 *f, int track, int sample) { - const struct mp4ff_track *t = f->track[track]; + const struct mp4_track *t = f->track[track]; if (t->stsz_sample_size != 0) return t->stsz_sample_size; return t->stsz_table[sample]; } -uint32_t mp4ff_get_sample_rate(const struct mp4ff *f, int32_t track) +uint32_t mp4_get_sample_rate(const struct mp4 *f, int32_t track) { return f->track[track]->sampleRate; } -uint32_t mp4ff_get_channel_count(const struct mp4ff *f, int32_t track) +uint32_t mp4_get_channel_count(const struct mp4 *f, int32_t track) { return f->track[track]->channelCount; } -int32_t mp4ff_num_samples(const struct mp4ff *f, int32_t track) +int32_t mp4_num_samples(const struct mp4 *f, int32_t track) { int32_t i; int32_t total = 0; @@ -1444,9 +1461,9 @@ int32_t mp4ff_num_samples(const struct mp4ff *f, int32_t track) return total; } -struct mp4ff *mp4ff_open_read_metaonly(struct mp4ff_callback *f) +struct mp4 *mp4_open_meta(struct mp4_callback *f) { - struct mp4ff *ff = para_calloc(sizeof(struct mp4ff)); + struct mp4 *ff = para_calloc(sizeof(struct mp4)); ff->stream = f; @@ -1460,12 +1477,12 @@ struct mp4ff *mp4ff_open_read_metaonly(struct mp4ff_callback *f) return ff; } -int32_t mp4ff_meta_get_num_items(const struct mp4ff *f) +int32_t mp4_meta_get_num_items(const struct mp4 *f) { return f->tags.count; } -int32_t mp4ff_meta_get_by_index(const struct mp4ff *f, uint32_t index, +int32_t mp4_meta_get_by_index(const struct mp4 *f, uint32_t index, char **item, char **value) { if (index >= f->tags.count) { @@ -1479,7 +1496,7 @@ int32_t mp4ff_meta_get_by_index(const struct mp4ff *f, uint32_t index, } } -static uint32_t find_atom(struct mp4ff *f, uint64_t base, uint32_t size, +static uint32_t find_atom(struct mp4 *f, uint64_t base, uint32_t size, const char *name) { uint32_t remaining = size; @@ -1508,7 +1525,7 @@ static uint32_t find_atom(struct mp4ff *f, uint64_t base, uint32_t size, return 0; } -static uint32_t find_atom_v2(struct mp4ff *f, uint64_t base, uint32_t size, +static uint32_t find_atom_v2(struct mp4 *f, uint64_t base, uint32_t size, const char *name, uint32_t extraheaders, const char *name_inside) { uint64_t first_base = (uint64_t) (-1); @@ -1758,7 +1775,7 @@ static void *membuffer_detach(struct membuffer *buf) return ret; } -static uint32_t create_ilst(const struct mp4ff_metadata *data, void **out_buffer, +static uint32_t create_ilst(const struct mp4_metadata *data, void **out_buffer, uint32_t * out_size) { struct membuffer *buf = membuffer_create(); @@ -1769,7 +1786,7 @@ static uint32_t create_ilst(const struct mp4ff_metadata *data, void **out_buffer const char *genre_ptr = 0, *tempo_ptr = 0; for (metaptr = 0; metaptr < data->count; metaptr++) { - struct mp4ff_tag *tag = &data->tags[metaptr]; + struct mp4_tag *tag = &data->tags[metaptr]; if (!strcasecmp(tag->item, "tracknumber") || !strcasecmp(tag->item, "track")) { if (tracknumber_ptr == 0) @@ -1816,7 +1833,7 @@ static uint32_t create_ilst(const struct mp4ff_metadata *data, void **out_buffer membuffer_write_int16_tag(buf, "gnre", index); } for (metaptr = 0; metaptr < data->count; metaptr++) { - struct mp4ff_tag *tag; + struct mp4_tag *tag; const char *std_meta_atom; if (mask[metaptr]) @@ -1860,7 +1877,7 @@ static void membuffer_set_error(struct membuffer *buf) buf->error = 1; } -static unsigned membuffer_transfer_from_file(struct membuffer *buf, struct mp4ff *src, +static unsigned membuffer_transfer_from_file(struct membuffer *buf, struct mp4 *src, unsigned bytes) { unsigned oldsize; @@ -1883,7 +1900,7 @@ static unsigned membuffer_transfer_from_file(struct membuffer *buf, struct mp4ff return bytes; } -static uint32_t create_meta(const struct mp4ff_metadata *data, void **out_buffer, +static uint32_t create_meta(const struct mp4_metadata *data, void **out_buffer, uint32_t * out_size) { struct membuffer *buf; @@ -1905,7 +1922,7 @@ static uint32_t create_meta(const struct mp4ff_metadata *data, void **out_buffer return 1; } -static uint32_t create_udta(const struct mp4ff_metadata *data, void **out_buffer, +static uint32_t create_udta(const struct mp4_metadata *data, void **out_buffer, uint32_t * out_size) { struct membuffer *buf; @@ -1932,7 +1949,7 @@ static uint32_t fix_byte_order_32(uint32_t src) return read_u32_be(&src); } -static uint32_t modify_moov(struct mp4ff *f, const struct mp4ff_metadata *data, +static uint32_t modify_moov(struct mp4 *f, const struct mp4_metadata *data, void **out_buffer, uint32_t * out_size) { uint64_t total_base = f->moov_offset + 8; @@ -2046,7 +2063,7 @@ static uint32_t modify_moov(struct mp4ff *f, const struct mp4ff_metadata *data, return 1; } -static int32_t write_data(struct mp4ff *f, void *data, uint32_t size) +static int32_t write_data(struct mp4 *f, void *data, uint32_t size) { int32_t result = 1; @@ -2057,31 +2074,31 @@ static int32_t write_data(struct mp4ff *f, void *data, uint32_t size) return result; } -static int32_t write_int32(struct mp4ff *f, uint32_t data) +static int32_t write_int32(struct mp4 *f, uint32_t data) { int8_t temp[4]; write_u32_be(temp, data); return write_data(f, temp, sizeof(temp)); } -static int32_t truncate_stream(struct mp4ff *f) +static int32_t truncate_stream(struct mp4 *f) { return f->stream->truncate(f->stream->user_data); } -int32_t mp4ff_meta_update(struct mp4ff_callback *f, const struct mp4ff_metadata *data) +int32_t mp4_meta_update(struct mp4_callback *f, const struct mp4_metadata *data) { void *new_moov_data; uint32_t new_moov_size; - struct mp4ff *ff = para_calloc(sizeof(struct mp4ff)); + struct mp4 *ff = para_calloc(sizeof(struct mp4)); ff->stream = f; set_position(ff, 0); parse_atoms(ff, 1); if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) { - mp4ff_close(ff); + mp4_close(ff); return 0; } @@ -2106,13 +2123,13 @@ int32_t mp4ff_meta_update(struct mp4ff_callback *f, const struct mp4ff_metadata truncate_stream(ff); - mp4ff_close(ff); + mp4_close(ff); return 1; } /* find a metadata item by name */ /* returns 0 if item found, 1 if no such item */ -static int32_t meta_find_by_name(const struct mp4ff *f, const char *item, +static int32_t meta_find_by_name(const struct mp4 *f, const char *item, char **value) { uint32_t i; @@ -2130,27 +2147,27 @@ static int32_t meta_find_by_name(const struct mp4ff *f, const char *item, return 0; } -int32_t mp4ff_meta_get_artist(const struct mp4ff *f, char **value) +int32_t mp4_meta_get_artist(const struct mp4 *f, char **value) { return meta_find_by_name(f, "artist", value); } -int32_t mp4ff_meta_get_title(const struct mp4ff *f, char **value) +int32_t mp4_meta_get_title(const struct mp4 *f, char **value) { return meta_find_by_name(f, "title", value); } -int32_t mp4ff_meta_get_date(const struct mp4ff *f, char **value) +int32_t mp4_meta_get_date(const struct mp4 *f, char **value) { return meta_find_by_name(f, "date", value); } -int32_t mp4ff_meta_get_album(const struct mp4ff *f, char **value) +int32_t mp4_meta_get_album(const struct mp4 *f, char **value) { return meta_find_by_name(f, "album", value); } -int32_t mp4ff_meta_get_comment(const struct mp4ff *f, char **value) +int32_t mp4_meta_get_comment(const struct mp4 *f, char **value) { return meta_find_by_name(f, "comment", value); }