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"
23 int32_t stsd_entry_count;
26 int32_t stsz_sample_size;
27 int32_t stsz_sample_count;
31 int32_t stts_entry_count;
32 int32_t *stts_sample_count;
33 int32_t *stts_sample_delta;
36 int32_t stsc_entry_count;
37 int32_t *stsc_first_chunk;
38 int32_t *stsc_samples_per_chunk;
39 int32_t *stsc_sample_desc_index;
42 int32_t stco_entry_count;
43 int32_t *stco_chunk_offset;
46 int32_t ctts_entry_count;
47 int32_t *ctts_sample_count;
48 int32_t *ctts_sample_offset;
51 uint8_t *decoderConfig;
52 int32_t decoderConfigLen;
61 #define MAX_TRACKS 1024
64 /* stream to read from */
65 struct mp4_callback *stream;
66 int64_t current_position;
78 /* incremental track index while reading the file */
82 struct mp4_track *track[MAX_TRACKS];
85 struct mp4_metadata tags;
88 int32_t mp4_total_tracks(const struct mp4 *f)
90 return f->total_tracks;
93 static int32_t read_data(struct mp4 *f, void *data, uint32_t size)
97 result = f->stream->read(f->stream->user_data, data, size);
100 f->stream->read_error++;
102 f->current_position += size;
107 static uint64_t read_int64(struct mp4 *f)
111 read_data(f, data, 8);
112 return read_u64_be(data);
115 /* comnapre 2 atom names, returns 1 for equal, 0 for unequal */
116 static int32_t atom_compare(int8_t a1, int8_t b1, int8_t c1, int8_t d1,
117 int8_t a2, int8_t b2, int8_t c2, int8_t d2)
119 if (a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2)
133 /* atoms with subatoms */
141 ATOM_ILST = 8, /* iTunes Metadata list */
152 ATOM_COMPILATION = 19,
162 /* atoms without subatoms */
182 ATOM_META = 148, /* iTunes Metadata box */
183 ATOM_NAME = 149, /* iTunes Metadata name box */
184 ATOM_DATA = 150, /* iTunes Metadata data box */
191 ATOM_ALBUM_ARTIST = 157,
192 ATOM_CONTENTGROUP = 158,
194 ATOM_DESCRIPTION = 160,
197 ATOM_EPISODENAME = 163,
198 ATOM_SORTTITLE = 164,
199 ATOM_SORTALBUM = 165,
200 ATOM_SORTARTIST = 166,
201 ATOM_SORTALBUMARTIST = 167,
202 ATOM_SORTWRITER = 168,
211 #define ATOM_FREE ATOM_UNKNOWN
212 #define ATOM_SKIP ATOM_UNKNOWN
214 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
216 static uint8_t atom_name_to_type(int8_t a, int8_t b, int8_t c, int8_t d)
219 if (atom_compare(a, b, c, d, 'm', 'o', 'o', 'v'))
221 else if (atom_compare(a, b, c, d, 'm', 'i', 'n', 'f'))
223 else if (atom_compare(a, b, c, d, 'm', 'd', 'i', 'a'))
225 else if (atom_compare(a, b, c, d, 'm', 'd', 'a', 't'))
227 else if (atom_compare(a, b, c, d, 'm', 'd', 'h', 'd'))
229 else if (atom_compare(a, b, c, d, 'm', 'v', 'h', 'd'))
231 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'a'))
233 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'v'))
235 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 's'))
237 else if (atom_compare(a, b, c, d, 'm', 'e', 't', 'a'))
239 } else if (a == 't') {
240 if (atom_compare(a, b, c, d, 't', 'r', 'a', 'k'))
242 else if (atom_compare(a, b, c, d, 't', 'k', 'h', 'd'))
244 else if (atom_compare(a, b, c, d, 't', 'r', 'e', 'f'))
246 else if (atom_compare(a, b, c, d, 't', 'r', 'k', 'n'))
248 else if (atom_compare(a, b, c, d, 't', 'm', 'p', 'o'))
250 else if (atom_compare(a, b, c, d, 't', 'v', 'n', 'n'))
252 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'h'))
254 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 'n'))
255 return ATOM_EPISODENAME;
256 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'n'))
258 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 's'))
260 } else if (a == 's') {
261 if (atom_compare(a, b, c, d, 's', 't', 'b', 'l'))
263 else if (atom_compare(a, b, c, d, 's', 'm', 'h', 'd'))
265 else if (atom_compare(a, b, c, d, 's', 't', 's', 'd'))
267 else if (atom_compare(a, b, c, d, 's', 't', 't', 's'))
269 else if (atom_compare(a, b, c, d, 's', 't', 'c', 'o'))
271 else if (atom_compare(a, b, c, d, 's', 't', 's', 'c'))
273 else if (atom_compare(a, b, c, d, 's', 't', 's', 'z'))
275 else if (atom_compare(a, b, c, d, 's', 't', 'z', '2'))
277 else if (atom_compare(a, b, c, d, 's', 'k', 'i', 'p'))
279 else if (atom_compare(a, b, c, d, 's', 'i', 'n', 'f'))
281 else if (atom_compare(a, b, c, d, 's', 'c', 'h', 'i'))
283 else if (atom_compare(a, b, c, d, 's', 'o', 'n', 'm'))
284 return ATOM_SORTTITLE;
285 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'l'))
286 return ATOM_SORTALBUM;
287 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'r'))
288 return ATOM_SORTARTIST;
289 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'a'))
290 return ATOM_SORTALBUMARTIST;
291 else if (atom_compare(a, b, c, d, 's', 'o', 'c', 'o'))
292 return ATOM_SORTWRITER;
293 else if (atom_compare(a, b, c, d, 's', 'o', 's', 'n'))
294 return ATOM_SORTSHOW;
295 } else if (a == COPYRIGHT_SYMBOL) {
296 if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'n', 'a', 'm'))
298 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'A', 'R', 'T'))
300 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'w', 'r', 't'))
302 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'a', 'l', 'b'))
304 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'd', 'a', 'y'))
306 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 't', 'o', 'o'))
308 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'c', 'm', 't'))
310 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'e', 'n'))
312 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'r', 'p'))
313 return ATOM_CONTENTGROUP;
314 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'l', 'y', 'r'))
318 if (atom_compare(a, b, c, d, 'e', 'd', 't', 's'))
320 else if (atom_compare(a, b, c, d, 'e', 's', 'd', 's'))
322 else if (atom_compare(a, b, c, d, 'f', 't', 'y', 'p'))
324 else if (atom_compare(a, b, c, d, 'f', 'r', 'e', 'e'))
326 else if (atom_compare(a, b, c, d, 'h', 'm', 'h', 'd'))
328 else if (atom_compare(a, b, c, d, 'v', 'm', 'h', 'd'))
330 else if (atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
332 else if (atom_compare(a, b, c, d, 'i', 'l', 's', 't'))
334 else if (atom_compare(a, b, c, d, 'n', 'a', 'm', 'e'))
336 else if (atom_compare(a, b, c, d, 'd', 'a', 't', 'a'))
338 else if (atom_compare(a, b, c, d, 'd', 'i', 's', 'k'))
340 else if (atom_compare(a, b, c, d, 'g', 'n', 'r', 'e'))
342 else if (atom_compare(a, b, c, d, 'c', 'o', 'v', 'r'))
344 else if (atom_compare(a, b, c, d, 'c', 'p', 'i', 'l'))
345 return ATOM_COMPILATION;
346 else if (atom_compare(a, b, c, d, 'c', 't', 't', 's'))
348 else if (atom_compare(a, b, c, d, 'd', 'r', 'm', 's'))
350 else if (atom_compare(a, b, c, d, 'f', 'r', 'm', 'a'))
352 else if (atom_compare(a, b, c, d, 'p', 'r', 'i', 'v'))
354 else if (atom_compare(a, b, c, d, 'i', 'v', 'i', 'v'))
356 else if (atom_compare(a, b, c, d, 'u', 's', 'e', 'r'))
358 else if (atom_compare(a, b, c, d, 'k', 'e', 'y', ' '))
360 else if (atom_compare(a, b, c, d, 'a', 'A', 'R', 'T'))
361 return ATOM_ALBUM_ARTIST;
362 else if (atom_compare(a, b, c, d, 'd', 'e', 's', 'c'))
363 return ATOM_DESCRIPTION;
364 else if (atom_compare(a, b, c, d, 'p', 'c', 's', 't'))
370 /* read atom header, return atom size, atom size is with header included */
371 static uint64_t atom_read_header(struct mp4 *f, uint8_t * atom_type,
372 uint8_t * header_size)
376 int8_t atom_header[8];
378 ret = read_data(f, atom_header, 8);
382 size = read_u32_be(atom_header);
385 /* check for 64 bit atom size */
388 size = read_int64(f);
390 *atom_type = atom_name_to_type(atom_header[4], atom_header[5],
391 atom_header[6], atom_header[7]);
395 static int64_t get_position(const struct mp4 *f)
397 return f->current_position;
400 static int need_parse_when_meta_only(uint8_t atom_type)
421 static int32_t set_position(struct mp4 *f, int64_t position)
423 f->stream->seek(f->stream->user_data, position);
424 f->current_position = position;
429 static void track_add(struct mp4 *f)
433 if (f->total_tracks > MAX_TRACKS) {
438 f->track[f->total_tracks - 1] = para_calloc(sizeof(struct mp4_track));
441 static uint8_t read_char(struct mp4 *f)
444 read_data(f, &output, 1);
448 static uint32_t read_int24(struct mp4 *f)
452 read_data(f, data, 3);
453 return read_u24_be(data);
456 static uint32_t read_int32(struct mp4 *f)
460 read_data(f, data, 4);
461 return read_u32_be(data);
464 static int32_t read_stsz(struct mp4 *f)
469 if (f->total_tracks == 0)
471 t = f->track[f->total_tracks - 1];
472 read_char(f); /* version */
473 read_int24(f); /* flags */
474 t->stsz_sample_size = read_int32(f);
475 t->stsz_sample_count = read_int32(f);
476 if (t->stsz_sample_size != 0)
478 t->stsz_table = para_malloc(t->stsz_sample_count * sizeof(int32_t));
479 for (i = 0; i < t->stsz_sample_count && !f->stream->read_error; i++)
480 t->stsz_table[i] = read_int32(f);
484 static int32_t read_stts(struct mp4 *f)
490 if (f->total_tracks == 0)
492 t = f->track[f->total_tracks - 1];
493 if (t->stts_entry_count)
495 read_char(f); /* version */
496 read_int24(f); /* flags */
497 t->stts_entry_count = read_int32(f);
499 t->stts_sample_count = para_malloc(t->stts_entry_count
501 t->stts_sample_delta = para_malloc(t->stts_entry_count
504 for (i = 0; i < t->stts_entry_count && !f->stream->read_error; i++) {
505 t->stts_sample_count[i] = read_int32(f);
506 t->stts_sample_delta[i] = read_int32(f);
511 static int32_t read_ctts(struct mp4 *f)
516 if (f->total_tracks == 0)
518 t = f->track[f->total_tracks - 1];
519 if (t->ctts_entry_count)
522 read_char(f); /* version */
523 read_int24(f); /* flags */
524 t->ctts_entry_count = read_int32(f);
526 t->ctts_sample_count = para_malloc(t->ctts_entry_count
528 t->ctts_sample_offset = para_malloc(t->ctts_entry_count
532 for (i = 0; i < t->ctts_entry_count && !f->stream->read_error; i++) {
533 t->ctts_sample_count[i] = read_int32(f);
534 t->ctts_sample_offset[i] = read_int32(f);
539 static int32_t read_stsc(struct mp4 *f)
544 if (f->total_tracks == 0)
546 t = f->track[f->total_tracks - 1];
548 read_char(f); /* version */
549 read_int24(f); /* flags */
550 t->stsc_entry_count = read_int32(f);
551 t->stsc_first_chunk = para_malloc(t->stsc_entry_count * sizeof(int32_t));
552 t->stsc_samples_per_chunk = para_malloc(t->stsc_entry_count
554 t->stsc_sample_desc_index = para_malloc(t->stsc_entry_count *
558 for (i = 0; i < t->stsc_entry_count && !f->stream->read_error; i++) {
559 t->stsc_first_chunk[i] = read_int32(f);
560 t->stsc_samples_per_chunk[i] = read_int32(f);
561 t->stsc_sample_desc_index[i] = read_int32(f);
566 static int32_t read_stco(struct mp4 *f)
571 if (f->total_tracks == 0)
573 t = f->track[f->total_tracks - 1];
575 read_char(f); /* version */
576 read_int24(f); /* flags */
577 t->stco_entry_count = read_int32(f);
578 t->stco_chunk_offset = para_malloc(t->stco_entry_count
581 for (i = 0; i < t->stco_entry_count && !f->stream->read_error; i++)
582 t->stco_chunk_offset[i] = read_int32(f);
586 static uint16_t read_int16(struct mp4 *f)
590 read_data(f, data, 2);
591 return read_u16_be(data);
594 static uint32_t read_mp4_descr_length(struct mp4 *f)
597 uint8_t numBytes = 0;
603 length = (length << 7) | (b & 0x7F);
604 } while ((b & 0x80) && numBytes < 4);
608 static int32_t read_esds(struct mp4 *f)
614 if (f->total_tracks == 0)
616 t = f->track[f->total_tracks - 1];
617 read_char(f); /* version */
618 read_int24(f); /* flags */
619 /* get and verify ES_DescrTag */
623 if (read_mp4_descr_length(f) < 5 + 15) {
633 /* get and verify DecoderConfigDescrTab */
634 if (read_char(f) != 0x04) {
639 temp = read_mp4_descr_length(f);
643 t->audioType = read_char(f);
644 read_int32(f); //0x15000414 ????
645 t->maxBitrate = read_int32(f);
646 t->avgBitrate = read_int32(f);
648 /* get and verify DecSpecificInfoTag */
649 if (read_char(f) != 0x05) {
654 t->decoderConfigLen = read_mp4_descr_length(f);
655 free(t->decoderConfig);
656 t->decoderConfig = para_malloc(t->decoderConfigLen);
657 read_data(f, t->decoderConfig, t->decoderConfigLen);
658 /* will skip the remainder of the atom */
662 static int32_t read_mp4a(struct mp4 *f)
665 uint8_t atom_type = 0;
666 uint8_t header_size = 0;
669 if (f->total_tracks == 0)
671 t = f->track[f->total_tracks - 1];
673 for (i = 0; i < 6; i++) {
674 read_char(f); /* reserved */
676 /* data_reference_index */ read_int16(f);
678 read_int32(f); /* reserved */
679 read_int32(f); /* reserved */
681 t->channelCount = read_int16(f);
682 t->sampleSize = read_int16(f);
687 t->sampleRate = read_int16(f);
691 atom_read_header(f, &atom_type, &header_size);
692 if (atom_type == ATOM_ESDS)
697 static int32_t read_stsd(struct mp4 *f)
700 uint8_t header_size = 0;
704 if (f->total_tracks == 0)
706 t = f->track[f->total_tracks - 1];
708 read_char(f); /* version */
709 read_int24(f); /* flags */
711 t->stsd_entry_count = read_int32(f);
714 for (i = 0; i < t->stsd_entry_count && !f->stream->read_error; i++) {
715 uint64_t skip = get_position(f);
717 uint8_t atom_type = 0;
718 size = atom_read_header(f, &atom_type, &header_size);
721 if (atom_type == ATOM_MP4A) {
722 t->type = TRACK_AUDIO;
724 } else if (atom_type == ATOM_MP4V) {
725 t->type = TRACK_VIDEO;
726 } else if (atom_type == ATOM_MP4S) {
727 t->type = TRACK_SYSTEM;
729 t->type = TRACK_UNKNOWN;
731 set_position(f, skip);
737 static int32_t read_mvhd(struct mp4 *f)
741 read_char(f); /* version */
742 read_int24(f); /* flags */
743 read_int32(f); /* creation_time */
744 read_int32(f); /* modification_time */
745 f->time_scale = read_int32(f);
746 f->duration = read_int32(f);
747 read_int32(f); /* preferred_rate */
748 read_int16(f); /* preferred_volume */
749 for (i = 0; i < 10; i++)
750 read_char(f); /* reserved */
751 for (i = 0; i < 9; i++)
752 read_int32(f); /* matrix */
753 read_int32(f); /* preview_time */
754 read_int32(f); /* preview_duration */
755 read_int32(f); /* poster_time */
756 read_int32(f); /* selection_time */
757 read_int32(f); /* selection_duration */
758 read_int32(f); /* current_time */
759 read_int32(f); /* next_track_id */
763 static int32_t tag_add_field(struct mp4_metadata *tags, const char *item,
764 const char *value, int32_t len)
766 if (!item || (item && !*item) || !value)
768 tags->tags = para_realloc(tags->tags,
769 (tags->count + 1) * sizeof(struct mp4_tag));
770 tags->tags[tags->count].item = para_strdup(item);
771 tags->tags[tags->count].len = len;
773 tags->tags[tags->count].value = para_malloc(len + 1);
774 memcpy(tags->tags[tags->count].value, value, len);
775 tags->tags[tags->count].value[len] = 0;
777 tags->tags[tags->count].value = para_strdup(value);
783 static const char *ID3v1GenreList[] = {
784 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
785 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
786 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
787 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
788 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
789 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
790 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
791 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
792 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
793 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
794 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
795 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
796 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
797 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
798 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
799 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
800 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
801 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
802 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
803 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
804 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
805 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
806 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
807 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
808 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
809 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
810 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
811 "Anime", "JPop", "SynthPop",
814 static const char *meta_index_to_genre(uint32_t idx)
816 if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
817 return ID3v1GenreList[idx - 1];
823 static char *read_string(struct mp4 *f, uint32_t length)
825 char *str = para_malloc(length + 1);
826 if ((uint32_t)read_data(f, str, length) != length) {
834 static int32_t set_metadata_name(uint8_t atom_type, char **name)
836 static char *tag_names[] = {
837 "unknown", "title", "artist", "writer", "album",
838 "date", "tool", "comment", "genre", "track",
839 "disc", "compilation", "genre", "tempo", "cover",
840 "album_artist", "contentgroup", "lyrics", "description",
841 "network", "show", "episodename",
842 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
843 "sortwriter", "sortshow",
844 "season", "episode", "podcast"
879 case ATOM_COMPILATION:
891 case ATOM_ALBUM_ARTIST:
894 case ATOM_CONTENTGROUP:
900 case ATOM_DESCRIPTION:
909 case ATOM_EPISODENAME:
918 case ATOM_SORTARTIST:
921 case ATOM_SORTALBUMARTIST:
924 case ATOM_SORTWRITER:
944 *name = para_strdup(tag_names[tag_idx]);
948 static uint32_t min_body_size(uint8_t atom_type)
955 return sizeof (char) /* version */
956 + sizeof(uint8_t) * 3 /* flags */
957 + sizeof(uint32_t) /* reserved */
958 + sizeof(uint16_t) /* leading uint16_t */
959 + sizeof(uint16_t) /* track */
960 + sizeof(uint16_t); /* totaltracks */
962 return sizeof (char) /* version */
963 + sizeof(uint8_t) * 3 /* flags */
964 + sizeof(uint32_t) /* reserved */
965 + sizeof(uint16_t) /* disc */
966 + sizeof(uint16_t); /* totaldiscs */
967 default: assert(false);
971 static int32_t parse_tag(struct mp4 *f, uint8_t parent, int32_t size)
974 uint8_t header_size = 0;
975 uint64_t subsize, sumsize;
984 sumsize < size && !f->stream->read_error; /* CVE-2017-9222 */
985 set_position(f, destpos), sumsize += subsize
987 subsize = atom_read_header(f, &atom_type, &header_size);
988 destpos = get_position(f) + subsize - header_size;
991 if (atom_type == ATOM_NAME) {
992 read_char(f); /* version */
993 read_int24(f); /* flags */
995 name = read_string(f, subsize - (header_size + 4));
998 if (atom_type != ATOM_DATA)
1000 read_char(f); /* version */
1001 read_int24(f); /* flags */
1002 read_int32(f); /* reserved */
1004 /* some need special attention */
1005 if (parent == ATOM_GENRE2 || parent == ATOM_TEMPO) {
1007 if (subsize - header_size < min_body_size(parent))
1009 val = read_int16(f);
1010 if (parent == ATOM_TEMPO) {
1012 sprintf(temp, "%.5u BPM", val);
1013 tag_add_field(&(f-> tags), "tempo",
1016 const char *tmp = meta_index_to_genre(val);
1018 tag_add_field (&(f->tags),
1022 } else if (parent == ATOM_TRACK || parent == ATOM_DISC) {
1023 uint16_t index, total;
1025 if (subsize - header_size < min_body_size(parent))
1028 index = read_int16(f);
1029 total = read_int16(f);
1030 if (parent == ATOM_TRACK)
1032 sprintf(temp, "%d", index);
1033 tag_add_field(&(f->tags), parent == ATOM_TRACK?
1034 "track" : "disc", temp, -1);
1036 sprintf(temp, "%d", total);
1037 tag_add_field(& (f-> tags),
1038 parent == ATOM_TRACK?
1039 "totaltracks" : "totaldiscs", temp, -1);
1044 data = read_string(f, subsize - (header_size + 8));
1045 len = subsize - (header_size + 8);
1051 set_metadata_name(parent , &name);
1053 tag_add_field(&(f->tags), name, data, len);
1062 static int32_t read_mdhd(struct mp4 *f)
1065 struct mp4_track *t;
1068 if (f->total_tracks == 0)
1070 t = f->track[f->total_tracks - 1];
1072 version = read_int32(f);
1074 read_int64(f); //creation-time
1075 read_int64(f); //modification-time
1076 t->timeScale = read_int32(f); //timescale
1077 t->duration = read_int64(f); //duration
1078 } else { //version == 0
1081 read_int32(f); //creation-time
1082 read_int32(f); //modification-time
1083 t->timeScale = read_int32(f); //timescale
1084 temp = read_int32(f);
1085 t->duration = (temp == (uint32_t) (-1))?
1086 (uint64_t) (-1) : (uint64_t) (temp);
1093 static int32_t parse_metadata(struct mp4 *f, int32_t size)
1095 uint64_t subsize, sumsize = 0;
1097 uint8_t header_size = 0;
1099 while (sumsize < size) {
1100 subsize = atom_read_header(f, &atom_type, &header_size);
1103 parse_tag(f, atom_type, (uint32_t)(subsize - header_size));
1110 static int32_t read_meta(struct mp4 *f, uint64_t size)
1112 uint64_t subsize, sumsize = 0;
1114 uint8_t header_size = 0;
1116 read_char(f); /* version */
1117 read_int24(f); /* flags */
1119 while (sumsize < (size - (header_size + 4))) {
1120 subsize = atom_read_header(f, &atom_type, &header_size);
1121 if (subsize <= header_size + 4)
1123 if (atom_type == ATOM_ILST) {
1124 parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1126 set_position(f, get_position(f) + subsize - header_size);
1134 static int32_t atom_read(struct mp4 *f, int32_t size, uint8_t atom_type)
1136 uint64_t dest_position = get_position(f) + size - 8;
1137 if (atom_type == ATOM_STSZ) {
1138 /* sample size box */
1140 } else if (atom_type == ATOM_STTS) {
1141 /* time to sample box */
1143 } else if (atom_type == ATOM_CTTS) {
1144 /* composition offset box */
1146 } else if (atom_type == ATOM_STSC) {
1147 /* sample to chunk box */
1149 } else if (atom_type == ATOM_STCO) {
1150 /* chunk offset box */
1152 } else if (atom_type == ATOM_STSD) {
1153 /* sample description box */
1155 } else if (atom_type == ATOM_MVHD) {
1156 /* movie header box */
1158 } else if (atom_type == ATOM_MDHD) {
1161 } else if (atom_type == ATOM_META) {
1162 /* iTunes Metadata box */
1166 set_position(f, dest_position);
1170 /* parse atoms that are sub atoms of other atoms */
1171 static int32_t parse_sub_atoms(struct mp4 *f, uint64_t total_size, int meta_only)
1174 uint8_t atom_type = 0;
1175 uint64_t counted_size = 0;
1176 uint8_t header_size = 0;
1178 while (counted_size < total_size) {
1179 size = atom_read_header(f, &atom_type, &header_size);
1180 counted_size += size;
1182 /* check for end of file */
1186 /* we're starting to read a new track, update index,
1187 * so that all data and tables get written in the right place
1189 if (atom_type == ATOM_TRAK)
1191 /* parse subatoms */
1192 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1193 set_position(f, get_position(f) + size - header_size);
1194 } else if (atom_type < SUBATOMIC) {
1195 parse_sub_atoms(f, size - header_size, meta_only);
1197 atom_read(f, (uint32_t) size, atom_type);
1204 /* parse root atoms */
1205 static int32_t parse_atoms(struct mp4 *f, int meta_only)
1208 uint8_t atom_type = 0;
1209 uint8_t header_size = 0;
1212 f->stream->read_error = 0;
1215 atom_read_header(f, &atom_type, &header_size)) != 0) {
1216 f->file_size += size;
1217 f->last_atom = atom_type;
1219 if (atom_type == ATOM_MOOV && size > header_size) {
1220 f->moov_offset = get_position(f) - header_size;
1221 f->moov_size = size;
1224 /* parse subatoms */
1225 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1226 set_position(f, get_position(f) + size - header_size);
1227 } else if (atom_type < SUBATOMIC) {
1228 parse_sub_atoms(f, size - header_size, meta_only);
1230 /* skip this atom */
1231 set_position(f, get_position(f) + size - header_size);
1238 void mp4_get_decoder_config(const struct mp4 *f, int track,
1239 unsigned char **ppBuf, unsigned int *pBufSize)
1241 if (track >= f->total_tracks) {
1247 if (f->track[track]->decoderConfig == NULL
1248 || f->track[track]->decoderConfigLen == 0) {
1252 *ppBuf = para_malloc(f->track[track]->decoderConfigLen);
1253 memcpy(*ppBuf, f->track[track]->decoderConfig,
1254 f->track[track]->decoderConfigLen);
1255 *pBufSize = f->track[track]->decoderConfigLen;
1259 struct mp4 *mp4_open_read(struct mp4_callback *f)
1261 struct mp4 *ff = para_calloc(sizeof(struct mp4));
1275 static int32_t tag_delete(struct mp4_metadata *tags)
1279 for (i = 0; i < tags->count; i++) {
1280 free(tags->tags[i].item);
1281 free(tags->tags[i].value);
1290 void mp4_close(struct mp4 *ff)
1294 for (i = 0; i < ff->total_tracks; i++) {
1296 free(ff->track[i]->stsz_table);
1297 free(ff->track[i]->stts_sample_count);
1298 free(ff->track[i]->stts_sample_delta);
1299 free(ff->track[i]->stsc_first_chunk);
1300 free(ff->track[i]->stsc_samples_per_chunk);
1301 free(ff->track[i]->stsc_sample_desc_index);
1302 free(ff->track[i]->stco_chunk_offset);
1303 free(ff->track[i]->decoderConfig);
1304 free(ff->track[i]->ctts_sample_count);
1305 free(ff->track[i]->ctts_sample_offset);
1310 tag_delete(&(ff->tags));
1314 static int32_t chunk_of_sample(const struct mp4 *f, int32_t track,
1315 int32_t sample, int32_t *chunk_sample, int32_t *chunk)
1317 int32_t total_entries = 0;
1318 int32_t chunk2entry;
1319 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1323 if (f->track[track] == NULL) {
1327 total_entries = f->track[track]->stsc_entry_count;
1334 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1335 *chunk = chunk2 - chunk1;
1336 range_samples = *chunk * chunk1samples;
1338 if (sample < total + range_samples)
1341 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1344 if (chunk2entry < total_entries) {
1346 total += range_samples;
1348 } while (chunk2entry < total_entries);
1351 *chunk = (sample - total) / chunk1samples + chunk1;
1355 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1360 static int32_t chunk_to_offset(const struct mp4 *f, int32_t track,
1363 const struct mp4_track *p_track = f->track[track];
1365 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1366 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1368 } else if (p_track->stco_entry_count) {
1369 return p_track->stco_chunk_offset[chunk - 1];
1377 static int32_t sample_range_size(const struct mp4 *f, int32_t track,
1378 int32_t chunk_sample, int32_t sample)
1381 const struct mp4_track *p_track = f->track[track];
1383 if (p_track->stsz_sample_size) {
1384 return (sample - chunk_sample) * p_track->stsz_sample_size;
1386 if (sample >= p_track->stsz_sample_count)
1389 for (i = chunk_sample, total = 0; i < sample; i++) {
1390 total += p_track->stsz_table[i];
1397 static int32_t sample_to_offset(const struct mp4 *f, int32_t track,
1400 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1402 chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1404 chunk_offset1 = chunk_to_offset(f, track, chunk);
1405 chunk_offset2 = chunk_offset1 + sample_range_size(f,
1406 track, chunk_sample, sample);
1407 return chunk_offset2;
1411 * Return the number of milliseconds of the given track.
1413 * \param f As returned by \ref mp4_open_read(), must not be NULL.
1414 * \param track Between zero and the value returned by \ref mp4_total_tracks().
1416 * The function returns zero if the audio file is of zero length or contains a
1417 * corrupt track header.
1419 uint64_t mp4_get_duration(const struct mp4 *f, int32_t track)
1421 const struct mp4_track *t = f->track[track];
1423 if (t->timeScale == 0)
1425 return t->duration * 1000 / t->timeScale;
1428 void mp4_set_sample_position(struct mp4 *f, int32_t track, int32_t sample)
1430 int32_t offset = sample_to_offset(f, track, sample);
1431 set_position(f, offset);
1434 int32_t mp4_get_sample_size(const struct mp4 *f, int track, int sample)
1436 const struct mp4_track *t = f->track[track];
1438 if (t->stsz_sample_size != 0)
1439 return t->stsz_sample_size;
1440 return t->stsz_table[sample];
1443 uint32_t mp4_get_sample_rate(const struct mp4 *f, int32_t track)
1445 return f->track[track]->sampleRate;
1448 uint32_t mp4_get_channel_count(const struct mp4 *f, int32_t track)
1450 return f->track[track]->channelCount;
1453 int32_t mp4_num_samples(const struct mp4 *f, int32_t track)
1458 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1459 total += f->track[track]->stts_sample_count[i];
1464 struct mp4 *mp4_open_meta(struct mp4_callback *f)
1466 struct mp4 *ff = para_calloc(sizeof(struct mp4));
1480 int32_t mp4_meta_get_num_items(const struct mp4 *f)
1482 return f->tags.count;
1485 int32_t mp4_meta_get_by_index(const struct mp4 *f, uint32_t index,
1486 char **item, char **value)
1488 if (index >= f->tags.count) {
1493 *item = para_strdup(f->tags.tags[index].item);
1494 *value = para_strdup(f->tags.tags[index].value);
1499 static uint32_t find_atom(struct mp4 *f, uint64_t base, uint32_t size,
1502 uint32_t remaining = size;
1503 uint64_t atom_offset = base;
1508 set_position(f, atom_offset);
1512 atom_size = read_int32(f);
1513 if (atom_size > remaining || atom_size < 8)
1515 read_data(f, atom_name, 4);
1517 if (!memcmp(atom_name, name, 4)) {
1518 set_position(f, atom_offset);
1522 remaining -= atom_size;
1523 atom_offset += atom_size;
1528 static uint32_t find_atom_v2(struct mp4 *f, uint64_t base, uint32_t size,
1529 const char *name, uint32_t extraheaders, const char *name_inside)
1531 uint64_t first_base = (uint64_t) (-1);
1532 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1534 uint64_t mybase = get_position(f);
1535 uint32_t mysize = read_int32(f);
1537 if (first_base == (uint64_t) (-1))
1538 first_base = mybase;
1540 if (mysize < 8 + extraheaders)
1543 if (find_atom (f, mybase + (8 + extraheaders),
1544 mysize - (8 + extraheaders), name_inside)) {
1545 set_position(f, mybase);
1549 if (size <= mysize) {
1556 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1558 set_position(f, first_base);
1571 static struct membuffer *membuffer_create(void)
1573 const unsigned initial_size = 256;
1575 struct membuffer *buf = para_malloc(sizeof(*buf));
1576 buf->data = para_malloc(initial_size);
1578 buf->allocated = initial_size;
1579 buf->error = buf->data == 0 ? 1 : 0;
1584 static unsigned membuffer_write(struct membuffer *buf, const void *ptr, unsigned bytes)
1586 unsigned dest_size = buf->written + bytes;
1590 if (dest_size > buf->allocated) {
1592 buf->allocated <<= 1;
1593 } while (dest_size > buf->allocated);
1594 buf->data = para_realloc(buf->data, buf->allocated);
1598 memcpy((char *) buf->data + buf->written, ptr, bytes);
1599 buf->written += bytes;
1603 static unsigned membuffer_write_atom_name(struct membuffer *buf, const char *data)
1605 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1608 static unsigned membuffer_write_int16(struct membuffer *buf, uint16_t data)
1612 write_u16_be(temp, data);
1613 return membuffer_write(buf, temp, 2);
1616 static unsigned membuffer_write_int32(struct membuffer *buf, uint32_t data)
1619 write_u32_be(temp, data);
1620 return membuffer_write(buf, temp, 4);
1623 static void membuffer_write_track_tag(struct membuffer *buf, const char *name,
1624 uint32_t index, uint32_t total)
1626 membuffer_write_int32(buf,
1627 8 /*atom header */ + 8 /*data atom header */ +
1628 8 /*flags + reserved */ + 8 /*actual data */ );
1629 membuffer_write_atom_name(buf, name);
1630 membuffer_write_int32(buf,
1631 8 /*data atom header */ +
1632 8 /*flags + reserved */ + 8 /*actual data */ );
1633 membuffer_write_atom_name(buf, "data");
1634 membuffer_write_int32(buf, 0); //flags
1635 membuffer_write_int32(buf, 0); //reserved
1636 membuffer_write_int16(buf, 0);
1637 membuffer_write_int16(buf, (uint16_t) index); //track number
1638 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1639 membuffer_write_int16(buf, 0);
1642 static void membuffer_write_int16_tag(struct membuffer *buf, const char *name,
1645 membuffer_write_int32(buf,
1646 8 /*atom header */ + 8 /*data atom header */ +
1647 8 /*flags + reserved */ + 2 /*actual data */ );
1648 membuffer_write_atom_name(buf, name);
1649 membuffer_write_int32(buf,
1650 8 /*data atom header */ +
1651 8 /*flags + reserved */ + 2 /*actual data */ );
1652 membuffer_write_atom_name(buf, "data");
1653 membuffer_write_int32(buf, 0); //flags
1654 membuffer_write_int32(buf, 0); //reserved
1655 membuffer_write_int16(buf, value); //value
1658 static uint32_t myatoi(const char *param)
1660 return param ? atoi(param) : 0;
1663 static uint32_t meta_genre_to_index(const char *genrestr)
1666 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1667 if (!strcasecmp(genrestr, ID3v1GenreList[n]))
1673 struct stdmeta_entry {
1678 struct stdmeta_entry stdmetas[] = {
1679 {"\xA9" "nam", "title"},
1680 {"\xA9" "ART", "artist"},
1681 {"\xA9" "wrt", "writer"},
1682 {"\xA9" "alb", "album"},
1683 {"\xA9" "day", "date"},
1684 {"\xA9" "too", "tool"},
1685 {"\xA9" "cmt", "comment"},
1686 {"cpil", "compilation"},
1688 {"aART", "album_artist"},
1691 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1694 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1695 if (!strcasecmp(name, stdmetas[n].name))
1696 return stdmetas[n].atom;
1701 static void membuffer_write_std_tag(struct membuffer *buf, const char *name,
1706 /* special check for compilation flag */
1707 if (strcmp(name, "cpil") == 0) {
1711 membuffer_write_int32(buf,
1712 8 /*atom header */ + 8 /*data atom header */ +
1713 8 /*flags + reserved */ + strlen(value));
1714 membuffer_write_atom_name(buf, name);
1715 membuffer_write_int32(buf,
1716 8 /*data atom header */ +
1717 8 /*flags + reserved */ + strlen(value));
1718 membuffer_write_atom_name(buf, "data");
1719 membuffer_write_int32(buf, flags); //flags
1720 membuffer_write_int32(buf, 0); //reserved
1721 membuffer_write(buf, value, strlen(value));
1724 static void membuffer_write_custom_tag(struct membuffer *buf, const char *name,
1727 membuffer_write_int32(buf,
1728 8 /*atom header */ +
1729 0x1C /*weirdo itunes atom */ +
1730 12 /*name atom header */ + strlen(name) +
1731 16 /*data atom header + flags */ + strlen(value));
1732 membuffer_write_atom_name(buf, "----");
1733 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1734 membuffer_write_atom_name(buf, "mean");
1735 membuffer_write_int32(buf, 0);
1736 membuffer_write(buf, "com.apple.iTunes", 16);
1737 membuffer_write_int32(buf, 12 + strlen(name));
1738 membuffer_write_atom_name(buf, "name");
1739 membuffer_write_int32(buf, 0);
1740 membuffer_write(buf, name, strlen(name));
1741 membuffer_write_int32(buf,
1742 8 /*data atom header */ +
1743 8 /*flags + reserved */ + strlen(value));
1744 membuffer_write_atom_name(buf, "data");
1745 membuffer_write_int32(buf, 1); //flags
1746 membuffer_write_int32(buf, 0); //reserved
1747 membuffer_write(buf, value, strlen(value));
1750 static unsigned membuffer_error(const struct membuffer *buf)
1755 static void membuffer_free(struct membuffer *buf)
1761 static unsigned membuffer_get_size(const struct membuffer *buf)
1763 return buf->written;
1766 static void *membuffer_detach(struct membuffer *buf)
1772 ret = para_realloc(buf->data, buf->written);
1778 static uint32_t create_ilst(const struct mp4_metadata *data, void **out_buffer,
1779 uint32_t * out_size)
1781 struct membuffer *buf = membuffer_create();
1783 char *mask = para_calloc(data->count);
1784 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1785 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1786 const char *genre_ptr = 0, *tempo_ptr = 0;
1788 for (metaptr = 0; metaptr < data->count; metaptr++) {
1789 struct mp4_tag *tag = &data->tags[metaptr];
1790 if (!strcasecmp(tag->item, "tracknumber")
1791 || !strcasecmp(tag->item, "track")) {
1792 if (tracknumber_ptr == 0)
1793 tracknumber_ptr = tag->value;
1795 } else if (!strcasecmp(tag->item, "totaltracks")) {
1796 if (totaltracks_ptr == 0)
1797 totaltracks_ptr = tag->value;
1799 } else if (!strcasecmp(tag->item, "discnumber")
1800 || !strcasecmp(tag->item, "disc")) {
1801 if (discnumber_ptr == 0)
1802 discnumber_ptr = tag->value;
1804 } else if (!strcasecmp(tag->item, "totaldiscs")) {
1805 if (totaldiscs_ptr == 0)
1806 totaldiscs_ptr = tag->value;
1808 } else if (!strcasecmp(tag->item, "genre")) {
1810 genre_ptr = tag->value;
1812 } else if (!strcasecmp(tag->item, "tempo")) {
1814 tempo_ptr = tag->value;
1819 if (tracknumber_ptr)
1820 membuffer_write_track_tag(buf, "trkn", myatoi(tracknumber_ptr),
1821 myatoi(totaltracks_ptr));
1823 membuffer_write_track_tag(buf, "disk", myatoi(discnumber_ptr),
1824 myatoi(totaldiscs_ptr));
1826 membuffer_write_int16_tag(buf, "tmpo", myatoi(tempo_ptr));
1829 uint32_t index = meta_genre_to_index(genre_ptr);
1831 membuffer_write_std_tag(buf, "©gen", genre_ptr);
1833 membuffer_write_int16_tag(buf, "gnre", index);
1835 for (metaptr = 0; metaptr < data->count; metaptr++) {
1836 struct mp4_tag *tag;
1837 const char *std_meta_atom;
1841 tag = &data->tags[metaptr];
1842 std_meta_atom = find_standard_meta(tag->item);
1844 membuffer_write_std_tag(buf, std_meta_atom, tag->value);
1846 membuffer_write_custom_tag(buf, tag->item, tag->value);
1850 if (membuffer_error(buf)) {
1851 membuffer_free(buf);
1855 *out_size = membuffer_get_size(buf);
1856 *out_buffer = membuffer_detach(buf);
1857 membuffer_free(buf);
1862 static void membuffer_write_atom(struct membuffer *buf, const char *name, unsigned size,
1865 membuffer_write_int32(buf, size + 8);
1866 membuffer_write_atom_name(buf, name);
1867 membuffer_write(buf, data, size);
1870 static void *membuffer_get_ptr(const struct membuffer *buf)
1875 static void membuffer_set_error(struct membuffer *buf)
1880 static unsigned membuffer_transfer_from_file(struct membuffer *buf, struct mp4 *src,
1886 oldsize = membuffer_get_size(buf);
1887 if (membuffer_write(buf, 0, bytes) != bytes)
1890 bufptr = membuffer_get_ptr(buf);
1894 if ((unsigned)read_data(src, (char *) bufptr + oldsize, bytes) !=
1896 membuffer_set_error(buf);
1903 static uint32_t create_meta(const struct mp4_metadata *data, void **out_buffer,
1904 uint32_t * out_size)
1906 struct membuffer *buf;
1910 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1913 buf = membuffer_create();
1915 membuffer_write_int32(buf, 0);
1916 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1919 *out_size = membuffer_get_size(buf);
1920 *out_buffer = membuffer_detach(buf);
1921 membuffer_free(buf);
1925 static uint32_t create_udta(const struct mp4_metadata *data, void **out_buffer,
1926 uint32_t * out_size)
1928 struct membuffer *buf;
1932 if (!create_meta(data, &meta_buffer, &meta_size))
1935 buf = membuffer_create();
1937 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1941 *out_size = membuffer_get_size(buf);
1942 *out_buffer = membuffer_detach(buf);
1943 membuffer_free(buf);
1947 static uint32_t fix_byte_order_32(uint32_t src)
1949 return read_u32_be(&src);
1952 static uint32_t modify_moov(struct mp4 *f, const struct mp4_metadata *data,
1953 void **out_buffer, uint32_t * out_size)
1955 uint64_t total_base = f->moov_offset + 8;
1956 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1958 uint64_t udta_offset, meta_offset, ilst_offset;
1959 uint32_t udta_size, meta_size, ilst_size;
1961 uint32_t new_ilst_size;
1962 void *new_ilst_buffer;
1967 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1968 struct membuffer *buf;
1969 void *new_udta_buffer;
1970 uint32_t new_udta_size;
1971 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1974 buf = membuffer_create();
1975 set_position(f, total_base);
1976 membuffer_transfer_from_file(buf, f, total_size);
1978 membuffer_write_atom(buf, "udta", new_udta_size,
1981 free(new_udta_buffer);
1983 *out_size = membuffer_get_size(buf);
1984 *out_buffer = membuffer_detach(buf);
1985 membuffer_free(buf);
1988 udta_offset = get_position(f);
1989 udta_size = read_int32(f);
1990 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
1991 struct membuffer *buf;
1992 void *new_meta_buffer;
1993 uint32_t new_meta_size;
1994 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
1997 buf = membuffer_create();
1998 set_position(f, total_base);
1999 membuffer_transfer_from_file(buf, f,
2000 (uint32_t)(udta_offset - total_base));
2002 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2003 membuffer_write_atom_name(buf, "udta");
2004 membuffer_transfer_from_file(buf, f, udta_size);
2006 membuffer_write_atom(buf, "meta", new_meta_size,
2008 free(new_meta_buffer);
2010 *out_size = membuffer_get_size(buf);
2011 *out_buffer = membuffer_detach(buf);
2012 membuffer_free(buf);
2015 meta_offset = get_position(f);
2016 meta_size = read_int32(f);
2017 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2018 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2019 ilst_offset = get_position(f);
2020 ilst_size = read_int32(f);
2022 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2025 size_delta = new_ilst_size - (ilst_size - 8);
2027 *out_size = total_size + size_delta;
2028 *out_buffer = para_malloc(*out_size);
2029 p_out = (uint8_t *) * out_buffer;
2031 set_position(f, total_base);
2033 (uint32_t) (udta_offset - total_base));
2034 p_out += (uint32_t) (udta_offset - total_base);
2035 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2037 read_data(f, p_out, 4);
2040 (uint32_t) (meta_offset - udta_offset - 8));
2041 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2042 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2044 read_data(f, p_out, 4);
2047 (uint32_t) (ilst_offset - meta_offset - 8));
2048 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2049 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2051 read_data(f, p_out, 4);
2054 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2055 p_out += new_ilst_size;
2057 set_position(f, ilst_offset + ilst_size);
2058 read_data(f, p_out, (uint32_t) (total_size
2059 - (ilst_offset - total_base) - ilst_size));
2061 free(new_ilst_buffer);
2066 static int32_t write_data(struct mp4 *f, void *data, uint32_t size)
2070 result = f->stream->write(f->stream->user_data, data, size);
2072 f->current_position += size;
2077 static int32_t write_int32(struct mp4 *f, uint32_t data)
2080 write_u32_be(temp, data);
2081 return write_data(f, temp, sizeof(temp));
2084 static int32_t truncate_stream(struct mp4 *f)
2086 return f->stream->truncate(f->stream->user_data);
2089 int32_t mp4_meta_update(struct mp4_callback *f, const struct mp4_metadata *data)
2091 void *new_moov_data;
2092 uint32_t new_moov_size;
2094 struct mp4 *ff = para_calloc(sizeof(struct mp4));
2096 set_position(ff, 0);
2100 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2105 /* copy moov atom to end of the file */
2106 if (ff->last_atom != ATOM_MOOV) {
2107 char *free_data = "free";
2109 /* rename old moov to free */
2110 set_position(ff, ff->moov_offset + 4);
2111 write_data(ff, free_data, 4);
2113 set_position(ff, ff->file_size);
2114 write_int32(ff, new_moov_size + 8);
2115 write_data(ff, "moov", 4);
2116 write_data(ff, new_moov_data, new_moov_size);
2118 set_position(ff, ff->moov_offset);
2119 write_int32(ff, new_moov_size + 8);
2120 write_data(ff, "moov", 4);
2121 write_data(ff, new_moov_data, new_moov_size);
2124 truncate_stream(ff);
2130 /* find a metadata item by name */
2131 /* returns 0 if item found, 1 if no such item */
2132 static int32_t meta_find_by_name(const struct mp4 *f, const char *item,
2137 for (i = 0; i < f->tags.count; i++) {
2138 if (!strcasecmp(f->tags.tags[i].item, item)) {
2139 *value = para_strdup(f->tags.tags[i].value);
2150 int32_t mp4_meta_get_artist(const struct mp4 *f, char **value)
2152 return meta_find_by_name(f, "artist", value);
2155 int32_t mp4_meta_get_title(const struct mp4 *f, char **value)
2157 return meta_find_by_name(f, "title", value);
2160 int32_t mp4_meta_get_date(const struct mp4 *f, char **value)
2162 return meta_find_by_name(f, "date", value);
2165 int32_t mp4_meta_get_album(const struct mp4 *f, char **value)
2167 return meta_find_by_name(f, "album", value);
2170 int32_t mp4_meta_get_comment(const struct mp4 *f, char **value)
2172 return meta_find_by_name(f, "comment", value);