2 * Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com
3 * FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
11 int32_t mp4ff_total_tracks(const mp4ff_t * f)
13 return f->total_tracks;
16 static int32_t mp4ff_read_data(mp4ff_t * f, void *data, uint32_t size)
20 result = f->stream->read(f->stream->user_data, data, size);
23 f->stream->read_error++;
25 f->current_position += size;
30 /* parse atom header size */
31 static int32_t mp4ff_atom_get_size(const int8_t * data)
36 a = (uint8_t) data[0];
37 b = (uint8_t) data[1];
38 c = (uint8_t) data[2];
39 d = (uint8_t) data[3];
41 result = (a << 24) | (b << 16) | (c << 8) | d;
42 return (int32_t) result;
45 static uint64_t mp4ff_read_int64(mp4ff_t * f)
51 mp4ff_read_data(f, data, 8);
53 for (i = 0; i < 8; i++) {
54 result |= ((uint64_t) data[i]) << ((7 - i) * 8);
60 /* comnapre 2 atom names, returns 1 for equal, 0 for unequal */
61 static int32_t mp4ff_atom_compare(const int8_t a1, const int8_t b1,
62 const int8_t c1, const int8_t d1,
63 const int8_t a2, const int8_t b2,
64 const int8_t c2, const int8_t d2)
66 if (a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2)
74 #define TRACK_SYSTEM 3
75 #define TRACK_UNKNOWN 0
77 /* atoms with subatoms */
85 #define ATOM_ILST 8 /* iTunes Metadata list */
87 #define ATOM_ARTIST 10
88 #define ATOM_WRITER 11
92 #define ATOM_COMMENT 15
93 #define ATOM_GENRE1 16
96 #define ATOM_COMPILATION 19
97 #define ATOM_GENRE2 20
104 #define SUBATOMIC 128
106 /* atoms without subatoms */
107 #define ATOM_FTYP 129
108 #define ATOM_MDAT 130
109 #define ATOM_MVHD 131
110 #define ATOM_TKHD 132
111 #define ATOM_TREF 133
112 #define ATOM_MDHD 134
113 #define ATOM_VMHD 135
114 #define ATOM_SMHD 136
115 #define ATOM_HMHD 137
116 #define ATOM_STSD 138
117 #define ATOM_STTS 139
118 #define ATOM_STSZ 140
119 #define ATOM_STZ2 141
120 #define ATOM_STCO 142
121 #define ATOM_STSC 143
122 #define ATOM_MP4A 144
123 #define ATOM_MP4V 145
124 #define ATOM_MP4S 146
125 #define ATOM_ESDS 147
126 #define ATOM_META 148 /* iTunes Metadata box */
127 #define ATOM_NAME 149 /* iTunes Metadata name box */
128 #define ATOM_DATA 150 /* iTunes Metadata data box */
129 #define ATOM_CTTS 151
130 #define ATOM_FRMA 152
131 #define ATOM_IVIV 153
132 #define ATOM_PRIV 154
133 #define ATOM_USER 155
135 #define ATOM_ALBUM_ARTIST 157
136 #define ATOM_CONTENTGROUP 158
137 #define ATOM_LYRICS 159
138 #define ATOM_DESCRIPTION 160
139 #define ATOM_NETWORK 161
140 #define ATOM_SHOW 162
141 #define ATOM_EPISODENAME 163
142 #define ATOM_SORTTITLE 164
143 #define ATOM_SORTALBUM 165
144 #define ATOM_SORTARTIST 166
145 #define ATOM_SORTALBUMARTIST 167
146 #define ATOM_SORTWRITER 168
147 #define ATOM_SORTSHOW 169
148 #define ATOM_SEASON 170
149 #define ATOM_EPISODE 171
150 #define ATOM_PODCAST 172
152 #define ATOM_UNKNOWN 255
153 #define ATOM_FREE ATOM_UNKNOWN
154 #define ATOM_SKIP ATOM_UNKNOWN
156 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
158 static uint8_t mp4ff_atom_name_to_type(const int8_t a, const int8_t b,
159 const int8_t c, const int8_t d)
162 if (mp4ff_atom_compare(a, b, c, d, 'm', 'o', 'o', 'v'))
164 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'i', 'n', 'f'))
166 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'd', 'i', 'a'))
168 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'd', 'a', 't'))
170 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'd', 'h', 'd'))
172 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'v', 'h', 'd'))
174 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'p', '4', 'a'))
176 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'p', '4', 'v'))
178 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'p', '4', 's'))
180 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'e', 't', 'a'))
182 } else if (a == 't') {
183 if (mp4ff_atom_compare(a, b, c, d, 't', 'r', 'a', 'k'))
185 else if (mp4ff_atom_compare(a, b, c, d, 't', 'k', 'h', 'd'))
187 else if (mp4ff_atom_compare(a, b, c, d, 't', 'r', 'e', 'f'))
189 else if (mp4ff_atom_compare(a, b, c, d, 't', 'r', 'k', 'n'))
191 else if (mp4ff_atom_compare(a, b, c, d, 't', 'm', 'p', 'o'))
193 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 'n', 'n'))
195 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 's', 'h'))
197 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 'e', 'n'))
198 return ATOM_EPISODENAME;
199 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 's', 'n'))
201 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 'e', 's'))
203 } else if (a == 's') {
204 if (mp4ff_atom_compare(a, b, c, d, 's', 't', 'b', 'l'))
206 else if (mp4ff_atom_compare(a, b, c, d, 's', 'm', 'h', 'd'))
208 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 's', 'd'))
210 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 't', 's'))
212 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 'c', 'o'))
214 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 's', 'c'))
216 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 's', 'z'))
218 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 'z', '2'))
220 else if (mp4ff_atom_compare(a, b, c, d, 's', 'k', 'i', 'p'))
222 else if (mp4ff_atom_compare(a, b, c, d, 's', 'i', 'n', 'f'))
224 else if (mp4ff_atom_compare(a, b, c, d, 's', 'c', 'h', 'i'))
226 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'n', 'm'))
227 return ATOM_SORTTITLE;
228 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'a', 'l'))
229 return ATOM_SORTALBUM;
230 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'a', 'r'))
231 return ATOM_SORTARTIST;
232 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'a', 'a'))
233 return ATOM_SORTALBUMARTIST;
234 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'c', 'o'))
235 return ATOM_SORTWRITER;
236 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 's', 'n'))
237 return ATOM_SORTSHOW;
238 } else if (a == COPYRIGHT_SYMBOL) {
239 if (mp4ff_atom_compare
240 (a, b, c, d, COPYRIGHT_SYMBOL, 'n', 'a', 'm'))
242 else if (mp4ff_atom_compare
243 (a, b, c, d, COPYRIGHT_SYMBOL, 'A', 'R', 'T'))
245 else if (mp4ff_atom_compare
246 (a, b, c, d, COPYRIGHT_SYMBOL, 'w', 'r', 't'))
248 else if (mp4ff_atom_compare
249 (a, b, c, d, COPYRIGHT_SYMBOL, 'a', 'l', 'b'))
251 else if (mp4ff_atom_compare
252 (a, b, c, d, COPYRIGHT_SYMBOL, 'd', 'a', 'y'))
254 else if (mp4ff_atom_compare
255 (a, b, c, d, COPYRIGHT_SYMBOL, 't', 'o', 'o'))
257 else if (mp4ff_atom_compare
258 (a, b, c, d, COPYRIGHT_SYMBOL, 'c', 'm', 't'))
260 else if (mp4ff_atom_compare
261 (a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'e', 'n'))
263 else if (mp4ff_atom_compare
264 (a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'r', 'p'))
265 return ATOM_CONTENTGROUP;
266 else if (mp4ff_atom_compare
267 (a, b, c, d, COPYRIGHT_SYMBOL, 'l', 'y', 'r'))
271 if (mp4ff_atom_compare(a, b, c, d, 'e', 'd', 't', 's'))
273 else if (mp4ff_atom_compare(a, b, c, d, 'e', 's', 'd', 's'))
275 else if (mp4ff_atom_compare(a, b, c, d, 'f', 't', 'y', 'p'))
277 else if (mp4ff_atom_compare(a, b, c, d, 'f', 'r', 'e', 'e'))
279 else if (mp4ff_atom_compare(a, b, c, d, 'h', 'm', 'h', 'd'))
281 else if (mp4ff_atom_compare(a, b, c, d, 'v', 'm', 'h', 'd'))
283 else if (mp4ff_atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
285 else if (mp4ff_atom_compare(a, b, c, d, 'i', 'l', 's', 't'))
287 else if (mp4ff_atom_compare(a, b, c, d, 'n', 'a', 'm', 'e'))
289 else if (mp4ff_atom_compare(a, b, c, d, 'd', 'a', 't', 'a'))
291 else if (mp4ff_atom_compare(a, b, c, d, 'd', 'i', 's', 'k'))
293 else if (mp4ff_atom_compare(a, b, c, d, 'g', 'n', 'r', 'e'))
295 else if (mp4ff_atom_compare(a, b, c, d, 'c', 'o', 'v', 'r'))
297 else if (mp4ff_atom_compare(a, b, c, d, 'c', 'p', 'i', 'l'))
298 return ATOM_COMPILATION;
299 else if (mp4ff_atom_compare(a, b, c, d, 'c', 't', 't', 's'))
301 else if (mp4ff_atom_compare(a, b, c, d, 'd', 'r', 'm', 's'))
303 else if (mp4ff_atom_compare(a, b, c, d, 'f', 'r', 'm', 'a'))
305 else if (mp4ff_atom_compare(a, b, c, d, 'p', 'r', 'i', 'v'))
307 else if (mp4ff_atom_compare(a, b, c, d, 'i', 'v', 'i', 'v'))
309 else if (mp4ff_atom_compare(a, b, c, d, 'u', 's', 'e', 'r'))
311 else if (mp4ff_atom_compare(a, b, c, d, 'k', 'e', 'y', ' '))
313 else if (mp4ff_atom_compare(a, b, c, d, 'a', 'A', 'R', 'T'))
314 return ATOM_ALBUM_ARTIST;
315 else if (mp4ff_atom_compare(a, b, c, d, 'd', 'e', 's', 'c'))
316 return ATOM_DESCRIPTION;
317 else if (mp4ff_atom_compare(a, b, c, d, 'p', 'c', 's', 't'))
323 /* read atom header, return atom size, atom size is with header included */
324 static uint64_t mp4ff_atom_read_header(mp4ff_t * f, uint8_t * atom_type,
325 uint8_t * header_size)
329 int8_t atom_header[8];
331 ret = mp4ff_read_data(f, atom_header, 8);
335 size = mp4ff_atom_get_size(atom_header);
338 /* check for 64 bit atom size */
341 size = mp4ff_read_int64(f);
343 *atom_type = mp4ff_atom_name_to_type(atom_header[4], atom_header[5],
344 atom_header[6], atom_header[7]);
348 static int64_t mp4ff_position(const mp4ff_t * f)
350 return f->current_position;
353 static int need_parse_when_meta_only(uint8_t atom_type)
374 static int32_t mp4ff_set_position(mp4ff_t * f, const int64_t position)
376 f->stream->seek(f->stream->user_data, position);
377 f->current_position = position;
382 static void mp4ff_track_add(mp4ff_t * f)
386 if (f->total_tracks > MAX_TRACKS) {
392 f->track[f->total_tracks - 1] = malloc(sizeof (mp4ff_track_t));
394 memset(f->track[f->total_tracks - 1], 0, sizeof (mp4ff_track_t));
397 static uint8_t mp4ff_read_char(mp4ff_t * f)
400 mp4ff_read_data(f, &output, 1);
404 static uint32_t mp4ff_read_int24(mp4ff_t * f)
410 mp4ff_read_data(f, data, 3);
411 a = (uint8_t) data[0];
412 b = (uint8_t) data[1];
413 c = (uint8_t) data[2];
415 result = (a << 16) | (b << 8) | c;
416 return (uint32_t) result;
419 static uint32_t mp4ff_read_int32(mp4ff_t * f)
425 mp4ff_read_data(f, data, 4);
426 a = (uint8_t) data[0];
427 b = (uint8_t) data[1];
428 c = (uint8_t) data[2];
429 d = (uint8_t) data[3];
431 result = (a << 24) | (b << 16) | (c << 8) | d;
432 return (uint32_t) result;
435 static int32_t mp4ff_read_stsz(mp4ff_t * f)
437 if (f->total_tracks == 0)
440 mp4ff_read_char(f); /* version */
441 mp4ff_read_int24(f); /* flags */
442 f->track[f->total_tracks - 1]->stsz_sample_size = mp4ff_read_int32(f);
443 f->track[f->total_tracks - 1]->stsz_sample_count = mp4ff_read_int32(f);
445 if (f->track[f->total_tracks - 1]->stsz_sample_size == 0) {
447 f->track[f->total_tracks - 1]->stsz_table =
448 (int32_t *)malloc(f->track[f->total_tracks - 1]->stsz_sample_count
451 if (!f->track[f->total_tracks - 1]->stsz_table)
454 for (i = 0; i < f->track[f->total_tracks - 1]->stsz_sample_count
455 && !f->stream->read_error; i++) {
456 f->track[f->total_tracks - 1]->stsz_table[i] = mp4ff_read_int32(f);
462 static int32_t mp4ff_read_stts(mp4ff_t * f)
465 mp4ff_track_t *p_track;
468 if (f->total_tracks == 0)
471 p_track = f->track[f->total_tracks - 1];
473 if (p_track->stts_entry_count)
476 mp4ff_read_char(f); /* version */
477 mp4ff_read_int24(f); /* flags */
478 p_track->stts_entry_count = mp4ff_read_int32(f);
480 p_track->stts_sample_count = (int32_t *)malloc(p_track->stts_entry_count
482 p_track->stts_sample_delta = (int32_t *)malloc(p_track->stts_entry_count
485 if (p_track->stts_sample_count == 0 || p_track->stts_sample_delta == 0) {
486 if (p_track->stts_sample_count) {
487 free(p_track->stts_sample_count);
488 p_track->stts_sample_count = 0;
490 if (p_track->stts_sample_delta) {
491 free(p_track->stts_sample_delta);
492 p_track->stts_sample_delta = 0;
494 p_track->stts_entry_count = 0;
497 for (i = 0; i < f->track[f->total_tracks - 1]->stts_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9254 */
498 p_track->stts_sample_count[i] = mp4ff_read_int32(f);
499 p_track->stts_sample_delta[i] = mp4ff_read_int32(f);
505 static int32_t mp4ff_read_ctts(mp4ff_t * f)
508 mp4ff_track_t *p_track;
510 if (f->total_tracks == 0)
513 p_track = f->track[f->total_tracks - 1];
514 if (p_track->ctts_entry_count)
517 mp4ff_read_char(f); /* version */
518 mp4ff_read_int24(f); /* flags */
519 p_track->ctts_entry_count = mp4ff_read_int32(f);
521 p_track->ctts_sample_count = (int32_t *)malloc(p_track->ctts_entry_count
523 p_track->ctts_sample_offset = (int32_t *)malloc(p_track->ctts_entry_count
526 if (p_track->ctts_sample_count == 0 || p_track->ctts_sample_offset == 0) {
527 if (p_track->ctts_sample_count) {
528 free(p_track->ctts_sample_count);
529 p_track->ctts_sample_count = 0;
531 if (p_track->ctts_sample_offset) {
532 free(p_track->ctts_sample_offset);
533 p_track->ctts_sample_offset = 0;
535 p_track->ctts_entry_count = 0;
538 for (i = 0; i < f->track[f->total_tracks - 1]->ctts_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9257 */
539 p_track->ctts_sample_count[i] = mp4ff_read_int32(f);
540 p_track->ctts_sample_offset[i] = mp4ff_read_int32(f);
546 static int32_t mp4ff_read_stsc(mp4ff_t * f)
550 if (f->total_tracks == 0)
553 mp4ff_read_char(f); /* version */
554 mp4ff_read_int24(f); /* flags */
555 f->track[f->total_tracks - 1]->stsc_entry_count = mp4ff_read_int32(f);
557 f->track[f->total_tracks - 1]->stsc_first_chunk =
558 (int32_t *) malloc(f->track[f->total_tracks - 1]->stsc_entry_count *
560 f->track[f->total_tracks - 1]->stsc_samples_per_chunk =
561 (int32_t *) malloc(f->track[f->total_tracks - 1]->stsc_entry_count *
563 f->track[f->total_tracks - 1]->stsc_sample_desc_index =
564 (int32_t *) malloc(f->track[f->total_tracks - 1]->stsc_entry_count *
568 if (!f->track[f->total_tracks - 1]->stsc_first_chunk) {
571 if (!f->track[f->total_tracks - 1]->stsc_samples_per_chunk) {
572 free(f->track[f->total_tracks - 1]->stsc_first_chunk);
573 f->track[f->total_tracks - 1]->stsc_first_chunk = NULL;
576 if (!f->track[f->total_tracks - 1]->stsc_sample_desc_index) {
577 free(f->track[f->total_tracks - 1]->stsc_first_chunk);
578 f->track[f->total_tracks - 1]->stsc_first_chunk = NULL;
579 free(f->track[f->total_tracks - 1]->stsc_samples_per_chunk);
580 f->track[f->total_tracks - 1]->stsc_samples_per_chunk = NULL;
584 for (i = 0; i < f->track[f->total_tracks - 1]->stsc_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9255 */
585 f->track[f->total_tracks - 1]->stsc_first_chunk[i] =
587 f->track[f->total_tracks - 1]->stsc_samples_per_chunk[i] =
589 f->track[f->total_tracks - 1]->stsc_sample_desc_index[i] =
596 static int32_t mp4ff_read_stco(mp4ff_t * f)
600 if (f->total_tracks == 0)
603 mp4ff_read_char(f); /* version */
604 mp4ff_read_int24(f); /* flags */
605 f->track[f->total_tracks - 1]->stco_entry_count = mp4ff_read_int32(f);
607 f->track[f->total_tracks - 1]->stco_chunk_offset =
608 (int32_t *) malloc(f->track[f->total_tracks - 1]->stco_entry_count *
612 if (!f->track[f->total_tracks - 1]->stco_chunk_offset)
615 for (i = 0; i < f->track[f->total_tracks - 1]->stco_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9256 */
616 f->track[f->total_tracks - 1]->stco_chunk_offset[i] =
623 static uint16_t mp4ff_read_int16(mp4ff_t * f)
629 mp4ff_read_data(f, data, 2);
630 a = (uint8_t) data[0];
631 b = (uint8_t) data[1];
633 result = (a << 8) | b;
634 return (uint16_t) result;
637 static uint32_t mp4ff_read_mp4_descr_length(mp4ff_t * f)
640 uint8_t numBytes = 0;
644 b = mp4ff_read_char(f);
646 length = (length << 7) | (b & 0x7F);
647 } while ((b & 0x80) && numBytes < 4);
651 static int32_t mp4ff_read_esds(mp4ff_t * f)
656 if (f->total_tracks == 0)
659 mp4ff_read_char(f); /* version */
660 mp4ff_read_int24(f); /* flags */
662 /* get and verify ES_DescrTag */
663 tag = mp4ff_read_char(f);
666 if (mp4ff_read_mp4_descr_length(f) < 5 + 15) {
676 /* get and verify DecoderConfigDescrTab */
677 if (mp4ff_read_char(f) != 0x04) {
682 temp = mp4ff_read_mp4_descr_length(f);
686 f->track[f->total_tracks - 1]->audioType = mp4ff_read_char(f);
687 mp4ff_read_int32(f); //0x15000414 ????
688 f->track[f->total_tracks - 1]->maxBitrate = mp4ff_read_int32(f);
689 f->track[f->total_tracks - 1]->avgBitrate = mp4ff_read_int32(f);
691 /* get and verify DecSpecificInfoTag */
692 if (mp4ff_read_char(f) != 0x05) {
697 f->track[f->total_tracks - 1]->decoderConfigLen =
698 mp4ff_read_mp4_descr_length(f);
700 if (f->track[f->total_tracks - 1]->decoderConfig)
701 free(f->track[f->total_tracks - 1]->decoderConfig);
702 f->track[f->total_tracks - 1]->decoderConfig =
703 malloc(f->track[f->total_tracks - 1]->decoderConfigLen);
704 if (f->track[f->total_tracks - 1]->decoderConfig) {
705 mp4ff_read_data(f, f->track[f->total_tracks - 1]->decoderConfig,
706 f->track[f->total_tracks -
707 1]->decoderConfigLen);
709 f->track[f->total_tracks - 1]->decoderConfigLen = 0;
712 /* will skip the remainder of the atom */
715 static int32_t mp4ff_read_mp4a(mp4ff_t * f)
718 uint8_t atom_type = 0;
719 uint8_t header_size = 0;
721 if (f->total_tracks == 0)
724 for (i = 0; i < 6; i++) {
725 mp4ff_read_char(f); /* reserved */
727 /* data_reference_index */ mp4ff_read_int16(f);
729 mp4ff_read_int32(f); /* reserved */
730 mp4ff_read_int32(f); /* reserved */
732 f->track[f->total_tracks - 1]->channelCount = mp4ff_read_int16(f);
733 f->track[f->total_tracks - 1]->sampleSize = mp4ff_read_int16(f);
738 f->track[f->total_tracks - 1]->sampleRate = mp4ff_read_int16(f);
742 mp4ff_atom_read_header(f, &atom_type, &header_size);
743 if (atom_type == ATOM_ESDS) {
750 static int32_t mp4ff_read_stsd(mp4ff_t * f)
753 uint8_t header_size = 0;
756 if (f->total_tracks == 0)
759 mp4ff_read_char(f); /* version */
760 mp4ff_read_int24(f); /* flags */
762 f->track[f->total_tracks - 1]->stsd_entry_count = mp4ff_read_int32(f);
764 for (i = 0; i < f->track[f->total_tracks - 1]->stsd_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9253 */
765 uint64_t skip = mp4ff_position(f);
767 uint8_t atom_type = 0;
768 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
771 if (atom_type == ATOM_MP4A) {
772 f->track[f->total_tracks - 1]->type = TRACK_AUDIO;
774 } else if (atom_type == ATOM_MP4V) {
775 f->track[f->total_tracks - 1]->type = TRACK_VIDEO;
776 } else if (atom_type == ATOM_MP4S) {
777 f->track[f->total_tracks - 1]->type = TRACK_SYSTEM;
779 f->track[f->total_tracks - 1]->type = TRACK_UNKNOWN;
782 mp4ff_set_position(f, skip);
788 static int32_t mp4ff_read_mvhd(mp4ff_t * f)
792 mp4ff_read_char(f); /* version */
793 mp4ff_read_int24(f); /* flags */
794 /* creation_time */ mp4ff_read_int32(f);
795 /* modification_time */ mp4ff_read_int32(f);
796 f->time_scale = mp4ff_read_int32(f);
797 f->duration = mp4ff_read_int32(f);
798 /* preferred_rate */ mp4ff_read_int32(f);
799 /*mp4ff_read_fixed32(f); */
800 /* preferred_volume */ mp4ff_read_int16(f);
801 /*mp4ff_read_fixed16(f); */
802 for (i = 0; i < 10; i++) {
803 /* reserved */ mp4ff_read_char(f);
805 for (i = 0; i < 9; i++) {
806 mp4ff_read_int32(f); /* matrix */
808 /* preview_time */ mp4ff_read_int32(f);
809 /* preview_duration */ mp4ff_read_int32(f);
810 /* poster_time */ mp4ff_read_int32(f);
811 /* selection_time */ mp4ff_read_int32(f);
812 /* selection_duration */ mp4ff_read_int32(f);
813 /* current_time */ mp4ff_read_int32(f);
814 /* next_track_id */ mp4ff_read_int32(f);
819 static int32_t mp4ff_tag_add_field(mp4ff_metadata_t * tags, const char *item,
820 const char *value, int32_t len)
822 void *backup = (void *) tags->tags;
824 if (!item || (item && !*item) || !value)
827 tags->tags = (mp4ff_tag_t *) realloc(tags->tags,
828 (tags->count + 1) * sizeof (mp4ff_tag_t));
834 tags->tags[tags->count].item = strdup(item);
835 tags->tags[tags->count].len = len;
837 tags->tags[tags->count].value = malloc(len + 1);
838 if (tags->tags[tags->count].value != NULL) {
839 memcpy(tags->tags[tags->count].value, value, len);
840 tags->tags[tags->count].value[len] = 0;
843 tags->tags[tags->count].value = strdup(value);
846 if (!tags->tags[tags->count].item || !tags->tags[tags->count].value) {
847 if (!tags->tags[tags->count].item)
848 free(tags->tags[tags->count].item);
849 if (!tags->tags[tags->count].value)
850 free(tags->tags[tags->count].value);
851 tags->tags[tags->count].item = NULL;
852 tags->tags[tags->count].value = NULL;
853 tags->tags[tags->count].len = 0;
862 static const char *ID3v1GenreList[] = {
863 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
864 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
865 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
866 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
867 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
868 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
869 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
870 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
871 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
872 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
873 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
874 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
875 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
876 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
877 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
878 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
879 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
880 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
881 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
882 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
883 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
884 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
885 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
886 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
887 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
888 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
889 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
890 "Anime", "JPop", "SynthPop",
893 static const char *mp4ff_meta_index_to_genre(uint32_t idx)
895 if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
896 return ID3v1GenreList[idx - 1];
902 static char *mp4ff_read_string(mp4ff_t * f, uint32_t length)
904 char *str = (char *) malloc(length + 1);
906 if ((uint32_t) mp4ff_read_data(f, str, length) != length) {
916 static int32_t mp4ff_set_metadata_name(const uint8_t atom_type, char **name)
918 static char *tag_names[] = {
919 "unknown", "title", "artist", "writer", "album",
920 "date", "tool", "comment", "genre", "track",
921 "disc", "compilation", "genre", "tempo", "cover",
922 "album_artist", "contentgroup", "lyrics", "description",
923 "network", "show", "episodename",
924 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
925 "sortwriter", "sortshow",
926 "season", "episode", "podcast"
961 case ATOM_COMPILATION:
973 case ATOM_ALBUM_ARTIST:
976 case ATOM_CONTENTGROUP:
982 case ATOM_DESCRIPTION:
991 case ATOM_EPISODENAME:
1000 case ATOM_SORTARTIST:
1003 case ATOM_SORTALBUMARTIST:
1006 case ATOM_SORTWRITER:
1026 *name = strdup(tag_names[tag_idx]);
1031 static int32_t mp4ff_parse_tag(mp4ff_t * f, const uint8_t parent_atom_type,
1035 uint8_t header_size = 0;
1036 uint64_t subsize, sumsize = 0;
1042 while (sumsize < size && !f->stream->read_error) { /* CVE-2017-9222 */
1044 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1045 destpos = mp4ff_position(f) + subsize - header_size;
1047 if (atom_type == ATOM_DATA) {
1048 mp4ff_read_char(f); /* version */
1049 mp4ff_read_int24(f); /* flags */
1050 mp4ff_read_int32(f); /* reserved */
1052 /* some need special attention */
1053 if (parent_atom_type == ATOM_GENRE2 || parent_atom_type == ATOM_TEMPO) {
1054 if (subsize - header_size >= 8 + 2) {
1055 uint16_t val = mp4ff_read_int16(f);
1057 if (parent_atom_type == ATOM_TEMPO) {
1062 mp4ff_tag_add_field(&(f-> tags), "tempo", temp, -1);
1064 const char *temp = mp4ff_meta_index_to_genre(val);
1066 mp4ff_tag_add_field (&(f->tags), "genre", temp, -1);
1071 } else if (parent_atom_type == ATOM_TRACK || parent_atom_type == ATOM_DISC) {
1072 if (!done && (subsize - header_size) >= (sizeof (char) + sizeof (uint8_t) * 3 + sizeof (uint32_t) + /* version + flags + reserved */
1073 +(parent_atom_type == ATOM_TRACK ? sizeof (uint16_t) : 0) /* leading uint16_t if ATOM_TRACK */
1074 +sizeof (uint16_t) /* track / disc */
1075 +sizeof (uint16_t)) /* totaltracks / totaldiscs */) {
1076 uint16_t index, total;
1078 mp4ff_read_int16(f);
1079 index = mp4ff_read_int16(f);
1080 total = mp4ff_read_int16(f);
1081 if (parent_atom_type == ATOM_TRACK)
1082 mp4ff_read_int16(f);
1084 sprintf(temp, "%d", index);
1085 mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ?
1086 "track" : "disc", temp, -1);
1090 mp4ff_tag_add_field(& (f-> tags),
1091 parent_atom_type == ATOM_TRACK?
1092 "totaltracks" : "totaldiscs", temp, -1);
1101 data = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 8)));
1102 len = (uint32_t) (subsize - (header_size + 8));
1104 } else if (atom_type == ATOM_NAME) {
1106 mp4ff_read_char(f); /* version */
1107 mp4ff_read_int24(f); /* flags */
1110 name = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 4)));
1113 mp4ff_set_position(f, destpos);
1121 mp4ff_set_metadata_name(parent_atom_type, &name);
1123 mp4ff_tag_add_field(&(f->tags), name, data, len);
1132 static int32_t mp4ff_read_mdhd(mp4ff_t * f)
1137 if (f->total_tracks == 0)
1140 version = mp4ff_read_int32(f);
1142 mp4ff_read_int64(f); //creation-time
1143 mp4ff_read_int64(f); //modification-time
1144 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1145 f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f); //duration
1146 } else //version == 0
1150 mp4ff_read_int32(f); //creation-time
1151 mp4ff_read_int32(f); //modification-time
1152 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1153 temp = mp4ff_read_int32(f);
1154 f->track[f->total_tracks - 1]->duration = (temp == (uint32_t) (-1)) ? (uint64_t) (-1) : (uint64_t) (temp);
1156 mp4ff_read_int16(f);
1157 mp4ff_read_int16(f);
1161 static int32_t mp4ff_parse_metadata(mp4ff_t * f, const int32_t size)
1163 uint64_t subsize, sumsize = 0;
1165 uint8_t header_size = 0;
1167 while (sumsize < size) {
1168 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1171 mp4ff_parse_tag(f, atom_type,
1172 (uint32_t) (subsize - header_size));
1179 static int32_t mp4ff_read_meta(mp4ff_t * f, const uint64_t size)
1181 uint64_t subsize, sumsize = 0;
1183 uint8_t header_size = 0;
1185 mp4ff_read_char(f); /* version */
1186 mp4ff_read_int24(f); /* flags */
1188 while (sumsize < (size - (header_size + 4))) {
1189 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1190 if (subsize <= header_size + 4)
1192 if (atom_type == ATOM_ILST) {
1193 mp4ff_parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1195 mp4ff_set_position(f, mp4ff_position(f) + subsize - header_size);
1203 static int32_t mp4ff_atom_read(mp4ff_t * f, const int32_t size,
1204 const uint8_t atom_type)
1206 uint64_t dest_position = mp4ff_position(f) + size - 8;
1207 if (atom_type == ATOM_STSZ) {
1208 /* sample size box */
1210 } else if (atom_type == ATOM_STTS) {
1211 /* time to sample box */
1213 } else if (atom_type == ATOM_CTTS) {
1214 /* composition offset box */
1216 } else if (atom_type == ATOM_STSC) {
1217 /* sample to chunk box */
1219 } else if (atom_type == ATOM_STCO) {
1220 /* chunk offset box */
1222 } else if (atom_type == ATOM_STSD) {
1223 /* sample description box */
1225 } else if (atom_type == ATOM_MVHD) {
1226 /* movie header box */
1228 } else if (atom_type == ATOM_MDHD) {
1231 } else if (atom_type == ATOM_META) {
1232 /* iTunes Metadata box */
1233 mp4ff_read_meta(f, size);
1236 mp4ff_set_position(f, dest_position);
1240 /* parse atoms that are sub atoms of other atoms */
1241 static int32_t parse_sub_atoms(mp4ff_t * f, const uint64_t total_size, int meta_only)
1244 uint8_t atom_type = 0;
1245 uint64_t counted_size = 0;
1246 uint8_t header_size = 0;
1248 while (counted_size < total_size) {
1249 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
1250 counted_size += size;
1252 /* check for end of file */
1256 /* we're starting to read a new track, update index,
1257 * so that all data and tables get written in the right place
1259 if (atom_type == ATOM_TRAK) {
1263 /* parse subatoms */
1264 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1265 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1266 } else if (atom_type < SUBATOMIC) {
1267 parse_sub_atoms(f, size - header_size, meta_only);
1269 mp4ff_atom_read(f, (uint32_t) size, atom_type);
1276 /* parse root atoms */
1277 static int32_t parse_atoms(mp4ff_t * f, int meta_only)
1280 uint8_t atom_type = 0;
1281 uint8_t header_size = 0;
1284 f->stream->read_error = 0;
1287 mp4ff_atom_read_header(f, &atom_type, &header_size)) != 0) {
1288 f->file_size += size;
1289 f->last_atom = atom_type;
1291 if (atom_type == ATOM_MOOV && size > header_size) {
1292 f->moov_offset = mp4ff_position(f) - header_size;
1293 f->moov_size = size;
1296 /* parse subatoms */
1297 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1298 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1299 } else if (atom_type < SUBATOMIC) {
1300 parse_sub_atoms(f, size - header_size, meta_only);
1302 /* skip this atom */
1303 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1310 void mp4ff_get_decoder_config(const mp4ff_t * f, const int track,
1311 unsigned char **ppBuf, unsigned int *pBufSize)
1313 if (track >= f->total_tracks) {
1319 if (f->track[track]->decoderConfig == NULL
1320 || f->track[track]->decoderConfigLen == 0) {
1324 *ppBuf = malloc(f->track[track]->decoderConfigLen);
1325 if (*ppBuf == NULL) {
1329 memcpy(*ppBuf, f->track[track]->decoderConfig,
1330 f->track[track]->decoderConfigLen);
1331 *pBufSize = f->track[track]->decoderConfigLen;
1335 mp4ff_t *mp4ff_open_read(mp4ff_callback_t * f)
1337 mp4ff_t *ff = malloc(sizeof (mp4ff_t));
1339 memset(ff, 0, sizeof (mp4ff_t));
1353 static int32_t mp4ff_tag_delete(mp4ff_metadata_t * tags)
1357 for (i = 0; i < tags->count; i++) {
1358 if (tags->tags[i].item)
1359 free(tags->tags[i].item);
1360 if (tags->tags[i].value)
1361 free(tags->tags[i].value);
1373 void mp4ff_close(mp4ff_t * ff)
1377 for (i = 0; i < ff->total_tracks; i++) {
1379 if (ff->track[i]->stsz_table)
1380 free(ff->track[i]->stsz_table);
1381 if (ff->track[i]->stts_sample_count)
1382 free(ff->track[i]->stts_sample_count);
1383 if (ff->track[i]->stts_sample_delta)
1384 free(ff->track[i]->stts_sample_delta);
1385 if (ff->track[i]->stsc_first_chunk)
1386 free(ff->track[i]->stsc_first_chunk);
1387 if (ff->track[i]->stsc_samples_per_chunk)
1388 free(ff->track[i]->stsc_samples_per_chunk);
1389 if (ff->track[i]->stsc_sample_desc_index)
1390 free(ff->track[i]->stsc_sample_desc_index);
1391 if (ff->track[i]->stco_chunk_offset)
1392 free(ff->track[i]->stco_chunk_offset);
1393 if (ff->track[i]->decoderConfig)
1394 free(ff->track[i]->decoderConfig);
1395 if (ff->track[i]->ctts_sample_count)
1396 free(ff->track[i]->ctts_sample_count);
1397 if (ff->track[i]->ctts_sample_offset)
1398 free(ff->track[i]->ctts_sample_offset);
1403 mp4ff_tag_delete(&(ff->tags));
1409 static int32_t mp4ff_chunk_of_sample(const mp4ff_t * f, const int32_t track,
1410 const int32_t sample, int32_t * chunk_sample, int32_t * chunk)
1412 int32_t total_entries = 0;
1413 int32_t chunk2entry;
1414 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1418 if (f->track[track] == NULL) {
1422 total_entries = f->track[track]->stsc_entry_count;
1429 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1430 *chunk = chunk2 - chunk1;
1431 range_samples = *chunk * chunk1samples;
1433 if (sample < total + range_samples)
1436 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1439 if (chunk2entry < total_entries) {
1441 total += range_samples;
1443 } while (chunk2entry < total_entries);
1446 *chunk = (sample - total) / chunk1samples + chunk1;
1450 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1455 static int32_t mp4ff_chunk_to_offset(const mp4ff_t * f, const int32_t track,
1456 const int32_t chunk)
1458 const mp4ff_track_t *p_track = f->track[track];
1460 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1461 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1463 } else if (p_track->stco_entry_count) {
1464 return p_track->stco_chunk_offset[chunk - 1];
1472 static int32_t mp4ff_sample_range_size(const mp4ff_t * f, const int32_t track,
1473 const int32_t chunk_sample, const int32_t sample)
1476 const mp4ff_track_t *p_track = f->track[track];
1478 if (p_track->stsz_sample_size) {
1479 return (sample - chunk_sample) * p_track->stsz_sample_size;
1481 if (sample >= p_track->stsz_sample_count)
1484 for (i = chunk_sample, total = 0; i < sample; i++) {
1485 total += p_track->stsz_table[i];
1491 static int32_t mp4ff_sample_to_offset(const mp4ff_t * f, const int32_t track,
1492 const int32_t sample)
1494 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1496 mp4ff_chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1498 chunk_offset1 = mp4ff_chunk_to_offset(f, track, chunk);
1499 chunk_offset2 = chunk_offset1 + mp4ff_sample_range_size(f,
1500 track, chunk_sample, sample);
1501 return chunk_offset2;
1504 void mp4ff_set_sample_position(mp4ff_t *f, const int32_t track,
1505 const int32_t sample)
1507 int32_t offset = mp4ff_sample_to_offset(f, track, sample);
1508 mp4ff_set_position(f, offset);
1511 int32_t mp4ff_get_sample_size(const mp4ff_t *f, int track, int sample)
1513 const mp4ff_track_t *t = f->track[track];
1515 if (t->stsz_sample_size != 0)
1516 return t->stsz_sample_size;
1517 return t->stsz_table[sample];
1520 uint32_t mp4ff_get_sample_rate(const mp4ff_t * f, const int32_t track)
1522 return f->track[track]->sampleRate;
1525 uint32_t mp4ff_get_channel_count(const mp4ff_t * f, const int32_t track)
1527 return f->track[track]->channelCount;
1530 int32_t mp4ff_num_samples(const mp4ff_t * f, const int32_t track)
1535 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1536 total += f->track[track]->stts_sample_count[i];
1541 mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t * f)
1543 mp4ff_t *ff = malloc(sizeof (mp4ff_t));
1545 memset(ff, 0, sizeof (mp4ff_t));
1559 int32_t mp4ff_meta_get_num_items(const mp4ff_t * f)
1561 return f->tags.count;
1564 int32_t mp4ff_meta_get_by_index(const mp4ff_t * f, uint32_t index,
1565 char **item, char **value)
1567 if (index >= f->tags.count) {
1572 *item = strdup(f->tags.tags[index].item);
1573 *value = strdup(f->tags.tags[index].value);
1578 static uint32_t find_atom(mp4ff_t * f, uint64_t base, uint32_t size,
1581 uint32_t remaining = size;
1582 uint64_t atom_offset = base;
1587 mp4ff_set_position(f, atom_offset);
1591 atom_size = mp4ff_read_int32(f);
1592 if (atom_size > remaining || atom_size < 8)
1594 mp4ff_read_data(f, atom_name, 4);
1596 if (!memcmp(atom_name, name, 4)) {
1597 mp4ff_set_position(f, atom_offset);
1601 remaining -= atom_size;
1602 atom_offset += atom_size;
1606 static uint32_t find_atom_v2(mp4ff_t * f, uint64_t base, uint32_t size,
1607 const char *name, uint32_t extraheaders, const char *name_inside)
1609 uint64_t first_base = (uint64_t) (-1);
1610 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1612 uint64_t mybase = mp4ff_position(f);
1613 uint32_t mysize = mp4ff_read_int32(f);
1615 if (first_base == (uint64_t) (-1))
1616 first_base = mybase;
1618 if (mysize < 8 + extraheaders)
1621 if (find_atom (f, mybase + (8 + extraheaders),
1622 mysize - (8 + extraheaders), name_inside)) {
1623 mp4ff_set_position(f, mybase);
1627 if (size <= mysize) {
1634 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1636 mp4ff_set_position(f, first_base);
1649 #define stricmp strcasecmp
1651 static membuffer *membuffer_create(void)
1653 const unsigned initial_size = 256;
1655 membuffer *buf = (membuffer *) malloc(sizeof (membuffer));
1656 buf->data = malloc(initial_size);
1658 buf->allocated = initial_size;
1659 buf->error = buf->data == 0 ? 1 : 0;
1664 static unsigned membuffer_write(membuffer * buf, const void *ptr, unsigned bytes)
1666 unsigned dest_size = buf->written + bytes;
1670 if (dest_size > buf->allocated) {
1672 buf->allocated <<= 1;
1673 } while (dest_size > buf->allocated);
1676 void *newptr = realloc(buf->data, buf->allocated);
1688 memcpy((char *) buf->data + buf->written, ptr, bytes);
1689 buf->written += bytes;
1693 static unsigned membuffer_write_atom_name(membuffer * buf, const char *data)
1695 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1698 static unsigned membuffer_write_int16(membuffer * buf, uint16_t data)
1700 uint8_t temp[2] = { (uint8_t) (data >> 8), (uint8_t) data };
1701 return membuffer_write(buf, temp, 2);
1704 static unsigned membuffer_write_int32(membuffer * buf, uint32_t data)
1706 uint8_t temp[4] = { (uint8_t) (data >> 24), (uint8_t) (data >> 16),
1707 (uint8_t) (data >> 8), (uint8_t) data };
1708 return membuffer_write(buf, temp, 4);
1711 static void membuffer_write_track_tag(membuffer * buf, const char *name,
1712 uint32_t index, uint32_t total)
1714 membuffer_write_int32(buf,
1715 8 /*atom header */ + 8 /*data atom header */ +
1716 8 /*flags + reserved */ + 8 /*actual data */ );
1717 membuffer_write_atom_name(buf, name);
1718 membuffer_write_int32(buf,
1719 8 /*data atom header */ +
1720 8 /*flags + reserved */ + 8 /*actual data */ );
1721 membuffer_write_atom_name(buf, "data");
1722 membuffer_write_int32(buf, 0); //flags
1723 membuffer_write_int32(buf, 0); //reserved
1724 membuffer_write_int16(buf, 0);
1725 membuffer_write_int16(buf, (uint16_t) index); //track number
1726 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1727 membuffer_write_int16(buf, 0);
1730 static void membuffer_write_int16_tag(membuffer * buf, const char *name,
1733 membuffer_write_int32(buf,
1734 8 /*atom header */ + 8 /*data atom header */ +
1735 8 /*flags + reserved */ + 2 /*actual data */ );
1736 membuffer_write_atom_name(buf, name);
1737 membuffer_write_int32(buf,
1738 8 /*data atom header */ +
1739 8 /*flags + reserved */ + 2 /*actual data */ );
1740 membuffer_write_atom_name(buf, "data");
1741 membuffer_write_int32(buf, 0); //flags
1742 membuffer_write_int32(buf, 0); //reserved
1743 membuffer_write_int16(buf, value); //value
1746 static uint32_t myatoi(const char *param)
1748 return param ? atoi(param) : 0;
1751 static uint32_t mp4ff_meta_genre_to_index(const char *genrestr)
1754 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1755 if (!stricmp(genrestr, ID3v1GenreList[n]))
1766 static stdmeta_entry stdmetas[] = {
1767 {"\xA9" "nam", "title"},
1768 {"\xA9" "ART", "artist"},
1769 {"\xA9" "wrt", "writer"},
1770 {"\xA9" "alb", "album"},
1771 {"\xA9" "day", "date"},
1772 {"\xA9" "too", "tool"},
1773 {"\xA9" "cmt", "comment"},
1774 {"cpil", "compilation"},
1776 {"aART", "album_artist"},
1779 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1782 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1783 if (!stricmp(name, stdmetas[n].name))
1784 return stdmetas[n].atom;
1789 static void membuffer_write_std_tag(membuffer * buf, const char *name,
1794 /* special check for compilation flag */
1795 if (strcmp(name, "cpil") == 0) {
1799 membuffer_write_int32(buf,
1800 8 /*atom header */ + 8 /*data atom header */ +
1801 8 /*flags + reserved */ + strlen(value));
1802 membuffer_write_atom_name(buf, name);
1803 membuffer_write_int32(buf,
1804 8 /*data atom header */ +
1805 8 /*flags + reserved */ + strlen(value));
1806 membuffer_write_atom_name(buf, "data");
1807 membuffer_write_int32(buf, flags); //flags
1808 membuffer_write_int32(buf, 0); //reserved
1809 membuffer_write(buf, value, strlen(value));
1812 static void membuffer_write_custom_tag(membuffer * buf, const char *name,
1815 membuffer_write_int32(buf,
1816 8 /*atom header */ +
1817 0x1C /*weirdo itunes atom */ +
1818 12 /*name atom header */ + strlen(name) +
1819 16 /*data atom header + flags */ + strlen(value));
1820 membuffer_write_atom_name(buf, "----");
1821 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1822 membuffer_write_atom_name(buf, "mean");
1823 membuffer_write_int32(buf, 0);
1824 membuffer_write(buf, "com.apple.iTunes", 16);
1825 membuffer_write_int32(buf, 12 + strlen(name));
1826 membuffer_write_atom_name(buf, "name");
1827 membuffer_write_int32(buf, 0);
1828 membuffer_write(buf, name, strlen(name));
1829 membuffer_write_int32(buf,
1830 8 /*data atom header */ +
1831 8 /*flags + reserved */ + strlen(value));
1832 membuffer_write_atom_name(buf, "data");
1833 membuffer_write_int32(buf, 1); //flags
1834 membuffer_write_int32(buf, 0); //reserved
1835 membuffer_write(buf, value, strlen(value));
1838 static unsigned membuffer_error(const membuffer * buf)
1843 static void membuffer_free(membuffer * buf)
1850 static unsigned membuffer_get_size(const membuffer * buf)
1852 return buf->written;
1855 static void *membuffer_detach(membuffer * buf)
1862 ret = realloc(buf->data, buf->written);
1873 static uint32_t create_ilst(const mp4ff_metadata_t * data, void **out_buffer,
1874 uint32_t * out_size)
1876 membuffer *buf = membuffer_create();
1878 char *mask = (char *) malloc(data->count);
1879 memset(mask, 0, data->count);
1882 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1883 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1884 const char *genre_ptr = 0, *tempo_ptr = 0;
1885 for (metaptr = 0; metaptr < data->count; metaptr++) {
1886 mp4ff_tag_t *tag = &data->tags[metaptr];
1887 if (!stricmp(tag->item, "tracknumber") || !stricmp(tag->item, "track")) {
1888 if (tracknumber_ptr == 0)
1889 tracknumber_ptr = tag->value;
1891 } else if (!stricmp(tag->item, "totaltracks")) {
1892 if (totaltracks_ptr == 0)
1893 totaltracks_ptr = tag->value;
1895 } else if (!stricmp(tag->item, "discnumber")
1896 || !stricmp(tag->item, "disc")) {
1897 if (discnumber_ptr == 0)
1898 discnumber_ptr = tag->value;
1900 } else if (!stricmp(tag->item, "totaldiscs")) {
1901 if (totaldiscs_ptr == 0)
1902 totaldiscs_ptr = tag->value;
1904 } else if (!stricmp(tag->item, "genre")) {
1906 genre_ptr = tag->value;
1908 } else if (!stricmp(tag->item, "tempo")) {
1910 tempo_ptr = tag->value;
1916 if (tracknumber_ptr)
1917 membuffer_write_track_tag(buf, "trkn",
1918 myatoi(tracknumber_ptr),
1919 myatoi(totaltracks_ptr));
1921 membuffer_write_track_tag(buf, "disk",
1922 myatoi(discnumber_ptr),
1923 myatoi(totaldiscs_ptr));
1925 membuffer_write_int16_tag(buf, "tmpo",
1926 (uint16_t) myatoi(tempo_ptr));
1929 uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
1931 membuffer_write_std_tag(buf, "©gen",
1934 membuffer_write_int16_tag(buf, "gnre",
1939 for (metaptr = 0; metaptr < data->count; metaptr++) {
1940 if (!mask[metaptr]) {
1941 mp4ff_tag_t *tag = &data->tags[metaptr];
1942 const char *std_meta_atom = find_standard_meta(tag->item);
1943 if (std_meta_atom) {
1944 membuffer_write_std_tag(buf, std_meta_atom,
1947 membuffer_write_custom_tag(buf, tag->item,
1955 if (membuffer_error(buf)) {
1956 membuffer_free(buf);
1960 *out_size = membuffer_get_size(buf);
1961 *out_buffer = membuffer_detach(buf);
1962 membuffer_free(buf);
1967 static void membuffer_write_atom(membuffer * buf, const char *name, unsigned size,
1970 membuffer_write_int32(buf, size + 8);
1971 membuffer_write_atom_name(buf, name);
1972 membuffer_write(buf, data, size);
1975 static void *membuffer_get_ptr(const membuffer * buf)
1980 static void membuffer_set_error(membuffer * buf)
1985 static unsigned membuffer_transfer_from_file(membuffer * buf, mp4ff_t * src,
1991 oldsize = membuffer_get_size(buf);
1992 if (membuffer_write(buf, 0, bytes) != bytes)
1995 bufptr = membuffer_get_ptr(buf);
1999 if ((unsigned) mp4ff_read_data(src, (char *) bufptr + oldsize, bytes) !=
2001 membuffer_set_error(buf);
2008 static uint32_t create_meta(const mp4ff_metadata_t * data, void **out_buffer,
2009 uint32_t * out_size)
2015 if (!create_ilst(data, &ilst_buffer, &ilst_size))
2018 buf = membuffer_create();
2020 membuffer_write_int32(buf, 0);
2021 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
2024 *out_size = membuffer_get_size(buf);
2025 *out_buffer = membuffer_detach(buf);
2026 membuffer_free(buf);
2030 static uint32_t create_udta(const mp4ff_metadata_t * data, void **out_buffer,
2031 uint32_t * out_size)
2037 if (!create_meta(data, &meta_buffer, &meta_size))
2040 buf = membuffer_create();
2042 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
2046 *out_size = membuffer_get_size(buf);
2047 *out_buffer = membuffer_detach(buf);
2048 membuffer_free(buf);
2052 static uint32_t fix_byte_order_32(uint32_t src)
2055 uint32_t a, b, c, d;
2058 memcpy(data, &src, sizeof (src));
2059 a = (uint8_t) data[0];
2060 b = (uint8_t) data[1];
2061 c = (uint8_t) data[2];
2062 d = (uint8_t) data[3];
2064 result = (a << 24) | (b << 16) | (c << 8) | d;
2065 return (uint32_t) result;
2068 static uint32_t modify_moov(mp4ff_t * f, const mp4ff_metadata_t * data,
2069 void **out_buffer, uint32_t * out_size)
2071 uint64_t total_base = f->moov_offset + 8;
2072 uint32_t total_size = (uint32_t) (f->moov_size - 8);
2074 uint64_t udta_offset, meta_offset, ilst_offset;
2075 uint32_t udta_size, meta_size, ilst_size;
2077 uint32_t new_ilst_size;
2078 void *new_ilst_buffer;
2083 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
2085 void *new_udta_buffer;
2086 uint32_t new_udta_size;
2087 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
2090 buf = membuffer_create();
2091 mp4ff_set_position(f, total_base);
2092 membuffer_transfer_from_file(buf, f, total_size);
2094 membuffer_write_atom(buf, "udta", new_udta_size,
2097 free(new_udta_buffer);
2099 *out_size = membuffer_get_size(buf);
2100 *out_buffer = membuffer_detach(buf);
2101 membuffer_free(buf);
2104 udta_offset = mp4ff_position(f);
2105 udta_size = mp4ff_read_int32(f);
2106 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
2108 void *new_meta_buffer;
2109 uint32_t new_meta_size;
2110 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
2113 buf = membuffer_create();
2114 mp4ff_set_position(f, total_base);
2115 membuffer_transfer_from_file(buf, f,
2116 (uint32_t)(udta_offset - total_base));
2118 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2119 membuffer_write_atom_name(buf, "udta");
2120 membuffer_transfer_from_file(buf, f, udta_size);
2122 membuffer_write_atom(buf, "meta", new_meta_size,
2124 free(new_meta_buffer);
2126 *out_size = membuffer_get_size(buf);
2127 *out_buffer = membuffer_detach(buf);
2128 membuffer_free(buf);
2131 meta_offset = mp4ff_position(f);
2132 meta_size = mp4ff_read_int32(f);
2133 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2134 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2135 ilst_offset = mp4ff_position(f);
2136 ilst_size = mp4ff_read_int32(f);
2138 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2141 size_delta = new_ilst_size - (ilst_size - 8);
2143 *out_size = total_size + size_delta;
2144 *out_buffer = malloc(*out_size);
2145 if (*out_buffer == 0) {
2146 free(new_ilst_buffer);
2150 p_out = (uint8_t *) * out_buffer;
2152 mp4ff_set_position(f, total_base);
2153 mp4ff_read_data(f, p_out,
2154 (uint32_t) (udta_offset - total_base));
2155 p_out += (uint32_t) (udta_offset - total_base);
2156 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2158 mp4ff_read_data(f, p_out, 4);
2160 mp4ff_read_data(f, p_out,
2161 (uint32_t) (meta_offset - udta_offset - 8));
2162 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2163 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2165 mp4ff_read_data(f, p_out, 4);
2167 mp4ff_read_data(f, p_out,
2168 (uint32_t) (ilst_offset - meta_offset - 8));
2169 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2170 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2172 mp4ff_read_data(f, p_out, 4);
2175 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2176 p_out += new_ilst_size;
2178 mp4ff_set_position(f, ilst_offset + ilst_size);
2179 mp4ff_read_data(f, p_out, (uint32_t) (total_size
2180 - (ilst_offset - total_base) - ilst_size));
2182 free(new_ilst_buffer);
2187 static int32_t mp4ff_write_data(mp4ff_t * f, void *data, uint32_t size)
2191 result = f->stream->write(f->stream->user_data, data, size);
2193 f->current_position += size;
2198 static int32_t mp4ff_write_int32(mp4ff_t * f, const uint32_t data)
2201 uint32_t a, b, c, d;
2204 *(uint32_t *) temp = data;
2205 a = (uint8_t) temp[0];
2206 b = (uint8_t) temp[1];
2207 c = (uint8_t) temp[2];
2208 d = (uint8_t) temp[3];
2210 result = (a << 24) | (b << 16) | (c << 8) | d;
2212 return mp4ff_write_data(f, (uint8_t *) & result, sizeof (result));
2215 static int32_t mp4ff_truncate(mp4ff_t * f)
2217 return f->stream->truncate(f->stream->user_data);
2220 int32_t mp4ff_meta_update(mp4ff_callback_t * f, const mp4ff_metadata_t * data)
2222 void *new_moov_data;
2223 uint32_t new_moov_size;
2225 mp4ff_t *ff = malloc(sizeof (mp4ff_t));
2227 memset(ff, 0, sizeof (mp4ff_t));
2229 mp4ff_set_position(ff, 0);
2233 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2238 /* copy moov atom to end of the file */
2239 if (ff->last_atom != ATOM_MOOV) {
2240 char *free_data = "free";
2242 /* rename old moov to free */
2243 mp4ff_set_position(ff, ff->moov_offset + 4);
2244 mp4ff_write_data(ff, free_data, 4);
2246 mp4ff_set_position(ff, ff->file_size);
2247 mp4ff_write_int32(ff, new_moov_size + 8);
2248 mp4ff_write_data(ff, "moov", 4);
2249 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2251 mp4ff_set_position(ff, ff->moov_offset);
2252 mp4ff_write_int32(ff, new_moov_size + 8);
2253 mp4ff_write_data(ff, "moov", 4);
2254 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2263 /* find a metadata item by name */
2264 /* returns 0 if item found, 1 if no such item */
2265 static int32_t mp4ff_meta_find_by_name(const mp4ff_t * f, const char *item,
2270 for (i = 0; i < f->tags.count; i++) {
2271 if (!stricmp(f->tags.tags[i].item, item)) {
2272 *value = strdup(f->tags.tags[i].value);
2283 int32_t mp4ff_meta_get_artist(const mp4ff_t * f, char **value)
2285 return mp4ff_meta_find_by_name(f, "artist", value);
2288 int32_t mp4ff_meta_get_title(const mp4ff_t * f, char **value)
2290 return mp4ff_meta_find_by_name(f, "title", value);
2293 int32_t mp4ff_meta_get_date(const mp4ff_t * f, char **value)
2295 return mp4ff_meta_find_by_name(f, "date", value);
2298 int32_t mp4ff_meta_get_album(const mp4ff_t * f, char **value)
2300 return mp4ff_meta_find_by_name(f, "album", value);
2303 int32_t mp4ff_meta_get_comment(const mp4ff_t * f, char **value)
2305 return mp4ff_meta_find_by_name(f, "comment", value);