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) {
1293 f->moov_offset = mp4ff_position(f) - header_size;
1294 f->moov_size = size;
1297 /* parse subatoms */
1298 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1299 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1300 } else if (atom_type < SUBATOMIC) {
1301 parse_sub_atoms(f, size - header_size, meta_only);
1303 /* skip this atom */
1304 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1311 void mp4ff_get_decoder_config(const mp4ff_t * f, const int track,
1312 unsigned char **ppBuf, unsigned int *pBufSize)
1314 if (track >= f->total_tracks) {
1320 if (f->track[track]->decoderConfig == NULL
1321 || f->track[track]->decoderConfigLen == 0) {
1325 *ppBuf = malloc(f->track[track]->decoderConfigLen);
1326 if (*ppBuf == NULL) {
1330 memcpy(*ppBuf, f->track[track]->decoderConfig,
1331 f->track[track]->decoderConfigLen);
1332 *pBufSize = f->track[track]->decoderConfigLen;
1336 mp4ff_t *mp4ff_open_read(mp4ff_callback_t * f)
1338 mp4ff_t *ff = malloc(sizeof (mp4ff_t));
1340 memset(ff, 0, sizeof (mp4ff_t));
1354 static int32_t mp4ff_tag_delete(mp4ff_metadata_t * tags)
1358 for (i = 0; i < tags->count; i++) {
1359 if (tags->tags[i].item)
1360 free(tags->tags[i].item);
1361 if (tags->tags[i].value)
1362 free(tags->tags[i].value);
1374 void mp4ff_close(mp4ff_t * ff)
1378 for (i = 0; i < ff->total_tracks; i++) {
1380 if (ff->track[i]->stsz_table)
1381 free(ff->track[i]->stsz_table);
1382 if (ff->track[i]->stts_sample_count)
1383 free(ff->track[i]->stts_sample_count);
1384 if (ff->track[i]->stts_sample_delta)
1385 free(ff->track[i]->stts_sample_delta);
1386 if (ff->track[i]->stsc_first_chunk)
1387 free(ff->track[i]->stsc_first_chunk);
1388 if (ff->track[i]->stsc_samples_per_chunk)
1389 free(ff->track[i]->stsc_samples_per_chunk);
1390 if (ff->track[i]->stsc_sample_desc_index)
1391 free(ff->track[i]->stsc_sample_desc_index);
1392 if (ff->track[i]->stco_chunk_offset)
1393 free(ff->track[i]->stco_chunk_offset);
1394 if (ff->track[i]->decoderConfig)
1395 free(ff->track[i]->decoderConfig);
1396 if (ff->track[i]->ctts_sample_count)
1397 free(ff->track[i]->ctts_sample_count);
1398 if (ff->track[i]->ctts_sample_offset)
1399 free(ff->track[i]->ctts_sample_offset);
1404 mp4ff_tag_delete(&(ff->tags));
1410 static int32_t mp4ff_chunk_of_sample(const mp4ff_t * f, const int32_t track,
1411 const int32_t sample, int32_t * chunk_sample, int32_t * chunk)
1413 int32_t total_entries = 0;
1414 int32_t chunk2entry;
1415 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1419 if (f->track[track] == NULL) {
1423 total_entries = f->track[track]->stsc_entry_count;
1430 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1431 *chunk = chunk2 - chunk1;
1432 range_samples = *chunk * chunk1samples;
1434 if (sample < total + range_samples)
1437 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1440 if (chunk2entry < total_entries) {
1442 total += range_samples;
1444 } while (chunk2entry < total_entries);
1447 *chunk = (sample - total) / chunk1samples + chunk1;
1451 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1456 static int32_t mp4ff_chunk_to_offset(const mp4ff_t * f, const int32_t track,
1457 const int32_t chunk)
1459 const mp4ff_track_t *p_track = f->track[track];
1461 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1462 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1464 } else if (p_track->stco_entry_count) {
1465 return p_track->stco_chunk_offset[chunk - 1];
1473 static int32_t mp4ff_sample_range_size(const mp4ff_t * f, const int32_t track,
1474 const int32_t chunk_sample, const int32_t sample)
1477 const mp4ff_track_t *p_track = f->track[track];
1479 if (p_track->stsz_sample_size) {
1480 return (sample - chunk_sample) * p_track->stsz_sample_size;
1482 if (sample >= p_track->stsz_sample_count)
1485 for (i = chunk_sample, total = 0; i < sample; i++) {
1486 total += p_track->stsz_table[i];
1492 static int32_t mp4ff_sample_to_offset(const mp4ff_t * f, const int32_t track,
1493 const int32_t sample)
1495 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1497 mp4ff_chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1499 chunk_offset1 = mp4ff_chunk_to_offset(f, track, chunk);
1500 chunk_offset2 = chunk_offset1 + mp4ff_sample_range_size(f,
1501 track, chunk_sample, sample);
1502 return chunk_offset2;
1505 void mp4ff_set_sample_position(mp4ff_t *f, const int32_t track,
1506 const int32_t sample)
1508 int32_t offset = mp4ff_sample_to_offset(f, track, sample);
1509 mp4ff_set_position(f, offset);
1512 int32_t mp4ff_get_sample_size(const mp4ff_t *f, int track, int sample)
1514 const mp4ff_track_t *t = f->track[track];
1516 if (t->stsz_sample_size != 0)
1517 return t->stsz_sample_size;
1518 return t->stsz_table[sample];
1521 uint32_t mp4ff_get_sample_rate(const mp4ff_t * f, const int32_t track)
1523 return f->track[track]->sampleRate;
1526 uint32_t mp4ff_get_channel_count(const mp4ff_t * f, const int32_t track)
1528 return f->track[track]->channelCount;
1531 int32_t mp4ff_num_samples(const mp4ff_t * f, const int32_t track)
1536 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1537 total += f->track[track]->stts_sample_count[i];
1542 mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t * f)
1544 mp4ff_t *ff = malloc(sizeof (mp4ff_t));
1546 memset(ff, 0, sizeof (mp4ff_t));
1560 int32_t mp4ff_meta_get_num_items(const mp4ff_t * f)
1562 return f->tags.count;
1565 int32_t mp4ff_meta_get_by_index(const mp4ff_t * f, uint32_t index,
1566 char **item, char **value)
1568 if (index >= f->tags.count) {
1573 *item = strdup(f->tags.tags[index].item);
1574 *value = strdup(f->tags.tags[index].value);
1579 static uint32_t find_atom(mp4ff_t * f, uint64_t base, uint32_t size,
1582 uint32_t remaining = size;
1583 uint64_t atom_offset = base;
1588 mp4ff_set_position(f, atom_offset);
1592 atom_size = mp4ff_read_int32(f);
1593 if (atom_size > remaining || atom_size < 8)
1595 mp4ff_read_data(f, atom_name, 4);
1597 if (!memcmp(atom_name, name, 4)) {
1598 mp4ff_set_position(f, atom_offset);
1602 remaining -= atom_size;
1603 atom_offset += atom_size;
1607 static uint32_t find_atom_v2(mp4ff_t * f, uint64_t base, uint32_t size,
1608 const char *name, uint32_t extraheaders, const char *name_inside)
1610 uint64_t first_base = (uint64_t) (-1);
1611 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1613 uint64_t mybase = mp4ff_position(f);
1614 uint32_t mysize = mp4ff_read_int32(f);
1616 if (first_base == (uint64_t) (-1))
1617 first_base = mybase;
1619 if (mysize < 8 + extraheaders)
1622 if (find_atom (f, mybase + (8 + extraheaders),
1623 mysize - (8 + extraheaders), name_inside)) {
1624 mp4ff_set_position(f, mybase);
1628 if (size <= mysize) {
1635 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1637 mp4ff_set_position(f, first_base);
1650 #define stricmp strcasecmp
1652 static membuffer *membuffer_create(void)
1654 const unsigned initial_size = 256;
1656 membuffer *buf = (membuffer *) malloc(sizeof (membuffer));
1657 buf->data = malloc(initial_size);
1659 buf->allocated = initial_size;
1660 buf->error = buf->data == 0 ? 1 : 0;
1665 static unsigned membuffer_write(membuffer * buf, const void *ptr, unsigned bytes)
1667 unsigned dest_size = buf->written + bytes;
1671 if (dest_size > buf->allocated) {
1673 buf->allocated <<= 1;
1674 } while (dest_size > buf->allocated);
1677 void *newptr = realloc(buf->data, buf->allocated);
1689 memcpy((char *) buf->data + buf->written, ptr, bytes);
1690 buf->written += bytes;
1694 static unsigned membuffer_write_atom_name(membuffer * buf, const char *data)
1696 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1699 static unsigned membuffer_write_int16(membuffer * buf, uint16_t data)
1701 uint8_t temp[2] = { (uint8_t) (data >> 8), (uint8_t) data };
1702 return membuffer_write(buf, temp, 2);
1705 static unsigned membuffer_write_int32(membuffer * buf, uint32_t data)
1707 uint8_t temp[4] = { (uint8_t) (data >> 24), (uint8_t) (data >> 16),
1708 (uint8_t) (data >> 8), (uint8_t) data };
1709 return membuffer_write(buf, temp, 4);
1712 static void membuffer_write_track_tag(membuffer * buf, const char *name,
1713 uint32_t index, uint32_t total)
1715 membuffer_write_int32(buf,
1716 8 /*atom header */ + 8 /*data atom header */ +
1717 8 /*flags + reserved */ + 8 /*actual data */ );
1718 membuffer_write_atom_name(buf, name);
1719 membuffer_write_int32(buf,
1720 8 /*data atom header */ +
1721 8 /*flags + reserved */ + 8 /*actual data */ );
1722 membuffer_write_atom_name(buf, "data");
1723 membuffer_write_int32(buf, 0); //flags
1724 membuffer_write_int32(buf, 0); //reserved
1725 membuffer_write_int16(buf, 0);
1726 membuffer_write_int16(buf, (uint16_t) index); //track number
1727 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1728 membuffer_write_int16(buf, 0);
1731 static void membuffer_write_int16_tag(membuffer * buf, const char *name,
1734 membuffer_write_int32(buf,
1735 8 /*atom header */ + 8 /*data atom header */ +
1736 8 /*flags + reserved */ + 2 /*actual data */ );
1737 membuffer_write_atom_name(buf, name);
1738 membuffer_write_int32(buf,
1739 8 /*data atom header */ +
1740 8 /*flags + reserved */ + 2 /*actual data */ );
1741 membuffer_write_atom_name(buf, "data");
1742 membuffer_write_int32(buf, 0); //flags
1743 membuffer_write_int32(buf, 0); //reserved
1744 membuffer_write_int16(buf, value); //value
1747 static uint32_t myatoi(const char *param)
1749 return param ? atoi(param) : 0;
1752 static uint32_t mp4ff_meta_genre_to_index(const char *genrestr)
1755 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1756 if (!stricmp(genrestr, ID3v1GenreList[n]))
1767 static stdmeta_entry stdmetas[] = {
1768 {"\xA9" "nam", "title"},
1769 {"\xA9" "ART", "artist"},
1770 {"\xA9" "wrt", "writer"},
1771 {"\xA9" "alb", "album"},
1772 {"\xA9" "day", "date"},
1773 {"\xA9" "too", "tool"},
1774 {"\xA9" "cmt", "comment"},
1775 {"cpil", "compilation"},
1777 {"aART", "album_artist"},
1780 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1783 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1784 if (!stricmp(name, stdmetas[n].name))
1785 return stdmetas[n].atom;
1790 static void membuffer_write_std_tag(membuffer * buf, const char *name,
1795 /* special check for compilation flag */
1796 if (strcmp(name, "cpil") == 0) {
1800 membuffer_write_int32(buf,
1801 8 /*atom header */ + 8 /*data atom header */ +
1802 8 /*flags + reserved */ + strlen(value));
1803 membuffer_write_atom_name(buf, name);
1804 membuffer_write_int32(buf,
1805 8 /*data atom header */ +
1806 8 /*flags + reserved */ + strlen(value));
1807 membuffer_write_atom_name(buf, "data");
1808 membuffer_write_int32(buf, flags); //flags
1809 membuffer_write_int32(buf, 0); //reserved
1810 membuffer_write(buf, value, strlen(value));
1813 static void membuffer_write_custom_tag(membuffer * buf, const char *name,
1816 membuffer_write_int32(buf,
1817 8 /*atom header */ +
1818 0x1C /*weirdo itunes atom */ +
1819 12 /*name atom header */ + strlen(name) +
1820 16 /*data atom header + flags */ + strlen(value));
1821 membuffer_write_atom_name(buf, "----");
1822 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1823 membuffer_write_atom_name(buf, "mean");
1824 membuffer_write_int32(buf, 0);
1825 membuffer_write(buf, "com.apple.iTunes", 16);
1826 membuffer_write_int32(buf, 12 + strlen(name));
1827 membuffer_write_atom_name(buf, "name");
1828 membuffer_write_int32(buf, 0);
1829 membuffer_write(buf, name, strlen(name));
1830 membuffer_write_int32(buf,
1831 8 /*data atom header */ +
1832 8 /*flags + reserved */ + strlen(value));
1833 membuffer_write_atom_name(buf, "data");
1834 membuffer_write_int32(buf, 1); //flags
1835 membuffer_write_int32(buf, 0); //reserved
1836 membuffer_write(buf, value, strlen(value));
1839 static unsigned membuffer_error(const membuffer * buf)
1844 static void membuffer_free(membuffer * buf)
1851 static unsigned membuffer_get_size(const membuffer * buf)
1853 return buf->written;
1856 static void *membuffer_detach(membuffer * buf)
1863 ret = realloc(buf->data, buf->written);
1874 static uint32_t create_ilst(const mp4ff_metadata_t * data, void **out_buffer,
1875 uint32_t * out_size)
1877 membuffer *buf = membuffer_create();
1879 char *mask = (char *) malloc(data->count);
1880 memset(mask, 0, data->count);
1883 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1884 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1885 const char *genre_ptr = 0, *tempo_ptr = 0;
1886 for (metaptr = 0; metaptr < data->count; metaptr++) {
1887 mp4ff_tag_t *tag = &data->tags[metaptr];
1888 if (!stricmp(tag->item, "tracknumber") || !stricmp(tag->item, "track")) {
1889 if (tracknumber_ptr == 0)
1890 tracknumber_ptr = tag->value;
1892 } else if (!stricmp(tag->item, "totaltracks")) {
1893 if (totaltracks_ptr == 0)
1894 totaltracks_ptr = tag->value;
1896 } else if (!stricmp(tag->item, "discnumber")
1897 || !stricmp(tag->item, "disc")) {
1898 if (discnumber_ptr == 0)
1899 discnumber_ptr = tag->value;
1901 } else if (!stricmp(tag->item, "totaldiscs")) {
1902 if (totaldiscs_ptr == 0)
1903 totaldiscs_ptr = tag->value;
1905 } else if (!stricmp(tag->item, "genre")) {
1907 genre_ptr = tag->value;
1909 } else if (!stricmp(tag->item, "tempo")) {
1911 tempo_ptr = tag->value;
1917 if (tracknumber_ptr)
1918 membuffer_write_track_tag(buf, "trkn",
1919 myatoi(tracknumber_ptr),
1920 myatoi(totaltracks_ptr));
1922 membuffer_write_track_tag(buf, "disk",
1923 myatoi(discnumber_ptr),
1924 myatoi(totaldiscs_ptr));
1926 membuffer_write_int16_tag(buf, "tmpo",
1927 (uint16_t) myatoi(tempo_ptr));
1930 uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
1932 membuffer_write_std_tag(buf, "©gen",
1935 membuffer_write_int16_tag(buf, "gnre",
1940 for (metaptr = 0; metaptr < data->count; metaptr++) {
1941 if (!mask[metaptr]) {
1942 mp4ff_tag_t *tag = &data->tags[metaptr];
1943 const char *std_meta_atom = find_standard_meta(tag->item);
1944 if (std_meta_atom) {
1945 membuffer_write_std_tag(buf, std_meta_atom,
1948 membuffer_write_custom_tag(buf, tag->item,
1956 if (membuffer_error(buf)) {
1957 membuffer_free(buf);
1961 *out_size = membuffer_get_size(buf);
1962 *out_buffer = membuffer_detach(buf);
1963 membuffer_free(buf);
1968 static void membuffer_write_atom(membuffer * buf, const char *name, unsigned size,
1971 membuffer_write_int32(buf, size + 8);
1972 membuffer_write_atom_name(buf, name);
1973 membuffer_write(buf, data, size);
1976 static void *membuffer_get_ptr(const membuffer * buf)
1981 static void membuffer_set_error(membuffer * buf)
1986 static unsigned membuffer_transfer_from_file(membuffer * buf, mp4ff_t * src,
1992 oldsize = membuffer_get_size(buf);
1993 if (membuffer_write(buf, 0, bytes) != bytes)
1996 bufptr = membuffer_get_ptr(buf);
2000 if ((unsigned) mp4ff_read_data(src, (char *) bufptr + oldsize, bytes) !=
2002 membuffer_set_error(buf);
2009 static uint32_t create_meta(const mp4ff_metadata_t * data, void **out_buffer,
2010 uint32_t * out_size)
2016 if (!create_ilst(data, &ilst_buffer, &ilst_size))
2019 buf = membuffer_create();
2021 membuffer_write_int32(buf, 0);
2022 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
2025 *out_size = membuffer_get_size(buf);
2026 *out_buffer = membuffer_detach(buf);
2027 membuffer_free(buf);
2031 static uint32_t create_udta(const mp4ff_metadata_t * data, void **out_buffer,
2032 uint32_t * out_size)
2038 if (!create_meta(data, &meta_buffer, &meta_size))
2041 buf = membuffer_create();
2043 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
2047 *out_size = membuffer_get_size(buf);
2048 *out_buffer = membuffer_detach(buf);
2049 membuffer_free(buf);
2053 static uint32_t fix_byte_order_32(uint32_t src)
2056 uint32_t a, b, c, d;
2059 memcpy(data, &src, sizeof (src));
2060 a = (uint8_t) data[0];
2061 b = (uint8_t) data[1];
2062 c = (uint8_t) data[2];
2063 d = (uint8_t) data[3];
2065 result = (a << 24) | (b << 16) | (c << 8) | d;
2066 return (uint32_t) result;
2069 static uint32_t modify_moov(mp4ff_t * f, const mp4ff_metadata_t * data,
2070 void **out_buffer, uint32_t * out_size)
2072 uint64_t total_base = f->moov_offset + 8;
2073 uint32_t total_size = (uint32_t) (f->moov_size - 8);
2075 uint64_t udta_offset, meta_offset, ilst_offset;
2076 uint32_t udta_size, meta_size, ilst_size;
2078 uint32_t new_ilst_size;
2079 void *new_ilst_buffer;
2084 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
2086 void *new_udta_buffer;
2087 uint32_t new_udta_size;
2088 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
2091 buf = membuffer_create();
2092 mp4ff_set_position(f, total_base);
2093 membuffer_transfer_from_file(buf, f, total_size);
2095 membuffer_write_atom(buf, "udta", new_udta_size,
2098 free(new_udta_buffer);
2100 *out_size = membuffer_get_size(buf);
2101 *out_buffer = membuffer_detach(buf);
2102 membuffer_free(buf);
2105 udta_offset = mp4ff_position(f);
2106 udta_size = mp4ff_read_int32(f);
2107 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
2109 void *new_meta_buffer;
2110 uint32_t new_meta_size;
2111 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
2114 buf = membuffer_create();
2115 mp4ff_set_position(f, total_base);
2116 membuffer_transfer_from_file(buf, f,
2117 (uint32_t)(udta_offset - total_base));
2119 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2120 membuffer_write_atom_name(buf, "udta");
2121 membuffer_transfer_from_file(buf, f, udta_size);
2123 membuffer_write_atom(buf, "meta", new_meta_size,
2125 free(new_meta_buffer);
2127 *out_size = membuffer_get_size(buf);
2128 *out_buffer = membuffer_detach(buf);
2129 membuffer_free(buf);
2132 meta_offset = mp4ff_position(f);
2133 meta_size = mp4ff_read_int32(f);
2134 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2135 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2136 ilst_offset = mp4ff_position(f);
2137 ilst_size = mp4ff_read_int32(f);
2139 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2142 size_delta = new_ilst_size - (ilst_size - 8);
2144 *out_size = total_size + size_delta;
2145 *out_buffer = malloc(*out_size);
2146 if (*out_buffer == 0) {
2147 free(new_ilst_buffer);
2151 p_out = (uint8_t *) * out_buffer;
2153 mp4ff_set_position(f, total_base);
2154 mp4ff_read_data(f, p_out,
2155 (uint32_t) (udta_offset - total_base));
2156 p_out += (uint32_t) (udta_offset - total_base);
2157 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2159 mp4ff_read_data(f, p_out, 4);
2161 mp4ff_read_data(f, p_out,
2162 (uint32_t) (meta_offset - udta_offset - 8));
2163 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2164 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2166 mp4ff_read_data(f, p_out, 4);
2168 mp4ff_read_data(f, p_out,
2169 (uint32_t) (ilst_offset - meta_offset - 8));
2170 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2171 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2173 mp4ff_read_data(f, p_out, 4);
2176 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2177 p_out += new_ilst_size;
2179 mp4ff_set_position(f, ilst_offset + ilst_size);
2180 mp4ff_read_data(f, p_out, (uint32_t) (total_size
2181 - (ilst_offset - total_base) - ilst_size));
2183 free(new_ilst_buffer);
2188 static int32_t mp4ff_write_data(mp4ff_t * f, void *data, uint32_t size)
2192 result = f->stream->write(f->stream->user_data, data, size);
2194 f->current_position += size;
2199 static int32_t mp4ff_write_int32(mp4ff_t * f, const uint32_t data)
2202 uint32_t a, b, c, d;
2205 *(uint32_t *) temp = data;
2206 a = (uint8_t) temp[0];
2207 b = (uint8_t) temp[1];
2208 c = (uint8_t) temp[2];
2209 d = (uint8_t) temp[3];
2211 result = (a << 24) | (b << 16) | (c << 8) | d;
2213 return mp4ff_write_data(f, (uint8_t *) & result, sizeof (result));
2216 static int32_t mp4ff_truncate(mp4ff_t * f)
2218 return f->stream->truncate(f->stream->user_data);
2221 int32_t mp4ff_meta_update(mp4ff_callback_t * f, const mp4ff_metadata_t * data)
2223 void *new_moov_data;
2224 uint32_t new_moov_size;
2226 mp4ff_t *ff = malloc(sizeof (mp4ff_t));
2228 memset(ff, 0, sizeof (mp4ff_t));
2230 mp4ff_set_position(ff, 0);
2234 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2239 /* copy moov atom to end of the file */
2240 if (ff->last_atom != ATOM_MOOV) {
2241 char *free_data = "free";
2243 /* rename old moov to free */
2244 mp4ff_set_position(ff, ff->moov_offset + 4);
2245 mp4ff_write_data(ff, free_data, 4);
2247 mp4ff_set_position(ff, ff->file_size);
2248 mp4ff_write_int32(ff, new_moov_size + 8);
2249 mp4ff_write_data(ff, "moov", 4);
2250 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2252 mp4ff_set_position(ff, ff->moov_offset);
2253 mp4ff_write_int32(ff, new_moov_size + 8);
2254 mp4ff_write_data(ff, "moov", 4);
2255 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2264 /* find a metadata item by name */
2265 /* returns 0 if item found, 1 if no such item */
2266 static int32_t mp4ff_meta_find_by_name(const mp4ff_t * f, const char *item,
2271 for (i = 0; i < f->tags.count; i++) {
2272 if (!stricmp(f->tags.tags[i].item, item)) {
2273 *value = strdup(f->tags.tags[i].value);
2284 int32_t mp4ff_meta_get_artist(const mp4ff_t * f, char **value)
2286 return mp4ff_meta_find_by_name(f, "artist", value);
2289 int32_t mp4ff_meta_get_title(const mp4ff_t * f, char **value)
2291 return mp4ff_meta_find_by_name(f, "title", value);
2294 int32_t mp4ff_meta_get_date(const mp4ff_t * f, char **value)
2296 return mp4ff_meta_find_by_name(f, "date", value);
2299 int32_t mp4ff_meta_get_album(const mp4ff_t * f, char **value)
2301 return mp4ff_meta_find_by_name(f, "album", value);
2304 int32_t mp4ff_meta_get_comment(const mp4ff_t * f, char **value)
2306 return mp4ff_meta_find_by_name(f, "comment", value);