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"
22 int32_t stsd_entry_count;
25 int32_t stsz_sample_size;
26 int32_t stsz_sample_count;
30 int32_t stts_entry_count;
31 int32_t *stts_sample_count;
32 int32_t *stts_sample_delta;
35 int32_t stsc_entry_count;
36 int32_t *stsc_first_chunk;
37 int32_t *stsc_samples_per_chunk;
38 int32_t *stsc_sample_desc_index;
41 int32_t stco_entry_count;
42 int32_t *stco_chunk_offset;
45 int32_t ctts_entry_count;
46 int32_t *ctts_sample_count;
47 int32_t *ctts_sample_offset;
56 #define MAX_TRACKS 1024
59 /* stream to read from */
60 struct mp4_callback *stream;
61 int64_t current_position;
73 /* incremental track index while reading the file */
77 struct mp4_track *track[MAX_TRACKS];
80 struct mp4_metadata tags;
83 int32_t mp4_total_tracks(const struct mp4 *f)
85 return f->total_tracks;
88 static int32_t read_data(struct mp4 *f, void *data, uint32_t size)
92 result = f->stream->read(f->stream->user_data, data, size);
95 f->stream->read_error++;
97 f->current_position += size;
102 static uint64_t read_int64(struct mp4 *f)
106 read_data(f, data, 8);
107 return read_u64_be(data);
110 static bool atom_compare(int8_t a1, int8_t b1, int8_t c1, int8_t d1,
111 int8_t a2, int8_t b2, int8_t c2, int8_t d2)
113 return a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2;
117 /* atoms with subatoms */
125 ATOM_ILST = 8, /* iTunes Metadata list */
136 ATOM_COMPILATION = 19,
146 /* atoms without subatoms */
166 ATOM_META = 148, /* iTunes Metadata box */
167 ATOM_NAME = 149, /* iTunes Metadata name box */
168 ATOM_DATA = 150, /* iTunes Metadata data box */
175 ATOM_ALBUM_ARTIST = 157,
176 ATOM_CONTENTGROUP = 158,
178 ATOM_DESCRIPTION = 160,
181 ATOM_EPISODENAME = 163,
182 ATOM_SORTTITLE = 164,
183 ATOM_SORTALBUM = 165,
184 ATOM_SORTARTIST = 166,
185 ATOM_SORTALBUMARTIST = 167,
186 ATOM_SORTWRITER = 168,
195 #define ATOM_FREE ATOM_UNKNOWN
196 #define ATOM_SKIP ATOM_UNKNOWN
198 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
200 static uint8_t atom_name_to_type(int8_t a, int8_t b, int8_t c, int8_t d)
203 if (atom_compare(a, b, c, d, 'm', 'o', 'o', 'v'))
205 else if (atom_compare(a, b, c, d, 'm', 'i', 'n', 'f'))
207 else if (atom_compare(a, b, c, d, 'm', 'd', 'i', 'a'))
209 else if (atom_compare(a, b, c, d, 'm', 'd', 'a', 't'))
211 else if (atom_compare(a, b, c, d, 'm', 'd', 'h', 'd'))
213 else if (atom_compare(a, b, c, d, 'm', 'v', 'h', 'd'))
215 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'a'))
217 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'v'))
219 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 's'))
221 else if (atom_compare(a, b, c, d, 'm', 'e', 't', 'a'))
223 } else if (a == 't') {
224 if (atom_compare(a, b, c, d, 't', 'r', 'a', 'k'))
226 else if (atom_compare(a, b, c, d, 't', 'k', 'h', 'd'))
228 else if (atom_compare(a, b, c, d, 't', 'r', 'e', 'f'))
230 else if (atom_compare(a, b, c, d, 't', 'r', 'k', 'n'))
232 else if (atom_compare(a, b, c, d, 't', 'm', 'p', 'o'))
234 else if (atom_compare(a, b, c, d, 't', 'v', 'n', 'n'))
236 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'h'))
238 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 'n'))
239 return ATOM_EPISODENAME;
240 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'n'))
242 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 's'))
244 } else if (a == 's') {
245 if (atom_compare(a, b, c, d, 's', 't', 'b', 'l'))
247 else if (atom_compare(a, b, c, d, 's', 'm', 'h', 'd'))
249 else if (atom_compare(a, b, c, d, 's', 't', 's', 'd'))
251 else if (atom_compare(a, b, c, d, 's', 't', 't', 's'))
253 else if (atom_compare(a, b, c, d, 's', 't', 'c', 'o'))
255 else if (atom_compare(a, b, c, d, 's', 't', 's', 'c'))
257 else if (atom_compare(a, b, c, d, 's', 't', 's', 'z'))
259 else if (atom_compare(a, b, c, d, 's', 't', 'z', '2'))
261 else if (atom_compare(a, b, c, d, 's', 'k', 'i', 'p'))
263 else if (atom_compare(a, b, c, d, 's', 'i', 'n', 'f'))
265 else if (atom_compare(a, b, c, d, 's', 'c', 'h', 'i'))
267 else if (atom_compare(a, b, c, d, 's', 'o', 'n', 'm'))
268 return ATOM_SORTTITLE;
269 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'l'))
270 return ATOM_SORTALBUM;
271 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'r'))
272 return ATOM_SORTARTIST;
273 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'a'))
274 return ATOM_SORTALBUMARTIST;
275 else if (atom_compare(a, b, c, d, 's', 'o', 'c', 'o'))
276 return ATOM_SORTWRITER;
277 else if (atom_compare(a, b, c, d, 's', 'o', 's', 'n'))
278 return ATOM_SORTSHOW;
279 } else if (a == COPYRIGHT_SYMBOL) {
280 if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'n', 'a', 'm'))
282 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'A', 'R', 'T'))
284 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'w', 'r', 't'))
286 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'a', 'l', 'b'))
288 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'd', 'a', 'y'))
290 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 't', 'o', 'o'))
292 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'c', 'm', 't'))
294 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'e', 'n'))
296 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'r', 'p'))
297 return ATOM_CONTENTGROUP;
298 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'l', 'y', 'r'))
302 if (atom_compare(a, b, c, d, 'e', 'd', 't', 's'))
304 else if (atom_compare(a, b, c, d, 'e', 's', 'd', 's'))
306 else if (atom_compare(a, b, c, d, 'f', 't', 'y', 'p'))
308 else if (atom_compare(a, b, c, d, 'f', 'r', 'e', 'e'))
310 else if (atom_compare(a, b, c, d, 'h', 'm', 'h', 'd'))
312 else if (atom_compare(a, b, c, d, 'v', 'm', 'h', 'd'))
314 else if (atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
316 else if (atom_compare(a, b, c, d, 'i', 'l', 's', 't'))
318 else if (atom_compare(a, b, c, d, 'n', 'a', 'm', 'e'))
320 else if (atom_compare(a, b, c, d, 'd', 'a', 't', 'a'))
322 else if (atom_compare(a, b, c, d, 'd', 'i', 's', 'k'))
324 else if (atom_compare(a, b, c, d, 'g', 'n', 'r', 'e'))
326 else if (atom_compare(a, b, c, d, 'c', 'o', 'v', 'r'))
328 else if (atom_compare(a, b, c, d, 'c', 'p', 'i', 'l'))
329 return ATOM_COMPILATION;
330 else if (atom_compare(a, b, c, d, 'c', 't', 't', 's'))
332 else if (atom_compare(a, b, c, d, 'd', 'r', 'm', 's'))
334 else if (atom_compare(a, b, c, d, 'f', 'r', 'm', 'a'))
336 else if (atom_compare(a, b, c, d, 'p', 'r', 'i', 'v'))
338 else if (atom_compare(a, b, c, d, 'i', 'v', 'i', 'v'))
340 else if (atom_compare(a, b, c, d, 'u', 's', 'e', 'r'))
342 else if (atom_compare(a, b, c, d, 'k', 'e', 'y', ' '))
344 else if (atom_compare(a, b, c, d, 'a', 'A', 'R', 'T'))
345 return ATOM_ALBUM_ARTIST;
346 else if (atom_compare(a, b, c, d, 'd', 'e', 's', 'c'))
347 return ATOM_DESCRIPTION;
348 else if (atom_compare(a, b, c, d, 'p', 'c', 's', 't'))
354 /* read atom header, return atom size, atom size is with header included */
355 static uint64_t atom_read_header(struct mp4 *f, uint8_t * atom_type,
356 uint8_t * header_size)
360 int8_t atom_header[8];
362 ret = read_data(f, atom_header, 8);
366 size = read_u32_be(atom_header);
369 /* check for 64 bit atom size */
372 size = read_int64(f);
374 *atom_type = atom_name_to_type(atom_header[4], atom_header[5],
375 atom_header[6], atom_header[7]);
379 static int64_t get_position(const struct mp4 *f)
381 return f->current_position;
384 static int need_parse_when_meta_only(uint8_t atom_type)
405 static int32_t set_position(struct mp4 *f, int64_t position)
407 f->stream->seek(f->stream->user_data, position);
408 f->current_position = position;
413 static void track_add(struct mp4 *f)
417 if (f->total_tracks > MAX_TRACKS) {
422 f->track[f->total_tracks - 1] = para_calloc(sizeof(struct mp4_track));
425 static uint8_t read_char(struct mp4 *f)
428 read_data(f, &output, 1);
432 static uint32_t read_int24(struct mp4 *f)
436 read_data(f, data, 3);
437 return read_u24_be(data);
440 static uint32_t read_int32(struct mp4 *f)
444 read_data(f, data, 4);
445 return read_u32_be(data);
448 static int32_t read_stsz(struct mp4 *f)
453 if (f->total_tracks == 0)
455 t = f->track[f->total_tracks - 1];
456 read_char(f); /* version */
457 read_int24(f); /* flags */
458 t->stsz_sample_size = read_int32(f);
459 t->stsz_sample_count = read_int32(f);
460 if (t->stsz_sample_size != 0)
462 t->stsz_table = para_malloc(t->stsz_sample_count * sizeof(int32_t));
463 for (i = 0; i < t->stsz_sample_count && !f->stream->read_error; i++)
464 t->stsz_table[i] = read_int32(f);
468 static int32_t read_stts(struct mp4 *f)
474 if (f->total_tracks == 0)
476 t = f->track[f->total_tracks - 1];
477 if (t->stts_entry_count)
479 read_char(f); /* version */
480 read_int24(f); /* flags */
481 t->stts_entry_count = read_int32(f);
483 t->stts_sample_count = para_malloc(t->stts_entry_count
485 t->stts_sample_delta = para_malloc(t->stts_entry_count
488 for (i = 0; i < t->stts_entry_count && !f->stream->read_error; i++) {
489 t->stts_sample_count[i] = read_int32(f);
490 t->stts_sample_delta[i] = read_int32(f);
495 static int32_t read_ctts(struct mp4 *f)
500 if (f->total_tracks == 0)
502 t = f->track[f->total_tracks - 1];
503 if (t->ctts_entry_count)
506 read_char(f); /* version */
507 read_int24(f); /* flags */
508 t->ctts_entry_count = read_int32(f);
510 t->ctts_sample_count = para_malloc(t->ctts_entry_count
512 t->ctts_sample_offset = para_malloc(t->ctts_entry_count
516 for (i = 0; i < t->ctts_entry_count && !f->stream->read_error; i++) {
517 t->ctts_sample_count[i] = read_int32(f);
518 t->ctts_sample_offset[i] = read_int32(f);
523 static int32_t read_stsc(struct mp4 *f)
528 if (f->total_tracks == 0)
530 t = f->track[f->total_tracks - 1];
532 read_char(f); /* version */
533 read_int24(f); /* flags */
534 t->stsc_entry_count = read_int32(f);
535 t->stsc_first_chunk = para_malloc(t->stsc_entry_count * sizeof(int32_t));
536 t->stsc_samples_per_chunk = para_malloc(t->stsc_entry_count
538 t->stsc_sample_desc_index = para_malloc(t->stsc_entry_count *
542 for (i = 0; i < t->stsc_entry_count && !f->stream->read_error; i++) {
543 t->stsc_first_chunk[i] = read_int32(f);
544 t->stsc_samples_per_chunk[i] = read_int32(f);
545 t->stsc_sample_desc_index[i] = read_int32(f);
550 static int32_t read_stco(struct mp4 *f)
555 if (f->total_tracks == 0)
557 t = f->track[f->total_tracks - 1];
559 read_char(f); /* version */
560 read_int24(f); /* flags */
561 t->stco_entry_count = read_int32(f);
562 t->stco_chunk_offset = para_malloc(t->stco_entry_count
565 for (i = 0; i < t->stco_entry_count && !f->stream->read_error; i++)
566 t->stco_chunk_offset[i] = read_int32(f);
570 static uint16_t read_int16(struct mp4 *f)
574 read_data(f, data, 2);
575 return read_u16_be(data);
578 static int32_t read_mp4a(struct mp4 *f)
581 uint8_t atom_type = 0;
582 uint8_t header_size = 0;
585 if (f->total_tracks == 0)
587 t = f->track[f->total_tracks - 1];
589 for (i = 0; i < 6; i++) {
590 read_char(f); /* reserved */
592 /* data_reference_index */ read_int16(f);
594 read_int32(f); /* reserved */
595 read_int32(f); /* reserved */
597 t->channelCount = read_int16(f);
598 t->sampleSize = read_int16(f);
603 t->sampleRate = read_int16(f);
607 atom_read_header(f, &atom_type, &header_size);
611 static int32_t read_stsd(struct mp4 *f)
614 uint8_t header_size = 0;
618 if (f->total_tracks == 0)
620 t = f->track[f->total_tracks - 1];
622 read_char(f); /* version */
623 read_int24(f); /* flags */
625 t->stsd_entry_count = read_int32(f);
628 for (i = 0; i < t->stsd_entry_count && !f->stream->read_error; i++) {
629 uint64_t skip = get_position(f);
631 uint8_t atom_type = 0;
632 size = atom_read_header(f, &atom_type, &header_size);
634 t->is_audio = atom_type == ATOM_MP4A;
637 set_position(f, skip);
643 static int32_t read_mvhd(struct mp4 *f)
647 read_char(f); /* version */
648 read_int24(f); /* flags */
649 read_int32(f); /* creation_time */
650 read_int32(f); /* modification_time */
651 f->time_scale = read_int32(f);
652 f->duration = read_int32(f);
653 read_int32(f); /* preferred_rate */
654 read_int16(f); /* preferred_volume */
655 for (i = 0; i < 10; i++)
656 read_char(f); /* reserved */
657 for (i = 0; i < 9; i++)
658 read_int32(f); /* matrix */
659 read_int32(f); /* preview_time */
660 read_int32(f); /* preview_duration */
661 read_int32(f); /* poster_time */
662 read_int32(f); /* selection_time */
663 read_int32(f); /* selection_duration */
664 read_int32(f); /* current_time */
665 read_int32(f); /* next_track_id */
669 static int32_t tag_add_field(struct mp4_metadata *tags, const char *item,
670 const char *value, int32_t len)
672 if (!item || (item && !*item) || !value)
674 tags->tags = para_realloc(tags->tags,
675 (tags->count + 1) * sizeof(struct mp4_tag));
676 tags->tags[tags->count].item = para_strdup(item);
677 tags->tags[tags->count].len = len;
679 tags->tags[tags->count].value = para_malloc(len + 1);
680 memcpy(tags->tags[tags->count].value, value, len);
681 tags->tags[tags->count].value[len] = 0;
683 tags->tags[tags->count].value = para_strdup(value);
689 static const char *ID3v1GenreList[] = {
690 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
691 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
692 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
693 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
694 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
695 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
696 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
697 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
698 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
699 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
700 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
701 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
702 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
703 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
704 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
705 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
706 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
707 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
708 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
709 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
710 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
711 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
712 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
713 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
714 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
715 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
716 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
717 "Anime", "JPop", "SynthPop",
720 static const char *meta_index_to_genre(uint32_t idx)
722 if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
723 return ID3v1GenreList[idx - 1];
729 static char *read_string(struct mp4 *f, uint32_t length)
731 char *str = para_malloc(length + 1);
732 if ((uint32_t)read_data(f, str, length) != length) {
740 static int32_t set_metadata_name(uint8_t atom_type, char **name)
742 static char *tag_names[] = {
743 "unknown", "title", "artist", "writer", "album",
744 "date", "tool", "comment", "genre", "track",
745 "disc", "compilation", "genre", "tempo", "cover",
746 "album_artist", "contentgroup", "lyrics", "description",
747 "network", "show", "episodename",
748 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
749 "sortwriter", "sortshow",
750 "season", "episode", "podcast"
785 case ATOM_COMPILATION:
797 case ATOM_ALBUM_ARTIST:
800 case ATOM_CONTENTGROUP:
806 case ATOM_DESCRIPTION:
815 case ATOM_EPISODENAME:
824 case ATOM_SORTARTIST:
827 case ATOM_SORTALBUMARTIST:
830 case ATOM_SORTWRITER:
850 *name = para_strdup(tag_names[tag_idx]);
854 static uint32_t min_body_size(uint8_t atom_type)
861 return sizeof (char) /* version */
862 + sizeof(uint8_t) * 3 /* flags */
863 + sizeof(uint32_t) /* reserved */
864 + sizeof(uint16_t) /* leading uint16_t */
865 + sizeof(uint16_t) /* track */
866 + sizeof(uint16_t); /* totaltracks */
868 return sizeof (char) /* version */
869 + sizeof(uint8_t) * 3 /* flags */
870 + sizeof(uint32_t) /* reserved */
871 + sizeof(uint16_t) /* disc */
872 + sizeof(uint16_t); /* totaldiscs */
873 default: assert(false);
877 static int32_t parse_tag(struct mp4 *f, uint8_t parent, int32_t size)
880 uint8_t header_size = 0;
881 uint64_t subsize, sumsize;
890 sumsize < size && !f->stream->read_error; /* CVE-2017-9222 */
891 set_position(f, destpos), sumsize += subsize
893 subsize = atom_read_header(f, &atom_type, &header_size);
894 destpos = get_position(f) + subsize - header_size;
897 if (atom_type == ATOM_NAME) {
898 read_char(f); /* version */
899 read_int24(f); /* flags */
901 name = read_string(f, subsize - (header_size + 4));
904 if (atom_type != ATOM_DATA)
906 read_char(f); /* version */
907 read_int24(f); /* flags */
908 read_int32(f); /* reserved */
910 /* some need special attention */
911 if (parent == ATOM_GENRE2 || parent == ATOM_TEMPO) {
913 if (subsize - header_size < min_body_size(parent))
916 if (parent == ATOM_TEMPO) {
918 sprintf(temp, "%.5u BPM", val);
919 tag_add_field(&(f-> tags), "tempo",
922 const char *tmp = meta_index_to_genre(val);
924 tag_add_field (&(f->tags),
928 } else if (parent == ATOM_TRACK || parent == ATOM_DISC) {
929 uint16_t index, total;
931 if (subsize - header_size < min_body_size(parent))
934 index = read_int16(f);
935 total = read_int16(f);
936 if (parent == ATOM_TRACK)
938 sprintf(temp, "%d", index);
939 tag_add_field(&(f->tags), parent == ATOM_TRACK?
940 "track" : "disc", temp, -1);
942 sprintf(temp, "%d", total);
943 tag_add_field(& (f-> tags),
944 parent == ATOM_TRACK?
945 "totaltracks" : "totaldiscs", temp, -1);
950 data = read_string(f, subsize - (header_size + 8));
951 len = subsize - (header_size + 8);
957 set_metadata_name(parent , &name);
959 tag_add_field(&(f->tags), name, data, len);
968 static int32_t read_mdhd(struct mp4 *f)
974 if (f->total_tracks == 0)
976 t = f->track[f->total_tracks - 1];
978 version = read_int32(f);
980 read_int64(f); //creation-time
981 read_int64(f); //modification-time
982 t->timeScale = read_int32(f); //timescale
983 t->duration = read_int64(f); //duration
984 } else { //version == 0
987 read_int32(f); //creation-time
988 read_int32(f); //modification-time
989 t->timeScale = read_int32(f); //timescale
990 temp = read_int32(f);
991 t->duration = (temp == (uint32_t) (-1))?
992 (uint64_t) (-1) : (uint64_t) (temp);
999 static int32_t parse_metadata(struct mp4 *f, int32_t size)
1001 uint64_t subsize, sumsize = 0;
1003 uint8_t header_size = 0;
1005 while (sumsize < size) {
1006 subsize = atom_read_header(f, &atom_type, &header_size);
1009 parse_tag(f, atom_type, (uint32_t)(subsize - header_size));
1016 static int32_t read_meta(struct mp4 *f, uint64_t size)
1018 uint64_t subsize, sumsize = 0;
1020 uint8_t header_size = 0;
1022 read_char(f); /* version */
1023 read_int24(f); /* flags */
1025 while (sumsize < (size - (header_size + 4))) {
1026 subsize = atom_read_header(f, &atom_type, &header_size);
1027 if (subsize <= header_size + 4)
1029 if (atom_type == ATOM_ILST) {
1030 parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1032 set_position(f, get_position(f) + subsize - header_size);
1040 static int32_t atom_read(struct mp4 *f, int32_t size, uint8_t atom_type)
1042 uint64_t dest_position = get_position(f) + size - 8;
1043 if (atom_type == ATOM_STSZ) {
1044 /* sample size box */
1046 } else if (atom_type == ATOM_STTS) {
1047 /* time to sample box */
1049 } else if (atom_type == ATOM_CTTS) {
1050 /* composition offset box */
1052 } else if (atom_type == ATOM_STSC) {
1053 /* sample to chunk box */
1055 } else if (atom_type == ATOM_STCO) {
1056 /* chunk offset box */
1058 } else if (atom_type == ATOM_STSD) {
1059 /* sample description box */
1061 } else if (atom_type == ATOM_MVHD) {
1062 /* movie header box */
1064 } else if (atom_type == ATOM_MDHD) {
1067 } else if (atom_type == ATOM_META) {
1068 /* iTunes Metadata box */
1072 set_position(f, dest_position);
1076 /* parse atoms that are sub atoms of other atoms */
1077 static int32_t parse_sub_atoms(struct mp4 *f, uint64_t total_size, int meta_only)
1080 uint8_t atom_type = 0;
1081 uint64_t counted_size = 0;
1082 uint8_t header_size = 0;
1084 while (counted_size < total_size) {
1085 size = atom_read_header(f, &atom_type, &header_size);
1086 counted_size += size;
1088 /* check for end of file */
1092 /* we're starting to read a new track, update index,
1093 * so that all data and tables get written in the right place
1095 if (atom_type == ATOM_TRAK)
1097 /* parse subatoms */
1098 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1099 set_position(f, get_position(f) + size - header_size);
1100 } else if (atom_type < SUBATOMIC) {
1101 parse_sub_atoms(f, size - header_size, meta_only);
1103 atom_read(f, (uint32_t) size, atom_type);
1110 /* parse root atoms */
1111 static int32_t parse_atoms(struct mp4 *f, int meta_only)
1114 uint8_t atom_type = 0;
1115 uint8_t header_size = 0;
1118 f->stream->read_error = 0;
1121 atom_read_header(f, &atom_type, &header_size)) != 0) {
1122 f->file_size += size;
1123 f->last_atom = atom_type;
1125 if (atom_type == ATOM_MOOV && size > header_size) {
1126 f->moov_offset = get_position(f) - header_size;
1127 f->moov_size = size;
1130 /* parse subatoms */
1131 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1132 set_position(f, get_position(f) + size - header_size);
1133 } else if (atom_type < SUBATOMIC) {
1134 parse_sub_atoms(f, size - header_size, meta_only);
1136 /* skip this atom */
1137 set_position(f, get_position(f) + size - header_size);
1144 struct mp4 *mp4_open_read(struct mp4_callback *f)
1146 struct mp4 *ff = para_calloc(sizeof(struct mp4));
1160 static int32_t tag_delete(struct mp4_metadata *tags)
1164 for (i = 0; i < tags->count; i++) {
1165 free(tags->tags[i].item);
1166 free(tags->tags[i].value);
1175 void mp4_close(struct mp4 *ff)
1179 for (i = 0; i < ff->total_tracks; i++) {
1181 free(ff->track[i]->stsz_table);
1182 free(ff->track[i]->stts_sample_count);
1183 free(ff->track[i]->stts_sample_delta);
1184 free(ff->track[i]->stsc_first_chunk);
1185 free(ff->track[i]->stsc_samples_per_chunk);
1186 free(ff->track[i]->stsc_sample_desc_index);
1187 free(ff->track[i]->stco_chunk_offset);
1188 free(ff->track[i]->ctts_sample_count);
1189 free(ff->track[i]->ctts_sample_offset);
1194 tag_delete(&(ff->tags));
1198 static int32_t chunk_of_sample(const struct mp4 *f, int32_t track,
1199 int32_t sample, int32_t *chunk_sample, int32_t *chunk)
1201 int32_t total_entries = 0;
1202 int32_t chunk2entry;
1203 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1207 if (f->track[track] == NULL) {
1211 total_entries = f->track[track]->stsc_entry_count;
1218 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1219 *chunk = chunk2 - chunk1;
1220 range_samples = *chunk * chunk1samples;
1222 if (sample < total + range_samples)
1225 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1228 if (chunk2entry < total_entries) {
1230 total += range_samples;
1232 } while (chunk2entry < total_entries);
1235 *chunk = (sample - total) / chunk1samples + chunk1;
1239 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1244 static int32_t chunk_to_offset(const struct mp4 *f, int32_t track,
1247 const struct mp4_track *p_track = f->track[track];
1249 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1250 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1252 } else if (p_track->stco_entry_count) {
1253 return p_track->stco_chunk_offset[chunk - 1];
1261 static int32_t sample_range_size(const struct mp4 *f, int32_t track,
1262 int32_t chunk_sample, int32_t sample)
1265 const struct mp4_track *p_track = f->track[track];
1267 if (p_track->stsz_sample_size) {
1268 return (sample - chunk_sample) * p_track->stsz_sample_size;
1270 if (sample >= p_track->stsz_sample_count)
1273 for (i = chunk_sample, total = 0; i < sample; i++) {
1274 total += p_track->stsz_table[i];
1281 static int32_t sample_to_offset(const struct mp4 *f, int32_t track,
1284 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1286 chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1288 chunk_offset1 = chunk_to_offset(f, track, chunk);
1289 chunk_offset2 = chunk_offset1 + sample_range_size(f,
1290 track, chunk_sample, sample);
1291 return chunk_offset2;
1295 * Return the number of milliseconds of the given track.
1297 * \param f As returned by \ref mp4_open_read(), must not be NULL.
1298 * \param track Between zero and the value returned by \ref mp4_total_tracks().
1300 * The function returns zero if the audio file is of zero length or contains a
1301 * corrupt track header.
1303 uint64_t mp4_get_duration(const struct mp4 *f, int32_t track)
1305 const struct mp4_track *t = f->track[track];
1307 if (t->timeScale == 0)
1309 return t->duration * 1000 / t->timeScale;
1313 * Check whether the given track number corresponds to an audio track.
1315 * \param f See \ref mp4_get_duration().
1316 * \param track See \ref mp4_get_duration().
1318 * Besides audio tracks, an mp4 file may contain video and system tracks. For
1319 * those the function returns false.
1321 bool mp4_is_audio_track(const struct mp4 *f, int32_t track)
1323 return f->track[track]->is_audio;
1326 void mp4_set_sample_position(struct mp4 *f, int32_t track, int32_t sample)
1328 int32_t offset = sample_to_offset(f, track, sample);
1329 set_position(f, offset);
1332 int32_t mp4_get_sample_size(const struct mp4 *f, int track, int sample)
1334 const struct mp4_track *t = f->track[track];
1336 if (t->stsz_sample_size != 0)
1337 return t->stsz_sample_size;
1338 return t->stsz_table[sample];
1341 uint32_t mp4_get_sample_rate(const struct mp4 *f, int32_t track)
1343 return f->track[track]->sampleRate;
1346 uint32_t mp4_get_channel_count(const struct mp4 *f, int32_t track)
1348 return f->track[track]->channelCount;
1351 int32_t mp4_num_samples(const struct mp4 *f, int32_t track)
1356 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1357 total += f->track[track]->stts_sample_count[i];
1362 struct mp4 *mp4_open_meta(struct mp4_callback *f)
1364 struct mp4 *ff = para_calloc(sizeof(struct mp4));
1378 int32_t mp4_meta_get_num_items(const struct mp4 *f)
1380 return f->tags.count;
1383 int32_t mp4_meta_get_by_index(const struct mp4 *f, uint32_t index,
1384 char **item, char **value)
1386 if (index >= f->tags.count) {
1391 *item = para_strdup(f->tags.tags[index].item);
1392 *value = para_strdup(f->tags.tags[index].value);
1397 static uint32_t find_atom(struct mp4 *f, uint64_t base, uint32_t size,
1400 uint32_t remaining = size;
1401 uint64_t atom_offset = base;
1406 set_position(f, atom_offset);
1410 atom_size = read_int32(f);
1411 if (atom_size > remaining || atom_size < 8)
1413 read_data(f, atom_name, 4);
1415 if (!memcmp(atom_name, name, 4)) {
1416 set_position(f, atom_offset);
1420 remaining -= atom_size;
1421 atom_offset += atom_size;
1426 static uint32_t find_atom_v2(struct mp4 *f, uint64_t base, uint32_t size,
1427 const char *name, uint32_t extraheaders, const char *name_inside)
1429 uint64_t first_base = (uint64_t) (-1);
1430 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1432 uint64_t mybase = get_position(f);
1433 uint32_t mysize = read_int32(f);
1435 if (first_base == (uint64_t) (-1))
1436 first_base = mybase;
1438 if (mysize < 8 + extraheaders)
1441 if (find_atom (f, mybase + (8 + extraheaders),
1442 mysize - (8 + extraheaders), name_inside)) {
1443 set_position(f, mybase);
1447 if (size <= mysize) {
1454 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1456 set_position(f, first_base);
1469 static struct membuffer *membuffer_create(void)
1471 const unsigned initial_size = 256;
1473 struct membuffer *buf = para_malloc(sizeof(*buf));
1474 buf->data = para_malloc(initial_size);
1476 buf->allocated = initial_size;
1477 buf->error = buf->data == 0 ? 1 : 0;
1482 static unsigned membuffer_write(struct membuffer *buf, const void *ptr, unsigned bytes)
1484 unsigned dest_size = buf->written + bytes;
1488 if (dest_size > buf->allocated) {
1490 buf->allocated <<= 1;
1491 } while (dest_size > buf->allocated);
1492 buf->data = para_realloc(buf->data, buf->allocated);
1496 memcpy((char *) buf->data + buf->written, ptr, bytes);
1497 buf->written += bytes;
1501 static unsigned membuffer_write_atom_name(struct membuffer *buf, const char *data)
1503 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1506 static unsigned membuffer_write_int16(struct membuffer *buf, uint16_t data)
1510 write_u16_be(temp, data);
1511 return membuffer_write(buf, temp, 2);
1514 static unsigned membuffer_write_int32(struct membuffer *buf, uint32_t data)
1517 write_u32_be(temp, data);
1518 return membuffer_write(buf, temp, 4);
1521 static void membuffer_write_track_tag(struct membuffer *buf, const char *name,
1522 uint32_t index, uint32_t total)
1524 membuffer_write_int32(buf,
1525 8 /*atom header */ + 8 /*data atom header */ +
1526 8 /*flags + reserved */ + 8 /*actual data */ );
1527 membuffer_write_atom_name(buf, name);
1528 membuffer_write_int32(buf,
1529 8 /*data atom header */ +
1530 8 /*flags + reserved */ + 8 /*actual data */ );
1531 membuffer_write_atom_name(buf, "data");
1532 membuffer_write_int32(buf, 0); //flags
1533 membuffer_write_int32(buf, 0); //reserved
1534 membuffer_write_int16(buf, 0);
1535 membuffer_write_int16(buf, (uint16_t) index); //track number
1536 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1537 membuffer_write_int16(buf, 0);
1540 static void membuffer_write_int16_tag(struct membuffer *buf, const char *name,
1543 membuffer_write_int32(buf,
1544 8 /*atom header */ + 8 /*data atom header */ +
1545 8 /*flags + reserved */ + 2 /*actual data */ );
1546 membuffer_write_atom_name(buf, name);
1547 membuffer_write_int32(buf,
1548 8 /*data atom header */ +
1549 8 /*flags + reserved */ + 2 /*actual data */ );
1550 membuffer_write_atom_name(buf, "data");
1551 membuffer_write_int32(buf, 0); //flags
1552 membuffer_write_int32(buf, 0); //reserved
1553 membuffer_write_int16(buf, value); //value
1556 static uint32_t myatoi(const char *param)
1558 return param ? atoi(param) : 0;
1561 static uint32_t meta_genre_to_index(const char *genrestr)
1564 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1565 if (!strcasecmp(genrestr, ID3v1GenreList[n]))
1571 struct stdmeta_entry {
1576 struct stdmeta_entry stdmetas[] = {
1577 {"\xA9" "nam", "title"},
1578 {"\xA9" "ART", "artist"},
1579 {"\xA9" "wrt", "writer"},
1580 {"\xA9" "alb", "album"},
1581 {"\xA9" "day", "date"},
1582 {"\xA9" "too", "tool"},
1583 {"\xA9" "cmt", "comment"},
1584 {"cpil", "compilation"},
1586 {"aART", "album_artist"},
1589 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1592 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1593 if (!strcasecmp(name, stdmetas[n].name))
1594 return stdmetas[n].atom;
1599 static void membuffer_write_std_tag(struct membuffer *buf, const char *name,
1604 /* special check for compilation flag */
1605 if (strcmp(name, "cpil") == 0) {
1609 membuffer_write_int32(buf,
1610 8 /*atom header */ + 8 /*data atom header */ +
1611 8 /*flags + reserved */ + strlen(value));
1612 membuffer_write_atom_name(buf, name);
1613 membuffer_write_int32(buf,
1614 8 /*data atom header */ +
1615 8 /*flags + reserved */ + strlen(value));
1616 membuffer_write_atom_name(buf, "data");
1617 membuffer_write_int32(buf, flags); //flags
1618 membuffer_write_int32(buf, 0); //reserved
1619 membuffer_write(buf, value, strlen(value));
1622 static void membuffer_write_custom_tag(struct membuffer *buf, const char *name,
1625 membuffer_write_int32(buf,
1626 8 /*atom header */ +
1627 0x1C /*weirdo itunes atom */ +
1628 12 /*name atom header */ + strlen(name) +
1629 16 /*data atom header + flags */ + strlen(value));
1630 membuffer_write_atom_name(buf, "----");
1631 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1632 membuffer_write_atom_name(buf, "mean");
1633 membuffer_write_int32(buf, 0);
1634 membuffer_write(buf, "com.apple.iTunes", 16);
1635 membuffer_write_int32(buf, 12 + strlen(name));
1636 membuffer_write_atom_name(buf, "name");
1637 membuffer_write_int32(buf, 0);
1638 membuffer_write(buf, name, strlen(name));
1639 membuffer_write_int32(buf,
1640 8 /*data atom header */ +
1641 8 /*flags + reserved */ + strlen(value));
1642 membuffer_write_atom_name(buf, "data");
1643 membuffer_write_int32(buf, 1); //flags
1644 membuffer_write_int32(buf, 0); //reserved
1645 membuffer_write(buf, value, strlen(value));
1648 static unsigned membuffer_error(const struct membuffer *buf)
1653 static void membuffer_free(struct membuffer *buf)
1659 static unsigned membuffer_get_size(const struct membuffer *buf)
1661 return buf->written;
1664 static void *membuffer_detach(struct membuffer *buf)
1670 ret = para_realloc(buf->data, buf->written);
1676 static uint32_t create_ilst(const struct mp4_metadata *data, void **out_buffer,
1677 uint32_t * out_size)
1679 struct membuffer *buf = membuffer_create();
1681 char *mask = para_calloc(data->count);
1682 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1683 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1684 const char *genre_ptr = 0, *tempo_ptr = 0;
1686 for (metaptr = 0; metaptr < data->count; metaptr++) {
1687 struct mp4_tag *tag = &data->tags[metaptr];
1688 if (!strcasecmp(tag->item, "tracknumber")
1689 || !strcasecmp(tag->item, "track")) {
1690 if (tracknumber_ptr == 0)
1691 tracknumber_ptr = tag->value;
1693 } else if (!strcasecmp(tag->item, "totaltracks")) {
1694 if (totaltracks_ptr == 0)
1695 totaltracks_ptr = tag->value;
1697 } else if (!strcasecmp(tag->item, "discnumber")
1698 || !strcasecmp(tag->item, "disc")) {
1699 if (discnumber_ptr == 0)
1700 discnumber_ptr = tag->value;
1702 } else if (!strcasecmp(tag->item, "totaldiscs")) {
1703 if (totaldiscs_ptr == 0)
1704 totaldiscs_ptr = tag->value;
1706 } else if (!strcasecmp(tag->item, "genre")) {
1708 genre_ptr = tag->value;
1710 } else if (!strcasecmp(tag->item, "tempo")) {
1712 tempo_ptr = tag->value;
1717 if (tracknumber_ptr)
1718 membuffer_write_track_tag(buf, "trkn", myatoi(tracknumber_ptr),
1719 myatoi(totaltracks_ptr));
1721 membuffer_write_track_tag(buf, "disk", myatoi(discnumber_ptr),
1722 myatoi(totaldiscs_ptr));
1724 membuffer_write_int16_tag(buf, "tmpo", myatoi(tempo_ptr));
1727 uint32_t index = meta_genre_to_index(genre_ptr);
1729 membuffer_write_std_tag(buf, "©gen", genre_ptr);
1731 membuffer_write_int16_tag(buf, "gnre", index);
1733 for (metaptr = 0; metaptr < data->count; metaptr++) {
1734 struct mp4_tag *tag;
1735 const char *std_meta_atom;
1739 tag = &data->tags[metaptr];
1740 std_meta_atom = find_standard_meta(tag->item);
1742 membuffer_write_std_tag(buf, std_meta_atom, tag->value);
1744 membuffer_write_custom_tag(buf, tag->item, tag->value);
1748 if (membuffer_error(buf)) {
1749 membuffer_free(buf);
1753 *out_size = membuffer_get_size(buf);
1754 *out_buffer = membuffer_detach(buf);
1755 membuffer_free(buf);
1760 static void membuffer_write_atom(struct membuffer *buf, const char *name, unsigned size,
1763 membuffer_write_int32(buf, size + 8);
1764 membuffer_write_atom_name(buf, name);
1765 membuffer_write(buf, data, size);
1768 static void *membuffer_get_ptr(const struct membuffer *buf)
1773 static void membuffer_set_error(struct membuffer *buf)
1778 static unsigned membuffer_transfer_from_file(struct membuffer *buf, struct mp4 *src,
1784 oldsize = membuffer_get_size(buf);
1785 if (membuffer_write(buf, 0, bytes) != bytes)
1788 bufptr = membuffer_get_ptr(buf);
1792 if ((unsigned)read_data(src, (char *) bufptr + oldsize, bytes) !=
1794 membuffer_set_error(buf);
1801 static uint32_t create_meta(const struct mp4_metadata *data, void **out_buffer,
1802 uint32_t * out_size)
1804 struct membuffer *buf;
1808 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1811 buf = membuffer_create();
1813 membuffer_write_int32(buf, 0);
1814 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1817 *out_size = membuffer_get_size(buf);
1818 *out_buffer = membuffer_detach(buf);
1819 membuffer_free(buf);
1823 static uint32_t create_udta(const struct mp4_metadata *data, void **out_buffer,
1824 uint32_t * out_size)
1826 struct membuffer *buf;
1830 if (!create_meta(data, &meta_buffer, &meta_size))
1833 buf = membuffer_create();
1835 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1839 *out_size = membuffer_get_size(buf);
1840 *out_buffer = membuffer_detach(buf);
1841 membuffer_free(buf);
1845 static uint32_t fix_byte_order_32(uint32_t src)
1847 return read_u32_be(&src);
1850 static uint32_t modify_moov(struct mp4 *f, const struct mp4_metadata *data,
1851 void **out_buffer, uint32_t * out_size)
1853 uint64_t total_base = f->moov_offset + 8;
1854 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1856 uint64_t udta_offset, meta_offset, ilst_offset;
1857 uint32_t udta_size, meta_size, ilst_size;
1859 uint32_t new_ilst_size;
1860 void *new_ilst_buffer;
1865 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1866 struct membuffer *buf;
1867 void *new_udta_buffer;
1868 uint32_t new_udta_size;
1869 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1872 buf = membuffer_create();
1873 set_position(f, total_base);
1874 membuffer_transfer_from_file(buf, f, total_size);
1876 membuffer_write_atom(buf, "udta", new_udta_size,
1879 free(new_udta_buffer);
1881 *out_size = membuffer_get_size(buf);
1882 *out_buffer = membuffer_detach(buf);
1883 membuffer_free(buf);
1886 udta_offset = get_position(f);
1887 udta_size = read_int32(f);
1888 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
1889 struct membuffer *buf;
1890 void *new_meta_buffer;
1891 uint32_t new_meta_size;
1892 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
1895 buf = membuffer_create();
1896 set_position(f, total_base);
1897 membuffer_transfer_from_file(buf, f,
1898 (uint32_t)(udta_offset - total_base));
1900 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
1901 membuffer_write_atom_name(buf, "udta");
1902 membuffer_transfer_from_file(buf, f, udta_size);
1904 membuffer_write_atom(buf, "meta", new_meta_size,
1906 free(new_meta_buffer);
1908 *out_size = membuffer_get_size(buf);
1909 *out_buffer = membuffer_detach(buf);
1910 membuffer_free(buf);
1913 meta_offset = get_position(f);
1914 meta_size = read_int32(f);
1915 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
1916 return 0; //shouldn't happen, find_atom_v2 above takes care of it
1917 ilst_offset = get_position(f);
1918 ilst_size = read_int32(f);
1920 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
1923 size_delta = new_ilst_size - (ilst_size - 8);
1925 *out_size = total_size + size_delta;
1926 *out_buffer = para_malloc(*out_size);
1927 p_out = (uint8_t *) * out_buffer;
1929 set_position(f, total_base);
1931 (uint32_t) (udta_offset - total_base));
1932 p_out += (uint32_t) (udta_offset - total_base);
1933 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1935 read_data(f, p_out, 4);
1938 (uint32_t) (meta_offset - udta_offset - 8));
1939 p_out += (uint32_t) (meta_offset - udta_offset - 8);
1940 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1942 read_data(f, p_out, 4);
1945 (uint32_t) (ilst_offset - meta_offset - 8));
1946 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
1947 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1949 read_data(f, p_out, 4);
1952 memcpy(p_out, new_ilst_buffer, new_ilst_size);
1953 p_out += new_ilst_size;
1955 set_position(f, ilst_offset + ilst_size);
1956 read_data(f, p_out, (uint32_t) (total_size
1957 - (ilst_offset - total_base) - ilst_size));
1959 free(new_ilst_buffer);
1964 static int32_t write_data(struct mp4 *f, void *data, uint32_t size)
1968 result = f->stream->write(f->stream->user_data, data, size);
1970 f->current_position += size;
1975 static int32_t write_int32(struct mp4 *f, uint32_t data)
1978 write_u32_be(temp, data);
1979 return write_data(f, temp, sizeof(temp));
1982 static int32_t truncate_stream(struct mp4 *f)
1984 return f->stream->truncate(f->stream->user_data);
1987 int32_t mp4_meta_update(struct mp4_callback *f, const struct mp4_metadata *data)
1989 void *new_moov_data;
1990 uint32_t new_moov_size;
1992 struct mp4 *ff = para_calloc(sizeof(struct mp4));
1994 set_position(ff, 0);
1998 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2003 /* copy moov atom to end of the file */
2004 if (ff->last_atom != ATOM_MOOV) {
2005 char *free_data = "free";
2007 /* rename old moov to free */
2008 set_position(ff, ff->moov_offset + 4);
2009 write_data(ff, free_data, 4);
2011 set_position(ff, ff->file_size);
2012 write_int32(ff, new_moov_size + 8);
2013 write_data(ff, "moov", 4);
2014 write_data(ff, new_moov_data, new_moov_size);
2016 set_position(ff, ff->moov_offset);
2017 write_int32(ff, new_moov_size + 8);
2018 write_data(ff, "moov", 4);
2019 write_data(ff, new_moov_data, new_moov_size);
2022 truncate_stream(ff);
2028 /* find a metadata item by name */
2029 /* returns 0 if item found, 1 if no such item */
2030 static int32_t meta_find_by_name(const struct mp4 *f, const char *item,
2035 for (i = 0; i < f->tags.count; i++) {
2036 if (!strcasecmp(f->tags.tags[i].item, item)) {
2037 *value = para_strdup(f->tags.tags[i].value);
2048 int32_t mp4_meta_get_artist(const struct mp4 *f, char **value)
2050 return meta_find_by_name(f, "artist", value);
2053 int32_t mp4_meta_get_title(const struct mp4 *f, char **value)
2055 return meta_find_by_name(f, "title", value);
2058 int32_t mp4_meta_get_date(const struct mp4 *f, char **value)
2060 return meta_find_by_name(f, "date", value);
2063 int32_t mp4_meta_get_album(const struct mp4 *f, char **value)
2065 return meta_find_by_name(f, "album", value);
2068 int32_t mp4_meta_get_comment(const struct mp4 *f, char **value)
2070 return meta_find_by_name(f, "comment", value);