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)
121 /* atoms with subatoms */
129 ATOM_ILST = 8, /* iTunes Metadata list */
140 ATOM_COMPILATION = 19,
150 /* atoms without subatoms */
170 ATOM_META = 148, /* iTunes Metadata box */
171 ATOM_NAME = 149, /* iTunes Metadata name box */
172 ATOM_DATA = 150, /* iTunes Metadata data box */
179 ATOM_ALBUM_ARTIST = 157,
180 ATOM_CONTENTGROUP = 158,
182 ATOM_DESCRIPTION = 160,
185 ATOM_EPISODENAME = 163,
186 ATOM_SORTTITLE = 164,
187 ATOM_SORTALBUM = 165,
188 ATOM_SORTARTIST = 166,
189 ATOM_SORTALBUMARTIST = 167,
190 ATOM_SORTWRITER = 168,
199 #define ATOM_FREE ATOM_UNKNOWN
200 #define ATOM_SKIP ATOM_UNKNOWN
202 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
204 static uint8_t atom_name_to_type(int8_t a, int8_t b, int8_t c, int8_t d)
207 if (atom_compare(a, b, c, d, 'm', 'o', 'o', 'v'))
209 else if (atom_compare(a, b, c, d, 'm', 'i', 'n', 'f'))
211 else if (atom_compare(a, b, c, d, 'm', 'd', 'i', 'a'))
213 else if (atom_compare(a, b, c, d, 'm', 'd', 'a', 't'))
215 else if (atom_compare(a, b, c, d, 'm', 'd', 'h', 'd'))
217 else if (atom_compare(a, b, c, d, 'm', 'v', 'h', 'd'))
219 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'a'))
221 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'v'))
223 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 's'))
225 else if (atom_compare(a, b, c, d, 'm', 'e', 't', 'a'))
227 } else if (a == 't') {
228 if (atom_compare(a, b, c, d, 't', 'r', 'a', 'k'))
230 else if (atom_compare(a, b, c, d, 't', 'k', 'h', 'd'))
232 else if (atom_compare(a, b, c, d, 't', 'r', 'e', 'f'))
234 else if (atom_compare(a, b, c, d, 't', 'r', 'k', 'n'))
236 else if (atom_compare(a, b, c, d, 't', 'm', 'p', 'o'))
238 else if (atom_compare(a, b, c, d, 't', 'v', 'n', 'n'))
240 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'h'))
242 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 'n'))
243 return ATOM_EPISODENAME;
244 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'n'))
246 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 's'))
248 } else if (a == 's') {
249 if (atom_compare(a, b, c, d, 's', 't', 'b', 'l'))
251 else if (atom_compare(a, b, c, d, 's', 'm', 'h', 'd'))
253 else if (atom_compare(a, b, c, d, 's', 't', 's', 'd'))
255 else if (atom_compare(a, b, c, d, 's', 't', 't', 's'))
257 else if (atom_compare(a, b, c, d, 's', 't', 'c', 'o'))
259 else if (atom_compare(a, b, c, d, 's', 't', 's', 'c'))
261 else if (atom_compare(a, b, c, d, 's', 't', 's', 'z'))
263 else if (atom_compare(a, b, c, d, 's', 't', 'z', '2'))
265 else if (atom_compare(a, b, c, d, 's', 'k', 'i', 'p'))
267 else if (atom_compare(a, b, c, d, 's', 'i', 'n', 'f'))
269 else if (atom_compare(a, b, c, d, 's', 'c', 'h', 'i'))
271 else if (atom_compare(a, b, c, d, 's', 'o', 'n', 'm'))
272 return ATOM_SORTTITLE;
273 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'l'))
274 return ATOM_SORTALBUM;
275 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'r'))
276 return ATOM_SORTARTIST;
277 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'a'))
278 return ATOM_SORTALBUMARTIST;
279 else if (atom_compare(a, b, c, d, 's', 'o', 'c', 'o'))
280 return ATOM_SORTWRITER;
281 else if (atom_compare(a, b, c, d, 's', 'o', 's', 'n'))
282 return ATOM_SORTSHOW;
283 } else if (a == COPYRIGHT_SYMBOL) {
284 if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'n', 'a', 'm'))
286 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'A', 'R', 'T'))
288 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'w', 'r', 't'))
290 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'a', 'l', 'b'))
292 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'd', 'a', 'y'))
294 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 't', 'o', 'o'))
296 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'c', 'm', 't'))
298 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'e', 'n'))
300 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'r', 'p'))
301 return ATOM_CONTENTGROUP;
302 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'l', 'y', 'r'))
306 if (atom_compare(a, b, c, d, 'e', 'd', 't', 's'))
308 else if (atom_compare(a, b, c, d, 'e', 's', 'd', 's'))
310 else if (atom_compare(a, b, c, d, 'f', 't', 'y', 'p'))
312 else if (atom_compare(a, b, c, d, 'f', 'r', 'e', 'e'))
314 else if (atom_compare(a, b, c, d, 'h', 'm', 'h', 'd'))
316 else if (atom_compare(a, b, c, d, 'v', 'm', 'h', 'd'))
318 else if (atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
320 else if (atom_compare(a, b, c, d, 'i', 'l', 's', 't'))
322 else if (atom_compare(a, b, c, d, 'n', 'a', 'm', 'e'))
324 else if (atom_compare(a, b, c, d, 'd', 'a', 't', 'a'))
326 else if (atom_compare(a, b, c, d, 'd', 'i', 's', 'k'))
328 else if (atom_compare(a, b, c, d, 'g', 'n', 'r', 'e'))
330 else if (atom_compare(a, b, c, d, 'c', 'o', 'v', 'r'))
332 else if (atom_compare(a, b, c, d, 'c', 'p', 'i', 'l'))
333 return ATOM_COMPILATION;
334 else if (atom_compare(a, b, c, d, 'c', 't', 't', 's'))
336 else if (atom_compare(a, b, c, d, 'd', 'r', 'm', 's'))
338 else if (atom_compare(a, b, c, d, 'f', 'r', 'm', 'a'))
340 else if (atom_compare(a, b, c, d, 'p', 'r', 'i', 'v'))
342 else if (atom_compare(a, b, c, d, 'i', 'v', 'i', 'v'))
344 else if (atom_compare(a, b, c, d, 'u', 's', 'e', 'r'))
346 else if (atom_compare(a, b, c, d, 'k', 'e', 'y', ' '))
348 else if (atom_compare(a, b, c, d, 'a', 'A', 'R', 'T'))
349 return ATOM_ALBUM_ARTIST;
350 else if (atom_compare(a, b, c, d, 'd', 'e', 's', 'c'))
351 return ATOM_DESCRIPTION;
352 else if (atom_compare(a, b, c, d, 'p', 'c', 's', 't'))
358 /* read atom header, return atom size, atom size is with header included */
359 static uint64_t atom_read_header(struct mp4 *f, uint8_t * atom_type,
360 uint8_t * header_size)
364 int8_t atom_header[8];
366 ret = read_data(f, atom_header, 8);
370 size = read_u32_be(atom_header);
373 /* check for 64 bit atom size */
376 size = read_int64(f);
378 *atom_type = atom_name_to_type(atom_header[4], atom_header[5],
379 atom_header[6], atom_header[7]);
383 static int64_t get_position(const struct mp4 *f)
385 return f->current_position;
388 static int need_parse_when_meta_only(uint8_t atom_type)
409 static int32_t set_position(struct mp4 *f, int64_t position)
411 f->stream->seek(f->stream->user_data, position);
412 f->current_position = position;
417 static void track_add(struct mp4 *f)
421 if (f->total_tracks > MAX_TRACKS) {
426 f->track[f->total_tracks - 1] = para_calloc(sizeof(struct mp4_track));
429 static uint8_t read_char(struct mp4 *f)
432 read_data(f, &output, 1);
436 static uint32_t read_int24(struct mp4 *f)
440 read_data(f, data, 3);
441 return read_u24_be(data);
444 static uint32_t read_int32(struct mp4 *f)
448 read_data(f, data, 4);
449 return read_u32_be(data);
452 static int32_t read_stsz(struct mp4 *f)
457 if (f->total_tracks == 0)
459 t = f->track[f->total_tracks - 1];
460 read_char(f); /* version */
461 read_int24(f); /* flags */
462 t->stsz_sample_size = read_int32(f);
463 t->stsz_sample_count = read_int32(f);
464 if (t->stsz_sample_size != 0)
466 t->stsz_table = para_malloc(t->stsz_sample_count * sizeof(int32_t));
467 for (i = 0; i < t->stsz_sample_count && !f->stream->read_error; i++)
468 t->stsz_table[i] = read_int32(f);
472 static int32_t read_stts(struct mp4 *f)
478 if (f->total_tracks == 0)
480 t = f->track[f->total_tracks - 1];
481 if (t->stts_entry_count)
483 read_char(f); /* version */
484 read_int24(f); /* flags */
485 t->stts_entry_count = read_int32(f);
487 t->stts_sample_count = para_malloc(t->stts_entry_count
489 t->stts_sample_delta = para_malloc(t->stts_entry_count
492 for (i = 0; i < t->stts_entry_count && !f->stream->read_error; i++) {
493 t->stts_sample_count[i] = read_int32(f);
494 t->stts_sample_delta[i] = read_int32(f);
499 static int32_t read_ctts(struct mp4 *f)
504 if (f->total_tracks == 0)
506 t = f->track[f->total_tracks - 1];
507 if (t->ctts_entry_count)
510 read_char(f); /* version */
511 read_int24(f); /* flags */
512 t->ctts_entry_count = read_int32(f);
514 t->ctts_sample_count = para_malloc(t->ctts_entry_count
516 t->ctts_sample_offset = para_malloc(t->ctts_entry_count
520 for (i = 0; i < t->ctts_entry_count && !f->stream->read_error; i++) {
521 t->ctts_sample_count[i] = read_int32(f);
522 t->ctts_sample_offset[i] = read_int32(f);
527 static int32_t read_stsc(struct mp4 *f)
532 if (f->total_tracks == 0)
534 t = f->track[f->total_tracks - 1];
536 read_char(f); /* version */
537 read_int24(f); /* flags */
538 t->stsc_entry_count = read_int32(f);
539 t->stsc_first_chunk = para_malloc(t->stsc_entry_count * sizeof(int32_t));
540 t->stsc_samples_per_chunk = para_malloc(t->stsc_entry_count
542 t->stsc_sample_desc_index = para_malloc(t->stsc_entry_count *
546 for (i = 0; i < t->stsc_entry_count && !f->stream->read_error; i++) {
547 t->stsc_first_chunk[i] = read_int32(f);
548 t->stsc_samples_per_chunk[i] = read_int32(f);
549 t->stsc_sample_desc_index[i] = read_int32(f);
554 static int32_t read_stco(struct mp4 *f)
559 if (f->total_tracks == 0)
561 t = f->track[f->total_tracks - 1];
563 read_char(f); /* version */
564 read_int24(f); /* flags */
565 t->stco_entry_count = read_int32(f);
566 t->stco_chunk_offset = para_malloc(t->stco_entry_count
569 for (i = 0; i < t->stco_entry_count && !f->stream->read_error; i++)
570 t->stco_chunk_offset[i] = read_int32(f);
574 static uint16_t read_int16(struct mp4 *f)
578 read_data(f, data, 2);
579 return read_u16_be(data);
582 static int32_t read_mp4a(struct mp4 *f)
585 uint8_t atom_type = 0;
586 uint8_t header_size = 0;
589 if (f->total_tracks == 0)
591 t = f->track[f->total_tracks - 1];
593 for (i = 0; i < 6; i++) {
594 read_char(f); /* reserved */
596 /* data_reference_index */ read_int16(f);
598 read_int32(f); /* reserved */
599 read_int32(f); /* reserved */
601 t->channelCount = read_int16(f);
602 t->sampleSize = read_int16(f);
607 t->sampleRate = read_int16(f);
611 atom_read_header(f, &atom_type, &header_size);
615 static int32_t read_stsd(struct mp4 *f)
618 uint8_t header_size = 0;
622 if (f->total_tracks == 0)
624 t = f->track[f->total_tracks - 1];
626 read_char(f); /* version */
627 read_int24(f); /* flags */
629 t->stsd_entry_count = read_int32(f);
632 for (i = 0; i < t->stsd_entry_count && !f->stream->read_error; i++) {
633 uint64_t skip = get_position(f);
635 uint8_t atom_type = 0;
636 size = atom_read_header(f, &atom_type, &header_size);
638 t->is_audio = atom_type == ATOM_MP4A;
641 set_position(f, skip);
647 static int32_t read_mvhd(struct mp4 *f)
651 read_char(f); /* version */
652 read_int24(f); /* flags */
653 read_int32(f); /* creation_time */
654 read_int32(f); /* modification_time */
655 f->time_scale = read_int32(f);
656 f->duration = read_int32(f);
657 read_int32(f); /* preferred_rate */
658 read_int16(f); /* preferred_volume */
659 for (i = 0; i < 10; i++)
660 read_char(f); /* reserved */
661 for (i = 0; i < 9; i++)
662 read_int32(f); /* matrix */
663 read_int32(f); /* preview_time */
664 read_int32(f); /* preview_duration */
665 read_int32(f); /* poster_time */
666 read_int32(f); /* selection_time */
667 read_int32(f); /* selection_duration */
668 read_int32(f); /* current_time */
669 read_int32(f); /* next_track_id */
673 static int32_t tag_add_field(struct mp4_metadata *tags, const char *item,
674 const char *value, int32_t len)
676 if (!item || (item && !*item) || !value)
678 tags->tags = para_realloc(tags->tags,
679 (tags->count + 1) * sizeof(struct mp4_tag));
680 tags->tags[tags->count].item = para_strdup(item);
681 tags->tags[tags->count].len = len;
683 tags->tags[tags->count].value = para_malloc(len + 1);
684 memcpy(tags->tags[tags->count].value, value, len);
685 tags->tags[tags->count].value[len] = 0;
687 tags->tags[tags->count].value = para_strdup(value);
693 static const char *ID3v1GenreList[] = {
694 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
695 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
696 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
697 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
698 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
699 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
700 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
701 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
702 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
703 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
704 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
705 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
706 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
707 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
708 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
709 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
710 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
711 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
712 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
713 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
714 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
715 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
716 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
717 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
718 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
719 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
720 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
721 "Anime", "JPop", "SynthPop",
724 static const char *meta_index_to_genre(uint32_t idx)
726 if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
727 return ID3v1GenreList[idx - 1];
733 static char *read_string(struct mp4 *f, uint32_t length)
735 char *str = para_malloc(length + 1);
736 if ((uint32_t)read_data(f, str, length) != length) {
744 static int32_t set_metadata_name(uint8_t atom_type, char **name)
746 static char *tag_names[] = {
747 "unknown", "title", "artist", "writer", "album",
748 "date", "tool", "comment", "genre", "track",
749 "disc", "compilation", "genre", "tempo", "cover",
750 "album_artist", "contentgroup", "lyrics", "description",
751 "network", "show", "episodename",
752 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
753 "sortwriter", "sortshow",
754 "season", "episode", "podcast"
789 case ATOM_COMPILATION:
801 case ATOM_ALBUM_ARTIST:
804 case ATOM_CONTENTGROUP:
810 case ATOM_DESCRIPTION:
819 case ATOM_EPISODENAME:
828 case ATOM_SORTARTIST:
831 case ATOM_SORTALBUMARTIST:
834 case ATOM_SORTWRITER:
854 *name = para_strdup(tag_names[tag_idx]);
858 static uint32_t min_body_size(uint8_t atom_type)
865 return sizeof (char) /* version */
866 + sizeof(uint8_t) * 3 /* flags */
867 + sizeof(uint32_t) /* reserved */
868 + sizeof(uint16_t) /* leading uint16_t */
869 + sizeof(uint16_t) /* track */
870 + sizeof(uint16_t); /* totaltracks */
872 return sizeof (char) /* version */
873 + sizeof(uint8_t) * 3 /* flags */
874 + sizeof(uint32_t) /* reserved */
875 + sizeof(uint16_t) /* disc */
876 + sizeof(uint16_t); /* totaldiscs */
877 default: assert(false);
881 static int32_t parse_tag(struct mp4 *f, uint8_t parent, int32_t size)
884 uint8_t header_size = 0;
885 uint64_t subsize, sumsize;
894 sumsize < size && !f->stream->read_error; /* CVE-2017-9222 */
895 set_position(f, destpos), sumsize += subsize
897 subsize = atom_read_header(f, &atom_type, &header_size);
898 destpos = get_position(f) + subsize - header_size;
901 if (atom_type == ATOM_NAME) {
902 read_char(f); /* version */
903 read_int24(f); /* flags */
905 name = read_string(f, subsize - (header_size + 4));
908 if (atom_type != ATOM_DATA)
910 read_char(f); /* version */
911 read_int24(f); /* flags */
912 read_int32(f); /* reserved */
914 /* some need special attention */
915 if (parent == ATOM_GENRE2 || parent == ATOM_TEMPO) {
917 if (subsize - header_size < min_body_size(parent))
920 if (parent == ATOM_TEMPO) {
922 sprintf(temp, "%.5u BPM", val);
923 tag_add_field(&(f-> tags), "tempo",
926 const char *tmp = meta_index_to_genre(val);
928 tag_add_field (&(f->tags),
932 } else if (parent == ATOM_TRACK || parent == ATOM_DISC) {
933 uint16_t index, total;
935 if (subsize - header_size < min_body_size(parent))
938 index = read_int16(f);
939 total = read_int16(f);
940 if (parent == ATOM_TRACK)
942 sprintf(temp, "%d", index);
943 tag_add_field(&(f->tags), parent == ATOM_TRACK?
944 "track" : "disc", temp, -1);
946 sprintf(temp, "%d", total);
947 tag_add_field(& (f-> tags),
948 parent == ATOM_TRACK?
949 "totaltracks" : "totaldiscs", temp, -1);
954 data = read_string(f, subsize - (header_size + 8));
955 len = subsize - (header_size + 8);
961 set_metadata_name(parent , &name);
963 tag_add_field(&(f->tags), name, data, len);
972 static int32_t read_mdhd(struct mp4 *f)
978 if (f->total_tracks == 0)
980 t = f->track[f->total_tracks - 1];
982 version = read_int32(f);
984 read_int64(f); //creation-time
985 read_int64(f); //modification-time
986 t->timeScale = read_int32(f); //timescale
987 t->duration = read_int64(f); //duration
988 } else { //version == 0
991 read_int32(f); //creation-time
992 read_int32(f); //modification-time
993 t->timeScale = read_int32(f); //timescale
994 temp = read_int32(f);
995 t->duration = (temp == (uint32_t) (-1))?
996 (uint64_t) (-1) : (uint64_t) (temp);
1003 static int32_t parse_metadata(struct mp4 *f, int32_t size)
1005 uint64_t subsize, sumsize = 0;
1007 uint8_t header_size = 0;
1009 while (sumsize < size) {
1010 subsize = atom_read_header(f, &atom_type, &header_size);
1013 parse_tag(f, atom_type, (uint32_t)(subsize - header_size));
1020 static int32_t read_meta(struct mp4 *f, uint64_t size)
1022 uint64_t subsize, sumsize = 0;
1024 uint8_t header_size = 0;
1026 read_char(f); /* version */
1027 read_int24(f); /* flags */
1029 while (sumsize < (size - (header_size + 4))) {
1030 subsize = atom_read_header(f, &atom_type, &header_size);
1031 if (subsize <= header_size + 4)
1033 if (atom_type == ATOM_ILST) {
1034 parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1036 set_position(f, get_position(f) + subsize - header_size);
1044 static int32_t atom_read(struct mp4 *f, int32_t size, uint8_t atom_type)
1046 uint64_t dest_position = get_position(f) + size - 8;
1047 if (atom_type == ATOM_STSZ) {
1048 /* sample size box */
1050 } else if (atom_type == ATOM_STTS) {
1051 /* time to sample box */
1053 } else if (atom_type == ATOM_CTTS) {
1054 /* composition offset box */
1056 } else if (atom_type == ATOM_STSC) {
1057 /* sample to chunk box */
1059 } else if (atom_type == ATOM_STCO) {
1060 /* chunk offset box */
1062 } else if (atom_type == ATOM_STSD) {
1063 /* sample description box */
1065 } else if (atom_type == ATOM_MVHD) {
1066 /* movie header box */
1068 } else if (atom_type == ATOM_MDHD) {
1071 } else if (atom_type == ATOM_META) {
1072 /* iTunes Metadata box */
1076 set_position(f, dest_position);
1080 /* parse atoms that are sub atoms of other atoms */
1081 static int32_t parse_sub_atoms(struct mp4 *f, uint64_t total_size, int meta_only)
1084 uint8_t atom_type = 0;
1085 uint64_t counted_size = 0;
1086 uint8_t header_size = 0;
1088 while (counted_size < total_size) {
1089 size = atom_read_header(f, &atom_type, &header_size);
1090 counted_size += size;
1092 /* check for end of file */
1096 /* we're starting to read a new track, update index,
1097 * so that all data and tables get written in the right place
1099 if (atom_type == ATOM_TRAK)
1101 /* parse subatoms */
1102 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1103 set_position(f, get_position(f) + size - header_size);
1104 } else if (atom_type < SUBATOMIC) {
1105 parse_sub_atoms(f, size - header_size, meta_only);
1107 atom_read(f, (uint32_t) size, atom_type);
1114 /* parse root atoms */
1115 static int32_t parse_atoms(struct mp4 *f, int meta_only)
1118 uint8_t atom_type = 0;
1119 uint8_t header_size = 0;
1122 f->stream->read_error = 0;
1125 atom_read_header(f, &atom_type, &header_size)) != 0) {
1126 f->file_size += size;
1127 f->last_atom = atom_type;
1129 if (atom_type == ATOM_MOOV && size > header_size) {
1130 f->moov_offset = get_position(f) - header_size;
1131 f->moov_size = size;
1134 /* parse subatoms */
1135 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1136 set_position(f, get_position(f) + size - header_size);
1137 } else if (atom_type < SUBATOMIC) {
1138 parse_sub_atoms(f, size - header_size, meta_only);
1140 /* skip this atom */
1141 set_position(f, get_position(f) + size - header_size);
1148 struct mp4 *mp4_open_read(struct mp4_callback *f)
1150 struct mp4 *ff = para_calloc(sizeof(struct mp4));
1164 static int32_t tag_delete(struct mp4_metadata *tags)
1168 for (i = 0; i < tags->count; i++) {
1169 free(tags->tags[i].item);
1170 free(tags->tags[i].value);
1179 void mp4_close(struct mp4 *ff)
1183 for (i = 0; i < ff->total_tracks; i++) {
1185 free(ff->track[i]->stsz_table);
1186 free(ff->track[i]->stts_sample_count);
1187 free(ff->track[i]->stts_sample_delta);
1188 free(ff->track[i]->stsc_first_chunk);
1189 free(ff->track[i]->stsc_samples_per_chunk);
1190 free(ff->track[i]->stsc_sample_desc_index);
1191 free(ff->track[i]->stco_chunk_offset);
1192 free(ff->track[i]->ctts_sample_count);
1193 free(ff->track[i]->ctts_sample_offset);
1198 tag_delete(&(ff->tags));
1202 static int32_t chunk_of_sample(const struct mp4 *f, int32_t track,
1203 int32_t sample, int32_t *chunk_sample, int32_t *chunk)
1205 int32_t total_entries = 0;
1206 int32_t chunk2entry;
1207 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1211 if (f->track[track] == NULL) {
1215 total_entries = f->track[track]->stsc_entry_count;
1222 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1223 *chunk = chunk2 - chunk1;
1224 range_samples = *chunk * chunk1samples;
1226 if (sample < total + range_samples)
1229 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1232 if (chunk2entry < total_entries) {
1234 total += range_samples;
1236 } while (chunk2entry < total_entries);
1239 *chunk = (sample - total) / chunk1samples + chunk1;
1243 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1248 static int32_t chunk_to_offset(const struct mp4 *f, int32_t track,
1251 const struct mp4_track *p_track = f->track[track];
1253 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1254 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1256 } else if (p_track->stco_entry_count) {
1257 return p_track->stco_chunk_offset[chunk - 1];
1265 static int32_t sample_range_size(const struct mp4 *f, int32_t track,
1266 int32_t chunk_sample, int32_t sample)
1269 const struct mp4_track *p_track = f->track[track];
1271 if (p_track->stsz_sample_size) {
1272 return (sample - chunk_sample) * p_track->stsz_sample_size;
1274 if (sample >= p_track->stsz_sample_count)
1277 for (i = chunk_sample, total = 0; i < sample; i++) {
1278 total += p_track->stsz_table[i];
1285 static int32_t sample_to_offset(const struct mp4 *f, int32_t track,
1288 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1290 chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1292 chunk_offset1 = chunk_to_offset(f, track, chunk);
1293 chunk_offset2 = chunk_offset1 + sample_range_size(f,
1294 track, chunk_sample, sample);
1295 return chunk_offset2;
1299 * Return the number of milliseconds of the given track.
1301 * \param f As returned by \ref mp4_open_read(), must not be NULL.
1302 * \param track Between zero and the value returned by \ref mp4_total_tracks().
1304 * The function returns zero if the audio file is of zero length or contains a
1305 * corrupt track header.
1307 uint64_t mp4_get_duration(const struct mp4 *f, int32_t track)
1309 const struct mp4_track *t = f->track[track];
1311 if (t->timeScale == 0)
1313 return t->duration * 1000 / t->timeScale;
1317 * Check whether the given track number corresponds to an audio track.
1319 * \param f See \ref mp4_get_duration().
1320 * \param track See \ref mp4_get_duration().
1322 * Besides audio tracks, an mp4 file may contain video and system tracks. For
1323 * those the function returns false.
1325 bool mp4_is_audio_track(const struct mp4 *f, int32_t track)
1327 return f->track[track]->is_audio;
1330 void mp4_set_sample_position(struct mp4 *f, int32_t track, int32_t sample)
1332 int32_t offset = sample_to_offset(f, track, sample);
1333 set_position(f, offset);
1336 int32_t mp4_get_sample_size(const struct mp4 *f, int track, int sample)
1338 const struct mp4_track *t = f->track[track];
1340 if (t->stsz_sample_size != 0)
1341 return t->stsz_sample_size;
1342 return t->stsz_table[sample];
1345 uint32_t mp4_get_sample_rate(const struct mp4 *f, int32_t track)
1347 return f->track[track]->sampleRate;
1350 uint32_t mp4_get_channel_count(const struct mp4 *f, int32_t track)
1352 return f->track[track]->channelCount;
1355 int32_t mp4_num_samples(const struct mp4 *f, int32_t track)
1360 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1361 total += f->track[track]->stts_sample_count[i];
1366 struct mp4 *mp4_open_meta(struct mp4_callback *f)
1368 struct mp4 *ff = para_calloc(sizeof(struct mp4));
1382 int32_t mp4_meta_get_num_items(const struct mp4 *f)
1384 return f->tags.count;
1387 int32_t mp4_meta_get_by_index(const struct mp4 *f, uint32_t index,
1388 char **item, char **value)
1390 if (index >= f->tags.count) {
1395 *item = para_strdup(f->tags.tags[index].item);
1396 *value = para_strdup(f->tags.tags[index].value);
1401 static uint32_t find_atom(struct mp4 *f, uint64_t base, uint32_t size,
1404 uint32_t remaining = size;
1405 uint64_t atom_offset = base;
1410 set_position(f, atom_offset);
1414 atom_size = read_int32(f);
1415 if (atom_size > remaining || atom_size < 8)
1417 read_data(f, atom_name, 4);
1419 if (!memcmp(atom_name, name, 4)) {
1420 set_position(f, atom_offset);
1424 remaining -= atom_size;
1425 atom_offset += atom_size;
1430 static uint32_t find_atom_v2(struct mp4 *f, uint64_t base, uint32_t size,
1431 const char *name, uint32_t extraheaders, const char *name_inside)
1433 uint64_t first_base = (uint64_t) (-1);
1434 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1436 uint64_t mybase = get_position(f);
1437 uint32_t mysize = read_int32(f);
1439 if (first_base == (uint64_t) (-1))
1440 first_base = mybase;
1442 if (mysize < 8 + extraheaders)
1445 if (find_atom (f, mybase + (8 + extraheaders),
1446 mysize - (8 + extraheaders), name_inside)) {
1447 set_position(f, mybase);
1451 if (size <= mysize) {
1458 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1460 set_position(f, first_base);
1473 static struct membuffer *membuffer_create(void)
1475 const unsigned initial_size = 256;
1477 struct membuffer *buf = para_malloc(sizeof(*buf));
1478 buf->data = para_malloc(initial_size);
1480 buf->allocated = initial_size;
1481 buf->error = buf->data == 0 ? 1 : 0;
1486 static unsigned membuffer_write(struct membuffer *buf, const void *ptr, unsigned bytes)
1488 unsigned dest_size = buf->written + bytes;
1492 if (dest_size > buf->allocated) {
1494 buf->allocated <<= 1;
1495 } while (dest_size > buf->allocated);
1496 buf->data = para_realloc(buf->data, buf->allocated);
1500 memcpy((char *) buf->data + buf->written, ptr, bytes);
1501 buf->written += bytes;
1505 static unsigned membuffer_write_atom_name(struct membuffer *buf, const char *data)
1507 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1510 static unsigned membuffer_write_int16(struct membuffer *buf, uint16_t data)
1514 write_u16_be(temp, data);
1515 return membuffer_write(buf, temp, 2);
1518 static unsigned membuffer_write_int32(struct membuffer *buf, uint32_t data)
1521 write_u32_be(temp, data);
1522 return membuffer_write(buf, temp, 4);
1525 static void membuffer_write_track_tag(struct membuffer *buf, const char *name,
1526 uint32_t index, uint32_t total)
1528 membuffer_write_int32(buf,
1529 8 /*atom header */ + 8 /*data atom header */ +
1530 8 /*flags + reserved */ + 8 /*actual data */ );
1531 membuffer_write_atom_name(buf, name);
1532 membuffer_write_int32(buf,
1533 8 /*data atom header */ +
1534 8 /*flags + reserved */ + 8 /*actual data */ );
1535 membuffer_write_atom_name(buf, "data");
1536 membuffer_write_int32(buf, 0); //flags
1537 membuffer_write_int32(buf, 0); //reserved
1538 membuffer_write_int16(buf, 0);
1539 membuffer_write_int16(buf, (uint16_t) index); //track number
1540 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1541 membuffer_write_int16(buf, 0);
1544 static void membuffer_write_int16_tag(struct membuffer *buf, const char *name,
1547 membuffer_write_int32(buf,
1548 8 /*atom header */ + 8 /*data atom header */ +
1549 8 /*flags + reserved */ + 2 /*actual data */ );
1550 membuffer_write_atom_name(buf, name);
1551 membuffer_write_int32(buf,
1552 8 /*data atom header */ +
1553 8 /*flags + reserved */ + 2 /*actual data */ );
1554 membuffer_write_atom_name(buf, "data");
1555 membuffer_write_int32(buf, 0); //flags
1556 membuffer_write_int32(buf, 0); //reserved
1557 membuffer_write_int16(buf, value); //value
1560 static uint32_t myatoi(const char *param)
1562 return param ? atoi(param) : 0;
1565 static uint32_t meta_genre_to_index(const char *genrestr)
1568 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1569 if (!strcasecmp(genrestr, ID3v1GenreList[n]))
1575 struct stdmeta_entry {
1580 struct stdmeta_entry stdmetas[] = {
1581 {"\xA9" "nam", "title"},
1582 {"\xA9" "ART", "artist"},
1583 {"\xA9" "wrt", "writer"},
1584 {"\xA9" "alb", "album"},
1585 {"\xA9" "day", "date"},
1586 {"\xA9" "too", "tool"},
1587 {"\xA9" "cmt", "comment"},
1588 {"cpil", "compilation"},
1590 {"aART", "album_artist"},
1593 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1596 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1597 if (!strcasecmp(name, stdmetas[n].name))
1598 return stdmetas[n].atom;
1603 static void membuffer_write_std_tag(struct membuffer *buf, const char *name,
1608 /* special check for compilation flag */
1609 if (strcmp(name, "cpil") == 0) {
1613 membuffer_write_int32(buf,
1614 8 /*atom header */ + 8 /*data atom header */ +
1615 8 /*flags + reserved */ + strlen(value));
1616 membuffer_write_atom_name(buf, name);
1617 membuffer_write_int32(buf,
1618 8 /*data atom header */ +
1619 8 /*flags + reserved */ + strlen(value));
1620 membuffer_write_atom_name(buf, "data");
1621 membuffer_write_int32(buf, flags); //flags
1622 membuffer_write_int32(buf, 0); //reserved
1623 membuffer_write(buf, value, strlen(value));
1626 static void membuffer_write_custom_tag(struct membuffer *buf, const char *name,
1629 membuffer_write_int32(buf,
1630 8 /*atom header */ +
1631 0x1C /*weirdo itunes atom */ +
1632 12 /*name atom header */ + strlen(name) +
1633 16 /*data atom header + flags */ + strlen(value));
1634 membuffer_write_atom_name(buf, "----");
1635 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1636 membuffer_write_atom_name(buf, "mean");
1637 membuffer_write_int32(buf, 0);
1638 membuffer_write(buf, "com.apple.iTunes", 16);
1639 membuffer_write_int32(buf, 12 + strlen(name));
1640 membuffer_write_atom_name(buf, "name");
1641 membuffer_write_int32(buf, 0);
1642 membuffer_write(buf, name, strlen(name));
1643 membuffer_write_int32(buf,
1644 8 /*data atom header */ +
1645 8 /*flags + reserved */ + strlen(value));
1646 membuffer_write_atom_name(buf, "data");
1647 membuffer_write_int32(buf, 1); //flags
1648 membuffer_write_int32(buf, 0); //reserved
1649 membuffer_write(buf, value, strlen(value));
1652 static unsigned membuffer_error(const struct membuffer *buf)
1657 static void membuffer_free(struct membuffer *buf)
1663 static unsigned membuffer_get_size(const struct membuffer *buf)
1665 return buf->written;
1668 static void *membuffer_detach(struct membuffer *buf)
1674 ret = para_realloc(buf->data, buf->written);
1680 static uint32_t create_ilst(const struct mp4_metadata *data, void **out_buffer,
1681 uint32_t * out_size)
1683 struct membuffer *buf = membuffer_create();
1685 char *mask = para_calloc(data->count);
1686 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1687 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1688 const char *genre_ptr = 0, *tempo_ptr = 0;
1690 for (metaptr = 0; metaptr < data->count; metaptr++) {
1691 struct mp4_tag *tag = &data->tags[metaptr];
1692 if (!strcasecmp(tag->item, "tracknumber")
1693 || !strcasecmp(tag->item, "track")) {
1694 if (tracknumber_ptr == 0)
1695 tracknumber_ptr = tag->value;
1697 } else if (!strcasecmp(tag->item, "totaltracks")) {
1698 if (totaltracks_ptr == 0)
1699 totaltracks_ptr = tag->value;
1701 } else if (!strcasecmp(tag->item, "discnumber")
1702 || !strcasecmp(tag->item, "disc")) {
1703 if (discnumber_ptr == 0)
1704 discnumber_ptr = tag->value;
1706 } else if (!strcasecmp(tag->item, "totaldiscs")) {
1707 if (totaldiscs_ptr == 0)
1708 totaldiscs_ptr = tag->value;
1710 } else if (!strcasecmp(tag->item, "genre")) {
1712 genre_ptr = tag->value;
1714 } else if (!strcasecmp(tag->item, "tempo")) {
1716 tempo_ptr = tag->value;
1721 if (tracknumber_ptr)
1722 membuffer_write_track_tag(buf, "trkn", myatoi(tracknumber_ptr),
1723 myatoi(totaltracks_ptr));
1725 membuffer_write_track_tag(buf, "disk", myatoi(discnumber_ptr),
1726 myatoi(totaldiscs_ptr));
1728 membuffer_write_int16_tag(buf, "tmpo", myatoi(tempo_ptr));
1731 uint32_t index = meta_genre_to_index(genre_ptr);
1733 membuffer_write_std_tag(buf, "©gen", genre_ptr);
1735 membuffer_write_int16_tag(buf, "gnre", index);
1737 for (metaptr = 0; metaptr < data->count; metaptr++) {
1738 struct mp4_tag *tag;
1739 const char *std_meta_atom;
1743 tag = &data->tags[metaptr];
1744 std_meta_atom = find_standard_meta(tag->item);
1746 membuffer_write_std_tag(buf, std_meta_atom, tag->value);
1748 membuffer_write_custom_tag(buf, tag->item, tag->value);
1752 if (membuffer_error(buf)) {
1753 membuffer_free(buf);
1757 *out_size = membuffer_get_size(buf);
1758 *out_buffer = membuffer_detach(buf);
1759 membuffer_free(buf);
1764 static void membuffer_write_atom(struct membuffer *buf, const char *name, unsigned size,
1767 membuffer_write_int32(buf, size + 8);
1768 membuffer_write_atom_name(buf, name);
1769 membuffer_write(buf, data, size);
1772 static void *membuffer_get_ptr(const struct membuffer *buf)
1777 static void membuffer_set_error(struct membuffer *buf)
1782 static unsigned membuffer_transfer_from_file(struct membuffer *buf, struct mp4 *src,
1788 oldsize = membuffer_get_size(buf);
1789 if (membuffer_write(buf, 0, bytes) != bytes)
1792 bufptr = membuffer_get_ptr(buf);
1796 if ((unsigned)read_data(src, (char *) bufptr + oldsize, bytes) !=
1798 membuffer_set_error(buf);
1805 static uint32_t create_meta(const struct mp4_metadata *data, void **out_buffer,
1806 uint32_t * out_size)
1808 struct membuffer *buf;
1812 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1815 buf = membuffer_create();
1817 membuffer_write_int32(buf, 0);
1818 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1821 *out_size = membuffer_get_size(buf);
1822 *out_buffer = membuffer_detach(buf);
1823 membuffer_free(buf);
1827 static uint32_t create_udta(const struct mp4_metadata *data, void **out_buffer,
1828 uint32_t * out_size)
1830 struct membuffer *buf;
1834 if (!create_meta(data, &meta_buffer, &meta_size))
1837 buf = membuffer_create();
1839 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1843 *out_size = membuffer_get_size(buf);
1844 *out_buffer = membuffer_detach(buf);
1845 membuffer_free(buf);
1849 static uint32_t fix_byte_order_32(uint32_t src)
1851 return read_u32_be(&src);
1854 static uint32_t modify_moov(struct mp4 *f, const struct mp4_metadata *data,
1855 void **out_buffer, uint32_t * out_size)
1857 uint64_t total_base = f->moov_offset + 8;
1858 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1860 uint64_t udta_offset, meta_offset, ilst_offset;
1861 uint32_t udta_size, meta_size, ilst_size;
1863 uint32_t new_ilst_size;
1864 void *new_ilst_buffer;
1869 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1870 struct membuffer *buf;
1871 void *new_udta_buffer;
1872 uint32_t new_udta_size;
1873 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1876 buf = membuffer_create();
1877 set_position(f, total_base);
1878 membuffer_transfer_from_file(buf, f, total_size);
1880 membuffer_write_atom(buf, "udta", new_udta_size,
1883 free(new_udta_buffer);
1885 *out_size = membuffer_get_size(buf);
1886 *out_buffer = membuffer_detach(buf);
1887 membuffer_free(buf);
1890 udta_offset = get_position(f);
1891 udta_size = read_int32(f);
1892 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
1893 struct membuffer *buf;
1894 void *new_meta_buffer;
1895 uint32_t new_meta_size;
1896 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
1899 buf = membuffer_create();
1900 set_position(f, total_base);
1901 membuffer_transfer_from_file(buf, f,
1902 (uint32_t)(udta_offset - total_base));
1904 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
1905 membuffer_write_atom_name(buf, "udta");
1906 membuffer_transfer_from_file(buf, f, udta_size);
1908 membuffer_write_atom(buf, "meta", new_meta_size,
1910 free(new_meta_buffer);
1912 *out_size = membuffer_get_size(buf);
1913 *out_buffer = membuffer_detach(buf);
1914 membuffer_free(buf);
1917 meta_offset = get_position(f);
1918 meta_size = read_int32(f);
1919 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
1920 return 0; //shouldn't happen, find_atom_v2 above takes care of it
1921 ilst_offset = get_position(f);
1922 ilst_size = read_int32(f);
1924 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
1927 size_delta = new_ilst_size - (ilst_size - 8);
1929 *out_size = total_size + size_delta;
1930 *out_buffer = para_malloc(*out_size);
1931 p_out = (uint8_t *) * out_buffer;
1933 set_position(f, total_base);
1935 (uint32_t) (udta_offset - total_base));
1936 p_out += (uint32_t) (udta_offset - total_base);
1937 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1939 read_data(f, p_out, 4);
1942 (uint32_t) (meta_offset - udta_offset - 8));
1943 p_out += (uint32_t) (meta_offset - udta_offset - 8);
1944 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1946 read_data(f, p_out, 4);
1949 (uint32_t) (ilst_offset - meta_offset - 8));
1950 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
1951 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1953 read_data(f, p_out, 4);
1956 memcpy(p_out, new_ilst_buffer, new_ilst_size);
1957 p_out += new_ilst_size;
1959 set_position(f, ilst_offset + ilst_size);
1960 read_data(f, p_out, (uint32_t) (total_size
1961 - (ilst_offset - total_base) - ilst_size));
1963 free(new_ilst_buffer);
1968 static int32_t write_data(struct mp4 *f, void *data, uint32_t size)
1972 result = f->stream->write(f->stream->user_data, data, size);
1974 f->current_position += size;
1979 static int32_t write_int32(struct mp4 *f, uint32_t data)
1982 write_u32_be(temp, data);
1983 return write_data(f, temp, sizeof(temp));
1986 static int32_t truncate_stream(struct mp4 *f)
1988 return f->stream->truncate(f->stream->user_data);
1991 int32_t mp4_meta_update(struct mp4_callback *f, const struct mp4_metadata *data)
1993 void *new_moov_data;
1994 uint32_t new_moov_size;
1996 struct mp4 *ff = para_calloc(sizeof(struct mp4));
1998 set_position(ff, 0);
2002 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2007 /* copy moov atom to end of the file */
2008 if (ff->last_atom != ATOM_MOOV) {
2009 char *free_data = "free";
2011 /* rename old moov to free */
2012 set_position(ff, ff->moov_offset + 4);
2013 write_data(ff, free_data, 4);
2015 set_position(ff, ff->file_size);
2016 write_int32(ff, new_moov_size + 8);
2017 write_data(ff, "moov", 4);
2018 write_data(ff, new_moov_data, new_moov_size);
2020 set_position(ff, ff->moov_offset);
2021 write_int32(ff, new_moov_size + 8);
2022 write_data(ff, "moov", 4);
2023 write_data(ff, new_moov_data, new_moov_size);
2026 truncate_stream(ff);
2032 /* find a metadata item by name */
2033 /* returns 0 if item found, 1 if no such item */
2034 static int32_t meta_find_by_name(const struct mp4 *f, const char *item,
2039 for (i = 0; i < f->tags.count; i++) {
2040 if (!strcasecmp(f->tags.tags[i].item, item)) {
2041 *value = para_strdup(f->tags.tags[i].value);
2052 int32_t mp4_meta_get_artist(const struct mp4 *f, char **value)
2054 return meta_find_by_name(f, "artist", value);
2057 int32_t mp4_meta_get_title(const struct mp4 *f, char **value)
2059 return meta_find_by_name(f, "title", value);
2062 int32_t mp4_meta_get_date(const struct mp4 *f, char **value)
2064 return meta_find_by_name(f, "date", value);
2067 int32_t mp4_meta_get_album(const struct mp4 *f, char **value)
2069 return meta_find_by_name(f, "album", value);
2072 int32_t mp4_meta_get_comment(const struct mp4 *f, char **value)
2074 return meta_find_by_name(f, "comment", value);