2 * Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com
3 * FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
11 #include "portable_io.h"
22 int32_t stsd_entry_count;
25 int32_t stsz_sample_size;
26 int32_t stsz_sample_count;
30 int32_t stts_entry_count;
31 int32_t *stts_sample_count;
32 int32_t *stts_sample_delta;
35 int32_t stsc_entry_count;
36 int32_t *stsc_first_chunk;
37 int32_t *stsc_samples_per_chunk;
38 int32_t *stsc_sample_desc_index;
41 int32_t stco_entry_count;
42 int32_t *stco_chunk_offset;
45 int32_t ctts_entry_count;
46 int32_t *ctts_sample_count;
47 int32_t *ctts_sample_offset;
56 #define MAX_TRACKS 1024
59 /* stream to read from */
60 struct mp4_callback *stream;
61 int64_t current_position;
73 /* incremental track index while reading the file */
77 struct mp4_track *track[MAX_TRACKS];
80 struct mp4_metadata tags;
83 int32_t mp4_total_tracks(const struct mp4 *f)
85 return f->total_tracks;
88 static int32_t read_data(struct mp4 *f, void *data, uint32_t size)
92 result = f->stream->read(f->stream->user_data, data, size);
95 f->stream->read_error++;
97 f->current_position += size;
102 static uint64_t read_int64(struct mp4 *f)
106 read_data(f, data, 8);
107 return read_u64_be(data);
110 /* comnapre 2 atom names, returns 1 for equal, 0 for unequal */
111 static int32_t atom_compare(int8_t a1, int8_t b1, int8_t c1, int8_t d1,
112 int8_t a2, int8_t b2, int8_t c2, int8_t d2)
114 if (a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2)
128 /* atoms with subatoms */
136 ATOM_ILST = 8, /* iTunes Metadata list */
147 ATOM_COMPILATION = 19,
157 /* atoms without subatoms */
177 ATOM_META = 148, /* iTunes Metadata box */
178 ATOM_NAME = 149, /* iTunes Metadata name box */
179 ATOM_DATA = 150, /* iTunes Metadata data box */
186 ATOM_ALBUM_ARTIST = 157,
187 ATOM_CONTENTGROUP = 158,
189 ATOM_DESCRIPTION = 160,
192 ATOM_EPISODENAME = 163,
193 ATOM_SORTTITLE = 164,
194 ATOM_SORTALBUM = 165,
195 ATOM_SORTARTIST = 166,
196 ATOM_SORTALBUMARTIST = 167,
197 ATOM_SORTWRITER = 168,
206 #define ATOM_FREE ATOM_UNKNOWN
207 #define ATOM_SKIP ATOM_UNKNOWN
209 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
211 static uint8_t atom_name_to_type(int8_t a, int8_t b, int8_t c, int8_t d)
214 if (atom_compare(a, b, c, d, 'm', 'o', 'o', 'v'))
216 else if (atom_compare(a, b, c, d, 'm', 'i', 'n', 'f'))
218 else if (atom_compare(a, b, c, d, 'm', 'd', 'i', 'a'))
220 else if (atom_compare(a, b, c, d, 'm', 'd', 'a', 't'))
222 else if (atom_compare(a, b, c, d, 'm', 'd', 'h', 'd'))
224 else if (atom_compare(a, b, c, d, 'm', 'v', 'h', 'd'))
226 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'a'))
228 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'v'))
230 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 's'))
232 else if (atom_compare(a, b, c, d, 'm', 'e', 't', 'a'))
234 } else if (a == 't') {
235 if (atom_compare(a, b, c, d, 't', 'r', 'a', 'k'))
237 else if (atom_compare(a, b, c, d, 't', 'k', 'h', 'd'))
239 else if (atom_compare(a, b, c, d, 't', 'r', 'e', 'f'))
241 else if (atom_compare(a, b, c, d, 't', 'r', 'k', 'n'))
243 else if (atom_compare(a, b, c, d, 't', 'm', 'p', 'o'))
245 else if (atom_compare(a, b, c, d, 't', 'v', 'n', 'n'))
247 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'h'))
249 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 'n'))
250 return ATOM_EPISODENAME;
251 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'n'))
253 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 's'))
255 } else if (a == 's') {
256 if (atom_compare(a, b, c, d, 's', 't', 'b', 'l'))
258 else if (atom_compare(a, b, c, d, 's', 'm', 'h', 'd'))
260 else if (atom_compare(a, b, c, d, 's', 't', 's', 'd'))
262 else if (atom_compare(a, b, c, d, 's', 't', 't', 's'))
264 else if (atom_compare(a, b, c, d, 's', 't', 'c', 'o'))
266 else if (atom_compare(a, b, c, d, 's', 't', 's', 'c'))
268 else if (atom_compare(a, b, c, d, 's', 't', 's', 'z'))
270 else if (atom_compare(a, b, c, d, 's', 't', 'z', '2'))
272 else if (atom_compare(a, b, c, d, 's', 'k', 'i', 'p'))
274 else if (atom_compare(a, b, c, d, 's', 'i', 'n', 'f'))
276 else if (atom_compare(a, b, c, d, 's', 'c', 'h', 'i'))
278 else if (atom_compare(a, b, c, d, 's', 'o', 'n', 'm'))
279 return ATOM_SORTTITLE;
280 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'l'))
281 return ATOM_SORTALBUM;
282 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'r'))
283 return ATOM_SORTARTIST;
284 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'a'))
285 return ATOM_SORTALBUMARTIST;
286 else if (atom_compare(a, b, c, d, 's', 'o', 'c', 'o'))
287 return ATOM_SORTWRITER;
288 else if (atom_compare(a, b, c, d, 's', 'o', 's', 'n'))
289 return ATOM_SORTSHOW;
290 } else if (a == COPYRIGHT_SYMBOL) {
291 if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'n', 'a', 'm'))
293 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'A', 'R', 'T'))
295 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'w', 'r', 't'))
297 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'a', 'l', 'b'))
299 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'd', 'a', 'y'))
301 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 't', 'o', 'o'))
303 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'c', 'm', 't'))
305 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'e', 'n'))
307 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'r', 'p'))
308 return ATOM_CONTENTGROUP;
309 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'l', 'y', 'r'))
313 if (atom_compare(a, b, c, d, 'e', 'd', 't', 's'))
315 else if (atom_compare(a, b, c, d, 'e', 's', 'd', 's'))
317 else if (atom_compare(a, b, c, d, 'f', 't', 'y', 'p'))
319 else if (atom_compare(a, b, c, d, 'f', 'r', 'e', 'e'))
321 else if (atom_compare(a, b, c, d, 'h', 'm', 'h', 'd'))
323 else if (atom_compare(a, b, c, d, 'v', 'm', 'h', 'd'))
325 else if (atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
327 else if (atom_compare(a, b, c, d, 'i', 'l', 's', 't'))
329 else if (atom_compare(a, b, c, d, 'n', 'a', 'm', 'e'))
331 else if (atom_compare(a, b, c, d, 'd', 'a', 't', 'a'))
333 else if (atom_compare(a, b, c, d, 'd', 'i', 's', 'k'))
335 else if (atom_compare(a, b, c, d, 'g', 'n', 'r', 'e'))
337 else if (atom_compare(a, b, c, d, 'c', 'o', 'v', 'r'))
339 else if (atom_compare(a, b, c, d, 'c', 'p', 'i', 'l'))
340 return ATOM_COMPILATION;
341 else if (atom_compare(a, b, c, d, 'c', 't', 't', 's'))
343 else if (atom_compare(a, b, c, d, 'd', 'r', 'm', 's'))
345 else if (atom_compare(a, b, c, d, 'f', 'r', 'm', 'a'))
347 else if (atom_compare(a, b, c, d, 'p', 'r', 'i', 'v'))
349 else if (atom_compare(a, b, c, d, 'i', 'v', 'i', 'v'))
351 else if (atom_compare(a, b, c, d, 'u', 's', 'e', 'r'))
353 else if (atom_compare(a, b, c, d, 'k', 'e', 'y', ' '))
355 else if (atom_compare(a, b, c, d, 'a', 'A', 'R', 'T'))
356 return ATOM_ALBUM_ARTIST;
357 else if (atom_compare(a, b, c, d, 'd', 'e', 's', 'c'))
358 return ATOM_DESCRIPTION;
359 else if (atom_compare(a, b, c, d, 'p', 'c', 's', 't'))
365 /* read atom header, return atom size, atom size is with header included */
366 static uint64_t atom_read_header(struct mp4 *f, uint8_t * atom_type,
367 uint8_t * header_size)
371 int8_t atom_header[8];
373 ret = read_data(f, atom_header, 8);
377 size = read_u32_be(atom_header);
380 /* check for 64 bit atom size */
383 size = read_int64(f);
385 *atom_type = atom_name_to_type(atom_header[4], atom_header[5],
386 atom_header[6], atom_header[7]);
390 static int64_t get_position(const struct mp4 *f)
392 return f->current_position;
395 static int need_parse_when_meta_only(uint8_t atom_type)
416 static int32_t set_position(struct mp4 *f, int64_t position)
418 f->stream->seek(f->stream->user_data, position);
419 f->current_position = position;
424 static void track_add(struct mp4 *f)
428 if (f->total_tracks > MAX_TRACKS) {
433 f->track[f->total_tracks - 1] = para_calloc(sizeof(struct mp4_track));
436 static uint8_t read_char(struct mp4 *f)
439 read_data(f, &output, 1);
443 static uint32_t read_int24(struct mp4 *f)
447 read_data(f, data, 3);
448 return read_u24_be(data);
451 static uint32_t read_int32(struct mp4 *f)
455 read_data(f, data, 4);
456 return read_u32_be(data);
459 static int32_t read_stsz(struct mp4 *f)
464 if (f->total_tracks == 0)
466 t = f->track[f->total_tracks - 1];
467 read_char(f); /* version */
468 read_int24(f); /* flags */
469 t->stsz_sample_size = read_int32(f);
470 t->stsz_sample_count = read_int32(f);
471 if (t->stsz_sample_size != 0)
473 t->stsz_table = para_malloc(t->stsz_sample_count * sizeof(int32_t));
474 for (i = 0; i < t->stsz_sample_count && !f->stream->read_error; i++)
475 t->stsz_table[i] = read_int32(f);
479 static int32_t read_stts(struct mp4 *f)
485 if (f->total_tracks == 0)
487 t = f->track[f->total_tracks - 1];
488 if (t->stts_entry_count)
490 read_char(f); /* version */
491 read_int24(f); /* flags */
492 t->stts_entry_count = read_int32(f);
494 t->stts_sample_count = para_malloc(t->stts_entry_count
496 t->stts_sample_delta = para_malloc(t->stts_entry_count
499 for (i = 0; i < t->stts_entry_count && !f->stream->read_error; i++) {
500 t->stts_sample_count[i] = read_int32(f);
501 t->stts_sample_delta[i] = read_int32(f);
506 static int32_t read_ctts(struct mp4 *f)
511 if (f->total_tracks == 0)
513 t = f->track[f->total_tracks - 1];
514 if (t->ctts_entry_count)
517 read_char(f); /* version */
518 read_int24(f); /* flags */
519 t->ctts_entry_count = read_int32(f);
521 t->ctts_sample_count = para_malloc(t->ctts_entry_count
523 t->ctts_sample_offset = para_malloc(t->ctts_entry_count
527 for (i = 0; i < t->ctts_entry_count && !f->stream->read_error; i++) {
528 t->ctts_sample_count[i] = read_int32(f);
529 t->ctts_sample_offset[i] = read_int32(f);
534 static int32_t read_stsc(struct mp4 *f)
539 if (f->total_tracks == 0)
541 t = f->track[f->total_tracks - 1];
543 read_char(f); /* version */
544 read_int24(f); /* flags */
545 t->stsc_entry_count = read_int32(f);
546 t->stsc_first_chunk = para_malloc(t->stsc_entry_count * sizeof(int32_t));
547 t->stsc_samples_per_chunk = para_malloc(t->stsc_entry_count
549 t->stsc_sample_desc_index = para_malloc(t->stsc_entry_count *
553 for (i = 0; i < t->stsc_entry_count && !f->stream->read_error; i++) {
554 t->stsc_first_chunk[i] = read_int32(f);
555 t->stsc_samples_per_chunk[i] = read_int32(f);
556 t->stsc_sample_desc_index[i] = read_int32(f);
561 static int32_t read_stco(struct mp4 *f)
566 if (f->total_tracks == 0)
568 t = f->track[f->total_tracks - 1];
570 read_char(f); /* version */
571 read_int24(f); /* flags */
572 t->stco_entry_count = read_int32(f);
573 t->stco_chunk_offset = para_malloc(t->stco_entry_count
576 for (i = 0; i < t->stco_entry_count && !f->stream->read_error; i++)
577 t->stco_chunk_offset[i] = read_int32(f);
581 static uint16_t read_int16(struct mp4 *f)
585 read_data(f, data, 2);
586 return read_u16_be(data);
589 static int32_t read_mp4a(struct mp4 *f)
592 uint8_t atom_type = 0;
593 uint8_t header_size = 0;
596 if (f->total_tracks == 0)
598 t = f->track[f->total_tracks - 1];
600 for (i = 0; i < 6; i++) {
601 read_char(f); /* reserved */
603 /* data_reference_index */ read_int16(f);
605 read_int32(f); /* reserved */
606 read_int32(f); /* reserved */
608 t->channelCount = read_int16(f);
609 t->sampleSize = read_int16(f);
614 t->sampleRate = read_int16(f);
618 atom_read_header(f, &atom_type, &header_size);
622 static int32_t read_stsd(struct mp4 *f)
625 uint8_t header_size = 0;
629 if (f->total_tracks == 0)
631 t = f->track[f->total_tracks - 1];
633 read_char(f); /* version */
634 read_int24(f); /* flags */
636 t->stsd_entry_count = read_int32(f);
639 for (i = 0; i < t->stsd_entry_count && !f->stream->read_error; i++) {
640 uint64_t skip = get_position(f);
642 uint8_t atom_type = 0;
643 size = atom_read_header(f, &atom_type, &header_size);
646 if (atom_type == ATOM_MP4A) {
647 t->type = TRACK_AUDIO;
649 } else if (atom_type == ATOM_MP4V) {
650 t->type = TRACK_VIDEO;
651 } else if (atom_type == ATOM_MP4S) {
652 t->type = TRACK_SYSTEM;
654 t->type = TRACK_UNKNOWN;
656 set_position(f, skip);
662 static int32_t read_mvhd(struct mp4 *f)
666 read_char(f); /* version */
667 read_int24(f); /* flags */
668 read_int32(f); /* creation_time */
669 read_int32(f); /* modification_time */
670 f->time_scale = read_int32(f);
671 f->duration = read_int32(f);
672 read_int32(f); /* preferred_rate */
673 read_int16(f); /* preferred_volume */
674 for (i = 0; i < 10; i++)
675 read_char(f); /* reserved */
676 for (i = 0; i < 9; i++)
677 read_int32(f); /* matrix */
678 read_int32(f); /* preview_time */
679 read_int32(f); /* preview_duration */
680 read_int32(f); /* poster_time */
681 read_int32(f); /* selection_time */
682 read_int32(f); /* selection_duration */
683 read_int32(f); /* current_time */
684 read_int32(f); /* next_track_id */
688 static int32_t tag_add_field(struct mp4_metadata *tags, const char *item,
689 const char *value, int32_t len)
691 if (!item || (item && !*item) || !value)
693 tags->tags = para_realloc(tags->tags,
694 (tags->count + 1) * sizeof(struct mp4_tag));
695 tags->tags[tags->count].item = para_strdup(item);
696 tags->tags[tags->count].len = len;
698 tags->tags[tags->count].value = para_malloc(len + 1);
699 memcpy(tags->tags[tags->count].value, value, len);
700 tags->tags[tags->count].value[len] = 0;
702 tags->tags[tags->count].value = para_strdup(value);
708 static const char *ID3v1GenreList[] = {
709 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
710 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
711 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
712 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
713 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
714 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
715 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
716 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
717 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
718 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
719 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
720 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
721 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
722 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
723 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
724 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
725 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
726 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
727 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
728 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
729 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
730 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
731 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
732 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
733 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
734 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
735 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
736 "Anime", "JPop", "SynthPop",
739 static const char *meta_index_to_genre(uint32_t idx)
741 if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
742 return ID3v1GenreList[idx - 1];
748 static char *read_string(struct mp4 *f, uint32_t length)
750 char *str = para_malloc(length + 1);
751 if ((uint32_t)read_data(f, str, length) != length) {
759 static int32_t set_metadata_name(uint8_t atom_type, char **name)
761 static char *tag_names[] = {
762 "unknown", "title", "artist", "writer", "album",
763 "date", "tool", "comment", "genre", "track",
764 "disc", "compilation", "genre", "tempo", "cover",
765 "album_artist", "contentgroup", "lyrics", "description",
766 "network", "show", "episodename",
767 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
768 "sortwriter", "sortshow",
769 "season", "episode", "podcast"
804 case ATOM_COMPILATION:
816 case ATOM_ALBUM_ARTIST:
819 case ATOM_CONTENTGROUP:
825 case ATOM_DESCRIPTION:
834 case ATOM_EPISODENAME:
843 case ATOM_SORTARTIST:
846 case ATOM_SORTALBUMARTIST:
849 case ATOM_SORTWRITER:
869 *name = para_strdup(tag_names[tag_idx]);
873 static uint32_t min_body_size(uint8_t atom_type)
880 return sizeof (char) /* version */
881 + sizeof(uint8_t) * 3 /* flags */
882 + sizeof(uint32_t) /* reserved */
883 + sizeof(uint16_t) /* leading uint16_t */
884 + sizeof(uint16_t) /* track */
885 + sizeof(uint16_t); /* totaltracks */
887 return sizeof (char) /* version */
888 + sizeof(uint8_t) * 3 /* flags */
889 + sizeof(uint32_t) /* reserved */
890 + sizeof(uint16_t) /* disc */
891 + sizeof(uint16_t); /* totaldiscs */
892 default: assert(false);
896 static int32_t parse_tag(struct mp4 *f, uint8_t parent, int32_t size)
899 uint8_t header_size = 0;
900 uint64_t subsize, sumsize;
909 sumsize < size && !f->stream->read_error; /* CVE-2017-9222 */
910 set_position(f, destpos), sumsize += subsize
912 subsize = atom_read_header(f, &atom_type, &header_size);
913 destpos = get_position(f) + subsize - header_size;
916 if (atom_type == ATOM_NAME) {
917 read_char(f); /* version */
918 read_int24(f); /* flags */
920 name = read_string(f, subsize - (header_size + 4));
923 if (atom_type != ATOM_DATA)
925 read_char(f); /* version */
926 read_int24(f); /* flags */
927 read_int32(f); /* reserved */
929 /* some need special attention */
930 if (parent == ATOM_GENRE2 || parent == ATOM_TEMPO) {
932 if (subsize - header_size < min_body_size(parent))
935 if (parent == ATOM_TEMPO) {
937 sprintf(temp, "%.5u BPM", val);
938 tag_add_field(&(f-> tags), "tempo",
941 const char *tmp = meta_index_to_genre(val);
943 tag_add_field (&(f->tags),
947 } else if (parent == ATOM_TRACK || parent == ATOM_DISC) {
948 uint16_t index, total;
950 if (subsize - header_size < min_body_size(parent))
953 index = read_int16(f);
954 total = read_int16(f);
955 if (parent == ATOM_TRACK)
957 sprintf(temp, "%d", index);
958 tag_add_field(&(f->tags), parent == ATOM_TRACK?
959 "track" : "disc", temp, -1);
961 sprintf(temp, "%d", total);
962 tag_add_field(& (f-> tags),
963 parent == ATOM_TRACK?
964 "totaltracks" : "totaldiscs", temp, -1);
969 data = read_string(f, subsize - (header_size + 8));
970 len = subsize - (header_size + 8);
976 set_metadata_name(parent , &name);
978 tag_add_field(&(f->tags), name, data, len);
987 static int32_t read_mdhd(struct mp4 *f)
993 if (f->total_tracks == 0)
995 t = f->track[f->total_tracks - 1];
997 version = read_int32(f);
999 read_int64(f); //creation-time
1000 read_int64(f); //modification-time
1001 t->timeScale = read_int32(f); //timescale
1002 t->duration = read_int64(f); //duration
1003 } else { //version == 0
1006 read_int32(f); //creation-time
1007 read_int32(f); //modification-time
1008 t->timeScale = read_int32(f); //timescale
1009 temp = read_int32(f);
1010 t->duration = (temp == (uint32_t) (-1))?
1011 (uint64_t) (-1) : (uint64_t) (temp);
1018 static int32_t parse_metadata(struct mp4 *f, int32_t size)
1020 uint64_t subsize, sumsize = 0;
1022 uint8_t header_size = 0;
1024 while (sumsize < size) {
1025 subsize = atom_read_header(f, &atom_type, &header_size);
1028 parse_tag(f, atom_type, (uint32_t)(subsize - header_size));
1035 static int32_t read_meta(struct mp4 *f, uint64_t size)
1037 uint64_t subsize, sumsize = 0;
1039 uint8_t header_size = 0;
1041 read_char(f); /* version */
1042 read_int24(f); /* flags */
1044 while (sumsize < (size - (header_size + 4))) {
1045 subsize = atom_read_header(f, &atom_type, &header_size);
1046 if (subsize <= header_size + 4)
1048 if (atom_type == ATOM_ILST) {
1049 parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1051 set_position(f, get_position(f) + subsize - header_size);
1059 static int32_t atom_read(struct mp4 *f, int32_t size, uint8_t atom_type)
1061 uint64_t dest_position = get_position(f) + size - 8;
1062 if (atom_type == ATOM_STSZ) {
1063 /* sample size box */
1065 } else if (atom_type == ATOM_STTS) {
1066 /* time to sample box */
1068 } else if (atom_type == ATOM_CTTS) {
1069 /* composition offset box */
1071 } else if (atom_type == ATOM_STSC) {
1072 /* sample to chunk box */
1074 } else if (atom_type == ATOM_STCO) {
1075 /* chunk offset box */
1077 } else if (atom_type == ATOM_STSD) {
1078 /* sample description box */
1080 } else if (atom_type == ATOM_MVHD) {
1081 /* movie header box */
1083 } else if (atom_type == ATOM_MDHD) {
1086 } else if (atom_type == ATOM_META) {
1087 /* iTunes Metadata box */
1091 set_position(f, dest_position);
1095 /* parse atoms that are sub atoms of other atoms */
1096 static int32_t parse_sub_atoms(struct mp4 *f, uint64_t total_size, int meta_only)
1099 uint8_t atom_type = 0;
1100 uint64_t counted_size = 0;
1101 uint8_t header_size = 0;
1103 while (counted_size < total_size) {
1104 size = atom_read_header(f, &atom_type, &header_size);
1105 counted_size += size;
1107 /* check for end of file */
1111 /* we're starting to read a new track, update index,
1112 * so that all data and tables get written in the right place
1114 if (atom_type == ATOM_TRAK)
1116 /* parse subatoms */
1117 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1118 set_position(f, get_position(f) + size - header_size);
1119 } else if (atom_type < SUBATOMIC) {
1120 parse_sub_atoms(f, size - header_size, meta_only);
1122 atom_read(f, (uint32_t) size, atom_type);
1129 /* parse root atoms */
1130 static int32_t parse_atoms(struct mp4 *f, int meta_only)
1133 uint8_t atom_type = 0;
1134 uint8_t header_size = 0;
1137 f->stream->read_error = 0;
1140 atom_read_header(f, &atom_type, &header_size)) != 0) {
1141 f->file_size += size;
1142 f->last_atom = atom_type;
1144 if (atom_type == ATOM_MOOV && size > header_size) {
1145 f->moov_offset = get_position(f) - header_size;
1146 f->moov_size = size;
1149 /* parse subatoms */
1150 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1151 set_position(f, get_position(f) + size - header_size);
1152 } else if (atom_type < SUBATOMIC) {
1153 parse_sub_atoms(f, size - header_size, meta_only);
1155 /* skip this atom */
1156 set_position(f, get_position(f) + size - header_size);
1163 struct mp4 *mp4_open_read(struct mp4_callback *f)
1165 struct mp4 *ff = para_calloc(sizeof(struct mp4));
1179 static int32_t tag_delete(struct mp4_metadata *tags)
1183 for (i = 0; i < tags->count; i++) {
1184 free(tags->tags[i].item);
1185 free(tags->tags[i].value);
1194 void mp4_close(struct mp4 *ff)
1198 for (i = 0; i < ff->total_tracks; i++) {
1200 free(ff->track[i]->stsz_table);
1201 free(ff->track[i]->stts_sample_count);
1202 free(ff->track[i]->stts_sample_delta);
1203 free(ff->track[i]->stsc_first_chunk);
1204 free(ff->track[i]->stsc_samples_per_chunk);
1205 free(ff->track[i]->stsc_sample_desc_index);
1206 free(ff->track[i]->stco_chunk_offset);
1207 free(ff->track[i]->ctts_sample_count);
1208 free(ff->track[i]->ctts_sample_offset);
1213 tag_delete(&(ff->tags));
1217 static int32_t chunk_of_sample(const struct mp4 *f, int32_t track,
1218 int32_t sample, int32_t *chunk_sample, int32_t *chunk)
1220 int32_t total_entries = 0;
1221 int32_t chunk2entry;
1222 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1226 if (f->track[track] == NULL) {
1230 total_entries = f->track[track]->stsc_entry_count;
1237 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1238 *chunk = chunk2 - chunk1;
1239 range_samples = *chunk * chunk1samples;
1241 if (sample < total + range_samples)
1244 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1247 if (chunk2entry < total_entries) {
1249 total += range_samples;
1251 } while (chunk2entry < total_entries);
1254 *chunk = (sample - total) / chunk1samples + chunk1;
1258 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1263 static int32_t chunk_to_offset(const struct mp4 *f, int32_t track,
1266 const struct mp4_track *p_track = f->track[track];
1268 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1269 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1271 } else if (p_track->stco_entry_count) {
1272 return p_track->stco_chunk_offset[chunk - 1];
1280 static int32_t sample_range_size(const struct mp4 *f, int32_t track,
1281 int32_t chunk_sample, int32_t sample)
1284 const struct mp4_track *p_track = f->track[track];
1286 if (p_track->stsz_sample_size) {
1287 return (sample - chunk_sample) * p_track->stsz_sample_size;
1289 if (sample >= p_track->stsz_sample_count)
1292 for (i = chunk_sample, total = 0; i < sample; i++) {
1293 total += p_track->stsz_table[i];
1300 static int32_t sample_to_offset(const struct mp4 *f, int32_t track,
1303 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1305 chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1307 chunk_offset1 = chunk_to_offset(f, track, chunk);
1308 chunk_offset2 = chunk_offset1 + sample_range_size(f,
1309 track, chunk_sample, sample);
1310 return chunk_offset2;
1314 * Return the number of milliseconds of the given track.
1316 * \param f As returned by \ref mp4_open_read(), must not be NULL.
1317 * \param track Between zero and the value returned by \ref mp4_total_tracks().
1319 * The function returns zero if the audio file is of zero length or contains a
1320 * corrupt track header.
1322 uint64_t mp4_get_duration(const struct mp4 *f, int32_t track)
1324 const struct mp4_track *t = f->track[track];
1326 if (t->timeScale == 0)
1328 return t->duration * 1000 / t->timeScale;
1332 * Check whether the given track number corresponds to an audio track.
1334 * \param f See \ref mp4_get_duration().
1335 * \param track See \ref mp4_get_duration().
1337 * Besides audio tracks, an mp4 file may contain video and system tracks. For
1338 * those the function returns false.
1340 bool mp4_is_audio_track(const struct mp4 *f, int32_t track)
1342 return f->track[track]->type == TRACK_AUDIO;
1345 void mp4_set_sample_position(struct mp4 *f, int32_t track, int32_t sample)
1347 int32_t offset = sample_to_offset(f, track, sample);
1348 set_position(f, offset);
1351 int32_t mp4_get_sample_size(const struct mp4 *f, int track, int sample)
1353 const struct mp4_track *t = f->track[track];
1355 if (t->stsz_sample_size != 0)
1356 return t->stsz_sample_size;
1357 return t->stsz_table[sample];
1360 uint32_t mp4_get_sample_rate(const struct mp4 *f, int32_t track)
1362 return f->track[track]->sampleRate;
1365 uint32_t mp4_get_channel_count(const struct mp4 *f, int32_t track)
1367 return f->track[track]->channelCount;
1370 int32_t mp4_num_samples(const struct mp4 *f, int32_t track)
1375 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1376 total += f->track[track]->stts_sample_count[i];
1381 struct mp4 *mp4_open_meta(struct mp4_callback *f)
1383 struct mp4 *ff = para_calloc(sizeof(struct mp4));
1397 int32_t mp4_meta_get_num_items(const struct mp4 *f)
1399 return f->tags.count;
1402 int32_t mp4_meta_get_by_index(const struct mp4 *f, uint32_t index,
1403 char **item, char **value)
1405 if (index >= f->tags.count) {
1410 *item = para_strdup(f->tags.tags[index].item);
1411 *value = para_strdup(f->tags.tags[index].value);
1416 static uint32_t find_atom(struct mp4 *f, uint64_t base, uint32_t size,
1419 uint32_t remaining = size;
1420 uint64_t atom_offset = base;
1425 set_position(f, atom_offset);
1429 atom_size = read_int32(f);
1430 if (atom_size > remaining || atom_size < 8)
1432 read_data(f, atom_name, 4);
1434 if (!memcmp(atom_name, name, 4)) {
1435 set_position(f, atom_offset);
1439 remaining -= atom_size;
1440 atom_offset += atom_size;
1445 static uint32_t find_atom_v2(struct mp4 *f, uint64_t base, uint32_t size,
1446 const char *name, uint32_t extraheaders, const char *name_inside)
1448 uint64_t first_base = (uint64_t) (-1);
1449 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1451 uint64_t mybase = get_position(f);
1452 uint32_t mysize = read_int32(f);
1454 if (first_base == (uint64_t) (-1))
1455 first_base = mybase;
1457 if (mysize < 8 + extraheaders)
1460 if (find_atom (f, mybase + (8 + extraheaders),
1461 mysize - (8 + extraheaders), name_inside)) {
1462 set_position(f, mybase);
1466 if (size <= mysize) {
1473 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1475 set_position(f, first_base);
1488 static struct membuffer *membuffer_create(void)
1490 const unsigned initial_size = 256;
1492 struct membuffer *buf = para_malloc(sizeof(*buf));
1493 buf->data = para_malloc(initial_size);
1495 buf->allocated = initial_size;
1496 buf->error = buf->data == 0 ? 1 : 0;
1501 static unsigned membuffer_write(struct membuffer *buf, const void *ptr, unsigned bytes)
1503 unsigned dest_size = buf->written + bytes;
1507 if (dest_size > buf->allocated) {
1509 buf->allocated <<= 1;
1510 } while (dest_size > buf->allocated);
1511 buf->data = para_realloc(buf->data, buf->allocated);
1515 memcpy((char *) buf->data + buf->written, ptr, bytes);
1516 buf->written += bytes;
1520 static unsigned membuffer_write_atom_name(struct membuffer *buf, const char *data)
1522 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1525 static unsigned membuffer_write_int16(struct membuffer *buf, uint16_t data)
1529 write_u16_be(temp, data);
1530 return membuffer_write(buf, temp, 2);
1533 static unsigned membuffer_write_int32(struct membuffer *buf, uint32_t data)
1536 write_u32_be(temp, data);
1537 return membuffer_write(buf, temp, 4);
1540 static void membuffer_write_track_tag(struct membuffer *buf, const char *name,
1541 uint32_t index, uint32_t total)
1543 membuffer_write_int32(buf,
1544 8 /*atom header */ + 8 /*data atom header */ +
1545 8 /*flags + reserved */ + 8 /*actual data */ );
1546 membuffer_write_atom_name(buf, name);
1547 membuffer_write_int32(buf,
1548 8 /*data atom header */ +
1549 8 /*flags + reserved */ + 8 /*actual data */ );
1550 membuffer_write_atom_name(buf, "data");
1551 membuffer_write_int32(buf, 0); //flags
1552 membuffer_write_int32(buf, 0); //reserved
1553 membuffer_write_int16(buf, 0);
1554 membuffer_write_int16(buf, (uint16_t) index); //track number
1555 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1556 membuffer_write_int16(buf, 0);
1559 static void membuffer_write_int16_tag(struct membuffer *buf, const char *name,
1562 membuffer_write_int32(buf,
1563 8 /*atom header */ + 8 /*data atom header */ +
1564 8 /*flags + reserved */ + 2 /*actual data */ );
1565 membuffer_write_atom_name(buf, name);
1566 membuffer_write_int32(buf,
1567 8 /*data atom header */ +
1568 8 /*flags + reserved */ + 2 /*actual data */ );
1569 membuffer_write_atom_name(buf, "data");
1570 membuffer_write_int32(buf, 0); //flags
1571 membuffer_write_int32(buf, 0); //reserved
1572 membuffer_write_int16(buf, value); //value
1575 static uint32_t myatoi(const char *param)
1577 return param ? atoi(param) : 0;
1580 static uint32_t meta_genre_to_index(const char *genrestr)
1583 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1584 if (!strcasecmp(genrestr, ID3v1GenreList[n]))
1590 struct stdmeta_entry {
1595 struct stdmeta_entry stdmetas[] = {
1596 {"\xA9" "nam", "title"},
1597 {"\xA9" "ART", "artist"},
1598 {"\xA9" "wrt", "writer"},
1599 {"\xA9" "alb", "album"},
1600 {"\xA9" "day", "date"},
1601 {"\xA9" "too", "tool"},
1602 {"\xA9" "cmt", "comment"},
1603 {"cpil", "compilation"},
1605 {"aART", "album_artist"},
1608 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1611 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1612 if (!strcasecmp(name, stdmetas[n].name))
1613 return stdmetas[n].atom;
1618 static void membuffer_write_std_tag(struct membuffer *buf, const char *name,
1623 /* special check for compilation flag */
1624 if (strcmp(name, "cpil") == 0) {
1628 membuffer_write_int32(buf,
1629 8 /*atom header */ + 8 /*data atom header */ +
1630 8 /*flags + reserved */ + strlen(value));
1631 membuffer_write_atom_name(buf, name);
1632 membuffer_write_int32(buf,
1633 8 /*data atom header */ +
1634 8 /*flags + reserved */ + strlen(value));
1635 membuffer_write_atom_name(buf, "data");
1636 membuffer_write_int32(buf, flags); //flags
1637 membuffer_write_int32(buf, 0); //reserved
1638 membuffer_write(buf, value, strlen(value));
1641 static void membuffer_write_custom_tag(struct membuffer *buf, const char *name,
1644 membuffer_write_int32(buf,
1645 8 /*atom header */ +
1646 0x1C /*weirdo itunes atom */ +
1647 12 /*name atom header */ + strlen(name) +
1648 16 /*data atom header + flags */ + strlen(value));
1649 membuffer_write_atom_name(buf, "----");
1650 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1651 membuffer_write_atom_name(buf, "mean");
1652 membuffer_write_int32(buf, 0);
1653 membuffer_write(buf, "com.apple.iTunes", 16);
1654 membuffer_write_int32(buf, 12 + strlen(name));
1655 membuffer_write_atom_name(buf, "name");
1656 membuffer_write_int32(buf, 0);
1657 membuffer_write(buf, name, strlen(name));
1658 membuffer_write_int32(buf,
1659 8 /*data atom header */ +
1660 8 /*flags + reserved */ + strlen(value));
1661 membuffer_write_atom_name(buf, "data");
1662 membuffer_write_int32(buf, 1); //flags
1663 membuffer_write_int32(buf, 0); //reserved
1664 membuffer_write(buf, value, strlen(value));
1667 static unsigned membuffer_error(const struct membuffer *buf)
1672 static void membuffer_free(struct membuffer *buf)
1678 static unsigned membuffer_get_size(const struct membuffer *buf)
1680 return buf->written;
1683 static void *membuffer_detach(struct membuffer *buf)
1689 ret = para_realloc(buf->data, buf->written);
1695 static uint32_t create_ilst(const struct mp4_metadata *data, void **out_buffer,
1696 uint32_t * out_size)
1698 struct membuffer *buf = membuffer_create();
1700 char *mask = para_calloc(data->count);
1701 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1702 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1703 const char *genre_ptr = 0, *tempo_ptr = 0;
1705 for (metaptr = 0; metaptr < data->count; metaptr++) {
1706 struct mp4_tag *tag = &data->tags[metaptr];
1707 if (!strcasecmp(tag->item, "tracknumber")
1708 || !strcasecmp(tag->item, "track")) {
1709 if (tracknumber_ptr == 0)
1710 tracknumber_ptr = tag->value;
1712 } else if (!strcasecmp(tag->item, "totaltracks")) {
1713 if (totaltracks_ptr == 0)
1714 totaltracks_ptr = tag->value;
1716 } else if (!strcasecmp(tag->item, "discnumber")
1717 || !strcasecmp(tag->item, "disc")) {
1718 if (discnumber_ptr == 0)
1719 discnumber_ptr = tag->value;
1721 } else if (!strcasecmp(tag->item, "totaldiscs")) {
1722 if (totaldiscs_ptr == 0)
1723 totaldiscs_ptr = tag->value;
1725 } else if (!strcasecmp(tag->item, "genre")) {
1727 genre_ptr = tag->value;
1729 } else if (!strcasecmp(tag->item, "tempo")) {
1731 tempo_ptr = tag->value;
1736 if (tracknumber_ptr)
1737 membuffer_write_track_tag(buf, "trkn", myatoi(tracknumber_ptr),
1738 myatoi(totaltracks_ptr));
1740 membuffer_write_track_tag(buf, "disk", myatoi(discnumber_ptr),
1741 myatoi(totaldiscs_ptr));
1743 membuffer_write_int16_tag(buf, "tmpo", myatoi(tempo_ptr));
1746 uint32_t index = meta_genre_to_index(genre_ptr);
1748 membuffer_write_std_tag(buf, "©gen", genre_ptr);
1750 membuffer_write_int16_tag(buf, "gnre", index);
1752 for (metaptr = 0; metaptr < data->count; metaptr++) {
1753 struct mp4_tag *tag;
1754 const char *std_meta_atom;
1758 tag = &data->tags[metaptr];
1759 std_meta_atom = find_standard_meta(tag->item);
1761 membuffer_write_std_tag(buf, std_meta_atom, tag->value);
1763 membuffer_write_custom_tag(buf, tag->item, tag->value);
1767 if (membuffer_error(buf)) {
1768 membuffer_free(buf);
1772 *out_size = membuffer_get_size(buf);
1773 *out_buffer = membuffer_detach(buf);
1774 membuffer_free(buf);
1779 static void membuffer_write_atom(struct membuffer *buf, const char *name, unsigned size,
1782 membuffer_write_int32(buf, size + 8);
1783 membuffer_write_atom_name(buf, name);
1784 membuffer_write(buf, data, size);
1787 static void *membuffer_get_ptr(const struct membuffer *buf)
1792 static void membuffer_set_error(struct membuffer *buf)
1797 static unsigned membuffer_transfer_from_file(struct membuffer *buf, struct mp4 *src,
1803 oldsize = membuffer_get_size(buf);
1804 if (membuffer_write(buf, 0, bytes) != bytes)
1807 bufptr = membuffer_get_ptr(buf);
1811 if ((unsigned)read_data(src, (char *) bufptr + oldsize, bytes) !=
1813 membuffer_set_error(buf);
1820 static uint32_t create_meta(const struct mp4_metadata *data, void **out_buffer,
1821 uint32_t * out_size)
1823 struct membuffer *buf;
1827 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1830 buf = membuffer_create();
1832 membuffer_write_int32(buf, 0);
1833 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1836 *out_size = membuffer_get_size(buf);
1837 *out_buffer = membuffer_detach(buf);
1838 membuffer_free(buf);
1842 static uint32_t create_udta(const struct mp4_metadata *data, void **out_buffer,
1843 uint32_t * out_size)
1845 struct membuffer *buf;
1849 if (!create_meta(data, &meta_buffer, &meta_size))
1852 buf = membuffer_create();
1854 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1858 *out_size = membuffer_get_size(buf);
1859 *out_buffer = membuffer_detach(buf);
1860 membuffer_free(buf);
1864 static uint32_t fix_byte_order_32(uint32_t src)
1866 return read_u32_be(&src);
1869 static uint32_t modify_moov(struct mp4 *f, const struct mp4_metadata *data,
1870 void **out_buffer, uint32_t * out_size)
1872 uint64_t total_base = f->moov_offset + 8;
1873 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1875 uint64_t udta_offset, meta_offset, ilst_offset;
1876 uint32_t udta_size, meta_size, ilst_size;
1878 uint32_t new_ilst_size;
1879 void *new_ilst_buffer;
1884 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1885 struct membuffer *buf;
1886 void *new_udta_buffer;
1887 uint32_t new_udta_size;
1888 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1891 buf = membuffer_create();
1892 set_position(f, total_base);
1893 membuffer_transfer_from_file(buf, f, total_size);
1895 membuffer_write_atom(buf, "udta", new_udta_size,
1898 free(new_udta_buffer);
1900 *out_size = membuffer_get_size(buf);
1901 *out_buffer = membuffer_detach(buf);
1902 membuffer_free(buf);
1905 udta_offset = get_position(f);
1906 udta_size = read_int32(f);
1907 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
1908 struct membuffer *buf;
1909 void *new_meta_buffer;
1910 uint32_t new_meta_size;
1911 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
1914 buf = membuffer_create();
1915 set_position(f, total_base);
1916 membuffer_transfer_from_file(buf, f,
1917 (uint32_t)(udta_offset - total_base));
1919 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
1920 membuffer_write_atom_name(buf, "udta");
1921 membuffer_transfer_from_file(buf, f, udta_size);
1923 membuffer_write_atom(buf, "meta", new_meta_size,
1925 free(new_meta_buffer);
1927 *out_size = membuffer_get_size(buf);
1928 *out_buffer = membuffer_detach(buf);
1929 membuffer_free(buf);
1932 meta_offset = get_position(f);
1933 meta_size = read_int32(f);
1934 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
1935 return 0; //shouldn't happen, find_atom_v2 above takes care of it
1936 ilst_offset = get_position(f);
1937 ilst_size = read_int32(f);
1939 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
1942 size_delta = new_ilst_size - (ilst_size - 8);
1944 *out_size = total_size + size_delta;
1945 *out_buffer = para_malloc(*out_size);
1946 p_out = (uint8_t *) * out_buffer;
1948 set_position(f, total_base);
1950 (uint32_t) (udta_offset - total_base));
1951 p_out += (uint32_t) (udta_offset - total_base);
1952 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1954 read_data(f, p_out, 4);
1957 (uint32_t) (meta_offset - udta_offset - 8));
1958 p_out += (uint32_t) (meta_offset - udta_offset - 8);
1959 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1961 read_data(f, p_out, 4);
1964 (uint32_t) (ilst_offset - meta_offset - 8));
1965 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
1966 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1968 read_data(f, p_out, 4);
1971 memcpy(p_out, new_ilst_buffer, new_ilst_size);
1972 p_out += new_ilst_size;
1974 set_position(f, ilst_offset + ilst_size);
1975 read_data(f, p_out, (uint32_t) (total_size
1976 - (ilst_offset - total_base) - ilst_size));
1978 free(new_ilst_buffer);
1983 static int32_t write_data(struct mp4 *f, void *data, uint32_t size)
1987 result = f->stream->write(f->stream->user_data, data, size);
1989 f->current_position += size;
1994 static int32_t write_int32(struct mp4 *f, uint32_t data)
1997 write_u32_be(temp, data);
1998 return write_data(f, temp, sizeof(temp));
2001 static int32_t truncate_stream(struct mp4 *f)
2003 return f->stream->truncate(f->stream->user_data);
2006 int32_t mp4_meta_update(struct mp4_callback *f, const struct mp4_metadata *data)
2008 void *new_moov_data;
2009 uint32_t new_moov_size;
2011 struct mp4 *ff = para_calloc(sizeof(struct mp4));
2013 set_position(ff, 0);
2017 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2022 /* copy moov atom to end of the file */
2023 if (ff->last_atom != ATOM_MOOV) {
2024 char *free_data = "free";
2026 /* rename old moov to free */
2027 set_position(ff, ff->moov_offset + 4);
2028 write_data(ff, free_data, 4);
2030 set_position(ff, ff->file_size);
2031 write_int32(ff, new_moov_size + 8);
2032 write_data(ff, "moov", 4);
2033 write_data(ff, new_moov_data, new_moov_size);
2035 set_position(ff, ff->moov_offset);
2036 write_int32(ff, new_moov_size + 8);
2037 write_data(ff, "moov", 4);
2038 write_data(ff, new_moov_data, new_moov_size);
2041 truncate_stream(ff);
2047 /* find a metadata item by name */
2048 /* returns 0 if item found, 1 if no such item */
2049 static int32_t meta_find_by_name(const struct mp4 *f, const char *item,
2054 for (i = 0; i < f->tags.count; i++) {
2055 if (!strcasecmp(f->tags.tags[i].item, item)) {
2056 *value = para_strdup(f->tags.tags[i].value);
2067 int32_t mp4_meta_get_artist(const struct mp4 *f, char **value)
2069 return meta_find_by_name(f, "artist", value);
2072 int32_t mp4_meta_get_title(const struct mp4 *f, char **value)
2074 return meta_find_by_name(f, "title", value);
2077 int32_t mp4_meta_get_date(const struct mp4 *f, char **value)
2079 return meta_find_by_name(f, "date", value);
2082 int32_t mp4_meta_get_album(const struct mp4 *f, char **value)
2084 return meta_find_by_name(f, "album", value);
2087 int32_t mp4_meta_get_comment(const struct mp4 *f, char **value)
2089 return meta_find_by_name(f, "comment", value);