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 struct mp4 *mp4_open_read(struct mp4_callback *f)
1240 struct mp4 *ff = para_calloc(sizeof(struct mp4));
1254 static int32_t tag_delete(struct mp4_metadata *tags)
1258 for (i = 0; i < tags->count; i++) {
1259 free(tags->tags[i].item);
1260 free(tags->tags[i].value);
1269 void mp4_close(struct mp4 *ff)
1273 for (i = 0; i < ff->total_tracks; i++) {
1275 free(ff->track[i]->stsz_table);
1276 free(ff->track[i]->stts_sample_count);
1277 free(ff->track[i]->stts_sample_delta);
1278 free(ff->track[i]->stsc_first_chunk);
1279 free(ff->track[i]->stsc_samples_per_chunk);
1280 free(ff->track[i]->stsc_sample_desc_index);
1281 free(ff->track[i]->stco_chunk_offset);
1282 free(ff->track[i]->decoderConfig);
1283 free(ff->track[i]->ctts_sample_count);
1284 free(ff->track[i]->ctts_sample_offset);
1289 tag_delete(&(ff->tags));
1293 static int32_t chunk_of_sample(const struct mp4 *f, int32_t track,
1294 int32_t sample, int32_t *chunk_sample, int32_t *chunk)
1296 int32_t total_entries = 0;
1297 int32_t chunk2entry;
1298 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1302 if (f->track[track] == NULL) {
1306 total_entries = f->track[track]->stsc_entry_count;
1313 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1314 *chunk = chunk2 - chunk1;
1315 range_samples = *chunk * chunk1samples;
1317 if (sample < total + range_samples)
1320 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1323 if (chunk2entry < total_entries) {
1325 total += range_samples;
1327 } while (chunk2entry < total_entries);
1330 *chunk = (sample - total) / chunk1samples + chunk1;
1334 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1339 static int32_t chunk_to_offset(const struct mp4 *f, int32_t track,
1342 const struct mp4_track *p_track = f->track[track];
1344 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1345 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1347 } else if (p_track->stco_entry_count) {
1348 return p_track->stco_chunk_offset[chunk - 1];
1356 static int32_t sample_range_size(const struct mp4 *f, int32_t track,
1357 int32_t chunk_sample, int32_t sample)
1360 const struct mp4_track *p_track = f->track[track];
1362 if (p_track->stsz_sample_size) {
1363 return (sample - chunk_sample) * p_track->stsz_sample_size;
1365 if (sample >= p_track->stsz_sample_count)
1368 for (i = chunk_sample, total = 0; i < sample; i++) {
1369 total += p_track->stsz_table[i];
1376 static int32_t sample_to_offset(const struct mp4 *f, int32_t track,
1379 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1381 chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1383 chunk_offset1 = chunk_to_offset(f, track, chunk);
1384 chunk_offset2 = chunk_offset1 + sample_range_size(f,
1385 track, chunk_sample, sample);
1386 return chunk_offset2;
1390 * Return the number of milliseconds of the given track.
1392 * \param f As returned by \ref mp4_open_read(), must not be NULL.
1393 * \param track Between zero and the value returned by \ref mp4_total_tracks().
1395 * The function returns zero if the audio file is of zero length or contains a
1396 * corrupt track header.
1398 uint64_t mp4_get_duration(const struct mp4 *f, int32_t track)
1400 const struct mp4_track *t = f->track[track];
1402 if (t->timeScale == 0)
1404 return t->duration * 1000 / t->timeScale;
1408 * Check whether the given track number corresponds to an audio track.
1410 * \param f See \ref mp4_get_duration().
1411 * \param track See \ref mp4_get_duration().
1413 * Besides audio tracks, an mp4 file may contain video and system tracks. For
1414 * those the function returns false.
1416 bool mp4_is_audio_track(const struct mp4 *f, int32_t track)
1418 return f->track[track]->type == TRACK_AUDIO;
1421 void mp4_set_sample_position(struct mp4 *f, int32_t track, int32_t sample)
1423 int32_t offset = sample_to_offset(f, track, sample);
1424 set_position(f, offset);
1427 int32_t mp4_get_sample_size(const struct mp4 *f, int track, int sample)
1429 const struct mp4_track *t = f->track[track];
1431 if (t->stsz_sample_size != 0)
1432 return t->stsz_sample_size;
1433 return t->stsz_table[sample];
1436 uint32_t mp4_get_sample_rate(const struct mp4 *f, int32_t track)
1438 return f->track[track]->sampleRate;
1441 uint32_t mp4_get_channel_count(const struct mp4 *f, int32_t track)
1443 return f->track[track]->channelCount;
1446 int32_t mp4_num_samples(const struct mp4 *f, int32_t track)
1451 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1452 total += f->track[track]->stts_sample_count[i];
1457 struct mp4 *mp4_open_meta(struct mp4_callback *f)
1459 struct mp4 *ff = para_calloc(sizeof(struct mp4));
1473 int32_t mp4_meta_get_num_items(const struct mp4 *f)
1475 return f->tags.count;
1478 int32_t mp4_meta_get_by_index(const struct mp4 *f, uint32_t index,
1479 char **item, char **value)
1481 if (index >= f->tags.count) {
1486 *item = para_strdup(f->tags.tags[index].item);
1487 *value = para_strdup(f->tags.tags[index].value);
1492 static uint32_t find_atom(struct mp4 *f, uint64_t base, uint32_t size,
1495 uint32_t remaining = size;
1496 uint64_t atom_offset = base;
1501 set_position(f, atom_offset);
1505 atom_size = read_int32(f);
1506 if (atom_size > remaining || atom_size < 8)
1508 read_data(f, atom_name, 4);
1510 if (!memcmp(atom_name, name, 4)) {
1511 set_position(f, atom_offset);
1515 remaining -= atom_size;
1516 atom_offset += atom_size;
1521 static uint32_t find_atom_v2(struct mp4 *f, uint64_t base, uint32_t size,
1522 const char *name, uint32_t extraheaders, const char *name_inside)
1524 uint64_t first_base = (uint64_t) (-1);
1525 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1527 uint64_t mybase = get_position(f);
1528 uint32_t mysize = read_int32(f);
1530 if (first_base == (uint64_t) (-1))
1531 first_base = mybase;
1533 if (mysize < 8 + extraheaders)
1536 if (find_atom (f, mybase + (8 + extraheaders),
1537 mysize - (8 + extraheaders), name_inside)) {
1538 set_position(f, mybase);
1542 if (size <= mysize) {
1549 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1551 set_position(f, first_base);
1564 static struct membuffer *membuffer_create(void)
1566 const unsigned initial_size = 256;
1568 struct membuffer *buf = para_malloc(sizeof(*buf));
1569 buf->data = para_malloc(initial_size);
1571 buf->allocated = initial_size;
1572 buf->error = buf->data == 0 ? 1 : 0;
1577 static unsigned membuffer_write(struct membuffer *buf, const void *ptr, unsigned bytes)
1579 unsigned dest_size = buf->written + bytes;
1583 if (dest_size > buf->allocated) {
1585 buf->allocated <<= 1;
1586 } while (dest_size > buf->allocated);
1587 buf->data = para_realloc(buf->data, buf->allocated);
1591 memcpy((char *) buf->data + buf->written, ptr, bytes);
1592 buf->written += bytes;
1596 static unsigned membuffer_write_atom_name(struct membuffer *buf, const char *data)
1598 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1601 static unsigned membuffer_write_int16(struct membuffer *buf, uint16_t data)
1605 write_u16_be(temp, data);
1606 return membuffer_write(buf, temp, 2);
1609 static unsigned membuffer_write_int32(struct membuffer *buf, uint32_t data)
1612 write_u32_be(temp, data);
1613 return membuffer_write(buf, temp, 4);
1616 static void membuffer_write_track_tag(struct membuffer *buf, const char *name,
1617 uint32_t index, uint32_t total)
1619 membuffer_write_int32(buf,
1620 8 /*atom header */ + 8 /*data atom header */ +
1621 8 /*flags + reserved */ + 8 /*actual data */ );
1622 membuffer_write_atom_name(buf, name);
1623 membuffer_write_int32(buf,
1624 8 /*data atom header */ +
1625 8 /*flags + reserved */ + 8 /*actual data */ );
1626 membuffer_write_atom_name(buf, "data");
1627 membuffer_write_int32(buf, 0); //flags
1628 membuffer_write_int32(buf, 0); //reserved
1629 membuffer_write_int16(buf, 0);
1630 membuffer_write_int16(buf, (uint16_t) index); //track number
1631 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1632 membuffer_write_int16(buf, 0);
1635 static void membuffer_write_int16_tag(struct membuffer *buf, const char *name,
1638 membuffer_write_int32(buf,
1639 8 /*atom header */ + 8 /*data atom header */ +
1640 8 /*flags + reserved */ + 2 /*actual data */ );
1641 membuffer_write_atom_name(buf, name);
1642 membuffer_write_int32(buf,
1643 8 /*data atom header */ +
1644 8 /*flags + reserved */ + 2 /*actual data */ );
1645 membuffer_write_atom_name(buf, "data");
1646 membuffer_write_int32(buf, 0); //flags
1647 membuffer_write_int32(buf, 0); //reserved
1648 membuffer_write_int16(buf, value); //value
1651 static uint32_t myatoi(const char *param)
1653 return param ? atoi(param) : 0;
1656 static uint32_t meta_genre_to_index(const char *genrestr)
1659 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1660 if (!strcasecmp(genrestr, ID3v1GenreList[n]))
1666 struct stdmeta_entry {
1671 struct stdmeta_entry stdmetas[] = {
1672 {"\xA9" "nam", "title"},
1673 {"\xA9" "ART", "artist"},
1674 {"\xA9" "wrt", "writer"},
1675 {"\xA9" "alb", "album"},
1676 {"\xA9" "day", "date"},
1677 {"\xA9" "too", "tool"},
1678 {"\xA9" "cmt", "comment"},
1679 {"cpil", "compilation"},
1681 {"aART", "album_artist"},
1684 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1687 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1688 if (!strcasecmp(name, stdmetas[n].name))
1689 return stdmetas[n].atom;
1694 static void membuffer_write_std_tag(struct membuffer *buf, const char *name,
1699 /* special check for compilation flag */
1700 if (strcmp(name, "cpil") == 0) {
1704 membuffer_write_int32(buf,
1705 8 /*atom header */ + 8 /*data atom header */ +
1706 8 /*flags + reserved */ + strlen(value));
1707 membuffer_write_atom_name(buf, name);
1708 membuffer_write_int32(buf,
1709 8 /*data atom header */ +
1710 8 /*flags + reserved */ + strlen(value));
1711 membuffer_write_atom_name(buf, "data");
1712 membuffer_write_int32(buf, flags); //flags
1713 membuffer_write_int32(buf, 0); //reserved
1714 membuffer_write(buf, value, strlen(value));
1717 static void membuffer_write_custom_tag(struct membuffer *buf, const char *name,
1720 membuffer_write_int32(buf,
1721 8 /*atom header */ +
1722 0x1C /*weirdo itunes atom */ +
1723 12 /*name atom header */ + strlen(name) +
1724 16 /*data atom header + flags */ + strlen(value));
1725 membuffer_write_atom_name(buf, "----");
1726 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1727 membuffer_write_atom_name(buf, "mean");
1728 membuffer_write_int32(buf, 0);
1729 membuffer_write(buf, "com.apple.iTunes", 16);
1730 membuffer_write_int32(buf, 12 + strlen(name));
1731 membuffer_write_atom_name(buf, "name");
1732 membuffer_write_int32(buf, 0);
1733 membuffer_write(buf, name, strlen(name));
1734 membuffer_write_int32(buf,
1735 8 /*data atom header */ +
1736 8 /*flags + reserved */ + strlen(value));
1737 membuffer_write_atom_name(buf, "data");
1738 membuffer_write_int32(buf, 1); //flags
1739 membuffer_write_int32(buf, 0); //reserved
1740 membuffer_write(buf, value, strlen(value));
1743 static unsigned membuffer_error(const struct membuffer *buf)
1748 static void membuffer_free(struct membuffer *buf)
1754 static unsigned membuffer_get_size(const struct membuffer *buf)
1756 return buf->written;
1759 static void *membuffer_detach(struct membuffer *buf)
1765 ret = para_realloc(buf->data, buf->written);
1771 static uint32_t create_ilst(const struct mp4_metadata *data, void **out_buffer,
1772 uint32_t * out_size)
1774 struct membuffer *buf = membuffer_create();
1776 char *mask = para_calloc(data->count);
1777 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1778 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1779 const char *genre_ptr = 0, *tempo_ptr = 0;
1781 for (metaptr = 0; metaptr < data->count; metaptr++) {
1782 struct mp4_tag *tag = &data->tags[metaptr];
1783 if (!strcasecmp(tag->item, "tracknumber")
1784 || !strcasecmp(tag->item, "track")) {
1785 if (tracknumber_ptr == 0)
1786 tracknumber_ptr = tag->value;
1788 } else if (!strcasecmp(tag->item, "totaltracks")) {
1789 if (totaltracks_ptr == 0)
1790 totaltracks_ptr = tag->value;
1792 } else if (!strcasecmp(tag->item, "discnumber")
1793 || !strcasecmp(tag->item, "disc")) {
1794 if (discnumber_ptr == 0)
1795 discnumber_ptr = tag->value;
1797 } else if (!strcasecmp(tag->item, "totaldiscs")) {
1798 if (totaldiscs_ptr == 0)
1799 totaldiscs_ptr = tag->value;
1801 } else if (!strcasecmp(tag->item, "genre")) {
1803 genre_ptr = tag->value;
1805 } else if (!strcasecmp(tag->item, "tempo")) {
1807 tempo_ptr = tag->value;
1812 if (tracknumber_ptr)
1813 membuffer_write_track_tag(buf, "trkn", myatoi(tracknumber_ptr),
1814 myatoi(totaltracks_ptr));
1816 membuffer_write_track_tag(buf, "disk", myatoi(discnumber_ptr),
1817 myatoi(totaldiscs_ptr));
1819 membuffer_write_int16_tag(buf, "tmpo", myatoi(tempo_ptr));
1822 uint32_t index = meta_genre_to_index(genre_ptr);
1824 membuffer_write_std_tag(buf, "©gen", genre_ptr);
1826 membuffer_write_int16_tag(buf, "gnre", index);
1828 for (metaptr = 0; metaptr < data->count; metaptr++) {
1829 struct mp4_tag *tag;
1830 const char *std_meta_atom;
1834 tag = &data->tags[metaptr];
1835 std_meta_atom = find_standard_meta(tag->item);
1837 membuffer_write_std_tag(buf, std_meta_atom, tag->value);
1839 membuffer_write_custom_tag(buf, tag->item, tag->value);
1843 if (membuffer_error(buf)) {
1844 membuffer_free(buf);
1848 *out_size = membuffer_get_size(buf);
1849 *out_buffer = membuffer_detach(buf);
1850 membuffer_free(buf);
1855 static void membuffer_write_atom(struct membuffer *buf, const char *name, unsigned size,
1858 membuffer_write_int32(buf, size + 8);
1859 membuffer_write_atom_name(buf, name);
1860 membuffer_write(buf, data, size);
1863 static void *membuffer_get_ptr(const struct membuffer *buf)
1868 static void membuffer_set_error(struct membuffer *buf)
1873 static unsigned membuffer_transfer_from_file(struct membuffer *buf, struct mp4 *src,
1879 oldsize = membuffer_get_size(buf);
1880 if (membuffer_write(buf, 0, bytes) != bytes)
1883 bufptr = membuffer_get_ptr(buf);
1887 if ((unsigned)read_data(src, (char *) bufptr + oldsize, bytes) !=
1889 membuffer_set_error(buf);
1896 static uint32_t create_meta(const struct mp4_metadata *data, void **out_buffer,
1897 uint32_t * out_size)
1899 struct membuffer *buf;
1903 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1906 buf = membuffer_create();
1908 membuffer_write_int32(buf, 0);
1909 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1912 *out_size = membuffer_get_size(buf);
1913 *out_buffer = membuffer_detach(buf);
1914 membuffer_free(buf);
1918 static uint32_t create_udta(const struct mp4_metadata *data, void **out_buffer,
1919 uint32_t * out_size)
1921 struct membuffer *buf;
1925 if (!create_meta(data, &meta_buffer, &meta_size))
1928 buf = membuffer_create();
1930 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1934 *out_size = membuffer_get_size(buf);
1935 *out_buffer = membuffer_detach(buf);
1936 membuffer_free(buf);
1940 static uint32_t fix_byte_order_32(uint32_t src)
1942 return read_u32_be(&src);
1945 static uint32_t modify_moov(struct mp4 *f, const struct mp4_metadata *data,
1946 void **out_buffer, uint32_t * out_size)
1948 uint64_t total_base = f->moov_offset + 8;
1949 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1951 uint64_t udta_offset, meta_offset, ilst_offset;
1952 uint32_t udta_size, meta_size, ilst_size;
1954 uint32_t new_ilst_size;
1955 void *new_ilst_buffer;
1960 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1961 struct membuffer *buf;
1962 void *new_udta_buffer;
1963 uint32_t new_udta_size;
1964 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1967 buf = membuffer_create();
1968 set_position(f, total_base);
1969 membuffer_transfer_from_file(buf, f, total_size);
1971 membuffer_write_atom(buf, "udta", new_udta_size,
1974 free(new_udta_buffer);
1976 *out_size = membuffer_get_size(buf);
1977 *out_buffer = membuffer_detach(buf);
1978 membuffer_free(buf);
1981 udta_offset = get_position(f);
1982 udta_size = read_int32(f);
1983 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
1984 struct membuffer *buf;
1985 void *new_meta_buffer;
1986 uint32_t new_meta_size;
1987 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
1990 buf = membuffer_create();
1991 set_position(f, total_base);
1992 membuffer_transfer_from_file(buf, f,
1993 (uint32_t)(udta_offset - total_base));
1995 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
1996 membuffer_write_atom_name(buf, "udta");
1997 membuffer_transfer_from_file(buf, f, udta_size);
1999 membuffer_write_atom(buf, "meta", new_meta_size,
2001 free(new_meta_buffer);
2003 *out_size = membuffer_get_size(buf);
2004 *out_buffer = membuffer_detach(buf);
2005 membuffer_free(buf);
2008 meta_offset = get_position(f);
2009 meta_size = read_int32(f);
2010 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2011 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2012 ilst_offset = get_position(f);
2013 ilst_size = read_int32(f);
2015 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2018 size_delta = new_ilst_size - (ilst_size - 8);
2020 *out_size = total_size + size_delta;
2021 *out_buffer = para_malloc(*out_size);
2022 p_out = (uint8_t *) * out_buffer;
2024 set_position(f, total_base);
2026 (uint32_t) (udta_offset - total_base));
2027 p_out += (uint32_t) (udta_offset - total_base);
2028 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2030 read_data(f, p_out, 4);
2033 (uint32_t) (meta_offset - udta_offset - 8));
2034 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2035 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2037 read_data(f, p_out, 4);
2040 (uint32_t) (ilst_offset - meta_offset - 8));
2041 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2042 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2044 read_data(f, p_out, 4);
2047 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2048 p_out += new_ilst_size;
2050 set_position(f, ilst_offset + ilst_size);
2051 read_data(f, p_out, (uint32_t) (total_size
2052 - (ilst_offset - total_base) - ilst_size));
2054 free(new_ilst_buffer);
2059 static int32_t write_data(struct mp4 *f, void *data, uint32_t size)
2063 result = f->stream->write(f->stream->user_data, data, size);
2065 f->current_position += size;
2070 static int32_t write_int32(struct mp4 *f, uint32_t data)
2073 write_u32_be(temp, data);
2074 return write_data(f, temp, sizeof(temp));
2077 static int32_t truncate_stream(struct mp4 *f)
2079 return f->stream->truncate(f->stream->user_data);
2082 int32_t mp4_meta_update(struct mp4_callback *f, const struct mp4_metadata *data)
2084 void *new_moov_data;
2085 uint32_t new_moov_size;
2087 struct mp4 *ff = para_calloc(sizeof(struct mp4));
2089 set_position(ff, 0);
2093 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2098 /* copy moov atom to end of the file */
2099 if (ff->last_atom != ATOM_MOOV) {
2100 char *free_data = "free";
2102 /* rename old moov to free */
2103 set_position(ff, ff->moov_offset + 4);
2104 write_data(ff, free_data, 4);
2106 set_position(ff, ff->file_size);
2107 write_int32(ff, new_moov_size + 8);
2108 write_data(ff, "moov", 4);
2109 write_data(ff, new_moov_data, new_moov_size);
2111 set_position(ff, ff->moov_offset);
2112 write_int32(ff, new_moov_size + 8);
2113 write_data(ff, "moov", 4);
2114 write_data(ff, new_moov_data, new_moov_size);
2117 truncate_stream(ff);
2123 /* find a metadata item by name */
2124 /* returns 0 if item found, 1 if no such item */
2125 static int32_t meta_find_by_name(const struct mp4 *f, const char *item,
2130 for (i = 0; i < f->tags.count; i++) {
2131 if (!strcasecmp(f->tags.tags[i].item, item)) {
2132 *value = para_strdup(f->tags.tags[i].value);
2143 int32_t mp4_meta_get_artist(const struct mp4 *f, char **value)
2145 return meta_find_by_name(f, "artist", value);
2148 int32_t mp4_meta_get_title(const struct mp4 *f, char **value)
2150 return meta_find_by_name(f, "title", value);
2153 int32_t mp4_meta_get_date(const struct mp4 *f, char **value)
2155 return meta_find_by_name(f, "date", value);
2158 int32_t mp4_meta_get_album(const struct mp4 *f, char **value)
2160 return meta_find_by_name(f, "album", value);
2163 int32_t mp4_meta_get_comment(const struct mp4 *f, char **value)
2165 return meta_find_by_name(f, "comment", value);