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;
69 /* incremental track index while reading the file */
73 struct mp4_track *track[MAX_TRACKS];
76 struct mp4_metadata tags;
79 int32_t mp4_total_tracks(const struct mp4 *f)
81 return f->total_tracks;
84 static int32_t read_data(struct mp4 *f, void *data, uint32_t size)
88 result = f->stream->read(f->stream->user_data, data, size);
91 f->stream->read_error++;
93 f->current_position += size;
98 static uint64_t read_int64(struct mp4 *f)
102 read_data(f, data, 8);
103 return read_u64_be(data);
106 static bool atom_compare(int8_t a1, int8_t b1, int8_t c1, int8_t d1,
107 int8_t a2, int8_t b2, int8_t c2, int8_t d2)
109 return a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2;
113 /* atoms with subatoms */
121 ATOM_ILST = 8, /* iTunes Metadata list */
132 ATOM_COMPILATION = 19,
142 /* atoms without subatoms */
162 ATOM_META = 148, /* iTunes Metadata box */
163 ATOM_NAME = 149, /* iTunes Metadata name box */
164 ATOM_DATA = 150, /* iTunes Metadata data box */
171 ATOM_ALBUM_ARTIST = 157,
172 ATOM_CONTENTGROUP = 158,
174 ATOM_DESCRIPTION = 160,
177 ATOM_EPISODENAME = 163,
178 ATOM_SORTTITLE = 164,
179 ATOM_SORTALBUM = 165,
180 ATOM_SORTARTIST = 166,
181 ATOM_SORTALBUMARTIST = 167,
182 ATOM_SORTWRITER = 168,
191 #define ATOM_FREE ATOM_UNKNOWN
192 #define ATOM_SKIP ATOM_UNKNOWN
194 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
196 static uint8_t atom_name_to_type(int8_t a, int8_t b, int8_t c, int8_t d)
199 if (atom_compare(a, b, c, d, 'm', 'o', 'o', 'v'))
201 else if (atom_compare(a, b, c, d, 'm', 'i', 'n', 'f'))
203 else if (atom_compare(a, b, c, d, 'm', 'd', 'i', 'a'))
205 else if (atom_compare(a, b, c, d, 'm', 'd', 'a', 't'))
207 else if (atom_compare(a, b, c, d, 'm', 'd', 'h', 'd'))
209 else if (atom_compare(a, b, c, d, 'm', 'v', 'h', 'd'))
211 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'a'))
213 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'v'))
215 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 's'))
217 else if (atom_compare(a, b, c, d, 'm', 'e', 't', 'a'))
219 } else if (a == 't') {
220 if (atom_compare(a, b, c, d, 't', 'r', 'a', 'k'))
222 else if (atom_compare(a, b, c, d, 't', 'k', 'h', 'd'))
224 else if (atom_compare(a, b, c, d, 't', 'r', 'e', 'f'))
226 else if (atom_compare(a, b, c, d, 't', 'r', 'k', 'n'))
228 else if (atom_compare(a, b, c, d, 't', 'm', 'p', 'o'))
230 else if (atom_compare(a, b, c, d, 't', 'v', 'n', 'n'))
232 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'h'))
234 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 'n'))
235 return ATOM_EPISODENAME;
236 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'n'))
238 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 's'))
240 } else if (a == 's') {
241 if (atom_compare(a, b, c, d, 's', 't', 'b', 'l'))
243 else if (atom_compare(a, b, c, d, 's', 'm', 'h', 'd'))
245 else if (atom_compare(a, b, c, d, 's', 't', 's', 'd'))
247 else if (atom_compare(a, b, c, d, 's', 't', 't', 's'))
249 else if (atom_compare(a, b, c, d, 's', 't', 'c', 'o'))
251 else if (atom_compare(a, b, c, d, 's', 't', 's', 'c'))
253 else if (atom_compare(a, b, c, d, 's', 't', 's', 'z'))
255 else if (atom_compare(a, b, c, d, 's', 't', 'z', '2'))
257 else if (atom_compare(a, b, c, d, 's', 'k', 'i', 'p'))
259 else if (atom_compare(a, b, c, d, 's', 'i', 'n', 'f'))
261 else if (atom_compare(a, b, c, d, 's', 'c', 'h', 'i'))
263 else if (atom_compare(a, b, c, d, 's', 'o', 'n', 'm'))
264 return ATOM_SORTTITLE;
265 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'l'))
266 return ATOM_SORTALBUM;
267 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'r'))
268 return ATOM_SORTARTIST;
269 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'a'))
270 return ATOM_SORTALBUMARTIST;
271 else if (atom_compare(a, b, c, d, 's', 'o', 'c', 'o'))
272 return ATOM_SORTWRITER;
273 else if (atom_compare(a, b, c, d, 's', 'o', 's', 'n'))
274 return ATOM_SORTSHOW;
275 } else if (a == COPYRIGHT_SYMBOL) {
276 if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'n', 'a', 'm'))
278 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'A', 'R', 'T'))
280 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'w', 'r', 't'))
282 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'a', 'l', 'b'))
284 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'd', 'a', 'y'))
286 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 't', 'o', 'o'))
288 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'c', 'm', 't'))
290 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'e', 'n'))
292 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'r', 'p'))
293 return ATOM_CONTENTGROUP;
294 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'l', 'y', 'r'))
298 if (atom_compare(a, b, c, d, 'e', 'd', 't', 's'))
300 else if (atom_compare(a, b, c, d, 'e', 's', 'd', 's'))
302 else if (atom_compare(a, b, c, d, 'f', 't', 'y', 'p'))
304 else if (atom_compare(a, b, c, d, 'f', 'r', 'e', 'e'))
306 else if (atom_compare(a, b, c, d, 'h', 'm', 'h', 'd'))
308 else if (atom_compare(a, b, c, d, 'v', 'm', 'h', 'd'))
310 else if (atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
312 else if (atom_compare(a, b, c, d, 'i', 'l', 's', 't'))
314 else if (atom_compare(a, b, c, d, 'n', 'a', 'm', 'e'))
316 else if (atom_compare(a, b, c, d, 'd', 'a', 't', 'a'))
318 else if (atom_compare(a, b, c, d, 'd', 'i', 's', 'k'))
320 else if (atom_compare(a, b, c, d, 'g', 'n', 'r', 'e'))
322 else if (atom_compare(a, b, c, d, 'c', 'o', 'v', 'r'))
324 else if (atom_compare(a, b, c, d, 'c', 'p', 'i', 'l'))
325 return ATOM_COMPILATION;
326 else if (atom_compare(a, b, c, d, 'c', 't', 't', 's'))
328 else if (atom_compare(a, b, c, d, 'd', 'r', 'm', 's'))
330 else if (atom_compare(a, b, c, d, 'f', 'r', 'm', 'a'))
332 else if (atom_compare(a, b, c, d, 'p', 'r', 'i', 'v'))
334 else if (atom_compare(a, b, c, d, 'i', 'v', 'i', 'v'))
336 else if (atom_compare(a, b, c, d, 'u', 's', 'e', 'r'))
338 else if (atom_compare(a, b, c, d, 'k', 'e', 'y', ' '))
340 else if (atom_compare(a, b, c, d, 'a', 'A', 'R', 'T'))
341 return ATOM_ALBUM_ARTIST;
342 else if (atom_compare(a, b, c, d, 'd', 'e', 's', 'c'))
343 return ATOM_DESCRIPTION;
344 else if (atom_compare(a, b, c, d, 'p', 'c', 's', 't'))
350 /* read atom header, return atom size, atom size is with header included */
351 static uint64_t atom_read_header(struct mp4 *f, uint8_t * atom_type,
352 uint8_t * header_size)
356 int8_t atom_header[8];
358 ret = read_data(f, atom_header, 8);
362 size = read_u32_be(atom_header);
365 /* check for 64 bit atom size */
368 size = read_int64(f);
370 *atom_type = atom_name_to_type(atom_header[4], atom_header[5],
371 atom_header[6], atom_header[7]);
375 static int64_t get_position(const struct mp4 *f)
377 return f->current_position;
380 static int need_parse_when_meta_only(uint8_t atom_type)
401 static int32_t set_position(struct mp4 *f, int64_t position)
403 f->stream->seek(f->stream->user_data, position);
404 f->current_position = position;
409 static void track_add(struct mp4 *f)
413 if (f->total_tracks > MAX_TRACKS) {
418 f->track[f->total_tracks - 1] = para_calloc(sizeof(struct mp4_track));
421 static uint8_t read_char(struct mp4 *f)
424 read_data(f, &output, 1);
428 static uint32_t read_int24(struct mp4 *f)
432 read_data(f, data, 3);
433 return read_u24_be(data);
436 static uint32_t read_int32(struct mp4 *f)
440 read_data(f, data, 4);
441 return read_u32_be(data);
444 static int32_t read_stsz(struct mp4 *f)
449 if (f->total_tracks == 0)
451 t = f->track[f->total_tracks - 1];
452 read_char(f); /* version */
453 read_int24(f); /* flags */
454 t->stsz_sample_size = read_int32(f);
455 t->stsz_sample_count = read_int32(f);
456 if (t->stsz_sample_size != 0)
458 t->stsz_table = para_malloc(t->stsz_sample_count * sizeof(int32_t));
459 for (i = 0; i < t->stsz_sample_count && !f->stream->read_error; i++)
460 t->stsz_table[i] = read_int32(f);
464 static int32_t read_stts(struct mp4 *f)
470 if (f->total_tracks == 0)
472 t = f->track[f->total_tracks - 1];
473 if (t->stts_entry_count)
475 read_char(f); /* version */
476 read_int24(f); /* flags */
477 t->stts_entry_count = read_int32(f);
479 t->stts_sample_count = para_malloc(t->stts_entry_count
481 t->stts_sample_delta = para_malloc(t->stts_entry_count
484 for (i = 0; i < t->stts_entry_count && !f->stream->read_error; i++) {
485 t->stts_sample_count[i] = read_int32(f);
486 t->stts_sample_delta[i] = read_int32(f);
491 static int32_t read_ctts(struct mp4 *f)
496 if (f->total_tracks == 0)
498 t = f->track[f->total_tracks - 1];
499 if (t->ctts_entry_count)
502 read_char(f); /* version */
503 read_int24(f); /* flags */
504 t->ctts_entry_count = read_int32(f);
506 t->ctts_sample_count = para_malloc(t->ctts_entry_count
508 t->ctts_sample_offset = para_malloc(t->ctts_entry_count
512 for (i = 0; i < t->ctts_entry_count && !f->stream->read_error; i++) {
513 t->ctts_sample_count[i] = read_int32(f);
514 t->ctts_sample_offset[i] = read_int32(f);
519 static int32_t read_stsc(struct mp4 *f)
524 if (f->total_tracks == 0)
526 t = f->track[f->total_tracks - 1];
528 read_char(f); /* version */
529 read_int24(f); /* flags */
530 t->stsc_entry_count = read_int32(f);
531 t->stsc_first_chunk = para_malloc(t->stsc_entry_count * sizeof(int32_t));
532 t->stsc_samples_per_chunk = para_malloc(t->stsc_entry_count
534 t->stsc_sample_desc_index = para_malloc(t->stsc_entry_count *
538 for (i = 0; i < t->stsc_entry_count && !f->stream->read_error; i++) {
539 t->stsc_first_chunk[i] = read_int32(f);
540 t->stsc_samples_per_chunk[i] = read_int32(f);
541 t->stsc_sample_desc_index[i] = read_int32(f);
546 static int32_t read_stco(struct mp4 *f)
551 if (f->total_tracks == 0)
553 t = f->track[f->total_tracks - 1];
555 read_char(f); /* version */
556 read_int24(f); /* flags */
557 t->stco_entry_count = read_int32(f);
558 t->stco_chunk_offset = para_malloc(t->stco_entry_count
561 for (i = 0; i < t->stco_entry_count && !f->stream->read_error; i++)
562 t->stco_chunk_offset[i] = read_int32(f);
566 static uint16_t read_int16(struct mp4 *f)
570 read_data(f, data, 2);
571 return read_u16_be(data);
574 static int32_t read_mp4a(struct mp4 *f)
577 uint8_t atom_type = 0;
578 uint8_t header_size = 0;
581 if (f->total_tracks == 0)
583 t = f->track[f->total_tracks - 1];
585 for (i = 0; i < 6; i++) {
586 read_char(f); /* reserved */
588 /* data_reference_index */ read_int16(f);
590 read_int32(f); /* reserved */
591 read_int32(f); /* reserved */
593 t->channelCount = read_int16(f);
594 t->sampleSize = read_int16(f);
599 t->sampleRate = read_int16(f);
603 atom_read_header(f, &atom_type, &header_size);
607 static int32_t read_stsd(struct mp4 *f)
610 uint8_t header_size = 0;
614 if (f->total_tracks == 0)
616 t = f->track[f->total_tracks - 1];
618 read_char(f); /* version */
619 read_int24(f); /* flags */
621 t->stsd_entry_count = read_int32(f);
624 for (i = 0; i < t->stsd_entry_count && !f->stream->read_error; i++) {
625 uint64_t skip = get_position(f);
627 uint8_t atom_type = 0;
628 size = atom_read_header(f, &atom_type, &header_size);
630 t->is_audio = atom_type == ATOM_MP4A;
633 set_position(f, skip);
639 static int32_t tag_add_field(struct mp4_metadata *tags, const char *item,
640 const char *value, int32_t len)
642 if (!item || (item && !*item) || !value)
644 tags->tags = para_realloc(tags->tags,
645 (tags->count + 1) * sizeof(struct mp4_tag));
646 tags->tags[tags->count].item = para_strdup(item);
647 tags->tags[tags->count].len = len;
649 tags->tags[tags->count].value = para_malloc(len + 1);
650 memcpy(tags->tags[tags->count].value, value, len);
651 tags->tags[tags->count].value[len] = 0;
653 tags->tags[tags->count].value = para_strdup(value);
659 static const char *ID3v1GenreList[] = {
660 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
661 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
662 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
663 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
664 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
665 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
666 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
667 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
668 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
669 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
670 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
671 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
672 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
673 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
674 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
675 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
676 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
677 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
678 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
679 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
680 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
681 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
682 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
683 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
684 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
685 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
686 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
687 "Anime", "JPop", "SynthPop",
690 static const char *meta_index_to_genre(uint32_t idx)
692 if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
693 return ID3v1GenreList[idx - 1];
699 static char *read_string(struct mp4 *f, uint32_t length)
701 char *str = para_malloc(length + 1);
702 if ((uint32_t)read_data(f, str, length) != length) {
710 static int32_t set_metadata_name(uint8_t atom_type, char **name)
712 static char *tag_names[] = {
713 "unknown", "title", "artist", "writer", "album",
714 "date", "tool", "comment", "genre", "track",
715 "disc", "compilation", "genre", "tempo", "cover",
716 "album_artist", "contentgroup", "lyrics", "description",
717 "network", "show", "episodename",
718 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
719 "sortwriter", "sortshow",
720 "season", "episode", "podcast"
755 case ATOM_COMPILATION:
767 case ATOM_ALBUM_ARTIST:
770 case ATOM_CONTENTGROUP:
776 case ATOM_DESCRIPTION:
785 case ATOM_EPISODENAME:
794 case ATOM_SORTARTIST:
797 case ATOM_SORTALBUMARTIST:
800 case ATOM_SORTWRITER:
820 *name = para_strdup(tag_names[tag_idx]);
824 static uint32_t min_body_size(uint8_t atom_type)
831 return sizeof (char) /* version */
832 + sizeof(uint8_t) * 3 /* flags */
833 + sizeof(uint32_t) /* reserved */
834 + sizeof(uint16_t) /* leading uint16_t */
835 + sizeof(uint16_t) /* track */
836 + sizeof(uint16_t); /* totaltracks */
838 return sizeof (char) /* version */
839 + sizeof(uint8_t) * 3 /* flags */
840 + sizeof(uint32_t) /* reserved */
841 + sizeof(uint16_t) /* disc */
842 + sizeof(uint16_t); /* totaldiscs */
843 default: assert(false);
847 static int32_t parse_tag(struct mp4 *f, uint8_t parent, int32_t size)
850 uint8_t header_size = 0;
851 uint64_t subsize, sumsize;
860 sumsize < size && !f->stream->read_error; /* CVE-2017-9222 */
861 set_position(f, destpos), sumsize += subsize
863 subsize = atom_read_header(f, &atom_type, &header_size);
864 destpos = get_position(f) + subsize - header_size;
867 if (atom_type == ATOM_NAME) {
868 read_char(f); /* version */
869 read_int24(f); /* flags */
871 name = read_string(f, subsize - (header_size + 4));
874 if (atom_type != ATOM_DATA)
876 read_char(f); /* version */
877 read_int24(f); /* flags */
878 read_int32(f); /* reserved */
880 /* some need special attention */
881 if (parent == ATOM_GENRE2 || parent == ATOM_TEMPO) {
883 if (subsize - header_size < min_body_size(parent))
886 if (parent == ATOM_TEMPO) {
888 sprintf(temp, "%.5u BPM", val);
889 tag_add_field(&(f-> tags), "tempo",
892 const char *tmp = meta_index_to_genre(val);
894 tag_add_field (&(f->tags),
898 } else if (parent == ATOM_TRACK || parent == ATOM_DISC) {
899 uint16_t index, total;
901 if (subsize - header_size < min_body_size(parent))
904 index = read_int16(f);
905 total = read_int16(f);
906 if (parent == ATOM_TRACK)
908 sprintf(temp, "%d", index);
909 tag_add_field(&(f->tags), parent == ATOM_TRACK?
910 "track" : "disc", temp, -1);
912 sprintf(temp, "%d", total);
913 tag_add_field(& (f-> tags),
914 parent == ATOM_TRACK?
915 "totaltracks" : "totaldiscs", temp, -1);
920 data = read_string(f, subsize - (header_size + 8));
921 len = subsize - (header_size + 8);
927 set_metadata_name(parent , &name);
929 tag_add_field(&(f->tags), name, data, len);
938 static int32_t read_mdhd(struct mp4 *f)
944 if (f->total_tracks == 0)
946 t = f->track[f->total_tracks - 1];
948 version = read_int32(f);
950 read_int64(f); //creation-time
951 read_int64(f); //modification-time
952 t->timeScale = read_int32(f); //timescale
953 t->duration = read_int64(f); //duration
954 } else { //version == 0
957 read_int32(f); //creation-time
958 read_int32(f); //modification-time
959 t->timeScale = read_int32(f); //timescale
960 temp = read_int32(f);
961 t->duration = (temp == (uint32_t) (-1))?
962 (uint64_t) (-1) : (uint64_t) (temp);
969 static int32_t parse_metadata(struct mp4 *f, int32_t size)
971 uint64_t subsize, sumsize = 0;
973 uint8_t header_size = 0;
975 while (sumsize < size) {
976 subsize = atom_read_header(f, &atom_type, &header_size);
979 parse_tag(f, atom_type, (uint32_t)(subsize - header_size));
986 static int32_t read_meta(struct mp4 *f, uint64_t size)
988 uint64_t subsize, sumsize = 0;
990 uint8_t header_size = 0;
992 read_char(f); /* version */
993 read_int24(f); /* flags */
995 while (sumsize < (size - (header_size + 4))) {
996 subsize = atom_read_header(f, &atom_type, &header_size);
997 if (subsize <= header_size + 4)
999 if (atom_type == ATOM_ILST) {
1000 parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1002 set_position(f, get_position(f) + subsize - header_size);
1010 static int32_t atom_read(struct mp4 *f, int32_t size, uint8_t atom_type)
1012 uint64_t dest_position = get_position(f) + size - 8;
1013 if (atom_type == ATOM_STSZ) {
1014 /* sample size box */
1016 } else if (atom_type == ATOM_STTS) {
1017 /* time to sample box */
1019 } else if (atom_type == ATOM_CTTS) {
1020 /* composition offset box */
1022 } else if (atom_type == ATOM_STSC) {
1023 /* sample to chunk box */
1025 } else if (atom_type == ATOM_STCO) {
1026 /* chunk offset box */
1028 } else if (atom_type == ATOM_STSD) {
1029 /* sample description box */
1031 } else if (atom_type == ATOM_MDHD) {
1034 } else if (atom_type == ATOM_META) {
1035 /* iTunes Metadata box */
1039 set_position(f, dest_position);
1043 /* parse atoms that are sub atoms of other atoms */
1044 static int32_t parse_sub_atoms(struct mp4 *f, uint64_t total_size, int meta_only)
1047 uint8_t atom_type = 0;
1048 uint64_t counted_size = 0;
1049 uint8_t header_size = 0;
1051 while (counted_size < total_size) {
1052 size = atom_read_header(f, &atom_type, &header_size);
1053 counted_size += size;
1055 /* check for end of file */
1059 /* we're starting to read a new track, update index,
1060 * so that all data and tables get written in the right place
1062 if (atom_type == ATOM_TRAK)
1064 /* parse subatoms */
1065 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1066 set_position(f, get_position(f) + size - header_size);
1067 } else if (atom_type < SUBATOMIC) {
1068 parse_sub_atoms(f, size - header_size, meta_only);
1070 atom_read(f, (uint32_t) size, atom_type);
1077 /* parse root atoms */
1078 static int32_t parse_atoms(struct mp4 *f, int meta_only)
1081 uint8_t atom_type = 0;
1082 uint8_t header_size = 0;
1085 f->stream->read_error = 0;
1088 atom_read_header(f, &atom_type, &header_size)) != 0) {
1089 f->file_size += size;
1090 f->last_atom = atom_type;
1092 if (atom_type == ATOM_MOOV && size > header_size) {
1093 f->moov_offset = get_position(f) - header_size;
1094 f->moov_size = size;
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 /* skip this atom */
1104 set_position(f, get_position(f) + size - header_size);
1111 struct mp4 *mp4_open_read(struct mp4_callback *f)
1113 struct mp4 *ff = para_calloc(sizeof(struct mp4));
1127 static int32_t tag_delete(struct mp4_metadata *tags)
1131 for (i = 0; i < tags->count; i++) {
1132 free(tags->tags[i].item);
1133 free(tags->tags[i].value);
1142 void mp4_close(struct mp4 *ff)
1146 for (i = 0; i < ff->total_tracks; i++) {
1148 free(ff->track[i]->stsz_table);
1149 free(ff->track[i]->stts_sample_count);
1150 free(ff->track[i]->stts_sample_delta);
1151 free(ff->track[i]->stsc_first_chunk);
1152 free(ff->track[i]->stsc_samples_per_chunk);
1153 free(ff->track[i]->stsc_sample_desc_index);
1154 free(ff->track[i]->stco_chunk_offset);
1155 free(ff->track[i]->ctts_sample_count);
1156 free(ff->track[i]->ctts_sample_offset);
1161 tag_delete(&(ff->tags));
1165 static int32_t chunk_of_sample(const struct mp4 *f, int32_t track,
1166 int32_t sample, int32_t *chunk_sample, int32_t *chunk)
1168 int32_t total_entries = 0;
1169 int32_t chunk2entry;
1170 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1174 if (f->track[track] == NULL) {
1178 total_entries = f->track[track]->stsc_entry_count;
1185 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1186 *chunk = chunk2 - chunk1;
1187 range_samples = *chunk * chunk1samples;
1189 if (sample < total + range_samples)
1192 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1195 if (chunk2entry < total_entries) {
1197 total += range_samples;
1199 } while (chunk2entry < total_entries);
1202 *chunk = (sample - total) / chunk1samples + chunk1;
1206 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1211 static int32_t chunk_to_offset(const struct mp4 *f, int32_t track,
1214 const struct mp4_track *p_track = f->track[track];
1216 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1217 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1219 } else if (p_track->stco_entry_count) {
1220 return p_track->stco_chunk_offset[chunk - 1];
1228 static int32_t sample_range_size(const struct mp4 *f, int32_t track,
1229 int32_t chunk_sample, int32_t sample)
1232 const struct mp4_track *p_track = f->track[track];
1234 if (p_track->stsz_sample_size) {
1235 return (sample - chunk_sample) * p_track->stsz_sample_size;
1237 if (sample >= p_track->stsz_sample_count)
1240 for (i = chunk_sample, total = 0; i < sample; i++) {
1241 total += p_track->stsz_table[i];
1248 static int32_t sample_to_offset(const struct mp4 *f, int32_t track,
1251 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1253 chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1255 chunk_offset1 = chunk_to_offset(f, track, chunk);
1256 chunk_offset2 = chunk_offset1 + sample_range_size(f,
1257 track, chunk_sample, sample);
1258 return chunk_offset2;
1262 * Return the number of milliseconds of the given track.
1264 * \param f As returned by \ref mp4_open_read(), must not be NULL.
1265 * \param track Between zero and the value returned by \ref mp4_total_tracks().
1267 * The function returns zero if the audio file is of zero length or contains a
1268 * corrupt track header.
1270 uint64_t mp4_get_duration(const struct mp4 *f, int32_t track)
1272 const struct mp4_track *t = f->track[track];
1274 if (t->timeScale == 0)
1276 return t->duration * 1000 / t->timeScale;
1280 * Check whether the given track number corresponds to an audio track.
1282 * \param f See \ref mp4_get_duration().
1283 * \param track See \ref mp4_get_duration().
1285 * Besides audio tracks, an mp4 file may contain video and system tracks. For
1286 * those the function returns false.
1288 bool mp4_is_audio_track(const struct mp4 *f, int32_t track)
1290 return f->track[track]->is_audio;
1293 void mp4_set_sample_position(struct mp4 *f, int32_t track, int32_t sample)
1295 int32_t offset = sample_to_offset(f, track, sample);
1296 set_position(f, offset);
1299 int32_t mp4_get_sample_size(const struct mp4 *f, int track, int sample)
1301 const struct mp4_track *t = f->track[track];
1303 if (t->stsz_sample_size != 0)
1304 return t->stsz_sample_size;
1305 return t->stsz_table[sample];
1308 uint32_t mp4_get_sample_rate(const struct mp4 *f, int32_t track)
1310 return f->track[track]->sampleRate;
1313 uint32_t mp4_get_channel_count(const struct mp4 *f, int32_t track)
1315 return f->track[track]->channelCount;
1318 int32_t mp4_num_samples(const struct mp4 *f, int32_t track)
1323 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1324 total += f->track[track]->stts_sample_count[i];
1329 struct mp4 *mp4_open_meta(struct mp4_callback *f)
1331 struct mp4 *ff = para_calloc(sizeof(struct mp4));
1345 int32_t mp4_meta_get_num_items(const struct mp4 *f)
1347 return f->tags.count;
1350 int32_t mp4_meta_get_by_index(const struct mp4 *f, uint32_t index,
1351 char **item, char **value)
1353 if (index >= f->tags.count) {
1358 *item = para_strdup(f->tags.tags[index].item);
1359 *value = para_strdup(f->tags.tags[index].value);
1364 static uint32_t find_atom(struct mp4 *f, uint64_t base, uint32_t size,
1367 uint32_t remaining = size;
1368 uint64_t atom_offset = base;
1373 set_position(f, atom_offset);
1377 atom_size = read_int32(f);
1378 if (atom_size > remaining || atom_size < 8)
1380 read_data(f, atom_name, 4);
1382 if (!memcmp(atom_name, name, 4)) {
1383 set_position(f, atom_offset);
1387 remaining -= atom_size;
1388 atom_offset += atom_size;
1393 static uint32_t find_atom_v2(struct mp4 *f, uint64_t base, uint32_t size,
1394 const char *name, uint32_t extraheaders, const char *name_inside)
1396 uint64_t first_base = (uint64_t) (-1);
1397 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1399 uint64_t mybase = get_position(f);
1400 uint32_t mysize = read_int32(f);
1402 if (first_base == (uint64_t) (-1))
1403 first_base = mybase;
1405 if (mysize < 8 + extraheaders)
1408 if (find_atom (f, mybase + (8 + extraheaders),
1409 mysize - (8 + extraheaders), name_inside)) {
1410 set_position(f, mybase);
1414 if (size <= mysize) {
1421 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1423 set_position(f, first_base);
1436 static struct membuffer *membuffer_create(void)
1438 const unsigned initial_size = 256;
1440 struct membuffer *buf = para_malloc(sizeof(*buf));
1441 buf->data = para_malloc(initial_size);
1443 buf->allocated = initial_size;
1444 buf->error = buf->data == 0 ? 1 : 0;
1449 static unsigned membuffer_write(struct membuffer *buf, const void *ptr, unsigned bytes)
1451 unsigned dest_size = buf->written + bytes;
1455 if (dest_size > buf->allocated) {
1457 buf->allocated <<= 1;
1458 } while (dest_size > buf->allocated);
1459 buf->data = para_realloc(buf->data, buf->allocated);
1463 memcpy((char *) buf->data + buf->written, ptr, bytes);
1464 buf->written += bytes;
1468 static unsigned membuffer_write_atom_name(struct membuffer *buf, const char *data)
1470 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1473 static unsigned membuffer_write_int16(struct membuffer *buf, uint16_t data)
1477 write_u16_be(temp, data);
1478 return membuffer_write(buf, temp, 2);
1481 static unsigned membuffer_write_int32(struct membuffer *buf, uint32_t data)
1484 write_u32_be(temp, data);
1485 return membuffer_write(buf, temp, 4);
1488 static void membuffer_write_track_tag(struct membuffer *buf, const char *name,
1489 uint32_t index, uint32_t total)
1491 membuffer_write_int32(buf,
1492 8 /*atom header */ + 8 /*data atom header */ +
1493 8 /*flags + reserved */ + 8 /*actual data */ );
1494 membuffer_write_atom_name(buf, name);
1495 membuffer_write_int32(buf,
1496 8 /*data atom header */ +
1497 8 /*flags + reserved */ + 8 /*actual data */ );
1498 membuffer_write_atom_name(buf, "data");
1499 membuffer_write_int32(buf, 0); //flags
1500 membuffer_write_int32(buf, 0); //reserved
1501 membuffer_write_int16(buf, 0);
1502 membuffer_write_int16(buf, (uint16_t) index); //track number
1503 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1504 membuffer_write_int16(buf, 0);
1507 static void membuffer_write_int16_tag(struct membuffer *buf, const char *name,
1510 membuffer_write_int32(buf,
1511 8 /*atom header */ + 8 /*data atom header */ +
1512 8 /*flags + reserved */ + 2 /*actual data */ );
1513 membuffer_write_atom_name(buf, name);
1514 membuffer_write_int32(buf,
1515 8 /*data atom header */ +
1516 8 /*flags + reserved */ + 2 /*actual data */ );
1517 membuffer_write_atom_name(buf, "data");
1518 membuffer_write_int32(buf, 0); //flags
1519 membuffer_write_int32(buf, 0); //reserved
1520 membuffer_write_int16(buf, value); //value
1523 static uint32_t myatoi(const char *param)
1525 return param ? atoi(param) : 0;
1528 static uint32_t meta_genre_to_index(const char *genrestr)
1531 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1532 if (!strcasecmp(genrestr, ID3v1GenreList[n]))
1538 struct stdmeta_entry {
1543 struct stdmeta_entry stdmetas[] = {
1544 {"\xA9" "nam", "title"},
1545 {"\xA9" "ART", "artist"},
1546 {"\xA9" "wrt", "writer"},
1547 {"\xA9" "alb", "album"},
1548 {"\xA9" "day", "date"},
1549 {"\xA9" "too", "tool"},
1550 {"\xA9" "cmt", "comment"},
1551 {"cpil", "compilation"},
1553 {"aART", "album_artist"},
1556 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1559 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1560 if (!strcasecmp(name, stdmetas[n].name))
1561 return stdmetas[n].atom;
1566 static void membuffer_write_std_tag(struct membuffer *buf, const char *name,
1571 /* special check for compilation flag */
1572 if (strcmp(name, "cpil") == 0) {
1576 membuffer_write_int32(buf,
1577 8 /*atom header */ + 8 /*data atom header */ +
1578 8 /*flags + reserved */ + strlen(value));
1579 membuffer_write_atom_name(buf, name);
1580 membuffer_write_int32(buf,
1581 8 /*data atom header */ +
1582 8 /*flags + reserved */ + strlen(value));
1583 membuffer_write_atom_name(buf, "data");
1584 membuffer_write_int32(buf, flags); //flags
1585 membuffer_write_int32(buf, 0); //reserved
1586 membuffer_write(buf, value, strlen(value));
1589 static void membuffer_write_custom_tag(struct membuffer *buf, const char *name,
1592 membuffer_write_int32(buf,
1593 8 /*atom header */ +
1594 0x1C /*weirdo itunes atom */ +
1595 12 /*name atom header */ + strlen(name) +
1596 16 /*data atom header + flags */ + strlen(value));
1597 membuffer_write_atom_name(buf, "----");
1598 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1599 membuffer_write_atom_name(buf, "mean");
1600 membuffer_write_int32(buf, 0);
1601 membuffer_write(buf, "com.apple.iTunes", 16);
1602 membuffer_write_int32(buf, 12 + strlen(name));
1603 membuffer_write_atom_name(buf, "name");
1604 membuffer_write_int32(buf, 0);
1605 membuffer_write(buf, name, strlen(name));
1606 membuffer_write_int32(buf,
1607 8 /*data atom header */ +
1608 8 /*flags + reserved */ + strlen(value));
1609 membuffer_write_atom_name(buf, "data");
1610 membuffer_write_int32(buf, 1); //flags
1611 membuffer_write_int32(buf, 0); //reserved
1612 membuffer_write(buf, value, strlen(value));
1615 static unsigned membuffer_error(const struct membuffer *buf)
1620 static void membuffer_free(struct membuffer *buf)
1626 static unsigned membuffer_get_size(const struct membuffer *buf)
1628 return buf->written;
1631 static void *membuffer_detach(struct membuffer *buf)
1637 ret = para_realloc(buf->data, buf->written);
1643 static uint32_t create_ilst(const struct mp4_metadata *data, void **out_buffer,
1644 uint32_t * out_size)
1646 struct membuffer *buf = membuffer_create();
1648 char *mask = para_calloc(data->count);
1649 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1650 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1651 const char *genre_ptr = 0, *tempo_ptr = 0;
1653 for (metaptr = 0; metaptr < data->count; metaptr++) {
1654 struct mp4_tag *tag = &data->tags[metaptr];
1655 if (!strcasecmp(tag->item, "tracknumber")
1656 || !strcasecmp(tag->item, "track")) {
1657 if (tracknumber_ptr == 0)
1658 tracknumber_ptr = tag->value;
1660 } else if (!strcasecmp(tag->item, "totaltracks")) {
1661 if (totaltracks_ptr == 0)
1662 totaltracks_ptr = tag->value;
1664 } else if (!strcasecmp(tag->item, "discnumber")
1665 || !strcasecmp(tag->item, "disc")) {
1666 if (discnumber_ptr == 0)
1667 discnumber_ptr = tag->value;
1669 } else if (!strcasecmp(tag->item, "totaldiscs")) {
1670 if (totaldiscs_ptr == 0)
1671 totaldiscs_ptr = tag->value;
1673 } else if (!strcasecmp(tag->item, "genre")) {
1675 genre_ptr = tag->value;
1677 } else if (!strcasecmp(tag->item, "tempo")) {
1679 tempo_ptr = tag->value;
1684 if (tracknumber_ptr)
1685 membuffer_write_track_tag(buf, "trkn", myatoi(tracknumber_ptr),
1686 myatoi(totaltracks_ptr));
1688 membuffer_write_track_tag(buf, "disk", myatoi(discnumber_ptr),
1689 myatoi(totaldiscs_ptr));
1691 membuffer_write_int16_tag(buf, "tmpo", myatoi(tempo_ptr));
1694 uint32_t index = meta_genre_to_index(genre_ptr);
1696 membuffer_write_std_tag(buf, "©gen", genre_ptr);
1698 membuffer_write_int16_tag(buf, "gnre", index);
1700 for (metaptr = 0; metaptr < data->count; metaptr++) {
1701 struct mp4_tag *tag;
1702 const char *std_meta_atom;
1706 tag = &data->tags[metaptr];
1707 std_meta_atom = find_standard_meta(tag->item);
1709 membuffer_write_std_tag(buf, std_meta_atom, tag->value);
1711 membuffer_write_custom_tag(buf, tag->item, tag->value);
1715 if (membuffer_error(buf)) {
1716 membuffer_free(buf);
1720 *out_size = membuffer_get_size(buf);
1721 *out_buffer = membuffer_detach(buf);
1722 membuffer_free(buf);
1727 static void membuffer_write_atom(struct membuffer *buf, const char *name, unsigned size,
1730 membuffer_write_int32(buf, size + 8);
1731 membuffer_write_atom_name(buf, name);
1732 membuffer_write(buf, data, size);
1735 static void *membuffer_get_ptr(const struct membuffer *buf)
1740 static void membuffer_set_error(struct membuffer *buf)
1745 static unsigned membuffer_transfer_from_file(struct membuffer *buf, struct mp4 *src,
1751 oldsize = membuffer_get_size(buf);
1752 if (membuffer_write(buf, 0, bytes) != bytes)
1755 bufptr = membuffer_get_ptr(buf);
1759 if ((unsigned)read_data(src, (char *) bufptr + oldsize, bytes) !=
1761 membuffer_set_error(buf);
1768 static uint32_t create_meta(const struct mp4_metadata *data, void **out_buffer,
1769 uint32_t * out_size)
1771 struct membuffer *buf;
1775 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1778 buf = membuffer_create();
1780 membuffer_write_int32(buf, 0);
1781 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1784 *out_size = membuffer_get_size(buf);
1785 *out_buffer = membuffer_detach(buf);
1786 membuffer_free(buf);
1790 static uint32_t create_udta(const struct mp4_metadata *data, void **out_buffer,
1791 uint32_t * out_size)
1793 struct membuffer *buf;
1797 if (!create_meta(data, &meta_buffer, &meta_size))
1800 buf = membuffer_create();
1802 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1806 *out_size = membuffer_get_size(buf);
1807 *out_buffer = membuffer_detach(buf);
1808 membuffer_free(buf);
1812 static uint32_t fix_byte_order_32(uint32_t src)
1814 return read_u32_be(&src);
1817 static uint32_t modify_moov(struct mp4 *f, const struct mp4_metadata *data,
1818 void **out_buffer, uint32_t * out_size)
1820 uint64_t total_base = f->moov_offset + 8;
1821 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1823 uint64_t udta_offset, meta_offset, ilst_offset;
1824 uint32_t udta_size, meta_size, ilst_size;
1826 uint32_t new_ilst_size;
1827 void *new_ilst_buffer;
1832 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1833 struct membuffer *buf;
1834 void *new_udta_buffer;
1835 uint32_t new_udta_size;
1836 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1839 buf = membuffer_create();
1840 set_position(f, total_base);
1841 membuffer_transfer_from_file(buf, f, total_size);
1843 membuffer_write_atom(buf, "udta", new_udta_size,
1846 free(new_udta_buffer);
1848 *out_size = membuffer_get_size(buf);
1849 *out_buffer = membuffer_detach(buf);
1850 membuffer_free(buf);
1853 udta_offset = get_position(f);
1854 udta_size = read_int32(f);
1855 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
1856 struct membuffer *buf;
1857 void *new_meta_buffer;
1858 uint32_t new_meta_size;
1859 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
1862 buf = membuffer_create();
1863 set_position(f, total_base);
1864 membuffer_transfer_from_file(buf, f,
1865 (uint32_t)(udta_offset - total_base));
1867 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
1868 membuffer_write_atom_name(buf, "udta");
1869 membuffer_transfer_from_file(buf, f, udta_size);
1871 membuffer_write_atom(buf, "meta", new_meta_size,
1873 free(new_meta_buffer);
1875 *out_size = membuffer_get_size(buf);
1876 *out_buffer = membuffer_detach(buf);
1877 membuffer_free(buf);
1880 meta_offset = get_position(f);
1881 meta_size = read_int32(f);
1882 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
1883 return 0; //shouldn't happen, find_atom_v2 above takes care of it
1884 ilst_offset = get_position(f);
1885 ilst_size = read_int32(f);
1887 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
1890 size_delta = new_ilst_size - (ilst_size - 8);
1892 *out_size = total_size + size_delta;
1893 *out_buffer = para_malloc(*out_size);
1894 p_out = (uint8_t *) * out_buffer;
1896 set_position(f, total_base);
1898 (uint32_t) (udta_offset - total_base));
1899 p_out += (uint32_t) (udta_offset - total_base);
1900 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1902 read_data(f, p_out, 4);
1905 (uint32_t) (meta_offset - udta_offset - 8));
1906 p_out += (uint32_t) (meta_offset - udta_offset - 8);
1907 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1909 read_data(f, p_out, 4);
1912 (uint32_t) (ilst_offset - meta_offset - 8));
1913 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
1914 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1916 read_data(f, p_out, 4);
1919 memcpy(p_out, new_ilst_buffer, new_ilst_size);
1920 p_out += new_ilst_size;
1922 set_position(f, ilst_offset + ilst_size);
1923 read_data(f, p_out, (uint32_t) (total_size
1924 - (ilst_offset - total_base) - ilst_size));
1926 free(new_ilst_buffer);
1931 static int32_t write_data(struct mp4 *f, void *data, uint32_t size)
1935 result = f->stream->write(f->stream->user_data, data, size);
1937 f->current_position += size;
1942 static int32_t write_int32(struct mp4 *f, uint32_t data)
1945 write_u32_be(temp, data);
1946 return write_data(f, temp, sizeof(temp));
1949 static int32_t truncate_stream(struct mp4 *f)
1951 return f->stream->truncate(f->stream->user_data);
1954 int32_t mp4_meta_update(struct mp4_callback *f, const struct mp4_metadata *data)
1956 void *new_moov_data;
1957 uint32_t new_moov_size;
1959 struct mp4 *ff = para_calloc(sizeof(struct mp4));
1961 set_position(ff, 0);
1965 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
1970 /* copy moov atom to end of the file */
1971 if (ff->last_atom != ATOM_MOOV) {
1972 char *free_data = "free";
1974 /* rename old moov to free */
1975 set_position(ff, ff->moov_offset + 4);
1976 write_data(ff, free_data, 4);
1978 set_position(ff, ff->file_size);
1979 write_int32(ff, new_moov_size + 8);
1980 write_data(ff, "moov", 4);
1981 write_data(ff, new_moov_data, new_moov_size);
1983 set_position(ff, ff->moov_offset);
1984 write_int32(ff, new_moov_size + 8);
1985 write_data(ff, "moov", 4);
1986 write_data(ff, new_moov_data, new_moov_size);
1989 truncate_stream(ff);
1995 /* find a metadata item by name */
1996 /* returns 0 if item found, 1 if no such item */
1997 static int32_t meta_find_by_name(const struct mp4 *f, const char *item,
2002 for (i = 0; i < f->tags.count; i++) {
2003 if (!strcasecmp(f->tags.tags[i].item, item)) {
2004 *value = para_strdup(f->tags.tags[i].value);
2015 int32_t mp4_meta_get_artist(const struct mp4 *f, char **value)
2017 return meta_find_by_name(f, "artist", value);
2020 int32_t mp4_meta_get_title(const struct mp4 *f, char **value)
2022 return meta_find_by_name(f, "title", value);
2025 int32_t mp4_meta_get_date(const struct mp4 *f, char **value)
2027 return meta_find_by_name(f, "date", value);
2030 int32_t mp4_meta_get_album(const struct mp4 *f, char **value)
2032 return meta_find_by_name(f, "album", value);
2035 int32_t mp4_meta_get_comment(const struct mp4 *f, char **value)
2037 return meta_find_by_name(f, "comment", value);