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)
56 #define TRACK_SYSTEM 3
57 #define TRACK_UNKNOWN 0
59 /* atoms with subatoms */
67 #define ATOM_ILST 8 /* iTunes Metadata list */
69 #define ATOM_ARTIST 10
70 #define ATOM_WRITER 11
74 #define ATOM_COMMENT 15
75 #define ATOM_GENRE1 16
78 #define ATOM_COMPILATION 19
79 #define ATOM_GENRE2 20
88 /* atoms without subatoms */
100 #define ATOM_STSZ 140
101 #define ATOM_STZ2 141
102 #define ATOM_STCO 142
103 #define ATOM_STSC 143
104 #define ATOM_MP4A 144
105 #define ATOM_MP4V 145
106 #define ATOM_MP4S 146
107 #define ATOM_ESDS 147
108 #define ATOM_META 148 /* iTunes Metadata box */
109 #define ATOM_NAME 149 /* iTunes Metadata name box */
110 #define ATOM_DATA 150 /* iTunes Metadata data box */
111 #define ATOM_CTTS 151
112 #define ATOM_FRMA 152
113 #define ATOM_IVIV 153
114 #define ATOM_PRIV 154
115 #define ATOM_USER 155
117 #define ATOM_ALBUM_ARTIST 157
118 #define ATOM_CONTENTGROUP 158
119 #define ATOM_LYRICS 159
120 #define ATOM_DESCRIPTION 160
121 #define ATOM_NETWORK 161
122 #define ATOM_SHOW 162
123 #define ATOM_EPISODENAME 163
124 #define ATOM_SORTTITLE 164
125 #define ATOM_SORTALBUM 165
126 #define ATOM_SORTARTIST 166
127 #define ATOM_SORTALBUMARTIST 167
128 #define ATOM_SORTWRITER 168
129 #define ATOM_SORTSHOW 169
130 #define ATOM_SEASON 170
131 #define ATOM_EPISODE 171
132 #define ATOM_PODCAST 172
134 #define ATOM_UNKNOWN 255
135 #define ATOM_FREE ATOM_UNKNOWN
136 #define ATOM_SKIP ATOM_UNKNOWN
138 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
140 static uint8_t atom_name_to_type(const int8_t a, const int8_t b,
141 const int8_t c, const int8_t d)
144 if (atom_compare(a, b, c, d, 'm', 'o', 'o', 'v'))
146 else if (atom_compare(a, b, c, d, 'm', 'i', 'n', 'f'))
148 else if (atom_compare(a, b, c, d, 'm', 'd', 'i', 'a'))
150 else if (atom_compare(a, b, c, d, 'm', 'd', 'a', 't'))
152 else if (atom_compare(a, b, c, d, 'm', 'd', 'h', 'd'))
154 else if (atom_compare(a, b, c, d, 'm', 'v', 'h', 'd'))
156 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'a'))
158 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'v'))
160 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 's'))
162 else if (atom_compare(a, b, c, d, 'm', 'e', 't', 'a'))
164 } else if (a == 't') {
165 if (atom_compare(a, b, c, d, 't', 'r', 'a', 'k'))
167 else if (atom_compare(a, b, c, d, 't', 'k', 'h', 'd'))
169 else if (atom_compare(a, b, c, d, 't', 'r', 'e', 'f'))
171 else if (atom_compare(a, b, c, d, 't', 'r', 'k', 'n'))
173 else if (atom_compare(a, b, c, d, 't', 'm', 'p', 'o'))
175 else if (atom_compare(a, b, c, d, 't', 'v', 'n', 'n'))
177 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'h'))
179 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 'n'))
180 return ATOM_EPISODENAME;
181 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'n'))
183 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 's'))
185 } else if (a == 's') {
186 if (atom_compare(a, b, c, d, 's', 't', 'b', 'l'))
188 else if (atom_compare(a, b, c, d, 's', 'm', 'h', 'd'))
190 else if (atom_compare(a, b, c, d, 's', 't', 's', 'd'))
192 else if (atom_compare(a, b, c, d, 's', 't', 't', 's'))
194 else if (atom_compare(a, b, c, d, 's', 't', 'c', 'o'))
196 else if (atom_compare(a, b, c, d, 's', 't', 's', 'c'))
198 else if (atom_compare(a, b, c, d, 's', 't', 's', 'z'))
200 else if (atom_compare(a, b, c, d, 's', 't', 'z', '2'))
202 else if (atom_compare(a, b, c, d, 's', 'k', 'i', 'p'))
204 else if (atom_compare(a, b, c, d, 's', 'i', 'n', 'f'))
206 else if (atom_compare(a, b, c, d, 's', 'c', 'h', 'i'))
208 else if (atom_compare(a, b, c, d, 's', 'o', 'n', 'm'))
209 return ATOM_SORTTITLE;
210 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'l'))
211 return ATOM_SORTALBUM;
212 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'r'))
213 return ATOM_SORTARTIST;
214 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'a'))
215 return ATOM_SORTALBUMARTIST;
216 else if (atom_compare(a, b, c, d, 's', 'o', 'c', 'o'))
217 return ATOM_SORTWRITER;
218 else if (atom_compare(a, b, c, d, 's', 'o', 's', 'n'))
219 return ATOM_SORTSHOW;
220 } else if (a == COPYRIGHT_SYMBOL) {
221 if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'n', 'a', 'm'))
223 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'A', 'R', 'T'))
225 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'w', 'r', 't'))
227 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'a', 'l', 'b'))
229 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'd', 'a', 'y'))
231 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 't', 'o', 'o'))
233 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'c', 'm', 't'))
235 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'e', 'n'))
237 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'r', 'p'))
238 return ATOM_CONTENTGROUP;
239 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'l', 'y', 'r'))
243 if (atom_compare(a, b, c, d, 'e', 'd', 't', 's'))
245 else if (atom_compare(a, b, c, d, 'e', 's', 'd', 's'))
247 else if (atom_compare(a, b, c, d, 'f', 't', 'y', 'p'))
249 else if (atom_compare(a, b, c, d, 'f', 'r', 'e', 'e'))
251 else if (atom_compare(a, b, c, d, 'h', 'm', 'h', 'd'))
253 else if (atom_compare(a, b, c, d, 'v', 'm', 'h', 'd'))
255 else if (atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
257 else if (atom_compare(a, b, c, d, 'i', 'l', 's', 't'))
259 else if (atom_compare(a, b, c, d, 'n', 'a', 'm', 'e'))
261 else if (atom_compare(a, b, c, d, 'd', 'a', 't', 'a'))
263 else if (atom_compare(a, b, c, d, 'd', 'i', 's', 'k'))
265 else if (atom_compare(a, b, c, d, 'g', 'n', 'r', 'e'))
267 else if (atom_compare(a, b, c, d, 'c', 'o', 'v', 'r'))
269 else if (atom_compare(a, b, c, d, 'c', 'p', 'i', 'l'))
270 return ATOM_COMPILATION;
271 else if (atom_compare(a, b, c, d, 'c', 't', 't', 's'))
273 else if (atom_compare(a, b, c, d, 'd', 'r', 'm', 's'))
275 else if (atom_compare(a, b, c, d, 'f', 'r', 'm', 'a'))
277 else if (atom_compare(a, b, c, d, 'p', 'r', 'i', 'v'))
279 else if (atom_compare(a, b, c, d, 'i', 'v', 'i', 'v'))
281 else if (atom_compare(a, b, c, d, 'u', 's', 'e', 'r'))
283 else if (atom_compare(a, b, c, d, 'k', 'e', 'y', ' '))
285 else if (atom_compare(a, b, c, d, 'a', 'A', 'R', 'T'))
286 return ATOM_ALBUM_ARTIST;
287 else if (atom_compare(a, b, c, d, 'd', 'e', 's', 'c'))
288 return ATOM_DESCRIPTION;
289 else if (atom_compare(a, b, c, d, 'p', 'c', 's', 't'))
295 /* read atom header, return atom size, atom size is with header included */
296 static uint64_t atom_read_header(mp4ff_t * f, uint8_t * atom_type,
297 uint8_t * header_size)
301 int8_t atom_header[8];
303 ret = read_data(f, atom_header, 8);
307 size = read_u32_be(atom_header);
310 /* check for 64 bit atom size */
313 size = read_int64(f);
315 *atom_type = atom_name_to_type(atom_header[4], atom_header[5],
316 atom_header[6], atom_header[7]);
320 static int64_t get_position(const mp4ff_t * f)
322 return f->current_position;
325 static int need_parse_when_meta_only(uint8_t atom_type)
346 static int32_t set_position(mp4ff_t * f, const int64_t position)
348 f->stream->seek(f->stream->user_data, position);
349 f->current_position = position;
354 static void track_add(mp4ff_t * f)
358 if (f->total_tracks > MAX_TRACKS) {
363 f->track[f->total_tracks - 1] = para_calloc(sizeof (mp4ff_track_t));
366 static uint8_t read_char(mp4ff_t * f)
369 read_data(f, &output, 1);
373 static uint32_t read_int24(mp4ff_t * f)
377 read_data(f, data, 3);
378 return read_u24_be(data);
381 static uint32_t read_int32(mp4ff_t * f)
385 read_data(f, data, 4);
386 return read_u32_be(data);
389 static int32_t read_stsz(mp4ff_t * f)
394 if (f->total_tracks == 0)
396 t = f->track[f->total_tracks - 1];
397 read_char(f); /* version */
398 read_int24(f); /* flags */
399 t->stsz_sample_size = read_int32(f);
400 t->stsz_sample_count = read_int32(f);
401 if (t->stsz_sample_size != 0)
403 t->stsz_table = para_malloc(t->stsz_sample_count * sizeof(int32_t));
404 for (i = 0; i < t->stsz_sample_count && !f->stream->read_error; i++)
405 t->stsz_table[i] = read_int32(f);
409 static int32_t read_stts(mp4ff_t * f)
415 if (f->total_tracks == 0)
417 t = f->track[f->total_tracks - 1];
418 if (t->stts_entry_count)
420 read_char(f); /* version */
421 read_int24(f); /* flags */
422 t->stts_entry_count = read_int32(f);
424 t->stts_sample_count = para_malloc(t->stts_entry_count
426 t->stts_sample_delta = para_malloc(t->stts_entry_count
429 for (i = 0; i < t->stts_entry_count && !f->stream->read_error; i++) {
430 t->stts_sample_count[i] = read_int32(f);
431 t->stts_sample_delta[i] = read_int32(f);
436 static int32_t read_ctts(mp4ff_t * f)
441 if (f->total_tracks == 0)
443 t = f->track[f->total_tracks - 1];
444 if (t->ctts_entry_count)
447 read_char(f); /* version */
448 read_int24(f); /* flags */
449 t->ctts_entry_count = read_int32(f);
451 t->ctts_sample_count = para_malloc(t->ctts_entry_count
453 t->ctts_sample_offset = para_malloc(t->ctts_entry_count
457 for (i = 0; i < t->ctts_entry_count && !f->stream->read_error; i++) {
458 t->ctts_sample_count[i] = read_int32(f);
459 t->ctts_sample_offset[i] = read_int32(f);
464 static int32_t read_stsc(mp4ff_t * f)
469 if (f->total_tracks == 0)
471 t = f->track[f->total_tracks - 1];
473 read_char(f); /* version */
474 read_int24(f); /* flags */
475 t->stsc_entry_count = read_int32(f);
476 t->stsc_first_chunk = para_malloc(t->stsc_entry_count * sizeof(int32_t));
477 t->stsc_samples_per_chunk = para_malloc(t->stsc_entry_count
479 t->stsc_sample_desc_index = para_malloc(t->stsc_entry_count *
483 for (i = 0; i < t->stsc_entry_count && !f->stream->read_error; i++) {
484 t->stsc_first_chunk[i] = read_int32(f);
485 t->stsc_samples_per_chunk[i] = read_int32(f);
486 t->stsc_sample_desc_index[i] = read_int32(f);
491 static int32_t read_stco(mp4ff_t * f)
496 if (f->total_tracks == 0)
498 t = f->track[f->total_tracks - 1];
500 read_char(f); /* version */
501 read_int24(f); /* flags */
502 t->stco_entry_count = read_int32(f);
503 t->stco_chunk_offset = para_malloc(t->stco_entry_count
506 for (i = 0; i < t->stco_entry_count && !f->stream->read_error; i++)
507 t->stco_chunk_offset[i] = read_int32(f);
511 static uint16_t read_int16(mp4ff_t * f)
515 read_data(f, data, 2);
516 return read_u16_be(data);
519 static uint32_t read_mp4_descr_length(mp4ff_t * f)
522 uint8_t numBytes = 0;
528 length = (length << 7) | (b & 0x7F);
529 } while ((b & 0x80) && numBytes < 4);
533 static int32_t read_esds(mp4ff_t * f)
539 if (f->total_tracks == 0)
541 t = f->track[f->total_tracks - 1];
542 read_char(f); /* version */
543 read_int24(f); /* flags */
544 /* get and verify ES_DescrTag */
548 if (read_mp4_descr_length(f) < 5 + 15) {
558 /* get and verify DecoderConfigDescrTab */
559 if (read_char(f) != 0x04) {
564 temp = read_mp4_descr_length(f);
568 t->audioType = read_char(f);
569 read_int32(f); //0x15000414 ????
570 t->maxBitrate = read_int32(f);
571 t->avgBitrate = read_int32(f);
573 /* get and verify DecSpecificInfoTag */
574 if (read_char(f) != 0x05) {
579 t->decoderConfigLen = read_mp4_descr_length(f);
580 free(t->decoderConfig);
581 t->decoderConfig = para_malloc(t->decoderConfigLen);
582 read_data(f, t->decoderConfig, t->decoderConfigLen);
583 /* will skip the remainder of the atom */
587 static int32_t read_mp4a(mp4ff_t * f)
590 uint8_t atom_type = 0;
591 uint8_t header_size = 0;
594 if (f->total_tracks == 0)
596 t = f->track[f->total_tracks - 1];
598 for (i = 0; i < 6; i++) {
599 read_char(f); /* reserved */
601 /* data_reference_index */ read_int16(f);
603 read_int32(f); /* reserved */
604 read_int32(f); /* reserved */
606 t->channelCount = read_int16(f);
607 t->sampleSize = read_int16(f);
612 t->sampleRate = read_int16(f);
616 atom_read_header(f, &atom_type, &header_size);
617 if (atom_type == ATOM_ESDS)
622 static int32_t read_stsd(mp4ff_t * f)
625 uint8_t header_size = 0;
629 if (f->total_tracks == 0)
631 t = f->track[f->total_tracks - 1];
633 read_char(f); /* version */
634 read_int24(f); /* flags */
636 t->stsd_entry_count = read_int32(f);
639 for (i = 0; i < t->stsd_entry_count && !f->stream->read_error; i++) {
640 uint64_t skip = get_position(f);
642 uint8_t atom_type = 0;
643 size = atom_read_header(f, &atom_type, &header_size);
646 if (atom_type == ATOM_MP4A) {
647 t->type = TRACK_AUDIO;
649 } else if (atom_type == ATOM_MP4V) {
650 t->type = TRACK_VIDEO;
651 } else if (atom_type == ATOM_MP4S) {
652 t->type = TRACK_SYSTEM;
654 t->type = TRACK_UNKNOWN;
656 set_position(f, skip);
662 static int32_t read_mvhd(mp4ff_t * f)
666 read_char(f); /* version */
667 read_int24(f); /* flags */
668 /* creation_time */ read_int32(f);
669 /* modification_time */ read_int32(f);
670 f->time_scale = read_int32(f);
671 f->duration = read_int32(f);
672 /* preferred_rate */ read_int32(f);
673 /*mp4ff_read_fixed32(f); */
674 /* preferred_volume */ read_int16(f);
675 /*mp4ff_read_fixed16(f); */
676 for (i = 0; i < 10; i++) {
677 /* reserved */ read_char(f);
679 for (i = 0; i < 9; i++) {
680 read_int32(f); /* matrix */
682 /* preview_time */ read_int32(f);
683 /* preview_duration */ read_int32(f);
684 /* poster_time */ read_int32(f);
685 /* selection_time */ read_int32(f);
686 /* selection_duration */ read_int32(f);
687 /* current_time */ read_int32(f);
688 /* next_track_id */ read_int32(f);
693 static int32_t tag_add_field(mp4ff_metadata_t * tags, const char *item,
694 const char *value, int32_t len)
696 void *backup = (void *) tags->tags;
698 if (!item || (item && !*item) || !value)
701 tags->tags = (mp4ff_tag_t *) realloc(tags->tags,
702 (tags->count + 1) * sizeof (mp4ff_tag_t));
707 tags->tags[tags->count].item = para_strdup(item);
708 tags->tags[tags->count].len = len;
710 tags->tags[tags->count].value = para_malloc(len + 1);
711 memcpy(tags->tags[tags->count].value, value, len);
712 tags->tags[tags->count].value[len] = 0;
714 tags->tags[tags->count].value = para_strdup(value);
721 static const char *ID3v1GenreList[] = {
722 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
723 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
724 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
725 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
726 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
727 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
728 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
729 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
730 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
731 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
732 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
733 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
734 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
735 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
736 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
737 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
738 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
739 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
740 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
741 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
742 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
743 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
744 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
745 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
746 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
747 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
748 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
749 "Anime", "JPop", "SynthPop",
752 static const char *meta_index_to_genre(uint32_t idx)
754 if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
755 return ID3v1GenreList[idx - 1];
761 static char *read_string(mp4ff_t *f, uint32_t length)
763 char *str = para_malloc(length + 1);
764 if ((uint32_t)read_data(f, str, length) != length) {
772 static int32_t set_metadata_name(const uint8_t atom_type, char **name)
774 static char *tag_names[] = {
775 "unknown", "title", "artist", "writer", "album",
776 "date", "tool", "comment", "genre", "track",
777 "disc", "compilation", "genre", "tempo", "cover",
778 "album_artist", "contentgroup", "lyrics", "description",
779 "network", "show", "episodename",
780 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
781 "sortwriter", "sortshow",
782 "season", "episode", "podcast"
817 case ATOM_COMPILATION:
829 case ATOM_ALBUM_ARTIST:
832 case ATOM_CONTENTGROUP:
838 case ATOM_DESCRIPTION:
847 case ATOM_EPISODENAME:
856 case ATOM_SORTARTIST:
859 case ATOM_SORTALBUMARTIST:
862 case ATOM_SORTWRITER:
882 *name = para_strdup(tag_names[tag_idx]);
886 static uint32_t min_body_size(const uint8_t atom_type)
893 return sizeof (char) /* version */
894 + sizeof(uint8_t) * 3 /* flags */
895 + sizeof(uint32_t) /* reserved */
896 + sizeof(uint16_t) /* leading uint16_t */
897 + sizeof(uint16_t) /* track */
898 + sizeof(uint16_t); /* totaltracks */
900 return sizeof (char) /* version */
901 + sizeof(uint8_t) * 3 /* flags */
902 + sizeof(uint32_t) /* reserved */
903 + sizeof(uint16_t) /* disc */
904 + sizeof(uint16_t); /* totaldiscs */
905 default: assert(false);
909 static int32_t parse_tag(mp4ff_t * f, const uint8_t parent,
913 uint8_t header_size = 0;
914 uint64_t subsize, sumsize;
923 sumsize < size && !f->stream->read_error; /* CVE-2017-9222 */
924 set_position(f, destpos), sumsize += subsize
926 subsize = atom_read_header(f, &atom_type, &header_size);
927 destpos = get_position(f) + subsize - header_size;
930 if (atom_type == ATOM_NAME) {
931 read_char(f); /* version */
932 read_int24(f); /* flags */
934 name = read_string(f, subsize - (header_size + 4));
937 if (atom_type != ATOM_DATA)
939 read_char(f); /* version */
940 read_int24(f); /* flags */
941 read_int32(f); /* reserved */
943 /* some need special attention */
944 if (parent == ATOM_GENRE2 || parent == ATOM_TEMPO) {
946 if (subsize - header_size < min_body_size(parent))
949 if (parent == ATOM_TEMPO) {
951 sprintf(temp, "%.5u BPM", val);
952 tag_add_field(&(f-> tags), "tempo",
955 const char *tmp = meta_index_to_genre(val);
957 tag_add_field (&(f->tags),
961 } else if (parent == ATOM_TRACK || parent == ATOM_DISC) {
962 uint16_t index, total;
964 if (subsize - header_size < min_body_size(parent))
967 index = read_int16(f);
968 total = read_int16(f);
969 if (parent == ATOM_TRACK)
971 sprintf(temp, "%d", index);
972 tag_add_field(&(f->tags), parent == ATOM_TRACK?
973 "track" : "disc", temp, -1);
975 sprintf(temp, "%d", total);
976 tag_add_field(& (f-> tags),
977 parent == ATOM_TRACK?
978 "totaltracks" : "totaldiscs", temp, -1);
983 data = read_string(f, subsize - (header_size + 8));
984 len = subsize - (header_size + 8);
990 set_metadata_name(parent , &name);
992 tag_add_field(&(f->tags), name, data, len);
1001 static int32_t read_mdhd(mp4ff_t * f)
1007 if (f->total_tracks == 0)
1009 t = f->track[f->total_tracks - 1];
1011 version = read_int32(f);
1013 read_int64(f); //creation-time
1014 read_int64(f); //modification-time
1015 t->timeScale = read_int32(f); //timescale
1016 t->duration = read_int64(f); //duration
1017 } else { //version == 0
1020 read_int32(f); //creation-time
1021 read_int32(f); //modification-time
1022 t->timeScale = read_int32(f); //timescale
1023 temp = read_int32(f);
1024 t->duration = (temp == (uint32_t) (-1))?
1025 (uint64_t) (-1) : (uint64_t) (temp);
1032 static int32_t parse_metadata(mp4ff_t * f, const int32_t size)
1034 uint64_t subsize, sumsize = 0;
1036 uint8_t header_size = 0;
1038 while (sumsize < size) {
1039 subsize = atom_read_header(f, &atom_type, &header_size);
1042 parse_tag(f, atom_type, (uint32_t)(subsize - header_size));
1049 static int32_t read_meta(mp4ff_t * f, const uint64_t size)
1051 uint64_t subsize, sumsize = 0;
1053 uint8_t header_size = 0;
1055 read_char(f); /* version */
1056 read_int24(f); /* flags */
1058 while (sumsize < (size - (header_size + 4))) {
1059 subsize = atom_read_header(f, &atom_type, &header_size);
1060 if (subsize <= header_size + 4)
1062 if (atom_type == ATOM_ILST) {
1063 parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1065 set_position(f, get_position(f) + subsize - header_size);
1073 static int32_t atom_read(mp4ff_t *f, const int32_t size,
1074 const uint8_t atom_type)
1076 uint64_t dest_position = get_position(f) + size - 8;
1077 if (atom_type == ATOM_STSZ) {
1078 /* sample size box */
1080 } else if (atom_type == ATOM_STTS) {
1081 /* time to sample box */
1083 } else if (atom_type == ATOM_CTTS) {
1084 /* composition offset box */
1086 } else if (atom_type == ATOM_STSC) {
1087 /* sample to chunk box */
1089 } else if (atom_type == ATOM_STCO) {
1090 /* chunk offset box */
1092 } else if (atom_type == ATOM_STSD) {
1093 /* sample description box */
1095 } else if (atom_type == ATOM_MVHD) {
1096 /* movie header box */
1098 } else if (atom_type == ATOM_MDHD) {
1101 } else if (atom_type == ATOM_META) {
1102 /* iTunes Metadata box */
1106 set_position(f, dest_position);
1110 /* parse atoms that are sub atoms of other atoms */
1111 static int32_t parse_sub_atoms(mp4ff_t * f, const uint64_t total_size, int meta_only)
1114 uint8_t atom_type = 0;
1115 uint64_t counted_size = 0;
1116 uint8_t header_size = 0;
1118 while (counted_size < total_size) {
1119 size = atom_read_header(f, &atom_type, &header_size);
1120 counted_size += size;
1122 /* check for end of file */
1126 /* we're starting to read a new track, update index,
1127 * so that all data and tables get written in the right place
1129 if (atom_type == ATOM_TRAK)
1131 /* parse subatoms */
1132 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1133 set_position(f, get_position(f) + size - header_size);
1134 } else if (atom_type < SUBATOMIC) {
1135 parse_sub_atoms(f, size - header_size, meta_only);
1137 atom_read(f, (uint32_t) size, atom_type);
1144 /* parse root atoms */
1145 static int32_t parse_atoms(mp4ff_t * f, int meta_only)
1148 uint8_t atom_type = 0;
1149 uint8_t header_size = 0;
1152 f->stream->read_error = 0;
1155 atom_read_header(f, &atom_type, &header_size)) != 0) {
1156 f->file_size += size;
1157 f->last_atom = atom_type;
1159 if (atom_type == ATOM_MOOV && size > header_size) {
1160 f->moov_offset = get_position(f) - header_size;
1161 f->moov_size = size;
1164 /* parse subatoms */
1165 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1166 set_position(f, get_position(f) + size - header_size);
1167 } else if (atom_type < SUBATOMIC) {
1168 parse_sub_atoms(f, size - header_size, meta_only);
1170 /* skip this atom */
1171 set_position(f, get_position(f) + size - header_size);
1178 void mp4ff_get_decoder_config(const mp4ff_t * f, const int track,
1179 unsigned char **ppBuf, unsigned int *pBufSize)
1181 if (track >= f->total_tracks) {
1187 if (f->track[track]->decoderConfig == NULL
1188 || f->track[track]->decoderConfigLen == 0) {
1192 *ppBuf = para_malloc(f->track[track]->decoderConfigLen);
1193 memcpy(*ppBuf, f->track[track]->decoderConfig,
1194 f->track[track]->decoderConfigLen);
1195 *pBufSize = f->track[track]->decoderConfigLen;
1199 mp4ff_t *mp4ff_open_read(mp4ff_callback_t * f)
1201 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1215 static int32_t tag_delete(mp4ff_metadata_t * tags)
1219 for (i = 0; i < tags->count; i++) {
1220 free(tags->tags[i].item);
1221 free(tags->tags[i].value);
1230 void mp4ff_close(mp4ff_t * ff)
1234 for (i = 0; i < ff->total_tracks; i++) {
1236 free(ff->track[i]->stsz_table);
1237 free(ff->track[i]->stts_sample_count);
1238 free(ff->track[i]->stts_sample_delta);
1239 free(ff->track[i]->stsc_first_chunk);
1240 free(ff->track[i]->stsc_samples_per_chunk);
1241 free(ff->track[i]->stsc_sample_desc_index);
1242 free(ff->track[i]->stco_chunk_offset);
1243 free(ff->track[i]->decoderConfig);
1244 free(ff->track[i]->ctts_sample_count);
1245 free(ff->track[i]->ctts_sample_offset);
1250 tag_delete(&(ff->tags));
1254 static int32_t chunk_of_sample(const mp4ff_t * f, const int32_t track,
1255 const int32_t sample, int32_t * chunk_sample, int32_t * chunk)
1257 int32_t total_entries = 0;
1258 int32_t chunk2entry;
1259 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1263 if (f->track[track] == NULL) {
1267 total_entries = f->track[track]->stsc_entry_count;
1274 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1275 *chunk = chunk2 - chunk1;
1276 range_samples = *chunk * chunk1samples;
1278 if (sample < total + range_samples)
1281 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1284 if (chunk2entry < total_entries) {
1286 total += range_samples;
1288 } while (chunk2entry < total_entries);
1291 *chunk = (sample - total) / chunk1samples + chunk1;
1295 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1300 static int32_t chunk_to_offset(const mp4ff_t * f, const int32_t track,
1301 const int32_t chunk)
1303 const mp4ff_track_t *p_track = f->track[track];
1305 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1306 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1308 } else if (p_track->stco_entry_count) {
1309 return p_track->stco_chunk_offset[chunk - 1];
1317 static int32_t sample_range_size(const mp4ff_t * f, const int32_t track,
1318 const int32_t chunk_sample, const int32_t sample)
1321 const mp4ff_track_t *p_track = f->track[track];
1323 if (p_track->stsz_sample_size) {
1324 return (sample - chunk_sample) * p_track->stsz_sample_size;
1326 if (sample >= p_track->stsz_sample_count)
1329 for (i = chunk_sample, total = 0; i < sample; i++) {
1330 total += p_track->stsz_table[i];
1337 static int32_t sample_to_offset(const mp4ff_t * f, const int32_t track,
1338 const int32_t sample)
1340 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1342 chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1344 chunk_offset1 = chunk_to_offset(f, track, chunk);
1345 chunk_offset2 = chunk_offset1 + sample_range_size(f,
1346 track, chunk_sample, sample);
1347 return chunk_offset2;
1350 void mp4ff_set_sample_position(mp4ff_t *f, const int32_t track,
1351 const int32_t sample)
1353 int32_t offset = sample_to_offset(f, track, sample);
1354 set_position(f, offset);
1357 int32_t mp4ff_get_sample_size(const mp4ff_t *f, int track, int sample)
1359 const mp4ff_track_t *t = f->track[track];
1361 if (t->stsz_sample_size != 0)
1362 return t->stsz_sample_size;
1363 return t->stsz_table[sample];
1366 uint32_t mp4ff_get_sample_rate(const mp4ff_t * f, const int32_t track)
1368 return f->track[track]->sampleRate;
1371 uint32_t mp4ff_get_channel_count(const mp4ff_t * f, const int32_t track)
1373 return f->track[track]->channelCount;
1376 int32_t mp4ff_num_samples(const mp4ff_t * f, const int32_t track)
1381 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1382 total += f->track[track]->stts_sample_count[i];
1387 mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t * f)
1389 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1403 int32_t mp4ff_meta_get_num_items(const mp4ff_t * f)
1405 return f->tags.count;
1408 int32_t mp4ff_meta_get_by_index(const mp4ff_t * f, uint32_t index,
1409 char **item, char **value)
1411 if (index >= f->tags.count) {
1416 *item = para_strdup(f->tags.tags[index].item);
1417 *value = para_strdup(f->tags.tags[index].value);
1422 static uint32_t find_atom(mp4ff_t * f, uint64_t base, uint32_t size,
1425 uint32_t remaining = size;
1426 uint64_t atom_offset = base;
1431 set_position(f, atom_offset);
1435 atom_size = read_int32(f);
1436 if (atom_size > remaining || atom_size < 8)
1438 read_data(f, atom_name, 4);
1440 if (!memcmp(atom_name, name, 4)) {
1441 set_position(f, atom_offset);
1445 remaining -= atom_size;
1446 atom_offset += atom_size;
1451 static uint32_t find_atom_v2(mp4ff_t * f, uint64_t base, uint32_t size,
1452 const char *name, uint32_t extraheaders, const char *name_inside)
1454 uint64_t first_base = (uint64_t) (-1);
1455 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1457 uint64_t mybase = get_position(f);
1458 uint32_t mysize = read_int32(f);
1460 if (first_base == (uint64_t) (-1))
1461 first_base = mybase;
1463 if (mysize < 8 + extraheaders)
1466 if (find_atom (f, mybase + (8 + extraheaders),
1467 mysize - (8 + extraheaders), name_inside)) {
1468 set_position(f, mybase);
1472 if (size <= mysize) {
1479 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1481 set_position(f, first_base);
1494 #define stricmp strcasecmp
1496 static membuffer *membuffer_create(void)
1498 const unsigned initial_size = 256;
1500 membuffer *buf = para_malloc(sizeof (membuffer));
1501 buf->data = para_malloc(initial_size);
1503 buf->allocated = initial_size;
1504 buf->error = buf->data == 0 ? 1 : 0;
1509 static unsigned membuffer_write(membuffer * buf, const void *ptr, unsigned bytes)
1511 unsigned dest_size = buf->written + bytes;
1515 if (dest_size > buf->allocated) {
1517 buf->allocated <<= 1;
1518 } while (dest_size > buf->allocated);
1521 void *newptr = realloc(buf->data, buf->allocated);
1533 memcpy((char *) buf->data + buf->written, ptr, bytes);
1534 buf->written += bytes;
1538 static unsigned membuffer_write_atom_name(membuffer * buf, const char *data)
1540 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1543 static unsigned membuffer_write_int16(membuffer * buf, uint16_t data)
1547 write_u16_be(temp, data);
1548 return membuffer_write(buf, temp, 2);
1551 static unsigned membuffer_write_int32(membuffer * buf, uint32_t data)
1554 write_u32_be(temp, data);
1555 return membuffer_write(buf, temp, 4);
1558 static void membuffer_write_track_tag(membuffer * buf, const char *name,
1559 uint32_t index, uint32_t total)
1561 membuffer_write_int32(buf,
1562 8 /*atom header */ + 8 /*data atom header */ +
1563 8 /*flags + reserved */ + 8 /*actual data */ );
1564 membuffer_write_atom_name(buf, name);
1565 membuffer_write_int32(buf,
1566 8 /*data atom header */ +
1567 8 /*flags + reserved */ + 8 /*actual data */ );
1568 membuffer_write_atom_name(buf, "data");
1569 membuffer_write_int32(buf, 0); //flags
1570 membuffer_write_int32(buf, 0); //reserved
1571 membuffer_write_int16(buf, 0);
1572 membuffer_write_int16(buf, (uint16_t) index); //track number
1573 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1574 membuffer_write_int16(buf, 0);
1577 static void membuffer_write_int16_tag(membuffer * buf, const char *name,
1580 membuffer_write_int32(buf,
1581 8 /*atom header */ + 8 /*data atom header */ +
1582 8 /*flags + reserved */ + 2 /*actual data */ );
1583 membuffer_write_atom_name(buf, name);
1584 membuffer_write_int32(buf,
1585 8 /*data atom header */ +
1586 8 /*flags + reserved */ + 2 /*actual data */ );
1587 membuffer_write_atom_name(buf, "data");
1588 membuffer_write_int32(buf, 0); //flags
1589 membuffer_write_int32(buf, 0); //reserved
1590 membuffer_write_int16(buf, value); //value
1593 static uint32_t myatoi(const char *param)
1595 return param ? atoi(param) : 0;
1598 static uint32_t meta_genre_to_index(const char *genrestr)
1601 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1602 if (!stricmp(genrestr, ID3v1GenreList[n]))
1613 static stdmeta_entry stdmetas[] = {
1614 {"\xA9" "nam", "title"},
1615 {"\xA9" "ART", "artist"},
1616 {"\xA9" "wrt", "writer"},
1617 {"\xA9" "alb", "album"},
1618 {"\xA9" "day", "date"},
1619 {"\xA9" "too", "tool"},
1620 {"\xA9" "cmt", "comment"},
1621 {"cpil", "compilation"},
1623 {"aART", "album_artist"},
1626 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1629 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1630 if (!stricmp(name, stdmetas[n].name))
1631 return stdmetas[n].atom;
1636 static void membuffer_write_std_tag(membuffer * buf, const char *name,
1641 /* special check for compilation flag */
1642 if (strcmp(name, "cpil") == 0) {
1646 membuffer_write_int32(buf,
1647 8 /*atom header */ + 8 /*data atom header */ +
1648 8 /*flags + reserved */ + strlen(value));
1649 membuffer_write_atom_name(buf, name);
1650 membuffer_write_int32(buf,
1651 8 /*data atom header */ +
1652 8 /*flags + reserved */ + strlen(value));
1653 membuffer_write_atom_name(buf, "data");
1654 membuffer_write_int32(buf, flags); //flags
1655 membuffer_write_int32(buf, 0); //reserved
1656 membuffer_write(buf, value, strlen(value));
1659 static void membuffer_write_custom_tag(membuffer * buf, const char *name,
1662 membuffer_write_int32(buf,
1663 8 /*atom header */ +
1664 0x1C /*weirdo itunes atom */ +
1665 12 /*name atom header */ + strlen(name) +
1666 16 /*data atom header + flags */ + strlen(value));
1667 membuffer_write_atom_name(buf, "----");
1668 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1669 membuffer_write_atom_name(buf, "mean");
1670 membuffer_write_int32(buf, 0);
1671 membuffer_write(buf, "com.apple.iTunes", 16);
1672 membuffer_write_int32(buf, 12 + strlen(name));
1673 membuffer_write_atom_name(buf, "name");
1674 membuffer_write_int32(buf, 0);
1675 membuffer_write(buf, name, strlen(name));
1676 membuffer_write_int32(buf,
1677 8 /*data atom header */ +
1678 8 /*flags + reserved */ + strlen(value));
1679 membuffer_write_atom_name(buf, "data");
1680 membuffer_write_int32(buf, 1); //flags
1681 membuffer_write_int32(buf, 0); //reserved
1682 membuffer_write(buf, value, strlen(value));
1685 static unsigned membuffer_error(const membuffer * buf)
1690 static void membuffer_free(membuffer * buf)
1696 static unsigned membuffer_get_size(const membuffer * buf)
1698 return buf->written;
1701 static void *membuffer_detach(membuffer * buf)
1708 ret = realloc(buf->data, buf->written);
1719 static uint32_t create_ilst(const mp4ff_metadata_t * data, void **out_buffer,
1720 uint32_t * out_size)
1722 membuffer *buf = membuffer_create();
1724 char *mask = para_calloc(data->count);
1726 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1727 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1728 const char *genre_ptr = 0, *tempo_ptr = 0;
1729 for (metaptr = 0; metaptr < data->count; metaptr++) {
1730 mp4ff_tag_t *tag = &data->tags[metaptr];
1731 if (!stricmp(tag->item, "tracknumber") || !stricmp(tag->item, "track")) {
1732 if (tracknumber_ptr == 0)
1733 tracknumber_ptr = tag->value;
1735 } else if (!stricmp(tag->item, "totaltracks")) {
1736 if (totaltracks_ptr == 0)
1737 totaltracks_ptr = tag->value;
1739 } else if (!stricmp(tag->item, "discnumber")
1740 || !stricmp(tag->item, "disc")) {
1741 if (discnumber_ptr == 0)
1742 discnumber_ptr = tag->value;
1744 } else if (!stricmp(tag->item, "totaldiscs")) {
1745 if (totaldiscs_ptr == 0)
1746 totaldiscs_ptr = tag->value;
1748 } else if (!stricmp(tag->item, "genre")) {
1750 genre_ptr = tag->value;
1752 } else if (!stricmp(tag->item, "tempo")) {
1754 tempo_ptr = tag->value;
1760 if (tracknumber_ptr)
1761 membuffer_write_track_tag(buf, "trkn",
1762 myatoi(tracknumber_ptr),
1763 myatoi(totaltracks_ptr));
1765 membuffer_write_track_tag(buf, "disk",
1766 myatoi(discnumber_ptr),
1767 myatoi(totaldiscs_ptr));
1769 membuffer_write_int16_tag(buf, "tmpo",
1770 (uint16_t) myatoi(tempo_ptr));
1773 uint32_t index = meta_genre_to_index(genre_ptr);
1775 membuffer_write_std_tag(buf, "©gen",
1778 membuffer_write_int16_tag(buf, "gnre",
1783 for (metaptr = 0; metaptr < data->count; metaptr++) {
1784 if (!mask[metaptr]) {
1785 mp4ff_tag_t *tag = &data->tags[metaptr];
1786 const char *std_meta_atom = find_standard_meta(tag->item);
1787 if (std_meta_atom) {
1788 membuffer_write_std_tag(buf, std_meta_atom,
1791 membuffer_write_custom_tag(buf, tag->item,
1799 if (membuffer_error(buf)) {
1800 membuffer_free(buf);
1804 *out_size = membuffer_get_size(buf);
1805 *out_buffer = membuffer_detach(buf);
1806 membuffer_free(buf);
1811 static void membuffer_write_atom(membuffer * buf, const char *name, unsigned size,
1814 membuffer_write_int32(buf, size + 8);
1815 membuffer_write_atom_name(buf, name);
1816 membuffer_write(buf, data, size);
1819 static void *membuffer_get_ptr(const membuffer * buf)
1824 static void membuffer_set_error(membuffer * buf)
1829 static unsigned membuffer_transfer_from_file(membuffer * buf, mp4ff_t * src,
1835 oldsize = membuffer_get_size(buf);
1836 if (membuffer_write(buf, 0, bytes) != bytes)
1839 bufptr = membuffer_get_ptr(buf);
1843 if ((unsigned)read_data(src, (char *) bufptr + oldsize, bytes) !=
1845 membuffer_set_error(buf);
1852 static uint32_t create_meta(const mp4ff_metadata_t * data, void **out_buffer,
1853 uint32_t * out_size)
1859 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1862 buf = membuffer_create();
1864 membuffer_write_int32(buf, 0);
1865 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1868 *out_size = membuffer_get_size(buf);
1869 *out_buffer = membuffer_detach(buf);
1870 membuffer_free(buf);
1874 static uint32_t create_udta(const mp4ff_metadata_t * data, void **out_buffer,
1875 uint32_t * out_size)
1881 if (!create_meta(data, &meta_buffer, &meta_size))
1884 buf = membuffer_create();
1886 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1890 *out_size = membuffer_get_size(buf);
1891 *out_buffer = membuffer_detach(buf);
1892 membuffer_free(buf);
1896 static uint32_t fix_byte_order_32(uint32_t src)
1898 return read_u32_be(&src);
1901 static uint32_t modify_moov(mp4ff_t * f, const mp4ff_metadata_t * data,
1902 void **out_buffer, uint32_t * out_size)
1904 uint64_t total_base = f->moov_offset + 8;
1905 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1907 uint64_t udta_offset, meta_offset, ilst_offset;
1908 uint32_t udta_size, meta_size, ilst_size;
1910 uint32_t new_ilst_size;
1911 void *new_ilst_buffer;
1916 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1918 void *new_udta_buffer;
1919 uint32_t new_udta_size;
1920 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1923 buf = membuffer_create();
1924 set_position(f, total_base);
1925 membuffer_transfer_from_file(buf, f, total_size);
1927 membuffer_write_atom(buf, "udta", new_udta_size,
1930 free(new_udta_buffer);
1932 *out_size = membuffer_get_size(buf);
1933 *out_buffer = membuffer_detach(buf);
1934 membuffer_free(buf);
1937 udta_offset = get_position(f);
1938 udta_size = read_int32(f);
1939 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
1941 void *new_meta_buffer;
1942 uint32_t new_meta_size;
1943 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
1946 buf = membuffer_create();
1947 set_position(f, total_base);
1948 membuffer_transfer_from_file(buf, f,
1949 (uint32_t)(udta_offset - total_base));
1951 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
1952 membuffer_write_atom_name(buf, "udta");
1953 membuffer_transfer_from_file(buf, f, udta_size);
1955 membuffer_write_atom(buf, "meta", new_meta_size,
1957 free(new_meta_buffer);
1959 *out_size = membuffer_get_size(buf);
1960 *out_buffer = membuffer_detach(buf);
1961 membuffer_free(buf);
1964 meta_offset = get_position(f);
1965 meta_size = read_int32(f);
1966 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
1967 return 0; //shouldn't happen, find_atom_v2 above takes care of it
1968 ilst_offset = get_position(f);
1969 ilst_size = read_int32(f);
1971 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
1974 size_delta = new_ilst_size - (ilst_size - 8);
1976 *out_size = total_size + size_delta;
1977 *out_buffer = para_malloc(*out_size);
1978 p_out = (uint8_t *) * out_buffer;
1980 set_position(f, total_base);
1982 (uint32_t) (udta_offset - total_base));
1983 p_out += (uint32_t) (udta_offset - total_base);
1984 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1986 read_data(f, p_out, 4);
1989 (uint32_t) (meta_offset - udta_offset - 8));
1990 p_out += (uint32_t) (meta_offset - udta_offset - 8);
1991 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1993 read_data(f, p_out, 4);
1996 (uint32_t) (ilst_offset - meta_offset - 8));
1997 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
1998 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2000 read_data(f, p_out, 4);
2003 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2004 p_out += new_ilst_size;
2006 set_position(f, ilst_offset + ilst_size);
2007 read_data(f, p_out, (uint32_t) (total_size
2008 - (ilst_offset - total_base) - ilst_size));
2010 free(new_ilst_buffer);
2015 static int32_t write_data(mp4ff_t * f, void *data, uint32_t size)
2019 result = f->stream->write(f->stream->user_data, data, size);
2021 f->current_position += size;
2026 static int32_t write_int32(mp4ff_t * f, const uint32_t data)
2029 write_u32_be(temp, data);
2030 return write_data(f, temp, sizeof(temp));
2033 static int32_t truncate_stream(mp4ff_t * f)
2035 return f->stream->truncate(f->stream->user_data);
2038 int32_t mp4ff_meta_update(mp4ff_callback_t * f, const mp4ff_metadata_t * data)
2040 void *new_moov_data;
2041 uint32_t new_moov_size;
2043 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
2045 set_position(ff, 0);
2049 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2054 /* copy moov atom to end of the file */
2055 if (ff->last_atom != ATOM_MOOV) {
2056 char *free_data = "free";
2058 /* rename old moov to free */
2059 set_position(ff, ff->moov_offset + 4);
2060 write_data(ff, free_data, 4);
2062 set_position(ff, ff->file_size);
2063 write_int32(ff, new_moov_size + 8);
2064 write_data(ff, "moov", 4);
2065 write_data(ff, new_moov_data, new_moov_size);
2067 set_position(ff, ff->moov_offset);
2068 write_int32(ff, new_moov_size + 8);
2069 write_data(ff, "moov", 4);
2070 write_data(ff, new_moov_data, new_moov_size);
2073 truncate_stream(ff);
2079 /* find a metadata item by name */
2080 /* returns 0 if item found, 1 if no such item */
2081 static int32_t meta_find_by_name(const mp4ff_t * f, const char *item,
2086 for (i = 0; i < f->tags.count; i++) {
2087 if (!stricmp(f->tags.tags[i].item, item)) {
2088 *value = para_strdup(f->tags.tags[i].value);
2099 int32_t mp4ff_meta_get_artist(const mp4ff_t * f, char **value)
2101 return meta_find_by_name(f, "artist", value);
2104 int32_t mp4ff_meta_get_title(const mp4ff_t * f, char **value)
2106 return meta_find_by_name(f, "title", value);
2109 int32_t mp4ff_meta_get_date(const mp4ff_t * f, char **value)
2111 return meta_find_by_name(f, "date", value);
2114 int32_t mp4ff_meta_get_album(const mp4ff_t * f, char **value)
2116 return meta_find_by_name(f, "album", value);
2119 int32_t mp4ff_meta_get_comment(const mp4ff_t * f, char **value)
2121 return meta_find_by_name(f, "comment", value);