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));
1108 int32_t mp4_meta_get_num_items(const struct mp4 *f)
1110 return f->tags.count;
1113 int32_t mp4_meta_get_by_index(const struct mp4 *f, uint32_t index,
1114 char **item, char **value)
1116 if (index >= f->tags.count) {
1121 *item = para_strdup(f->tags.tags[index].item);
1122 *value = para_strdup(f->tags.tags[index].value);
1127 static uint32_t find_atom(struct mp4 *f, uint64_t base, uint32_t size,
1130 uint32_t remaining = size;
1131 uint64_t atom_offset = base;
1136 set_position(f, atom_offset);
1140 atom_size = read_int32(f);
1141 if (atom_size > remaining || atom_size < 8)
1143 read_data(f, atom_name, 4);
1145 if (!memcmp(atom_name, name, 4)) {
1146 set_position(f, atom_offset);
1150 remaining -= atom_size;
1151 atom_offset += atom_size;
1156 static uint32_t find_atom_v2(struct mp4 *f, uint64_t base, uint32_t size,
1157 const char *name, uint32_t extraheaders, const char *name_inside)
1159 uint64_t first_base = (uint64_t) (-1);
1160 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1162 uint64_t mybase = get_position(f);
1163 uint32_t mysize = read_int32(f);
1165 if (first_base == (uint64_t) (-1))
1166 first_base = mybase;
1168 if (mysize < 8 + extraheaders)
1171 if (find_atom (f, mybase + (8 + extraheaders),
1172 mysize - (8 + extraheaders), name_inside)) {
1173 set_position(f, mybase);
1177 if (size <= mysize) {
1184 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1186 set_position(f, first_base);
1199 static struct membuffer *membuffer_create(void)
1201 const unsigned initial_size = 256;
1203 struct membuffer *buf = para_malloc(sizeof(*buf));
1204 buf->data = para_malloc(initial_size);
1206 buf->allocated = initial_size;
1207 buf->error = buf->data == 0 ? 1 : 0;
1212 static unsigned membuffer_write(struct membuffer *buf, const void *ptr, unsigned bytes)
1214 unsigned dest_size = buf->written + bytes;
1218 if (dest_size > buf->allocated) {
1220 buf->allocated <<= 1;
1221 } while (dest_size > buf->allocated);
1222 buf->data = para_realloc(buf->data, buf->allocated);
1226 memcpy((char *) buf->data + buf->written, ptr, bytes);
1227 buf->written += bytes;
1231 static unsigned membuffer_write_atom_name(struct membuffer *buf, const char *data)
1233 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1236 static unsigned membuffer_write_int16(struct membuffer *buf, uint16_t data)
1240 write_u16_be(temp, data);
1241 return membuffer_write(buf, temp, 2);
1244 static unsigned membuffer_write_int32(struct membuffer *buf, uint32_t data)
1247 write_u32_be(temp, data);
1248 return membuffer_write(buf, temp, 4);
1251 static void membuffer_write_track_tag(struct membuffer *buf, const char *name,
1252 uint32_t index, uint32_t total)
1254 membuffer_write_int32(buf,
1255 8 /*atom header */ + 8 /*data atom header */ +
1256 8 /*flags + reserved */ + 8 /*actual data */ );
1257 membuffer_write_atom_name(buf, name);
1258 membuffer_write_int32(buf,
1259 8 /*data atom header */ +
1260 8 /*flags + reserved */ + 8 /*actual data */ );
1261 membuffer_write_atom_name(buf, "data");
1262 membuffer_write_int32(buf, 0); //flags
1263 membuffer_write_int32(buf, 0); //reserved
1264 membuffer_write_int16(buf, 0);
1265 membuffer_write_int16(buf, (uint16_t) index); //track number
1266 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1267 membuffer_write_int16(buf, 0);
1270 static void membuffer_write_int16_tag(struct membuffer *buf, const char *name,
1273 membuffer_write_int32(buf,
1274 8 /*atom header */ + 8 /*data atom header */ +
1275 8 /*flags + reserved */ + 2 /*actual data */ );
1276 membuffer_write_atom_name(buf, name);
1277 membuffer_write_int32(buf,
1278 8 /*data atom header */ +
1279 8 /*flags + reserved */ + 2 /*actual data */ );
1280 membuffer_write_atom_name(buf, "data");
1281 membuffer_write_int32(buf, 0); //flags
1282 membuffer_write_int32(buf, 0); //reserved
1283 membuffer_write_int16(buf, value); //value
1286 static uint32_t myatoi(const char *param)
1288 return param ? atoi(param) : 0;
1291 static uint32_t meta_genre_to_index(const char *genrestr)
1294 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1295 if (!strcasecmp(genrestr, ID3v1GenreList[n]))
1301 struct stdmeta_entry {
1306 struct stdmeta_entry stdmetas[] = {
1307 {"\xA9" "nam", "title"},
1308 {"\xA9" "ART", "artist"},
1309 {"\xA9" "wrt", "writer"},
1310 {"\xA9" "alb", "album"},
1311 {"\xA9" "day", "date"},
1312 {"\xA9" "too", "tool"},
1313 {"\xA9" "cmt", "comment"},
1314 {"cpil", "compilation"},
1316 {"aART", "album_artist"},
1319 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1322 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1323 if (!strcasecmp(name, stdmetas[n].name))
1324 return stdmetas[n].atom;
1329 static void membuffer_write_std_tag(struct membuffer *buf, const char *name,
1334 /* special check for compilation flag */
1335 if (strcmp(name, "cpil") == 0) {
1339 membuffer_write_int32(buf,
1340 8 /*atom header */ + 8 /*data atom header */ +
1341 8 /*flags + reserved */ + strlen(value));
1342 membuffer_write_atom_name(buf, name);
1343 membuffer_write_int32(buf,
1344 8 /*data atom header */ +
1345 8 /*flags + reserved */ + strlen(value));
1346 membuffer_write_atom_name(buf, "data");
1347 membuffer_write_int32(buf, flags); //flags
1348 membuffer_write_int32(buf, 0); //reserved
1349 membuffer_write(buf, value, strlen(value));
1352 static void membuffer_write_custom_tag(struct membuffer *buf, const char *name,
1355 membuffer_write_int32(buf,
1356 8 /*atom header */ +
1357 0x1C /*weirdo itunes atom */ +
1358 12 /*name atom header */ + strlen(name) +
1359 16 /*data atom header + flags */ + strlen(value));
1360 membuffer_write_atom_name(buf, "----");
1361 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1362 membuffer_write_atom_name(buf, "mean");
1363 membuffer_write_int32(buf, 0);
1364 membuffer_write(buf, "com.apple.iTunes", 16);
1365 membuffer_write_int32(buf, 12 + strlen(name));
1366 membuffer_write_atom_name(buf, "name");
1367 membuffer_write_int32(buf, 0);
1368 membuffer_write(buf, name, strlen(name));
1369 membuffer_write_int32(buf,
1370 8 /*data atom header */ +
1371 8 /*flags + reserved */ + strlen(value));
1372 membuffer_write_atom_name(buf, "data");
1373 membuffer_write_int32(buf, 1); //flags
1374 membuffer_write_int32(buf, 0); //reserved
1375 membuffer_write(buf, value, strlen(value));
1378 static unsigned membuffer_error(const struct membuffer *buf)
1383 static void membuffer_free(struct membuffer *buf)
1389 static unsigned membuffer_get_size(const struct membuffer *buf)
1391 return buf->written;
1394 static void *membuffer_detach(struct membuffer *buf)
1400 ret = para_realloc(buf->data, buf->written);
1406 static uint32_t create_ilst(const struct mp4_metadata *data, void **out_buffer,
1407 uint32_t * out_size)
1409 struct membuffer *buf = membuffer_create();
1411 char *mask = para_calloc(data->count);
1412 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1413 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1414 const char *genre_ptr = 0, *tempo_ptr = 0;
1416 for (metaptr = 0; metaptr < data->count; metaptr++) {
1417 struct mp4_tag *tag = &data->tags[metaptr];
1418 if (!strcasecmp(tag->item, "tracknumber")
1419 || !strcasecmp(tag->item, "track")) {
1420 if (tracknumber_ptr == 0)
1421 tracknumber_ptr = tag->value;
1423 } else if (!strcasecmp(tag->item, "totaltracks")) {
1424 if (totaltracks_ptr == 0)
1425 totaltracks_ptr = tag->value;
1427 } else if (!strcasecmp(tag->item, "discnumber")
1428 || !strcasecmp(tag->item, "disc")) {
1429 if (discnumber_ptr == 0)
1430 discnumber_ptr = tag->value;
1432 } else if (!strcasecmp(tag->item, "totaldiscs")) {
1433 if (totaldiscs_ptr == 0)
1434 totaldiscs_ptr = tag->value;
1436 } else if (!strcasecmp(tag->item, "genre")) {
1438 genre_ptr = tag->value;
1440 } else if (!strcasecmp(tag->item, "tempo")) {
1442 tempo_ptr = tag->value;
1447 if (tracknumber_ptr)
1448 membuffer_write_track_tag(buf, "trkn", myatoi(tracknumber_ptr),
1449 myatoi(totaltracks_ptr));
1451 membuffer_write_track_tag(buf, "disk", myatoi(discnumber_ptr),
1452 myatoi(totaldiscs_ptr));
1454 membuffer_write_int16_tag(buf, "tmpo", myatoi(tempo_ptr));
1457 uint32_t index = meta_genre_to_index(genre_ptr);
1459 membuffer_write_std_tag(buf, "©gen", genre_ptr);
1461 membuffer_write_int16_tag(buf, "gnre", index);
1463 for (metaptr = 0; metaptr < data->count; metaptr++) {
1464 struct mp4_tag *tag;
1465 const char *std_meta_atom;
1469 tag = &data->tags[metaptr];
1470 std_meta_atom = find_standard_meta(tag->item);
1472 membuffer_write_std_tag(buf, std_meta_atom, tag->value);
1474 membuffer_write_custom_tag(buf, tag->item, tag->value);
1478 if (membuffer_error(buf)) {
1479 membuffer_free(buf);
1483 *out_size = membuffer_get_size(buf);
1484 *out_buffer = membuffer_detach(buf);
1485 membuffer_free(buf);
1490 static void membuffer_write_atom(struct membuffer *buf, const char *name, unsigned size,
1493 membuffer_write_int32(buf, size + 8);
1494 membuffer_write_atom_name(buf, name);
1495 membuffer_write(buf, data, size);
1498 static void *membuffer_get_ptr(const struct membuffer *buf)
1503 static void membuffer_set_error(struct membuffer *buf)
1508 static unsigned membuffer_transfer_from_file(struct membuffer *buf, struct mp4 *src,
1514 oldsize = membuffer_get_size(buf);
1515 if (membuffer_write(buf, 0, bytes) != bytes)
1518 bufptr = membuffer_get_ptr(buf);
1522 if ((unsigned)read_data(src, (char *) bufptr + oldsize, bytes) !=
1524 membuffer_set_error(buf);
1531 static uint32_t create_meta(const struct mp4_metadata *data, void **out_buffer,
1532 uint32_t * out_size)
1534 struct membuffer *buf;
1538 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1541 buf = membuffer_create();
1543 membuffer_write_int32(buf, 0);
1544 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1547 *out_size = membuffer_get_size(buf);
1548 *out_buffer = membuffer_detach(buf);
1549 membuffer_free(buf);
1553 static uint32_t create_udta(const struct mp4_metadata *data, void **out_buffer,
1554 uint32_t * out_size)
1556 struct membuffer *buf;
1560 if (!create_meta(data, &meta_buffer, &meta_size))
1563 buf = membuffer_create();
1565 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1569 *out_size = membuffer_get_size(buf);
1570 *out_buffer = membuffer_detach(buf);
1571 membuffer_free(buf);
1575 static uint32_t fix_byte_order_32(uint32_t src)
1577 return read_u32_be(&src);
1580 static uint32_t modify_moov(struct mp4 *f, const struct mp4_metadata *data,
1581 void **out_buffer, uint32_t * out_size)
1583 uint64_t total_base = f->moov_offset + 8;
1584 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1586 uint64_t udta_offset, meta_offset, ilst_offset;
1587 uint32_t udta_size, meta_size, ilst_size;
1589 uint32_t new_ilst_size;
1590 void *new_ilst_buffer;
1595 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1596 struct membuffer *buf;
1597 void *new_udta_buffer;
1598 uint32_t new_udta_size;
1599 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1602 buf = membuffer_create();
1603 set_position(f, total_base);
1604 membuffer_transfer_from_file(buf, f, total_size);
1606 membuffer_write_atom(buf, "udta", new_udta_size,
1609 free(new_udta_buffer);
1611 *out_size = membuffer_get_size(buf);
1612 *out_buffer = membuffer_detach(buf);
1613 membuffer_free(buf);
1616 udta_offset = get_position(f);
1617 udta_size = read_int32(f);
1618 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
1619 struct membuffer *buf;
1620 void *new_meta_buffer;
1621 uint32_t new_meta_size;
1622 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
1625 buf = membuffer_create();
1626 set_position(f, total_base);
1627 membuffer_transfer_from_file(buf, f,
1628 (uint32_t)(udta_offset - total_base));
1630 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
1631 membuffer_write_atom_name(buf, "udta");
1632 membuffer_transfer_from_file(buf, f, udta_size);
1634 membuffer_write_atom(buf, "meta", new_meta_size,
1636 free(new_meta_buffer);
1638 *out_size = membuffer_get_size(buf);
1639 *out_buffer = membuffer_detach(buf);
1640 membuffer_free(buf);
1643 meta_offset = get_position(f);
1644 meta_size = read_int32(f);
1645 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
1646 return 0; //shouldn't happen, find_atom_v2 above takes care of it
1647 ilst_offset = get_position(f);
1648 ilst_size = read_int32(f);
1650 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
1653 size_delta = new_ilst_size - (ilst_size - 8);
1655 *out_size = total_size + size_delta;
1656 *out_buffer = para_malloc(*out_size);
1657 p_out = (uint8_t *) * out_buffer;
1659 set_position(f, total_base);
1661 (uint32_t) (udta_offset - total_base));
1662 p_out += (uint32_t) (udta_offset - total_base);
1663 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1665 read_data(f, p_out, 4);
1668 (uint32_t) (meta_offset - udta_offset - 8));
1669 p_out += (uint32_t) (meta_offset - udta_offset - 8);
1670 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1672 read_data(f, p_out, 4);
1675 (uint32_t) (ilst_offset - meta_offset - 8));
1676 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
1677 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
1679 read_data(f, p_out, 4);
1682 memcpy(p_out, new_ilst_buffer, new_ilst_size);
1683 p_out += new_ilst_size;
1685 set_position(f, ilst_offset + ilst_size);
1686 read_data(f, p_out, (uint32_t) (total_size
1687 - (ilst_offset - total_base) - ilst_size));
1689 free(new_ilst_buffer);
1694 static int32_t write_data(struct mp4 *f, void *data, uint32_t size)
1698 result = f->cb->write(f->cb->user_data, data, size);
1700 f->current_position += size;
1705 static int32_t write_int32(struct mp4 *f, uint32_t data)
1708 write_u32_be(temp, data);
1709 return write_data(f, temp, sizeof(temp));
1712 int32_t mp4_meta_update(struct mp4 *f, struct mp4_metadata *meta)
1714 void *new_moov_data;
1715 uint32_t new_moov_size;
1717 tag_delete(&f->tags);
1720 if (!modify_moov(f, meta, &new_moov_data, &new_moov_size)) {
1725 /* copy moov atom to end of the file */
1726 if (f->last_atom != ATOM_MOOV) {
1727 char *free_data = "free";
1729 /* rename old moov to free */
1730 set_position(f, f->moov_offset + 4);
1731 write_data(f, free_data, 4);
1733 set_position(f, f->file_size);
1734 write_int32(f, new_moov_size + 8);
1735 write_data(f, "moov", 4);
1736 write_data(f, new_moov_data, new_moov_size);
1738 set_position(f, f->moov_offset);
1739 write_int32(f, new_moov_size + 8);
1740 write_data(f, "moov", 4);
1741 write_data(f, new_moov_data, new_moov_size);
1743 free(new_moov_data);
1744 f->cb->truncate(f->cb->user_data);
1748 static char *meta_find_by_name(const struct mp4 *f, const char *item)
1752 for (i = 0; i < f->tags.count; i++)
1753 if (!strcasecmp(f->tags.tags[i].item, item))
1754 return para_strdup(f->tags.tags[i].value);
1759 * Return the value of the artist meta tag of an mp4 file.
1761 * \param f Must not be NULL.
1763 * \return If the file does not contain this metadata tag, the function returns
1764 * NULL. Otherwise, a copy of the tag value is returned. The caller should free
1765 * this memory when it is no longer needed.
1767 char *mp4_meta_get_artist(const struct mp4 *f)
1769 return meta_find_by_name(f, "artist");
1773 * Return the value of the title meta tag of an mp4 file.
1775 * \param f See \ref mp4_meta_get_artist().
1776 * \return See \ref mp4_meta_get_artist().
1778 char *mp4_meta_get_title(const struct mp4 *f)
1780 return meta_find_by_name(f, "title");
1784 * Return the value of the date meta tag of an mp4 file.
1786 * \param f See \ref mp4_meta_get_artist().
1787 * \return See \ref mp4_meta_get_artist().
1789 char *mp4_meta_get_date(const struct mp4 *f)
1791 return meta_find_by_name(f, "date");
1795 * Return the value of the album meta tag of an mp4 file.
1797 * \param f See \ref mp4_meta_get_artist().
1798 * \return See \ref mp4_meta_get_artist().
1800 char *mp4_meta_get_album(const struct mp4 *f)
1802 return meta_find_by_name(f, "album");
1806 * Return the value of the comment meta tag of an mp4 file.
1808 * \param f See \ref mp4_meta_get_artist().
1809 * \return See \ref mp4_meta_get_artist().
1811 char *mp4_meta_get_comment(const struct mp4 *f)
1813 return meta_find_by_name(f, "comment");