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(const int8_t a1, const int8_t b1,
117 const int8_t c1, const int8_t d1,
118 const int8_t a2, const int8_t b2,
119 const int8_t c2, const int8_t d2)
121 if (a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2)
135 /* atoms with subatoms */
143 ATOM_ILST = 8, /* iTunes Metadata list */
154 ATOM_COMPILATION = 19,
164 /* atoms without subatoms */
184 ATOM_META = 148, /* iTunes Metadata box */
185 ATOM_NAME = 149, /* iTunes Metadata name box */
186 ATOM_DATA = 150, /* iTunes Metadata data box */
193 ATOM_ALBUM_ARTIST = 157,
194 ATOM_CONTENTGROUP = 158,
196 ATOM_DESCRIPTION = 160,
199 ATOM_EPISODENAME = 163,
200 ATOM_SORTTITLE = 164,
201 ATOM_SORTALBUM = 165,
202 ATOM_SORTARTIST = 166,
203 ATOM_SORTALBUMARTIST = 167,
204 ATOM_SORTWRITER = 168,
213 #define ATOM_FREE ATOM_UNKNOWN
214 #define ATOM_SKIP ATOM_UNKNOWN
216 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
218 static uint8_t atom_name_to_type(const int8_t a, const int8_t b,
219 const int8_t c, const int8_t d)
222 if (atom_compare(a, b, c, d, 'm', 'o', 'o', 'v'))
224 else if (atom_compare(a, b, c, d, 'm', 'i', 'n', 'f'))
226 else if (atom_compare(a, b, c, d, 'm', 'd', 'i', 'a'))
228 else if (atom_compare(a, b, c, d, 'm', 'd', 'a', 't'))
230 else if (atom_compare(a, b, c, d, 'm', 'd', 'h', 'd'))
232 else if (atom_compare(a, b, c, d, 'm', 'v', 'h', 'd'))
234 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'a'))
236 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'v'))
238 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 's'))
240 else if (atom_compare(a, b, c, d, 'm', 'e', 't', 'a'))
242 } else if (a == 't') {
243 if (atom_compare(a, b, c, d, 't', 'r', 'a', 'k'))
245 else if (atom_compare(a, b, c, d, 't', 'k', 'h', 'd'))
247 else if (atom_compare(a, b, c, d, 't', 'r', 'e', 'f'))
249 else if (atom_compare(a, b, c, d, 't', 'r', 'k', 'n'))
251 else if (atom_compare(a, b, c, d, 't', 'm', 'p', 'o'))
253 else if (atom_compare(a, b, c, d, 't', 'v', 'n', 'n'))
255 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'h'))
257 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 'n'))
258 return ATOM_EPISODENAME;
259 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'n'))
261 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 's'))
263 } else if (a == 's') {
264 if (atom_compare(a, b, c, d, 's', 't', 'b', 'l'))
266 else if (atom_compare(a, b, c, d, 's', 'm', 'h', 'd'))
268 else if (atom_compare(a, b, c, d, 's', 't', 's', 'd'))
270 else if (atom_compare(a, b, c, d, 's', 't', 't', 's'))
272 else if (atom_compare(a, b, c, d, 's', 't', 'c', 'o'))
274 else if (atom_compare(a, b, c, d, 's', 't', 's', 'c'))
276 else if (atom_compare(a, b, c, d, 's', 't', 's', 'z'))
278 else if (atom_compare(a, b, c, d, 's', 't', 'z', '2'))
280 else if (atom_compare(a, b, c, d, 's', 'k', 'i', 'p'))
282 else if (atom_compare(a, b, c, d, 's', 'i', 'n', 'f'))
284 else if (atom_compare(a, b, c, d, 's', 'c', 'h', 'i'))
286 else if (atom_compare(a, b, c, d, 's', 'o', 'n', 'm'))
287 return ATOM_SORTTITLE;
288 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'l'))
289 return ATOM_SORTALBUM;
290 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'r'))
291 return ATOM_SORTARTIST;
292 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'a'))
293 return ATOM_SORTALBUMARTIST;
294 else if (atom_compare(a, b, c, d, 's', 'o', 'c', 'o'))
295 return ATOM_SORTWRITER;
296 else if (atom_compare(a, b, c, d, 's', 'o', 's', 'n'))
297 return ATOM_SORTSHOW;
298 } else if (a == COPYRIGHT_SYMBOL) {
299 if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'n', 'a', 'm'))
301 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'A', 'R', 'T'))
303 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'w', 'r', 't'))
305 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'a', 'l', 'b'))
307 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'd', 'a', 'y'))
309 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 't', 'o', 'o'))
311 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'c', 'm', 't'))
313 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'e', 'n'))
315 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'r', 'p'))
316 return ATOM_CONTENTGROUP;
317 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'l', 'y', 'r'))
321 if (atom_compare(a, b, c, d, 'e', 'd', 't', 's'))
323 else if (atom_compare(a, b, c, d, 'e', 's', 'd', 's'))
325 else if (atom_compare(a, b, c, d, 'f', 't', 'y', 'p'))
327 else if (atom_compare(a, b, c, d, 'f', 'r', 'e', 'e'))
329 else if (atom_compare(a, b, c, d, 'h', 'm', 'h', 'd'))
331 else if (atom_compare(a, b, c, d, 'v', 'm', 'h', 'd'))
333 else if (atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
335 else if (atom_compare(a, b, c, d, 'i', 'l', 's', 't'))
337 else if (atom_compare(a, b, c, d, 'n', 'a', 'm', 'e'))
339 else if (atom_compare(a, b, c, d, 'd', 'a', 't', 'a'))
341 else if (atom_compare(a, b, c, d, 'd', 'i', 's', 'k'))
343 else if (atom_compare(a, b, c, d, 'g', 'n', 'r', 'e'))
345 else if (atom_compare(a, b, c, d, 'c', 'o', 'v', 'r'))
347 else if (atom_compare(a, b, c, d, 'c', 'p', 'i', 'l'))
348 return ATOM_COMPILATION;
349 else if (atom_compare(a, b, c, d, 'c', 't', 't', 's'))
351 else if (atom_compare(a, b, c, d, 'd', 'r', 'm', 's'))
353 else if (atom_compare(a, b, c, d, 'f', 'r', 'm', 'a'))
355 else if (atom_compare(a, b, c, d, 'p', 'r', 'i', 'v'))
357 else if (atom_compare(a, b, c, d, 'i', 'v', 'i', 'v'))
359 else if (atom_compare(a, b, c, d, 'u', 's', 'e', 'r'))
361 else if (atom_compare(a, b, c, d, 'k', 'e', 'y', ' '))
363 else if (atom_compare(a, b, c, d, 'a', 'A', 'R', 'T'))
364 return ATOM_ALBUM_ARTIST;
365 else if (atom_compare(a, b, c, d, 'd', 'e', 's', 'c'))
366 return ATOM_DESCRIPTION;
367 else if (atom_compare(a, b, c, d, 'p', 'c', 's', 't'))
373 /* read atom header, return atom size, atom size is with header included */
374 static uint64_t atom_read_header(struct mp4ff *f, uint8_t * atom_type,
375 uint8_t * header_size)
379 int8_t atom_header[8];
381 ret = read_data(f, atom_header, 8);
385 size = read_u32_be(atom_header);
388 /* check for 64 bit atom size */
391 size = read_int64(f);
393 *atom_type = atom_name_to_type(atom_header[4], atom_header[5],
394 atom_header[6], atom_header[7]);
398 static int64_t get_position(const struct mp4ff *f)
400 return f->current_position;
403 static int need_parse_when_meta_only(uint8_t atom_type)
424 static int32_t set_position(struct mp4ff *f, const int64_t position)
426 f->stream->seek(f->stream->user_data, position);
427 f->current_position = position;
432 static void track_add(struct mp4ff *f)
436 if (f->total_tracks > MAX_TRACKS) {
441 f->track[f->total_tracks - 1] = para_calloc(sizeof(struct mp4ff_track));
444 static uint8_t read_char(struct mp4ff *f)
447 read_data(f, &output, 1);
451 static uint32_t read_int24(struct mp4ff *f)
455 read_data(f, data, 3);
456 return read_u24_be(data);
459 static uint32_t read_int32(struct mp4ff *f)
463 read_data(f, data, 4);
464 return read_u32_be(data);
467 static int32_t read_stsz(struct mp4ff *f)
470 struct mp4ff_track *t;
472 if (f->total_tracks == 0)
474 t = f->track[f->total_tracks - 1];
475 read_char(f); /* version */
476 read_int24(f); /* flags */
477 t->stsz_sample_size = read_int32(f);
478 t->stsz_sample_count = read_int32(f);
479 if (t->stsz_sample_size != 0)
481 t->stsz_table = para_malloc(t->stsz_sample_count * sizeof(int32_t));
482 for (i = 0; i < t->stsz_sample_count && !f->stream->read_error; i++)
483 t->stsz_table[i] = read_int32(f);
487 static int32_t read_stts(struct mp4ff *f)
490 struct mp4ff_track *t;
493 if (f->total_tracks == 0)
495 t = f->track[f->total_tracks - 1];
496 if (t->stts_entry_count)
498 read_char(f); /* version */
499 read_int24(f); /* flags */
500 t->stts_entry_count = read_int32(f);
502 t->stts_sample_count = para_malloc(t->stts_entry_count
504 t->stts_sample_delta = para_malloc(t->stts_entry_count
507 for (i = 0; i < t->stts_entry_count && !f->stream->read_error; i++) {
508 t->stts_sample_count[i] = read_int32(f);
509 t->stts_sample_delta[i] = read_int32(f);
514 static int32_t read_ctts(struct mp4ff *f)
517 struct mp4ff_track *t;
519 if (f->total_tracks == 0)
521 t = f->track[f->total_tracks - 1];
522 if (t->ctts_entry_count)
525 read_char(f); /* version */
526 read_int24(f); /* flags */
527 t->ctts_entry_count = read_int32(f);
529 t->ctts_sample_count = para_malloc(t->ctts_entry_count
531 t->ctts_sample_offset = para_malloc(t->ctts_entry_count
535 for (i = 0; i < t->ctts_entry_count && !f->stream->read_error; i++) {
536 t->ctts_sample_count[i] = read_int32(f);
537 t->ctts_sample_offset[i] = read_int32(f);
542 static int32_t read_stsc(struct mp4ff *f)
545 struct mp4ff_track *t;
547 if (f->total_tracks == 0)
549 t = f->track[f->total_tracks - 1];
551 read_char(f); /* version */
552 read_int24(f); /* flags */
553 t->stsc_entry_count = read_int32(f);
554 t->stsc_first_chunk = para_malloc(t->stsc_entry_count * sizeof(int32_t));
555 t->stsc_samples_per_chunk = para_malloc(t->stsc_entry_count
557 t->stsc_sample_desc_index = para_malloc(t->stsc_entry_count *
561 for (i = 0; i < t->stsc_entry_count && !f->stream->read_error; i++) {
562 t->stsc_first_chunk[i] = read_int32(f);
563 t->stsc_samples_per_chunk[i] = read_int32(f);
564 t->stsc_sample_desc_index[i] = read_int32(f);
569 static int32_t read_stco(struct mp4ff *f)
572 struct mp4ff_track *t;
574 if (f->total_tracks == 0)
576 t = f->track[f->total_tracks - 1];
578 read_char(f); /* version */
579 read_int24(f); /* flags */
580 t->stco_entry_count = read_int32(f);
581 t->stco_chunk_offset = para_malloc(t->stco_entry_count
584 for (i = 0; i < t->stco_entry_count && !f->stream->read_error; i++)
585 t->stco_chunk_offset[i] = read_int32(f);
589 static uint16_t read_int16(struct mp4ff *f)
593 read_data(f, data, 2);
594 return read_u16_be(data);
597 static uint32_t read_mp4_descr_length(struct mp4ff *f)
600 uint8_t numBytes = 0;
606 length = (length << 7) | (b & 0x7F);
607 } while ((b & 0x80) && numBytes < 4);
611 static int32_t read_esds(struct mp4ff *f)
615 struct mp4ff_track *t;
617 if (f->total_tracks == 0)
619 t = f->track[f->total_tracks - 1];
620 read_char(f); /* version */
621 read_int24(f); /* flags */
622 /* get and verify ES_DescrTag */
626 if (read_mp4_descr_length(f) < 5 + 15) {
636 /* get and verify DecoderConfigDescrTab */
637 if (read_char(f) != 0x04) {
642 temp = read_mp4_descr_length(f);
646 t->audioType = read_char(f);
647 read_int32(f); //0x15000414 ????
648 t->maxBitrate = read_int32(f);
649 t->avgBitrate = read_int32(f);
651 /* get and verify DecSpecificInfoTag */
652 if (read_char(f) != 0x05) {
657 t->decoderConfigLen = read_mp4_descr_length(f);
658 free(t->decoderConfig);
659 t->decoderConfig = para_malloc(t->decoderConfigLen);
660 read_data(f, t->decoderConfig, t->decoderConfigLen);
661 /* will skip the remainder of the atom */
665 static int32_t read_mp4a(struct mp4ff *f)
668 uint8_t atom_type = 0;
669 uint8_t header_size = 0;
670 struct mp4ff_track *t;
672 if (f->total_tracks == 0)
674 t = f->track[f->total_tracks - 1];
676 for (i = 0; i < 6; i++) {
677 read_char(f); /* reserved */
679 /* data_reference_index */ read_int16(f);
681 read_int32(f); /* reserved */
682 read_int32(f); /* reserved */
684 t->channelCount = read_int16(f);
685 t->sampleSize = read_int16(f);
690 t->sampleRate = read_int16(f);
694 atom_read_header(f, &atom_type, &header_size);
695 if (atom_type == ATOM_ESDS)
700 static int32_t read_stsd(struct mp4ff *f)
703 uint8_t header_size = 0;
704 struct mp4ff_track *t;
707 if (f->total_tracks == 0)
709 t = f->track[f->total_tracks - 1];
711 read_char(f); /* version */
712 read_int24(f); /* flags */
714 t->stsd_entry_count = read_int32(f);
717 for (i = 0; i < t->stsd_entry_count && !f->stream->read_error; i++) {
718 uint64_t skip = get_position(f);
720 uint8_t atom_type = 0;
721 size = atom_read_header(f, &atom_type, &header_size);
724 if (atom_type == ATOM_MP4A) {
725 t->type = TRACK_AUDIO;
727 } else if (atom_type == ATOM_MP4V) {
728 t->type = TRACK_VIDEO;
729 } else if (atom_type == ATOM_MP4S) {
730 t->type = TRACK_SYSTEM;
732 t->type = TRACK_UNKNOWN;
734 set_position(f, skip);
740 static int32_t read_mvhd(struct mp4ff *f)
744 read_char(f); /* version */
745 read_int24(f); /* flags */
746 read_int32(f); /* creation_time */
747 read_int32(f); /* modification_time */
748 f->time_scale = read_int32(f);
749 f->duration = read_int32(f);
750 read_int32(f); /* preferred_rate */
751 read_int16(f); /* preferred_volume */
752 for (i = 0; i < 10; i++)
753 read_char(f); /* reserved */
754 for (i = 0; i < 9; i++)
755 read_int32(f); /* matrix */
756 read_int32(f); /* preview_time */
757 read_int32(f); /* preview_duration */
758 read_int32(f); /* poster_time */
759 read_int32(f); /* selection_time */
760 read_int32(f); /* selection_duration */
761 read_int32(f); /* current_time */
762 read_int32(f); /* next_track_id */
766 static int32_t tag_add_field(struct mp4ff_metadata *tags, const char *item,
767 const char *value, int32_t len)
769 void *backup = (void *) tags->tags;
771 if (!item || (item && !*item) || !value)
774 tags->tags = (struct mp4ff_tag *)realloc(tags->tags,
775 (tags->count + 1) * sizeof(struct mp4ff_tag));
780 tags->tags[tags->count].item = para_strdup(item);
781 tags->tags[tags->count].len = len;
783 tags->tags[tags->count].value = para_malloc(len + 1);
784 memcpy(tags->tags[tags->count].value, value, len);
785 tags->tags[tags->count].value[len] = 0;
787 tags->tags[tags->count].value = para_strdup(value);
794 static const char *ID3v1GenreList[] = {
795 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
796 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
797 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
798 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
799 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
800 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
801 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
802 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
803 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
804 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
805 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
806 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
807 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
808 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
809 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
810 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
811 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
812 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
813 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
814 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
815 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
816 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
817 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
818 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
819 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
820 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
821 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
822 "Anime", "JPop", "SynthPop",
825 static const char *meta_index_to_genre(uint32_t idx)
827 if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
828 return ID3v1GenreList[idx - 1];
834 static char *read_string(struct mp4ff *f, uint32_t length)
836 char *str = para_malloc(length + 1);
837 if ((uint32_t)read_data(f, str, length) != length) {
845 static int32_t set_metadata_name(const uint8_t atom_type, char **name)
847 static char *tag_names[] = {
848 "unknown", "title", "artist", "writer", "album",
849 "date", "tool", "comment", "genre", "track",
850 "disc", "compilation", "genre", "tempo", "cover",
851 "album_artist", "contentgroup", "lyrics", "description",
852 "network", "show", "episodename",
853 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
854 "sortwriter", "sortshow",
855 "season", "episode", "podcast"
890 case ATOM_COMPILATION:
902 case ATOM_ALBUM_ARTIST:
905 case ATOM_CONTENTGROUP:
911 case ATOM_DESCRIPTION:
920 case ATOM_EPISODENAME:
929 case ATOM_SORTARTIST:
932 case ATOM_SORTALBUMARTIST:
935 case ATOM_SORTWRITER:
955 *name = para_strdup(tag_names[tag_idx]);
959 static uint32_t min_body_size(const uint8_t atom_type)
966 return sizeof (char) /* version */
967 + sizeof(uint8_t) * 3 /* flags */
968 + sizeof(uint32_t) /* reserved */
969 + sizeof(uint16_t) /* leading uint16_t */
970 + sizeof(uint16_t) /* track */
971 + sizeof(uint16_t); /* totaltracks */
973 return sizeof (char) /* version */
974 + sizeof(uint8_t) * 3 /* flags */
975 + sizeof(uint32_t) /* reserved */
976 + sizeof(uint16_t) /* disc */
977 + sizeof(uint16_t); /* totaldiscs */
978 default: assert(false);
982 static int32_t parse_tag(struct mp4ff *f, const uint8_t parent,
986 uint8_t header_size = 0;
987 uint64_t subsize, sumsize;
996 sumsize < size && !f->stream->read_error; /* CVE-2017-9222 */
997 set_position(f, destpos), sumsize += subsize
999 subsize = atom_read_header(f, &atom_type, &header_size);
1000 destpos = get_position(f) + subsize - header_size;
1003 if (atom_type == ATOM_NAME) {
1004 read_char(f); /* version */
1005 read_int24(f); /* flags */
1007 name = read_string(f, subsize - (header_size + 4));
1010 if (atom_type != ATOM_DATA)
1012 read_char(f); /* version */
1013 read_int24(f); /* flags */
1014 read_int32(f); /* reserved */
1016 /* some need special attention */
1017 if (parent == ATOM_GENRE2 || parent == ATOM_TEMPO) {
1019 if (subsize - header_size < min_body_size(parent))
1021 val = read_int16(f);
1022 if (parent == ATOM_TEMPO) {
1024 sprintf(temp, "%.5u BPM", val);
1025 tag_add_field(&(f-> tags), "tempo",
1028 const char *tmp = meta_index_to_genre(val);
1030 tag_add_field (&(f->tags),
1034 } else if (parent == ATOM_TRACK || parent == ATOM_DISC) {
1035 uint16_t index, total;
1037 if (subsize - header_size < min_body_size(parent))
1040 index = read_int16(f);
1041 total = read_int16(f);
1042 if (parent == ATOM_TRACK)
1044 sprintf(temp, "%d", index);
1045 tag_add_field(&(f->tags), parent == ATOM_TRACK?
1046 "track" : "disc", temp, -1);
1048 sprintf(temp, "%d", total);
1049 tag_add_field(& (f-> tags),
1050 parent == ATOM_TRACK?
1051 "totaltracks" : "totaldiscs", temp, -1);
1056 data = read_string(f, subsize - (header_size + 8));
1057 len = subsize - (header_size + 8);
1063 set_metadata_name(parent , &name);
1065 tag_add_field(&(f->tags), name, data, len);
1074 static int32_t read_mdhd(struct mp4ff *f)
1077 struct mp4ff_track *t;
1080 if (f->total_tracks == 0)
1082 t = f->track[f->total_tracks - 1];
1084 version = read_int32(f);
1086 read_int64(f); //creation-time
1087 read_int64(f); //modification-time
1088 t->timeScale = read_int32(f); //timescale
1089 t->duration = read_int64(f); //duration
1090 } else { //version == 0
1093 read_int32(f); //creation-time
1094 read_int32(f); //modification-time
1095 t->timeScale = read_int32(f); //timescale
1096 temp = read_int32(f);
1097 t->duration = (temp == (uint32_t) (-1))?
1098 (uint64_t) (-1) : (uint64_t) (temp);
1105 static int32_t parse_metadata(struct mp4ff *f, const int32_t size)
1107 uint64_t subsize, sumsize = 0;
1109 uint8_t header_size = 0;
1111 while (sumsize < size) {
1112 subsize = atom_read_header(f, &atom_type, &header_size);
1115 parse_tag(f, atom_type, (uint32_t)(subsize - header_size));
1122 static int32_t read_meta(struct mp4ff *f, const uint64_t size)
1124 uint64_t subsize, sumsize = 0;
1126 uint8_t header_size = 0;
1128 read_char(f); /* version */
1129 read_int24(f); /* flags */
1131 while (sumsize < (size - (header_size + 4))) {
1132 subsize = atom_read_header(f, &atom_type, &header_size);
1133 if (subsize <= header_size + 4)
1135 if (atom_type == ATOM_ILST) {
1136 parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1138 set_position(f, get_position(f) + subsize - header_size);
1146 static int32_t atom_read(struct mp4ff *f, const int32_t size,
1147 const uint8_t atom_type)
1149 uint64_t dest_position = get_position(f) + size - 8;
1150 if (atom_type == ATOM_STSZ) {
1151 /* sample size box */
1153 } else if (atom_type == ATOM_STTS) {
1154 /* time to sample box */
1156 } else if (atom_type == ATOM_CTTS) {
1157 /* composition offset box */
1159 } else if (atom_type == ATOM_STSC) {
1160 /* sample to chunk box */
1162 } else if (atom_type == ATOM_STCO) {
1163 /* chunk offset box */
1165 } else if (atom_type == ATOM_STSD) {
1166 /* sample description box */
1168 } else if (atom_type == ATOM_MVHD) {
1169 /* movie header box */
1171 } else if (atom_type == ATOM_MDHD) {
1174 } else if (atom_type == ATOM_META) {
1175 /* iTunes Metadata box */
1179 set_position(f, dest_position);
1183 /* parse atoms that are sub atoms of other atoms */
1184 static int32_t parse_sub_atoms(struct mp4ff *f, const uint64_t total_size, int meta_only)
1187 uint8_t atom_type = 0;
1188 uint64_t counted_size = 0;
1189 uint8_t header_size = 0;
1191 while (counted_size < total_size) {
1192 size = atom_read_header(f, &atom_type, &header_size);
1193 counted_size += size;
1195 /* check for end of file */
1199 /* we're starting to read a new track, update index,
1200 * so that all data and tables get written in the right place
1202 if (atom_type == ATOM_TRAK)
1204 /* parse subatoms */
1205 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1206 set_position(f, get_position(f) + size - header_size);
1207 } else if (atom_type < SUBATOMIC) {
1208 parse_sub_atoms(f, size - header_size, meta_only);
1210 atom_read(f, (uint32_t) size, atom_type);
1217 /* parse root atoms */
1218 static int32_t parse_atoms(struct mp4ff *f, int meta_only)
1221 uint8_t atom_type = 0;
1222 uint8_t header_size = 0;
1225 f->stream->read_error = 0;
1228 atom_read_header(f, &atom_type, &header_size)) != 0) {
1229 f->file_size += size;
1230 f->last_atom = atom_type;
1232 if (atom_type == ATOM_MOOV && size > header_size) {
1233 f->moov_offset = get_position(f) - header_size;
1234 f->moov_size = size;
1237 /* parse subatoms */
1238 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1239 set_position(f, get_position(f) + size - header_size);
1240 } else if (atom_type < SUBATOMIC) {
1241 parse_sub_atoms(f, size - header_size, meta_only);
1243 /* skip this atom */
1244 set_position(f, get_position(f) + size - header_size);
1251 void mp4ff_get_decoder_config(const struct mp4ff *f, const int track,
1252 unsigned char **ppBuf, unsigned int *pBufSize)
1254 if (track >= f->total_tracks) {
1260 if (f->track[track]->decoderConfig == NULL
1261 || f->track[track]->decoderConfigLen == 0) {
1265 *ppBuf = para_malloc(f->track[track]->decoderConfigLen);
1266 memcpy(*ppBuf, f->track[track]->decoderConfig,
1267 f->track[track]->decoderConfigLen);
1268 *pBufSize = f->track[track]->decoderConfigLen;
1272 struct mp4ff *mp4ff_open_read(struct mp4ff_callback *f)
1274 struct mp4ff *ff = para_calloc(sizeof(struct mp4ff));
1288 static int32_t tag_delete(struct mp4ff_metadata *tags)
1292 for (i = 0; i < tags->count; i++) {
1293 free(tags->tags[i].item);
1294 free(tags->tags[i].value);
1303 void mp4ff_close(struct mp4ff *ff)
1307 for (i = 0; i < ff->total_tracks; i++) {
1309 free(ff->track[i]->stsz_table);
1310 free(ff->track[i]->stts_sample_count);
1311 free(ff->track[i]->stts_sample_delta);
1312 free(ff->track[i]->stsc_first_chunk);
1313 free(ff->track[i]->stsc_samples_per_chunk);
1314 free(ff->track[i]->stsc_sample_desc_index);
1315 free(ff->track[i]->stco_chunk_offset);
1316 free(ff->track[i]->decoderConfig);
1317 free(ff->track[i]->ctts_sample_count);
1318 free(ff->track[i]->ctts_sample_offset);
1323 tag_delete(&(ff->tags));
1327 static int32_t chunk_of_sample(const struct mp4ff *f, const int32_t track,
1328 const int32_t sample, int32_t * chunk_sample, int32_t * chunk)
1330 int32_t total_entries = 0;
1331 int32_t chunk2entry;
1332 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1336 if (f->track[track] == NULL) {
1340 total_entries = f->track[track]->stsc_entry_count;
1347 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1348 *chunk = chunk2 - chunk1;
1349 range_samples = *chunk * chunk1samples;
1351 if (sample < total + range_samples)
1354 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1357 if (chunk2entry < total_entries) {
1359 total += range_samples;
1361 } while (chunk2entry < total_entries);
1364 *chunk = (sample - total) / chunk1samples + chunk1;
1368 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1373 static int32_t chunk_to_offset(const struct mp4ff *f, const int32_t track,
1374 const int32_t chunk)
1376 const struct mp4ff_track *p_track = f->track[track];
1378 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1379 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1381 } else if (p_track->stco_entry_count) {
1382 return p_track->stco_chunk_offset[chunk - 1];
1390 static int32_t sample_range_size(const struct mp4ff *f, const int32_t track,
1391 const int32_t chunk_sample, const int32_t sample)
1394 const struct mp4ff_track *p_track = f->track[track];
1396 if (p_track->stsz_sample_size) {
1397 return (sample - chunk_sample) * p_track->stsz_sample_size;
1399 if (sample >= p_track->stsz_sample_count)
1402 for (i = chunk_sample, total = 0; i < sample; i++) {
1403 total += p_track->stsz_table[i];
1410 static int32_t sample_to_offset(const struct mp4ff *f, const int32_t track,
1411 const int32_t sample)
1413 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1415 chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1417 chunk_offset1 = chunk_to_offset(f, track, chunk);
1418 chunk_offset2 = chunk_offset1 + sample_range_size(f,
1419 track, chunk_sample, sample);
1420 return chunk_offset2;
1423 void mp4ff_set_sample_position(struct mp4ff *f, const int32_t track,
1424 const int32_t sample)
1426 int32_t offset = sample_to_offset(f, track, sample);
1427 set_position(f, offset);
1430 int32_t mp4ff_get_sample_size(const struct mp4ff *f, int track, int sample)
1432 const struct mp4ff_track *t = f->track[track];
1434 if (t->stsz_sample_size != 0)
1435 return t->stsz_sample_size;
1436 return t->stsz_table[sample];
1439 uint32_t mp4ff_get_sample_rate(const struct mp4ff *f, const int32_t track)
1441 return f->track[track]->sampleRate;
1444 uint32_t mp4ff_get_channel_count(const struct mp4ff *f, const int32_t track)
1446 return f->track[track]->channelCount;
1449 int32_t mp4ff_num_samples(const struct mp4ff *f, const int32_t track)
1454 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1455 total += f->track[track]->stts_sample_count[i];
1460 struct mp4ff *mp4ff_open_read_metaonly(struct mp4ff_callback *f)
1462 struct mp4ff *ff = para_calloc(sizeof(struct mp4ff));
1476 int32_t mp4ff_meta_get_num_items(const struct mp4ff *f)
1478 return f->tags.count;
1481 int32_t mp4ff_meta_get_by_index(const struct mp4ff *f, uint32_t index,
1482 char **item, char **value)
1484 if (index >= f->tags.count) {
1489 *item = para_strdup(f->tags.tags[index].item);
1490 *value = para_strdup(f->tags.tags[index].value);
1495 static uint32_t find_atom(struct mp4ff *f, uint64_t base, uint32_t size,
1498 uint32_t remaining = size;
1499 uint64_t atom_offset = base;
1504 set_position(f, atom_offset);
1508 atom_size = read_int32(f);
1509 if (atom_size > remaining || atom_size < 8)
1511 read_data(f, atom_name, 4);
1513 if (!memcmp(atom_name, name, 4)) {
1514 set_position(f, atom_offset);
1518 remaining -= atom_size;
1519 atom_offset += atom_size;
1524 static uint32_t find_atom_v2(struct mp4ff *f, uint64_t base, uint32_t size,
1525 const char *name, uint32_t extraheaders, const char *name_inside)
1527 uint64_t first_base = (uint64_t) (-1);
1528 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1530 uint64_t mybase = get_position(f);
1531 uint32_t mysize = read_int32(f);
1533 if (first_base == (uint64_t) (-1))
1534 first_base = mybase;
1536 if (mysize < 8 + extraheaders)
1539 if (find_atom (f, mybase + (8 + extraheaders),
1540 mysize - (8 + extraheaders), name_inside)) {
1541 set_position(f, mybase);
1545 if (size <= mysize) {
1552 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1554 set_position(f, first_base);
1567 #define stricmp strcasecmp
1569 static struct membuffer *membuffer_create(void)
1571 const unsigned initial_size = 256;
1573 struct membuffer *buf = para_malloc(sizeof(*buf));
1574 buf->data = para_malloc(initial_size);
1576 buf->allocated = initial_size;
1577 buf->error = buf->data == 0 ? 1 : 0;
1582 static unsigned membuffer_write(struct membuffer *buf, const void *ptr, unsigned bytes)
1584 unsigned dest_size = buf->written + bytes;
1588 if (dest_size > buf->allocated) {
1590 buf->allocated <<= 1;
1591 } while (dest_size > buf->allocated);
1594 void *newptr = realloc(buf->data, buf->allocated);
1606 memcpy((char *) buf->data + buf->written, ptr, bytes);
1607 buf->written += bytes;
1611 static unsigned membuffer_write_atom_name(struct membuffer *buf, const char *data)
1613 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1616 static unsigned membuffer_write_int16(struct membuffer *buf, uint16_t data)
1620 write_u16_be(temp, data);
1621 return membuffer_write(buf, temp, 2);
1624 static unsigned membuffer_write_int32(struct membuffer *buf, uint32_t data)
1627 write_u32_be(temp, data);
1628 return membuffer_write(buf, temp, 4);
1631 static void membuffer_write_track_tag(struct membuffer *buf, const char *name,
1632 uint32_t index, uint32_t total)
1634 membuffer_write_int32(buf,
1635 8 /*atom header */ + 8 /*data atom header */ +
1636 8 /*flags + reserved */ + 8 /*actual data */ );
1637 membuffer_write_atom_name(buf, name);
1638 membuffer_write_int32(buf,
1639 8 /*data atom header */ +
1640 8 /*flags + reserved */ + 8 /*actual data */ );
1641 membuffer_write_atom_name(buf, "data");
1642 membuffer_write_int32(buf, 0); //flags
1643 membuffer_write_int32(buf, 0); //reserved
1644 membuffer_write_int16(buf, 0);
1645 membuffer_write_int16(buf, (uint16_t) index); //track number
1646 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1647 membuffer_write_int16(buf, 0);
1650 static void membuffer_write_int16_tag(struct membuffer *buf, const char *name,
1653 membuffer_write_int32(buf,
1654 8 /*atom header */ + 8 /*data atom header */ +
1655 8 /*flags + reserved */ + 2 /*actual data */ );
1656 membuffer_write_atom_name(buf, name);
1657 membuffer_write_int32(buf,
1658 8 /*data atom header */ +
1659 8 /*flags + reserved */ + 2 /*actual data */ );
1660 membuffer_write_atom_name(buf, "data");
1661 membuffer_write_int32(buf, 0); //flags
1662 membuffer_write_int32(buf, 0); //reserved
1663 membuffer_write_int16(buf, value); //value
1666 static uint32_t myatoi(const char *param)
1668 return param ? atoi(param) : 0;
1671 static uint32_t meta_genre_to_index(const char *genrestr)
1674 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1675 if (!stricmp(genrestr, ID3v1GenreList[n]))
1681 struct stdmeta_entry {
1686 struct stdmeta_entry stdmetas[] = {
1687 {"\xA9" "nam", "title"},
1688 {"\xA9" "ART", "artist"},
1689 {"\xA9" "wrt", "writer"},
1690 {"\xA9" "alb", "album"},
1691 {"\xA9" "day", "date"},
1692 {"\xA9" "too", "tool"},
1693 {"\xA9" "cmt", "comment"},
1694 {"cpil", "compilation"},
1696 {"aART", "album_artist"},
1699 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1702 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1703 if (!stricmp(name, stdmetas[n].name))
1704 return stdmetas[n].atom;
1709 static void membuffer_write_std_tag(struct membuffer *buf, const char *name,
1714 /* special check for compilation flag */
1715 if (strcmp(name, "cpil") == 0) {
1719 membuffer_write_int32(buf,
1720 8 /*atom header */ + 8 /*data atom header */ +
1721 8 /*flags + reserved */ + strlen(value));
1722 membuffer_write_atom_name(buf, name);
1723 membuffer_write_int32(buf,
1724 8 /*data atom header */ +
1725 8 /*flags + reserved */ + strlen(value));
1726 membuffer_write_atom_name(buf, "data");
1727 membuffer_write_int32(buf, flags); //flags
1728 membuffer_write_int32(buf, 0); //reserved
1729 membuffer_write(buf, value, strlen(value));
1732 static void membuffer_write_custom_tag(struct membuffer *buf, const char *name,
1735 membuffer_write_int32(buf,
1736 8 /*atom header */ +
1737 0x1C /*weirdo itunes atom */ +
1738 12 /*name atom header */ + strlen(name) +
1739 16 /*data atom header + flags */ + strlen(value));
1740 membuffer_write_atom_name(buf, "----");
1741 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1742 membuffer_write_atom_name(buf, "mean");
1743 membuffer_write_int32(buf, 0);
1744 membuffer_write(buf, "com.apple.iTunes", 16);
1745 membuffer_write_int32(buf, 12 + strlen(name));
1746 membuffer_write_atom_name(buf, "name");
1747 membuffer_write_int32(buf, 0);
1748 membuffer_write(buf, name, strlen(name));
1749 membuffer_write_int32(buf,
1750 8 /*data atom header */ +
1751 8 /*flags + reserved */ + strlen(value));
1752 membuffer_write_atom_name(buf, "data");
1753 membuffer_write_int32(buf, 1); //flags
1754 membuffer_write_int32(buf, 0); //reserved
1755 membuffer_write(buf, value, strlen(value));
1758 static unsigned membuffer_error(const struct membuffer *buf)
1763 static void membuffer_free(struct membuffer *buf)
1769 static unsigned membuffer_get_size(const struct membuffer *buf)
1771 return buf->written;
1774 static void *membuffer_detach(struct membuffer *buf)
1781 ret = realloc(buf->data, buf->written);
1792 static uint32_t create_ilst(const struct mp4ff_metadata *data, void **out_buffer,
1793 uint32_t * out_size)
1795 struct membuffer *buf = membuffer_create();
1797 char *mask = para_calloc(data->count);
1799 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1800 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1801 const char *genre_ptr = 0, *tempo_ptr = 0;
1802 for (metaptr = 0; metaptr < data->count; metaptr++) {
1803 struct mp4ff_tag *tag = &data->tags[metaptr];
1804 if (!stricmp(tag->item, "tracknumber") || !stricmp(tag->item, "track")) {
1805 if (tracknumber_ptr == 0)
1806 tracknumber_ptr = tag->value;
1808 } else if (!stricmp(tag->item, "totaltracks")) {
1809 if (totaltracks_ptr == 0)
1810 totaltracks_ptr = tag->value;
1812 } else if (!stricmp(tag->item, "discnumber")
1813 || !stricmp(tag->item, "disc")) {
1814 if (discnumber_ptr == 0)
1815 discnumber_ptr = tag->value;
1817 } else if (!stricmp(tag->item, "totaldiscs")) {
1818 if (totaldiscs_ptr == 0)
1819 totaldiscs_ptr = tag->value;
1821 } else if (!stricmp(tag->item, "genre")) {
1823 genre_ptr = tag->value;
1825 } else if (!stricmp(tag->item, "tempo")) {
1827 tempo_ptr = tag->value;
1833 if (tracknumber_ptr)
1834 membuffer_write_track_tag(buf, "trkn",
1835 myatoi(tracknumber_ptr),
1836 myatoi(totaltracks_ptr));
1838 membuffer_write_track_tag(buf, "disk",
1839 myatoi(discnumber_ptr),
1840 myatoi(totaldiscs_ptr));
1842 membuffer_write_int16_tag(buf, "tmpo",
1843 (uint16_t) myatoi(tempo_ptr));
1846 uint32_t index = meta_genre_to_index(genre_ptr);
1848 membuffer_write_std_tag(buf, "©gen",
1851 membuffer_write_int16_tag(buf, "gnre",
1856 for (metaptr = 0; metaptr < data->count; metaptr++) {
1857 if (!mask[metaptr]) {
1858 struct mp4ff_tag *tag = &data->tags[metaptr];
1859 const char *std_meta_atom = find_standard_meta(tag->item);
1860 if (std_meta_atom) {
1861 membuffer_write_std_tag(buf, std_meta_atom,
1864 membuffer_write_custom_tag(buf, tag->item,
1872 if (membuffer_error(buf)) {
1873 membuffer_free(buf);
1877 *out_size = membuffer_get_size(buf);
1878 *out_buffer = membuffer_detach(buf);
1879 membuffer_free(buf);
1884 static void membuffer_write_atom(struct membuffer *buf, const char *name, unsigned size,
1887 membuffer_write_int32(buf, size + 8);
1888 membuffer_write_atom_name(buf, name);
1889 membuffer_write(buf, data, size);
1892 static void *membuffer_get_ptr(const struct membuffer *buf)
1897 static void membuffer_set_error(struct membuffer *buf)
1902 static unsigned membuffer_transfer_from_file(struct membuffer *buf, struct mp4ff *src,
1908 oldsize = membuffer_get_size(buf);
1909 if (membuffer_write(buf, 0, bytes) != bytes)
1912 bufptr = membuffer_get_ptr(buf);
1916 if ((unsigned)read_data(src, (char *) bufptr + oldsize, bytes) !=
1918 membuffer_set_error(buf);
1925 static uint32_t create_meta(const struct mp4ff_metadata *data, void **out_buffer,
1926 uint32_t * out_size)
1928 struct membuffer *buf;
1932 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1935 buf = membuffer_create();
1937 membuffer_write_int32(buf, 0);
1938 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1941 *out_size = membuffer_get_size(buf);
1942 *out_buffer = membuffer_detach(buf);
1943 membuffer_free(buf);
1947 static uint32_t create_udta(const struct mp4ff_metadata *data, void **out_buffer,
1948 uint32_t * out_size)
1950 struct membuffer *buf;
1954 if (!create_meta(data, &meta_buffer, &meta_size))
1957 buf = membuffer_create();
1959 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1963 *out_size = membuffer_get_size(buf);
1964 *out_buffer = membuffer_detach(buf);
1965 membuffer_free(buf);
1969 static uint32_t fix_byte_order_32(uint32_t src)
1971 return read_u32_be(&src);
1974 static uint32_t modify_moov(struct mp4ff *f, const struct mp4ff_metadata *data,
1975 void **out_buffer, uint32_t * out_size)
1977 uint64_t total_base = f->moov_offset + 8;
1978 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1980 uint64_t udta_offset, meta_offset, ilst_offset;
1981 uint32_t udta_size, meta_size, ilst_size;
1983 uint32_t new_ilst_size;
1984 void *new_ilst_buffer;
1989 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1990 struct membuffer *buf;
1991 void *new_udta_buffer;
1992 uint32_t new_udta_size;
1993 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1996 buf = membuffer_create();
1997 set_position(f, total_base);
1998 membuffer_transfer_from_file(buf, f, total_size);
2000 membuffer_write_atom(buf, "udta", new_udta_size,
2003 free(new_udta_buffer);
2005 *out_size = membuffer_get_size(buf);
2006 *out_buffer = membuffer_detach(buf);
2007 membuffer_free(buf);
2010 udta_offset = get_position(f);
2011 udta_size = read_int32(f);
2012 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
2013 struct membuffer *buf;
2014 void *new_meta_buffer;
2015 uint32_t new_meta_size;
2016 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
2019 buf = membuffer_create();
2020 set_position(f, total_base);
2021 membuffer_transfer_from_file(buf, f,
2022 (uint32_t)(udta_offset - total_base));
2024 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2025 membuffer_write_atom_name(buf, "udta");
2026 membuffer_transfer_from_file(buf, f, udta_size);
2028 membuffer_write_atom(buf, "meta", new_meta_size,
2030 free(new_meta_buffer);
2032 *out_size = membuffer_get_size(buf);
2033 *out_buffer = membuffer_detach(buf);
2034 membuffer_free(buf);
2037 meta_offset = get_position(f);
2038 meta_size = read_int32(f);
2039 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2040 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2041 ilst_offset = get_position(f);
2042 ilst_size = read_int32(f);
2044 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2047 size_delta = new_ilst_size - (ilst_size - 8);
2049 *out_size = total_size + size_delta;
2050 *out_buffer = para_malloc(*out_size);
2051 p_out = (uint8_t *) * out_buffer;
2053 set_position(f, total_base);
2055 (uint32_t) (udta_offset - total_base));
2056 p_out += (uint32_t) (udta_offset - total_base);
2057 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2059 read_data(f, p_out, 4);
2062 (uint32_t) (meta_offset - udta_offset - 8));
2063 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2064 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2066 read_data(f, p_out, 4);
2069 (uint32_t) (ilst_offset - meta_offset - 8));
2070 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2071 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2073 read_data(f, p_out, 4);
2076 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2077 p_out += new_ilst_size;
2079 set_position(f, ilst_offset + ilst_size);
2080 read_data(f, p_out, (uint32_t) (total_size
2081 - (ilst_offset - total_base) - ilst_size));
2083 free(new_ilst_buffer);
2088 static int32_t write_data(struct mp4ff *f, void *data, uint32_t size)
2092 result = f->stream->write(f->stream->user_data, data, size);
2094 f->current_position += size;
2099 static int32_t write_int32(struct mp4ff *f, const uint32_t data)
2102 write_u32_be(temp, data);
2103 return write_data(f, temp, sizeof(temp));
2106 static int32_t truncate_stream(struct mp4ff *f)
2108 return f->stream->truncate(f->stream->user_data);
2111 int32_t mp4ff_meta_update(struct mp4ff_callback *f, const struct mp4ff_metadata *data)
2113 void *new_moov_data;
2114 uint32_t new_moov_size;
2116 struct mp4ff *ff = para_calloc(sizeof(struct mp4ff));
2118 set_position(ff, 0);
2122 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2127 /* copy moov atom to end of the file */
2128 if (ff->last_atom != ATOM_MOOV) {
2129 char *free_data = "free";
2131 /* rename old moov to free */
2132 set_position(ff, ff->moov_offset + 4);
2133 write_data(ff, free_data, 4);
2135 set_position(ff, ff->file_size);
2136 write_int32(ff, new_moov_size + 8);
2137 write_data(ff, "moov", 4);
2138 write_data(ff, new_moov_data, new_moov_size);
2140 set_position(ff, ff->moov_offset);
2141 write_int32(ff, new_moov_size + 8);
2142 write_data(ff, "moov", 4);
2143 write_data(ff, new_moov_data, new_moov_size);
2146 truncate_stream(ff);
2152 /* find a metadata item by name */
2153 /* returns 0 if item found, 1 if no such item */
2154 static int32_t meta_find_by_name(const struct mp4ff *f, const char *item,
2159 for (i = 0; i < f->tags.count; i++) {
2160 if (!stricmp(f->tags.tags[i].item, item)) {
2161 *value = para_strdup(f->tags.tags[i].value);
2172 int32_t mp4ff_meta_get_artist(const struct mp4ff *f, char **value)
2174 return meta_find_by_name(f, "artist", value);
2177 int32_t mp4ff_meta_get_title(const struct mp4ff *f, char **value)
2179 return meta_find_by_name(f, "title", value);
2182 int32_t mp4ff_meta_get_date(const struct mp4ff *f, char **value)
2184 return meta_find_by_name(f, "date", value);
2187 int32_t mp4ff_meta_get_album(const struct mp4ff *f, char **value)
2189 return meta_find_by_name(f, "album", value);
2192 int32_t mp4ff_meta_get_comment(const struct mp4ff *f, char **value)
2194 return meta_find_by_name(f, "comment", value);