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 static struct membuffer *membuffer_create(void)
1569 const unsigned initial_size = 256;
1571 struct membuffer *buf = para_malloc(sizeof(*buf));
1572 buf->data = para_malloc(initial_size);
1574 buf->allocated = initial_size;
1575 buf->error = buf->data == 0 ? 1 : 0;
1580 static unsigned membuffer_write(struct membuffer *buf, const void *ptr, unsigned bytes)
1582 unsigned dest_size = buf->written + bytes;
1586 if (dest_size > buf->allocated) {
1588 buf->allocated <<= 1;
1589 } while (dest_size > buf->allocated);
1592 void *newptr = realloc(buf->data, buf->allocated);
1604 memcpy((char *) buf->data + buf->written, ptr, bytes);
1605 buf->written += bytes;
1609 static unsigned membuffer_write_atom_name(struct membuffer *buf, const char *data)
1611 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1614 static unsigned membuffer_write_int16(struct membuffer *buf, uint16_t data)
1618 write_u16_be(temp, data);
1619 return membuffer_write(buf, temp, 2);
1622 static unsigned membuffer_write_int32(struct membuffer *buf, uint32_t data)
1625 write_u32_be(temp, data);
1626 return membuffer_write(buf, temp, 4);
1629 static void membuffer_write_track_tag(struct membuffer *buf, const char *name,
1630 uint32_t index, uint32_t total)
1632 membuffer_write_int32(buf,
1633 8 /*atom header */ + 8 /*data atom header */ +
1634 8 /*flags + reserved */ + 8 /*actual data */ );
1635 membuffer_write_atom_name(buf, name);
1636 membuffer_write_int32(buf,
1637 8 /*data atom header */ +
1638 8 /*flags + reserved */ + 8 /*actual data */ );
1639 membuffer_write_atom_name(buf, "data");
1640 membuffer_write_int32(buf, 0); //flags
1641 membuffer_write_int32(buf, 0); //reserved
1642 membuffer_write_int16(buf, 0);
1643 membuffer_write_int16(buf, (uint16_t) index); //track number
1644 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1645 membuffer_write_int16(buf, 0);
1648 static void membuffer_write_int16_tag(struct membuffer *buf, const char *name,
1651 membuffer_write_int32(buf,
1652 8 /*atom header */ + 8 /*data atom header */ +
1653 8 /*flags + reserved */ + 2 /*actual data */ );
1654 membuffer_write_atom_name(buf, name);
1655 membuffer_write_int32(buf,
1656 8 /*data atom header */ +
1657 8 /*flags + reserved */ + 2 /*actual data */ );
1658 membuffer_write_atom_name(buf, "data");
1659 membuffer_write_int32(buf, 0); //flags
1660 membuffer_write_int32(buf, 0); //reserved
1661 membuffer_write_int16(buf, value); //value
1664 static uint32_t myatoi(const char *param)
1666 return param ? atoi(param) : 0;
1669 static uint32_t meta_genre_to_index(const char *genrestr)
1672 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1673 if (!strcasecmp(genrestr, ID3v1GenreList[n]))
1679 struct stdmeta_entry {
1684 struct stdmeta_entry stdmetas[] = {
1685 {"\xA9" "nam", "title"},
1686 {"\xA9" "ART", "artist"},
1687 {"\xA9" "wrt", "writer"},
1688 {"\xA9" "alb", "album"},
1689 {"\xA9" "day", "date"},
1690 {"\xA9" "too", "tool"},
1691 {"\xA9" "cmt", "comment"},
1692 {"cpil", "compilation"},
1694 {"aART", "album_artist"},
1697 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1700 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1701 if (!strcasecmp(name, stdmetas[n].name))
1702 return stdmetas[n].atom;
1707 static void membuffer_write_std_tag(struct membuffer *buf, const char *name,
1712 /* special check for compilation flag */
1713 if (strcmp(name, "cpil") == 0) {
1717 membuffer_write_int32(buf,
1718 8 /*atom header */ + 8 /*data atom header */ +
1719 8 /*flags + reserved */ + strlen(value));
1720 membuffer_write_atom_name(buf, name);
1721 membuffer_write_int32(buf,
1722 8 /*data atom header */ +
1723 8 /*flags + reserved */ + strlen(value));
1724 membuffer_write_atom_name(buf, "data");
1725 membuffer_write_int32(buf, flags); //flags
1726 membuffer_write_int32(buf, 0); //reserved
1727 membuffer_write(buf, value, strlen(value));
1730 static void membuffer_write_custom_tag(struct membuffer *buf, const char *name,
1733 membuffer_write_int32(buf,
1734 8 /*atom header */ +
1735 0x1C /*weirdo itunes atom */ +
1736 12 /*name atom header */ + strlen(name) +
1737 16 /*data atom header + flags */ + strlen(value));
1738 membuffer_write_atom_name(buf, "----");
1739 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1740 membuffer_write_atom_name(buf, "mean");
1741 membuffer_write_int32(buf, 0);
1742 membuffer_write(buf, "com.apple.iTunes", 16);
1743 membuffer_write_int32(buf, 12 + strlen(name));
1744 membuffer_write_atom_name(buf, "name");
1745 membuffer_write_int32(buf, 0);
1746 membuffer_write(buf, name, strlen(name));
1747 membuffer_write_int32(buf,
1748 8 /*data atom header */ +
1749 8 /*flags + reserved */ + strlen(value));
1750 membuffer_write_atom_name(buf, "data");
1751 membuffer_write_int32(buf, 1); //flags
1752 membuffer_write_int32(buf, 0); //reserved
1753 membuffer_write(buf, value, strlen(value));
1756 static unsigned membuffer_error(const struct membuffer *buf)
1761 static void membuffer_free(struct membuffer *buf)
1767 static unsigned membuffer_get_size(const struct membuffer *buf)
1769 return buf->written;
1772 static void *membuffer_detach(struct membuffer *buf)
1779 ret = realloc(buf->data, buf->written);
1790 static uint32_t create_ilst(const struct mp4ff_metadata *data, void **out_buffer,
1791 uint32_t * out_size)
1793 struct membuffer *buf = membuffer_create();
1795 char *mask = para_calloc(data->count);
1796 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1797 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1798 const char *genre_ptr = 0, *tempo_ptr = 0;
1799 for (metaptr = 0; metaptr < data->count; metaptr++) {
1800 struct mp4ff_tag *tag = &data->tags[metaptr];
1801 if (!strcasecmp(tag->item, "tracknumber") || !strcasecmp(tag->item, "track")) {
1802 if (tracknumber_ptr == 0)
1803 tracknumber_ptr = tag->value;
1805 } else if (!strcasecmp(tag->item, "totaltracks")) {
1806 if (totaltracks_ptr == 0)
1807 totaltracks_ptr = tag->value;
1809 } else if (!strcasecmp(tag->item, "discnumber")
1810 || !strcasecmp(tag->item, "disc")) {
1811 if (discnumber_ptr == 0)
1812 discnumber_ptr = tag->value;
1814 } else if (!strcasecmp(tag->item, "totaldiscs")) {
1815 if (totaldiscs_ptr == 0)
1816 totaldiscs_ptr = tag->value;
1818 } else if (!strcasecmp(tag->item, "genre")) {
1820 genre_ptr = tag->value;
1822 } else if (!strcasecmp(tag->item, "tempo")) {
1824 tempo_ptr = tag->value;
1829 if (tracknumber_ptr)
1830 membuffer_write_track_tag(buf, "trkn",
1831 myatoi(tracknumber_ptr),
1832 myatoi(totaltracks_ptr));
1834 membuffer_write_track_tag(buf, "disk",
1835 myatoi(discnumber_ptr),
1836 myatoi(totaldiscs_ptr));
1838 membuffer_write_int16_tag(buf, "tmpo", myatoi(tempo_ptr));
1841 uint32_t index = meta_genre_to_index(genre_ptr);
1843 membuffer_write_std_tag(buf, "©gen",
1846 membuffer_write_int16_tag(buf, "gnre", index);
1848 for (metaptr = 0; metaptr < data->count; metaptr++) {
1849 if (!mask[metaptr]) {
1850 struct mp4ff_tag *tag = &data->tags[metaptr];
1851 const char *std_meta_atom = find_standard_meta(tag->item);
1852 if (std_meta_atom) {
1853 membuffer_write_std_tag(buf, std_meta_atom,
1856 membuffer_write_custom_tag(buf, tag->item,
1864 if (membuffer_error(buf)) {
1865 membuffer_free(buf);
1869 *out_size = membuffer_get_size(buf);
1870 *out_buffer = membuffer_detach(buf);
1871 membuffer_free(buf);
1876 static void membuffer_write_atom(struct membuffer *buf, const char *name, unsigned size,
1879 membuffer_write_int32(buf, size + 8);
1880 membuffer_write_atom_name(buf, name);
1881 membuffer_write(buf, data, size);
1884 static void *membuffer_get_ptr(const struct membuffer *buf)
1889 static void membuffer_set_error(struct membuffer *buf)
1894 static unsigned membuffer_transfer_from_file(struct membuffer *buf, struct mp4ff *src,
1900 oldsize = membuffer_get_size(buf);
1901 if (membuffer_write(buf, 0, bytes) != bytes)
1904 bufptr = membuffer_get_ptr(buf);
1908 if ((unsigned)read_data(src, (char *) bufptr + oldsize, bytes) !=
1910 membuffer_set_error(buf);
1917 static uint32_t create_meta(const struct mp4ff_metadata *data, void **out_buffer,
1918 uint32_t * out_size)
1920 struct membuffer *buf;
1924 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1927 buf = membuffer_create();
1929 membuffer_write_int32(buf, 0);
1930 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1933 *out_size = membuffer_get_size(buf);
1934 *out_buffer = membuffer_detach(buf);
1935 membuffer_free(buf);
1939 static uint32_t create_udta(const struct mp4ff_metadata *data, void **out_buffer,
1940 uint32_t * out_size)
1942 struct membuffer *buf;
1946 if (!create_meta(data, &meta_buffer, &meta_size))
1949 buf = membuffer_create();
1951 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1955 *out_size = membuffer_get_size(buf);
1956 *out_buffer = membuffer_detach(buf);
1957 membuffer_free(buf);
1961 static uint32_t fix_byte_order_32(uint32_t src)
1963 return read_u32_be(&src);
1966 static uint32_t modify_moov(struct mp4ff *f, const struct mp4ff_metadata *data,
1967 void **out_buffer, uint32_t * out_size)
1969 uint64_t total_base = f->moov_offset + 8;
1970 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1972 uint64_t udta_offset, meta_offset, ilst_offset;
1973 uint32_t udta_size, meta_size, ilst_size;
1975 uint32_t new_ilst_size;
1976 void *new_ilst_buffer;
1981 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1982 struct membuffer *buf;
1983 void *new_udta_buffer;
1984 uint32_t new_udta_size;
1985 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1988 buf = membuffer_create();
1989 set_position(f, total_base);
1990 membuffer_transfer_from_file(buf, f, total_size);
1992 membuffer_write_atom(buf, "udta", new_udta_size,
1995 free(new_udta_buffer);
1997 *out_size = membuffer_get_size(buf);
1998 *out_buffer = membuffer_detach(buf);
1999 membuffer_free(buf);
2002 udta_offset = get_position(f);
2003 udta_size = read_int32(f);
2004 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
2005 struct membuffer *buf;
2006 void *new_meta_buffer;
2007 uint32_t new_meta_size;
2008 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
2011 buf = membuffer_create();
2012 set_position(f, total_base);
2013 membuffer_transfer_from_file(buf, f,
2014 (uint32_t)(udta_offset - total_base));
2016 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2017 membuffer_write_atom_name(buf, "udta");
2018 membuffer_transfer_from_file(buf, f, udta_size);
2020 membuffer_write_atom(buf, "meta", new_meta_size,
2022 free(new_meta_buffer);
2024 *out_size = membuffer_get_size(buf);
2025 *out_buffer = membuffer_detach(buf);
2026 membuffer_free(buf);
2029 meta_offset = get_position(f);
2030 meta_size = read_int32(f);
2031 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2032 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2033 ilst_offset = get_position(f);
2034 ilst_size = read_int32(f);
2036 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2039 size_delta = new_ilst_size - (ilst_size - 8);
2041 *out_size = total_size + size_delta;
2042 *out_buffer = para_malloc(*out_size);
2043 p_out = (uint8_t *) * out_buffer;
2045 set_position(f, total_base);
2047 (uint32_t) (udta_offset - total_base));
2048 p_out += (uint32_t) (udta_offset - total_base);
2049 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2051 read_data(f, p_out, 4);
2054 (uint32_t) (meta_offset - udta_offset - 8));
2055 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2056 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2058 read_data(f, p_out, 4);
2061 (uint32_t) (ilst_offset - meta_offset - 8));
2062 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2063 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2065 read_data(f, p_out, 4);
2068 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2069 p_out += new_ilst_size;
2071 set_position(f, ilst_offset + ilst_size);
2072 read_data(f, p_out, (uint32_t) (total_size
2073 - (ilst_offset - total_base) - ilst_size));
2075 free(new_ilst_buffer);
2080 static int32_t write_data(struct mp4ff *f, void *data, uint32_t size)
2084 result = f->stream->write(f->stream->user_data, data, size);
2086 f->current_position += size;
2091 static int32_t write_int32(struct mp4ff *f, const uint32_t data)
2094 write_u32_be(temp, data);
2095 return write_data(f, temp, sizeof(temp));
2098 static int32_t truncate_stream(struct mp4ff *f)
2100 return f->stream->truncate(f->stream->user_data);
2103 int32_t mp4ff_meta_update(struct mp4ff_callback *f, const struct mp4ff_metadata *data)
2105 void *new_moov_data;
2106 uint32_t new_moov_size;
2108 struct mp4ff *ff = para_calloc(sizeof(struct mp4ff));
2110 set_position(ff, 0);
2114 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2119 /* copy moov atom to end of the file */
2120 if (ff->last_atom != ATOM_MOOV) {
2121 char *free_data = "free";
2123 /* rename old moov to free */
2124 set_position(ff, ff->moov_offset + 4);
2125 write_data(ff, free_data, 4);
2127 set_position(ff, ff->file_size);
2128 write_int32(ff, new_moov_size + 8);
2129 write_data(ff, "moov", 4);
2130 write_data(ff, new_moov_data, new_moov_size);
2132 set_position(ff, ff->moov_offset);
2133 write_int32(ff, new_moov_size + 8);
2134 write_data(ff, "moov", 4);
2135 write_data(ff, new_moov_data, new_moov_size);
2138 truncate_stream(ff);
2144 /* find a metadata item by name */
2145 /* returns 0 if item found, 1 if no such item */
2146 static int32_t meta_find_by_name(const struct mp4ff *f, const char *item,
2151 for (i = 0; i < f->tags.count; i++) {
2152 if (!strcasecmp(f->tags.tags[i].item, item)) {
2153 *value = para_strdup(f->tags.tags[i].value);
2164 int32_t mp4ff_meta_get_artist(const struct mp4ff *f, char **value)
2166 return meta_find_by_name(f, "artist", value);
2169 int32_t mp4ff_meta_get_title(const struct mp4ff *f, char **value)
2171 return meta_find_by_name(f, "title", value);
2174 int32_t mp4ff_meta_get_date(const struct mp4ff *f, char **value)
2176 return meta_find_by_name(f, "date", value);
2179 int32_t mp4ff_meta_get_album(const struct mp4ff *f, char **value)
2181 return meta_find_by_name(f, "album", value);
2184 int32_t mp4ff_meta_get_comment(const struct mp4ff *f, char **value)
2186 return meta_find_by_name(f, "comment", value);