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 read_int32(f); /* creation_time */
674 read_int32(f); /* modification_time */
675 f->time_scale = read_int32(f);
676 f->duration = read_int32(f);
677 read_int32(f); /* preferred_rate */
678 read_int16(f); /* preferred_volume */
679 for (i = 0; i < 10; i++)
680 read_char(f); /* reserved */
681 for (i = 0; i < 9; i++)
682 read_int32(f); /* matrix */
683 read_int32(f); /* preview_time */
684 read_int32(f); /* preview_duration */
685 read_int32(f); /* poster_time */
686 read_int32(f); /* selection_time */
687 read_int32(f); /* selection_duration */
688 read_int32(f); /* current_time */
689 read_int32(f); /* next_track_id */
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);