2 * Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com
3 * FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
11 #include "portable_io.h"
23 int32_t stsd_entry_count;
26 int32_t stsz_sample_size;
27 int32_t stsz_sample_count;
31 int32_t stts_entry_count;
32 int32_t *stts_sample_count;
33 int32_t *stts_sample_delta;
36 int32_t stsc_entry_count;
37 int32_t *stsc_first_chunk;
38 int32_t *stsc_samples_per_chunk;
39 int32_t *stsc_sample_desc_index;
42 int32_t stco_entry_count;
43 int32_t *stco_chunk_offset;
46 int32_t ctts_entry_count;
47 int32_t *ctts_sample_count;
48 int32_t *ctts_sample_offset;
51 uint8_t *decoderConfig;
52 int32_t decoderConfigLen;
61 #define MAX_TRACKS 1024
64 /* stream to read from */
65 struct mp4ff_callback *stream;
66 int64_t current_position;
78 /* incremental track index while reading the file */
82 struct mp4ff_track *track[MAX_TRACKS];
85 struct mp4ff_metadata tags;
88 int32_t mp4ff_total_tracks(const struct mp4ff *f)
90 return f->total_tracks;
93 static int32_t read_data(struct mp4ff *f, void *data, uint32_t size)
97 result = f->stream->read(f->stream->user_data, data, size);
100 f->stream->read_error++;
102 f->current_position += size;
107 static uint64_t read_int64(struct mp4ff *f)
111 read_data(f, data, 8);
112 return read_u64_be(data);
115 /* comnapre 2 atom names, returns 1 for equal, 0 for unequal */
116 static int32_t atom_compare(int8_t a1, int8_t b1, int8_t c1, int8_t d1,
117 int8_t a2, int8_t b2, int8_t c2, int8_t d2)
119 if (a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2)
133 /* atoms with subatoms */
141 ATOM_ILST = 8, /* iTunes Metadata list */
152 ATOM_COMPILATION = 19,
162 /* atoms without subatoms */
182 ATOM_META = 148, /* iTunes Metadata box */
183 ATOM_NAME = 149, /* iTunes Metadata name box */
184 ATOM_DATA = 150, /* iTunes Metadata data box */
191 ATOM_ALBUM_ARTIST = 157,
192 ATOM_CONTENTGROUP = 158,
194 ATOM_DESCRIPTION = 160,
197 ATOM_EPISODENAME = 163,
198 ATOM_SORTTITLE = 164,
199 ATOM_SORTALBUM = 165,
200 ATOM_SORTARTIST = 166,
201 ATOM_SORTALBUMARTIST = 167,
202 ATOM_SORTWRITER = 168,
211 #define ATOM_FREE ATOM_UNKNOWN
212 #define ATOM_SKIP ATOM_UNKNOWN
214 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
216 static uint8_t atom_name_to_type(int8_t a, int8_t b, int8_t c, int8_t d)
219 if (atom_compare(a, b, c, d, 'm', 'o', 'o', 'v'))
221 else if (atom_compare(a, b, c, d, 'm', 'i', 'n', 'f'))
223 else if (atom_compare(a, b, c, d, 'm', 'd', 'i', 'a'))
225 else if (atom_compare(a, b, c, d, 'm', 'd', 'a', 't'))
227 else if (atom_compare(a, b, c, d, 'm', 'd', 'h', 'd'))
229 else if (atom_compare(a, b, c, d, 'm', 'v', 'h', 'd'))
231 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'a'))
233 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'v'))
235 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 's'))
237 else if (atom_compare(a, b, c, d, 'm', 'e', 't', 'a'))
239 } else if (a == 't') {
240 if (atom_compare(a, b, c, d, 't', 'r', 'a', 'k'))
242 else if (atom_compare(a, b, c, d, 't', 'k', 'h', 'd'))
244 else if (atom_compare(a, b, c, d, 't', 'r', 'e', 'f'))
246 else if (atom_compare(a, b, c, d, 't', 'r', 'k', 'n'))
248 else if (atom_compare(a, b, c, d, 't', 'm', 'p', 'o'))
250 else if (atom_compare(a, b, c, d, 't', 'v', 'n', 'n'))
252 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'h'))
254 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 'n'))
255 return ATOM_EPISODENAME;
256 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'n'))
258 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 's'))
260 } else if (a == 's') {
261 if (atom_compare(a, b, c, d, 's', 't', 'b', 'l'))
263 else if (atom_compare(a, b, c, d, 's', 'm', 'h', 'd'))
265 else if (atom_compare(a, b, c, d, 's', 't', 's', 'd'))
267 else if (atom_compare(a, b, c, d, 's', 't', 't', 's'))
269 else if (atom_compare(a, b, c, d, 's', 't', 'c', 'o'))
271 else if (atom_compare(a, b, c, d, 's', 't', 's', 'c'))
273 else if (atom_compare(a, b, c, d, 's', 't', 's', 'z'))
275 else if (atom_compare(a, b, c, d, 's', 't', 'z', '2'))
277 else if (atom_compare(a, b, c, d, 's', 'k', 'i', 'p'))
279 else if (atom_compare(a, b, c, d, 's', 'i', 'n', 'f'))
281 else if (atom_compare(a, b, c, d, 's', 'c', 'h', 'i'))
283 else if (atom_compare(a, b, c, d, 's', 'o', 'n', 'm'))
284 return ATOM_SORTTITLE;
285 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'l'))
286 return ATOM_SORTALBUM;
287 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'r'))
288 return ATOM_SORTARTIST;
289 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'a'))
290 return ATOM_SORTALBUMARTIST;
291 else if (atom_compare(a, b, c, d, 's', 'o', 'c', 'o'))
292 return ATOM_SORTWRITER;
293 else if (atom_compare(a, b, c, d, 's', 'o', 's', 'n'))
294 return ATOM_SORTSHOW;
295 } else if (a == COPYRIGHT_SYMBOL) {
296 if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'n', 'a', 'm'))
298 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'A', 'R', 'T'))
300 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'w', 'r', 't'))
302 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'a', 'l', 'b'))
304 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'd', 'a', 'y'))
306 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 't', 'o', 'o'))
308 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'c', 'm', 't'))
310 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'e', 'n'))
312 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'r', 'p'))
313 return ATOM_CONTENTGROUP;
314 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'l', 'y', 'r'))
318 if (atom_compare(a, b, c, d, 'e', 'd', 't', 's'))
320 else if (atom_compare(a, b, c, d, 'e', 's', 'd', 's'))
322 else if (atom_compare(a, b, c, d, 'f', 't', 'y', 'p'))
324 else if (atom_compare(a, b, c, d, 'f', 'r', 'e', 'e'))
326 else if (atom_compare(a, b, c, d, 'h', 'm', 'h', 'd'))
328 else if (atom_compare(a, b, c, d, 'v', 'm', 'h', 'd'))
330 else if (atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
332 else if (atom_compare(a, b, c, d, 'i', 'l', 's', 't'))
334 else if (atom_compare(a, b, c, d, 'n', 'a', 'm', 'e'))
336 else if (atom_compare(a, b, c, d, 'd', 'a', 't', 'a'))
338 else if (atom_compare(a, b, c, d, 'd', 'i', 's', 'k'))
340 else if (atom_compare(a, b, c, d, 'g', 'n', 'r', 'e'))
342 else if (atom_compare(a, b, c, d, 'c', 'o', 'v', 'r'))
344 else if (atom_compare(a, b, c, d, 'c', 'p', 'i', 'l'))
345 return ATOM_COMPILATION;
346 else if (atom_compare(a, b, c, d, 'c', 't', 't', 's'))
348 else if (atom_compare(a, b, c, d, 'd', 'r', 'm', 's'))
350 else if (atom_compare(a, b, c, d, 'f', 'r', 'm', 'a'))
352 else if (atom_compare(a, b, c, d, 'p', 'r', 'i', 'v'))
354 else if (atom_compare(a, b, c, d, 'i', 'v', 'i', 'v'))
356 else if (atom_compare(a, b, c, d, 'u', 's', 'e', 'r'))
358 else if (atom_compare(a, b, c, d, 'k', 'e', 'y', ' '))
360 else if (atom_compare(a, b, c, d, 'a', 'A', 'R', 'T'))
361 return ATOM_ALBUM_ARTIST;
362 else if (atom_compare(a, b, c, d, 'd', 'e', 's', 'c'))
363 return ATOM_DESCRIPTION;
364 else if (atom_compare(a, b, c, d, 'p', 'c', 's', 't'))
370 /* read atom header, return atom size, atom size is with header included */
371 static uint64_t atom_read_header(struct mp4ff *f, uint8_t * atom_type,
372 uint8_t * header_size)
376 int8_t atom_header[8];
378 ret = read_data(f, atom_header, 8);
382 size = read_u32_be(atom_header);
385 /* check for 64 bit atom size */
388 size = read_int64(f);
390 *atom_type = atom_name_to_type(atom_header[4], atom_header[5],
391 atom_header[6], atom_header[7]);
395 static int64_t get_position(const struct mp4ff *f)
397 return f->current_position;
400 static int need_parse_when_meta_only(uint8_t atom_type)
421 static int32_t set_position(struct mp4ff *f, int64_t position)
423 f->stream->seek(f->stream->user_data, position);
424 f->current_position = position;
429 static void track_add(struct mp4ff *f)
433 if (f->total_tracks > MAX_TRACKS) {
438 f->track[f->total_tracks - 1] = para_calloc(sizeof(struct mp4ff_track));
441 static uint8_t read_char(struct mp4ff *f)
444 read_data(f, &output, 1);
448 static uint32_t read_int24(struct mp4ff *f)
452 read_data(f, data, 3);
453 return read_u24_be(data);
456 static uint32_t read_int32(struct mp4ff *f)
460 read_data(f, data, 4);
461 return read_u32_be(data);
464 static int32_t read_stsz(struct mp4ff *f)
467 struct mp4ff_track *t;
469 if (f->total_tracks == 0)
471 t = f->track[f->total_tracks - 1];
472 read_char(f); /* version */
473 read_int24(f); /* flags */
474 t->stsz_sample_size = read_int32(f);
475 t->stsz_sample_count = read_int32(f);
476 if (t->stsz_sample_size != 0)
478 t->stsz_table = para_malloc(t->stsz_sample_count * sizeof(int32_t));
479 for (i = 0; i < t->stsz_sample_count && !f->stream->read_error; i++)
480 t->stsz_table[i] = read_int32(f);
484 static int32_t read_stts(struct mp4ff *f)
487 struct mp4ff_track *t;
490 if (f->total_tracks == 0)
492 t = f->track[f->total_tracks - 1];
493 if (t->stts_entry_count)
495 read_char(f); /* version */
496 read_int24(f); /* flags */
497 t->stts_entry_count = read_int32(f);
499 t->stts_sample_count = para_malloc(t->stts_entry_count
501 t->stts_sample_delta = para_malloc(t->stts_entry_count
504 for (i = 0; i < t->stts_entry_count && !f->stream->read_error; i++) {
505 t->stts_sample_count[i] = read_int32(f);
506 t->stts_sample_delta[i] = read_int32(f);
511 static int32_t read_ctts(struct mp4ff *f)
514 struct mp4ff_track *t;
516 if (f->total_tracks == 0)
518 t = f->track[f->total_tracks - 1];
519 if (t->ctts_entry_count)
522 read_char(f); /* version */
523 read_int24(f); /* flags */
524 t->ctts_entry_count = read_int32(f);
526 t->ctts_sample_count = para_malloc(t->ctts_entry_count
528 t->ctts_sample_offset = para_malloc(t->ctts_entry_count
532 for (i = 0; i < t->ctts_entry_count && !f->stream->read_error; i++) {
533 t->ctts_sample_count[i] = read_int32(f);
534 t->ctts_sample_offset[i] = read_int32(f);
539 static int32_t read_stsc(struct mp4ff *f)
542 struct mp4ff_track *t;
544 if (f->total_tracks == 0)
546 t = f->track[f->total_tracks - 1];
548 read_char(f); /* version */
549 read_int24(f); /* flags */
550 t->stsc_entry_count = read_int32(f);
551 t->stsc_first_chunk = para_malloc(t->stsc_entry_count * sizeof(int32_t));
552 t->stsc_samples_per_chunk = para_malloc(t->stsc_entry_count
554 t->stsc_sample_desc_index = para_malloc(t->stsc_entry_count *
558 for (i = 0; i < t->stsc_entry_count && !f->stream->read_error; i++) {
559 t->stsc_first_chunk[i] = read_int32(f);
560 t->stsc_samples_per_chunk[i] = read_int32(f);
561 t->stsc_sample_desc_index[i] = read_int32(f);
566 static int32_t read_stco(struct mp4ff *f)
569 struct mp4ff_track *t;
571 if (f->total_tracks == 0)
573 t = f->track[f->total_tracks - 1];
575 read_char(f); /* version */
576 read_int24(f); /* flags */
577 t->stco_entry_count = read_int32(f);
578 t->stco_chunk_offset = para_malloc(t->stco_entry_count
581 for (i = 0; i < t->stco_entry_count && !f->stream->read_error; i++)
582 t->stco_chunk_offset[i] = read_int32(f);
586 static uint16_t read_int16(struct mp4ff *f)
590 read_data(f, data, 2);
591 return read_u16_be(data);
594 static uint32_t read_mp4_descr_length(struct mp4ff *f)
597 uint8_t numBytes = 0;
603 length = (length << 7) | (b & 0x7F);
604 } while ((b & 0x80) && numBytes < 4);
608 static int32_t read_esds(struct mp4ff *f)
612 struct mp4ff_track *t;
614 if (f->total_tracks == 0)
616 t = f->track[f->total_tracks - 1];
617 read_char(f); /* version */
618 read_int24(f); /* flags */
619 /* get and verify ES_DescrTag */
623 if (read_mp4_descr_length(f) < 5 + 15) {
633 /* get and verify DecoderConfigDescrTab */
634 if (read_char(f) != 0x04) {
639 temp = read_mp4_descr_length(f);
643 t->audioType = read_char(f);
644 read_int32(f); //0x15000414 ????
645 t->maxBitrate = read_int32(f);
646 t->avgBitrate = read_int32(f);
648 /* get and verify DecSpecificInfoTag */
649 if (read_char(f) != 0x05) {
654 t->decoderConfigLen = read_mp4_descr_length(f);
655 free(t->decoderConfig);
656 t->decoderConfig = para_malloc(t->decoderConfigLen);
657 read_data(f, t->decoderConfig, t->decoderConfigLen);
658 /* will skip the remainder of the atom */
662 static int32_t read_mp4a(struct mp4ff *f)
665 uint8_t atom_type = 0;
666 uint8_t header_size = 0;
667 struct mp4ff_track *t;
669 if (f->total_tracks == 0)
671 t = f->track[f->total_tracks - 1];
673 for (i = 0; i < 6; i++) {
674 read_char(f); /* reserved */
676 /* data_reference_index */ read_int16(f);
678 read_int32(f); /* reserved */
679 read_int32(f); /* reserved */
681 t->channelCount = read_int16(f);
682 t->sampleSize = read_int16(f);
687 t->sampleRate = read_int16(f);
691 atom_read_header(f, &atom_type, &header_size);
692 if (atom_type == ATOM_ESDS)
697 static int32_t read_stsd(struct mp4ff *f)
700 uint8_t header_size = 0;
701 struct mp4ff_track *t;
704 if (f->total_tracks == 0)
706 t = f->track[f->total_tracks - 1];
708 read_char(f); /* version */
709 read_int24(f); /* flags */
711 t->stsd_entry_count = read_int32(f);
714 for (i = 0; i < t->stsd_entry_count && !f->stream->read_error; i++) {
715 uint64_t skip = get_position(f);
717 uint8_t atom_type = 0;
718 size = atom_read_header(f, &atom_type, &header_size);
721 if (atom_type == ATOM_MP4A) {
722 t->type = TRACK_AUDIO;
724 } else if (atom_type == ATOM_MP4V) {
725 t->type = TRACK_VIDEO;
726 } else if (atom_type == ATOM_MP4S) {
727 t->type = TRACK_SYSTEM;
729 t->type = TRACK_UNKNOWN;
731 set_position(f, skip);
737 static int32_t read_mvhd(struct mp4ff *f)
741 read_char(f); /* version */
742 read_int24(f); /* flags */
743 read_int32(f); /* creation_time */
744 read_int32(f); /* modification_time */
745 f->time_scale = read_int32(f);
746 f->duration = read_int32(f);
747 read_int32(f); /* preferred_rate */
748 read_int16(f); /* preferred_volume */
749 for (i = 0; i < 10; i++)
750 read_char(f); /* reserved */
751 for (i = 0; i < 9; i++)
752 read_int32(f); /* matrix */
753 read_int32(f); /* preview_time */
754 read_int32(f); /* preview_duration */
755 read_int32(f); /* poster_time */
756 read_int32(f); /* selection_time */
757 read_int32(f); /* selection_duration */
758 read_int32(f); /* current_time */
759 read_int32(f); /* next_track_id */
763 static int32_t tag_add_field(struct mp4ff_metadata *tags, const char *item,
764 const char *value, int32_t len)
766 if (!item || (item && !*item) || !value)
769 tags->tags = para_realloc(tags->tags,
770 (tags->count + 1) * sizeof(struct mp4ff_tag));
771 tags->tags[tags->count].item = para_strdup(item);
772 tags->tags[tags->count].len = len;
774 tags->tags[tags->count].value = para_malloc(len + 1);
775 memcpy(tags->tags[tags->count].value, value, len);
776 tags->tags[tags->count].value[len] = 0;
778 tags->tags[tags->count].value = para_strdup(value);
784 static const char *ID3v1GenreList[] = {
785 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
786 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
787 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
788 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
789 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
790 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
791 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
792 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
793 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
794 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
795 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
796 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
797 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
798 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
799 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
800 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
801 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
802 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
803 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
804 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
805 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
806 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
807 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
808 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
809 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
810 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
811 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
812 "Anime", "JPop", "SynthPop",
815 static const char *meta_index_to_genre(uint32_t idx)
817 if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
818 return ID3v1GenreList[idx - 1];
824 static char *read_string(struct mp4ff *f, uint32_t length)
826 char *str = para_malloc(length + 1);
827 if ((uint32_t)read_data(f, str, length) != length) {
835 static int32_t set_metadata_name(uint8_t atom_type, char **name)
837 static char *tag_names[] = {
838 "unknown", "title", "artist", "writer", "album",
839 "date", "tool", "comment", "genre", "track",
840 "disc", "compilation", "genre", "tempo", "cover",
841 "album_artist", "contentgroup", "lyrics", "description",
842 "network", "show", "episodename",
843 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
844 "sortwriter", "sortshow",
845 "season", "episode", "podcast"
880 case ATOM_COMPILATION:
892 case ATOM_ALBUM_ARTIST:
895 case ATOM_CONTENTGROUP:
901 case ATOM_DESCRIPTION:
910 case ATOM_EPISODENAME:
919 case ATOM_SORTARTIST:
922 case ATOM_SORTALBUMARTIST:
925 case ATOM_SORTWRITER:
945 *name = para_strdup(tag_names[tag_idx]);
949 static uint32_t min_body_size(uint8_t atom_type)
956 return sizeof (char) /* version */
957 + sizeof(uint8_t) * 3 /* flags */
958 + sizeof(uint32_t) /* reserved */
959 + sizeof(uint16_t) /* leading uint16_t */
960 + sizeof(uint16_t) /* track */
961 + sizeof(uint16_t); /* totaltracks */
963 return sizeof (char) /* version */
964 + sizeof(uint8_t) * 3 /* flags */
965 + sizeof(uint32_t) /* reserved */
966 + sizeof(uint16_t) /* disc */
967 + sizeof(uint16_t); /* totaldiscs */
968 default: assert(false);
972 static int32_t parse_tag(struct mp4ff *f, uint8_t parent, int32_t size)
975 uint8_t header_size = 0;
976 uint64_t subsize, sumsize;
985 sumsize < size && !f->stream->read_error; /* CVE-2017-9222 */
986 set_position(f, destpos), sumsize += subsize
988 subsize = atom_read_header(f, &atom_type, &header_size);
989 destpos = get_position(f) + subsize - header_size;
992 if (atom_type == ATOM_NAME) {
993 read_char(f); /* version */
994 read_int24(f); /* flags */
996 name = read_string(f, subsize - (header_size + 4));
999 if (atom_type != ATOM_DATA)
1001 read_char(f); /* version */
1002 read_int24(f); /* flags */
1003 read_int32(f); /* reserved */
1005 /* some need special attention */
1006 if (parent == ATOM_GENRE2 || parent == ATOM_TEMPO) {
1008 if (subsize - header_size < min_body_size(parent))
1010 val = read_int16(f);
1011 if (parent == ATOM_TEMPO) {
1013 sprintf(temp, "%.5u BPM", val);
1014 tag_add_field(&(f-> tags), "tempo",
1017 const char *tmp = meta_index_to_genre(val);
1019 tag_add_field (&(f->tags),
1023 } else if (parent == ATOM_TRACK || parent == ATOM_DISC) {
1024 uint16_t index, total;
1026 if (subsize - header_size < min_body_size(parent))
1029 index = read_int16(f);
1030 total = read_int16(f);
1031 if (parent == ATOM_TRACK)
1033 sprintf(temp, "%d", index);
1034 tag_add_field(&(f->tags), parent == ATOM_TRACK?
1035 "track" : "disc", temp, -1);
1037 sprintf(temp, "%d", total);
1038 tag_add_field(& (f-> tags),
1039 parent == ATOM_TRACK?
1040 "totaltracks" : "totaldiscs", temp, -1);
1045 data = read_string(f, subsize - (header_size + 8));
1046 len = subsize - (header_size + 8);
1052 set_metadata_name(parent , &name);
1054 tag_add_field(&(f->tags), name, data, len);
1063 static int32_t read_mdhd(struct mp4ff *f)
1066 struct mp4ff_track *t;
1069 if (f->total_tracks == 0)
1071 t = f->track[f->total_tracks - 1];
1073 version = read_int32(f);
1075 read_int64(f); //creation-time
1076 read_int64(f); //modification-time
1077 t->timeScale = read_int32(f); //timescale
1078 t->duration = read_int64(f); //duration
1079 } else { //version == 0
1082 read_int32(f); //creation-time
1083 read_int32(f); //modification-time
1084 t->timeScale = read_int32(f); //timescale
1085 temp = read_int32(f);
1086 t->duration = (temp == (uint32_t) (-1))?
1087 (uint64_t) (-1) : (uint64_t) (temp);
1094 static int32_t parse_metadata(struct mp4ff *f, int32_t size)
1096 uint64_t subsize, sumsize = 0;
1098 uint8_t header_size = 0;
1100 while (sumsize < size) {
1101 subsize = atom_read_header(f, &atom_type, &header_size);
1104 parse_tag(f, atom_type, (uint32_t)(subsize - header_size));
1111 static int32_t read_meta(struct mp4ff *f, uint64_t size)
1113 uint64_t subsize, sumsize = 0;
1115 uint8_t header_size = 0;
1117 read_char(f); /* version */
1118 read_int24(f); /* flags */
1120 while (sumsize < (size - (header_size + 4))) {
1121 subsize = atom_read_header(f, &atom_type, &header_size);
1122 if (subsize <= header_size + 4)
1124 if (atom_type == ATOM_ILST) {
1125 parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1127 set_position(f, get_position(f) + subsize - header_size);
1135 static int32_t atom_read(struct mp4ff *f, int32_t size, uint8_t atom_type)
1137 uint64_t dest_position = get_position(f) + size - 8;
1138 if (atom_type == ATOM_STSZ) {
1139 /* sample size box */
1141 } else if (atom_type == ATOM_STTS) {
1142 /* time to sample box */
1144 } else if (atom_type == ATOM_CTTS) {
1145 /* composition offset box */
1147 } else if (atom_type == ATOM_STSC) {
1148 /* sample to chunk box */
1150 } else if (atom_type == ATOM_STCO) {
1151 /* chunk offset box */
1153 } else if (atom_type == ATOM_STSD) {
1154 /* sample description box */
1156 } else if (atom_type == ATOM_MVHD) {
1157 /* movie header box */
1159 } else if (atom_type == ATOM_MDHD) {
1162 } else if (atom_type == ATOM_META) {
1163 /* iTunes Metadata box */
1167 set_position(f, dest_position);
1171 /* parse atoms that are sub atoms of other atoms */
1172 static int32_t parse_sub_atoms(struct mp4ff *f, uint64_t total_size, int meta_only)
1175 uint8_t atom_type = 0;
1176 uint64_t counted_size = 0;
1177 uint8_t header_size = 0;
1179 while (counted_size < total_size) {
1180 size = atom_read_header(f, &atom_type, &header_size);
1181 counted_size += size;
1183 /* check for end of file */
1187 /* we're starting to read a new track, update index,
1188 * so that all data and tables get written in the right place
1190 if (atom_type == ATOM_TRAK)
1192 /* parse subatoms */
1193 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1194 set_position(f, get_position(f) + size - header_size);
1195 } else if (atom_type < SUBATOMIC) {
1196 parse_sub_atoms(f, size - header_size, meta_only);
1198 atom_read(f, (uint32_t) size, atom_type);
1205 /* parse root atoms */
1206 static int32_t parse_atoms(struct mp4ff *f, int meta_only)
1209 uint8_t atom_type = 0;
1210 uint8_t header_size = 0;
1213 f->stream->read_error = 0;
1216 atom_read_header(f, &atom_type, &header_size)) != 0) {
1217 f->file_size += size;
1218 f->last_atom = atom_type;
1220 if (atom_type == ATOM_MOOV && size > header_size) {
1221 f->moov_offset = get_position(f) - header_size;
1222 f->moov_size = size;
1225 /* parse subatoms */
1226 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1227 set_position(f, get_position(f) + size - header_size);
1228 } else if (atom_type < SUBATOMIC) {
1229 parse_sub_atoms(f, size - header_size, meta_only);
1231 /* skip this atom */
1232 set_position(f, get_position(f) + size - header_size);
1239 void mp4ff_get_decoder_config(const struct mp4ff *f, int track,
1240 unsigned char **ppBuf, unsigned int *pBufSize)
1242 if (track >= f->total_tracks) {
1248 if (f->track[track]->decoderConfig == NULL
1249 || f->track[track]->decoderConfigLen == 0) {
1253 *ppBuf = para_malloc(f->track[track]->decoderConfigLen);
1254 memcpy(*ppBuf, f->track[track]->decoderConfig,
1255 f->track[track]->decoderConfigLen);
1256 *pBufSize = f->track[track]->decoderConfigLen;
1260 struct mp4ff *mp4ff_open_read(struct mp4ff_callback *f)
1262 struct mp4ff *ff = para_calloc(sizeof(struct mp4ff));
1276 static int32_t tag_delete(struct mp4ff_metadata *tags)
1280 for (i = 0; i < tags->count; i++) {
1281 free(tags->tags[i].item);
1282 free(tags->tags[i].value);
1291 void mp4ff_close(struct mp4ff *ff)
1295 for (i = 0; i < ff->total_tracks; i++) {
1297 free(ff->track[i]->stsz_table);
1298 free(ff->track[i]->stts_sample_count);
1299 free(ff->track[i]->stts_sample_delta);
1300 free(ff->track[i]->stsc_first_chunk);
1301 free(ff->track[i]->stsc_samples_per_chunk);
1302 free(ff->track[i]->stsc_sample_desc_index);
1303 free(ff->track[i]->stco_chunk_offset);
1304 free(ff->track[i]->decoderConfig);
1305 free(ff->track[i]->ctts_sample_count);
1306 free(ff->track[i]->ctts_sample_offset);
1311 tag_delete(&(ff->tags));
1315 static int32_t chunk_of_sample(const struct mp4ff *f, int32_t track,
1316 int32_t sample, int32_t *chunk_sample, int32_t *chunk)
1318 int32_t total_entries = 0;
1319 int32_t chunk2entry;
1320 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1324 if (f->track[track] == NULL) {
1328 total_entries = f->track[track]->stsc_entry_count;
1335 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1336 *chunk = chunk2 - chunk1;
1337 range_samples = *chunk * chunk1samples;
1339 if (sample < total + range_samples)
1342 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1345 if (chunk2entry < total_entries) {
1347 total += range_samples;
1349 } while (chunk2entry < total_entries);
1352 *chunk = (sample - total) / chunk1samples + chunk1;
1356 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1361 static int32_t chunk_to_offset(const struct mp4ff *f, int32_t track,
1364 const struct mp4ff_track *p_track = f->track[track];
1366 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1367 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1369 } else if (p_track->stco_entry_count) {
1370 return p_track->stco_chunk_offset[chunk - 1];
1378 static int32_t sample_range_size(const struct mp4ff *f, int32_t track,
1379 int32_t chunk_sample, int32_t sample)
1382 const struct mp4ff_track *p_track = f->track[track];
1384 if (p_track->stsz_sample_size) {
1385 return (sample - chunk_sample) * p_track->stsz_sample_size;
1387 if (sample >= p_track->stsz_sample_count)
1390 for (i = chunk_sample, total = 0; i < sample; i++) {
1391 total += p_track->stsz_table[i];
1398 static int32_t sample_to_offset(const struct mp4ff *f, int32_t track,
1401 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1403 chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1405 chunk_offset1 = chunk_to_offset(f, track, chunk);
1406 chunk_offset2 = chunk_offset1 + sample_range_size(f,
1407 track, chunk_sample, sample);
1408 return chunk_offset2;
1411 void mp4ff_set_sample_position(struct mp4ff *f, int32_t track, int32_t sample)
1413 int32_t offset = sample_to_offset(f, track, sample);
1414 set_position(f, offset);
1417 int32_t mp4ff_get_sample_size(const struct mp4ff *f, int track, int sample)
1419 const struct mp4ff_track *t = f->track[track];
1421 if (t->stsz_sample_size != 0)
1422 return t->stsz_sample_size;
1423 return t->stsz_table[sample];
1426 uint32_t mp4ff_get_sample_rate(const struct mp4ff *f, int32_t track)
1428 return f->track[track]->sampleRate;
1431 uint32_t mp4ff_get_channel_count(const struct mp4ff *f, int32_t track)
1433 return f->track[track]->channelCount;
1436 int32_t mp4ff_num_samples(const struct mp4ff *f, int32_t track)
1441 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1442 total += f->track[track]->stts_sample_count[i];
1447 struct mp4ff *mp4ff_open_read_metaonly(struct mp4ff_callback *f)
1449 struct mp4ff *ff = para_calloc(sizeof(struct mp4ff));
1463 int32_t mp4ff_meta_get_num_items(const struct mp4ff *f)
1465 return f->tags.count;
1468 int32_t mp4ff_meta_get_by_index(const struct mp4ff *f, uint32_t index,
1469 char **item, char **value)
1471 if (index >= f->tags.count) {
1476 *item = para_strdup(f->tags.tags[index].item);
1477 *value = para_strdup(f->tags.tags[index].value);
1482 static uint32_t find_atom(struct mp4ff *f, uint64_t base, uint32_t size,
1485 uint32_t remaining = size;
1486 uint64_t atom_offset = base;
1491 set_position(f, atom_offset);
1495 atom_size = read_int32(f);
1496 if (atom_size > remaining || atom_size < 8)
1498 read_data(f, atom_name, 4);
1500 if (!memcmp(atom_name, name, 4)) {
1501 set_position(f, atom_offset);
1505 remaining -= atom_size;
1506 atom_offset += atom_size;
1511 static uint32_t find_atom_v2(struct mp4ff *f, uint64_t base, uint32_t size,
1512 const char *name, uint32_t extraheaders, const char *name_inside)
1514 uint64_t first_base = (uint64_t) (-1);
1515 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1517 uint64_t mybase = get_position(f);
1518 uint32_t mysize = read_int32(f);
1520 if (first_base == (uint64_t) (-1))
1521 first_base = mybase;
1523 if (mysize < 8 + extraheaders)
1526 if (find_atom (f, mybase + (8 + extraheaders),
1527 mysize - (8 + extraheaders), name_inside)) {
1528 set_position(f, mybase);
1532 if (size <= mysize) {
1539 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1541 set_position(f, first_base);
1554 static struct membuffer *membuffer_create(void)
1556 const unsigned initial_size = 256;
1558 struct membuffer *buf = para_malloc(sizeof(*buf));
1559 buf->data = para_malloc(initial_size);
1561 buf->allocated = initial_size;
1562 buf->error = buf->data == 0 ? 1 : 0;
1567 static unsigned membuffer_write(struct membuffer *buf, const void *ptr, unsigned bytes)
1569 unsigned dest_size = buf->written + bytes;
1573 if (dest_size > buf->allocated) {
1575 buf->allocated <<= 1;
1576 } while (dest_size > buf->allocated);
1577 buf->data = para_realloc(buf->data, buf->allocated);
1581 memcpy((char *) buf->data + buf->written, ptr, bytes);
1582 buf->written += bytes;
1586 static unsigned membuffer_write_atom_name(struct membuffer *buf, const char *data)
1588 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1591 static unsigned membuffer_write_int16(struct membuffer *buf, uint16_t data)
1595 write_u16_be(temp, data);
1596 return membuffer_write(buf, temp, 2);
1599 static unsigned membuffer_write_int32(struct membuffer *buf, uint32_t data)
1602 write_u32_be(temp, data);
1603 return membuffer_write(buf, temp, 4);
1606 static void membuffer_write_track_tag(struct membuffer *buf, const char *name,
1607 uint32_t index, uint32_t total)
1609 membuffer_write_int32(buf,
1610 8 /*atom header */ + 8 /*data atom header */ +
1611 8 /*flags + reserved */ + 8 /*actual data */ );
1612 membuffer_write_atom_name(buf, name);
1613 membuffer_write_int32(buf,
1614 8 /*data atom header */ +
1615 8 /*flags + reserved */ + 8 /*actual data */ );
1616 membuffer_write_atom_name(buf, "data");
1617 membuffer_write_int32(buf, 0); //flags
1618 membuffer_write_int32(buf, 0); //reserved
1619 membuffer_write_int16(buf, 0);
1620 membuffer_write_int16(buf, (uint16_t) index); //track number
1621 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1622 membuffer_write_int16(buf, 0);
1625 static void membuffer_write_int16_tag(struct membuffer *buf, const char *name,
1628 membuffer_write_int32(buf,
1629 8 /*atom header */ + 8 /*data atom header */ +
1630 8 /*flags + reserved */ + 2 /*actual data */ );
1631 membuffer_write_atom_name(buf, name);
1632 membuffer_write_int32(buf,
1633 8 /*data atom header */ +
1634 8 /*flags + reserved */ + 2 /*actual data */ );
1635 membuffer_write_atom_name(buf, "data");
1636 membuffer_write_int32(buf, 0); //flags
1637 membuffer_write_int32(buf, 0); //reserved
1638 membuffer_write_int16(buf, value); //value
1641 static uint32_t myatoi(const char *param)
1643 return param ? atoi(param) : 0;
1646 static uint32_t meta_genre_to_index(const char *genrestr)
1649 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1650 if (!strcasecmp(genrestr, ID3v1GenreList[n]))
1656 struct stdmeta_entry {
1661 struct stdmeta_entry stdmetas[] = {
1662 {"\xA9" "nam", "title"},
1663 {"\xA9" "ART", "artist"},
1664 {"\xA9" "wrt", "writer"},
1665 {"\xA9" "alb", "album"},
1666 {"\xA9" "day", "date"},
1667 {"\xA9" "too", "tool"},
1668 {"\xA9" "cmt", "comment"},
1669 {"cpil", "compilation"},
1671 {"aART", "album_artist"},
1674 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1677 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1678 if (!strcasecmp(name, stdmetas[n].name))
1679 return stdmetas[n].atom;
1684 static void membuffer_write_std_tag(struct membuffer *buf, const char *name,
1689 /* special check for compilation flag */
1690 if (strcmp(name, "cpil") == 0) {
1694 membuffer_write_int32(buf,
1695 8 /*atom header */ + 8 /*data atom header */ +
1696 8 /*flags + reserved */ + strlen(value));
1697 membuffer_write_atom_name(buf, name);
1698 membuffer_write_int32(buf,
1699 8 /*data atom header */ +
1700 8 /*flags + reserved */ + strlen(value));
1701 membuffer_write_atom_name(buf, "data");
1702 membuffer_write_int32(buf, flags); //flags
1703 membuffer_write_int32(buf, 0); //reserved
1704 membuffer_write(buf, value, strlen(value));
1707 static void membuffer_write_custom_tag(struct membuffer *buf, const char *name,
1710 membuffer_write_int32(buf,
1711 8 /*atom header */ +
1712 0x1C /*weirdo itunes atom */ +
1713 12 /*name atom header */ + strlen(name) +
1714 16 /*data atom header + flags */ + strlen(value));
1715 membuffer_write_atom_name(buf, "----");
1716 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1717 membuffer_write_atom_name(buf, "mean");
1718 membuffer_write_int32(buf, 0);
1719 membuffer_write(buf, "com.apple.iTunes", 16);
1720 membuffer_write_int32(buf, 12 + strlen(name));
1721 membuffer_write_atom_name(buf, "name");
1722 membuffer_write_int32(buf, 0);
1723 membuffer_write(buf, name, strlen(name));
1724 membuffer_write_int32(buf,
1725 8 /*data atom header */ +
1726 8 /*flags + reserved */ + strlen(value));
1727 membuffer_write_atom_name(buf, "data");
1728 membuffer_write_int32(buf, 1); //flags
1729 membuffer_write_int32(buf, 0); //reserved
1730 membuffer_write(buf, value, strlen(value));
1733 static unsigned membuffer_error(const struct membuffer *buf)
1738 static void membuffer_free(struct membuffer *buf)
1744 static unsigned membuffer_get_size(const struct membuffer *buf)
1746 return buf->written;
1749 static void *membuffer_detach(struct membuffer *buf)
1755 ret = para_realloc(buf->data, buf->written);
1761 static uint32_t create_ilst(const struct mp4ff_metadata *data, void **out_buffer,
1762 uint32_t * out_size)
1764 struct membuffer *buf = membuffer_create();
1766 char *mask = para_calloc(data->count);
1767 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1768 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1769 const char *genre_ptr = 0, *tempo_ptr = 0;
1771 for (metaptr = 0; metaptr < data->count; metaptr++) {
1772 struct mp4ff_tag *tag = &data->tags[metaptr];
1773 if (!strcasecmp(tag->item, "tracknumber")
1774 || !strcasecmp(tag->item, "track")) {
1775 if (tracknumber_ptr == 0)
1776 tracknumber_ptr = tag->value;
1778 } else if (!strcasecmp(tag->item, "totaltracks")) {
1779 if (totaltracks_ptr == 0)
1780 totaltracks_ptr = tag->value;
1782 } else if (!strcasecmp(tag->item, "discnumber")
1783 || !strcasecmp(tag->item, "disc")) {
1784 if (discnumber_ptr == 0)
1785 discnumber_ptr = tag->value;
1787 } else if (!strcasecmp(tag->item, "totaldiscs")) {
1788 if (totaldiscs_ptr == 0)
1789 totaldiscs_ptr = tag->value;
1791 } else if (!strcasecmp(tag->item, "genre")) {
1793 genre_ptr = tag->value;
1795 } else if (!strcasecmp(tag->item, "tempo")) {
1797 tempo_ptr = tag->value;
1802 if (tracknumber_ptr)
1803 membuffer_write_track_tag(buf, "trkn", myatoi(tracknumber_ptr),
1804 myatoi(totaltracks_ptr));
1806 membuffer_write_track_tag(buf, "disk", myatoi(discnumber_ptr),
1807 myatoi(totaldiscs_ptr));
1809 membuffer_write_int16_tag(buf, "tmpo", myatoi(tempo_ptr));
1812 uint32_t index = meta_genre_to_index(genre_ptr);
1814 membuffer_write_std_tag(buf, "©gen", genre_ptr);
1816 membuffer_write_int16_tag(buf, "gnre", index);
1818 for (metaptr = 0; metaptr < data->count; metaptr++) {
1819 struct mp4ff_tag *tag;
1820 const char *std_meta_atom;
1824 tag = &data->tags[metaptr];
1825 std_meta_atom = find_standard_meta(tag->item);
1827 membuffer_write_std_tag(buf, std_meta_atom, tag->value);
1829 membuffer_write_custom_tag(buf, tag->item, tag->value);
1833 if (membuffer_error(buf)) {
1834 membuffer_free(buf);
1838 *out_size = membuffer_get_size(buf);
1839 *out_buffer = membuffer_detach(buf);
1840 membuffer_free(buf);
1845 static void membuffer_write_atom(struct membuffer *buf, const char *name, unsigned size,
1848 membuffer_write_int32(buf, size + 8);
1849 membuffer_write_atom_name(buf, name);
1850 membuffer_write(buf, data, size);
1853 static void *membuffer_get_ptr(const struct membuffer *buf)
1858 static void membuffer_set_error(struct membuffer *buf)
1863 static unsigned membuffer_transfer_from_file(struct membuffer *buf, struct mp4ff *src,
1869 oldsize = membuffer_get_size(buf);
1870 if (membuffer_write(buf, 0, bytes) != bytes)
1873 bufptr = membuffer_get_ptr(buf);
1877 if ((unsigned)read_data(src, (char *) bufptr + oldsize, bytes) !=
1879 membuffer_set_error(buf);
1886 static uint32_t create_meta(const struct mp4ff_metadata *data, void **out_buffer,
1887 uint32_t * out_size)
1889 struct membuffer *buf;
1893 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1896 buf = membuffer_create();
1898 membuffer_write_int32(buf, 0);
1899 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1902 *out_size = membuffer_get_size(buf);
1903 *out_buffer = membuffer_detach(buf);
1904 membuffer_free(buf);
1908 static uint32_t create_udta(const struct mp4ff_metadata *data, void **out_buffer,
1909 uint32_t * out_size)
1911 struct membuffer *buf;
1915 if (!create_meta(data, &meta_buffer, &meta_size))
1918 buf = membuffer_create();
1920 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1924 *out_size = membuffer_get_size(buf);
1925 *out_buffer = membuffer_detach(buf);
1926 membuffer_free(buf);
1930 static uint32_t fix_byte_order_32(uint32_t src)
1932 return read_u32_be(&src);
1935 static uint32_t modify_moov(struct mp4ff *f, const struct mp4ff_metadata *data,
1936 void **out_buffer, uint32_t * out_size)
1938 uint64_t total_base = f->moov_offset + 8;
1939 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1941 uint64_t udta_offset, meta_offset, ilst_offset;
1942 uint32_t udta_size, meta_size, ilst_size;
1944 uint32_t new_ilst_size;
1945 void *new_ilst_buffer;
1950 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1951 struct membuffer *buf;
1952 void *new_udta_buffer;
1953 uint32_t new_udta_size;
1954 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1957 buf = membuffer_create();
1958 set_position(f, total_base);
1959 membuffer_transfer_from_file(buf, f, total_size);
1961 membuffer_write_atom(buf, "udta", new_udta_size,
1964 free(new_udta_buffer);
1966 *out_size = membuffer_get_size(buf);
1967 *out_buffer = membuffer_detach(buf);
1968 membuffer_free(buf);
1971 udta_offset = get_position(f);
1972 udta_size = read_int32(f);
1973 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
1974 struct membuffer *buf;
1975 void *new_meta_buffer;
1976 uint32_t new_meta_size;
1977 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
1980 buf = membuffer_create();
1981 set_position(f, total_base);
1982 membuffer_transfer_from_file(buf, f,
1983 (uint32_t)(udta_offset - total_base));
1985 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
1986 membuffer_write_atom_name(buf, "udta");
1987 membuffer_transfer_from_file(buf, f, udta_size);
1989 membuffer_write_atom(buf, "meta", new_meta_size,
1991 free(new_meta_buffer);
1993 *out_size = membuffer_get_size(buf);
1994 *out_buffer = membuffer_detach(buf);
1995 membuffer_free(buf);
1998 meta_offset = get_position(f);
1999 meta_size = read_int32(f);
2000 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2001 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2002 ilst_offset = get_position(f);
2003 ilst_size = read_int32(f);
2005 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2008 size_delta = new_ilst_size - (ilst_size - 8);
2010 *out_size = total_size + size_delta;
2011 *out_buffer = para_malloc(*out_size);
2012 p_out = (uint8_t *) * out_buffer;
2014 set_position(f, total_base);
2016 (uint32_t) (udta_offset - total_base));
2017 p_out += (uint32_t) (udta_offset - total_base);
2018 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2020 read_data(f, p_out, 4);
2023 (uint32_t) (meta_offset - udta_offset - 8));
2024 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2025 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2027 read_data(f, p_out, 4);
2030 (uint32_t) (ilst_offset - meta_offset - 8));
2031 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2032 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2034 read_data(f, p_out, 4);
2037 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2038 p_out += new_ilst_size;
2040 set_position(f, ilst_offset + ilst_size);
2041 read_data(f, p_out, (uint32_t) (total_size
2042 - (ilst_offset - total_base) - ilst_size));
2044 free(new_ilst_buffer);
2049 static int32_t write_data(struct mp4ff *f, void *data, uint32_t size)
2053 result = f->stream->write(f->stream->user_data, data, size);
2055 f->current_position += size;
2060 static int32_t write_int32(struct mp4ff *f, uint32_t data)
2063 write_u32_be(temp, data);
2064 return write_data(f, temp, sizeof(temp));
2067 static int32_t truncate_stream(struct mp4ff *f)
2069 return f->stream->truncate(f->stream->user_data);
2072 int32_t mp4ff_meta_update(struct mp4ff_callback *f, const struct mp4ff_metadata *data)
2074 void *new_moov_data;
2075 uint32_t new_moov_size;
2077 struct mp4ff *ff = para_calloc(sizeof(struct mp4ff));
2079 set_position(ff, 0);
2083 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2088 /* copy moov atom to end of the file */
2089 if (ff->last_atom != ATOM_MOOV) {
2090 char *free_data = "free";
2092 /* rename old moov to free */
2093 set_position(ff, ff->moov_offset + 4);
2094 write_data(ff, free_data, 4);
2096 set_position(ff, ff->file_size);
2097 write_int32(ff, new_moov_size + 8);
2098 write_data(ff, "moov", 4);
2099 write_data(ff, new_moov_data, new_moov_size);
2101 set_position(ff, ff->moov_offset);
2102 write_int32(ff, new_moov_size + 8);
2103 write_data(ff, "moov", 4);
2104 write_data(ff, new_moov_data, new_moov_size);
2107 truncate_stream(ff);
2113 /* find a metadata item by name */
2114 /* returns 0 if item found, 1 if no such item */
2115 static int32_t meta_find_by_name(const struct mp4ff *f, const char *item,
2120 for (i = 0; i < f->tags.count; i++) {
2121 if (!strcasecmp(f->tags.tags[i].item, item)) {
2122 *value = para_strdup(f->tags.tags[i].value);
2133 int32_t mp4ff_meta_get_artist(const struct mp4ff *f, char **value)
2135 return meta_find_by_name(f, "artist", value);
2138 int32_t mp4ff_meta_get_title(const struct mp4ff *f, char **value)
2140 return meta_find_by_name(f, "title", value);
2143 int32_t mp4ff_meta_get_date(const struct mp4ff *f, char **value)
2145 return meta_find_by_name(f, "date", value);
2148 int32_t mp4ff_meta_get_album(const struct mp4ff *f, char **value)
2150 return meta_find_by_name(f, "album", value);
2153 int32_t mp4ff_meta_get_comment(const struct mp4ff *f, char **value)
2155 return meta_find_by_name(f, "comment", value);