2 * Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com
3 * FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
14 int32_t mp4ff_total_tracks(const mp4ff_t * f)
16 return f->total_tracks;
19 static int32_t read_data(mp4ff_t * f, void *data, uint32_t size)
23 result = f->stream->read(f->stream->user_data, data, size);
26 f->stream->read_error++;
28 f->current_position += size;
33 /* parse atom header size */
34 static int32_t atom_get_size(const int8_t * data)
39 a = (uint8_t) data[0];
40 b = (uint8_t) data[1];
41 c = (uint8_t) data[2];
42 d = (uint8_t) data[3];
44 result = (a << 24) | (b << 16) | (c << 8) | d;
45 return (int32_t) result;
48 static uint64_t read_int64(mp4ff_t * f)
54 read_data(f, data, 8);
56 for (i = 0; i < 8; i++) {
57 result |= ((uint64_t) data[i]) << ((7 - i) * 8);
63 /* comnapre 2 atom names, returns 1 for equal, 0 for unequal */
64 static int32_t atom_compare(const int8_t a1, const int8_t b1,
65 const int8_t c1, const int8_t d1,
66 const int8_t a2, const int8_t b2,
67 const int8_t c2, const int8_t d2)
69 if (a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2)
77 #define TRACK_SYSTEM 3
78 #define TRACK_UNKNOWN 0
80 /* atoms with subatoms */
88 #define ATOM_ILST 8 /* iTunes Metadata list */
90 #define ATOM_ARTIST 10
91 #define ATOM_WRITER 11
95 #define ATOM_COMMENT 15
96 #define ATOM_GENRE1 16
99 #define ATOM_COMPILATION 19
100 #define ATOM_GENRE2 20
101 #define ATOM_TEMPO 21
102 #define ATOM_COVER 22
107 #define SUBATOMIC 128
109 /* atoms without subatoms */
110 #define ATOM_FTYP 129
111 #define ATOM_MDAT 130
112 #define ATOM_MVHD 131
113 #define ATOM_TKHD 132
114 #define ATOM_TREF 133
115 #define ATOM_MDHD 134
116 #define ATOM_VMHD 135
117 #define ATOM_SMHD 136
118 #define ATOM_HMHD 137
119 #define ATOM_STSD 138
120 #define ATOM_STTS 139
121 #define ATOM_STSZ 140
122 #define ATOM_STZ2 141
123 #define ATOM_STCO 142
124 #define ATOM_STSC 143
125 #define ATOM_MP4A 144
126 #define ATOM_MP4V 145
127 #define ATOM_MP4S 146
128 #define ATOM_ESDS 147
129 #define ATOM_META 148 /* iTunes Metadata box */
130 #define ATOM_NAME 149 /* iTunes Metadata name box */
131 #define ATOM_DATA 150 /* iTunes Metadata data box */
132 #define ATOM_CTTS 151
133 #define ATOM_FRMA 152
134 #define ATOM_IVIV 153
135 #define ATOM_PRIV 154
136 #define ATOM_USER 155
138 #define ATOM_ALBUM_ARTIST 157
139 #define ATOM_CONTENTGROUP 158
140 #define ATOM_LYRICS 159
141 #define ATOM_DESCRIPTION 160
142 #define ATOM_NETWORK 161
143 #define ATOM_SHOW 162
144 #define ATOM_EPISODENAME 163
145 #define ATOM_SORTTITLE 164
146 #define ATOM_SORTALBUM 165
147 #define ATOM_SORTARTIST 166
148 #define ATOM_SORTALBUMARTIST 167
149 #define ATOM_SORTWRITER 168
150 #define ATOM_SORTSHOW 169
151 #define ATOM_SEASON 170
152 #define ATOM_EPISODE 171
153 #define ATOM_PODCAST 172
155 #define ATOM_UNKNOWN 255
156 #define ATOM_FREE ATOM_UNKNOWN
157 #define ATOM_SKIP ATOM_UNKNOWN
159 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
161 static uint8_t atom_name_to_type(const int8_t a, const int8_t b,
162 const int8_t c, const int8_t d)
165 if (atom_compare(a, b, c, d, 'm', 'o', 'o', 'v'))
167 else if (atom_compare(a, b, c, d, 'm', 'i', 'n', 'f'))
169 else if (atom_compare(a, b, c, d, 'm', 'd', 'i', 'a'))
171 else if (atom_compare(a, b, c, d, 'm', 'd', 'a', 't'))
173 else if (atom_compare(a, b, c, d, 'm', 'd', 'h', 'd'))
175 else if (atom_compare(a, b, c, d, 'm', 'v', 'h', 'd'))
177 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'a'))
179 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'v'))
181 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 's'))
183 else if (atom_compare(a, b, c, d, 'm', 'e', 't', 'a'))
185 } else if (a == 't') {
186 if (atom_compare(a, b, c, d, 't', 'r', 'a', 'k'))
188 else if (atom_compare(a, b, c, d, 't', 'k', 'h', 'd'))
190 else if (atom_compare(a, b, c, d, 't', 'r', 'e', 'f'))
192 else if (atom_compare(a, b, c, d, 't', 'r', 'k', 'n'))
194 else if (atom_compare(a, b, c, d, 't', 'm', 'p', 'o'))
196 else if (atom_compare(a, b, c, d, 't', 'v', 'n', 'n'))
198 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'h'))
200 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 'n'))
201 return ATOM_EPISODENAME;
202 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'n'))
204 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 's'))
206 } else if (a == 's') {
207 if (atom_compare(a, b, c, d, 's', 't', 'b', 'l'))
209 else if (atom_compare(a, b, c, d, 's', 'm', 'h', 'd'))
211 else if (atom_compare(a, b, c, d, 's', 't', 's', 'd'))
213 else if (atom_compare(a, b, c, d, 's', 't', 't', 's'))
215 else if (atom_compare(a, b, c, d, 's', 't', 'c', 'o'))
217 else if (atom_compare(a, b, c, d, 's', 't', 's', 'c'))
219 else if (atom_compare(a, b, c, d, 's', 't', 's', 'z'))
221 else if (atom_compare(a, b, c, d, 's', 't', 'z', '2'))
223 else if (atom_compare(a, b, c, d, 's', 'k', 'i', 'p'))
225 else if (atom_compare(a, b, c, d, 's', 'i', 'n', 'f'))
227 else if (atom_compare(a, b, c, d, 's', 'c', 'h', 'i'))
229 else if (atom_compare(a, b, c, d, 's', 'o', 'n', 'm'))
230 return ATOM_SORTTITLE;
231 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'l'))
232 return ATOM_SORTALBUM;
233 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'r'))
234 return ATOM_SORTARTIST;
235 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'a'))
236 return ATOM_SORTALBUMARTIST;
237 else if (atom_compare(a, b, c, d, 's', 'o', 'c', 'o'))
238 return ATOM_SORTWRITER;
239 else if (atom_compare(a, b, c, d, 's', 'o', 's', 'n'))
240 return ATOM_SORTSHOW;
241 } else if (a == COPYRIGHT_SYMBOL) {
242 if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'n', 'a', 'm'))
244 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'A', 'R', 'T'))
246 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'w', 'r', 't'))
248 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'a', 'l', 'b'))
250 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'd', 'a', 'y'))
252 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 't', 'o', 'o'))
254 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'c', 'm', 't'))
256 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'e', 'n'))
258 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'r', 'p'))
259 return ATOM_CONTENTGROUP;
260 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'l', 'y', 'r'))
264 if (atom_compare(a, b, c, d, 'e', 'd', 't', 's'))
266 else if (atom_compare(a, b, c, d, 'e', 's', 'd', 's'))
268 else if (atom_compare(a, b, c, d, 'f', 't', 'y', 'p'))
270 else if (atom_compare(a, b, c, d, 'f', 'r', 'e', 'e'))
272 else if (atom_compare(a, b, c, d, 'h', 'm', 'h', 'd'))
274 else if (atom_compare(a, b, c, d, 'v', 'm', 'h', 'd'))
276 else if (atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
278 else if (atom_compare(a, b, c, d, 'i', 'l', 's', 't'))
280 else if (atom_compare(a, b, c, d, 'n', 'a', 'm', 'e'))
282 else if (atom_compare(a, b, c, d, 'd', 'a', 't', 'a'))
284 else if (atom_compare(a, b, c, d, 'd', 'i', 's', 'k'))
286 else if (atom_compare(a, b, c, d, 'g', 'n', 'r', 'e'))
288 else if (atom_compare(a, b, c, d, 'c', 'o', 'v', 'r'))
290 else if (atom_compare(a, b, c, d, 'c', 'p', 'i', 'l'))
291 return ATOM_COMPILATION;
292 else if (atom_compare(a, b, c, d, 'c', 't', 't', 's'))
294 else if (atom_compare(a, b, c, d, 'd', 'r', 'm', 's'))
296 else if (atom_compare(a, b, c, d, 'f', 'r', 'm', 'a'))
298 else if (atom_compare(a, b, c, d, 'p', 'r', 'i', 'v'))
300 else if (atom_compare(a, b, c, d, 'i', 'v', 'i', 'v'))
302 else if (atom_compare(a, b, c, d, 'u', 's', 'e', 'r'))
304 else if (atom_compare(a, b, c, d, 'k', 'e', 'y', ' '))
306 else if (atom_compare(a, b, c, d, 'a', 'A', 'R', 'T'))
307 return ATOM_ALBUM_ARTIST;
308 else if (atom_compare(a, b, c, d, 'd', 'e', 's', 'c'))
309 return ATOM_DESCRIPTION;
310 else if (atom_compare(a, b, c, d, 'p', 'c', 's', 't'))
316 /* read atom header, return atom size, atom size is with header included */
317 static uint64_t atom_read_header(mp4ff_t * f, uint8_t * atom_type,
318 uint8_t * header_size)
322 int8_t atom_header[8];
324 ret = read_data(f, atom_header, 8);
328 size = atom_get_size(atom_header);
331 /* check for 64 bit atom size */
334 size = read_int64(f);
336 *atom_type = atom_name_to_type(atom_header[4], atom_header[5],
337 atom_header[6], atom_header[7]);
341 static int64_t get_position(const mp4ff_t * f)
343 return f->current_position;
346 static int need_parse_when_meta_only(uint8_t atom_type)
367 static int32_t set_position(mp4ff_t * f, const int64_t position)
369 f->stream->seek(f->stream->user_data, position);
370 f->current_position = position;
375 static void track_add(mp4ff_t * f)
379 if (f->total_tracks > MAX_TRACKS) {
384 f->track[f->total_tracks - 1] = para_calloc(sizeof (mp4ff_track_t));
387 static uint8_t read_char(mp4ff_t * f)
390 read_data(f, &output, 1);
394 static uint32_t read_int24(mp4ff_t * f)
400 read_data(f, data, 3);
401 a = (uint8_t) data[0];
402 b = (uint8_t) data[1];
403 c = (uint8_t) data[2];
405 result = (a << 16) | (b << 8) | c;
406 return (uint32_t) result;
409 static uint32_t read_int32(mp4ff_t * f)
415 read_data(f, data, 4);
416 a = (uint8_t) data[0];
417 b = (uint8_t) data[1];
418 c = (uint8_t) data[2];
419 d = (uint8_t) data[3];
421 result = (a << 24) | (b << 16) | (c << 8) | d;
422 return (uint32_t) result;
425 static int32_t read_stsz(mp4ff_t * f)
430 if (f->total_tracks == 0)
432 t = f->track[f->total_tracks - 1];
433 read_char(f); /* version */
434 read_int24(f); /* flags */
435 t->stsz_sample_size = read_int32(f);
436 t->stsz_sample_count = read_int32(f);
437 if (t->stsz_sample_size != 0)
439 t->stsz_table = para_malloc(t->stsz_sample_count * sizeof(int32_t));
440 for (i = 0; i < t->stsz_sample_count && !f->stream->read_error; i++)
441 t->stsz_table[i] = read_int32(f);
445 static int32_t read_stts(mp4ff_t * f)
451 if (f->total_tracks == 0)
453 t = f->track[f->total_tracks - 1];
454 if (t->stts_entry_count)
456 read_char(f); /* version */
457 read_int24(f); /* flags */
458 t->stts_entry_count = read_int32(f);
460 t->stts_sample_count = para_malloc(t->stts_entry_count
462 t->stts_sample_delta = para_malloc(t->stts_entry_count
465 for (i = 0; i < t->stts_entry_count && !f->stream->read_error; i++) {
466 t->stts_sample_count[i] = read_int32(f);
467 t->stts_sample_delta[i] = read_int32(f);
472 static int32_t read_ctts(mp4ff_t * f)
477 if (f->total_tracks == 0)
479 t = f->track[f->total_tracks - 1];
480 if (t->ctts_entry_count)
483 read_char(f); /* version */
484 read_int24(f); /* flags */
485 t->ctts_entry_count = read_int32(f);
487 t->ctts_sample_count = para_malloc(t->ctts_entry_count
489 t->ctts_sample_offset = para_malloc(t->ctts_entry_count
493 for (i = 0; i < t->ctts_entry_count && !f->stream->read_error; i++) {
494 t->ctts_sample_count[i] = read_int32(f);
495 t->ctts_sample_offset[i] = read_int32(f);
500 static int32_t read_stsc(mp4ff_t * f)
505 if (f->total_tracks == 0)
507 t = f->track[f->total_tracks - 1];
509 read_char(f); /* version */
510 read_int24(f); /* flags */
511 t->stsc_entry_count = read_int32(f);
512 t->stsc_first_chunk = para_malloc(t->stsc_entry_count * sizeof(int32_t));
513 t->stsc_samples_per_chunk = para_malloc(t->stsc_entry_count
515 t->stsc_sample_desc_index = para_malloc(t->stsc_entry_count *
519 for (i = 0; i < t->stsc_entry_count && !f->stream->read_error; i++) {
520 t->stsc_first_chunk[i] = read_int32(f);
521 t->stsc_samples_per_chunk[i] = read_int32(f);
522 t->stsc_sample_desc_index[i] = read_int32(f);
527 static int32_t read_stco(mp4ff_t * f)
532 if (f->total_tracks == 0)
534 t = f->track[f->total_tracks - 1];
536 read_char(f); /* version */
537 read_int24(f); /* flags */
538 t->stco_entry_count = read_int32(f);
539 t->stco_chunk_offset = para_malloc(t->stco_entry_count
542 for (i = 0; i < t->stco_entry_count && !f->stream->read_error; i++)
543 t->stco_chunk_offset[i] = read_int32(f);
547 static uint16_t read_int16(mp4ff_t * f)
553 read_data(f, data, 2);
554 a = (uint8_t) data[0];
555 b = (uint8_t) data[1];
557 result = (a << 8) | b;
558 return (uint16_t) result;
561 static uint32_t read_mp4_descr_length(mp4ff_t * f)
564 uint8_t numBytes = 0;
570 length = (length << 7) | (b & 0x7F);
571 } while ((b & 0x80) && numBytes < 4);
575 static int32_t read_esds(mp4ff_t * f)
581 if (f->total_tracks == 0)
583 t = f->track[f->total_tracks - 1];
584 read_char(f); /* version */
585 read_int24(f); /* flags */
586 /* get and verify ES_DescrTag */
590 if (read_mp4_descr_length(f) < 5 + 15) {
600 /* get and verify DecoderConfigDescrTab */
601 if (read_char(f) != 0x04) {
606 temp = read_mp4_descr_length(f);
610 t->audioType = read_char(f);
611 read_int32(f); //0x15000414 ????
612 t->maxBitrate = read_int32(f);
613 t->avgBitrate = read_int32(f);
615 /* get and verify DecSpecificInfoTag */
616 if (read_char(f) != 0x05) {
621 t->decoderConfigLen = read_mp4_descr_length(f);
622 free(t->decoderConfig);
623 t->decoderConfig = para_malloc(t->decoderConfigLen);
624 read_data(f, t->decoderConfig, t->decoderConfigLen);
625 /* will skip the remainder of the atom */
629 static int32_t read_mp4a(mp4ff_t * f)
632 uint8_t atom_type = 0;
633 uint8_t header_size = 0;
636 if (f->total_tracks == 0)
638 t = f->track[f->total_tracks - 1];
640 for (i = 0; i < 6; i++) {
641 read_char(f); /* reserved */
643 /* data_reference_index */ read_int16(f);
645 read_int32(f); /* reserved */
646 read_int32(f); /* reserved */
648 t->channelCount = read_int16(f);
649 t->sampleSize = read_int16(f);
654 t->sampleRate = read_int16(f);
658 atom_read_header(f, &atom_type, &header_size);
659 if (atom_type == ATOM_ESDS)
664 static int32_t read_stsd(mp4ff_t * f)
667 uint8_t header_size = 0;
671 if (f->total_tracks == 0)
673 t = f->track[f->total_tracks - 1];
675 read_char(f); /* version */
676 read_int24(f); /* flags */
678 t->stsd_entry_count = read_int32(f);
681 for (i = 0; i < t->stsd_entry_count && !f->stream->read_error; i++) {
682 uint64_t skip = get_position(f);
684 uint8_t atom_type = 0;
685 size = atom_read_header(f, &atom_type, &header_size);
688 if (atom_type == ATOM_MP4A) {
689 t->type = TRACK_AUDIO;
691 } else if (atom_type == ATOM_MP4V) {
692 t->type = TRACK_VIDEO;
693 } else if (atom_type == ATOM_MP4S) {
694 t->type = TRACK_SYSTEM;
696 t->type = TRACK_UNKNOWN;
698 set_position(f, skip);
704 static int32_t read_mvhd(mp4ff_t * f)
708 read_char(f); /* version */
709 read_int24(f); /* flags */
710 /* creation_time */ read_int32(f);
711 /* modification_time */ read_int32(f);
712 f->time_scale = read_int32(f);
713 f->duration = read_int32(f);
714 /* preferred_rate */ read_int32(f);
715 /*mp4ff_read_fixed32(f); */
716 /* preferred_volume */ read_int16(f);
717 /*mp4ff_read_fixed16(f); */
718 for (i = 0; i < 10; i++) {
719 /* reserved */ read_char(f);
721 for (i = 0; i < 9; i++) {
722 read_int32(f); /* matrix */
724 /* preview_time */ read_int32(f);
725 /* preview_duration */ read_int32(f);
726 /* poster_time */ read_int32(f);
727 /* selection_time */ read_int32(f);
728 /* selection_duration */ read_int32(f);
729 /* current_time */ read_int32(f);
730 /* next_track_id */ read_int32(f);
735 static int32_t tag_add_field(mp4ff_metadata_t * tags, const char *item,
736 const char *value, int32_t len)
738 void *backup = (void *) tags->tags;
740 if (!item || (item && !*item) || !value)
743 tags->tags = (mp4ff_tag_t *) realloc(tags->tags,
744 (tags->count + 1) * sizeof (mp4ff_tag_t));
749 tags->tags[tags->count].item = para_strdup(item);
750 tags->tags[tags->count].len = len;
752 tags->tags[tags->count].value = para_malloc(len + 1);
753 memcpy(tags->tags[tags->count].value, value, len);
754 tags->tags[tags->count].value[len] = 0;
756 tags->tags[tags->count].value = para_strdup(value);
763 static const char *ID3v1GenreList[] = {
764 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
765 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
766 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
767 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
768 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
769 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
770 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
771 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
772 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
773 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
774 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
775 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
776 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
777 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
778 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
779 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
780 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
781 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
782 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
783 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
784 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
785 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
786 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
787 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
788 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
789 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
790 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
791 "Anime", "JPop", "SynthPop",
794 static const char *meta_index_to_genre(uint32_t idx)
796 if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
797 return ID3v1GenreList[idx - 1];
803 static char *read_string(mp4ff_t *f, uint32_t length)
805 char *str = para_malloc(length + 1);
806 if ((uint32_t)read_data(f, str, length) != length) {
814 static int32_t set_metadata_name(const uint8_t atom_type, char **name)
816 static char *tag_names[] = {
817 "unknown", "title", "artist", "writer", "album",
818 "date", "tool", "comment", "genre", "track",
819 "disc", "compilation", "genre", "tempo", "cover",
820 "album_artist", "contentgroup", "lyrics", "description",
821 "network", "show", "episodename",
822 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
823 "sortwriter", "sortshow",
824 "season", "episode", "podcast"
859 case ATOM_COMPILATION:
871 case ATOM_ALBUM_ARTIST:
874 case ATOM_CONTENTGROUP:
880 case ATOM_DESCRIPTION:
889 case ATOM_EPISODENAME:
898 case ATOM_SORTARTIST:
901 case ATOM_SORTALBUMARTIST:
904 case ATOM_SORTWRITER:
924 *name = para_strdup(tag_names[tag_idx]);
928 static uint32_t min_body_size(const uint8_t atom_type)
935 return sizeof (char) /* version */
936 + sizeof(uint8_t) * 3 /* flags */
937 + sizeof(uint32_t) /* reserved */
938 + sizeof(uint16_t) /* leading uint16_t */
939 + sizeof(uint16_t) /* track */
940 + sizeof(uint16_t); /* totaltracks */
942 return sizeof (char) /* version */
943 + sizeof(uint8_t) * 3 /* flags */
944 + sizeof(uint32_t) /* reserved */
945 + sizeof(uint16_t) /* disc */
946 + sizeof(uint16_t); /* totaldiscs */
947 default: assert(false);
951 static int32_t parse_tag(mp4ff_t * f, const uint8_t parent,
955 uint8_t header_size = 0;
956 uint64_t subsize, sumsize;
965 sumsize < size && !f->stream->read_error; /* CVE-2017-9222 */
966 set_position(f, destpos), sumsize += subsize
968 subsize = atom_read_header(f, &atom_type, &header_size);
969 destpos = get_position(f) + subsize - header_size;
972 if (atom_type == ATOM_NAME) {
973 read_char(f); /* version */
974 read_int24(f); /* flags */
976 name = read_string(f, subsize - (header_size + 4));
979 if (atom_type != ATOM_DATA)
981 read_char(f); /* version */
982 read_int24(f); /* flags */
983 read_int32(f); /* reserved */
985 /* some need special attention */
986 if (parent == ATOM_GENRE2 || parent == ATOM_TEMPO) {
988 if (subsize - header_size < min_body_size(parent))
991 if (parent == ATOM_TEMPO) {
993 sprintf(temp, "%.5u BPM", val);
994 tag_add_field(&(f-> tags), "tempo",
997 const char *tmp = meta_index_to_genre(val);
999 tag_add_field (&(f->tags),
1003 } else if (parent == ATOM_TRACK || parent == ATOM_DISC) {
1004 uint16_t index, total;
1006 if (subsize - header_size < min_body_size(parent))
1009 index = read_int16(f);
1010 total = read_int16(f);
1011 if (parent == ATOM_TRACK)
1013 sprintf(temp, "%d", index);
1014 tag_add_field(&(f->tags), parent == ATOM_TRACK?
1015 "track" : "disc", temp, -1);
1017 sprintf(temp, "%d", total);
1018 tag_add_field(& (f-> tags),
1019 parent == ATOM_TRACK?
1020 "totaltracks" : "totaldiscs", temp, -1);
1025 data = read_string(f, subsize - (header_size + 8));
1026 len = subsize - (header_size + 8);
1032 set_metadata_name(parent , &name);
1034 tag_add_field(&(f->tags), name, data, len);
1043 static int32_t read_mdhd(mp4ff_t * f)
1049 if (f->total_tracks == 0)
1051 t = f->track[f->total_tracks - 1];
1053 version = read_int32(f);
1055 read_int64(f); //creation-time
1056 read_int64(f); //modification-time
1057 t->timeScale = read_int32(f); //timescale
1058 t->duration = read_int64(f); //duration
1059 } else { //version == 0
1062 read_int32(f); //creation-time
1063 read_int32(f); //modification-time
1064 t->timeScale = read_int32(f); //timescale
1065 temp = read_int32(f);
1066 t->duration = (temp == (uint32_t) (-1))?
1067 (uint64_t) (-1) : (uint64_t) (temp);
1074 static int32_t parse_metadata(mp4ff_t * f, const int32_t size)
1076 uint64_t subsize, sumsize = 0;
1078 uint8_t header_size = 0;
1080 while (sumsize < size) {
1081 subsize = atom_read_header(f, &atom_type, &header_size);
1084 parse_tag(f, atom_type, (uint32_t)(subsize - header_size));
1091 static int32_t read_meta(mp4ff_t * f, const uint64_t size)
1093 uint64_t subsize, sumsize = 0;
1095 uint8_t header_size = 0;
1097 read_char(f); /* version */
1098 read_int24(f); /* flags */
1100 while (sumsize < (size - (header_size + 4))) {
1101 subsize = atom_read_header(f, &atom_type, &header_size);
1102 if (subsize <= header_size + 4)
1104 if (atom_type == ATOM_ILST) {
1105 parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1107 set_position(f, get_position(f) + subsize - header_size);
1115 static int32_t atom_read(mp4ff_t *f, const int32_t size,
1116 const uint8_t atom_type)
1118 uint64_t dest_position = get_position(f) + size - 8;
1119 if (atom_type == ATOM_STSZ) {
1120 /* sample size box */
1122 } else if (atom_type == ATOM_STTS) {
1123 /* time to sample box */
1125 } else if (atom_type == ATOM_CTTS) {
1126 /* composition offset box */
1128 } else if (atom_type == ATOM_STSC) {
1129 /* sample to chunk box */
1131 } else if (atom_type == ATOM_STCO) {
1132 /* chunk offset box */
1134 } else if (atom_type == ATOM_STSD) {
1135 /* sample description box */
1137 } else if (atom_type == ATOM_MVHD) {
1138 /* movie header box */
1140 } else if (atom_type == ATOM_MDHD) {
1143 } else if (atom_type == ATOM_META) {
1144 /* iTunes Metadata box */
1148 set_position(f, dest_position);
1152 /* parse atoms that are sub atoms of other atoms */
1153 static int32_t parse_sub_atoms(mp4ff_t * f, const uint64_t total_size, int meta_only)
1156 uint8_t atom_type = 0;
1157 uint64_t counted_size = 0;
1158 uint8_t header_size = 0;
1160 while (counted_size < total_size) {
1161 size = atom_read_header(f, &atom_type, &header_size);
1162 counted_size += size;
1164 /* check for end of file */
1168 /* we're starting to read a new track, update index,
1169 * so that all data and tables get written in the right place
1171 if (atom_type == ATOM_TRAK)
1173 /* parse subatoms */
1174 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1175 set_position(f, get_position(f) + size - header_size);
1176 } else if (atom_type < SUBATOMIC) {
1177 parse_sub_atoms(f, size - header_size, meta_only);
1179 atom_read(f, (uint32_t) size, atom_type);
1186 /* parse root atoms */
1187 static int32_t parse_atoms(mp4ff_t * f, int meta_only)
1190 uint8_t atom_type = 0;
1191 uint8_t header_size = 0;
1194 f->stream->read_error = 0;
1197 atom_read_header(f, &atom_type, &header_size)) != 0) {
1198 f->file_size += size;
1199 f->last_atom = atom_type;
1201 if (atom_type == ATOM_MOOV && size > header_size) {
1202 f->moov_offset = get_position(f) - header_size;
1203 f->moov_size = size;
1206 /* parse subatoms */
1207 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1208 set_position(f, get_position(f) + size - header_size);
1209 } else if (atom_type < SUBATOMIC) {
1210 parse_sub_atoms(f, size - header_size, meta_only);
1212 /* skip this atom */
1213 set_position(f, get_position(f) + size - header_size);
1220 void mp4ff_get_decoder_config(const mp4ff_t * f, const int track,
1221 unsigned char **ppBuf, unsigned int *pBufSize)
1223 if (track >= f->total_tracks) {
1229 if (f->track[track]->decoderConfig == NULL
1230 || f->track[track]->decoderConfigLen == 0) {
1234 *ppBuf = para_malloc(f->track[track]->decoderConfigLen);
1235 memcpy(*ppBuf, f->track[track]->decoderConfig,
1236 f->track[track]->decoderConfigLen);
1237 *pBufSize = f->track[track]->decoderConfigLen;
1241 mp4ff_t *mp4ff_open_read(mp4ff_callback_t * f)
1243 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1257 static int32_t tag_delete(mp4ff_metadata_t * tags)
1261 for (i = 0; i < tags->count; i++) {
1262 free(tags->tags[i].item);
1263 free(tags->tags[i].value);
1272 void mp4ff_close(mp4ff_t * ff)
1276 for (i = 0; i < ff->total_tracks; i++) {
1278 free(ff->track[i]->stsz_table);
1279 free(ff->track[i]->stts_sample_count);
1280 free(ff->track[i]->stts_sample_delta);
1281 free(ff->track[i]->stsc_first_chunk);
1282 free(ff->track[i]->stsc_samples_per_chunk);
1283 free(ff->track[i]->stsc_sample_desc_index);
1284 free(ff->track[i]->stco_chunk_offset);
1285 free(ff->track[i]->decoderConfig);
1286 free(ff->track[i]->ctts_sample_count);
1287 free(ff->track[i]->ctts_sample_offset);
1292 tag_delete(&(ff->tags));
1296 static int32_t chunk_of_sample(const mp4ff_t * f, const int32_t track,
1297 const int32_t sample, int32_t * chunk_sample, int32_t * chunk)
1299 int32_t total_entries = 0;
1300 int32_t chunk2entry;
1301 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1305 if (f->track[track] == NULL) {
1309 total_entries = f->track[track]->stsc_entry_count;
1316 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1317 *chunk = chunk2 - chunk1;
1318 range_samples = *chunk * chunk1samples;
1320 if (sample < total + range_samples)
1323 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1326 if (chunk2entry < total_entries) {
1328 total += range_samples;
1330 } while (chunk2entry < total_entries);
1333 *chunk = (sample - total) / chunk1samples + chunk1;
1337 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1342 static int32_t chunk_to_offset(const mp4ff_t * f, const int32_t track,
1343 const int32_t chunk)
1345 const mp4ff_track_t *p_track = f->track[track];
1347 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1348 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1350 } else if (p_track->stco_entry_count) {
1351 return p_track->stco_chunk_offset[chunk - 1];
1359 static int32_t sample_range_size(const mp4ff_t * f, const int32_t track,
1360 const int32_t chunk_sample, const int32_t sample)
1363 const mp4ff_track_t *p_track = f->track[track];
1365 if (p_track->stsz_sample_size) {
1366 return (sample - chunk_sample) * p_track->stsz_sample_size;
1368 if (sample >= p_track->stsz_sample_count)
1371 for (i = chunk_sample, total = 0; i < sample; i++) {
1372 total += p_track->stsz_table[i];
1379 static int32_t sample_to_offset(const mp4ff_t * f, const int32_t track,
1380 const int32_t sample)
1382 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1384 chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1386 chunk_offset1 = chunk_to_offset(f, track, chunk);
1387 chunk_offset2 = chunk_offset1 + sample_range_size(f,
1388 track, chunk_sample, sample);
1389 return chunk_offset2;
1392 void mp4ff_set_sample_position(mp4ff_t *f, const int32_t track,
1393 const int32_t sample)
1395 int32_t offset = sample_to_offset(f, track, sample);
1396 set_position(f, offset);
1399 int32_t mp4ff_get_sample_size(const mp4ff_t *f, int track, int sample)
1401 const mp4ff_track_t *t = f->track[track];
1403 if (t->stsz_sample_size != 0)
1404 return t->stsz_sample_size;
1405 return t->stsz_table[sample];
1408 uint32_t mp4ff_get_sample_rate(const mp4ff_t * f, const int32_t track)
1410 return f->track[track]->sampleRate;
1413 uint32_t mp4ff_get_channel_count(const mp4ff_t * f, const int32_t track)
1415 return f->track[track]->channelCount;
1418 int32_t mp4ff_num_samples(const mp4ff_t * f, const int32_t track)
1423 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1424 total += f->track[track]->stts_sample_count[i];
1429 mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t * f)
1431 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1445 int32_t mp4ff_meta_get_num_items(const mp4ff_t * f)
1447 return f->tags.count;
1450 int32_t mp4ff_meta_get_by_index(const mp4ff_t * f, uint32_t index,
1451 char **item, char **value)
1453 if (index >= f->tags.count) {
1458 *item = para_strdup(f->tags.tags[index].item);
1459 *value = para_strdup(f->tags.tags[index].value);
1464 static uint32_t find_atom(mp4ff_t * f, uint64_t base, uint32_t size,
1467 uint32_t remaining = size;
1468 uint64_t atom_offset = base;
1473 set_position(f, atom_offset);
1477 atom_size = read_int32(f);
1478 if (atom_size > remaining || atom_size < 8)
1480 read_data(f, atom_name, 4);
1482 if (!memcmp(atom_name, name, 4)) {
1483 set_position(f, atom_offset);
1487 remaining -= atom_size;
1488 atom_offset += atom_size;
1493 static uint32_t find_atom_v2(mp4ff_t * f, uint64_t base, uint32_t size,
1494 const char *name, uint32_t extraheaders, const char *name_inside)
1496 uint64_t first_base = (uint64_t) (-1);
1497 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1499 uint64_t mybase = get_position(f);
1500 uint32_t mysize = read_int32(f);
1502 if (first_base == (uint64_t) (-1))
1503 first_base = mybase;
1505 if (mysize < 8 + extraheaders)
1508 if (find_atom (f, mybase + (8 + extraheaders),
1509 mysize - (8 + extraheaders), name_inside)) {
1510 set_position(f, mybase);
1514 if (size <= mysize) {
1521 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1523 set_position(f, first_base);
1536 #define stricmp strcasecmp
1538 static membuffer *membuffer_create(void)
1540 const unsigned initial_size = 256;
1542 membuffer *buf = para_malloc(sizeof (membuffer));
1543 buf->data = para_malloc(initial_size);
1545 buf->allocated = initial_size;
1546 buf->error = buf->data == 0 ? 1 : 0;
1551 static unsigned membuffer_write(membuffer * buf, const void *ptr, unsigned bytes)
1553 unsigned dest_size = buf->written + bytes;
1557 if (dest_size > buf->allocated) {
1559 buf->allocated <<= 1;
1560 } while (dest_size > buf->allocated);
1563 void *newptr = realloc(buf->data, buf->allocated);
1575 memcpy((char *) buf->data + buf->written, ptr, bytes);
1576 buf->written += bytes;
1580 static unsigned membuffer_write_atom_name(membuffer * buf, const char *data)
1582 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1585 static unsigned membuffer_write_int16(membuffer * buf, uint16_t data)
1587 uint8_t temp[2] = { (uint8_t) (data >> 8), (uint8_t) data };
1588 return membuffer_write(buf, temp, 2);
1591 static unsigned membuffer_write_int32(membuffer * buf, uint32_t data)
1593 uint8_t temp[4] = { (uint8_t) (data >> 24), (uint8_t) (data >> 16),
1594 (uint8_t) (data >> 8), (uint8_t) data };
1595 return membuffer_write(buf, temp, 4);
1598 static void membuffer_write_track_tag(membuffer * buf, const char *name,
1599 uint32_t index, uint32_t total)
1601 membuffer_write_int32(buf,
1602 8 /*atom header */ + 8 /*data atom header */ +
1603 8 /*flags + reserved */ + 8 /*actual data */ );
1604 membuffer_write_atom_name(buf, name);
1605 membuffer_write_int32(buf,
1606 8 /*data atom header */ +
1607 8 /*flags + reserved */ + 8 /*actual data */ );
1608 membuffer_write_atom_name(buf, "data");
1609 membuffer_write_int32(buf, 0); //flags
1610 membuffer_write_int32(buf, 0); //reserved
1611 membuffer_write_int16(buf, 0);
1612 membuffer_write_int16(buf, (uint16_t) index); //track number
1613 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1614 membuffer_write_int16(buf, 0);
1617 static void membuffer_write_int16_tag(membuffer * buf, const char *name,
1620 membuffer_write_int32(buf,
1621 8 /*atom header */ + 8 /*data atom header */ +
1622 8 /*flags + reserved */ + 2 /*actual data */ );
1623 membuffer_write_atom_name(buf, name);
1624 membuffer_write_int32(buf,
1625 8 /*data atom header */ +
1626 8 /*flags + reserved */ + 2 /*actual data */ );
1627 membuffer_write_atom_name(buf, "data");
1628 membuffer_write_int32(buf, 0); //flags
1629 membuffer_write_int32(buf, 0); //reserved
1630 membuffer_write_int16(buf, value); //value
1633 static uint32_t myatoi(const char *param)
1635 return param ? atoi(param) : 0;
1638 static uint32_t meta_genre_to_index(const char *genrestr)
1641 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1642 if (!stricmp(genrestr, ID3v1GenreList[n]))
1653 static stdmeta_entry stdmetas[] = {
1654 {"\xA9" "nam", "title"},
1655 {"\xA9" "ART", "artist"},
1656 {"\xA9" "wrt", "writer"},
1657 {"\xA9" "alb", "album"},
1658 {"\xA9" "day", "date"},
1659 {"\xA9" "too", "tool"},
1660 {"\xA9" "cmt", "comment"},
1661 {"cpil", "compilation"},
1663 {"aART", "album_artist"},
1666 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1669 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1670 if (!stricmp(name, stdmetas[n].name))
1671 return stdmetas[n].atom;
1676 static void membuffer_write_std_tag(membuffer * buf, const char *name,
1681 /* special check for compilation flag */
1682 if (strcmp(name, "cpil") == 0) {
1686 membuffer_write_int32(buf,
1687 8 /*atom header */ + 8 /*data atom header */ +
1688 8 /*flags + reserved */ + strlen(value));
1689 membuffer_write_atom_name(buf, name);
1690 membuffer_write_int32(buf,
1691 8 /*data atom header */ +
1692 8 /*flags + reserved */ + strlen(value));
1693 membuffer_write_atom_name(buf, "data");
1694 membuffer_write_int32(buf, flags); //flags
1695 membuffer_write_int32(buf, 0); //reserved
1696 membuffer_write(buf, value, strlen(value));
1699 static void membuffer_write_custom_tag(membuffer * buf, const char *name,
1702 membuffer_write_int32(buf,
1703 8 /*atom header */ +
1704 0x1C /*weirdo itunes atom */ +
1705 12 /*name atom header */ + strlen(name) +
1706 16 /*data atom header + flags */ + strlen(value));
1707 membuffer_write_atom_name(buf, "----");
1708 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1709 membuffer_write_atom_name(buf, "mean");
1710 membuffer_write_int32(buf, 0);
1711 membuffer_write(buf, "com.apple.iTunes", 16);
1712 membuffer_write_int32(buf, 12 + strlen(name));
1713 membuffer_write_atom_name(buf, "name");
1714 membuffer_write_int32(buf, 0);
1715 membuffer_write(buf, name, strlen(name));
1716 membuffer_write_int32(buf,
1717 8 /*data atom header */ +
1718 8 /*flags + reserved */ + strlen(value));
1719 membuffer_write_atom_name(buf, "data");
1720 membuffer_write_int32(buf, 1); //flags
1721 membuffer_write_int32(buf, 0); //reserved
1722 membuffer_write(buf, value, strlen(value));
1725 static unsigned membuffer_error(const membuffer * buf)
1730 static void membuffer_free(membuffer * buf)
1736 static unsigned membuffer_get_size(const membuffer * buf)
1738 return buf->written;
1741 static void *membuffer_detach(membuffer * buf)
1748 ret = realloc(buf->data, buf->written);
1759 static uint32_t create_ilst(const mp4ff_metadata_t * data, void **out_buffer,
1760 uint32_t * out_size)
1762 membuffer *buf = membuffer_create();
1764 char *mask = para_calloc(data->count);
1766 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1767 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1768 const char *genre_ptr = 0, *tempo_ptr = 0;
1769 for (metaptr = 0; metaptr < data->count; metaptr++) {
1770 mp4ff_tag_t *tag = &data->tags[metaptr];
1771 if (!stricmp(tag->item, "tracknumber") || !stricmp(tag->item, "track")) {
1772 if (tracknumber_ptr == 0)
1773 tracknumber_ptr = tag->value;
1775 } else if (!stricmp(tag->item, "totaltracks")) {
1776 if (totaltracks_ptr == 0)
1777 totaltracks_ptr = tag->value;
1779 } else if (!stricmp(tag->item, "discnumber")
1780 || !stricmp(tag->item, "disc")) {
1781 if (discnumber_ptr == 0)
1782 discnumber_ptr = tag->value;
1784 } else if (!stricmp(tag->item, "totaldiscs")) {
1785 if (totaldiscs_ptr == 0)
1786 totaldiscs_ptr = tag->value;
1788 } else if (!stricmp(tag->item, "genre")) {
1790 genre_ptr = tag->value;
1792 } else if (!stricmp(tag->item, "tempo")) {
1794 tempo_ptr = tag->value;
1800 if (tracknumber_ptr)
1801 membuffer_write_track_tag(buf, "trkn",
1802 myatoi(tracknumber_ptr),
1803 myatoi(totaltracks_ptr));
1805 membuffer_write_track_tag(buf, "disk",
1806 myatoi(discnumber_ptr),
1807 myatoi(totaldiscs_ptr));
1809 membuffer_write_int16_tag(buf, "tmpo",
1810 (uint16_t) myatoi(tempo_ptr));
1813 uint32_t index = meta_genre_to_index(genre_ptr);
1815 membuffer_write_std_tag(buf, "©gen",
1818 membuffer_write_int16_tag(buf, "gnre",
1823 for (metaptr = 0; metaptr < data->count; metaptr++) {
1824 if (!mask[metaptr]) {
1825 mp4ff_tag_t *tag = &data->tags[metaptr];
1826 const char *std_meta_atom = find_standard_meta(tag->item);
1827 if (std_meta_atom) {
1828 membuffer_write_std_tag(buf, std_meta_atom,
1831 membuffer_write_custom_tag(buf, tag->item,
1839 if (membuffer_error(buf)) {
1840 membuffer_free(buf);
1844 *out_size = membuffer_get_size(buf);
1845 *out_buffer = membuffer_detach(buf);
1846 membuffer_free(buf);
1851 static void membuffer_write_atom(membuffer * buf, const char *name, unsigned size,
1854 membuffer_write_int32(buf, size + 8);
1855 membuffer_write_atom_name(buf, name);
1856 membuffer_write(buf, data, size);
1859 static void *membuffer_get_ptr(const membuffer * buf)
1864 static void membuffer_set_error(membuffer * buf)
1869 static unsigned membuffer_transfer_from_file(membuffer * buf, mp4ff_t * src,
1875 oldsize = membuffer_get_size(buf);
1876 if (membuffer_write(buf, 0, bytes) != bytes)
1879 bufptr = membuffer_get_ptr(buf);
1883 if ((unsigned)read_data(src, (char *) bufptr + oldsize, bytes) !=
1885 membuffer_set_error(buf);
1892 static uint32_t create_meta(const mp4ff_metadata_t * data, void **out_buffer,
1893 uint32_t * out_size)
1899 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1902 buf = membuffer_create();
1904 membuffer_write_int32(buf, 0);
1905 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1908 *out_size = membuffer_get_size(buf);
1909 *out_buffer = membuffer_detach(buf);
1910 membuffer_free(buf);
1914 static uint32_t create_udta(const mp4ff_metadata_t * data, void **out_buffer,
1915 uint32_t * out_size)
1921 if (!create_meta(data, &meta_buffer, &meta_size))
1924 buf = membuffer_create();
1926 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1930 *out_size = membuffer_get_size(buf);
1931 *out_buffer = membuffer_detach(buf);
1932 membuffer_free(buf);
1936 static uint32_t fix_byte_order_32(uint32_t src)
1939 uint32_t a, b, c, d;
1942 memcpy(data, &src, sizeof (src));
1943 a = (uint8_t) data[0];
1944 b = (uint8_t) data[1];
1945 c = (uint8_t) data[2];
1946 d = (uint8_t) data[3];
1948 result = (a << 24) | (b << 16) | (c << 8) | d;
1949 return (uint32_t) result;
1952 static uint32_t modify_moov(mp4ff_t * f, const mp4ff_metadata_t * data,
1953 void **out_buffer, uint32_t * out_size)
1955 uint64_t total_base = f->moov_offset + 8;
1956 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1958 uint64_t udta_offset, meta_offset, ilst_offset;
1959 uint32_t udta_size, meta_size, ilst_size;
1961 uint32_t new_ilst_size;
1962 void *new_ilst_buffer;
1967 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1969 void *new_udta_buffer;
1970 uint32_t new_udta_size;
1971 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1974 buf = membuffer_create();
1975 set_position(f, total_base);
1976 membuffer_transfer_from_file(buf, f, total_size);
1978 membuffer_write_atom(buf, "udta", new_udta_size,
1981 free(new_udta_buffer);
1983 *out_size = membuffer_get_size(buf);
1984 *out_buffer = membuffer_detach(buf);
1985 membuffer_free(buf);
1988 udta_offset = get_position(f);
1989 udta_size = read_int32(f);
1990 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
1992 void *new_meta_buffer;
1993 uint32_t new_meta_size;
1994 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
1997 buf = membuffer_create();
1998 set_position(f, total_base);
1999 membuffer_transfer_from_file(buf, f,
2000 (uint32_t)(udta_offset - total_base));
2002 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2003 membuffer_write_atom_name(buf, "udta");
2004 membuffer_transfer_from_file(buf, f, udta_size);
2006 membuffer_write_atom(buf, "meta", new_meta_size,
2008 free(new_meta_buffer);
2010 *out_size = membuffer_get_size(buf);
2011 *out_buffer = membuffer_detach(buf);
2012 membuffer_free(buf);
2015 meta_offset = get_position(f);
2016 meta_size = read_int32(f);
2017 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2018 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2019 ilst_offset = get_position(f);
2020 ilst_size = read_int32(f);
2022 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2025 size_delta = new_ilst_size - (ilst_size - 8);
2027 *out_size = total_size + size_delta;
2028 *out_buffer = para_malloc(*out_size);
2029 p_out = (uint8_t *) * out_buffer;
2031 set_position(f, total_base);
2033 (uint32_t) (udta_offset - total_base));
2034 p_out += (uint32_t) (udta_offset - total_base);
2035 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2037 read_data(f, p_out, 4);
2040 (uint32_t) (meta_offset - udta_offset - 8));
2041 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2042 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2044 read_data(f, p_out, 4);
2047 (uint32_t) (ilst_offset - meta_offset - 8));
2048 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2049 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2051 read_data(f, p_out, 4);
2054 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2055 p_out += new_ilst_size;
2057 set_position(f, ilst_offset + ilst_size);
2058 read_data(f, p_out, (uint32_t) (total_size
2059 - (ilst_offset - total_base) - ilst_size));
2061 free(new_ilst_buffer);
2066 static int32_t write_data(mp4ff_t * f, void *data, uint32_t size)
2070 result = f->stream->write(f->stream->user_data, data, size);
2072 f->current_position += size;
2077 static int32_t write_int32(mp4ff_t * f, const uint32_t data)
2080 uint32_t a, b, c, d;
2083 *(uint32_t *) temp = data;
2084 a = (uint8_t) temp[0];
2085 b = (uint8_t) temp[1];
2086 c = (uint8_t) temp[2];
2087 d = (uint8_t) temp[3];
2089 result = (a << 24) | (b << 16) | (c << 8) | d;
2091 return write_data(f, (uint8_t *) & result, sizeof (result));
2094 static int32_t truncate_stream(mp4ff_t * f)
2096 return f->stream->truncate(f->stream->user_data);
2099 int32_t mp4ff_meta_update(mp4ff_callback_t * f, const mp4ff_metadata_t * data)
2101 void *new_moov_data;
2102 uint32_t new_moov_size;
2104 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
2106 set_position(ff, 0);
2110 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2115 /* copy moov atom to end of the file */
2116 if (ff->last_atom != ATOM_MOOV) {
2117 char *free_data = "free";
2119 /* rename old moov to free */
2120 set_position(ff, ff->moov_offset + 4);
2121 write_data(ff, free_data, 4);
2123 set_position(ff, ff->file_size);
2124 write_int32(ff, new_moov_size + 8);
2125 write_data(ff, "moov", 4);
2126 write_data(ff, new_moov_data, new_moov_size);
2128 set_position(ff, ff->moov_offset);
2129 write_int32(ff, new_moov_size + 8);
2130 write_data(ff, "moov", 4);
2131 write_data(ff, new_moov_data, new_moov_size);
2134 truncate_stream(ff);
2140 /* find a metadata item by name */
2141 /* returns 0 if item found, 1 if no such item */
2142 static int32_t meta_find_by_name(const mp4ff_t * f, const char *item,
2147 for (i = 0; i < f->tags.count; i++) {
2148 if (!stricmp(f->tags.tags[i].item, item)) {
2149 *value = para_strdup(f->tags.tags[i].value);
2160 int32_t mp4ff_meta_get_artist(const mp4ff_t * f, char **value)
2162 return meta_find_by_name(f, "artist", value);
2165 int32_t mp4ff_meta_get_title(const mp4ff_t * f, char **value)
2167 return meta_find_by_name(f, "title", value);
2170 int32_t mp4ff_meta_get_date(const mp4ff_t * f, char **value)
2172 return meta_find_by_name(f, "date", value);
2175 int32_t mp4ff_meta_get_album(const mp4ff_t * f, char **value)
2177 return meta_find_by_name(f, "album", value);
2180 int32_t mp4ff_meta_get_comment(const mp4ff_t * f, char **value)
2182 return meta_find_by_name(f, "comment", value);