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;
1800 for (metaptr = 0; metaptr < data->count; metaptr++) {
1801 struct mp4ff_tag *tag = &data->tags[metaptr];
1802 if (!strcasecmp(tag->item, "tracknumber")
1803 || !strcasecmp(tag->item, "track")) {
1804 if (tracknumber_ptr == 0)
1805 tracknumber_ptr = tag->value;
1807 } else if (!strcasecmp(tag->item, "totaltracks")) {
1808 if (totaltracks_ptr == 0)
1809 totaltracks_ptr = tag->value;
1811 } else if (!strcasecmp(tag->item, "discnumber")
1812 || !strcasecmp(tag->item, "disc")) {
1813 if (discnumber_ptr == 0)
1814 discnumber_ptr = tag->value;
1816 } else if (!strcasecmp(tag->item, "totaldiscs")) {
1817 if (totaldiscs_ptr == 0)
1818 totaldiscs_ptr = tag->value;
1820 } else if (!strcasecmp(tag->item, "genre")) {
1822 genre_ptr = tag->value;
1824 } else if (!strcasecmp(tag->item, "tempo")) {
1826 tempo_ptr = tag->value;
1831 if (tracknumber_ptr)
1832 membuffer_write_track_tag(buf, "trkn", myatoi(tracknumber_ptr),
1833 myatoi(totaltracks_ptr));
1835 membuffer_write_track_tag(buf, "disk", 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", genre_ptr);
1845 membuffer_write_int16_tag(buf, "gnre", index);
1847 for (metaptr = 0; metaptr < data->count; metaptr++) {
1848 struct mp4ff_tag *tag;
1849 const char *std_meta_atom;
1853 tag = &data->tags[metaptr];
1854 std_meta_atom = find_standard_meta(tag->item);
1856 membuffer_write_std_tag(buf, std_meta_atom, tag->value);
1858 membuffer_write_custom_tag(buf, tag->item, tag->value);
1862 if (membuffer_error(buf)) {
1863 membuffer_free(buf);
1867 *out_size = membuffer_get_size(buf);
1868 *out_buffer = membuffer_detach(buf);
1869 membuffer_free(buf);
1874 static void membuffer_write_atom(struct membuffer *buf, const char *name, unsigned size,
1877 membuffer_write_int32(buf, size + 8);
1878 membuffer_write_atom_name(buf, name);
1879 membuffer_write(buf, data, size);
1882 static void *membuffer_get_ptr(const struct membuffer *buf)
1887 static void membuffer_set_error(struct membuffer *buf)
1892 static unsigned membuffer_transfer_from_file(struct membuffer *buf, struct mp4ff *src,
1898 oldsize = membuffer_get_size(buf);
1899 if (membuffer_write(buf, 0, bytes) != bytes)
1902 bufptr = membuffer_get_ptr(buf);
1906 if ((unsigned)read_data(src, (char *) bufptr + oldsize, bytes) !=
1908 membuffer_set_error(buf);
1915 static uint32_t create_meta(const struct mp4ff_metadata *data, void **out_buffer,
1916 uint32_t * out_size)
1918 struct membuffer *buf;
1922 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1925 buf = membuffer_create();
1927 membuffer_write_int32(buf, 0);
1928 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1931 *out_size = membuffer_get_size(buf);
1932 *out_buffer = membuffer_detach(buf);
1933 membuffer_free(buf);
1937 static uint32_t create_udta(const struct mp4ff_metadata *data, void **out_buffer,
1938 uint32_t * out_size)
1940 struct membuffer *buf;
1944 if (!create_meta(data, &meta_buffer, &meta_size))
1947 buf = membuffer_create();
1949 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1953 *out_size = membuffer_get_size(buf);
1954 *out_buffer = membuffer_detach(buf);
1955 membuffer_free(buf);
1959 static uint32_t fix_byte_order_32(uint32_t src)
1961 return read_u32_be(&src);
1964 static uint32_t modify_moov(struct mp4ff *f, const struct mp4ff_metadata *data,
1965 void **out_buffer, uint32_t * out_size)
1967 uint64_t total_base = f->moov_offset + 8;
1968 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1970 uint64_t udta_offset, meta_offset, ilst_offset;
1971 uint32_t udta_size, meta_size, ilst_size;
1973 uint32_t new_ilst_size;
1974 void *new_ilst_buffer;
1979 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1980 struct membuffer *buf;
1981 void *new_udta_buffer;
1982 uint32_t new_udta_size;
1983 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1986 buf = membuffer_create();
1987 set_position(f, total_base);
1988 membuffer_transfer_from_file(buf, f, total_size);
1990 membuffer_write_atom(buf, "udta", new_udta_size,
1993 free(new_udta_buffer);
1995 *out_size = membuffer_get_size(buf);
1996 *out_buffer = membuffer_detach(buf);
1997 membuffer_free(buf);
2000 udta_offset = get_position(f);
2001 udta_size = read_int32(f);
2002 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
2003 struct membuffer *buf;
2004 void *new_meta_buffer;
2005 uint32_t new_meta_size;
2006 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
2009 buf = membuffer_create();
2010 set_position(f, total_base);
2011 membuffer_transfer_from_file(buf, f,
2012 (uint32_t)(udta_offset - total_base));
2014 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2015 membuffer_write_atom_name(buf, "udta");
2016 membuffer_transfer_from_file(buf, f, udta_size);
2018 membuffer_write_atom(buf, "meta", new_meta_size,
2020 free(new_meta_buffer);
2022 *out_size = membuffer_get_size(buf);
2023 *out_buffer = membuffer_detach(buf);
2024 membuffer_free(buf);
2027 meta_offset = get_position(f);
2028 meta_size = read_int32(f);
2029 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2030 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2031 ilst_offset = get_position(f);
2032 ilst_size = read_int32(f);
2034 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2037 size_delta = new_ilst_size - (ilst_size - 8);
2039 *out_size = total_size + size_delta;
2040 *out_buffer = para_malloc(*out_size);
2041 p_out = (uint8_t *) * out_buffer;
2043 set_position(f, total_base);
2045 (uint32_t) (udta_offset - total_base));
2046 p_out += (uint32_t) (udta_offset - total_base);
2047 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2049 read_data(f, p_out, 4);
2052 (uint32_t) (meta_offset - udta_offset - 8));
2053 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2054 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2056 read_data(f, p_out, 4);
2059 (uint32_t) (ilst_offset - meta_offset - 8));
2060 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2061 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2063 read_data(f, p_out, 4);
2066 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2067 p_out += new_ilst_size;
2069 set_position(f, ilst_offset + ilst_size);
2070 read_data(f, p_out, (uint32_t) (total_size
2071 - (ilst_offset - total_base) - ilst_size));
2073 free(new_ilst_buffer);
2078 static int32_t write_data(struct mp4ff *f, void *data, uint32_t size)
2082 result = f->stream->write(f->stream->user_data, data, size);
2084 f->current_position += size;
2089 static int32_t write_int32(struct mp4ff *f, const uint32_t data)
2092 write_u32_be(temp, data);
2093 return write_data(f, temp, sizeof(temp));
2096 static int32_t truncate_stream(struct mp4ff *f)
2098 return f->stream->truncate(f->stream->user_data);
2101 int32_t mp4ff_meta_update(struct mp4ff_callback *f, const struct mp4ff_metadata *data)
2103 void *new_moov_data;
2104 uint32_t new_moov_size;
2106 struct mp4ff *ff = para_calloc(sizeof(struct mp4ff));
2108 set_position(ff, 0);
2112 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2117 /* copy moov atom to end of the file */
2118 if (ff->last_atom != ATOM_MOOV) {
2119 char *free_data = "free";
2121 /* rename old moov to free */
2122 set_position(ff, ff->moov_offset + 4);
2123 write_data(ff, free_data, 4);
2125 set_position(ff, ff->file_size);
2126 write_int32(ff, new_moov_size + 8);
2127 write_data(ff, "moov", 4);
2128 write_data(ff, new_moov_data, new_moov_size);
2130 set_position(ff, ff->moov_offset);
2131 write_int32(ff, new_moov_size + 8);
2132 write_data(ff, "moov", 4);
2133 write_data(ff, new_moov_data, new_moov_size);
2136 truncate_stream(ff);
2142 /* find a metadata item by name */
2143 /* returns 0 if item found, 1 if no such item */
2144 static int32_t meta_find_by_name(const struct mp4ff *f, const char *item,
2149 for (i = 0; i < f->tags.count; i++) {
2150 if (!strcasecmp(f->tags.tags[i].item, item)) {
2151 *value = para_strdup(f->tags.tags[i].value);
2162 int32_t mp4ff_meta_get_artist(const struct mp4ff *f, char **value)
2164 return meta_find_by_name(f, "artist", value);
2167 int32_t mp4ff_meta_get_title(const struct mp4ff *f, char **value)
2169 return meta_find_by_name(f, "title", value);
2172 int32_t mp4ff_meta_get_date(const struct mp4ff *f, char **value)
2174 return meta_find_by_name(f, "date", value);
2177 int32_t mp4ff_meta_get_album(const struct mp4ff *f, char **value)
2179 return meta_find_by_name(f, "album", value);
2182 int32_t mp4ff_meta_get_comment(const struct mp4ff *f, char **value)
2184 return meta_find_by_name(f, "comment", value);