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 if (!item || (item && !*item) || !value)
604 tags->tags = para_realloc(tags->tags,
605 (tags->count + 1) * sizeof(struct mp4_tag));
606 tags->tags[tags->count].item = para_strdup(item);
607 tags->tags[tags->count].len = len;
609 tags->tags[tags->count].value = para_malloc(len + 1);
610 memcpy(tags->tags[tags->count].value, value, len);
611 tags->tags[tags->count].value[len] = 0;
613 tags->tags[tags->count].value = para_strdup(value);
619 static const char *ID3v1GenreList[] = {
620 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
621 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
622 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
623 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
624 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
625 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
626 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
627 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
628 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
629 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
630 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
631 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
632 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
633 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
634 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
635 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
636 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
637 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
638 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
639 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
640 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
641 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
642 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
643 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
644 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
645 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
646 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
647 "Anime", "JPop", "SynthPop",
650 static char *read_string(struct mp4 *f, uint32_t length)
652 char *str = para_malloc(length + 1);
653 if ((uint32_t)read_data(f, str, length) != length) {
661 static const char *get_metadata_name(uint8_t atom_type)
664 case ATOM_TITLE: return "title";
665 case ATOM_ARTIST: return "artist";
666 case ATOM_ALBUM: return "album";
667 case ATOM_DATE: return "date";
668 case ATOM_COMMENT: return "comment";
669 default: return "unknown";
673 static void parse_tag(struct mp4 *f, uint8_t parent, int32_t size)
675 uint64_t subsize, sumsize;
683 sumsize < size && !f->read_error; /* CVE-2017-9222 */
684 set_position(f, destpos), sumsize += subsize
687 uint8_t header_size = 0;
688 subsize = atom_read_header(f, &atom_type, &header_size);
689 destpos = get_position(f) + subsize - header_size;
690 if (atom_type == ATOM_NAME) {
691 read_char(f); /* version */
692 read_int24(f); /* flags */
694 name = read_string(f, subsize - (header_size + 4));
697 if (atom_type != ATOM_DATA)
699 read_char(f); /* version */
700 read_int24(f); /* flags */
701 read_int32(f); /* reserved */
703 data = read_string(f, subsize - (header_size + 8));
704 len = subsize - (header_size + 8);
708 name = para_strdup(get_metadata_name(parent));
709 tag_add_field(&(f->tags), name, data, len);
715 static int32_t read_mdhd(struct mp4 *f)
721 if (f->total_tracks == 0)
723 t = f->track[f->total_tracks - 1];
725 version = read_int32(f);
727 read_int64(f); //creation-time
728 read_int64(f); //modification-time
729 t->timeScale = read_int32(f); //timescale
730 t->duration = read_int64(f); //duration
731 } else { //version == 0
734 read_int32(f); //creation-time
735 read_int32(f); //modification-time
736 t->timeScale = read_int32(f); //timescale
737 temp = read_int32(f);
738 t->duration = (temp == (uint32_t) (-1))?
739 (uint64_t) (-1) : (uint64_t) (temp);
746 static int32_t parse_metadata(struct mp4 *f, int32_t size)
748 uint64_t sumsize = 0;
750 while (sumsize < size) {
752 uint64_t subsize, destpos;
753 uint8_t header_size = 0;
754 subsize = atom_read_header(f, &atom_type, &header_size);
757 destpos = get_position(f) + subsize - header_size;
764 parse_tag(f, atom_type, subsize - header_size);
766 set_position(f, destpos);
773 static int32_t read_meta(struct mp4 *f, uint64_t size)
775 uint64_t subsize, sumsize = 0;
777 uint8_t header_size = 0;
779 read_char(f); /* version */
780 read_int24(f); /* flags */
782 while (sumsize < (size - (header_size + 4))) {
783 subsize = atom_read_header(f, &atom_type, &header_size);
784 if (subsize <= header_size + 4)
786 if (atom_type == ATOM_ILST) {
787 parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
789 set_position(f, get_position(f) + subsize - header_size);
797 static int32_t atom_read(struct mp4 *f, int32_t size, uint8_t atom_type)
799 uint64_t dest_position = get_position(f) + size - 8;
800 if (atom_type == ATOM_STSZ) {
801 /* sample size box */
803 } else if (atom_type == ATOM_STTS) {
804 /* time to sample box */
806 } else if (atom_type == ATOM_STSC) {
807 /* sample to chunk box */
809 } else if (atom_type == ATOM_STCO) {
810 /* chunk offset box */
812 } else if (atom_type == ATOM_STSD) {
813 /* sample description box */
815 } else if (atom_type == ATOM_MDHD) {
818 } else if (atom_type == ATOM_META) {
819 /* iTunes Metadata box */
823 set_position(f, dest_position);
827 /* parse atoms that are sub atoms of other atoms */
828 static int32_t parse_sub_atoms(struct mp4 *f, uint64_t total_size, int meta_only)
831 uint8_t atom_type = 0;
832 uint64_t counted_size = 0;
833 uint8_t header_size = 0;
835 while (counted_size < total_size) {
836 size = atom_read_header(f, &atom_type, &header_size);
837 counted_size += size;
839 /* check for end of file */
843 /* we're starting to read a new track, update index,
844 * so that all data and tables get written in the right place
846 if (atom_type == ATOM_TRAK)
849 if (meta_only && !need_parse_when_meta_only(atom_type)) {
850 set_position(f, get_position(f) + size - header_size);
851 } else if (atom_type < SUBATOMIC) {
852 parse_sub_atoms(f, size - header_size, meta_only);
854 atom_read(f, (uint32_t) size, atom_type);
861 /* parse root atoms */
862 static int32_t parse_atoms(struct mp4 *f, int meta_only)
865 uint8_t atom_type = 0;
866 uint8_t header_size = 0;
872 atom_read_header(f, &atom_type, &header_size)) != 0) {
873 f->file_size += size;
874 f->last_atom = atom_type;
876 if (atom_type == ATOM_MOOV && size > header_size) {
877 f->moov_offset = get_position(f) - header_size;
882 if (meta_only && !need_parse_when_meta_only(atom_type)) {
883 set_position(f, get_position(f) + size - header_size);
884 } else if (atom_type < SUBATOMIC) {
885 parse_sub_atoms(f, size - header_size, meta_only);
888 set_position(f, get_position(f) + size - header_size);
895 struct mp4 *mp4_open_read(const struct mp4_callback *cb)
897 struct mp4 *f = para_calloc(sizeof(struct mp4));
908 static int32_t tag_delete(struct mp4_metadata *tags)
912 for (i = 0; i < tags->count; i++) {
913 free(tags->tags[i].item);
914 free(tags->tags[i].value);
923 void mp4_close(struct mp4 *f)
927 for (i = 0; i < f->total_tracks; i++) {
929 free(f->track[i]->stsz_table);
930 free(f->track[i]->stts_sample_count);
931 free(f->track[i]->stts_sample_delta);
932 free(f->track[i]->stsc_first_chunk);
933 free(f->track[i]->stsc_samples_per_chunk);
934 free(f->track[i]->stsc_sample_desc_index);
935 free(f->track[i]->stco_chunk_offset);
940 tag_delete(&(f->tags));
944 static int32_t chunk_of_sample(const struct mp4 *f, int32_t track,
945 int32_t sample, int32_t *chunk_sample, int32_t *chunk)
947 int32_t total_entries = 0;
949 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
953 if (f->track[track] == NULL) {
957 total_entries = f->track[track]->stsc_entry_count;
964 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
965 *chunk = chunk2 - chunk1;
966 range_samples = *chunk * chunk1samples;
968 if (sample < total + range_samples)
971 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
974 if (chunk2entry < total_entries) {
976 total += range_samples;
978 } while (chunk2entry < total_entries);
981 *chunk = (sample - total) / chunk1samples + chunk1;
985 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
990 static int32_t chunk_to_offset(const struct mp4 *f, int32_t track,
993 const struct mp4_track *p_track = f->track[track];
995 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
996 return p_track->stco_chunk_offset[p_track->stco_entry_count -
998 } else if (p_track->stco_entry_count) {
999 return p_track->stco_chunk_offset[chunk - 1];
1007 static int32_t sample_range_size(const struct mp4 *f, int32_t track,
1008 int32_t chunk_sample, int32_t sample)
1011 const struct mp4_track *p_track = f->track[track];
1013 if (p_track->stsz_sample_size) {
1014 return (sample - chunk_sample) * p_track->stsz_sample_size;
1016 if (sample >= p_track->stsz_sample_count)
1019 for (i = chunk_sample, total = 0; i < sample; i++) {
1020 total += p_track->stsz_table[i];
1027 static int32_t sample_to_offset(const struct mp4 *f, int32_t track,
1030 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1032 chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1034 chunk_offset1 = chunk_to_offset(f, track, chunk);
1035 chunk_offset2 = chunk_offset1 + sample_range_size(f,
1036 track, chunk_sample, sample);
1037 return chunk_offset2;
1041 * Return the number of milliseconds of the given track.
1043 * \param f As returned by \ref mp4_open_read(), must not be NULL.
1044 * \param track Between zero and the value returned by \ref mp4_total_tracks().
1046 * The function returns zero if the audio file is of zero length or contains a
1047 * corrupt track header.
1049 uint64_t mp4_get_duration(const struct mp4 *f, int32_t track)
1051 const struct mp4_track *t = f->track[track];
1053 if (t->timeScale == 0)
1055 return t->duration * 1000 / t->timeScale;
1059 * Check whether the given track number corresponds to an audio track.
1061 * \param f See \ref mp4_get_duration().
1062 * \param track See \ref mp4_get_duration().
1064 * Besides audio tracks, an mp4 file may contain video and system tracks. For
1065 * those the function returns false.
1067 bool mp4_is_audio_track(const struct mp4 *f, int32_t track)
1069 return f->track[track]->is_audio;
1072 void mp4_set_sample_position(struct mp4 *f, int32_t track, int32_t sample)
1074 int32_t offset = sample_to_offset(f, track, sample);
1075 set_position(f, offset);
1078 int32_t mp4_get_sample_size(const struct mp4 *f, int track, int sample)
1080 const struct mp4_track *t = f->track[track];
1082 if (t->stsz_sample_size != 0)
1083 return t->stsz_sample_size;
1084 return t->stsz_table[sample];
1087 uint32_t mp4_get_sample_rate(const struct mp4 *f, int32_t track)
1089 return f->track[track]->sampleRate;
1092 uint32_t mp4_get_channel_count(const struct mp4 *f, int32_t track)
1094 return f->track[track]->channelCount;
1097 int32_t mp4_num_samples(const struct mp4 *f, int32_t track)
1102 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1103 total += f->track[track]->stts_sample_count[i];
1108 struct mp4 *mp4_open_meta(const struct mp4_callback *cb)
1110 struct mp4 *f = para_calloc(sizeof(struct mp4));
1121 int32_t mp4_meta_get_num_items(const struct mp4 *f)
1123 return f->tags.count;
1126 int32_t mp4_meta_get_by_index(const struct mp4 *f, uint32_t index,
1127 char **item, char **value)
1129 if (index >= f->tags.count) {
1134 *item = para_strdup(f->tags.tags[index].item);
1135 *value = para_strdup(f->tags.tags[index].value);
1140 static uint32_t find_atom(struct mp4 *f, uint64_t base, uint32_t size,
1143 uint32_t remaining = size;
1144 uint64_t atom_offset = base;
1149 set_position(f, atom_offset);
1153 atom_size = read_int32(f);
1154 if (atom_size > remaining || atom_size < 8)
1156 read_data(f, atom_name, 4);
1158 if (!memcmp(atom_name, name, 4)) {
1159 set_position(f, atom_offset);
1163 remaining -= atom_size;
1164 atom_offset += atom_size;
1169 static uint32_t find_atom_v2(struct mp4 *f, uint64_t base, uint32_t size,
1170 const char *name, uint32_t extraheaders, const char *name_inside)
1172 uint64_t first_base = (uint64_t) (-1);
1173 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1175 uint64_t mybase = get_position(f);
1176 uint32_t mysize = read_int32(f);
1178 if (first_base == (uint64_t) (-1))
1179 first_base = mybase;
1181 if (mysize < 8 + extraheaders)
1184 if (find_atom (f, mybase + (8 + extraheaders),
1185 mysize - (8 + extraheaders), name_inside)) {
1186 set_position(f, mybase);
1190 if (size <= mysize) {
1197 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1199 set_position(f, first_base);
1212 static struct membuffer *membuffer_create(void)
1214 const unsigned initial_size = 256;
1216 struct membuffer *buf = para_malloc(sizeof(*buf));
1217 buf->data = para_malloc(initial_size);
1219 buf->allocated = initial_size;
1220 buf->error = buf->data == 0 ? 1 : 0;
1225 static unsigned membuffer_write(struct membuffer *buf, const void *ptr, unsigned bytes)
1227 unsigned dest_size = buf->written + bytes;
1231 if (dest_size > buf->allocated) {
1233 buf->allocated <<= 1;
1234 } while (dest_size > buf->allocated);
1235 buf->data = para_realloc(buf->data, buf->allocated);
1239 memcpy((char *) buf->data + buf->written, ptr, bytes);
1240 buf->written += bytes;
1244 static unsigned membuffer_write_atom_name(struct membuffer *buf, const char *data)
1246 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1249 static unsigned membuffer_write_int16(struct membuffer *buf, uint16_t data)
1253 write_u16_be(temp, data);
1254 return membuffer_write(buf, temp, 2);
1257 static unsigned membuffer_write_int32(struct membuffer *buf, uint32_t data)
1260 write_u32_be(temp, data);
1261 return membuffer_write(buf, temp, 4);
1264 static void membuffer_write_track_tag(struct membuffer *buf, const char *name,
1265 uint32_t index, uint32_t total)
1267 membuffer_write_int32(buf,
1268 8 /*atom header */ + 8 /*data atom header */ +
1269 8 /*flags + reserved */ + 8 /*actual data */ );
1270 membuffer_write_atom_name(buf, name);
1271 membuffer_write_int32(buf,
1272 8 /*data atom header */ +
1273 8 /*flags + reserved */ + 8 /*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, 0);
1278 membuffer_write_int16(buf, (uint16_t) index); //track number
1279 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1280 membuffer_write_int16(buf, 0);
1283 static void membuffer_write_int16_tag(struct membuffer *buf, const char *name,
1286 membuffer_write_int32(buf,
1287 8 /*atom header */ + 8 /*data atom header */ +
1288 8 /*flags + reserved */ + 2 /*actual data */ );
1289 membuffer_write_atom_name(buf, name);
1290 membuffer_write_int32(buf,
1291 8 /*data atom header */ +
1292 8 /*flags + reserved */ + 2 /*actual data */ );
1293 membuffer_write_atom_name(buf, "data");
1294 membuffer_write_int32(buf, 0); //flags
1295 membuffer_write_int32(buf, 0); //reserved
1296 membuffer_write_int16(buf, value); //value
1299 static uint32_t myatoi(const char *param)
1301 return param ? atoi(param) : 0;
1304 static uint32_t meta_genre_to_index(const char *genrestr)
1307 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1308 if (!strcasecmp(genrestr, ID3v1GenreList[n]))
1314 struct stdmeta_entry {
1319 struct stdmeta_entry stdmetas[] = {
1320 {"\xA9" "nam", "title"},
1321 {"\xA9" "ART", "artist"},
1322 {"\xA9" "wrt", "writer"},
1323 {"\xA9" "alb", "album"},
1324 {"\xA9" "day", "date"},
1325 {"\xA9" "too", "tool"},
1326 {"\xA9" "cmt", "comment"},
1327 {"cpil", "compilation"},
1329 {"aART", "album_artist"},
1332 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1335 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1336 if (!strcasecmp(name, stdmetas[n].name))
1337 return stdmetas[n].atom;
1342 static void membuffer_write_std_tag(struct membuffer *buf, const char *name,
1347 /* special check for compilation flag */
1348 if (strcmp(name, "cpil") == 0) {
1352 membuffer_write_int32(buf,
1353 8 /*atom header */ + 8 /*data atom header */ +
1354 8 /*flags + reserved */ + strlen(value));
1355 membuffer_write_atom_name(buf, name);
1356 membuffer_write_int32(buf,
1357 8 /*data atom header */ +
1358 8 /*flags + reserved */ + strlen(value));
1359 membuffer_write_atom_name(buf, "data");
1360 membuffer_write_int32(buf, flags); //flags
1361 membuffer_write_int32(buf, 0); //reserved
1362 membuffer_write(buf, value, strlen(value));
1365 static void membuffer_write_custom_tag(struct membuffer *buf, const char *name,
1368 membuffer_write_int32(buf,
1369 8 /*atom header */ +
1370 0x1C /*weirdo itunes atom */ +
1371 12 /*name atom header */ + strlen(name) +
1372 16 /*data atom header + flags */ + strlen(value));
1373 membuffer_write_atom_name(buf, "----");
1374 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1375 membuffer_write_atom_name(buf, "mean");
1376 membuffer_write_int32(buf, 0);
1377 membuffer_write(buf, "com.apple.iTunes", 16);
1378 membuffer_write_int32(buf, 12 + strlen(name));
1379 membuffer_write_atom_name(buf, "name");
1380 membuffer_write_int32(buf, 0);
1381 membuffer_write(buf, name, strlen(name));
1382 membuffer_write_int32(buf,
1383 8 /*data atom header */ +
1384 8 /*flags + reserved */ + strlen(value));
1385 membuffer_write_atom_name(buf, "data");
1386 membuffer_write_int32(buf, 1); //flags
1387 membuffer_write_int32(buf, 0); //reserved
1388 membuffer_write(buf, value, strlen(value));
1391 static unsigned membuffer_error(const struct membuffer *buf)
1396 static void membuffer_free(struct membuffer *buf)
1402 static unsigned membuffer_get_size(const struct membuffer *buf)
1404 return buf->written;
1407 static void *membuffer_detach(struct membuffer *buf)
1413 ret = para_realloc(buf->data, buf->written);
1419 static uint32_t create_ilst(const struct mp4_metadata *data, void **out_buffer,
1420 uint32_t * out_size)
1422 struct membuffer *buf = membuffer_create();
1424 char *mask = para_calloc(data->count);
1425 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1426 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1427 const char *genre_ptr = 0, *tempo_ptr = 0;
1429 for (metaptr = 0; metaptr < data->count; metaptr++) {
1430 struct mp4_tag *tag = &data->tags[metaptr];
1431 if (!strcasecmp(tag->item, "tracknumber")
1432 || !strcasecmp(tag->item, "track")) {
1433 if (tracknumber_ptr == 0)
1434 tracknumber_ptr = tag->value;
1436 } else if (!strcasecmp(tag->item, "totaltracks")) {
1437 if (totaltracks_ptr == 0)
1438 totaltracks_ptr = tag->value;
1440 } else if (!strcasecmp(tag->item, "discnumber")
1441 || !strcasecmp(tag->item, "disc")) {
1442 if (discnumber_ptr == 0)
1443 discnumber_ptr = tag->value;
1445 } else if (!strcasecmp(tag->item, "totaldiscs")) {
1446 if (totaldiscs_ptr == 0)
1447 totaldiscs_ptr = tag->value;
1449 } else if (!strcasecmp(tag->item, "genre")) {
1451 genre_ptr = tag->value;
1453 } else if (!strcasecmp(tag->item, "tempo")) {
1455 tempo_ptr = tag->value;
1460 if (tracknumber_ptr)
1461 membuffer_write_track_tag(buf, "trkn", myatoi(tracknumber_ptr),
1462 myatoi(totaltracks_ptr));
1464 membuffer_write_track_tag(buf, "disk", myatoi(discnumber_ptr),
1465 myatoi(totaldiscs_ptr));
1467 membuffer_write_int16_tag(buf, "tmpo", myatoi(tempo_ptr));
1470 uint32_t index = meta_genre_to_index(genre_ptr);
1472 membuffer_write_std_tag(buf, "©gen", genre_ptr);
1474 membuffer_write_int16_tag(buf, "gnre", index);
1476 for (metaptr = 0; metaptr < data->count; metaptr++) {
1477 struct mp4_tag *tag;
1478 const char *std_meta_atom;
1482 tag = &data->tags[metaptr];
1483 std_meta_atom = find_standard_meta(tag->item);
1485 membuffer_write_std_tag(buf, std_meta_atom, tag->value);
1487 membuffer_write_custom_tag(buf, tag->item, tag->value);
1491 if (membuffer_error(buf)) {
1492 membuffer_free(buf);
1496 *out_size = membuffer_get_size(buf);
1497 *out_buffer = membuffer_detach(buf);
1498 membuffer_free(buf);
1503 static void membuffer_write_atom(struct membuffer *buf, const char *name, unsigned size,
1506 membuffer_write_int32(buf, size + 8);
1507 membuffer_write_atom_name(buf, name);
1508 membuffer_write(buf, data, size);
1511 static void *membuffer_get_ptr(const struct membuffer *buf)
1516 static void membuffer_set_error(struct membuffer *buf)
1521 static unsigned membuffer_transfer_from_file(struct membuffer *buf, struct mp4 *src,
1527 oldsize = membuffer_get_size(buf);
1528 if (membuffer_write(buf, 0, bytes) != bytes)
1531 bufptr = membuffer_get_ptr(buf);
1535 if ((unsigned)read_data(src, (char *) bufptr + oldsize, bytes) !=
1537 membuffer_set_error(buf);
1544 static uint32_t create_meta(const struct mp4_metadata *data, void **out_buffer,
1545 uint32_t * out_size)
1547 struct membuffer *buf;
1551 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1554 buf = membuffer_create();
1556 membuffer_write_int32(buf, 0);
1557 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1560 *out_size = membuffer_get_size(buf);
1561 *out_buffer = membuffer_detach(buf);
1562 membuffer_free(buf);
1566 static uint32_t create_udta(const struct mp4_metadata *data, void **out_buffer,
1567 uint32_t * out_size)
1569 struct membuffer *buf;
1573 if (!create_meta(data, &meta_buffer, &meta_size))
1576 buf = membuffer_create();
1578 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1582 *out_size = membuffer_get_size(buf);
1583 *out_buffer = membuffer_detach(buf);
1584 membuffer_free(buf);
1588 static uint32_t fix_byte_order_32(uint32_t src)
1590 return read_u32_be(&src);
1593 static uint32_t modify_moov(struct mp4 *f, const struct mp4_metadata *data,
1594 void **out_buffer, uint32_t * out_size)
1596 uint64_t total_base = f->moov_offset + 8;
1597 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1599 uint64_t udta_offset, meta_offset, ilst_offset;
1600 uint32_t udta_size, meta_size, ilst_size;
1602 uint32_t new_ilst_size;
1603 void *new_ilst_buffer;
1608 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1609 struct membuffer *buf;
1610 void *new_udta_buffer;
1611 uint32_t new_udta_size;
1612 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1615 buf = membuffer_create();
1616 set_position(f, total_base);
1617 membuffer_transfer_from_file(buf, f, total_size);
1619 membuffer_write_atom(buf, "udta", new_udta_size,
1622 free(new_udta_buffer);
1624 *out_size = membuffer_get_size(buf);
1625 *out_buffer = membuffer_detach(buf);
1626 membuffer_free(buf);
1629 udta_offset = get_position(f);
1630 udta_size = read_int32(f);
1631 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
1632 struct membuffer *buf;
1633 void *new_meta_buffer;
1634 uint32_t new_meta_size;
1635 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
1638 buf = membuffer_create();
1639 set_position(f, total_base);
1640 membuffer_transfer_from_file(buf, f,
1641 (uint32_t)(udta_offset - total_base));
1643 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
1644 membuffer_write_atom_name(buf, "udta");
1645 membuffer_transfer_from_file(buf, f, udta_size);
1647 membuffer_write_atom(buf, "meta", new_meta_size,
1649 free(new_meta_buffer);
1651 *out_size = membuffer_get_size(buf);
1652 *out_buffer = membuffer_detach(buf);
1653 membuffer_free(buf);
1656 meta_offset = get_position(f);
1657 meta_size = read_int32(f);
1658 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
1659 return 0; //shouldn't happen, find_atom_v2 above takes care of it
1660 ilst_offset = get_position(f);
1661 ilst_size = read_int32(f);
1663 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
1666 size_delta = new_ilst_size - (ilst_size - 8);
1668 *out_size = total_size + size_delta;
1669 *out_buffer = para_malloc(*out_size);
1670 p_out = (uint8_t *) * out_buffer;
1672 set_position(f, total_base);
1674 (uint32_t) (udta_offset - total_base));
1675 p_out += (uint32_t) (udta_offset - total_base);
1676 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1678 read_data(f, p_out, 4);
1681 (uint32_t) (meta_offset - udta_offset - 8));
1682 p_out += (uint32_t) (meta_offset - udta_offset - 8);
1683 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1685 read_data(f, p_out, 4);
1688 (uint32_t) (ilst_offset - meta_offset - 8));
1689 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
1690 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1692 read_data(f, p_out, 4);
1695 memcpy(p_out, new_ilst_buffer, new_ilst_size);
1696 p_out += new_ilst_size;
1698 set_position(f, ilst_offset + ilst_size);
1699 read_data(f, p_out, (uint32_t) (total_size
1700 - (ilst_offset - total_base) - ilst_size));
1702 free(new_ilst_buffer);
1707 static int32_t write_data(struct mp4 *f, void *data, uint32_t size)
1711 result = f->cb->write(f->cb->user_data, data, size);
1713 f->current_position += size;
1718 static int32_t write_int32(struct mp4 *f, uint32_t data)
1721 write_u32_be(temp, data);
1722 return write_data(f, temp, sizeof(temp));
1725 int32_t mp4_meta_update(const struct mp4_callback *cb,
1726 const struct mp4_metadata *data)
1728 void *new_moov_data;
1729 uint32_t new_moov_size;
1731 struct mp4 *f = para_calloc(sizeof(struct mp4));
1735 if (!modify_moov(f, data, &new_moov_data, &new_moov_size)) {
1740 /* copy moov atom to end of the file */
1741 if (f->last_atom != ATOM_MOOV) {
1742 char *free_data = "free";
1744 /* rename old moov to free */
1745 set_position(f, f->moov_offset + 4);
1746 write_data(f, free_data, 4);
1748 set_position(f, f->file_size);
1749 write_int32(f, new_moov_size + 8);
1750 write_data(f, "moov", 4);
1751 write_data(f, new_moov_data, new_moov_size);
1753 set_position(f, f->moov_offset);
1754 write_int32(f, new_moov_size + 8);
1755 write_data(f, "moov", 4);
1756 write_data(f, new_moov_data, new_moov_size);
1758 cb->truncate(cb->user_data);
1763 /* find a metadata item by name */
1764 /* returns 0 if item found, 1 if no such item */
1765 static int32_t meta_find_by_name(const struct mp4 *f, const char *item,
1770 for (i = 0; i < f->tags.count; i++) {
1771 if (!strcasecmp(f->tags.tags[i].item, item)) {
1772 *value = para_strdup(f->tags.tags[i].value);
1783 int32_t mp4_meta_get_artist(const struct mp4 *f, char **value)
1785 return meta_find_by_name(f, "artist", value);
1788 int32_t mp4_meta_get_title(const struct mp4 *f, char **value)
1790 return meta_find_by_name(f, "title", value);
1793 int32_t mp4_meta_get_date(const struct mp4 *f, char **value)
1795 return meta_find_by_name(f, "date", value);
1798 int32_t mp4_meta_get_album(const struct mp4 *f, char **value)
1800 return meta_find_by_name(f, "album", value);
1803 int32_t mp4_meta_get_comment(const struct mp4 *f, char **value)
1805 return meta_find_by_name(f, "comment", value);