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"
15 int32_t mp4ff_total_tracks(const mp4ff_t * f)
17 return f->total_tracks;
20 static int32_t read_data(mp4ff_t * f, void *data, uint32_t size)
24 result = f->stream->read(f->stream->user_data, data, size);
27 f->stream->read_error++;
29 f->current_position += size;
34 static uint64_t read_int64(mp4ff_t * f)
38 read_data(f, data, 8);
39 return read_u64_be(data);
42 /* comnapre 2 atom names, returns 1 for equal, 0 for unequal */
43 static int32_t atom_compare(const int8_t a1, const int8_t b1,
44 const int8_t c1, const int8_t d1,
45 const int8_t a2, const int8_t b2,
46 const int8_t c2, const int8_t d2)
48 if (a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2)
62 /* atoms with subatoms */
70 ATOM_ILST = 8, /* iTunes Metadata list */
81 ATOM_COMPILATION = 19,
91 /* atoms without subatoms */
111 ATOM_META = 148, /* iTunes Metadata box */
112 ATOM_NAME = 149, /* iTunes Metadata name box */
113 ATOM_DATA = 150, /* iTunes Metadata data box */
120 ATOM_ALBUM_ARTIST = 157,
121 ATOM_CONTENTGROUP = 158,
123 ATOM_DESCRIPTION = 160,
126 ATOM_EPISODENAME = 163,
127 ATOM_SORTTITLE = 164,
128 ATOM_SORTALBUM = 165,
129 ATOM_SORTARTIST = 166,
130 ATOM_SORTALBUMARTIST = 167,
131 ATOM_SORTWRITER = 168,
140 #define ATOM_FREE ATOM_UNKNOWN
141 #define ATOM_SKIP ATOM_UNKNOWN
143 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
145 static uint8_t atom_name_to_type(const int8_t a, const int8_t b,
146 const int8_t c, const int8_t d)
149 if (atom_compare(a, b, c, d, 'm', 'o', 'o', 'v'))
151 else if (atom_compare(a, b, c, d, 'm', 'i', 'n', 'f'))
153 else if (atom_compare(a, b, c, d, 'm', 'd', 'i', 'a'))
155 else if (atom_compare(a, b, c, d, 'm', 'd', 'a', 't'))
157 else if (atom_compare(a, b, c, d, 'm', 'd', 'h', 'd'))
159 else if (atom_compare(a, b, c, d, 'm', 'v', 'h', 'd'))
161 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'a'))
163 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'v'))
165 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 's'))
167 else if (atom_compare(a, b, c, d, 'm', 'e', 't', 'a'))
169 } else if (a == 't') {
170 if (atom_compare(a, b, c, d, 't', 'r', 'a', 'k'))
172 else if (atom_compare(a, b, c, d, 't', 'k', 'h', 'd'))
174 else if (atom_compare(a, b, c, d, 't', 'r', 'e', 'f'))
176 else if (atom_compare(a, b, c, d, 't', 'r', 'k', 'n'))
178 else if (atom_compare(a, b, c, d, 't', 'm', 'p', 'o'))
180 else if (atom_compare(a, b, c, d, 't', 'v', 'n', 'n'))
182 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'h'))
184 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 'n'))
185 return ATOM_EPISODENAME;
186 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'n'))
188 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 's'))
190 } else if (a == 's') {
191 if (atom_compare(a, b, c, d, 's', 't', 'b', 'l'))
193 else if (atom_compare(a, b, c, d, 's', 'm', 'h', 'd'))
195 else if (atom_compare(a, b, c, d, 's', 't', 's', 'd'))
197 else if (atom_compare(a, b, c, d, 's', 't', 't', 's'))
199 else if (atom_compare(a, b, c, d, 's', 't', 'c', 'o'))
201 else if (atom_compare(a, b, c, d, 's', 't', 's', 'c'))
203 else if (atom_compare(a, b, c, d, 's', 't', 's', 'z'))
205 else if (atom_compare(a, b, c, d, 's', 't', 'z', '2'))
207 else if (atom_compare(a, b, c, d, 's', 'k', 'i', 'p'))
209 else if (atom_compare(a, b, c, d, 's', 'i', 'n', 'f'))
211 else if (atom_compare(a, b, c, d, 's', 'c', 'h', 'i'))
213 else if (atom_compare(a, b, c, d, 's', 'o', 'n', 'm'))
214 return ATOM_SORTTITLE;
215 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'l'))
216 return ATOM_SORTALBUM;
217 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'r'))
218 return ATOM_SORTARTIST;
219 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'a'))
220 return ATOM_SORTALBUMARTIST;
221 else if (atom_compare(a, b, c, d, 's', 'o', 'c', 'o'))
222 return ATOM_SORTWRITER;
223 else if (atom_compare(a, b, c, d, 's', 'o', 's', 'n'))
224 return ATOM_SORTSHOW;
225 } else if (a == COPYRIGHT_SYMBOL) {
226 if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'n', 'a', 'm'))
228 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'A', 'R', 'T'))
230 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'w', 'r', 't'))
232 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'a', 'l', 'b'))
234 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'd', 'a', 'y'))
236 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 't', 'o', 'o'))
238 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'c', 'm', 't'))
240 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'e', 'n'))
242 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'r', 'p'))
243 return ATOM_CONTENTGROUP;
244 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'l', 'y', 'r'))
248 if (atom_compare(a, b, c, d, 'e', 'd', 't', 's'))
250 else if (atom_compare(a, b, c, d, 'e', 's', 'd', 's'))
252 else if (atom_compare(a, b, c, d, 'f', 't', 'y', 'p'))
254 else if (atom_compare(a, b, c, d, 'f', 'r', 'e', 'e'))
256 else if (atom_compare(a, b, c, d, 'h', 'm', 'h', 'd'))
258 else if (atom_compare(a, b, c, d, 'v', 'm', 'h', 'd'))
260 else if (atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
262 else if (atom_compare(a, b, c, d, 'i', 'l', 's', 't'))
264 else if (atom_compare(a, b, c, d, 'n', 'a', 'm', 'e'))
266 else if (atom_compare(a, b, c, d, 'd', 'a', 't', 'a'))
268 else if (atom_compare(a, b, c, d, 'd', 'i', 's', 'k'))
270 else if (atom_compare(a, b, c, d, 'g', 'n', 'r', 'e'))
272 else if (atom_compare(a, b, c, d, 'c', 'o', 'v', 'r'))
274 else if (atom_compare(a, b, c, d, 'c', 'p', 'i', 'l'))
275 return ATOM_COMPILATION;
276 else if (atom_compare(a, b, c, d, 'c', 't', 't', 's'))
278 else if (atom_compare(a, b, c, d, 'd', 'r', 'm', 's'))
280 else if (atom_compare(a, b, c, d, 'f', 'r', 'm', 'a'))
282 else if (atom_compare(a, b, c, d, 'p', 'r', 'i', 'v'))
284 else if (atom_compare(a, b, c, d, 'i', 'v', 'i', 'v'))
286 else if (atom_compare(a, b, c, d, 'u', 's', 'e', 'r'))
288 else if (atom_compare(a, b, c, d, 'k', 'e', 'y', ' '))
290 else if (atom_compare(a, b, c, d, 'a', 'A', 'R', 'T'))
291 return ATOM_ALBUM_ARTIST;
292 else if (atom_compare(a, b, c, d, 'd', 'e', 's', 'c'))
293 return ATOM_DESCRIPTION;
294 else if (atom_compare(a, b, c, d, 'p', 'c', 's', 't'))
300 /* read atom header, return atom size, atom size is with header included */
301 static uint64_t atom_read_header(mp4ff_t * f, uint8_t * atom_type,
302 uint8_t * header_size)
306 int8_t atom_header[8];
308 ret = read_data(f, atom_header, 8);
312 size = read_u32_be(atom_header);
315 /* check for 64 bit atom size */
318 size = read_int64(f);
320 *atom_type = atom_name_to_type(atom_header[4], atom_header[5],
321 atom_header[6], atom_header[7]);
325 static int64_t get_position(const mp4ff_t * f)
327 return f->current_position;
330 static int need_parse_when_meta_only(uint8_t atom_type)
351 static int32_t set_position(mp4ff_t * f, const int64_t position)
353 f->stream->seek(f->stream->user_data, position);
354 f->current_position = position;
359 static void track_add(mp4ff_t * f)
363 if (f->total_tracks > MAX_TRACKS) {
368 f->track[f->total_tracks - 1] = para_calloc(sizeof (mp4ff_track_t));
371 static uint8_t read_char(mp4ff_t * f)
374 read_data(f, &output, 1);
378 static uint32_t read_int24(mp4ff_t * f)
382 read_data(f, data, 3);
383 return read_u24_be(data);
386 static uint32_t read_int32(mp4ff_t * f)
390 read_data(f, data, 4);
391 return read_u32_be(data);
394 static int32_t read_stsz(mp4ff_t * f)
399 if (f->total_tracks == 0)
401 t = f->track[f->total_tracks - 1];
402 read_char(f); /* version */
403 read_int24(f); /* flags */
404 t->stsz_sample_size = read_int32(f);
405 t->stsz_sample_count = read_int32(f);
406 if (t->stsz_sample_size != 0)
408 t->stsz_table = para_malloc(t->stsz_sample_count * sizeof(int32_t));
409 for (i = 0; i < t->stsz_sample_count && !f->stream->read_error; i++)
410 t->stsz_table[i] = read_int32(f);
414 static int32_t read_stts(mp4ff_t * f)
420 if (f->total_tracks == 0)
422 t = f->track[f->total_tracks - 1];
423 if (t->stts_entry_count)
425 read_char(f); /* version */
426 read_int24(f); /* flags */
427 t->stts_entry_count = read_int32(f);
429 t->stts_sample_count = para_malloc(t->stts_entry_count
431 t->stts_sample_delta = para_malloc(t->stts_entry_count
434 for (i = 0; i < t->stts_entry_count && !f->stream->read_error; i++) {
435 t->stts_sample_count[i] = read_int32(f);
436 t->stts_sample_delta[i] = read_int32(f);
441 static int32_t read_ctts(mp4ff_t * f)
446 if (f->total_tracks == 0)
448 t = f->track[f->total_tracks - 1];
449 if (t->ctts_entry_count)
452 read_char(f); /* version */
453 read_int24(f); /* flags */
454 t->ctts_entry_count = read_int32(f);
456 t->ctts_sample_count = para_malloc(t->ctts_entry_count
458 t->ctts_sample_offset = para_malloc(t->ctts_entry_count
462 for (i = 0; i < t->ctts_entry_count && !f->stream->read_error; i++) {
463 t->ctts_sample_count[i] = read_int32(f);
464 t->ctts_sample_offset[i] = read_int32(f);
469 static int32_t read_stsc(mp4ff_t * f)
474 if (f->total_tracks == 0)
476 t = f->track[f->total_tracks - 1];
478 read_char(f); /* version */
479 read_int24(f); /* flags */
480 t->stsc_entry_count = read_int32(f);
481 t->stsc_first_chunk = para_malloc(t->stsc_entry_count * sizeof(int32_t));
482 t->stsc_samples_per_chunk = para_malloc(t->stsc_entry_count
484 t->stsc_sample_desc_index = para_malloc(t->stsc_entry_count *
488 for (i = 0; i < t->stsc_entry_count && !f->stream->read_error; i++) {
489 t->stsc_first_chunk[i] = read_int32(f);
490 t->stsc_samples_per_chunk[i] = read_int32(f);
491 t->stsc_sample_desc_index[i] = read_int32(f);
496 static int32_t read_stco(mp4ff_t * f)
501 if (f->total_tracks == 0)
503 t = f->track[f->total_tracks - 1];
505 read_char(f); /* version */
506 read_int24(f); /* flags */
507 t->stco_entry_count = read_int32(f);
508 t->stco_chunk_offset = para_malloc(t->stco_entry_count
511 for (i = 0; i < t->stco_entry_count && !f->stream->read_error; i++)
512 t->stco_chunk_offset[i] = read_int32(f);
516 static uint16_t read_int16(mp4ff_t * f)
520 read_data(f, data, 2);
521 return read_u16_be(data);
524 static uint32_t read_mp4_descr_length(mp4ff_t * f)
527 uint8_t numBytes = 0;
533 length = (length << 7) | (b & 0x7F);
534 } while ((b & 0x80) && numBytes < 4);
538 static int32_t read_esds(mp4ff_t * f)
544 if (f->total_tracks == 0)
546 t = f->track[f->total_tracks - 1];
547 read_char(f); /* version */
548 read_int24(f); /* flags */
549 /* get and verify ES_DescrTag */
553 if (read_mp4_descr_length(f) < 5 + 15) {
563 /* get and verify DecoderConfigDescrTab */
564 if (read_char(f) != 0x04) {
569 temp = read_mp4_descr_length(f);
573 t->audioType = read_char(f);
574 read_int32(f); //0x15000414 ????
575 t->maxBitrate = read_int32(f);
576 t->avgBitrate = read_int32(f);
578 /* get and verify DecSpecificInfoTag */
579 if (read_char(f) != 0x05) {
584 t->decoderConfigLen = read_mp4_descr_length(f);
585 free(t->decoderConfig);
586 t->decoderConfig = para_malloc(t->decoderConfigLen);
587 read_data(f, t->decoderConfig, t->decoderConfigLen);
588 /* will skip the remainder of the atom */
592 static int32_t read_mp4a(mp4ff_t * f)
595 uint8_t atom_type = 0;
596 uint8_t header_size = 0;
599 if (f->total_tracks == 0)
601 t = f->track[f->total_tracks - 1];
603 for (i = 0; i < 6; i++) {
604 read_char(f); /* reserved */
606 /* data_reference_index */ read_int16(f);
608 read_int32(f); /* reserved */
609 read_int32(f); /* reserved */
611 t->channelCount = read_int16(f);
612 t->sampleSize = read_int16(f);
617 t->sampleRate = read_int16(f);
621 atom_read_header(f, &atom_type, &header_size);
622 if (atom_type == ATOM_ESDS)
627 static int32_t read_stsd(mp4ff_t * f)
630 uint8_t header_size = 0;
634 if (f->total_tracks == 0)
636 t = f->track[f->total_tracks - 1];
638 read_char(f); /* version */
639 read_int24(f); /* flags */
641 t->stsd_entry_count = read_int32(f);
644 for (i = 0; i < t->stsd_entry_count && !f->stream->read_error; i++) {
645 uint64_t skip = get_position(f);
647 uint8_t atom_type = 0;
648 size = atom_read_header(f, &atom_type, &header_size);
651 if (atom_type == ATOM_MP4A) {
652 t->type = TRACK_AUDIO;
654 } else if (atom_type == ATOM_MP4V) {
655 t->type = TRACK_VIDEO;
656 } else if (atom_type == ATOM_MP4S) {
657 t->type = TRACK_SYSTEM;
659 t->type = TRACK_UNKNOWN;
661 set_position(f, skip);
667 static int32_t read_mvhd(mp4ff_t * f)
671 read_char(f); /* version */
672 read_int24(f); /* flags */
673 /* creation_time */ read_int32(f);
674 /* modification_time */ read_int32(f);
675 f->time_scale = read_int32(f);
676 f->duration = read_int32(f);
677 /* preferred_rate */ read_int32(f);
678 /*mp4ff_read_fixed32(f); */
679 /* preferred_volume */ read_int16(f);
680 /*mp4ff_read_fixed16(f); */
681 for (i = 0; i < 10; i++) {
682 /* reserved */ read_char(f);
684 for (i = 0; i < 9; i++) {
685 read_int32(f); /* matrix */
687 /* preview_time */ read_int32(f);
688 /* preview_duration */ read_int32(f);
689 /* poster_time */ read_int32(f);
690 /* selection_time */ read_int32(f);
691 /* selection_duration */ read_int32(f);
692 /* current_time */ read_int32(f);
693 /* next_track_id */ read_int32(f);
698 static int32_t tag_add_field(mp4ff_metadata_t * tags, const char *item,
699 const char *value, int32_t len)
701 void *backup = (void *) tags->tags;
703 if (!item || (item && !*item) || !value)
706 tags->tags = (mp4ff_tag_t *) realloc(tags->tags,
707 (tags->count + 1) * sizeof (mp4ff_tag_t));
712 tags->tags[tags->count].item = para_strdup(item);
713 tags->tags[tags->count].len = len;
715 tags->tags[tags->count].value = para_malloc(len + 1);
716 memcpy(tags->tags[tags->count].value, value, len);
717 tags->tags[tags->count].value[len] = 0;
719 tags->tags[tags->count].value = para_strdup(value);
726 static const char *ID3v1GenreList[] = {
727 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
728 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
729 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
730 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
731 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
732 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
733 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
734 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
735 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
736 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
737 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
738 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
739 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
740 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
741 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
742 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
743 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
744 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
745 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
746 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
747 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
748 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
749 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
750 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
751 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
752 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
753 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
754 "Anime", "JPop", "SynthPop",
757 static const char *meta_index_to_genre(uint32_t idx)
759 if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
760 return ID3v1GenreList[idx - 1];
766 static char *read_string(mp4ff_t *f, uint32_t length)
768 char *str = para_malloc(length + 1);
769 if ((uint32_t)read_data(f, str, length) != length) {
777 static int32_t set_metadata_name(const uint8_t atom_type, char **name)
779 static char *tag_names[] = {
780 "unknown", "title", "artist", "writer", "album",
781 "date", "tool", "comment", "genre", "track",
782 "disc", "compilation", "genre", "tempo", "cover",
783 "album_artist", "contentgroup", "lyrics", "description",
784 "network", "show", "episodename",
785 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
786 "sortwriter", "sortshow",
787 "season", "episode", "podcast"
822 case ATOM_COMPILATION:
834 case ATOM_ALBUM_ARTIST:
837 case ATOM_CONTENTGROUP:
843 case ATOM_DESCRIPTION:
852 case ATOM_EPISODENAME:
861 case ATOM_SORTARTIST:
864 case ATOM_SORTALBUMARTIST:
867 case ATOM_SORTWRITER:
887 *name = para_strdup(tag_names[tag_idx]);
891 static uint32_t min_body_size(const uint8_t atom_type)
898 return sizeof (char) /* version */
899 + sizeof(uint8_t) * 3 /* flags */
900 + sizeof(uint32_t) /* reserved */
901 + sizeof(uint16_t) /* leading uint16_t */
902 + sizeof(uint16_t) /* track */
903 + sizeof(uint16_t); /* totaltracks */
905 return sizeof (char) /* version */
906 + sizeof(uint8_t) * 3 /* flags */
907 + sizeof(uint32_t) /* reserved */
908 + sizeof(uint16_t) /* disc */
909 + sizeof(uint16_t); /* totaldiscs */
910 default: assert(false);
914 static int32_t parse_tag(mp4ff_t * f, const uint8_t parent,
918 uint8_t header_size = 0;
919 uint64_t subsize, sumsize;
928 sumsize < size && !f->stream->read_error; /* CVE-2017-9222 */
929 set_position(f, destpos), sumsize += subsize
931 subsize = atom_read_header(f, &atom_type, &header_size);
932 destpos = get_position(f) + subsize - header_size;
935 if (atom_type == ATOM_NAME) {
936 read_char(f); /* version */
937 read_int24(f); /* flags */
939 name = read_string(f, subsize - (header_size + 4));
942 if (atom_type != ATOM_DATA)
944 read_char(f); /* version */
945 read_int24(f); /* flags */
946 read_int32(f); /* reserved */
948 /* some need special attention */
949 if (parent == ATOM_GENRE2 || parent == ATOM_TEMPO) {
951 if (subsize - header_size < min_body_size(parent))
954 if (parent == ATOM_TEMPO) {
956 sprintf(temp, "%.5u BPM", val);
957 tag_add_field(&(f-> tags), "tempo",
960 const char *tmp = meta_index_to_genre(val);
962 tag_add_field (&(f->tags),
966 } else if (parent == ATOM_TRACK || parent == ATOM_DISC) {
967 uint16_t index, total;
969 if (subsize - header_size < min_body_size(parent))
972 index = read_int16(f);
973 total = read_int16(f);
974 if (parent == ATOM_TRACK)
976 sprintf(temp, "%d", index);
977 tag_add_field(&(f->tags), parent == ATOM_TRACK?
978 "track" : "disc", temp, -1);
980 sprintf(temp, "%d", total);
981 tag_add_field(& (f-> tags),
982 parent == ATOM_TRACK?
983 "totaltracks" : "totaldiscs", temp, -1);
988 data = read_string(f, subsize - (header_size + 8));
989 len = subsize - (header_size + 8);
995 set_metadata_name(parent , &name);
997 tag_add_field(&(f->tags), name, data, len);
1006 static int32_t read_mdhd(mp4ff_t * f)
1012 if (f->total_tracks == 0)
1014 t = f->track[f->total_tracks - 1];
1016 version = read_int32(f);
1018 read_int64(f); //creation-time
1019 read_int64(f); //modification-time
1020 t->timeScale = read_int32(f); //timescale
1021 t->duration = read_int64(f); //duration
1022 } else { //version == 0
1025 read_int32(f); //creation-time
1026 read_int32(f); //modification-time
1027 t->timeScale = read_int32(f); //timescale
1028 temp = read_int32(f);
1029 t->duration = (temp == (uint32_t) (-1))?
1030 (uint64_t) (-1) : (uint64_t) (temp);
1037 static int32_t parse_metadata(mp4ff_t * f, const int32_t size)
1039 uint64_t subsize, sumsize = 0;
1041 uint8_t header_size = 0;
1043 while (sumsize < size) {
1044 subsize = atom_read_header(f, &atom_type, &header_size);
1047 parse_tag(f, atom_type, (uint32_t)(subsize - header_size));
1054 static int32_t read_meta(mp4ff_t * f, const uint64_t size)
1056 uint64_t subsize, sumsize = 0;
1058 uint8_t header_size = 0;
1060 read_char(f); /* version */
1061 read_int24(f); /* flags */
1063 while (sumsize < (size - (header_size + 4))) {
1064 subsize = atom_read_header(f, &atom_type, &header_size);
1065 if (subsize <= header_size + 4)
1067 if (atom_type == ATOM_ILST) {
1068 parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1070 set_position(f, get_position(f) + subsize - header_size);
1078 static int32_t atom_read(mp4ff_t *f, const int32_t size,
1079 const uint8_t atom_type)
1081 uint64_t dest_position = get_position(f) + size - 8;
1082 if (atom_type == ATOM_STSZ) {
1083 /* sample size box */
1085 } else if (atom_type == ATOM_STTS) {
1086 /* time to sample box */
1088 } else if (atom_type == ATOM_CTTS) {
1089 /* composition offset box */
1091 } else if (atom_type == ATOM_STSC) {
1092 /* sample to chunk box */
1094 } else if (atom_type == ATOM_STCO) {
1095 /* chunk offset box */
1097 } else if (atom_type == ATOM_STSD) {
1098 /* sample description box */
1100 } else if (atom_type == ATOM_MVHD) {
1101 /* movie header box */
1103 } else if (atom_type == ATOM_MDHD) {
1106 } else if (atom_type == ATOM_META) {
1107 /* iTunes Metadata box */
1111 set_position(f, dest_position);
1115 /* parse atoms that are sub atoms of other atoms */
1116 static int32_t parse_sub_atoms(mp4ff_t * f, const uint64_t total_size, int meta_only)
1119 uint8_t atom_type = 0;
1120 uint64_t counted_size = 0;
1121 uint8_t header_size = 0;
1123 while (counted_size < total_size) {
1124 size = atom_read_header(f, &atom_type, &header_size);
1125 counted_size += size;
1127 /* check for end of file */
1131 /* we're starting to read a new track, update index,
1132 * so that all data and tables get written in the right place
1134 if (atom_type == ATOM_TRAK)
1136 /* parse subatoms */
1137 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1138 set_position(f, get_position(f) + size - header_size);
1139 } else if (atom_type < SUBATOMIC) {
1140 parse_sub_atoms(f, size - header_size, meta_only);
1142 atom_read(f, (uint32_t) size, atom_type);
1149 /* parse root atoms */
1150 static int32_t parse_atoms(mp4ff_t * f, int meta_only)
1153 uint8_t atom_type = 0;
1154 uint8_t header_size = 0;
1157 f->stream->read_error = 0;
1160 atom_read_header(f, &atom_type, &header_size)) != 0) {
1161 f->file_size += size;
1162 f->last_atom = atom_type;
1164 if (atom_type == ATOM_MOOV && size > header_size) {
1165 f->moov_offset = get_position(f) - header_size;
1166 f->moov_size = size;
1169 /* parse subatoms */
1170 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1171 set_position(f, get_position(f) + size - header_size);
1172 } else if (atom_type < SUBATOMIC) {
1173 parse_sub_atoms(f, size - header_size, meta_only);
1175 /* skip this atom */
1176 set_position(f, get_position(f) + size - header_size);
1183 void mp4ff_get_decoder_config(const mp4ff_t * f, const int track,
1184 unsigned char **ppBuf, unsigned int *pBufSize)
1186 if (track >= f->total_tracks) {
1192 if (f->track[track]->decoderConfig == NULL
1193 || f->track[track]->decoderConfigLen == 0) {
1197 *ppBuf = para_malloc(f->track[track]->decoderConfigLen);
1198 memcpy(*ppBuf, f->track[track]->decoderConfig,
1199 f->track[track]->decoderConfigLen);
1200 *pBufSize = f->track[track]->decoderConfigLen;
1204 mp4ff_t *mp4ff_open_read(mp4ff_callback_t * f)
1206 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1220 static int32_t tag_delete(mp4ff_metadata_t * tags)
1224 for (i = 0; i < tags->count; i++) {
1225 free(tags->tags[i].item);
1226 free(tags->tags[i].value);
1235 void mp4ff_close(mp4ff_t * ff)
1239 for (i = 0; i < ff->total_tracks; i++) {
1241 free(ff->track[i]->stsz_table);
1242 free(ff->track[i]->stts_sample_count);
1243 free(ff->track[i]->stts_sample_delta);
1244 free(ff->track[i]->stsc_first_chunk);
1245 free(ff->track[i]->stsc_samples_per_chunk);
1246 free(ff->track[i]->stsc_sample_desc_index);
1247 free(ff->track[i]->stco_chunk_offset);
1248 free(ff->track[i]->decoderConfig);
1249 free(ff->track[i]->ctts_sample_count);
1250 free(ff->track[i]->ctts_sample_offset);
1255 tag_delete(&(ff->tags));
1259 static int32_t chunk_of_sample(const mp4ff_t * f, const int32_t track,
1260 const int32_t sample, int32_t * chunk_sample, int32_t * chunk)
1262 int32_t total_entries = 0;
1263 int32_t chunk2entry;
1264 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1268 if (f->track[track] == NULL) {
1272 total_entries = f->track[track]->stsc_entry_count;
1279 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1280 *chunk = chunk2 - chunk1;
1281 range_samples = *chunk * chunk1samples;
1283 if (sample < total + range_samples)
1286 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1289 if (chunk2entry < total_entries) {
1291 total += range_samples;
1293 } while (chunk2entry < total_entries);
1296 *chunk = (sample - total) / chunk1samples + chunk1;
1300 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1305 static int32_t chunk_to_offset(const mp4ff_t * f, const int32_t track,
1306 const int32_t chunk)
1308 const mp4ff_track_t *p_track = f->track[track];
1310 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1311 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1313 } else if (p_track->stco_entry_count) {
1314 return p_track->stco_chunk_offset[chunk - 1];
1322 static int32_t sample_range_size(const mp4ff_t * f, const int32_t track,
1323 const int32_t chunk_sample, const int32_t sample)
1326 const mp4ff_track_t *p_track = f->track[track];
1328 if (p_track->stsz_sample_size) {
1329 return (sample - chunk_sample) * p_track->stsz_sample_size;
1331 if (sample >= p_track->stsz_sample_count)
1334 for (i = chunk_sample, total = 0; i < sample; i++) {
1335 total += p_track->stsz_table[i];
1342 static int32_t sample_to_offset(const mp4ff_t * f, const int32_t track,
1343 const int32_t sample)
1345 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1347 chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1349 chunk_offset1 = chunk_to_offset(f, track, chunk);
1350 chunk_offset2 = chunk_offset1 + sample_range_size(f,
1351 track, chunk_sample, sample);
1352 return chunk_offset2;
1355 void mp4ff_set_sample_position(mp4ff_t *f, const int32_t track,
1356 const int32_t sample)
1358 int32_t offset = sample_to_offset(f, track, sample);
1359 set_position(f, offset);
1362 int32_t mp4ff_get_sample_size(const mp4ff_t *f, int track, int sample)
1364 const mp4ff_track_t *t = f->track[track];
1366 if (t->stsz_sample_size != 0)
1367 return t->stsz_sample_size;
1368 return t->stsz_table[sample];
1371 uint32_t mp4ff_get_sample_rate(const mp4ff_t * f, const int32_t track)
1373 return f->track[track]->sampleRate;
1376 uint32_t mp4ff_get_channel_count(const mp4ff_t * f, const int32_t track)
1378 return f->track[track]->channelCount;
1381 int32_t mp4ff_num_samples(const mp4ff_t * f, const int32_t track)
1386 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1387 total += f->track[track]->stts_sample_count[i];
1392 mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t * f)
1394 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1408 int32_t mp4ff_meta_get_num_items(const mp4ff_t * f)
1410 return f->tags.count;
1413 int32_t mp4ff_meta_get_by_index(const mp4ff_t * f, uint32_t index,
1414 char **item, char **value)
1416 if (index >= f->tags.count) {
1421 *item = para_strdup(f->tags.tags[index].item);
1422 *value = para_strdup(f->tags.tags[index].value);
1427 static uint32_t find_atom(mp4ff_t * f, uint64_t base, uint32_t size,
1430 uint32_t remaining = size;
1431 uint64_t atom_offset = base;
1436 set_position(f, atom_offset);
1440 atom_size = read_int32(f);
1441 if (atom_size > remaining || atom_size < 8)
1443 read_data(f, atom_name, 4);
1445 if (!memcmp(atom_name, name, 4)) {
1446 set_position(f, atom_offset);
1450 remaining -= atom_size;
1451 atom_offset += atom_size;
1456 static uint32_t find_atom_v2(mp4ff_t * f, uint64_t base, uint32_t size,
1457 const char *name, uint32_t extraheaders, const char *name_inside)
1459 uint64_t first_base = (uint64_t) (-1);
1460 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1462 uint64_t mybase = get_position(f);
1463 uint32_t mysize = read_int32(f);
1465 if (first_base == (uint64_t) (-1))
1466 first_base = mybase;
1468 if (mysize < 8 + extraheaders)
1471 if (find_atom (f, mybase + (8 + extraheaders),
1472 mysize - (8 + extraheaders), name_inside)) {
1473 set_position(f, mybase);
1477 if (size <= mysize) {
1484 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1486 set_position(f, first_base);
1499 #define stricmp strcasecmp
1501 static membuffer *membuffer_create(void)
1503 const unsigned initial_size = 256;
1505 membuffer *buf = para_malloc(sizeof (membuffer));
1506 buf->data = para_malloc(initial_size);
1508 buf->allocated = initial_size;
1509 buf->error = buf->data == 0 ? 1 : 0;
1514 static unsigned membuffer_write(membuffer * buf, const void *ptr, unsigned bytes)
1516 unsigned dest_size = buf->written + bytes;
1520 if (dest_size > buf->allocated) {
1522 buf->allocated <<= 1;
1523 } while (dest_size > buf->allocated);
1526 void *newptr = realloc(buf->data, buf->allocated);
1538 memcpy((char *) buf->data + buf->written, ptr, bytes);
1539 buf->written += bytes;
1543 static unsigned membuffer_write_atom_name(membuffer * buf, const char *data)
1545 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1548 static unsigned membuffer_write_int16(membuffer * buf, uint16_t data)
1552 write_u16_be(temp, data);
1553 return membuffer_write(buf, temp, 2);
1556 static unsigned membuffer_write_int32(membuffer * buf, uint32_t data)
1559 write_u32_be(temp, data);
1560 return membuffer_write(buf, temp, 4);
1563 static void membuffer_write_track_tag(membuffer * buf, const char *name,
1564 uint32_t index, uint32_t total)
1566 membuffer_write_int32(buf,
1567 8 /*atom header */ + 8 /*data atom header */ +
1568 8 /*flags + reserved */ + 8 /*actual data */ );
1569 membuffer_write_atom_name(buf, name);
1570 membuffer_write_int32(buf,
1571 8 /*data atom header */ +
1572 8 /*flags + reserved */ + 8 /*actual data */ );
1573 membuffer_write_atom_name(buf, "data");
1574 membuffer_write_int32(buf, 0); //flags
1575 membuffer_write_int32(buf, 0); //reserved
1576 membuffer_write_int16(buf, 0);
1577 membuffer_write_int16(buf, (uint16_t) index); //track number
1578 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1579 membuffer_write_int16(buf, 0);
1582 static void membuffer_write_int16_tag(membuffer * buf, const char *name,
1585 membuffer_write_int32(buf,
1586 8 /*atom header */ + 8 /*data atom header */ +
1587 8 /*flags + reserved */ + 2 /*actual data */ );
1588 membuffer_write_atom_name(buf, name);
1589 membuffer_write_int32(buf,
1590 8 /*data atom header */ +
1591 8 /*flags + reserved */ + 2 /*actual data */ );
1592 membuffer_write_atom_name(buf, "data");
1593 membuffer_write_int32(buf, 0); //flags
1594 membuffer_write_int32(buf, 0); //reserved
1595 membuffer_write_int16(buf, value); //value
1598 static uint32_t myatoi(const char *param)
1600 return param ? atoi(param) : 0;
1603 static uint32_t meta_genre_to_index(const char *genrestr)
1606 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1607 if (!stricmp(genrestr, ID3v1GenreList[n]))
1618 static stdmeta_entry stdmetas[] = {
1619 {"\xA9" "nam", "title"},
1620 {"\xA9" "ART", "artist"},
1621 {"\xA9" "wrt", "writer"},
1622 {"\xA9" "alb", "album"},
1623 {"\xA9" "day", "date"},
1624 {"\xA9" "too", "tool"},
1625 {"\xA9" "cmt", "comment"},
1626 {"cpil", "compilation"},
1628 {"aART", "album_artist"},
1631 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1634 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1635 if (!stricmp(name, stdmetas[n].name))
1636 return stdmetas[n].atom;
1641 static void membuffer_write_std_tag(membuffer * buf, const char *name,
1646 /* special check for compilation flag */
1647 if (strcmp(name, "cpil") == 0) {
1651 membuffer_write_int32(buf,
1652 8 /*atom header */ + 8 /*data atom header */ +
1653 8 /*flags + reserved */ + strlen(value));
1654 membuffer_write_atom_name(buf, name);
1655 membuffer_write_int32(buf,
1656 8 /*data atom header */ +
1657 8 /*flags + reserved */ + strlen(value));
1658 membuffer_write_atom_name(buf, "data");
1659 membuffer_write_int32(buf, flags); //flags
1660 membuffer_write_int32(buf, 0); //reserved
1661 membuffer_write(buf, value, strlen(value));
1664 static void membuffer_write_custom_tag(membuffer * buf, const char *name,
1667 membuffer_write_int32(buf,
1668 8 /*atom header */ +
1669 0x1C /*weirdo itunes atom */ +
1670 12 /*name atom header */ + strlen(name) +
1671 16 /*data atom header + flags */ + strlen(value));
1672 membuffer_write_atom_name(buf, "----");
1673 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1674 membuffer_write_atom_name(buf, "mean");
1675 membuffer_write_int32(buf, 0);
1676 membuffer_write(buf, "com.apple.iTunes", 16);
1677 membuffer_write_int32(buf, 12 + strlen(name));
1678 membuffer_write_atom_name(buf, "name");
1679 membuffer_write_int32(buf, 0);
1680 membuffer_write(buf, name, strlen(name));
1681 membuffer_write_int32(buf,
1682 8 /*data atom header */ +
1683 8 /*flags + reserved */ + strlen(value));
1684 membuffer_write_atom_name(buf, "data");
1685 membuffer_write_int32(buf, 1); //flags
1686 membuffer_write_int32(buf, 0); //reserved
1687 membuffer_write(buf, value, strlen(value));
1690 static unsigned membuffer_error(const membuffer * buf)
1695 static void membuffer_free(membuffer * buf)
1701 static unsigned membuffer_get_size(const membuffer * buf)
1703 return buf->written;
1706 static void *membuffer_detach(membuffer * buf)
1713 ret = realloc(buf->data, buf->written);
1724 static uint32_t create_ilst(const mp4ff_metadata_t * data, void **out_buffer,
1725 uint32_t * out_size)
1727 membuffer *buf = membuffer_create();
1729 char *mask = para_calloc(data->count);
1731 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1732 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1733 const char *genre_ptr = 0, *tempo_ptr = 0;
1734 for (metaptr = 0; metaptr < data->count; metaptr++) {
1735 mp4ff_tag_t *tag = &data->tags[metaptr];
1736 if (!stricmp(tag->item, "tracknumber") || !stricmp(tag->item, "track")) {
1737 if (tracknumber_ptr == 0)
1738 tracknumber_ptr = tag->value;
1740 } else if (!stricmp(tag->item, "totaltracks")) {
1741 if (totaltracks_ptr == 0)
1742 totaltracks_ptr = tag->value;
1744 } else if (!stricmp(tag->item, "discnumber")
1745 || !stricmp(tag->item, "disc")) {
1746 if (discnumber_ptr == 0)
1747 discnumber_ptr = tag->value;
1749 } else if (!stricmp(tag->item, "totaldiscs")) {
1750 if (totaldiscs_ptr == 0)
1751 totaldiscs_ptr = tag->value;
1753 } else if (!stricmp(tag->item, "genre")) {
1755 genre_ptr = tag->value;
1757 } else if (!stricmp(tag->item, "tempo")) {
1759 tempo_ptr = tag->value;
1765 if (tracknumber_ptr)
1766 membuffer_write_track_tag(buf, "trkn",
1767 myatoi(tracknumber_ptr),
1768 myatoi(totaltracks_ptr));
1770 membuffer_write_track_tag(buf, "disk",
1771 myatoi(discnumber_ptr),
1772 myatoi(totaldiscs_ptr));
1774 membuffer_write_int16_tag(buf, "tmpo",
1775 (uint16_t) myatoi(tempo_ptr));
1778 uint32_t index = meta_genre_to_index(genre_ptr);
1780 membuffer_write_std_tag(buf, "©gen",
1783 membuffer_write_int16_tag(buf, "gnre",
1788 for (metaptr = 0; metaptr < data->count; metaptr++) {
1789 if (!mask[metaptr]) {
1790 mp4ff_tag_t *tag = &data->tags[metaptr];
1791 const char *std_meta_atom = find_standard_meta(tag->item);
1792 if (std_meta_atom) {
1793 membuffer_write_std_tag(buf, std_meta_atom,
1796 membuffer_write_custom_tag(buf, tag->item,
1804 if (membuffer_error(buf)) {
1805 membuffer_free(buf);
1809 *out_size = membuffer_get_size(buf);
1810 *out_buffer = membuffer_detach(buf);
1811 membuffer_free(buf);
1816 static void membuffer_write_atom(membuffer * buf, const char *name, unsigned size,
1819 membuffer_write_int32(buf, size + 8);
1820 membuffer_write_atom_name(buf, name);
1821 membuffer_write(buf, data, size);
1824 static void *membuffer_get_ptr(const membuffer * buf)
1829 static void membuffer_set_error(membuffer * buf)
1834 static unsigned membuffer_transfer_from_file(membuffer * buf, mp4ff_t * src,
1840 oldsize = membuffer_get_size(buf);
1841 if (membuffer_write(buf, 0, bytes) != bytes)
1844 bufptr = membuffer_get_ptr(buf);
1848 if ((unsigned)read_data(src, (char *) bufptr + oldsize, bytes) !=
1850 membuffer_set_error(buf);
1857 static uint32_t create_meta(const mp4ff_metadata_t * data, void **out_buffer,
1858 uint32_t * out_size)
1864 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1867 buf = membuffer_create();
1869 membuffer_write_int32(buf, 0);
1870 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1873 *out_size = membuffer_get_size(buf);
1874 *out_buffer = membuffer_detach(buf);
1875 membuffer_free(buf);
1879 static uint32_t create_udta(const mp4ff_metadata_t * data, void **out_buffer,
1880 uint32_t * out_size)
1886 if (!create_meta(data, &meta_buffer, &meta_size))
1889 buf = membuffer_create();
1891 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1895 *out_size = membuffer_get_size(buf);
1896 *out_buffer = membuffer_detach(buf);
1897 membuffer_free(buf);
1901 static uint32_t fix_byte_order_32(uint32_t src)
1903 return read_u32_be(&src);
1906 static uint32_t modify_moov(mp4ff_t * f, const mp4ff_metadata_t * data,
1907 void **out_buffer, uint32_t * out_size)
1909 uint64_t total_base = f->moov_offset + 8;
1910 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1912 uint64_t udta_offset, meta_offset, ilst_offset;
1913 uint32_t udta_size, meta_size, ilst_size;
1915 uint32_t new_ilst_size;
1916 void *new_ilst_buffer;
1921 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1923 void *new_udta_buffer;
1924 uint32_t new_udta_size;
1925 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1928 buf = membuffer_create();
1929 set_position(f, total_base);
1930 membuffer_transfer_from_file(buf, f, total_size);
1932 membuffer_write_atom(buf, "udta", new_udta_size,
1935 free(new_udta_buffer);
1937 *out_size = membuffer_get_size(buf);
1938 *out_buffer = membuffer_detach(buf);
1939 membuffer_free(buf);
1942 udta_offset = get_position(f);
1943 udta_size = read_int32(f);
1944 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
1946 void *new_meta_buffer;
1947 uint32_t new_meta_size;
1948 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
1951 buf = membuffer_create();
1952 set_position(f, total_base);
1953 membuffer_transfer_from_file(buf, f,
1954 (uint32_t)(udta_offset - total_base));
1956 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
1957 membuffer_write_atom_name(buf, "udta");
1958 membuffer_transfer_from_file(buf, f, udta_size);
1960 membuffer_write_atom(buf, "meta", new_meta_size,
1962 free(new_meta_buffer);
1964 *out_size = membuffer_get_size(buf);
1965 *out_buffer = membuffer_detach(buf);
1966 membuffer_free(buf);
1969 meta_offset = get_position(f);
1970 meta_size = read_int32(f);
1971 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
1972 return 0; //shouldn't happen, find_atom_v2 above takes care of it
1973 ilst_offset = get_position(f);
1974 ilst_size = read_int32(f);
1976 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
1979 size_delta = new_ilst_size - (ilst_size - 8);
1981 *out_size = total_size + size_delta;
1982 *out_buffer = para_malloc(*out_size);
1983 p_out = (uint8_t *) * out_buffer;
1985 set_position(f, total_base);
1987 (uint32_t) (udta_offset - total_base));
1988 p_out += (uint32_t) (udta_offset - total_base);
1989 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1991 read_data(f, p_out, 4);
1994 (uint32_t) (meta_offset - udta_offset - 8));
1995 p_out += (uint32_t) (meta_offset - udta_offset - 8);
1996 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1998 read_data(f, p_out, 4);
2001 (uint32_t) (ilst_offset - meta_offset - 8));
2002 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2003 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2005 read_data(f, p_out, 4);
2008 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2009 p_out += new_ilst_size;
2011 set_position(f, ilst_offset + ilst_size);
2012 read_data(f, p_out, (uint32_t) (total_size
2013 - (ilst_offset - total_base) - ilst_size));
2015 free(new_ilst_buffer);
2020 static int32_t write_data(mp4ff_t * f, void *data, uint32_t size)
2024 result = f->stream->write(f->stream->user_data, data, size);
2026 f->current_position += size;
2031 static int32_t write_int32(mp4ff_t * f, const uint32_t data)
2034 write_u32_be(temp, data);
2035 return write_data(f, temp, sizeof(temp));
2038 static int32_t truncate_stream(mp4ff_t * f)
2040 return f->stream->truncate(f->stream->user_data);
2043 int32_t mp4ff_meta_update(mp4ff_callback_t * f, const mp4ff_metadata_t * data)
2045 void *new_moov_data;
2046 uint32_t new_moov_size;
2048 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
2050 set_position(ff, 0);
2054 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2059 /* copy moov atom to end of the file */
2060 if (ff->last_atom != ATOM_MOOV) {
2061 char *free_data = "free";
2063 /* rename old moov to free */
2064 set_position(ff, ff->moov_offset + 4);
2065 write_data(ff, free_data, 4);
2067 set_position(ff, ff->file_size);
2068 write_int32(ff, new_moov_size + 8);
2069 write_data(ff, "moov", 4);
2070 write_data(ff, new_moov_data, new_moov_size);
2072 set_position(ff, ff->moov_offset);
2073 write_int32(ff, new_moov_size + 8);
2074 write_data(ff, "moov", 4);
2075 write_data(ff, new_moov_data, new_moov_size);
2078 truncate_stream(ff);
2084 /* find a metadata item by name */
2085 /* returns 0 if item found, 1 if no such item */
2086 static int32_t meta_find_by_name(const mp4ff_t * f, const char *item,
2091 for (i = 0; i < f->tags.count; i++) {
2092 if (!stricmp(f->tags.tags[i].item, item)) {
2093 *value = para_strdup(f->tags.tags[i].value);
2104 int32_t mp4ff_meta_get_artist(const mp4ff_t * f, char **value)
2106 return meta_find_by_name(f, "artist", value);
2109 int32_t mp4ff_meta_get_title(const mp4ff_t * f, char **value)
2111 return meta_find_by_name(f, "title", value);
2114 int32_t mp4ff_meta_get_date(const mp4ff_t * f, char **value)
2116 return meta_find_by_name(f, "date", value);
2119 int32_t mp4ff_meta_get_album(const mp4ff_t * f, char **value)
2121 return meta_find_by_name(f, "album", value);
2124 int32_t mp4ff_meta_get_comment(const mp4ff_t * f, char **value)
2126 return meta_find_by_name(f, "comment", value);