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 void *backup = (void *) tags->tags;
768 if (!item || (item && !*item) || !value)
771 tags->tags = (struct mp4ff_tag *)realloc(tags->tags,
772 (tags->count + 1) * sizeof(struct mp4ff_tag));
777 tags->tags[tags->count].item = para_strdup(item);
778 tags->tags[tags->count].len = len;
780 tags->tags[tags->count].value = para_malloc(len + 1);
781 memcpy(tags->tags[tags->count].value, value, len);
782 tags->tags[tags->count].value[len] = 0;
784 tags->tags[tags->count].value = para_strdup(value);
791 static const char *ID3v1GenreList[] = {
792 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
793 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
794 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
795 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
796 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
797 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
798 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
799 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
800 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
801 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
802 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
803 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
804 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
805 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
806 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
807 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
808 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
809 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
810 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
811 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
812 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
813 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
814 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
815 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
816 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
817 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
818 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
819 "Anime", "JPop", "SynthPop",
822 static const char *meta_index_to_genre(uint32_t idx)
824 if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
825 return ID3v1GenreList[idx - 1];
831 static char *read_string(struct mp4ff *f, uint32_t length)
833 char *str = para_malloc(length + 1);
834 if ((uint32_t)read_data(f, str, length) != length) {
842 static int32_t set_metadata_name(uint8_t atom_type, char **name)
844 static char *tag_names[] = {
845 "unknown", "title", "artist", "writer", "album",
846 "date", "tool", "comment", "genre", "track",
847 "disc", "compilation", "genre", "tempo", "cover",
848 "album_artist", "contentgroup", "lyrics", "description",
849 "network", "show", "episodename",
850 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
851 "sortwriter", "sortshow",
852 "season", "episode", "podcast"
887 case ATOM_COMPILATION:
899 case ATOM_ALBUM_ARTIST:
902 case ATOM_CONTENTGROUP:
908 case ATOM_DESCRIPTION:
917 case ATOM_EPISODENAME:
926 case ATOM_SORTARTIST:
929 case ATOM_SORTALBUMARTIST:
932 case ATOM_SORTWRITER:
952 *name = para_strdup(tag_names[tag_idx]);
956 static uint32_t min_body_size(uint8_t atom_type)
963 return sizeof (char) /* version */
964 + sizeof(uint8_t) * 3 /* flags */
965 + sizeof(uint32_t) /* reserved */
966 + sizeof(uint16_t) /* leading uint16_t */
967 + sizeof(uint16_t) /* track */
968 + sizeof(uint16_t); /* totaltracks */
970 return sizeof (char) /* version */
971 + sizeof(uint8_t) * 3 /* flags */
972 + sizeof(uint32_t) /* reserved */
973 + sizeof(uint16_t) /* disc */
974 + sizeof(uint16_t); /* totaldiscs */
975 default: assert(false);
979 static int32_t parse_tag(struct mp4ff *f, uint8_t parent, int32_t size)
982 uint8_t header_size = 0;
983 uint64_t subsize, sumsize;
992 sumsize < size && !f->stream->read_error; /* CVE-2017-9222 */
993 set_position(f, destpos), sumsize += subsize
995 subsize = atom_read_header(f, &atom_type, &header_size);
996 destpos = get_position(f) + subsize - header_size;
999 if (atom_type == ATOM_NAME) {
1000 read_char(f); /* version */
1001 read_int24(f); /* flags */
1003 name = read_string(f, subsize - (header_size + 4));
1006 if (atom_type != ATOM_DATA)
1008 read_char(f); /* version */
1009 read_int24(f); /* flags */
1010 read_int32(f); /* reserved */
1012 /* some need special attention */
1013 if (parent == ATOM_GENRE2 || parent == ATOM_TEMPO) {
1015 if (subsize - header_size < min_body_size(parent))
1017 val = read_int16(f);
1018 if (parent == ATOM_TEMPO) {
1020 sprintf(temp, "%.5u BPM", val);
1021 tag_add_field(&(f-> tags), "tempo",
1024 const char *tmp = meta_index_to_genre(val);
1026 tag_add_field (&(f->tags),
1030 } else if (parent == ATOM_TRACK || parent == ATOM_DISC) {
1031 uint16_t index, total;
1033 if (subsize - header_size < min_body_size(parent))
1036 index = read_int16(f);
1037 total = read_int16(f);
1038 if (parent == ATOM_TRACK)
1040 sprintf(temp, "%d", index);
1041 tag_add_field(&(f->tags), parent == ATOM_TRACK?
1042 "track" : "disc", temp, -1);
1044 sprintf(temp, "%d", total);
1045 tag_add_field(& (f-> tags),
1046 parent == ATOM_TRACK?
1047 "totaltracks" : "totaldiscs", temp, -1);
1052 data = read_string(f, subsize - (header_size + 8));
1053 len = subsize - (header_size + 8);
1059 set_metadata_name(parent , &name);
1061 tag_add_field(&(f->tags), name, data, len);
1070 static int32_t read_mdhd(struct mp4ff *f)
1073 struct mp4ff_track *t;
1076 if (f->total_tracks == 0)
1078 t = f->track[f->total_tracks - 1];
1080 version = read_int32(f);
1082 read_int64(f); //creation-time
1083 read_int64(f); //modification-time
1084 t->timeScale = read_int32(f); //timescale
1085 t->duration = read_int64(f); //duration
1086 } else { //version == 0
1089 read_int32(f); //creation-time
1090 read_int32(f); //modification-time
1091 t->timeScale = read_int32(f); //timescale
1092 temp = read_int32(f);
1093 t->duration = (temp == (uint32_t) (-1))?
1094 (uint64_t) (-1) : (uint64_t) (temp);
1101 static int32_t parse_metadata(struct mp4ff *f, int32_t size)
1103 uint64_t subsize, sumsize = 0;
1105 uint8_t header_size = 0;
1107 while (sumsize < size) {
1108 subsize = atom_read_header(f, &atom_type, &header_size);
1111 parse_tag(f, atom_type, (uint32_t)(subsize - header_size));
1118 static int32_t read_meta(struct mp4ff *f, uint64_t size)
1120 uint64_t subsize, sumsize = 0;
1122 uint8_t header_size = 0;
1124 read_char(f); /* version */
1125 read_int24(f); /* flags */
1127 while (sumsize < (size - (header_size + 4))) {
1128 subsize = atom_read_header(f, &atom_type, &header_size);
1129 if (subsize <= header_size + 4)
1131 if (atom_type == ATOM_ILST) {
1132 parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1134 set_position(f, get_position(f) + subsize - header_size);
1142 static int32_t atom_read(struct mp4ff *f, int32_t size, uint8_t atom_type)
1144 uint64_t dest_position = get_position(f) + size - 8;
1145 if (atom_type == ATOM_STSZ) {
1146 /* sample size box */
1148 } else if (atom_type == ATOM_STTS) {
1149 /* time to sample box */
1151 } else if (atom_type == ATOM_CTTS) {
1152 /* composition offset box */
1154 } else if (atom_type == ATOM_STSC) {
1155 /* sample to chunk box */
1157 } else if (atom_type == ATOM_STCO) {
1158 /* chunk offset box */
1160 } else if (atom_type == ATOM_STSD) {
1161 /* sample description box */
1163 } else if (atom_type == ATOM_MVHD) {
1164 /* movie header box */
1166 } else if (atom_type == ATOM_MDHD) {
1169 } else if (atom_type == ATOM_META) {
1170 /* iTunes Metadata box */
1174 set_position(f, dest_position);
1178 /* parse atoms that are sub atoms of other atoms */
1179 static int32_t parse_sub_atoms(struct mp4ff *f, uint64_t total_size, int meta_only)
1182 uint8_t atom_type = 0;
1183 uint64_t counted_size = 0;
1184 uint8_t header_size = 0;
1186 while (counted_size < total_size) {
1187 size = atom_read_header(f, &atom_type, &header_size);
1188 counted_size += size;
1190 /* check for end of file */
1194 /* we're starting to read a new track, update index,
1195 * so that all data and tables get written in the right place
1197 if (atom_type == ATOM_TRAK)
1199 /* parse subatoms */
1200 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1201 set_position(f, get_position(f) + size - header_size);
1202 } else if (atom_type < SUBATOMIC) {
1203 parse_sub_atoms(f, size - header_size, meta_only);
1205 atom_read(f, (uint32_t) size, atom_type);
1212 /* parse root atoms */
1213 static int32_t parse_atoms(struct mp4ff *f, int meta_only)
1216 uint8_t atom_type = 0;
1217 uint8_t header_size = 0;
1220 f->stream->read_error = 0;
1223 atom_read_header(f, &atom_type, &header_size)) != 0) {
1224 f->file_size += size;
1225 f->last_atom = atom_type;
1227 if (atom_type == ATOM_MOOV && size > header_size) {
1228 f->moov_offset = get_position(f) - header_size;
1229 f->moov_size = size;
1232 /* parse subatoms */
1233 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1234 set_position(f, get_position(f) + size - header_size);
1235 } else if (atom_type < SUBATOMIC) {
1236 parse_sub_atoms(f, size - header_size, meta_only);
1238 /* skip this atom */
1239 set_position(f, get_position(f) + size - header_size);
1246 void mp4ff_get_decoder_config(const struct mp4ff *f, int track,
1247 unsigned char **ppBuf, unsigned int *pBufSize)
1249 if (track >= f->total_tracks) {
1255 if (f->track[track]->decoderConfig == NULL
1256 || f->track[track]->decoderConfigLen == 0) {
1260 *ppBuf = para_malloc(f->track[track]->decoderConfigLen);
1261 memcpy(*ppBuf, f->track[track]->decoderConfig,
1262 f->track[track]->decoderConfigLen);
1263 *pBufSize = f->track[track]->decoderConfigLen;
1267 struct mp4ff *mp4ff_open_read(struct mp4ff_callback *f)
1269 struct mp4ff *ff = para_calloc(sizeof(struct mp4ff));
1283 static int32_t tag_delete(struct mp4ff_metadata *tags)
1287 for (i = 0; i < tags->count; i++) {
1288 free(tags->tags[i].item);
1289 free(tags->tags[i].value);
1298 void mp4ff_close(struct mp4ff *ff)
1302 for (i = 0; i < ff->total_tracks; i++) {
1304 free(ff->track[i]->stsz_table);
1305 free(ff->track[i]->stts_sample_count);
1306 free(ff->track[i]->stts_sample_delta);
1307 free(ff->track[i]->stsc_first_chunk);
1308 free(ff->track[i]->stsc_samples_per_chunk);
1309 free(ff->track[i]->stsc_sample_desc_index);
1310 free(ff->track[i]->stco_chunk_offset);
1311 free(ff->track[i]->decoderConfig);
1312 free(ff->track[i]->ctts_sample_count);
1313 free(ff->track[i]->ctts_sample_offset);
1318 tag_delete(&(ff->tags));
1322 static int32_t chunk_of_sample(const struct mp4ff *f, int32_t track,
1323 int32_t sample, int32_t *chunk_sample, int32_t *chunk)
1325 int32_t total_entries = 0;
1326 int32_t chunk2entry;
1327 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1331 if (f->track[track] == NULL) {
1335 total_entries = f->track[track]->stsc_entry_count;
1342 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1343 *chunk = chunk2 - chunk1;
1344 range_samples = *chunk * chunk1samples;
1346 if (sample < total + range_samples)
1349 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1352 if (chunk2entry < total_entries) {
1354 total += range_samples;
1356 } while (chunk2entry < total_entries);
1359 *chunk = (sample - total) / chunk1samples + chunk1;
1363 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1368 static int32_t chunk_to_offset(const struct mp4ff *f, int32_t track,
1371 const struct mp4ff_track *p_track = f->track[track];
1373 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1374 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1376 } else if (p_track->stco_entry_count) {
1377 return p_track->stco_chunk_offset[chunk - 1];
1385 static int32_t sample_range_size(const struct mp4ff *f, int32_t track,
1386 int32_t chunk_sample, int32_t sample)
1389 const struct mp4ff_track *p_track = f->track[track];
1391 if (p_track->stsz_sample_size) {
1392 return (sample - chunk_sample) * p_track->stsz_sample_size;
1394 if (sample >= p_track->stsz_sample_count)
1397 for (i = chunk_sample, total = 0; i < sample; i++) {
1398 total += p_track->stsz_table[i];
1405 static int32_t sample_to_offset(const struct mp4ff *f, int32_t track,
1408 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1410 chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1412 chunk_offset1 = chunk_to_offset(f, track, chunk);
1413 chunk_offset2 = chunk_offset1 + sample_range_size(f,
1414 track, chunk_sample, sample);
1415 return chunk_offset2;
1418 void mp4ff_set_sample_position(struct mp4ff *f, int32_t track, int32_t sample)
1420 int32_t offset = sample_to_offset(f, track, sample);
1421 set_position(f, offset);
1424 int32_t mp4ff_get_sample_size(const struct mp4ff *f, int track, int sample)
1426 const struct mp4ff_track *t = f->track[track];
1428 if (t->stsz_sample_size != 0)
1429 return t->stsz_sample_size;
1430 return t->stsz_table[sample];
1433 uint32_t mp4ff_get_sample_rate(const struct mp4ff *f, int32_t track)
1435 return f->track[track]->sampleRate;
1438 uint32_t mp4ff_get_channel_count(const struct mp4ff *f, int32_t track)
1440 return f->track[track]->channelCount;
1443 int32_t mp4ff_num_samples(const struct mp4ff *f, int32_t track)
1448 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1449 total += f->track[track]->stts_sample_count[i];
1454 struct mp4ff *mp4ff_open_read_metaonly(struct mp4ff_callback *f)
1456 struct mp4ff *ff = para_calloc(sizeof(struct mp4ff));
1470 int32_t mp4ff_meta_get_num_items(const struct mp4ff *f)
1472 return f->tags.count;
1475 int32_t mp4ff_meta_get_by_index(const struct mp4ff *f, uint32_t index,
1476 char **item, char **value)
1478 if (index >= f->tags.count) {
1483 *item = para_strdup(f->tags.tags[index].item);
1484 *value = para_strdup(f->tags.tags[index].value);
1489 static uint32_t find_atom(struct mp4ff *f, uint64_t base, uint32_t size,
1492 uint32_t remaining = size;
1493 uint64_t atom_offset = base;
1498 set_position(f, atom_offset);
1502 atom_size = read_int32(f);
1503 if (atom_size > remaining || atom_size < 8)
1505 read_data(f, atom_name, 4);
1507 if (!memcmp(atom_name, name, 4)) {
1508 set_position(f, atom_offset);
1512 remaining -= atom_size;
1513 atom_offset += atom_size;
1518 static uint32_t find_atom_v2(struct mp4ff *f, uint64_t base, uint32_t size,
1519 const char *name, uint32_t extraheaders, const char *name_inside)
1521 uint64_t first_base = (uint64_t) (-1);
1522 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1524 uint64_t mybase = get_position(f);
1525 uint32_t mysize = read_int32(f);
1527 if (first_base == (uint64_t) (-1))
1528 first_base = mybase;
1530 if (mysize < 8 + extraheaders)
1533 if (find_atom (f, mybase + (8 + extraheaders),
1534 mysize - (8 + extraheaders), name_inside)) {
1535 set_position(f, mybase);
1539 if (size <= mysize) {
1546 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1548 set_position(f, first_base);
1561 static struct membuffer *membuffer_create(void)
1563 const unsigned initial_size = 256;
1565 struct membuffer *buf = para_malloc(sizeof(*buf));
1566 buf->data = para_malloc(initial_size);
1568 buf->allocated = initial_size;
1569 buf->error = buf->data == 0 ? 1 : 0;
1574 static unsigned membuffer_write(struct membuffer *buf, const void *ptr, unsigned bytes)
1576 unsigned dest_size = buf->written + bytes;
1580 if (dest_size > buf->allocated) {
1582 buf->allocated <<= 1;
1583 } while (dest_size > buf->allocated);
1586 void *newptr = realloc(buf->data, buf->allocated);
1598 memcpy((char *) buf->data + buf->written, ptr, bytes);
1599 buf->written += bytes;
1603 static unsigned membuffer_write_atom_name(struct membuffer *buf, const char *data)
1605 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1608 static unsigned membuffer_write_int16(struct membuffer *buf, uint16_t data)
1612 write_u16_be(temp, data);
1613 return membuffer_write(buf, temp, 2);
1616 static unsigned membuffer_write_int32(struct membuffer *buf, uint32_t data)
1619 write_u32_be(temp, data);
1620 return membuffer_write(buf, temp, 4);
1623 static void membuffer_write_track_tag(struct membuffer *buf, const char *name,
1624 uint32_t index, uint32_t total)
1626 membuffer_write_int32(buf,
1627 8 /*atom header */ + 8 /*data atom header */ +
1628 8 /*flags + reserved */ + 8 /*actual data */ );
1629 membuffer_write_atom_name(buf, name);
1630 membuffer_write_int32(buf,
1631 8 /*data atom header */ +
1632 8 /*flags + reserved */ + 8 /*actual data */ );
1633 membuffer_write_atom_name(buf, "data");
1634 membuffer_write_int32(buf, 0); //flags
1635 membuffer_write_int32(buf, 0); //reserved
1636 membuffer_write_int16(buf, 0);
1637 membuffer_write_int16(buf, (uint16_t) index); //track number
1638 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1639 membuffer_write_int16(buf, 0);
1642 static void membuffer_write_int16_tag(struct membuffer *buf, const char *name,
1645 membuffer_write_int32(buf,
1646 8 /*atom header */ + 8 /*data atom header */ +
1647 8 /*flags + reserved */ + 2 /*actual data */ );
1648 membuffer_write_atom_name(buf, name);
1649 membuffer_write_int32(buf,
1650 8 /*data atom header */ +
1651 8 /*flags + reserved */ + 2 /*actual data */ );
1652 membuffer_write_atom_name(buf, "data");
1653 membuffer_write_int32(buf, 0); //flags
1654 membuffer_write_int32(buf, 0); //reserved
1655 membuffer_write_int16(buf, value); //value
1658 static uint32_t myatoi(const char *param)
1660 return param ? atoi(param) : 0;
1663 static uint32_t meta_genre_to_index(const char *genrestr)
1666 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1667 if (!strcasecmp(genrestr, ID3v1GenreList[n]))
1673 struct stdmeta_entry {
1678 struct stdmeta_entry stdmetas[] = {
1679 {"\xA9" "nam", "title"},
1680 {"\xA9" "ART", "artist"},
1681 {"\xA9" "wrt", "writer"},
1682 {"\xA9" "alb", "album"},
1683 {"\xA9" "day", "date"},
1684 {"\xA9" "too", "tool"},
1685 {"\xA9" "cmt", "comment"},
1686 {"cpil", "compilation"},
1688 {"aART", "album_artist"},
1691 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1694 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1695 if (!strcasecmp(name, stdmetas[n].name))
1696 return stdmetas[n].atom;
1701 static void membuffer_write_std_tag(struct membuffer *buf, const char *name,
1706 /* special check for compilation flag */
1707 if (strcmp(name, "cpil") == 0) {
1711 membuffer_write_int32(buf,
1712 8 /*atom header */ + 8 /*data atom header */ +
1713 8 /*flags + reserved */ + strlen(value));
1714 membuffer_write_atom_name(buf, name);
1715 membuffer_write_int32(buf,
1716 8 /*data atom header */ +
1717 8 /*flags + reserved */ + strlen(value));
1718 membuffer_write_atom_name(buf, "data");
1719 membuffer_write_int32(buf, flags); //flags
1720 membuffer_write_int32(buf, 0); //reserved
1721 membuffer_write(buf, value, strlen(value));
1724 static void membuffer_write_custom_tag(struct membuffer *buf, const char *name,
1727 membuffer_write_int32(buf,
1728 8 /*atom header */ +
1729 0x1C /*weirdo itunes atom */ +
1730 12 /*name atom header */ + strlen(name) +
1731 16 /*data atom header + flags */ + strlen(value));
1732 membuffer_write_atom_name(buf, "----");
1733 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1734 membuffer_write_atom_name(buf, "mean");
1735 membuffer_write_int32(buf, 0);
1736 membuffer_write(buf, "com.apple.iTunes", 16);
1737 membuffer_write_int32(buf, 12 + strlen(name));
1738 membuffer_write_atom_name(buf, "name");
1739 membuffer_write_int32(buf, 0);
1740 membuffer_write(buf, name, strlen(name));
1741 membuffer_write_int32(buf,
1742 8 /*data atom header */ +
1743 8 /*flags + reserved */ + strlen(value));
1744 membuffer_write_atom_name(buf, "data");
1745 membuffer_write_int32(buf, 1); //flags
1746 membuffer_write_int32(buf, 0); //reserved
1747 membuffer_write(buf, value, strlen(value));
1750 static unsigned membuffer_error(const struct membuffer *buf)
1755 static void membuffer_free(struct membuffer *buf)
1761 static unsigned membuffer_get_size(const struct membuffer *buf)
1763 return buf->written;
1766 static void *membuffer_detach(struct membuffer *buf)
1773 ret = realloc(buf->data, buf->written);
1784 static uint32_t create_ilst(const struct mp4ff_metadata *data, void **out_buffer,
1785 uint32_t * out_size)
1787 struct membuffer *buf = membuffer_create();
1789 char *mask = para_calloc(data->count);
1790 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1791 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1792 const char *genre_ptr = 0, *tempo_ptr = 0;
1794 for (metaptr = 0; metaptr < data->count; metaptr++) {
1795 struct mp4ff_tag *tag = &data->tags[metaptr];
1796 if (!strcasecmp(tag->item, "tracknumber")
1797 || !strcasecmp(tag->item, "track")) {
1798 if (tracknumber_ptr == 0)
1799 tracknumber_ptr = tag->value;
1801 } else if (!strcasecmp(tag->item, "totaltracks")) {
1802 if (totaltracks_ptr == 0)
1803 totaltracks_ptr = tag->value;
1805 } else if (!strcasecmp(tag->item, "discnumber")
1806 || !strcasecmp(tag->item, "disc")) {
1807 if (discnumber_ptr == 0)
1808 discnumber_ptr = tag->value;
1810 } else if (!strcasecmp(tag->item, "totaldiscs")) {
1811 if (totaldiscs_ptr == 0)
1812 totaldiscs_ptr = tag->value;
1814 } else if (!strcasecmp(tag->item, "genre")) {
1816 genre_ptr = tag->value;
1818 } else if (!strcasecmp(tag->item, "tempo")) {
1820 tempo_ptr = tag->value;
1825 if (tracknumber_ptr)
1826 membuffer_write_track_tag(buf, "trkn", myatoi(tracknumber_ptr),
1827 myatoi(totaltracks_ptr));
1829 membuffer_write_track_tag(buf, "disk", myatoi(discnumber_ptr),
1830 myatoi(totaldiscs_ptr));
1832 membuffer_write_int16_tag(buf, "tmpo", myatoi(tempo_ptr));
1835 uint32_t index = meta_genre_to_index(genre_ptr);
1837 membuffer_write_std_tag(buf, "©gen", genre_ptr);
1839 membuffer_write_int16_tag(buf, "gnre", index);
1841 for (metaptr = 0; metaptr < data->count; metaptr++) {
1842 struct mp4ff_tag *tag;
1843 const char *std_meta_atom;
1847 tag = &data->tags[metaptr];
1848 std_meta_atom = find_standard_meta(tag->item);
1850 membuffer_write_std_tag(buf, std_meta_atom, tag->value);
1852 membuffer_write_custom_tag(buf, tag->item, tag->value);
1856 if (membuffer_error(buf)) {
1857 membuffer_free(buf);
1861 *out_size = membuffer_get_size(buf);
1862 *out_buffer = membuffer_detach(buf);
1863 membuffer_free(buf);
1868 static void membuffer_write_atom(struct membuffer *buf, const char *name, unsigned size,
1871 membuffer_write_int32(buf, size + 8);
1872 membuffer_write_atom_name(buf, name);
1873 membuffer_write(buf, data, size);
1876 static void *membuffer_get_ptr(const struct membuffer *buf)
1881 static void membuffer_set_error(struct membuffer *buf)
1886 static unsigned membuffer_transfer_from_file(struct membuffer *buf, struct mp4ff *src,
1892 oldsize = membuffer_get_size(buf);
1893 if (membuffer_write(buf, 0, bytes) != bytes)
1896 bufptr = membuffer_get_ptr(buf);
1900 if ((unsigned)read_data(src, (char *) bufptr + oldsize, bytes) !=
1902 membuffer_set_error(buf);
1909 static uint32_t create_meta(const struct mp4ff_metadata *data, void **out_buffer,
1910 uint32_t * out_size)
1912 struct membuffer *buf;
1916 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1919 buf = membuffer_create();
1921 membuffer_write_int32(buf, 0);
1922 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1925 *out_size = membuffer_get_size(buf);
1926 *out_buffer = membuffer_detach(buf);
1927 membuffer_free(buf);
1931 static uint32_t create_udta(const struct mp4ff_metadata *data, void **out_buffer,
1932 uint32_t * out_size)
1934 struct membuffer *buf;
1938 if (!create_meta(data, &meta_buffer, &meta_size))
1941 buf = membuffer_create();
1943 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1947 *out_size = membuffer_get_size(buf);
1948 *out_buffer = membuffer_detach(buf);
1949 membuffer_free(buf);
1953 static uint32_t fix_byte_order_32(uint32_t src)
1955 return read_u32_be(&src);
1958 static uint32_t modify_moov(struct mp4ff *f, const struct mp4ff_metadata *data,
1959 void **out_buffer, uint32_t * out_size)
1961 uint64_t total_base = f->moov_offset + 8;
1962 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1964 uint64_t udta_offset, meta_offset, ilst_offset;
1965 uint32_t udta_size, meta_size, ilst_size;
1967 uint32_t new_ilst_size;
1968 void *new_ilst_buffer;
1973 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1974 struct membuffer *buf;
1975 void *new_udta_buffer;
1976 uint32_t new_udta_size;
1977 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1980 buf = membuffer_create();
1981 set_position(f, total_base);
1982 membuffer_transfer_from_file(buf, f, total_size);
1984 membuffer_write_atom(buf, "udta", new_udta_size,
1987 free(new_udta_buffer);
1989 *out_size = membuffer_get_size(buf);
1990 *out_buffer = membuffer_detach(buf);
1991 membuffer_free(buf);
1994 udta_offset = get_position(f);
1995 udta_size = read_int32(f);
1996 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
1997 struct membuffer *buf;
1998 void *new_meta_buffer;
1999 uint32_t new_meta_size;
2000 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
2003 buf = membuffer_create();
2004 set_position(f, total_base);
2005 membuffer_transfer_from_file(buf, f,
2006 (uint32_t)(udta_offset - total_base));
2008 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2009 membuffer_write_atom_name(buf, "udta");
2010 membuffer_transfer_from_file(buf, f, udta_size);
2012 membuffer_write_atom(buf, "meta", new_meta_size,
2014 free(new_meta_buffer);
2016 *out_size = membuffer_get_size(buf);
2017 *out_buffer = membuffer_detach(buf);
2018 membuffer_free(buf);
2021 meta_offset = get_position(f);
2022 meta_size = read_int32(f);
2023 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2024 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2025 ilst_offset = get_position(f);
2026 ilst_size = read_int32(f);
2028 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2031 size_delta = new_ilst_size - (ilst_size - 8);
2033 *out_size = total_size + size_delta;
2034 *out_buffer = para_malloc(*out_size);
2035 p_out = (uint8_t *) * out_buffer;
2037 set_position(f, total_base);
2039 (uint32_t) (udta_offset - total_base));
2040 p_out += (uint32_t) (udta_offset - total_base);
2041 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2043 read_data(f, p_out, 4);
2046 (uint32_t) (meta_offset - udta_offset - 8));
2047 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2048 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2050 read_data(f, p_out, 4);
2053 (uint32_t) (ilst_offset - meta_offset - 8));
2054 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2055 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2057 read_data(f, p_out, 4);
2060 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2061 p_out += new_ilst_size;
2063 set_position(f, ilst_offset + ilst_size);
2064 read_data(f, p_out, (uint32_t) (total_size
2065 - (ilst_offset - total_base) - ilst_size));
2067 free(new_ilst_buffer);
2072 static int32_t write_data(struct mp4ff *f, void *data, uint32_t size)
2076 result = f->stream->write(f->stream->user_data, data, size);
2078 f->current_position += size;
2083 static int32_t write_int32(struct mp4ff *f, uint32_t data)
2086 write_u32_be(temp, data);
2087 return write_data(f, temp, sizeof(temp));
2090 static int32_t truncate_stream(struct mp4ff *f)
2092 return f->stream->truncate(f->stream->user_data);
2095 int32_t mp4ff_meta_update(struct mp4ff_callback *f, const struct mp4ff_metadata *data)
2097 void *new_moov_data;
2098 uint32_t new_moov_size;
2100 struct mp4ff *ff = para_calloc(sizeof(struct mp4ff));
2102 set_position(ff, 0);
2106 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2111 /* copy moov atom to end of the file */
2112 if (ff->last_atom != ATOM_MOOV) {
2113 char *free_data = "free";
2115 /* rename old moov to free */
2116 set_position(ff, ff->moov_offset + 4);
2117 write_data(ff, free_data, 4);
2119 set_position(ff, ff->file_size);
2120 write_int32(ff, new_moov_size + 8);
2121 write_data(ff, "moov", 4);
2122 write_data(ff, new_moov_data, new_moov_size);
2124 set_position(ff, ff->moov_offset);
2125 write_int32(ff, new_moov_size + 8);
2126 write_data(ff, "moov", 4);
2127 write_data(ff, new_moov_data, new_moov_size);
2130 truncate_stream(ff);
2136 /* find a metadata item by name */
2137 /* returns 0 if item found, 1 if no such item */
2138 static int32_t meta_find_by_name(const struct mp4ff *f, const char *item,
2143 for (i = 0; i < f->tags.count; i++) {
2144 if (!strcasecmp(f->tags.tags[i].item, item)) {
2145 *value = para_strdup(f->tags.tags[i].value);
2156 int32_t mp4ff_meta_get_artist(const struct mp4ff *f, char **value)
2158 return meta_find_by_name(f, "artist", value);
2161 int32_t mp4ff_meta_get_title(const struct mp4ff *f, char **value)
2163 return meta_find_by_name(f, "title", value);
2166 int32_t mp4ff_meta_get_date(const struct mp4ff *f, char **value)
2168 return meta_find_by_name(f, "date", value);
2171 int32_t mp4ff_meta_get_album(const struct mp4ff *f, char **value)
2173 return meta_find_by_name(f, "album", value);
2176 int32_t mp4ff_meta_get_comment(const struct mp4ff *f, char **value)
2178 return meta_find_by_name(f, "comment", value);