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"
21 int32_t stsz_sample_size;
22 int32_t stsz_sample_count;
26 int32_t stts_entry_count;
27 int32_t *stts_sample_count;
28 int32_t *stts_sample_delta;
31 int32_t stsc_entry_count;
32 int32_t *stsc_first_chunk;
33 int32_t *stsc_samples_per_chunk;
34 int32_t *stsc_sample_desc_index;
37 int32_t stco_entry_count;
38 int32_t *stco_chunk_offset;
44 #define MAX_TRACKS 1024
47 const struct mp4_callback *cb;
48 int64_t current_position;
58 /* incremental track index while reading the file */
62 struct mp4_track *track[MAX_TRACKS];
65 struct mp4_metadata tags;
68 int32_t mp4_total_tracks(const struct mp4 *f)
70 return f->total_tracks;
73 static int32_t read_data(struct mp4 *f, void *data, uint32_t size)
77 result = f->cb->read(f->cb->user_data, data, size);
82 f->current_position += size;
87 static uint64_t read_int64(struct mp4 *f)
91 read_data(f, data, 8);
92 return read_u64_be(data);
95 static bool atom_compare(int8_t a1, int8_t b1, int8_t c1, int8_t d1,
96 int8_t a2, int8_t b2, int8_t c2, int8_t d2)
98 return a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2;
101 /* atoms with subatoms */
109 ATOM_ILST = 8, /* iTunes Metadata list */
120 ATOM_COMPILATION = 19,
130 /* atoms without subatoms */
150 ATOM_META = 148, /* iTunes Metadata box */
151 ATOM_NAME = 149, /* iTunes Metadata name box */
152 ATOM_DATA = 150, /* iTunes Metadata data box */
159 ATOM_ALBUM_ARTIST = 157,
160 ATOM_CONTENTGROUP = 158,
162 ATOM_DESCRIPTION = 160,
165 ATOM_EPISODENAME = 163,
166 ATOM_SORTTITLE = 164,
167 ATOM_SORTALBUM = 165,
168 ATOM_SORTARTIST = 166,
169 ATOM_SORTALBUMARTIST = 167,
170 ATOM_SORTWRITER = 168,
179 #define ATOM_FREE ATOM_UNKNOWN
180 #define ATOM_SKIP ATOM_UNKNOWN
182 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
184 static uint8_t atom_name_to_type(int8_t a, int8_t b, int8_t c, int8_t d)
187 if (atom_compare(a, b, c, d, 'm', 'o', 'o', 'v'))
189 else if (atom_compare(a, b, c, d, 'm', 'i', 'n', 'f'))
191 else if (atom_compare(a, b, c, d, 'm', 'd', 'i', 'a'))
193 else if (atom_compare(a, b, c, d, 'm', 'd', 'a', 't'))
195 else if (atom_compare(a, b, c, d, 'm', 'd', 'h', 'd'))
197 else if (atom_compare(a, b, c, d, 'm', 'v', 'h', 'd'))
199 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'a'))
201 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'v'))
203 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 's'))
205 else if (atom_compare(a, b, c, d, 'm', 'e', 't', 'a'))
207 } else if (a == 't') {
208 if (atom_compare(a, b, c, d, 't', 'r', 'a', 'k'))
210 else if (atom_compare(a, b, c, d, 't', 'k', 'h', 'd'))
212 else if (atom_compare(a, b, c, d, 't', 'r', 'e', 'f'))
214 else if (atom_compare(a, b, c, d, 't', 'r', 'k', 'n'))
216 else if (atom_compare(a, b, c, d, 't', 'm', 'p', 'o'))
218 else if (atom_compare(a, b, c, d, 't', 'v', 'n', 'n'))
220 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'h'))
222 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 'n'))
223 return ATOM_EPISODENAME;
224 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'n'))
226 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 's'))
228 } else if (a == 's') {
229 if (atom_compare(a, b, c, d, 's', 't', 'b', 'l'))
231 else if (atom_compare(a, b, c, d, 's', 'm', 'h', 'd'))
233 else if (atom_compare(a, b, c, d, 's', 't', 's', 'd'))
235 else if (atom_compare(a, b, c, d, 's', 't', 't', 's'))
237 else if (atom_compare(a, b, c, d, 's', 't', 'c', 'o'))
239 else if (atom_compare(a, b, c, d, 's', 't', 's', 'c'))
241 else if (atom_compare(a, b, c, d, 's', 't', 's', 'z'))
243 else if (atom_compare(a, b, c, d, 's', 't', 'z', '2'))
245 else if (atom_compare(a, b, c, d, 's', 'k', 'i', 'p'))
247 else if (atom_compare(a, b, c, d, 's', 'i', 'n', 'f'))
249 else if (atom_compare(a, b, c, d, 's', 'c', 'h', 'i'))
251 else if (atom_compare(a, b, c, d, 's', 'o', 'n', 'm'))
252 return ATOM_SORTTITLE;
253 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'l'))
254 return ATOM_SORTALBUM;
255 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'r'))
256 return ATOM_SORTARTIST;
257 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'a'))
258 return ATOM_SORTALBUMARTIST;
259 else if (atom_compare(a, b, c, d, 's', 'o', 'c', 'o'))
260 return ATOM_SORTWRITER;
261 else if (atom_compare(a, b, c, d, 's', 'o', 's', 'n'))
262 return ATOM_SORTSHOW;
263 } else if (a == COPYRIGHT_SYMBOL) {
264 if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'n', 'a', 'm'))
266 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'A', 'R', 'T'))
268 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'w', 'r', 't'))
270 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'a', 'l', 'b'))
272 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'd', 'a', 'y'))
274 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 't', 'o', 'o'))
276 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'c', 'm', 't'))
278 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'e', 'n'))
280 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'r', 'p'))
281 return ATOM_CONTENTGROUP;
282 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'l', 'y', 'r'))
286 if (atom_compare(a, b, c, d, 'e', 'd', 't', 's'))
288 else if (atom_compare(a, b, c, d, 'e', 's', 'd', 's'))
290 else if (atom_compare(a, b, c, d, 'f', 't', 'y', 'p'))
292 else if (atom_compare(a, b, c, d, 'f', 'r', 'e', 'e'))
294 else if (atom_compare(a, b, c, d, 'h', 'm', 'h', 'd'))
296 else if (atom_compare(a, b, c, d, 'v', 'm', 'h', 'd'))
298 else if (atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
300 else if (atom_compare(a, b, c, d, 'i', 'l', 's', 't'))
302 else if (atom_compare(a, b, c, d, 'n', 'a', 'm', 'e'))
304 else if (atom_compare(a, b, c, d, 'd', 'a', 't', 'a'))
306 else if (atom_compare(a, b, c, d, 'd', 'i', 's', 'k'))
308 else if (atom_compare(a, b, c, d, 'g', 'n', 'r', 'e'))
310 else if (atom_compare(a, b, c, d, 'c', 'o', 'v', 'r'))
312 else if (atom_compare(a, b, c, d, 'c', 'p', 'i', 'l'))
313 return ATOM_COMPILATION;
314 else if (atom_compare(a, b, c, d, 'c', 't', 't', 's'))
316 else if (atom_compare(a, b, c, d, 'd', 'r', 'm', 's'))
318 else if (atom_compare(a, b, c, d, 'f', 'r', 'm', 'a'))
320 else if (atom_compare(a, b, c, d, 'p', 'r', 'i', 'v'))
322 else if (atom_compare(a, b, c, d, 'i', 'v', 'i', 'v'))
324 else if (atom_compare(a, b, c, d, 'u', 's', 'e', 'r'))
326 else if (atom_compare(a, b, c, d, 'k', 'e', 'y', ' '))
328 else if (atom_compare(a, b, c, d, 'a', 'A', 'R', 'T'))
329 return ATOM_ALBUM_ARTIST;
330 else if (atom_compare(a, b, c, d, 'd', 'e', 's', 'c'))
331 return ATOM_DESCRIPTION;
332 else if (atom_compare(a, b, c, d, 'p', 'c', 's', 't'))
338 /* read atom header, return atom size, atom size is with header included */
339 static uint64_t atom_read_header(struct mp4 *f, uint8_t * atom_type,
340 uint8_t * header_size)
344 int8_t atom_header[8];
346 ret = read_data(f, atom_header, 8);
350 size = read_u32_be(atom_header);
353 /* check for 64 bit atom size */
356 size = read_int64(f);
358 *atom_type = atom_name_to_type(atom_header[4], atom_header[5],
359 atom_header[6], atom_header[7]);
363 static int64_t get_position(const struct mp4 *f)
365 return f->current_position;
368 static int need_parse_when_meta_only(uint8_t atom_type)
389 static int32_t set_position(struct mp4 *f, int64_t position)
391 f->cb->seek(f->cb->user_data, position);
392 f->current_position = position;
397 static void track_add(struct mp4 *f)
401 if (f->total_tracks > MAX_TRACKS) {
406 f->track[f->total_tracks - 1] = para_calloc(sizeof(struct mp4_track));
409 static uint8_t read_char(struct mp4 *f)
412 read_data(f, &output, 1);
416 static uint32_t read_int24(struct mp4 *f)
420 read_data(f, data, 3);
421 return read_u24_be(data);
424 static uint32_t read_int32(struct mp4 *f)
428 read_data(f, data, 4);
429 return read_u32_be(data);
432 static int32_t read_stsz(struct mp4 *f)
437 if (f->total_tracks == 0)
439 t = f->track[f->total_tracks - 1];
440 read_char(f); /* version */
441 read_int24(f); /* flags */
442 t->stsz_sample_size = read_int32(f);
443 t->stsz_sample_count = read_int32(f);
444 if (t->stsz_sample_size != 0)
446 t->stsz_table = para_malloc(t->stsz_sample_count * sizeof(int32_t));
447 for (i = 0; i < t->stsz_sample_count && !f->read_error; i++)
448 t->stsz_table[i] = read_int32(f);
452 static int32_t read_stts(struct mp4 *f)
458 if (f->total_tracks == 0)
460 t = f->track[f->total_tracks - 1];
461 if (t->stts_entry_count)
463 read_char(f); /* version */
464 read_int24(f); /* flags */
465 t->stts_entry_count = read_int32(f);
467 t->stts_sample_count = para_malloc(t->stts_entry_count
469 t->stts_sample_delta = para_malloc(t->stts_entry_count
472 for (i = 0; i < t->stts_entry_count && !f->read_error; i++) {
473 t->stts_sample_count[i] = read_int32(f);
474 t->stts_sample_delta[i] = read_int32(f);
479 static int32_t read_stsc(struct mp4 *f)
484 if (f->total_tracks == 0)
486 t = f->track[f->total_tracks - 1];
488 read_char(f); /* version */
489 read_int24(f); /* flags */
490 t->stsc_entry_count = read_int32(f);
491 t->stsc_first_chunk = para_malloc(t->stsc_entry_count * sizeof(int32_t));
492 t->stsc_samples_per_chunk = para_malloc(t->stsc_entry_count
494 t->stsc_sample_desc_index = para_malloc(t->stsc_entry_count *
498 for (i = 0; i < t->stsc_entry_count && !f->read_error; i++) {
499 t->stsc_first_chunk[i] = read_int32(f);
500 t->stsc_samples_per_chunk[i] = read_int32(f);
501 t->stsc_sample_desc_index[i] = read_int32(f);
506 static int32_t read_stco(struct mp4 *f)
511 if (f->total_tracks == 0)
513 t = f->track[f->total_tracks - 1];
515 read_char(f); /* version */
516 read_int24(f); /* flags */
517 t->stco_entry_count = read_int32(f);
518 t->stco_chunk_offset = para_malloc(t->stco_entry_count
521 for (i = 0; i < t->stco_entry_count && !f->read_error; i++)
522 t->stco_chunk_offset[i] = read_int32(f);
526 static uint16_t read_int16(struct mp4 *f)
530 read_data(f, data, 2);
531 return read_u16_be(data);
534 static int32_t read_mp4a(struct mp4 *f)
537 uint8_t atom_type = 0;
538 uint8_t header_size = 0;
541 if (f->total_tracks == 0)
543 t = f->track[f->total_tracks - 1];
545 for (i = 0; i < 6; i++) {
546 read_char(f); /* reserved */
548 /* data_reference_index */ read_int16(f);
550 read_int32(f); /* reserved */
551 read_int32(f); /* reserved */
553 t->channelCount = read_int16(f);
559 t->sampleRate = read_int16(f);
563 atom_read_header(f, &atom_type, &header_size);
567 static int32_t read_stsd(struct mp4 *f)
569 int32_t i, entry_count;
570 uint8_t header_size = 0;
574 if (f->total_tracks == 0)
576 t = f->track[f->total_tracks - 1];
578 read_char(f); /* version */
579 read_int24(f); /* flags */
581 entry_count = read_int32(f);
584 for (i = 0; i < entry_count && !f->read_error; i++) {
585 uint64_t skip = get_position(f);
587 uint8_t atom_type = 0;
588 size = atom_read_header(f, &atom_type, &header_size);
590 t->is_audio = atom_type == ATOM_MP4A;
593 set_position(f, skip);
599 static int32_t tag_add_field(struct mp4_metadata *tags, const char *item,
600 const char *value, int32_t len)
602 tags->tags = para_realloc(tags->tags,
603 (tags->count + 1) * sizeof(struct mp4_tag));
604 tags->tags[tags->count].item = para_strdup(item);
605 tags->tags[tags->count].len = len;
607 tags->tags[tags->count].value = para_malloc(len + 1);
608 memcpy(tags->tags[tags->count].value, value, len);
609 tags->tags[tags->count].value[len] = 0;
611 tags->tags[tags->count].value = para_strdup(value);
617 static const char *ID3v1GenreList[] = {
618 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
619 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
620 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
621 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
622 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
623 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
624 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
625 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
626 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
627 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
628 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
629 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
630 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
631 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
632 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
633 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
634 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
635 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
636 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
637 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
638 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
639 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
640 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
641 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
642 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
643 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
644 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
645 "Anime", "JPop", "SynthPop",
648 static char *read_string(struct mp4 *f, uint32_t length)
650 char *str = para_malloc(length + 1);
651 if ((uint32_t)read_data(f, str, length) != length) {
659 static const char *get_metadata_name(uint8_t atom_type)
662 case ATOM_TITLE: return "title";
663 case ATOM_ARTIST: return "artist";
664 case ATOM_ALBUM: return "album";
665 case ATOM_DATE: return "date";
666 case ATOM_COMMENT: return "comment";
667 default: return "unknown";
671 static void parse_tag(struct mp4 *f, uint8_t parent, int32_t size)
673 uint64_t subsize, sumsize;
680 sumsize < size && !f->read_error; /* CVE-2017-9222 */
681 set_position(f, destpos), sumsize += subsize
684 uint8_t header_size = 0;
685 subsize = atom_read_header(f, &atom_type, &header_size);
686 destpos = get_position(f) + subsize - header_size;
687 if (atom_type != ATOM_DATA)
689 read_char(f); /* version */
690 read_int24(f); /* flags */
691 read_int32(f); /* reserved */
693 data = read_string(f, subsize - (header_size + 8));
694 len = subsize - (header_size + 8);
698 tag_add_field(&f->tags, get_metadata_name(parent), data, len);
702 static int32_t read_mdhd(struct mp4 *f)
708 if (f->total_tracks == 0)
710 t = f->track[f->total_tracks - 1];
712 version = read_int32(f);
714 read_int64(f); //creation-time
715 read_int64(f); //modification-time
716 t->timeScale = read_int32(f); //timescale
717 t->duration = read_int64(f); //duration
718 } else { //version == 0
721 read_int32(f); //creation-time
722 read_int32(f); //modification-time
723 t->timeScale = read_int32(f); //timescale
724 temp = read_int32(f);
725 t->duration = (temp == (uint32_t) (-1))?
726 (uint64_t) (-1) : (uint64_t) (temp);
733 static int32_t parse_metadata(struct mp4 *f, int32_t size)
735 uint64_t sumsize = 0;
737 while (sumsize < size) {
739 uint64_t subsize, destpos;
740 uint8_t header_size = 0;
741 subsize = atom_read_header(f, &atom_type, &header_size);
744 destpos = get_position(f) + subsize - header_size;
751 parse_tag(f, atom_type, subsize - header_size);
753 set_position(f, destpos);
760 static int32_t read_meta(struct mp4 *f, uint64_t size)
762 uint64_t subsize, sumsize = 0;
764 uint8_t header_size = 0;
766 read_char(f); /* version */
767 read_int24(f); /* flags */
769 while (sumsize < (size - (header_size + 4))) {
770 subsize = atom_read_header(f, &atom_type, &header_size);
771 if (subsize <= header_size + 4)
773 if (atom_type == ATOM_ILST) {
774 parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
776 set_position(f, get_position(f) + subsize - header_size);
784 static int32_t atom_read(struct mp4 *f, int32_t size, uint8_t atom_type)
786 uint64_t dest_position = get_position(f) + size - 8;
787 if (atom_type == ATOM_STSZ) {
788 /* sample size box */
790 } else if (atom_type == ATOM_STTS) {
791 /* time to sample box */
793 } else if (atom_type == ATOM_STSC) {
794 /* sample to chunk box */
796 } else if (atom_type == ATOM_STCO) {
797 /* chunk offset box */
799 } else if (atom_type == ATOM_STSD) {
800 /* sample description box */
802 } else if (atom_type == ATOM_MDHD) {
805 } else if (atom_type == ATOM_META) {
806 /* iTunes Metadata box */
810 set_position(f, dest_position);
814 /* parse atoms that are sub atoms of other atoms */
815 static int32_t parse_sub_atoms(struct mp4 *f, uint64_t total_size, int meta_only)
818 uint8_t atom_type = 0;
819 uint64_t counted_size = 0;
820 uint8_t header_size = 0;
822 while (counted_size < total_size) {
823 size = atom_read_header(f, &atom_type, &header_size);
824 counted_size += size;
826 /* check for end of file */
830 /* we're starting to read a new track, update index,
831 * so that all data and tables get written in the right place
833 if (atom_type == ATOM_TRAK)
836 if (meta_only && !need_parse_when_meta_only(atom_type)) {
837 set_position(f, get_position(f) + size - header_size);
838 } else if (atom_type < SUBATOMIC) {
839 parse_sub_atoms(f, size - header_size, meta_only);
841 atom_read(f, (uint32_t) size, atom_type);
848 /* parse root atoms */
849 static int32_t parse_atoms(struct mp4 *f, int meta_only)
852 uint8_t atom_type = 0;
853 uint8_t header_size = 0;
859 atom_read_header(f, &atom_type, &header_size)) != 0) {
860 f->file_size += size;
861 f->last_atom = atom_type;
863 if (atom_type == ATOM_MOOV && size > header_size) {
864 f->moov_offset = get_position(f) - header_size;
869 if (meta_only && !need_parse_when_meta_only(atom_type)) {
870 set_position(f, get_position(f) + size - header_size);
871 } else if (atom_type < SUBATOMIC) {
872 parse_sub_atoms(f, size - header_size, meta_only);
875 set_position(f, get_position(f) + size - header_size);
882 struct mp4 *mp4_open_read(const struct mp4_callback *cb)
884 struct mp4 *f = para_calloc(sizeof(struct mp4));
895 static int32_t tag_delete(struct mp4_metadata *tags)
899 for (i = 0; i < tags->count; i++) {
900 free(tags->tags[i].item);
901 free(tags->tags[i].value);
910 void mp4_close(struct mp4 *f)
914 for (i = 0; i < f->total_tracks; i++) {
916 free(f->track[i]->stsz_table);
917 free(f->track[i]->stts_sample_count);
918 free(f->track[i]->stts_sample_delta);
919 free(f->track[i]->stsc_first_chunk);
920 free(f->track[i]->stsc_samples_per_chunk);
921 free(f->track[i]->stsc_sample_desc_index);
922 free(f->track[i]->stco_chunk_offset);
927 tag_delete(&(f->tags));
931 static int32_t chunk_of_sample(const struct mp4 *f, int32_t track,
932 int32_t sample, int32_t *chunk_sample, int32_t *chunk)
934 int32_t total_entries = 0;
936 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
940 if (f->track[track] == NULL) {
944 total_entries = f->track[track]->stsc_entry_count;
951 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
952 *chunk = chunk2 - chunk1;
953 range_samples = *chunk * chunk1samples;
955 if (sample < total + range_samples)
958 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
961 if (chunk2entry < total_entries) {
963 total += range_samples;
965 } while (chunk2entry < total_entries);
968 *chunk = (sample - total) / chunk1samples + chunk1;
972 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
977 static int32_t chunk_to_offset(const struct mp4 *f, int32_t track,
980 const struct mp4_track *p_track = f->track[track];
982 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
983 return p_track->stco_chunk_offset[p_track->stco_entry_count -
985 } else if (p_track->stco_entry_count) {
986 return p_track->stco_chunk_offset[chunk - 1];
994 static int32_t sample_range_size(const struct mp4 *f, int32_t track,
995 int32_t chunk_sample, int32_t sample)
998 const struct mp4_track *p_track = f->track[track];
1000 if (p_track->stsz_sample_size) {
1001 return (sample - chunk_sample) * p_track->stsz_sample_size;
1003 if (sample >= p_track->stsz_sample_count)
1006 for (i = chunk_sample, total = 0; i < sample; i++) {
1007 total += p_track->stsz_table[i];
1014 static int32_t sample_to_offset(const struct mp4 *f, int32_t track,
1017 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1019 chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1021 chunk_offset1 = chunk_to_offset(f, track, chunk);
1022 chunk_offset2 = chunk_offset1 + sample_range_size(f,
1023 track, chunk_sample, sample);
1024 return chunk_offset2;
1028 * Return the number of milliseconds of the given track.
1030 * \param f As returned by \ref mp4_open_read(), must not be NULL.
1031 * \param track Between zero and the value returned by \ref mp4_total_tracks().
1033 * The function returns zero if the audio file is of zero length or contains a
1034 * corrupt track header.
1036 uint64_t mp4_get_duration(const struct mp4 *f, int32_t track)
1038 const struct mp4_track *t = f->track[track];
1040 if (t->timeScale == 0)
1042 return t->duration * 1000 / t->timeScale;
1046 * Check whether the given track number corresponds to an audio track.
1048 * \param f See \ref mp4_get_duration().
1049 * \param track See \ref mp4_get_duration().
1051 * Besides audio tracks, an mp4 file may contain video and system tracks. For
1052 * those the function returns false.
1054 bool mp4_is_audio_track(const struct mp4 *f, int32_t track)
1056 return f->track[track]->is_audio;
1059 void mp4_set_sample_position(struct mp4 *f, int32_t track, int32_t sample)
1061 int32_t offset = sample_to_offset(f, track, sample);
1062 set_position(f, offset);
1065 int32_t mp4_get_sample_size(const struct mp4 *f, int track, int sample)
1067 const struct mp4_track *t = f->track[track];
1069 if (t->stsz_sample_size != 0)
1070 return t->stsz_sample_size;
1071 return t->stsz_table[sample];
1074 uint32_t mp4_get_sample_rate(const struct mp4 *f, int32_t track)
1076 return f->track[track]->sampleRate;
1079 uint32_t mp4_get_channel_count(const struct mp4 *f, int32_t track)
1081 return f->track[track]->channelCount;
1084 int32_t mp4_num_samples(const struct mp4 *f, int32_t track)
1089 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1090 total += f->track[track]->stts_sample_count[i];
1095 struct mp4 *mp4_open_meta(const struct mp4_callback *cb)
1097 struct mp4 *f = para_calloc(sizeof(struct mp4));
1109 * Return the metadata of an mp4 file.
1111 * \param f As returned by either \ref mp4_open_read() or \ref mp4_open_meta().
1113 * The caller is allowed to add, delete or modify the entries of the returned
1114 * structure in order to pass the modified version to \ref mp4_meta_update().
1116 struct mp4_metadata *mp4_get_meta(struct mp4 *f)
1121 static uint32_t find_atom(struct mp4 *f, uint64_t base, uint32_t size,
1124 uint32_t remaining = size;
1125 uint64_t atom_offset = base;
1130 set_position(f, atom_offset);
1134 atom_size = read_int32(f);
1135 if (atom_size > remaining || atom_size < 8)
1137 read_data(f, atom_name, 4);
1139 if (!memcmp(atom_name, name, 4)) {
1140 set_position(f, atom_offset);
1144 remaining -= atom_size;
1145 atom_offset += atom_size;
1150 static uint32_t find_atom_v2(struct mp4 *f, uint64_t base, uint32_t size,
1151 const char *name, uint32_t extraheaders, const char *name_inside)
1153 uint64_t first_base = (uint64_t) (-1);
1154 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1156 uint64_t mybase = get_position(f);
1157 uint32_t mysize = read_int32(f);
1159 if (first_base == (uint64_t) (-1))
1160 first_base = mybase;
1162 if (mysize < 8 + extraheaders)
1165 if (find_atom (f, mybase + (8 + extraheaders),
1166 mysize - (8 + extraheaders), name_inside)) {
1167 set_position(f, mybase);
1171 if (size <= mysize) {
1178 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1180 set_position(f, first_base);
1193 static struct membuffer *membuffer_create(void)
1195 const unsigned initial_size = 256;
1197 struct membuffer *buf = para_malloc(sizeof(*buf));
1198 buf->data = para_malloc(initial_size);
1200 buf->allocated = initial_size;
1201 buf->error = buf->data == 0 ? 1 : 0;
1206 static unsigned membuffer_write(struct membuffer *buf, const void *ptr, unsigned bytes)
1208 unsigned dest_size = buf->written + bytes;
1212 if (dest_size > buf->allocated) {
1214 buf->allocated <<= 1;
1215 } while (dest_size > buf->allocated);
1216 buf->data = para_realloc(buf->data, buf->allocated);
1220 memcpy((char *) buf->data + buf->written, ptr, bytes);
1221 buf->written += bytes;
1225 static unsigned membuffer_write_atom_name(struct membuffer *buf, const char *data)
1227 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1230 static unsigned membuffer_write_int16(struct membuffer *buf, uint16_t data)
1234 write_u16_be(temp, data);
1235 return membuffer_write(buf, temp, 2);
1238 static unsigned membuffer_write_int32(struct membuffer *buf, uint32_t data)
1241 write_u32_be(temp, data);
1242 return membuffer_write(buf, temp, 4);
1245 static void membuffer_write_track_tag(struct membuffer *buf, const char *name,
1246 uint32_t index, uint32_t total)
1248 membuffer_write_int32(buf,
1249 8 /*atom header */ + 8 /*data atom header */ +
1250 8 /*flags + reserved */ + 8 /*actual data */ );
1251 membuffer_write_atom_name(buf, name);
1252 membuffer_write_int32(buf,
1253 8 /*data atom header */ +
1254 8 /*flags + reserved */ + 8 /*actual data */ );
1255 membuffer_write_atom_name(buf, "data");
1256 membuffer_write_int32(buf, 0); //flags
1257 membuffer_write_int32(buf, 0); //reserved
1258 membuffer_write_int16(buf, 0);
1259 membuffer_write_int16(buf, (uint16_t) index); //track number
1260 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1261 membuffer_write_int16(buf, 0);
1264 static void membuffer_write_int16_tag(struct membuffer *buf, const char *name,
1267 membuffer_write_int32(buf,
1268 8 /*atom header */ + 8 /*data atom header */ +
1269 8 /*flags + reserved */ + 2 /*actual data */ );
1270 membuffer_write_atom_name(buf, name);
1271 membuffer_write_int32(buf,
1272 8 /*data atom header */ +
1273 8 /*flags + reserved */ + 2 /*actual data */ );
1274 membuffer_write_atom_name(buf, "data");
1275 membuffer_write_int32(buf, 0); //flags
1276 membuffer_write_int32(buf, 0); //reserved
1277 membuffer_write_int16(buf, value); //value
1280 static uint32_t myatoi(const char *param)
1282 return param ? atoi(param) : 0;
1285 static uint32_t meta_genre_to_index(const char *genrestr)
1288 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1289 if (!strcasecmp(genrestr, ID3v1GenreList[n]))
1295 struct stdmeta_entry {
1300 struct stdmeta_entry stdmetas[] = {
1301 {"\xA9" "nam", "title"},
1302 {"\xA9" "ART", "artist"},
1303 {"\xA9" "wrt", "writer"},
1304 {"\xA9" "alb", "album"},
1305 {"\xA9" "day", "date"},
1306 {"\xA9" "too", "tool"},
1307 {"\xA9" "cmt", "comment"},
1308 {"cpil", "compilation"},
1310 {"aART", "album_artist"},
1313 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1316 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1317 if (!strcasecmp(name, stdmetas[n].name))
1318 return stdmetas[n].atom;
1323 static void membuffer_write_std_tag(struct membuffer *buf, const char *name,
1328 /* special check for compilation flag */
1329 if (strcmp(name, "cpil") == 0) {
1333 membuffer_write_int32(buf,
1334 8 /*atom header */ + 8 /*data atom header */ +
1335 8 /*flags + reserved */ + strlen(value));
1336 membuffer_write_atom_name(buf, name);
1337 membuffer_write_int32(buf,
1338 8 /*data atom header */ +
1339 8 /*flags + reserved */ + strlen(value));
1340 membuffer_write_atom_name(buf, "data");
1341 membuffer_write_int32(buf, flags); //flags
1342 membuffer_write_int32(buf, 0); //reserved
1343 membuffer_write(buf, value, strlen(value));
1346 static void membuffer_write_custom_tag(struct membuffer *buf, const char *name,
1349 membuffer_write_int32(buf,
1350 8 /*atom header */ +
1351 0x1C /*weirdo itunes atom */ +
1352 12 /*name atom header */ + strlen(name) +
1353 16 /*data atom header + flags */ + strlen(value));
1354 membuffer_write_atom_name(buf, "----");
1355 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1356 membuffer_write_atom_name(buf, "mean");
1357 membuffer_write_int32(buf, 0);
1358 membuffer_write(buf, "com.apple.iTunes", 16);
1359 membuffer_write_int32(buf, 12 + strlen(name));
1360 membuffer_write_atom_name(buf, "name");
1361 membuffer_write_int32(buf, 0);
1362 membuffer_write(buf, name, strlen(name));
1363 membuffer_write_int32(buf,
1364 8 /*data atom header */ +
1365 8 /*flags + reserved */ + strlen(value));
1366 membuffer_write_atom_name(buf, "data");
1367 membuffer_write_int32(buf, 1); //flags
1368 membuffer_write_int32(buf, 0); //reserved
1369 membuffer_write(buf, value, strlen(value));
1372 static unsigned membuffer_error(const struct membuffer *buf)
1377 static void membuffer_free(struct membuffer *buf)
1383 static unsigned membuffer_get_size(const struct membuffer *buf)
1385 return buf->written;
1388 static void *membuffer_detach(struct membuffer *buf)
1394 ret = para_realloc(buf->data, buf->written);
1400 static uint32_t create_ilst(const struct mp4_metadata *data, void **out_buffer,
1401 uint32_t * out_size)
1403 struct membuffer *buf = membuffer_create();
1405 char *mask = para_calloc(data->count);
1406 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1407 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1408 const char *genre_ptr = 0, *tempo_ptr = 0;
1410 for (metaptr = 0; metaptr < data->count; metaptr++) {
1411 struct mp4_tag *tag = &data->tags[metaptr];
1412 if (!strcasecmp(tag->item, "tracknumber")
1413 || !strcasecmp(tag->item, "track")) {
1414 if (tracknumber_ptr == 0)
1415 tracknumber_ptr = tag->value;
1417 } else if (!strcasecmp(tag->item, "totaltracks")) {
1418 if (totaltracks_ptr == 0)
1419 totaltracks_ptr = tag->value;
1421 } else if (!strcasecmp(tag->item, "discnumber")
1422 || !strcasecmp(tag->item, "disc")) {
1423 if (discnumber_ptr == 0)
1424 discnumber_ptr = tag->value;
1426 } else if (!strcasecmp(tag->item, "totaldiscs")) {
1427 if (totaldiscs_ptr == 0)
1428 totaldiscs_ptr = tag->value;
1430 } else if (!strcasecmp(tag->item, "genre")) {
1432 genre_ptr = tag->value;
1434 } else if (!strcasecmp(tag->item, "tempo")) {
1436 tempo_ptr = tag->value;
1441 if (tracknumber_ptr)
1442 membuffer_write_track_tag(buf, "trkn", myatoi(tracknumber_ptr),
1443 myatoi(totaltracks_ptr));
1445 membuffer_write_track_tag(buf, "disk", myatoi(discnumber_ptr),
1446 myatoi(totaldiscs_ptr));
1448 membuffer_write_int16_tag(buf, "tmpo", myatoi(tempo_ptr));
1451 uint32_t index = meta_genre_to_index(genre_ptr);
1453 membuffer_write_std_tag(buf, "©gen", genre_ptr);
1455 membuffer_write_int16_tag(buf, "gnre", index);
1457 for (metaptr = 0; metaptr < data->count; metaptr++) {
1458 struct mp4_tag *tag;
1459 const char *std_meta_atom;
1463 tag = &data->tags[metaptr];
1464 std_meta_atom = find_standard_meta(tag->item);
1466 membuffer_write_std_tag(buf, std_meta_atom, tag->value);
1468 membuffer_write_custom_tag(buf, tag->item, tag->value);
1472 if (membuffer_error(buf)) {
1473 membuffer_free(buf);
1477 *out_size = membuffer_get_size(buf);
1478 *out_buffer = membuffer_detach(buf);
1479 membuffer_free(buf);
1484 static void membuffer_write_atom(struct membuffer *buf, const char *name, unsigned size,
1487 membuffer_write_int32(buf, size + 8);
1488 membuffer_write_atom_name(buf, name);
1489 membuffer_write(buf, data, size);
1492 static void *membuffer_get_ptr(const struct membuffer *buf)
1497 static void membuffer_set_error(struct membuffer *buf)
1502 static unsigned membuffer_transfer_from_file(struct membuffer *buf, struct mp4 *src,
1508 oldsize = membuffer_get_size(buf);
1509 if (membuffer_write(buf, 0, bytes) != bytes)
1512 bufptr = membuffer_get_ptr(buf);
1516 if ((unsigned)read_data(src, (char *) bufptr + oldsize, bytes) !=
1518 membuffer_set_error(buf);
1525 static uint32_t create_meta(const struct mp4_metadata *data, void **out_buffer,
1526 uint32_t * out_size)
1528 struct membuffer *buf;
1532 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1535 buf = membuffer_create();
1537 membuffer_write_int32(buf, 0);
1538 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1541 *out_size = membuffer_get_size(buf);
1542 *out_buffer = membuffer_detach(buf);
1543 membuffer_free(buf);
1547 static uint32_t create_udta(const struct mp4_metadata *data, void **out_buffer,
1548 uint32_t * out_size)
1550 struct membuffer *buf;
1554 if (!create_meta(data, &meta_buffer, &meta_size))
1557 buf = membuffer_create();
1559 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1563 *out_size = membuffer_get_size(buf);
1564 *out_buffer = membuffer_detach(buf);
1565 membuffer_free(buf);
1569 static uint32_t fix_byte_order_32(uint32_t src)
1571 return read_u32_be(&src);
1574 static uint32_t modify_moov(struct mp4 *f, const struct mp4_metadata *data,
1575 void **out_buffer, uint32_t * out_size)
1577 uint64_t total_base = f->moov_offset + 8;
1578 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1580 uint64_t udta_offset, meta_offset, ilst_offset;
1581 uint32_t udta_size, meta_size, ilst_size;
1583 uint32_t new_ilst_size;
1584 void *new_ilst_buffer;
1589 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1590 struct membuffer *buf;
1591 void *new_udta_buffer;
1592 uint32_t new_udta_size;
1593 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1596 buf = membuffer_create();
1597 set_position(f, total_base);
1598 membuffer_transfer_from_file(buf, f, total_size);
1600 membuffer_write_atom(buf, "udta", new_udta_size,
1603 free(new_udta_buffer);
1605 *out_size = membuffer_get_size(buf);
1606 *out_buffer = membuffer_detach(buf);
1607 membuffer_free(buf);
1610 udta_offset = get_position(f);
1611 udta_size = read_int32(f);
1612 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
1613 struct membuffer *buf;
1614 void *new_meta_buffer;
1615 uint32_t new_meta_size;
1617 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
1620 buf = membuffer_create();
1621 set_position(f, total_base);
1622 membuffer_transfer_from_file(buf, f,
1623 (uint32_t)(udta_offset - total_base));
1625 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
1626 membuffer_write_atom_name(buf, "udta");
1627 membuffer_transfer_from_file(buf, f, udta_size);
1629 membuffer_write_atom(buf, "meta", new_meta_size,
1631 free(new_meta_buffer);
1633 *out_size = membuffer_get_size(buf);
1634 *out_buffer = membuffer_detach(buf);
1635 membuffer_free(buf);
1638 meta_offset = get_position(f);
1639 meta_size = read_int32(f);
1640 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
1641 return 0; //shouldn't happen, find_atom_v2 above takes care of it
1642 ilst_offset = get_position(f);
1643 ilst_size = read_int32(f);
1645 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
1648 size_delta = new_ilst_size - (ilst_size - 8);
1650 *out_size = total_size + size_delta;
1651 *out_buffer = para_malloc(*out_size);
1652 p_out = (uint8_t *) * out_buffer;
1654 set_position(f, total_base);
1656 (uint32_t) (udta_offset - total_base));
1657 p_out += (uint32_t) (udta_offset - total_base);
1658 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1660 read_data(f, p_out, 4);
1663 (uint32_t) (meta_offset - udta_offset - 8));
1664 p_out += (uint32_t) (meta_offset - udta_offset - 8);
1665 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1667 read_data(f, p_out, 4);
1670 (uint32_t) (ilst_offset - meta_offset - 8));
1671 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
1672 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1674 read_data(f, p_out, 4);
1677 memcpy(p_out, new_ilst_buffer, new_ilst_size);
1678 p_out += new_ilst_size;
1680 set_position(f, ilst_offset + ilst_size);
1681 read_data(f, p_out, (uint32_t) (total_size
1682 - (ilst_offset - total_base) - ilst_size));
1684 free(new_ilst_buffer);
1689 static int32_t write_data(struct mp4 *f, void *data, uint32_t size)
1693 result = f->cb->write(f->cb->user_data, data, size);
1695 f->current_position += size;
1700 static int32_t write_int32(struct mp4 *f, uint32_t data)
1703 write_u32_be(temp, data);
1704 return write_data(f, temp, sizeof(temp));
1707 int32_t mp4_meta_update(struct mp4 *f, struct mp4_metadata *meta)
1709 void *new_moov_data;
1710 uint32_t new_moov_size;
1713 if (!modify_moov(f, meta, &new_moov_data, &new_moov_size)) {
1717 /* copy moov atom to end of the file */
1718 if (f->last_atom != ATOM_MOOV) {
1719 char *free_data = "free";
1721 /* rename old moov to free */
1722 set_position(f, f->moov_offset + 4);
1723 write_data(f, free_data, 4);
1725 set_position(f, f->file_size);
1726 write_int32(f, new_moov_size + 8);
1727 write_data(f, "moov", 4);
1728 write_data(f, new_moov_data, new_moov_size);
1730 set_position(f, f->moov_offset);
1731 write_int32(f, new_moov_size + 8);
1732 write_data(f, "moov", 4);
1733 write_data(f, new_moov_data, new_moov_size);
1735 free(new_moov_data);
1736 f->cb->truncate(f->cb->user_data);
1740 static char *meta_find_by_name(const struct mp4 *f, const char *item)
1744 for (i = 0; i < f->tags.count; i++)
1745 if (!strcasecmp(f->tags.tags[i].item, item))
1746 return para_strdup(f->tags.tags[i].value);
1751 * Return the value of the artist meta tag of an mp4 file.
1753 * \param f Must not be NULL.
1755 * \return If the file does not contain this metadata tag, the function returns
1756 * NULL. Otherwise, a copy of the tag value is returned. The caller should free
1757 * this memory when it is no longer needed.
1759 char *mp4_meta_get_artist(const struct mp4 *f)
1761 return meta_find_by_name(f, "artist");
1765 * Return the value of the title meta tag of an mp4 file.
1767 * \param f See \ref mp4_meta_get_artist().
1768 * \return See \ref mp4_meta_get_artist().
1770 char *mp4_meta_get_title(const struct mp4 *f)
1772 return meta_find_by_name(f, "title");
1776 * Return the value of the date meta tag of an mp4 file.
1778 * \param f See \ref mp4_meta_get_artist().
1779 * \return See \ref mp4_meta_get_artist().
1781 char *mp4_meta_get_date(const struct mp4 *f)
1783 return meta_find_by_name(f, "date");
1787 * Return the value of the album meta tag of an mp4 file.
1789 * \param f See \ref mp4_meta_get_artist().
1790 * \return See \ref mp4_meta_get_artist().
1792 char *mp4_meta_get_album(const struct mp4 *f)
1794 return meta_find_by_name(f, "album");
1798 * Return the value of the comment meta tag of an mp4 file.
1800 * \param f See \ref mp4_meta_get_artist().
1801 * \return See \ref mp4_meta_get_artist().
1803 char *mp4_meta_get_comment(const struct mp4 *f)
1805 return meta_find_by_name(f, "comment");