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, void *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)
728 uint8_t atom_type = 0;
729 uint8_t header_size = 0;
731 if (f->total_tracks == 0)
734 for (i = 0; i < 6; i++) {
735 mp4ff_read_char(f); /* reserved */
737 /* data_reference_index */ mp4ff_read_int16(f);
739 mp4ff_read_int32(f); /* reserved */
740 mp4ff_read_int32(f); /* reserved */
742 f->track[f->total_tracks - 1]->channelCount = mp4ff_read_int16(f);
743 f->track[f->total_tracks - 1]->sampleSize = mp4ff_read_int16(f);
748 f->track[f->total_tracks - 1]->sampleRate = mp4ff_read_int16(f);
752 mp4ff_atom_read_header(f, &atom_type, &header_size);
753 if (atom_type == ATOM_ESDS) {
760 static int32_t mp4ff_read_stsd(mp4ff_t * f)
763 uint8_t header_size = 0;
766 if (f->total_tracks == 0)
769 mp4ff_read_char(f); /* version */
770 mp4ff_read_int24(f); /* flags */
772 f->track[f->total_tracks - 1]->stsd_entry_count = mp4ff_read_int32(f);
774 for (i = 0; i < f->track[f->total_tracks - 1]->stsd_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9253 */
775 uint64_t skip = mp4ff_position(f);
777 uint8_t atom_type = 0;
778 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
781 if (atom_type == ATOM_MP4A) {
782 f->track[f->total_tracks - 1]->type = TRACK_AUDIO;
784 } else if (atom_type == ATOM_MP4V) {
785 f->track[f->total_tracks - 1]->type = TRACK_VIDEO;
786 } else if (atom_type == ATOM_MP4S) {
787 f->track[f->total_tracks - 1]->type = TRACK_SYSTEM;
789 f->track[f->total_tracks - 1]->type = TRACK_UNKNOWN;
792 mp4ff_set_position(f, skip);
798 static int32_t mp4ff_read_mvhd(mp4ff_t * f)
802 mp4ff_read_char(f); /* version */
803 mp4ff_read_int24(f); /* flags */
804 /* creation_time */ mp4ff_read_int32(f);
805 /* modification_time */ mp4ff_read_int32(f);
806 f->time_scale = mp4ff_read_int32(f);
807 f->duration = mp4ff_read_int32(f);
808 /* preferred_rate */ mp4ff_read_int32(f);
809 /*mp4ff_read_fixed32(f); */
810 /* preferred_volume */ mp4ff_read_int16(f);
811 /*mp4ff_read_fixed16(f); */
812 for (i = 0; i < 10; i++) {
813 /* reserved */ mp4ff_read_char(f);
815 for (i = 0; i < 9; i++) {
816 mp4ff_read_int32(f); /* matrix */
818 /* preview_time */ mp4ff_read_int32(f);
819 /* preview_duration */ mp4ff_read_int32(f);
820 /* poster_time */ mp4ff_read_int32(f);
821 /* selection_time */ mp4ff_read_int32(f);
822 /* selection_duration */ mp4ff_read_int32(f);
823 /* current_time */ mp4ff_read_int32(f);
824 /* next_track_id */ mp4ff_read_int32(f);
829 static int32_t mp4ff_tag_add_field(mp4ff_metadata_t * tags, const char *item,
830 const char *value, int32_t len)
832 void *backup = (void *) tags->tags;
834 if (!item || (item && !*item) || !value)
837 tags->tags = (mp4ff_tag_t *) realloc(tags->tags,
838 (tags->count + 1) * sizeof (mp4ff_tag_t));
844 tags->tags[tags->count].item = strdup(item);
845 tags->tags[tags->count].len = len;
847 tags->tags[tags->count].value = malloc(len + 1);
848 if (tags->tags[tags->count].value != NULL) {
849 memcpy(tags->tags[tags->count].value, value, len);
850 tags->tags[tags->count].value[len] = 0;
853 tags->tags[tags->count].value = strdup(value);
856 if (!tags->tags[tags->count].item || !tags->tags[tags->count].value) {
857 if (!tags->tags[tags->count].item)
858 free(tags->tags[tags->count].item);
859 if (!tags->tags[tags->count].value)
860 free(tags->tags[tags->count].value);
861 tags->tags[tags->count].item = NULL;
862 tags->tags[tags->count].value = NULL;
863 tags->tags[tags->count].len = 0;
872 static const char *ID3v1GenreList[] = {
873 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
874 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
875 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
876 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
877 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
878 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
879 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
880 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
881 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
882 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
883 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
884 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
885 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
886 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
887 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
888 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
889 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
890 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
891 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
892 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
893 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
894 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
895 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
896 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
897 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
898 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
899 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
900 "Anime", "JPop", "SynthPop",
903 const char *mp4ff_meta_index_to_genre(uint32_t idx)
905 if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
906 return ID3v1GenreList[idx - 1];
912 char *mp4ff_read_string(mp4ff_t * f, uint32_t length)
914 char *str = (char *) malloc(length + 1);
916 if ((uint32_t) mp4ff_read_data(f, str, length) != length) {
926 static int32_t mp4ff_set_metadata_name(const uint8_t atom_type, char **name)
928 static char *tag_names[] = {
929 "unknown", "title", "artist", "writer", "album",
930 "date", "tool", "comment", "genre", "track",
931 "disc", "compilation", "genre", "tempo", "cover",
932 "album_artist", "contentgroup", "lyrics", "description",
933 "network", "show", "episodename",
934 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
935 "sortwriter", "sortshow",
936 "season", "episode", "podcast"
971 case ATOM_COMPILATION:
983 case ATOM_ALBUM_ARTIST:
986 case ATOM_CONTENTGROUP:
992 case ATOM_DESCRIPTION:
1001 case ATOM_EPISODENAME:
1004 case ATOM_SORTTITLE:
1007 case ATOM_SORTALBUM:
1010 case ATOM_SORTARTIST:
1013 case ATOM_SORTALBUMARTIST:
1016 case ATOM_SORTWRITER:
1036 *name = strdup(tag_names[tag_idx]);
1041 static int32_t mp4ff_parse_tag(mp4ff_t * f, const uint8_t parent_atom_type,
1045 uint8_t header_size = 0;
1046 uint64_t subsize, sumsize = 0;
1052 while (sumsize < size && !f->stream->read_error) { /* CVE-2017-9222 */
1054 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1055 destpos = mp4ff_position(f) + subsize - header_size;
1057 if (atom_type == ATOM_DATA) {
1058 mp4ff_read_char(f); /* version */
1059 mp4ff_read_int24(f); /* flags */
1060 mp4ff_read_int32(f); /* reserved */
1062 /* some need special attention */
1063 if (parent_atom_type == ATOM_GENRE2 || parent_atom_type == ATOM_TEMPO) {
1064 if (subsize - header_size >= 8 + 2) {
1065 uint16_t val = mp4ff_read_int16(f);
1067 if (parent_atom_type == ATOM_TEMPO) {
1072 mp4ff_tag_add_field(&(f-> tags), "tempo", temp, -1);
1074 const char *temp = mp4ff_meta_index_to_genre(val);
1076 mp4ff_tag_add_field (&(f->tags), "genre", temp, -1);
1081 } else if (parent_atom_type == ATOM_TRACK || parent_atom_type == ATOM_DISC) {
1082 /* if (!done && subsize - header_size >= 8 + 8) */
1083 /* modified by AJS */
1084 if (!done && (subsize - header_size) >= (sizeof (char) + sizeof (uint8_t) * 3 + sizeof (uint32_t) + /* version + flags + reserved */
1085 +(parent_atom_type == ATOM_TRACK ? sizeof (uint16_t) : 0) /* leading uint16_t if ATOM_TRACK */
1086 +sizeof (uint16_t) /* track / disc */
1087 +sizeof (uint16_t)) /* totaltracks / totaldiscs */) {
1088 uint16_t index, total;
1090 mp4ff_read_int16(f);
1091 index = mp4ff_read_int16(f);
1092 total = mp4ff_read_int16(f);
1093 if (parent_atom_type == ATOM_TRACK)
1094 mp4ff_read_int16(f);
1096 sprintf(temp, "%d", index);
1097 mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ?
1098 "track" : "disc", temp, -1);
1102 mp4ff_tag_add_field(& (f-> tags),
1103 parent_atom_type == ATOM_TRACK?
1104 "totaltracks" : "totaldiscs", temp, -1);
1113 data = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 8)));
1114 len = (uint32_t) (subsize - (header_size + 8));
1116 } else if (atom_type == ATOM_NAME) {
1118 mp4ff_read_char(f); /* version */
1119 mp4ff_read_int24(f); /* flags */
1122 name = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 4)));
1125 mp4ff_set_position(f, destpos);
1133 mp4ff_set_metadata_name(parent_atom_type, &name);
1135 mp4ff_tag_add_field(&(f->tags), name, data, len);
1144 static int32_t mp4ff_read_mdhd(mp4ff_t * f)
1149 if (f->total_tracks == 0)
1152 version = mp4ff_read_int32(f);
1154 mp4ff_read_int64(f); //creation-time
1155 mp4ff_read_int64(f); //modification-time
1156 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1157 f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f); //duration
1158 } else //version == 0
1162 mp4ff_read_int32(f); //creation-time
1163 mp4ff_read_int32(f); //modification-time
1164 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1165 temp = mp4ff_read_int32(f);
1166 f->track[f->total_tracks - 1]->duration = (temp == (uint32_t) (-1)) ? (uint64_t) (-1) : (uint64_t) (temp);
1168 mp4ff_read_int16(f);
1169 mp4ff_read_int16(f);
1173 int32_t mp4ff_parse_metadata(mp4ff_t * f, const int32_t size)
1175 uint64_t subsize, sumsize = 0;
1177 uint8_t header_size = 0;
1179 while (sumsize < size) {
1180 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1183 mp4ff_parse_tag(f, atom_type,
1184 (uint32_t) (subsize - header_size));
1191 static int32_t mp4ff_read_meta(mp4ff_t * f, const uint64_t size)
1193 uint64_t subsize, sumsize = 0;
1195 uint8_t header_size = 0;
1197 mp4ff_read_char(f); /* version */
1198 mp4ff_read_int24(f); /* flags */
1200 while (sumsize < (size - (header_size + 4))) {
1201 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1202 if (subsize <= header_size + 4)
1204 if (atom_type == ATOM_ILST) {
1205 mp4ff_parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1207 mp4ff_set_position(f, mp4ff_position(f) + subsize - header_size);
1215 int32_t mp4ff_atom_read(mp4ff_t * f, const int32_t size,
1216 const uint8_t atom_type)
1218 uint64_t dest_position = mp4ff_position(f) + size - 8;
1219 if (atom_type == ATOM_STSZ) {
1220 /* sample size box */
1222 } else if (atom_type == ATOM_STTS) {
1223 /* time to sample box */
1225 } else if (atom_type == ATOM_CTTS) {
1226 /* composition offset box */
1228 } else if (atom_type == ATOM_STSC) {
1229 /* sample to chunk box */
1231 } else if (atom_type == ATOM_STCO) {
1232 /* chunk offset box */
1234 } else if (atom_type == ATOM_STSD) {
1235 /* sample description box */
1237 } else if (atom_type == ATOM_MVHD) {
1238 /* movie header box */
1240 } else if (atom_type == ATOM_MDHD) {
1244 } else if (atom_type == ATOM_META) {
1245 /* iTunes Metadata box */
1246 mp4ff_read_meta(f, size);
1250 mp4ff_set_position(f, dest_position);
1254 /* parse atoms that are sub atoms of other atoms */
1255 int32_t parse_sub_atoms(mp4ff_t * f, const uint64_t total_size, int meta_only)
1258 uint8_t atom_type = 0;
1259 uint64_t counted_size = 0;
1260 uint8_t header_size = 0;
1262 while (counted_size < total_size) {
1263 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
1264 counted_size += size;
1266 /* check for end of file */
1270 /* we're starting to read a new track, update index,
1271 * so that all data and tables get written in the right place
1273 if (atom_type == ATOM_TRAK) {
1277 /* parse subatoms */
1278 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1279 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1280 } else if (atom_type < SUBATOMIC) {
1281 parse_sub_atoms(f, size - header_size, meta_only);
1283 mp4ff_atom_read(f, (uint32_t) size, atom_type);
1290 /* parse root atoms */
1291 int32_t parse_atoms(mp4ff_t * f, int meta_only)
1294 uint8_t atom_type = 0;
1295 uint8_t header_size = 0;
1298 f->stream->read_error = 0;
1301 mp4ff_atom_read_header(f, &atom_type, &header_size)) != 0) {
1302 f->file_size += size;
1303 f->last_atom = atom_type;
1305 if (atom_type == ATOM_MDAT && f->moov_read) {
1306 /* moov atom is before mdat, we can stop reading when mdat is encountered */
1307 /* file position will stay at beginning of mdat data */
1311 if (atom_type == ATOM_MOOV && size > header_size) {
1313 f->moov_offset = mp4ff_position(f) - header_size;
1314 f->moov_size = size;
1317 /* parse subatoms */
1318 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1319 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1320 } else if (atom_type < SUBATOMIC) {
1321 parse_sub_atoms(f, size - header_size, meta_only);
1323 /* skip this atom */
1324 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1331 void mp4ff_get_decoder_config(const mp4ff_t * f, const int track,
1332 unsigned char **ppBuf, unsigned int *pBufSize)
1334 if (track >= f->total_tracks) {
1340 if (f->track[track]->decoderConfig == NULL
1341 || f->track[track]->decoderConfigLen == 0) {
1345 *ppBuf = malloc(f->track[track]->decoderConfigLen);
1346 if (*ppBuf == NULL) {
1350 memcpy(*ppBuf, f->track[track]->decoderConfig,
1351 f->track[track]->decoderConfigLen);
1352 *pBufSize = f->track[track]->decoderConfigLen;
1356 mp4ff_t *mp4ff_open_read(mp4ff_callback_t * f)
1358 mp4ff_t *ff = malloc(sizeof (mp4ff_t));
1360 memset(ff, 0, sizeof (mp4ff_t));
1374 int32_t mp4ff_tag_delete(mp4ff_metadata_t * tags)
1378 for (i = 0; i < tags->count; i++) {
1379 if (tags->tags[i].item)
1380 free(tags->tags[i].item);
1381 if (tags->tags[i].value)
1382 free(tags->tags[i].value);
1394 void mp4ff_close(mp4ff_t * ff)
1398 for (i = 0; i < ff->total_tracks; i++) {
1400 if (ff->track[i]->stsz_table)
1401 free(ff->track[i]->stsz_table);
1402 if (ff->track[i]->stts_sample_count)
1403 free(ff->track[i]->stts_sample_count);
1404 if (ff->track[i]->stts_sample_delta)
1405 free(ff->track[i]->stts_sample_delta);
1406 if (ff->track[i]->stsc_first_chunk)
1407 free(ff->track[i]->stsc_first_chunk);
1408 if (ff->track[i]->stsc_samples_per_chunk)
1409 free(ff->track[i]->stsc_samples_per_chunk);
1410 if (ff->track[i]->stsc_sample_desc_index)
1411 free(ff->track[i]->stsc_sample_desc_index);
1412 if (ff->track[i]->stco_chunk_offset)
1413 free(ff->track[i]->stco_chunk_offset);
1414 if (ff->track[i]->decoderConfig)
1415 free(ff->track[i]->decoderConfig);
1416 if (ff->track[i]->ctts_sample_count)
1417 free(ff->track[i]->ctts_sample_count);
1418 if (ff->track[i]->ctts_sample_offset)
1419 free(ff->track[i]->ctts_sample_offset);
1421 if (ff->track[i]->p_drms)
1422 drms_free(ff->track[i]->p_drms);
1429 mp4ff_tag_delete(&(ff->tags));
1436 static int32_t mp4ff_chunk_of_sample(const mp4ff_t * f, const int32_t track,
1437 const int32_t sample, int32_t * chunk_sample, int32_t * chunk)
1439 int32_t total_entries = 0;
1440 int32_t chunk2entry;
1441 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1445 if (f->track[track] == NULL) {
1449 total_entries = f->track[track]->stsc_entry_count;
1456 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1457 *chunk = chunk2 - chunk1;
1458 range_samples = *chunk * chunk1samples;
1460 if (sample < total + range_samples)
1463 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1466 if (chunk2entry < total_entries) {
1468 total += range_samples;
1470 } while (chunk2entry < total_entries);
1473 *chunk = (sample - total) / chunk1samples + chunk1;
1477 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1482 static int32_t mp4ff_chunk_to_offset(const mp4ff_t * f, const int32_t track,
1483 const int32_t chunk)
1485 const mp4ff_track_t *p_track = f->track[track];
1487 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1488 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1490 } else if (p_track->stco_entry_count) {
1491 return p_track->stco_chunk_offset[chunk - 1];
1499 static int32_t mp4ff_sample_range_size(const mp4ff_t * f, const int32_t track,
1500 const int32_t chunk_sample, const int32_t sample)
1503 const mp4ff_track_t *p_track = f->track[track];
1505 if (p_track->stsz_sample_size) {
1506 return (sample - chunk_sample) * p_track->stsz_sample_size;
1508 if (sample >= p_track->stsz_sample_count)
1511 for (i = chunk_sample, total = 0; i < sample; i++) {
1512 total += p_track->stsz_table[i];
1518 static int32_t mp4ff_sample_to_offset(const mp4ff_t * f, const int32_t track,
1519 const int32_t sample)
1521 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1523 mp4ff_chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1525 chunk_offset1 = mp4ff_chunk_to_offset(f, track, chunk);
1526 chunk_offset2 = chunk_offset1 + mp4ff_sample_range_size(f,
1527 track, chunk_sample, sample);
1528 return chunk_offset2;
1531 int32_t mp4ff_set_sample_position(mp4ff_t * f, const int32_t track,
1532 const int32_t sample)
1536 offset = mp4ff_sample_to_offset(f, track, sample);
1537 mp4ff_set_position(f, offset);
1542 int32_t mp4ff_audio_frame_size(const mp4ff_t * f, const int32_t track,
1543 const int32_t sample)
1546 const mp4ff_track_t *p_track = f->track[track];
1548 if (p_track->stsz_sample_size) {
1549 bytes = p_track->stsz_sample_size;
1551 bytes = p_track->stsz_table[sample];
1557 int32_t mp4ff_read_sample_getsize(mp4ff_t * f, const int track,
1560 int32_t temp = mp4ff_audio_frame_size(f, track, sample);
1566 uint32_t mp4ff_get_sample_rate(const mp4ff_t * f, const int32_t track)
1568 return f->track[track]->sampleRate;
1571 uint32_t mp4ff_get_channel_count(const mp4ff_t * f, const int32_t track)
1573 return f->track[track]->channelCount;
1576 int32_t mp4ff_num_samples(const mp4ff_t * f, const int32_t track)
1581 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1582 total += f->track[track]->stts_sample_count[i];
1587 mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t * f)
1589 mp4ff_t *ff = malloc(sizeof (mp4ff_t));
1591 memset(ff, 0, sizeof (mp4ff_t));
1605 int32_t mp4ff_meta_get_num_items(const mp4ff_t * f)
1607 return f->tags.count;
1610 int32_t mp4ff_meta_get_by_index(const mp4ff_t * f, uint32_t index,
1611 char **item, char **value)
1613 if (index >= f->tags.count) {
1618 *item = strdup(f->tags.tags[index].item);
1619 *value = strdup(f->tags.tags[index].value);
1624 static uint32_t find_atom(mp4ff_t * f, uint64_t base, uint32_t size,
1627 uint32_t remaining = size;
1628 uint64_t atom_offset = base;
1633 mp4ff_set_position(f, atom_offset);
1637 atom_size = mp4ff_read_int32(f);
1638 if (atom_size > remaining || atom_size < 8)
1640 mp4ff_read_data(f, atom_name, 4);
1642 if (!memcmp(atom_name, name, 4)) {
1643 mp4ff_set_position(f, atom_offset);
1647 remaining -= atom_size;
1648 atom_offset += atom_size;
1652 static uint32_t find_atom_v2(mp4ff_t * f, uint64_t base, uint32_t size,
1653 const char *name, uint32_t extraheaders, const char *name_inside)
1655 uint64_t first_base = (uint64_t) (-1);
1656 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1658 uint64_t mybase = mp4ff_position(f);
1659 uint32_t mysize = mp4ff_read_int32(f);
1661 if (first_base == (uint64_t) (-1))
1662 first_base = mybase;
1664 if (mysize < 8 + extraheaders)
1667 if (find_atom (f, mybase + (8 + extraheaders),
1668 mysize - (8 + extraheaders), name_inside)) {
1669 mp4ff_set_position(f, mybase);
1673 if (size <= mysize) {
1680 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1682 mp4ff_set_position(f, first_base);
1695 #define stricmp strcasecmp
1697 membuffer *membuffer_create(void)
1699 const unsigned initial_size = 256;
1701 membuffer *buf = (membuffer *) malloc(sizeof (membuffer));
1702 buf->data = malloc(initial_size);
1704 buf->allocated = initial_size;
1705 buf->error = buf->data == 0 ? 1 : 0;
1710 unsigned membuffer_write(membuffer * buf, const void *ptr, unsigned bytes)
1712 unsigned dest_size = buf->written + bytes;
1716 if (dest_size > buf->allocated) {
1718 buf->allocated <<= 1;
1719 } while (dest_size > buf->allocated);
1722 void *newptr = realloc(buf->data, buf->allocated);
1734 memcpy((char *) buf->data + buf->written, ptr, bytes);
1735 buf->written += bytes;
1739 #define membuffer_write_data membuffer_write
1741 unsigned membuffer_write_atom_name(membuffer * buf, const char *data)
1743 return membuffer_write_data(buf, data, 4) == 4 ? 1 : 0;
1746 unsigned membuffer_write_int16(membuffer * buf, uint16_t data)
1748 uint8_t temp[2] = { (uint8_t) (data >> 8), (uint8_t) data };
1749 return membuffer_write_data(buf, temp, 2);
1752 unsigned membuffer_write_int32(membuffer * buf, uint32_t data)
1754 uint8_t temp[4] = { (uint8_t) (data >> 24), (uint8_t) (data >> 16),
1755 (uint8_t) (data >> 8), (uint8_t) data };
1756 return membuffer_write_data(buf, temp, 4);
1759 static void membuffer_write_track_tag(membuffer * buf, const char *name,
1760 uint32_t index, uint32_t total)
1762 membuffer_write_int32(buf,
1763 8 /*atom header */ + 8 /*data atom header */ +
1764 8 /*flags + reserved */ + 8 /*actual data */ );
1765 membuffer_write_atom_name(buf, name);
1766 membuffer_write_int32(buf,
1767 8 /*data atom header */ +
1768 8 /*flags + reserved */ + 8 /*actual data */ );
1769 membuffer_write_atom_name(buf, "data");
1770 membuffer_write_int32(buf, 0); //flags
1771 membuffer_write_int32(buf, 0); //reserved
1772 membuffer_write_int16(buf, 0);
1773 membuffer_write_int16(buf, (uint16_t) index); //track number
1774 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1775 membuffer_write_int16(buf, 0);
1778 static void membuffer_write_int16_tag(membuffer * buf, const char *name,
1781 membuffer_write_int32(buf,
1782 8 /*atom header */ + 8 /*data atom header */ +
1783 8 /*flags + reserved */ + 2 /*actual data */ );
1784 membuffer_write_atom_name(buf, name);
1785 membuffer_write_int32(buf,
1786 8 /*data atom header */ +
1787 8 /*flags + reserved */ + 2 /*actual data */ );
1788 membuffer_write_atom_name(buf, "data");
1789 membuffer_write_int32(buf, 0); //flags
1790 membuffer_write_int32(buf, 0); //reserved
1791 membuffer_write_int16(buf, value); //value
1794 static uint32_t myatoi(const char *param)
1796 return param ? atoi(param) : 0;
1799 uint32_t mp4ff_meta_genre_to_index(const char *genrestr)
1802 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1803 if (!stricmp(genrestr, ID3v1GenreList[n]))
1814 static stdmeta_entry stdmetas[] = {
1815 {"\xA9" "nam", "title"},
1816 {"\xA9" "ART", "artist"},
1817 {"\xA9" "wrt", "writer"},
1818 {"\xA9" "alb", "album"},
1819 {"\xA9" "day", "date"},
1820 {"\xA9" "too", "tool"},
1821 {"\xA9" "cmt", "comment"},
1822 // {"\xA9" "gen","genre"},
1823 {"cpil", "compilation"},
1824 // {"trkn","track"},
1826 // {"gnre","genre"},
1829 {"aART", "album_artist"},
1832 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1835 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1836 if (!stricmp(name, stdmetas[n].name))
1837 return stdmetas[n].atom;
1842 static void membuffer_write_std_tag(membuffer * buf, const char *name,
1848 /* special check for compilation flag */
1849 if (strcmp(name, "cpil") == 0) {
1853 membuffer_write_int32(buf,
1854 8 /*atom header */ + 8 /*data atom header */ +
1855 8 /*flags + reserved */ + strlen(value));
1856 membuffer_write_atom_name(buf, name);
1857 membuffer_write_int32(buf,
1858 8 /*data atom header */ +
1859 8 /*flags + reserved */ + strlen(value));
1860 membuffer_write_atom_name(buf, "data");
1861 membuffer_write_int32(buf, flags); //flags
1862 membuffer_write_int32(buf, 0); //reserved
1863 membuffer_write_data(buf, value, strlen(value));
1866 static void membuffer_write_custom_tag(membuffer * buf, const char *name,
1869 membuffer_write_int32(buf,
1870 8 /*atom header */ +
1871 0x1C /*weirdo itunes atom */ +
1872 12 /*name atom header */ + strlen(name) +
1873 16 /*data atom header + flags */ + strlen(value));
1874 membuffer_write_atom_name(buf, "----");
1875 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1876 membuffer_write_atom_name(buf, "mean");
1877 membuffer_write_int32(buf, 0);
1878 membuffer_write_data(buf, "com.apple.iTunes", 16);
1879 membuffer_write_int32(buf, 12 + strlen(name));
1880 membuffer_write_atom_name(buf, "name");
1881 membuffer_write_int32(buf, 0);
1882 membuffer_write_data(buf, name, strlen(name));
1883 membuffer_write_int32(buf,
1884 8 /*data atom header */ +
1885 8 /*flags + reserved */ + strlen(value));
1886 membuffer_write_atom_name(buf, "data");
1887 membuffer_write_int32(buf, 1); //flags
1888 membuffer_write_int32(buf, 0); //reserved
1889 membuffer_write_data(buf, value, strlen(value));
1892 unsigned membuffer_error(const membuffer * buf)
1897 void membuffer_free(membuffer * buf)
1904 unsigned membuffer_get_size(const membuffer * buf)
1906 return buf->written;
1909 void *membuffer_detach(membuffer * buf)
1916 ret = realloc(buf->data, buf->written);
1927 static uint32_t create_ilst(const mp4ff_metadata_t * data, void **out_buffer,
1928 uint32_t * out_size)
1930 membuffer *buf = membuffer_create();
1932 char *mask = (char *) malloc(data->count);
1933 memset(mask, 0, data->count);
1936 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1937 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1938 const char *genre_ptr = 0, *tempo_ptr = 0;
1939 for (metaptr = 0; metaptr < data->count; metaptr++) {
1940 mp4ff_tag_t *tag = &data->tags[metaptr];
1941 if (!stricmp(tag->item, "tracknumber") || !stricmp(tag->item, "track")) {
1942 if (tracknumber_ptr == 0)
1943 tracknumber_ptr = tag->value;
1945 } else if (!stricmp(tag->item, "totaltracks")) {
1946 if (totaltracks_ptr == 0)
1947 totaltracks_ptr = tag->value;
1949 } else if (!stricmp(tag->item, "discnumber")
1950 || !stricmp(tag->item, "disc")) {
1951 if (discnumber_ptr == 0)
1952 discnumber_ptr = tag->value;
1954 } else if (!stricmp(tag->item, "totaldiscs")) {
1955 if (totaldiscs_ptr == 0)
1956 totaldiscs_ptr = tag->value;
1958 } else if (!stricmp(tag->item, "genre")) {
1960 genre_ptr = tag->value;
1962 } else if (!stricmp(tag->item, "tempo")) {
1964 tempo_ptr = tag->value;
1970 if (tracknumber_ptr)
1971 membuffer_write_track_tag(buf, "trkn",
1972 myatoi(tracknumber_ptr),
1973 myatoi(totaltracks_ptr));
1975 membuffer_write_track_tag(buf, "disk",
1976 myatoi(discnumber_ptr),
1977 myatoi(totaldiscs_ptr));
1979 membuffer_write_int16_tag(buf, "tmpo",
1980 (uint16_t) myatoi(tempo_ptr));
1983 uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
1985 membuffer_write_std_tag(buf, "©gen",
1988 membuffer_write_int16_tag(buf, "gnre",
1993 for (metaptr = 0; metaptr < data->count; metaptr++) {
1994 if (!mask[metaptr]) {
1995 mp4ff_tag_t *tag = &data->tags[metaptr];
1996 const char *std_meta_atom = find_standard_meta(tag->item);
1997 if (std_meta_atom) {
1998 membuffer_write_std_tag(buf, std_meta_atom,
2001 membuffer_write_custom_tag(buf, tag->item,
2009 if (membuffer_error(buf)) {
2010 membuffer_free(buf);
2014 *out_size = membuffer_get_size(buf);
2015 *out_buffer = membuffer_detach(buf);
2016 membuffer_free(buf);
2021 void membuffer_write_atom(membuffer * buf, const char *name, unsigned size,
2024 membuffer_write_int32(buf, size + 8);
2025 membuffer_write_atom_name(buf, name);
2026 membuffer_write_data(buf, data, size);
2029 void *membuffer_get_ptr(const membuffer * buf)
2034 void membuffer_set_error(membuffer * buf)
2039 unsigned membuffer_transfer_from_file(membuffer * buf, mp4ff_t * src,
2045 oldsize = membuffer_get_size(buf);
2046 if (membuffer_write_data(buf, 0, bytes) != bytes)
2049 bufptr = membuffer_get_ptr(buf);
2053 if ((unsigned) mp4ff_read_data(src, (char *) bufptr + oldsize, bytes) !=
2055 membuffer_set_error(buf);
2062 static uint32_t create_meta(const mp4ff_metadata_t * data, void **out_buffer,
2063 uint32_t * out_size)
2069 if (!create_ilst(data, &ilst_buffer, &ilst_size))
2072 buf = membuffer_create();
2074 membuffer_write_int32(buf, 0);
2075 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
2078 *out_size = membuffer_get_size(buf);
2079 *out_buffer = membuffer_detach(buf);
2080 membuffer_free(buf);
2084 static uint32_t create_udta(const mp4ff_metadata_t * data, void **out_buffer,
2085 uint32_t * out_size)
2091 if (!create_meta(data, &meta_buffer, &meta_size))
2094 buf = membuffer_create();
2096 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
2100 *out_size = membuffer_get_size(buf);
2101 *out_buffer = membuffer_detach(buf);
2102 membuffer_free(buf);
2106 static uint32_t fix_byte_order_32(uint32_t src)
2109 uint32_t a, b, c, d;
2112 memcpy(data, &src, sizeof (src));
2113 a = (uint8_t) data[0];
2114 b = (uint8_t) data[1];
2115 c = (uint8_t) data[2];
2116 d = (uint8_t) data[3];
2118 result = (a << 24) | (b << 16) | (c << 8) | d;
2119 return (uint32_t) result;
2122 static uint32_t modify_moov(mp4ff_t * f, const mp4ff_metadata_t * data,
2123 void **out_buffer, uint32_t * out_size)
2125 uint64_t total_base = f->moov_offset + 8;
2126 uint32_t total_size = (uint32_t) (f->moov_size - 8);
2128 uint64_t udta_offset, meta_offset, ilst_offset;
2129 uint32_t udta_size, meta_size, ilst_size;
2131 uint32_t new_ilst_size;
2132 void *new_ilst_buffer;
2137 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
2139 void *new_udta_buffer;
2140 uint32_t new_udta_size;
2141 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
2144 buf = membuffer_create();
2145 mp4ff_set_position(f, total_base);
2146 membuffer_transfer_from_file(buf, f, total_size);
2148 membuffer_write_atom(buf, "udta", new_udta_size,
2151 free(new_udta_buffer);
2153 *out_size = membuffer_get_size(buf);
2154 *out_buffer = membuffer_detach(buf);
2155 membuffer_free(buf);
2158 udta_offset = mp4ff_position(f);
2159 udta_size = mp4ff_read_int32(f);
2160 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
2162 void *new_meta_buffer;
2163 uint32_t new_meta_size;
2164 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
2167 buf = membuffer_create();
2168 mp4ff_set_position(f, total_base);
2169 membuffer_transfer_from_file(buf, f,
2170 (uint32_t)(udta_offset - total_base));
2172 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2173 membuffer_write_atom_name(buf, "udta");
2174 membuffer_transfer_from_file(buf, f, udta_size);
2176 membuffer_write_atom(buf, "meta", new_meta_size,
2178 free(new_meta_buffer);
2180 *out_size = membuffer_get_size(buf);
2181 *out_buffer = membuffer_detach(buf);
2182 membuffer_free(buf);
2185 meta_offset = mp4ff_position(f);
2186 meta_size = mp4ff_read_int32(f);
2187 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2188 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2189 ilst_offset = mp4ff_position(f);
2190 ilst_size = mp4ff_read_int32(f);
2192 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2195 size_delta = new_ilst_size - (ilst_size - 8);
2197 *out_size = total_size + size_delta;
2198 *out_buffer = malloc(*out_size);
2199 if (*out_buffer == 0) {
2200 free(new_ilst_buffer);
2204 p_out = (uint8_t *) * out_buffer;
2206 mp4ff_set_position(f, total_base);
2207 mp4ff_read_data(f, p_out,
2208 (uint32_t) (udta_offset - total_base));
2209 p_out += (uint32_t) (udta_offset - total_base);
2210 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2212 mp4ff_read_data(f, p_out, 4);
2214 mp4ff_read_data(f, p_out,
2215 (uint32_t) (meta_offset - udta_offset - 8));
2216 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2217 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2219 mp4ff_read_data(f, p_out, 4);
2221 mp4ff_read_data(f, p_out,
2222 (uint32_t) (ilst_offset - meta_offset - 8));
2223 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2224 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2226 mp4ff_read_data(f, p_out, 4);
2229 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2230 p_out += new_ilst_size;
2232 mp4ff_set_position(f, ilst_offset + ilst_size);
2233 mp4ff_read_data(f, p_out, (uint32_t) (total_size
2234 - (ilst_offset - total_base) - ilst_size));
2236 free(new_ilst_buffer);
2241 int32_t mp4ff_write_data(mp4ff_t * f, void *data, uint32_t size)
2245 result = f->stream->write(f->stream->user_data, data, size);
2247 f->current_position += size;
2252 int32_t mp4ff_write_int32(mp4ff_t * f, const uint32_t data)
2255 uint32_t a, b, c, d;
2258 *(uint32_t *) temp = data;
2259 a = (uint8_t) temp[0];
2260 b = (uint8_t) temp[1];
2261 c = (uint8_t) temp[2];
2262 d = (uint8_t) temp[3];
2264 result = (a << 24) | (b << 16) | (c << 8) | d;
2266 return mp4ff_write_data(f, (uint8_t *) & result, sizeof (result));
2269 int32_t mp4ff_truncate(mp4ff_t * f)
2271 return f->stream->truncate(f->stream->user_data);
2274 int32_t mp4ff_meta_update(mp4ff_callback_t * f, const mp4ff_metadata_t * data)
2276 void *new_moov_data;
2277 uint32_t new_moov_size;
2279 mp4ff_t *ff = malloc(sizeof (mp4ff_t));
2281 memset(ff, 0, sizeof (mp4ff_t));
2283 mp4ff_set_position(ff, 0);
2287 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2292 /* copy moov atom to end of the file */
2293 if (ff->last_atom != ATOM_MOOV) {
2294 char *free_data = "free";
2296 /* rename old moov to free */
2297 mp4ff_set_position(ff, ff->moov_offset + 4);
2298 mp4ff_write_data(ff, free_data, 4);
2300 mp4ff_set_position(ff, ff->file_size);
2301 mp4ff_write_int32(ff, new_moov_size + 8);
2302 mp4ff_write_data(ff, "moov", 4);
2303 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2305 mp4ff_set_position(ff, ff->moov_offset);
2306 mp4ff_write_int32(ff, new_moov_size + 8);
2307 mp4ff_write_data(ff, "moov", 4);
2308 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2317 /* find a metadata item by name */
2318 /* returns 0 if item found, 1 if no such item */
2319 static int32_t mp4ff_meta_find_by_name(const mp4ff_t * f, const char *item,
2324 for (i = 0; i < f->tags.count; i++) {
2325 if (!stricmp(f->tags.tags[i].item, item)) {
2326 *value = strdup(f->tags.tags[i].value);
2337 int32_t mp4ff_meta_get_artist(const mp4ff_t * f, char **value)
2339 return mp4ff_meta_find_by_name(f, "artist", value);
2342 int32_t mp4ff_meta_get_title(const mp4ff_t * f, char **value)
2344 return mp4ff_meta_find_by_name(f, "title", value);
2347 int32_t mp4ff_meta_get_date(const mp4ff_t * f, char **value)
2349 return mp4ff_meta_find_by_name(f, "date", value);
2352 int32_t mp4ff_meta_get_album(const mp4ff_t * f, char **value)
2354 return mp4ff_meta_find_by_name(f, "album", value);
2357 int32_t mp4ff_meta_get_comment(const mp4ff_t * f, char **value)
2359 return mp4ff_meta_find_by_name(f, "comment", value);