2 * Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com
3 * FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
12 int32_t mp4ff_total_tracks(const mp4ff_t * f)
14 return f->total_tracks;
17 int32_t mp4ff_read_data(mp4ff_t * f, int8_t * data, uint32_t size)
21 result = f->stream->read(f->stream->user_data, data, size);
24 f->stream->read_error++;
26 f->current_position += size;
31 /* parse atom header size */
32 static int32_t mp4ff_atom_get_size(const int8_t * data)
37 a = (uint8_t) data[0];
38 b = (uint8_t) data[1];
39 c = (uint8_t) data[2];
40 d = (uint8_t) data[3];
42 result = (a << 24) | (b << 16) | (c << 8) | d;
43 //if (result > 0 && result < 8) result = 8;
45 return (int32_t) result;
48 uint64_t mp4ff_read_int64(mp4ff_t * f)
54 mp4ff_read_data(f, data, 8);
56 for (i = 0; i < 8; i++) {
57 result |= ((uint64_t) data[i]) << ((7 - i) * 8);
63 /* comnapre 2 atom names, returns 1 for equal, 0 for unequal */
64 static int32_t mp4ff_atom_compare(const int8_t a1, const int8_t b1,
65 const int8_t c1, const int8_t d1,
66 const int8_t a2, const int8_t b2,
67 const int8_t c2, const int8_t d2)
69 if (a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2)
77 #define TRACK_SYSTEM 3
78 #define TRACK_UNKNOWN 0
80 /* atoms with subatoms */
88 #define ATOM_ILST 8 /* iTunes Metadata list */
90 #define ATOM_ARTIST 10
91 #define ATOM_WRITER 11
95 #define ATOM_COMMENT 15
96 #define ATOM_GENRE1 16
99 #define ATOM_COMPILATION 19
100 #define ATOM_GENRE2 20
101 #define ATOM_TEMPO 21
102 #define ATOM_COVER 22
107 #define SUBATOMIC 128
109 /* atoms without subatoms */
110 #define ATOM_FTYP 129
111 #define ATOM_MDAT 130
112 #define ATOM_MVHD 131
113 #define ATOM_TKHD 132
114 #define ATOM_TREF 133
115 #define ATOM_MDHD 134
116 #define ATOM_VMHD 135
117 #define ATOM_SMHD 136
118 #define ATOM_HMHD 137
119 #define ATOM_STSD 138
120 #define ATOM_STTS 139
121 #define ATOM_STSZ 140
122 #define ATOM_STZ2 141
123 #define ATOM_STCO 142
124 #define ATOM_STSC 143
125 #define ATOM_MP4A 144
126 #define ATOM_MP4V 145
127 #define ATOM_MP4S 146
128 #define ATOM_ESDS 147
129 #define ATOM_META 148 /* iTunes Metadata box */
130 #define ATOM_NAME 149 /* iTunes Metadata name box */
131 #define ATOM_DATA 150 /* iTunes Metadata data box */
132 #define ATOM_CTTS 151
133 #define ATOM_FRMA 152
134 #define ATOM_IVIV 153
135 #define ATOM_PRIV 154
136 #define ATOM_USER 155
138 #define ATOM_ALBUM_ARTIST 157
139 #define ATOM_CONTENTGROUP 158
140 #define ATOM_LYRICS 159
141 #define ATOM_DESCRIPTION 160
142 #define ATOM_NETWORK 161
143 #define ATOM_SHOW 162
144 #define ATOM_EPISODENAME 163
145 #define ATOM_SORTTITLE 164
146 #define ATOM_SORTALBUM 165
147 #define ATOM_SORTARTIST 166
148 #define ATOM_SORTALBUMARTIST 167
149 #define ATOM_SORTWRITER 168
150 #define ATOM_SORTSHOW 169
151 #define ATOM_SEASON 170
152 #define ATOM_EPISODE 171
153 #define ATOM_PODCAST 172
155 #define ATOM_UNKNOWN 255
156 #define ATOM_FREE ATOM_UNKNOWN
157 #define ATOM_SKIP ATOM_UNKNOWN
159 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
161 static uint8_t mp4ff_atom_name_to_type(const int8_t a, const int8_t b,
162 const int8_t c, const int8_t d)
165 if (mp4ff_atom_compare(a, b, c, d, 'm', 'o', 'o', 'v'))
167 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'i', 'n', 'f'))
169 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'd', 'i', 'a'))
171 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'd', 'a', 't'))
173 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'd', 'h', 'd'))
175 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'v', 'h', 'd'))
177 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'p', '4', 'a'))
179 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'p', '4', 'v'))
181 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'p', '4', 's'))
183 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'e', 't', 'a'))
185 } else if (a == 't') {
186 if (mp4ff_atom_compare(a, b, c, d, 't', 'r', 'a', 'k'))
188 else if (mp4ff_atom_compare(a, b, c, d, 't', 'k', 'h', 'd'))
190 else if (mp4ff_atom_compare(a, b, c, d, 't', 'r', 'e', 'f'))
192 else if (mp4ff_atom_compare(a, b, c, d, 't', 'r', 'k', 'n'))
194 else if (mp4ff_atom_compare(a, b, c, d, 't', 'm', 'p', 'o'))
196 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 'n', 'n'))
198 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 's', 'h'))
200 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 'e', 'n'))
201 return ATOM_EPISODENAME;
202 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 's', 'n'))
204 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 'e', 's'))
206 } else if (a == 's') {
207 if (mp4ff_atom_compare(a, b, c, d, 's', 't', 'b', 'l'))
209 else if (mp4ff_atom_compare(a, b, c, d, 's', 'm', 'h', 'd'))
211 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 's', 'd'))
213 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 't', 's'))
215 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 'c', 'o'))
217 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 's', 'c'))
219 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 's', 'z'))
221 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 'z', '2'))
223 else if (mp4ff_atom_compare(a, b, c, d, 's', 'k', 'i', 'p'))
225 else if (mp4ff_atom_compare(a, b, c, d, 's', 'i', 'n', 'f'))
227 else if (mp4ff_atom_compare(a, b, c, d, 's', 'c', 'h', 'i'))
229 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'n', 'm'))
230 return ATOM_SORTTITLE;
231 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'a', 'l'))
232 return ATOM_SORTALBUM;
233 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'a', 'r'))
234 return ATOM_SORTARTIST;
235 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'a', 'a'))
236 return ATOM_SORTALBUMARTIST;
237 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'c', 'o'))
238 return ATOM_SORTWRITER;
239 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 's', 'n'))
240 return ATOM_SORTSHOW;
241 } else if (a == COPYRIGHT_SYMBOL) {
242 if (mp4ff_atom_compare
243 (a, b, c, d, COPYRIGHT_SYMBOL, 'n', 'a', 'm'))
245 else if (mp4ff_atom_compare
246 (a, b, c, d, COPYRIGHT_SYMBOL, 'A', 'R', 'T'))
248 else if (mp4ff_atom_compare
249 (a, b, c, d, COPYRIGHT_SYMBOL, 'w', 'r', 't'))
251 else if (mp4ff_atom_compare
252 (a, b, c, d, COPYRIGHT_SYMBOL, 'a', 'l', 'b'))
254 else if (mp4ff_atom_compare
255 (a, b, c, d, COPYRIGHT_SYMBOL, 'd', 'a', 'y'))
257 else if (mp4ff_atom_compare
258 (a, b, c, d, COPYRIGHT_SYMBOL, 't', 'o', 'o'))
260 else if (mp4ff_atom_compare
261 (a, b, c, d, COPYRIGHT_SYMBOL, 'c', 'm', 't'))
263 else if (mp4ff_atom_compare
264 (a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'e', 'n'))
266 else if (mp4ff_atom_compare
267 (a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'r', 'p'))
268 return ATOM_CONTENTGROUP;
269 else if (mp4ff_atom_compare
270 (a, b, c, d, COPYRIGHT_SYMBOL, 'l', 'y', 'r'))
274 if (mp4ff_atom_compare(a, b, c, d, 'e', 'd', 't', 's'))
276 else if (mp4ff_atom_compare(a, b, c, d, 'e', 's', 'd', 's'))
278 else if (mp4ff_atom_compare(a, b, c, d, 'f', 't', 'y', 'p'))
280 else if (mp4ff_atom_compare(a, b, c, d, 'f', 'r', 'e', 'e'))
282 else if (mp4ff_atom_compare(a, b, c, d, 'h', 'm', 'h', 'd'))
284 else if (mp4ff_atom_compare(a, b, c, d, 'v', 'm', 'h', 'd'))
286 else if (mp4ff_atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
288 else if (mp4ff_atom_compare(a, b, c, d, 'i', 'l', 's', 't'))
290 else if (mp4ff_atom_compare(a, b, c, d, 'n', 'a', 'm', 'e'))
292 else if (mp4ff_atom_compare(a, b, c, d, 'd', 'a', 't', 'a'))
294 else if (mp4ff_atom_compare(a, b, c, d, 'd', 'i', 's', 'k'))
296 else if (mp4ff_atom_compare(a, b, c, d, 'g', 'n', 'r', 'e'))
298 else if (mp4ff_atom_compare(a, b, c, d, 'c', 'o', 'v', 'r'))
300 else if (mp4ff_atom_compare(a, b, c, d, 'c', 'p', 'i', 'l'))
301 return ATOM_COMPILATION;
302 else if (mp4ff_atom_compare(a, b, c, d, 'c', 't', 't', 's'))
304 else if (mp4ff_atom_compare(a, b, c, d, 'd', 'r', 'm', 's'))
306 else if (mp4ff_atom_compare(a, b, c, d, 'f', 'r', 'm', 'a'))
308 else if (mp4ff_atom_compare(a, b, c, d, 'p', 'r', 'i', 'v'))
310 else if (mp4ff_atom_compare(a, b, c, d, 'i', 'v', 'i', 'v'))
312 else if (mp4ff_atom_compare(a, b, c, d, 'u', 's', 'e', 'r'))
314 else if (mp4ff_atom_compare(a, b, c, d, 'k', 'e', 'y', ' '))
316 else if (mp4ff_atom_compare(a, b, c, d, 'a', 'A', 'R', 'T'))
317 return ATOM_ALBUM_ARTIST;
318 else if (mp4ff_atom_compare(a, b, c, d, 'd', 'e', 's', 'c'))
319 return ATOM_DESCRIPTION;
320 else if (mp4ff_atom_compare(a, b, c, d, 'p', 'c', 's', 't'))
326 /* read atom header, return atom size, atom size is with header included */
327 uint64_t mp4ff_atom_read_header(mp4ff_t * f, uint8_t * atom_type,
328 uint8_t * header_size)
332 int8_t atom_header[8];
334 ret = mp4ff_read_data(f, atom_header, 8);
338 size = mp4ff_atom_get_size(atom_header);
341 /* check for 64 bit atom size */
344 size = mp4ff_read_int64(f);
346 //printf("%c%c%c%c\n", atom_header[4], atom_header[5], atom_header[6], atom_header[7]);
348 *atom_type = mp4ff_atom_name_to_type(atom_header[4], atom_header[5],
349 atom_header[6], atom_header[7]);
353 int64_t mp4ff_position(const mp4ff_t * f)
355 return f->current_position;
358 static int need_parse_when_meta_only(uint8_t atom_type)
384 int32_t mp4ff_set_position(mp4ff_t * f, const int64_t position)
386 f->stream->seek(f->stream->user_data, position);
387 f->current_position = position;
392 static void mp4ff_track_add(mp4ff_t * f)
396 if (f->total_tracks > MAX_TRACKS) {
402 f->track[f->total_tracks - 1] = malloc(sizeof (mp4ff_track_t));
404 memset(f->track[f->total_tracks - 1], 0, sizeof (mp4ff_track_t));
407 uint8_t mp4ff_read_char(mp4ff_t * f)
410 mp4ff_read_data(f, &output, 1);
414 uint32_t mp4ff_read_int24(mp4ff_t * f)
420 mp4ff_read_data(f, data, 3);
421 a = (uint8_t) data[0];
422 b = (uint8_t) data[1];
423 c = (uint8_t) data[2];
425 result = (a << 16) | (b << 8) | c;
426 return (uint32_t) result;
429 uint32_t mp4ff_read_int32(mp4ff_t * f)
435 mp4ff_read_data(f, data, 4);
436 a = (uint8_t) data[0];
437 b = (uint8_t) data[1];
438 c = (uint8_t) data[2];
439 d = (uint8_t) data[3];
441 result = (a << 24) | (b << 16) | (c << 8) | d;
442 return (uint32_t) result;
445 static int32_t mp4ff_read_stsz(mp4ff_t * f)
447 if (f->total_tracks == 0)
450 mp4ff_read_char(f); /* version */
451 mp4ff_read_int24(f); /* flags */
452 f->track[f->total_tracks - 1]->stsz_sample_size = mp4ff_read_int32(f);
453 f->track[f->total_tracks - 1]->stsz_sample_count = mp4ff_read_int32(f);
455 if (f->track[f->total_tracks - 1]->stsz_sample_size == 0) {
457 f->track[f->total_tracks - 1]->stsz_table =
458 (int32_t *)malloc(f->track[f->total_tracks - 1]->stsz_sample_count
461 if (!f->track[f->total_tracks - 1]->stsz_table)
464 for (i = 0; i < f->track[f->total_tracks - 1]->stsz_sample_count
465 && !f->stream->read_error; i++) {
466 f->track[f->total_tracks - 1]->stsz_table[i] = mp4ff_read_int32(f);
472 static int32_t mp4ff_read_stts(mp4ff_t * f)
475 mp4ff_track_t *p_track;
478 if (f->total_tracks == 0)
481 p_track = f->track[f->total_tracks - 1];
483 if (p_track->stts_entry_count)
486 mp4ff_read_char(f); /* version */
487 mp4ff_read_int24(f); /* flags */
488 p_track->stts_entry_count = mp4ff_read_int32(f);
490 p_track->stts_sample_count = (int32_t *)malloc(p_track->stts_entry_count
492 p_track->stts_sample_delta = (int32_t *)malloc(p_track->stts_entry_count
495 if (p_track->stts_sample_count == 0 || p_track->stts_sample_delta == 0) {
496 if (p_track->stts_sample_count) {
497 free(p_track->stts_sample_count);
498 p_track->stts_sample_count = 0;
500 if (p_track->stts_sample_delta) {
501 free(p_track->stts_sample_delta);
502 p_track->stts_sample_delta = 0;
504 p_track->stts_entry_count = 0;
507 for (i = 0; i < f->track[f->total_tracks - 1]->stts_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9254 */
508 p_track->stts_sample_count[i] = mp4ff_read_int32(f);
509 p_track->stts_sample_delta[i] = mp4ff_read_int32(f);
515 static int32_t mp4ff_read_ctts(mp4ff_t * f)
518 mp4ff_track_t *p_track;
520 if (f->total_tracks == 0)
523 p_track = f->track[f->total_tracks - 1];
524 if (p_track->ctts_entry_count)
527 mp4ff_read_char(f); /* version */
528 mp4ff_read_int24(f); /* flags */
529 p_track->ctts_entry_count = mp4ff_read_int32(f);
531 p_track->ctts_sample_count = (int32_t *)malloc(p_track->ctts_entry_count
533 p_track->ctts_sample_offset = (int32_t *)malloc(p_track->ctts_entry_count
536 if (p_track->ctts_sample_count == 0 || p_track->ctts_sample_offset == 0) {
537 if (p_track->ctts_sample_count) {
538 free(p_track->ctts_sample_count);
539 p_track->ctts_sample_count = 0;
541 if (p_track->ctts_sample_offset) {
542 free(p_track->ctts_sample_offset);
543 p_track->ctts_sample_offset = 0;
545 p_track->ctts_entry_count = 0;
548 for (i = 0; i < f->track[f->total_tracks - 1]->ctts_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9257 */
549 p_track->ctts_sample_count[i] = mp4ff_read_int32(f);
550 p_track->ctts_sample_offset[i] = mp4ff_read_int32(f);
556 static int32_t mp4ff_read_stsc(mp4ff_t * f)
560 if (f->total_tracks == 0)
563 mp4ff_read_char(f); /* version */
564 mp4ff_read_int24(f); /* flags */
565 f->track[f->total_tracks - 1]->stsc_entry_count = mp4ff_read_int32(f);
567 f->track[f->total_tracks - 1]->stsc_first_chunk =
568 (int32_t *) malloc(f->track[f->total_tracks - 1]->stsc_entry_count *
570 f->track[f->total_tracks - 1]->stsc_samples_per_chunk =
571 (int32_t *) malloc(f->track[f->total_tracks - 1]->stsc_entry_count *
573 f->track[f->total_tracks - 1]->stsc_sample_desc_index =
574 (int32_t *) malloc(f->track[f->total_tracks - 1]->stsc_entry_count *
578 if (!f->track[f->total_tracks - 1]->stsc_first_chunk) {
581 if (!f->track[f->total_tracks - 1]->stsc_samples_per_chunk) {
582 free(f->track[f->total_tracks - 1]->stsc_first_chunk);
583 f->track[f->total_tracks - 1]->stsc_first_chunk = NULL;
586 if (!f->track[f->total_tracks - 1]->stsc_sample_desc_index) {
587 free(f->track[f->total_tracks - 1]->stsc_first_chunk);
588 f->track[f->total_tracks - 1]->stsc_first_chunk = NULL;
589 free(f->track[f->total_tracks - 1]->stsc_samples_per_chunk);
590 f->track[f->total_tracks - 1]->stsc_samples_per_chunk = NULL;
594 for (i = 0; i < f->track[f->total_tracks - 1]->stsc_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9255 */
595 f->track[f->total_tracks - 1]->stsc_first_chunk[i] =
597 f->track[f->total_tracks - 1]->stsc_samples_per_chunk[i] =
599 f->track[f->total_tracks - 1]->stsc_sample_desc_index[i] =
606 static int32_t mp4ff_read_stco(mp4ff_t * f)
610 if (f->total_tracks == 0)
613 mp4ff_read_char(f); /* version */
614 mp4ff_read_int24(f); /* flags */
615 f->track[f->total_tracks - 1]->stco_entry_count = mp4ff_read_int32(f);
617 f->track[f->total_tracks - 1]->stco_chunk_offset =
618 (int32_t *) malloc(f->track[f->total_tracks - 1]->stco_entry_count *
622 if (!f->track[f->total_tracks - 1]->stco_chunk_offset)
625 for (i = 0; i < f->track[f->total_tracks - 1]->stco_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9256 */
626 f->track[f->total_tracks - 1]->stco_chunk_offset[i] =
633 uint16_t mp4ff_read_int16(mp4ff_t * f)
639 mp4ff_read_data(f, data, 2);
640 a = (uint8_t) data[0];
641 b = (uint8_t) data[1];
643 result = (a << 8) | b;
644 return (uint16_t) result;
647 uint32_t mp4ff_read_mp4_descr_length(mp4ff_t * f)
650 uint8_t numBytes = 0;
654 b = mp4ff_read_char(f);
656 length = (length << 7) | (b & 0x7F);
657 } while ((b & 0x80) && numBytes < 4);
661 static int32_t mp4ff_read_esds(mp4ff_t * f)
666 if (f->total_tracks == 0)
669 mp4ff_read_char(f); /* version */
670 mp4ff_read_int24(f); /* flags */
672 /* get and verify ES_DescrTag */
673 tag = mp4ff_read_char(f);
676 if (mp4ff_read_mp4_descr_length(f) < 5 + 15) {
686 /* get and verify DecoderConfigDescrTab */
687 if (mp4ff_read_char(f) != 0x04) {
692 temp = mp4ff_read_mp4_descr_length(f);
696 f->track[f->total_tracks - 1]->audioType = mp4ff_read_char(f);
697 mp4ff_read_int32(f); //0x15000414 ????
698 f->track[f->total_tracks - 1]->maxBitrate = mp4ff_read_int32(f);
699 f->track[f->total_tracks - 1]->avgBitrate = mp4ff_read_int32(f);
701 /* get and verify DecSpecificInfoTag */
702 if (mp4ff_read_char(f) != 0x05) {
707 f->track[f->total_tracks - 1]->decoderConfigLen =
708 mp4ff_read_mp4_descr_length(f);
710 if (f->track[f->total_tracks - 1]->decoderConfig)
711 free(f->track[f->total_tracks - 1]->decoderConfig);
712 f->track[f->total_tracks - 1]->decoderConfig =
713 malloc(f->track[f->total_tracks - 1]->decoderConfigLen);
714 if (f->track[f->total_tracks - 1]->decoderConfig) {
715 mp4ff_read_data(f, f->track[f->total_tracks - 1]->decoderConfig,
716 f->track[f->total_tracks -
717 1]->decoderConfigLen);
719 f->track[f->total_tracks - 1]->decoderConfigLen = 0;
722 /* will skip the remainder of the atom */
725 static int32_t mp4ff_read_mp4a(mp4ff_t * f)
729 uint8_t atom_type = 0;
730 uint8_t header_size = 0;
732 if (f->total_tracks == 0)
735 for (i = 0; i < 6; i++) {
736 mp4ff_read_char(f); /* reserved */
738 /* data_reference_index */ mp4ff_read_int16(f);
740 mp4ff_read_int32(f); /* reserved */
741 mp4ff_read_int32(f); /* reserved */
743 f->track[f->total_tracks - 1]->channelCount = mp4ff_read_int16(f);
744 f->track[f->total_tracks - 1]->sampleSize = mp4ff_read_int16(f);
749 f->track[f->total_tracks - 1]->sampleRate = mp4ff_read_int16(f);
753 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
754 if (atom_type == ATOM_ESDS) {
761 static int32_t mp4ff_read_stsd(mp4ff_t * f)
764 uint8_t header_size = 0;
767 if (f->total_tracks == 0)
770 mp4ff_read_char(f); /* version */
771 mp4ff_read_int24(f); /* flags */
773 f->track[f->total_tracks - 1]->stsd_entry_count = mp4ff_read_int32(f);
775 for (i = 0; i < f->track[f->total_tracks - 1]->stsd_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9253 */
776 uint64_t skip = mp4ff_position(f);
778 uint8_t atom_type = 0;
779 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
782 if (atom_type == ATOM_MP4A) {
783 f->track[f->total_tracks - 1]->type = TRACK_AUDIO;
785 } else if (atom_type == ATOM_MP4V) {
786 f->track[f->total_tracks - 1]->type = TRACK_VIDEO;
787 } else if (atom_type == ATOM_MP4S) {
788 f->track[f->total_tracks - 1]->type = TRACK_SYSTEM;
790 f->track[f->total_tracks - 1]->type = TRACK_UNKNOWN;
793 mp4ff_set_position(f, skip);
799 static int32_t mp4ff_read_mvhd(mp4ff_t * f)
803 mp4ff_read_char(f); /* version */
804 mp4ff_read_int24(f); /* flags */
805 /* creation_time */ mp4ff_read_int32(f);
806 /* modification_time */ mp4ff_read_int32(f);
807 f->time_scale = mp4ff_read_int32(f);
808 f->duration = mp4ff_read_int32(f);
809 /* preferred_rate */ mp4ff_read_int32(f);
810 /*mp4ff_read_fixed32(f); */
811 /* preferred_volume */ mp4ff_read_int16(f);
812 /*mp4ff_read_fixed16(f); */
813 for (i = 0; i < 10; i++) {
814 /* reserved */ mp4ff_read_char(f);
816 for (i = 0; i < 9; i++) {
817 mp4ff_read_int32(f); /* matrix */
819 /* preview_time */ mp4ff_read_int32(f);
820 /* preview_duration */ mp4ff_read_int32(f);
821 /* poster_time */ mp4ff_read_int32(f);
822 /* selection_time */ mp4ff_read_int32(f);
823 /* selection_duration */ mp4ff_read_int32(f);
824 /* current_time */ mp4ff_read_int32(f);
825 /* next_track_id */ mp4ff_read_int32(f);
830 static int32_t mp4ff_tag_add_field(mp4ff_metadata_t * tags, const char *item,
831 char *value, int32_t len)
833 void *backup = (void *) tags->tags;
835 if (!item || (item && !*item) || !value)
838 tags->tags = (mp4ff_tag_t *) realloc(tags->tags,
839 (tags->count + 1) * sizeof (mp4ff_tag_t));
845 tags->tags[tags->count].item = strdup(item);
846 tags->tags[tags->count].len = len;
848 tags->tags[tags->count].value = malloc(len + 1);
849 if (tags->tags[tags->count].value != NULL) {
850 memcpy(tags->tags[tags->count].value, value, len);
851 tags->tags[tags->count].value[len] = 0;
854 tags->tags[tags->count].value = strdup(value);
857 if (!tags->tags[tags->count].item || !tags->tags[tags->count].value) {
858 if (!tags->tags[tags->count].item)
859 free(tags->tags[tags->count].item);
860 if (!tags->tags[tags->count].value)
861 free(tags->tags[tags->count].value);
862 tags->tags[tags->count].item = NULL;
863 tags->tags[tags->count].value = NULL;
864 tags->tags[tags->count].len = 0;
873 static const char *ID3v1GenreList[] = {
874 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
875 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
876 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
877 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
878 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
879 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
880 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
881 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
882 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
883 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
884 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
885 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
886 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
887 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
888 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
889 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
890 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
891 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
892 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
893 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
894 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
895 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
896 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
897 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
898 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
899 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
900 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
901 "Anime", "JPop", "SynthPop",
904 const char *mp4ff_meta_index_to_genre(uint32_t idx)
906 if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
907 return ID3v1GenreList[idx - 1];
913 char *mp4ff_read_string(mp4ff_t * f, uint32_t length)
915 char *str = (char *) malloc(length + 1);
917 if ((uint32_t) mp4ff_read_data(f, str, length) != length) {
927 static int32_t mp4ff_set_metadata_name(mp4ff_t * f, const uint8_t atom_type,
930 static char *tag_names[] = {
931 "unknown", "title", "artist", "writer", "album",
932 "date", "tool", "comment", "genre", "track",
933 "disc", "compilation", "genre", "tempo", "cover",
934 "album_artist", "contentgroup", "lyrics", "description",
935 "network", "show", "episodename",
936 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
937 "sortwriter", "sortshow",
938 "season", "episode", "podcast"
973 case ATOM_COMPILATION:
985 case ATOM_ALBUM_ARTIST:
988 case ATOM_CONTENTGROUP:
994 case ATOM_DESCRIPTION:
1003 case ATOM_EPISODENAME:
1006 case ATOM_SORTTITLE:
1009 case ATOM_SORTALBUM:
1012 case ATOM_SORTARTIST:
1015 case ATOM_SORTALBUMARTIST:
1018 case ATOM_SORTWRITER:
1038 *name = strdup(tag_names[tag_idx]);
1043 static int32_t mp4ff_parse_tag(mp4ff_t * f, const uint8_t parent_atom_type,
1047 uint8_t header_size = 0;
1048 uint64_t subsize, sumsize = 0;
1054 while (sumsize < size && !f->stream->read_error) { /* CVE-2017-9222 */
1056 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1057 destpos = mp4ff_position(f) + subsize - header_size;
1059 if (atom_type == ATOM_DATA) {
1060 mp4ff_read_char(f); /* version */
1061 mp4ff_read_int24(f); /* flags */
1062 mp4ff_read_int32(f); /* reserved */
1064 /* some need special attention */
1065 if (parent_atom_type == ATOM_GENRE2 || parent_atom_type == ATOM_TEMPO) {
1066 if (subsize - header_size >= 8 + 2) {
1067 uint16_t val = mp4ff_read_int16(f);
1069 if (parent_atom_type == ATOM_TEMPO) {
1074 mp4ff_tag_add_field(&(f-> tags), "tempo", temp, -1);
1076 const char *temp = mp4ff_meta_index_to_genre(val);
1078 mp4ff_tag_add_field (&(f->tags), "genre", temp, -1);
1083 } else if (parent_atom_type == ATOM_TRACK || parent_atom_type == ATOM_DISC) {
1084 /* if (!done && subsize - header_size >= 8 + 8) */
1085 /* modified by AJS */
1086 if (!done && (subsize - header_size) >= (sizeof (char) + sizeof (uint8_t) * 3 + sizeof (uint32_t) + /* version + flags + reserved */
1087 +(parent_atom_type == ATOM_TRACK ? sizeof (uint16_t) : 0) /* leading uint16_t if ATOM_TRACK */
1088 +sizeof (uint16_t) /* track / disc */
1089 +sizeof (uint16_t)) /* totaltracks / totaldiscs */) {
1090 uint16_t index, total;
1092 mp4ff_read_int16(f);
1093 index = mp4ff_read_int16(f);
1094 total = mp4ff_read_int16(f);
1095 if (parent_atom_type == ATOM_TRACK)
1096 mp4ff_read_int16(f);
1098 sprintf(temp, "%d", index);
1099 mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ?
1100 "track" : "disc", temp, -1);
1104 mp4ff_tag_add_field(& (f-> tags),
1105 parent_atom_type == ATOM_TRACK?
1106 "totaltracks" : "totaldiscs", temp, -1);
1115 data = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 8)));
1116 len = (uint32_t) (subsize - (header_size + 8));
1118 } else if (atom_type == ATOM_NAME) {
1120 mp4ff_read_char(f); /* version */
1121 mp4ff_read_int24(f); /* flags */
1124 name = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 4)));
1127 mp4ff_set_position(f, destpos);
1135 mp4ff_set_metadata_name(f, parent_atom_type,
1138 mp4ff_tag_add_field(&(f->tags), name, data, len);
1147 static int32_t mp4ff_read_mdhd(mp4ff_t * f)
1152 if (f->total_tracks == 0)
1155 version = mp4ff_read_int32(f);
1157 mp4ff_read_int64(f); //creation-time
1158 mp4ff_read_int64(f); //modification-time
1159 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1160 f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f); //duration
1161 } else //version == 0
1165 mp4ff_read_int32(f); //creation-time
1166 mp4ff_read_int32(f); //modification-time
1167 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1168 temp = mp4ff_read_int32(f);
1169 f->track[f->total_tracks - 1]->duration = (temp == (uint32_t) (-1)) ? (uint64_t) (-1) : (uint64_t) (temp);
1171 mp4ff_read_int16(f);
1172 mp4ff_read_int16(f);
1176 int32_t mp4ff_parse_metadata(mp4ff_t * f, const int32_t size)
1178 uint64_t subsize, sumsize = 0;
1180 uint8_t header_size = 0;
1182 while (sumsize < size) {
1183 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1186 mp4ff_parse_tag(f, atom_type,
1187 (uint32_t) (subsize - header_size));
1194 static int32_t mp4ff_read_meta(mp4ff_t * f, const uint64_t size)
1196 uint64_t subsize, sumsize = 0;
1198 uint8_t header_size = 0;
1200 mp4ff_read_char(f); /* version */
1201 mp4ff_read_int24(f); /* flags */
1203 while (sumsize < (size - (header_size + 4))) {
1204 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1205 if (subsize <= header_size + 4)
1207 if (atom_type == ATOM_ILST) {
1208 mp4ff_parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1210 mp4ff_set_position(f, mp4ff_position(f) + subsize - header_size);
1218 int32_t mp4ff_atom_read(mp4ff_t * f, const int32_t size,
1219 const uint8_t atom_type)
1221 uint64_t dest_position = mp4ff_position(f) + size - 8;
1222 if (atom_type == ATOM_STSZ) {
1223 /* sample size box */
1225 } else if (atom_type == ATOM_STTS) {
1226 /* time to sample box */
1228 } else if (atom_type == ATOM_CTTS) {
1229 /* composition offset box */
1231 } else if (atom_type == ATOM_STSC) {
1232 /* sample to chunk box */
1234 } else if (atom_type == ATOM_STCO) {
1235 /* chunk offset box */
1237 } else if (atom_type == ATOM_STSD) {
1238 /* sample description box */
1240 } else if (atom_type == ATOM_MVHD) {
1241 /* movie header box */
1243 } else if (atom_type == ATOM_MDHD) {
1247 } else if (atom_type == ATOM_META) {
1248 /* iTunes Metadata box */
1249 mp4ff_read_meta(f, size);
1253 mp4ff_set_position(f, dest_position);
1257 /* parse atoms that are sub atoms of other atoms */
1258 int32_t parse_sub_atoms(mp4ff_t * f, const uint64_t total_size, int meta_only)
1261 uint8_t atom_type = 0;
1262 uint64_t counted_size = 0;
1263 uint8_t header_size = 0;
1265 while (counted_size < total_size) {
1266 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
1267 counted_size += size;
1269 /* check for end of file */
1273 /* we're starting to read a new track, update index,
1274 * so that all data and tables get written in the right place
1276 if (atom_type == ATOM_TRAK) {
1280 /* parse subatoms */
1281 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1282 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1283 } else if (atom_type < SUBATOMIC) {
1284 parse_sub_atoms(f, size - header_size, meta_only);
1286 mp4ff_atom_read(f, (uint32_t) size, atom_type);
1293 /* parse root atoms */
1294 int32_t parse_atoms(mp4ff_t * f, int meta_only)
1297 uint8_t atom_type = 0;
1298 uint8_t header_size = 0;
1301 f->stream->read_error = 0;
1304 mp4ff_atom_read_header(f, &atom_type, &header_size)) != 0) {
1305 f->file_size += size;
1306 f->last_atom = atom_type;
1308 if (atom_type == ATOM_MDAT && f->moov_read) {
1309 /* moov atom is before mdat, we can stop reading when mdat is encountered */
1310 /* file position will stay at beginning of mdat data */
1314 if (atom_type == ATOM_MOOV && size > header_size) {
1316 f->moov_offset = mp4ff_position(f) - header_size;
1317 f->moov_size = size;
1320 /* parse subatoms */
1321 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1322 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1323 } else if (atom_type < SUBATOMIC) {
1324 parse_sub_atoms(f, size - header_size, meta_only);
1326 /* skip this atom */
1327 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1334 int32_t mp4ff_get_decoder_config(const mp4ff_t * f, const int track,
1335 unsigned char **ppBuf, unsigned int *pBufSize)
1337 if (track >= f->total_tracks) {
1343 if (f->track[track]->decoderConfig == NULL
1344 || f->track[track]->decoderConfigLen == 0) {
1348 *ppBuf = malloc(f->track[track]->decoderConfigLen);
1349 if (*ppBuf == NULL) {
1353 memcpy(*ppBuf, f->track[track]->decoderConfig,
1354 f->track[track]->decoderConfigLen);
1355 *pBufSize = f->track[track]->decoderConfigLen;
1359 mp4ff_t *mp4ff_open_read(mp4ff_callback_t * f)
1361 mp4ff_t *ff = malloc(sizeof (mp4ff_t));
1363 memset(ff, 0, sizeof (mp4ff_t));
1377 int32_t mp4ff_tag_delete(mp4ff_metadata_t * tags)
1381 for (i = 0; i < tags->count; i++) {
1382 if (tags->tags[i].item)
1383 free(tags->tags[i].item);
1384 if (tags->tags[i].value)
1385 free(tags->tags[i].value);
1397 void mp4ff_close(mp4ff_t * ff)
1401 for (i = 0; i < ff->total_tracks; i++) {
1403 if (ff->track[i]->stsz_table)
1404 free(ff->track[i]->stsz_table);
1405 if (ff->track[i]->stts_sample_count)
1406 free(ff->track[i]->stts_sample_count);
1407 if (ff->track[i]->stts_sample_delta)
1408 free(ff->track[i]->stts_sample_delta);
1409 if (ff->track[i]->stsc_first_chunk)
1410 free(ff->track[i]->stsc_first_chunk);
1411 if (ff->track[i]->stsc_samples_per_chunk)
1412 free(ff->track[i]->stsc_samples_per_chunk);
1413 if (ff->track[i]->stsc_sample_desc_index)
1414 free(ff->track[i]->stsc_sample_desc_index);
1415 if (ff->track[i]->stco_chunk_offset)
1416 free(ff->track[i]->stco_chunk_offset);
1417 if (ff->track[i]->decoderConfig)
1418 free(ff->track[i]->decoderConfig);
1419 if (ff->track[i]->ctts_sample_count)
1420 free(ff->track[i]->ctts_sample_count);
1421 if (ff->track[i]->ctts_sample_offset)
1422 free(ff->track[i]->ctts_sample_offset);
1424 if (ff->track[i]->p_drms)
1425 drms_free(ff->track[i]->p_drms);
1432 mp4ff_tag_delete(&(ff->tags));
1439 static int32_t mp4ff_chunk_of_sample(const mp4ff_t * f, const int32_t track,
1440 const int32_t sample, int32_t * chunk_sample, int32_t * chunk)
1442 int32_t total_entries = 0;
1443 int32_t chunk2entry;
1444 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1446 if (f->track[track] == NULL) {
1450 total_entries = f->track[track]->stsc_entry_count;
1457 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1458 *chunk = chunk2 - chunk1;
1459 range_samples = *chunk * chunk1samples;
1461 if (sample < total + range_samples)
1464 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1467 if (chunk2entry < total_entries) {
1469 total += range_samples;
1471 } while (chunk2entry < total_entries);
1474 *chunk = (sample - total) / chunk1samples + chunk1;
1478 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1483 static int32_t mp4ff_chunk_to_offset(const mp4ff_t * f, const int32_t track,
1484 const int32_t chunk)
1486 const mp4ff_track_t *p_track = f->track[track];
1488 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1489 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1491 } else if (p_track->stco_entry_count) {
1492 return p_track->stco_chunk_offset[chunk - 1];
1500 static int32_t mp4ff_sample_range_size(const mp4ff_t * f, const int32_t track,
1501 const int32_t chunk_sample, const int32_t sample)
1504 const mp4ff_track_t *p_track = f->track[track];
1506 if (p_track->stsz_sample_size) {
1507 return (sample - chunk_sample) * p_track->stsz_sample_size;
1509 if (sample >= p_track->stsz_sample_count)
1512 for (i = chunk_sample, total = 0; i < sample; i++) {
1513 total += p_track->stsz_table[i];
1519 static int32_t mp4ff_sample_to_offset(const mp4ff_t * f, const int32_t track,
1520 const int32_t sample)
1522 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1524 mp4ff_chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1526 chunk_offset1 = mp4ff_chunk_to_offset(f, track, chunk);
1527 chunk_offset2 = chunk_offset1 + mp4ff_sample_range_size(f,
1528 track, chunk_sample, sample);
1529 return chunk_offset2;
1532 int32_t mp4ff_set_sample_position(mp4ff_t * f, const int32_t track,
1533 const int32_t sample)
1537 offset = mp4ff_sample_to_offset(f, track, sample);
1538 mp4ff_set_position(f, offset);
1543 int32_t mp4ff_audio_frame_size(const mp4ff_t * f, const int32_t track,
1544 const int32_t sample)
1547 const mp4ff_track_t *p_track = f->track[track];
1549 if (p_track->stsz_sample_size) {
1550 bytes = p_track->stsz_sample_size;
1552 bytes = p_track->stsz_table[sample];
1558 int32_t mp4ff_read_sample_getsize(mp4ff_t * f, const int track,
1561 int32_t temp = mp4ff_audio_frame_size(f, track, sample);
1567 uint32_t mp4ff_get_sample_rate(const mp4ff_t * f, const int32_t track)
1569 return f->track[track]->sampleRate;
1572 uint32_t mp4ff_get_channel_count(const mp4ff_t * f, const int32_t track)
1574 return f->track[track]->channelCount;
1577 int32_t mp4ff_num_samples(const mp4ff_t * f, const int32_t track)
1582 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1583 total += f->track[track]->stts_sample_count[i];
1588 mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t * f)
1590 mp4ff_t *ff = malloc(sizeof (mp4ff_t));
1592 memset(ff, 0, sizeof (mp4ff_t));
1606 int32_t mp4ff_meta_get_num_items(const mp4ff_t * f)
1608 return f->tags.count;
1611 int32_t mp4ff_meta_get_by_index(const mp4ff_t * f, uint32_t index,
1612 char **item, char **value)
1614 if (index >= f->tags.count) {
1619 *item = strdup(f->tags.tags[index].item);
1620 *value = strdup(f->tags.tags[index].value);
1625 static uint32_t find_atom(mp4ff_t * f, uint64_t base, uint32_t size,
1628 uint32_t remaining = size;
1629 uint64_t atom_offset = base;
1634 mp4ff_set_position(f, atom_offset);
1638 atom_size = mp4ff_read_int32(f);
1639 if (atom_size > remaining || atom_size < 8)
1641 mp4ff_read_data(f, atom_name, 4);
1643 if (!memcmp(atom_name, name, 4)) {
1644 mp4ff_set_position(f, atom_offset);
1648 remaining -= atom_size;
1649 atom_offset += atom_size;
1653 static uint32_t find_atom_v2(mp4ff_t * f, uint64_t base, uint32_t size,
1654 const char *name, uint32_t extraheaders, const char *name_inside)
1656 uint64_t first_base = (uint64_t) (-1);
1657 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1659 uint64_t mybase = mp4ff_position(f);
1660 uint32_t mysize = mp4ff_read_int32(f);
1662 if (first_base == (uint64_t) (-1))
1663 first_base = mybase;
1665 if (mysize < 8 + extraheaders)
1668 if (find_atom (f, mybase + (8 + extraheaders),
1669 mysize - (8 + extraheaders), name_inside)) {
1670 mp4ff_set_position(f, mybase);
1674 if (size <= mysize) {
1681 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1683 mp4ff_set_position(f, first_base);
1696 #define stricmp strcasecmp
1698 membuffer *membuffer_create()
1700 const unsigned initial_size = 256;
1702 membuffer *buf = (membuffer *) malloc(sizeof (membuffer));
1703 buf->data = malloc(initial_size);
1705 buf->allocated = initial_size;
1706 buf->error = buf->data == 0 ? 1 : 0;
1711 unsigned membuffer_write(membuffer * buf, const void *ptr, unsigned bytes)
1713 unsigned dest_size = buf->written + bytes;
1717 if (dest_size > buf->allocated) {
1719 buf->allocated <<= 1;
1720 } while (dest_size > buf->allocated);
1723 void *newptr = realloc(buf->data, buf->allocated);
1735 memcpy((char *) buf->data + buf->written, ptr, bytes);
1736 buf->written += bytes;
1740 #define membuffer_write_data membuffer_write
1742 unsigned membuffer_write_atom_name(membuffer * buf, const char *data)
1744 return membuffer_write_data(buf, data, 4) == 4 ? 1 : 0;
1747 unsigned membuffer_write_int16(membuffer * buf, uint16_t data)
1749 uint8_t temp[2] = { (uint8_t) (data >> 8), (uint8_t) data };
1750 return membuffer_write_data(buf, temp, 2);
1753 unsigned membuffer_write_int32(membuffer * buf, uint32_t data)
1755 uint8_t temp[4] = { (uint8_t) (data >> 24), (uint8_t) (data >> 16),
1756 (uint8_t) (data >> 8), (uint8_t) data };
1757 return membuffer_write_data(buf, temp, 4);
1760 static void membuffer_write_track_tag(membuffer * buf, const char *name,
1761 uint32_t index, uint32_t total)
1763 membuffer_write_int32(buf,
1764 8 /*atom header */ + 8 /*data atom header */ +
1765 8 /*flags + reserved */ + 8 /*actual data */ );
1766 membuffer_write_atom_name(buf, name);
1767 membuffer_write_int32(buf,
1768 8 /*data atom header */ +
1769 8 /*flags + reserved */ + 8 /*actual data */ );
1770 membuffer_write_atom_name(buf, "data");
1771 membuffer_write_int32(buf, 0); //flags
1772 membuffer_write_int32(buf, 0); //reserved
1773 membuffer_write_int16(buf, 0);
1774 membuffer_write_int16(buf, (uint16_t) index); //track number
1775 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1776 membuffer_write_int16(buf, 0);
1779 static void membuffer_write_int16_tag(membuffer * buf, const char *name,
1782 membuffer_write_int32(buf,
1783 8 /*atom header */ + 8 /*data atom header */ +
1784 8 /*flags + reserved */ + 2 /*actual data */ );
1785 membuffer_write_atom_name(buf, name);
1786 membuffer_write_int32(buf,
1787 8 /*data atom header */ +
1788 8 /*flags + reserved */ + 2 /*actual data */ );
1789 membuffer_write_atom_name(buf, "data");
1790 membuffer_write_int32(buf, 0); //flags
1791 membuffer_write_int32(buf, 0); //reserved
1792 membuffer_write_int16(buf, value); //value
1795 static uint32_t myatoi(const char *param)
1797 return param ? atoi(param) : 0;
1800 uint32_t mp4ff_meta_genre_to_index(const char *genrestr)
1803 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1804 if (!stricmp(genrestr, ID3v1GenreList[n]))
1815 static stdmeta_entry stdmetas[] = {
1816 {"\xA9" "nam", "title"},
1817 {"\xA9" "ART", "artist"},
1818 {"\xA9" "wrt", "writer"},
1819 {"\xA9" "alb", "album"},
1820 {"\xA9" "day", "date"},
1821 {"\xA9" "too", "tool"},
1822 {"\xA9" "cmt", "comment"},
1823 // {"\xA9" "gen","genre"},
1824 {"cpil", "compilation"},
1825 // {"trkn","track"},
1827 // {"gnre","genre"},
1830 {"aART", "album_artist"},
1833 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1836 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1837 if (!stricmp(name, stdmetas[n].name))
1838 return stdmetas[n].atom;
1843 static void membuffer_write_std_tag(membuffer * buf, const char *name,
1849 /* special check for compilation flag */
1850 if (strcmp(name, "cpil") == 0) {
1854 membuffer_write_int32(buf,
1855 8 /*atom header */ + 8 /*data atom header */ +
1856 8 /*flags + reserved */ + strlen(value));
1857 membuffer_write_atom_name(buf, name);
1858 membuffer_write_int32(buf,
1859 8 /*data atom header */ +
1860 8 /*flags + reserved */ + strlen(value));
1861 membuffer_write_atom_name(buf, "data");
1862 membuffer_write_int32(buf, flags); //flags
1863 membuffer_write_int32(buf, 0); //reserved
1864 membuffer_write_data(buf, value, strlen(value));
1867 static void membuffer_write_custom_tag(membuffer * buf, const char *name,
1870 membuffer_write_int32(buf,
1871 8 /*atom header */ +
1872 0x1C /*weirdo itunes atom */ +
1873 12 /*name atom header */ + strlen(name) +
1874 16 /*data atom header + flags */ + strlen(value));
1875 membuffer_write_atom_name(buf, "----");
1876 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1877 membuffer_write_atom_name(buf, "mean");
1878 membuffer_write_int32(buf, 0);
1879 membuffer_write_data(buf, "com.apple.iTunes", 16);
1880 membuffer_write_int32(buf, 12 + strlen(name));
1881 membuffer_write_atom_name(buf, "name");
1882 membuffer_write_int32(buf, 0);
1883 membuffer_write_data(buf, name, strlen(name));
1884 membuffer_write_int32(buf,
1885 8 /*data atom header */ +
1886 8 /*flags + reserved */ + strlen(value));
1887 membuffer_write_atom_name(buf, "data");
1888 membuffer_write_int32(buf, 1); //flags
1889 membuffer_write_int32(buf, 0); //reserved
1890 membuffer_write_data(buf, value, strlen(value));
1893 unsigned membuffer_error(const membuffer * buf)
1898 void membuffer_free(membuffer * buf)
1905 unsigned membuffer_get_size(const membuffer * buf)
1907 return buf->written;
1910 void *membuffer_detach(membuffer * buf)
1917 ret = realloc(buf->data, buf->written);
1928 static uint32_t create_ilst(const mp4ff_metadata_t * data, void **out_buffer,
1929 uint32_t * out_size)
1931 membuffer *buf = membuffer_create();
1933 char *mask = (char *) malloc(data->count);
1934 memset(mask, 0, data->count);
1937 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1938 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1939 const char *genre_ptr = 0, *tempo_ptr = 0;
1940 for (metaptr = 0; metaptr < data->count; metaptr++) {
1941 mp4ff_tag_t *tag = &data->tags[metaptr];
1942 if (!stricmp(tag->item, "tracknumber") || !stricmp(tag->item, "track")) {
1943 if (tracknumber_ptr == 0)
1944 tracknumber_ptr = tag->value;
1946 } else if (!stricmp(tag->item, "totaltracks")) {
1947 if (totaltracks_ptr == 0)
1948 totaltracks_ptr = tag->value;
1950 } else if (!stricmp(tag->item, "discnumber")
1951 || !stricmp(tag->item, "disc")) {
1952 if (discnumber_ptr == 0)
1953 discnumber_ptr = tag->value;
1955 } else if (!stricmp(tag->item, "totaldiscs")) {
1956 if (totaldiscs_ptr == 0)
1957 totaldiscs_ptr = tag->value;
1959 } else if (!stricmp(tag->item, "genre")) {
1961 genre_ptr = tag->value;
1963 } else if (!stricmp(tag->item, "tempo")) {
1965 tempo_ptr = tag->value;
1971 if (tracknumber_ptr)
1972 membuffer_write_track_tag(buf, "trkn",
1973 myatoi(tracknumber_ptr),
1974 myatoi(totaltracks_ptr));
1976 membuffer_write_track_tag(buf, "disk",
1977 myatoi(discnumber_ptr),
1978 myatoi(totaldiscs_ptr));
1980 membuffer_write_int16_tag(buf, "tmpo",
1981 (uint16_t) myatoi(tempo_ptr));
1984 uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
1986 membuffer_write_std_tag(buf, "©gen",
1989 membuffer_write_int16_tag(buf, "gnre",
1994 for (metaptr = 0; metaptr < data->count; metaptr++) {
1995 if (!mask[metaptr]) {
1996 mp4ff_tag_t *tag = &data->tags[metaptr];
1997 const char *std_meta_atom = find_standard_meta(tag->item);
1998 if (std_meta_atom) {
1999 membuffer_write_std_tag(buf, std_meta_atom,
2002 membuffer_write_custom_tag(buf, tag->item,
2010 if (membuffer_error(buf)) {
2011 membuffer_free(buf);
2015 *out_size = membuffer_get_size(buf);
2016 *out_buffer = membuffer_detach(buf);
2017 membuffer_free(buf);
2022 void membuffer_write_atom(membuffer * buf, const char *name, unsigned size,
2025 membuffer_write_int32(buf, size + 8);
2026 membuffer_write_atom_name(buf, name);
2027 membuffer_write_data(buf, data, size);
2030 void *membuffer_get_ptr(const membuffer * buf)
2035 void membuffer_set_error(membuffer * buf)
2040 unsigned membuffer_transfer_from_file(membuffer * buf, mp4ff_t * src,
2046 oldsize = membuffer_get_size(buf);
2047 if (membuffer_write_data(buf, 0, bytes) != bytes)
2050 bufptr = membuffer_get_ptr(buf);
2054 if ((unsigned) mp4ff_read_data(src, (char *) bufptr + oldsize, bytes) !=
2056 membuffer_set_error(buf);
2063 static uint32_t create_meta(const mp4ff_metadata_t * data, void **out_buffer,
2064 uint32_t * out_size)
2070 if (!create_ilst(data, &ilst_buffer, &ilst_size))
2073 buf = membuffer_create();
2075 membuffer_write_int32(buf, 0);
2076 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
2079 *out_size = membuffer_get_size(buf);
2080 *out_buffer = membuffer_detach(buf);
2081 membuffer_free(buf);
2085 static uint32_t create_udta(const mp4ff_metadata_t * data, void **out_buffer,
2086 uint32_t * out_size)
2092 if (!create_meta(data, &meta_buffer, &meta_size))
2095 buf = membuffer_create();
2097 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
2101 *out_size = membuffer_get_size(buf);
2102 *out_buffer = membuffer_detach(buf);
2103 membuffer_free(buf);
2107 static uint32_t fix_byte_order_32(uint32_t src)
2110 uint32_t a, b, c, d;
2113 memcpy(data, &src, sizeof (src));
2114 a = (uint8_t) data[0];
2115 b = (uint8_t) data[1];
2116 c = (uint8_t) data[2];
2117 d = (uint8_t) data[3];
2119 result = (a << 24) | (b << 16) | (c << 8) | d;
2120 return (uint32_t) result;
2123 static uint32_t modify_moov(mp4ff_t * f, const mp4ff_metadata_t * data,
2124 void **out_buffer, uint32_t * out_size)
2126 uint64_t total_base = f->moov_offset + 8;
2127 uint32_t total_size = (uint32_t) (f->moov_size - 8);
2129 uint64_t udta_offset, meta_offset, ilst_offset;
2130 uint32_t udta_size, meta_size, ilst_size;
2132 uint32_t new_ilst_size;
2133 void *new_ilst_buffer;
2138 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
2140 void *new_udta_buffer;
2141 uint32_t new_udta_size;
2142 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
2145 buf = membuffer_create();
2146 mp4ff_set_position(f, total_base);
2147 membuffer_transfer_from_file(buf, f, total_size);
2149 membuffer_write_atom(buf, "udta", new_udta_size,
2152 free(new_udta_buffer);
2154 *out_size = membuffer_get_size(buf);
2155 *out_buffer = membuffer_detach(buf);
2156 membuffer_free(buf);
2159 udta_offset = mp4ff_position(f);
2160 udta_size = mp4ff_read_int32(f);
2161 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
2163 void *new_meta_buffer;
2164 uint32_t new_meta_size;
2165 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
2168 buf = membuffer_create();
2169 mp4ff_set_position(f, total_base);
2170 membuffer_transfer_from_file(buf, f,
2171 (uint32_t)(udta_offset - total_base));
2173 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2174 membuffer_write_atom_name(buf, "udta");
2175 membuffer_transfer_from_file(buf, f, udta_size);
2177 membuffer_write_atom(buf, "meta", new_meta_size,
2179 free(new_meta_buffer);
2181 *out_size = membuffer_get_size(buf);
2182 *out_buffer = membuffer_detach(buf);
2183 membuffer_free(buf);
2186 meta_offset = mp4ff_position(f);
2187 meta_size = mp4ff_read_int32(f);
2188 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2189 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2190 ilst_offset = mp4ff_position(f);
2191 ilst_size = mp4ff_read_int32(f);
2193 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2196 size_delta = new_ilst_size - (ilst_size - 8);
2198 *out_size = total_size + size_delta;
2199 *out_buffer = malloc(*out_size);
2200 if (*out_buffer == 0) {
2201 free(new_ilst_buffer);
2205 p_out = (uint8_t *) * out_buffer;
2207 mp4ff_set_position(f, total_base);
2208 mp4ff_read_data(f, p_out,
2209 (uint32_t) (udta_offset - total_base));
2210 p_out += (uint32_t) (udta_offset - total_base);
2211 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2213 mp4ff_read_data(f, p_out, 4);
2215 mp4ff_read_data(f, p_out,
2216 (uint32_t) (meta_offset - udta_offset - 8));
2217 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2218 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2220 mp4ff_read_data(f, p_out, 4);
2222 mp4ff_read_data(f, p_out,
2223 (uint32_t) (ilst_offset - meta_offset - 8));
2224 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2225 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2227 mp4ff_read_data(f, p_out, 4);
2230 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2231 p_out += new_ilst_size;
2233 mp4ff_set_position(f, ilst_offset + ilst_size);
2234 mp4ff_read_data(f, p_out, (uint32_t) (total_size
2235 - (ilst_offset - total_base) - ilst_size));
2237 free(new_ilst_buffer);
2242 int32_t mp4ff_write_data(mp4ff_t * f, int8_t * data, uint32_t size)
2246 result = f->stream->write(f->stream->user_data, data, size);
2248 f->current_position += size;
2253 int32_t mp4ff_write_int32(mp4ff_t * f, const uint32_t data)
2256 uint32_t a, b, c, d;
2259 *(uint32_t *) temp = data;
2260 a = (uint8_t) temp[0];
2261 b = (uint8_t) temp[1];
2262 c = (uint8_t) temp[2];
2263 d = (uint8_t) temp[3];
2265 result = (a << 24) | (b << 16) | (c << 8) | d;
2267 return mp4ff_write_data(f, (uint8_t *) & result, sizeof (result));
2270 int32_t mp4ff_truncate(mp4ff_t * f)
2272 return f->stream->truncate(f->stream->user_data);
2275 int32_t mp4ff_meta_update(mp4ff_callback_t * f, const mp4ff_metadata_t * data)
2277 void *new_moov_data;
2278 uint32_t new_moov_size;
2280 mp4ff_t *ff = malloc(sizeof (mp4ff_t));
2282 memset(ff, 0, sizeof (mp4ff_t));
2284 mp4ff_set_position(ff, 0);
2288 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2293 /* copy moov atom to end of the file */
2294 if (ff->last_atom != ATOM_MOOV) {
2295 char *free_data = "free";
2297 /* rename old moov to free */
2298 mp4ff_set_position(ff, ff->moov_offset + 4);
2299 mp4ff_write_data(ff, free_data, 4);
2301 mp4ff_set_position(ff, ff->file_size);
2302 mp4ff_write_int32(ff, new_moov_size + 8);
2303 mp4ff_write_data(ff, "moov", 4);
2304 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2306 mp4ff_set_position(ff, ff->moov_offset);
2307 mp4ff_write_int32(ff, new_moov_size + 8);
2308 mp4ff_write_data(ff, "moov", 4);
2309 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2318 /* find a metadata item by name */
2319 /* returns 0 if item found, 1 if no such item */
2320 static int32_t mp4ff_meta_find_by_name(const mp4ff_t * f, const char *item,
2325 for (i = 0; i < f->tags.count; i++) {
2326 if (!stricmp(f->tags.tags[i].item, item)) {
2327 *value = strdup(f->tags.tags[i].value);
2338 int32_t mp4ff_meta_get_artist(const mp4ff_t * f, char **value)
2340 return mp4ff_meta_find_by_name(f, "artist", value);
2343 int32_t mp4ff_meta_get_title(const mp4ff_t * f, char **value)
2345 return mp4ff_meta_find_by_name(f, "title", value);
2348 int32_t mp4ff_meta_get_date(const mp4ff_t * f, char **value)
2350 return mp4ff_meta_find_by_name(f, "date", value);
2353 int32_t mp4ff_meta_get_album(const mp4ff_t * f, char **value)
2355 return mp4ff_meta_find_by_name(f, "album", value);
2358 int32_t mp4ff_meta_get_comment(const mp4ff_t * f, char **value)
2360 return mp4ff_meta_find_by_name(f, "comment", value);