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 static int32_t mp4ff_audio_frame_size(const mp4ff_t * f, const int32_t track,
1513 const int32_t sample)
1516 const mp4ff_track_t *p_track = f->track[track];
1518 if (p_track->stsz_sample_size) {
1519 bytes = p_track->stsz_sample_size;
1521 bytes = p_track->stsz_table[sample];
1527 int32_t mp4ff_read_sample_getsize(mp4ff_t * f, const int track,
1530 int32_t temp = mp4ff_audio_frame_size(f, track, sample);
1536 uint32_t mp4ff_get_sample_rate(const mp4ff_t * f, const int32_t track)
1538 return f->track[track]->sampleRate;
1541 uint32_t mp4ff_get_channel_count(const mp4ff_t * f, const int32_t track)
1543 return f->track[track]->channelCount;
1546 int32_t mp4ff_num_samples(const mp4ff_t * f, const int32_t track)
1551 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1552 total += f->track[track]->stts_sample_count[i];
1557 mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t * f)
1559 mp4ff_t *ff = malloc(sizeof (mp4ff_t));
1561 memset(ff, 0, sizeof (mp4ff_t));
1575 int32_t mp4ff_meta_get_num_items(const mp4ff_t * f)
1577 return f->tags.count;
1580 int32_t mp4ff_meta_get_by_index(const mp4ff_t * f, uint32_t index,
1581 char **item, char **value)
1583 if (index >= f->tags.count) {
1588 *item = strdup(f->tags.tags[index].item);
1589 *value = strdup(f->tags.tags[index].value);
1594 static uint32_t find_atom(mp4ff_t * f, uint64_t base, uint32_t size,
1597 uint32_t remaining = size;
1598 uint64_t atom_offset = base;
1603 mp4ff_set_position(f, atom_offset);
1607 atom_size = mp4ff_read_int32(f);
1608 if (atom_size > remaining || atom_size < 8)
1610 mp4ff_read_data(f, atom_name, 4);
1612 if (!memcmp(atom_name, name, 4)) {
1613 mp4ff_set_position(f, atom_offset);
1617 remaining -= atom_size;
1618 atom_offset += atom_size;
1622 static uint32_t find_atom_v2(mp4ff_t * f, uint64_t base, uint32_t size,
1623 const char *name, uint32_t extraheaders, const char *name_inside)
1625 uint64_t first_base = (uint64_t) (-1);
1626 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1628 uint64_t mybase = mp4ff_position(f);
1629 uint32_t mysize = mp4ff_read_int32(f);
1631 if (first_base == (uint64_t) (-1))
1632 first_base = mybase;
1634 if (mysize < 8 + extraheaders)
1637 if (find_atom (f, mybase + (8 + extraheaders),
1638 mysize - (8 + extraheaders), name_inside)) {
1639 mp4ff_set_position(f, mybase);
1643 if (size <= mysize) {
1650 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1652 mp4ff_set_position(f, first_base);
1665 #define stricmp strcasecmp
1667 static membuffer *membuffer_create(void)
1669 const unsigned initial_size = 256;
1671 membuffer *buf = (membuffer *) malloc(sizeof (membuffer));
1672 buf->data = malloc(initial_size);
1674 buf->allocated = initial_size;
1675 buf->error = buf->data == 0 ? 1 : 0;
1680 static unsigned membuffer_write(membuffer * buf, const void *ptr, unsigned bytes)
1682 unsigned dest_size = buf->written + bytes;
1686 if (dest_size > buf->allocated) {
1688 buf->allocated <<= 1;
1689 } while (dest_size > buf->allocated);
1692 void *newptr = realloc(buf->data, buf->allocated);
1704 memcpy((char *) buf->data + buf->written, ptr, bytes);
1705 buf->written += bytes;
1709 static unsigned membuffer_write_atom_name(membuffer * buf, const char *data)
1711 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1714 static unsigned membuffer_write_int16(membuffer * buf, uint16_t data)
1716 uint8_t temp[2] = { (uint8_t) (data >> 8), (uint8_t) data };
1717 return membuffer_write(buf, temp, 2);
1720 static unsigned membuffer_write_int32(membuffer * buf, uint32_t data)
1722 uint8_t temp[4] = { (uint8_t) (data >> 24), (uint8_t) (data >> 16),
1723 (uint8_t) (data >> 8), (uint8_t) data };
1724 return membuffer_write(buf, temp, 4);
1727 static void membuffer_write_track_tag(membuffer * buf, const char *name,
1728 uint32_t index, uint32_t total)
1730 membuffer_write_int32(buf,
1731 8 /*atom header */ + 8 /*data atom header */ +
1732 8 /*flags + reserved */ + 8 /*actual data */ );
1733 membuffer_write_atom_name(buf, name);
1734 membuffer_write_int32(buf,
1735 8 /*data atom header */ +
1736 8 /*flags + reserved */ + 8 /*actual data */ );
1737 membuffer_write_atom_name(buf, "data");
1738 membuffer_write_int32(buf, 0); //flags
1739 membuffer_write_int32(buf, 0); //reserved
1740 membuffer_write_int16(buf, 0);
1741 membuffer_write_int16(buf, (uint16_t) index); //track number
1742 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1743 membuffer_write_int16(buf, 0);
1746 static void membuffer_write_int16_tag(membuffer * buf, const char *name,
1749 membuffer_write_int32(buf,
1750 8 /*atom header */ + 8 /*data atom header */ +
1751 8 /*flags + reserved */ + 2 /*actual data */ );
1752 membuffer_write_atom_name(buf, name);
1753 membuffer_write_int32(buf,
1754 8 /*data atom header */ +
1755 8 /*flags + reserved */ + 2 /*actual data */ );
1756 membuffer_write_atom_name(buf, "data");
1757 membuffer_write_int32(buf, 0); //flags
1758 membuffer_write_int32(buf, 0); //reserved
1759 membuffer_write_int16(buf, value); //value
1762 static uint32_t myatoi(const char *param)
1764 return param ? atoi(param) : 0;
1767 static uint32_t mp4ff_meta_genre_to_index(const char *genrestr)
1770 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1771 if (!stricmp(genrestr, ID3v1GenreList[n]))
1782 static stdmeta_entry stdmetas[] = {
1783 {"\xA9" "nam", "title"},
1784 {"\xA9" "ART", "artist"},
1785 {"\xA9" "wrt", "writer"},
1786 {"\xA9" "alb", "album"},
1787 {"\xA9" "day", "date"},
1788 {"\xA9" "too", "tool"},
1789 {"\xA9" "cmt", "comment"},
1790 {"cpil", "compilation"},
1792 {"aART", "album_artist"},
1795 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1798 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1799 if (!stricmp(name, stdmetas[n].name))
1800 return stdmetas[n].atom;
1805 static void membuffer_write_std_tag(membuffer * buf, const char *name,
1810 /* special check for compilation flag */
1811 if (strcmp(name, "cpil") == 0) {
1815 membuffer_write_int32(buf,
1816 8 /*atom header */ + 8 /*data atom header */ +
1817 8 /*flags + reserved */ + strlen(value));
1818 membuffer_write_atom_name(buf, name);
1819 membuffer_write_int32(buf,
1820 8 /*data atom header */ +
1821 8 /*flags + reserved */ + strlen(value));
1822 membuffer_write_atom_name(buf, "data");
1823 membuffer_write_int32(buf, flags); //flags
1824 membuffer_write_int32(buf, 0); //reserved
1825 membuffer_write(buf, value, strlen(value));
1828 static void membuffer_write_custom_tag(membuffer * buf, const char *name,
1831 membuffer_write_int32(buf,
1832 8 /*atom header */ +
1833 0x1C /*weirdo itunes atom */ +
1834 12 /*name atom header */ + strlen(name) +
1835 16 /*data atom header + flags */ + strlen(value));
1836 membuffer_write_atom_name(buf, "----");
1837 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1838 membuffer_write_atom_name(buf, "mean");
1839 membuffer_write_int32(buf, 0);
1840 membuffer_write(buf, "com.apple.iTunes", 16);
1841 membuffer_write_int32(buf, 12 + strlen(name));
1842 membuffer_write_atom_name(buf, "name");
1843 membuffer_write_int32(buf, 0);
1844 membuffer_write(buf, name, strlen(name));
1845 membuffer_write_int32(buf,
1846 8 /*data atom header */ +
1847 8 /*flags + reserved */ + strlen(value));
1848 membuffer_write_atom_name(buf, "data");
1849 membuffer_write_int32(buf, 1); //flags
1850 membuffer_write_int32(buf, 0); //reserved
1851 membuffer_write(buf, value, strlen(value));
1854 static unsigned membuffer_error(const membuffer * buf)
1859 static void membuffer_free(membuffer * buf)
1866 static unsigned membuffer_get_size(const membuffer * buf)
1868 return buf->written;
1871 static void *membuffer_detach(membuffer * buf)
1878 ret = realloc(buf->data, buf->written);
1889 static uint32_t create_ilst(const mp4ff_metadata_t * data, void **out_buffer,
1890 uint32_t * out_size)
1892 membuffer *buf = membuffer_create();
1894 char *mask = (char *) malloc(data->count);
1895 memset(mask, 0, data->count);
1898 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1899 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1900 const char *genre_ptr = 0, *tempo_ptr = 0;
1901 for (metaptr = 0; metaptr < data->count; metaptr++) {
1902 mp4ff_tag_t *tag = &data->tags[metaptr];
1903 if (!stricmp(tag->item, "tracknumber") || !stricmp(tag->item, "track")) {
1904 if (tracknumber_ptr == 0)
1905 tracknumber_ptr = tag->value;
1907 } else if (!stricmp(tag->item, "totaltracks")) {
1908 if (totaltracks_ptr == 0)
1909 totaltracks_ptr = tag->value;
1911 } else if (!stricmp(tag->item, "discnumber")
1912 || !stricmp(tag->item, "disc")) {
1913 if (discnumber_ptr == 0)
1914 discnumber_ptr = tag->value;
1916 } else if (!stricmp(tag->item, "totaldiscs")) {
1917 if (totaldiscs_ptr == 0)
1918 totaldiscs_ptr = tag->value;
1920 } else if (!stricmp(tag->item, "genre")) {
1922 genre_ptr = tag->value;
1924 } else if (!stricmp(tag->item, "tempo")) {
1926 tempo_ptr = tag->value;
1932 if (tracknumber_ptr)
1933 membuffer_write_track_tag(buf, "trkn",
1934 myatoi(tracknumber_ptr),
1935 myatoi(totaltracks_ptr));
1937 membuffer_write_track_tag(buf, "disk",
1938 myatoi(discnumber_ptr),
1939 myatoi(totaldiscs_ptr));
1941 membuffer_write_int16_tag(buf, "tmpo",
1942 (uint16_t) myatoi(tempo_ptr));
1945 uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
1947 membuffer_write_std_tag(buf, "©gen",
1950 membuffer_write_int16_tag(buf, "gnre",
1955 for (metaptr = 0; metaptr < data->count; metaptr++) {
1956 if (!mask[metaptr]) {
1957 mp4ff_tag_t *tag = &data->tags[metaptr];
1958 const char *std_meta_atom = find_standard_meta(tag->item);
1959 if (std_meta_atom) {
1960 membuffer_write_std_tag(buf, std_meta_atom,
1963 membuffer_write_custom_tag(buf, tag->item,
1971 if (membuffer_error(buf)) {
1972 membuffer_free(buf);
1976 *out_size = membuffer_get_size(buf);
1977 *out_buffer = membuffer_detach(buf);
1978 membuffer_free(buf);
1983 static void membuffer_write_atom(membuffer * buf, const char *name, unsigned size,
1986 membuffer_write_int32(buf, size + 8);
1987 membuffer_write_atom_name(buf, name);
1988 membuffer_write(buf, data, size);
1991 static void *membuffer_get_ptr(const membuffer * buf)
1996 static void membuffer_set_error(membuffer * buf)
2001 static unsigned membuffer_transfer_from_file(membuffer * buf, mp4ff_t * src,
2007 oldsize = membuffer_get_size(buf);
2008 if (membuffer_write(buf, 0, bytes) != bytes)
2011 bufptr = membuffer_get_ptr(buf);
2015 if ((unsigned) mp4ff_read_data(src, (char *) bufptr + oldsize, bytes) !=
2017 membuffer_set_error(buf);
2024 static uint32_t create_meta(const mp4ff_metadata_t * data, void **out_buffer,
2025 uint32_t * out_size)
2031 if (!create_ilst(data, &ilst_buffer, &ilst_size))
2034 buf = membuffer_create();
2036 membuffer_write_int32(buf, 0);
2037 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
2040 *out_size = membuffer_get_size(buf);
2041 *out_buffer = membuffer_detach(buf);
2042 membuffer_free(buf);
2046 static uint32_t create_udta(const mp4ff_metadata_t * data, void **out_buffer,
2047 uint32_t * out_size)
2053 if (!create_meta(data, &meta_buffer, &meta_size))
2056 buf = membuffer_create();
2058 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
2062 *out_size = membuffer_get_size(buf);
2063 *out_buffer = membuffer_detach(buf);
2064 membuffer_free(buf);
2068 static uint32_t fix_byte_order_32(uint32_t src)
2071 uint32_t a, b, c, d;
2074 memcpy(data, &src, sizeof (src));
2075 a = (uint8_t) data[0];
2076 b = (uint8_t) data[1];
2077 c = (uint8_t) data[2];
2078 d = (uint8_t) data[3];
2080 result = (a << 24) | (b << 16) | (c << 8) | d;
2081 return (uint32_t) result;
2084 static uint32_t modify_moov(mp4ff_t * f, const mp4ff_metadata_t * data,
2085 void **out_buffer, uint32_t * out_size)
2087 uint64_t total_base = f->moov_offset + 8;
2088 uint32_t total_size = (uint32_t) (f->moov_size - 8);
2090 uint64_t udta_offset, meta_offset, ilst_offset;
2091 uint32_t udta_size, meta_size, ilst_size;
2093 uint32_t new_ilst_size;
2094 void *new_ilst_buffer;
2099 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
2101 void *new_udta_buffer;
2102 uint32_t new_udta_size;
2103 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
2106 buf = membuffer_create();
2107 mp4ff_set_position(f, total_base);
2108 membuffer_transfer_from_file(buf, f, total_size);
2110 membuffer_write_atom(buf, "udta", new_udta_size,
2113 free(new_udta_buffer);
2115 *out_size = membuffer_get_size(buf);
2116 *out_buffer = membuffer_detach(buf);
2117 membuffer_free(buf);
2120 udta_offset = mp4ff_position(f);
2121 udta_size = mp4ff_read_int32(f);
2122 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
2124 void *new_meta_buffer;
2125 uint32_t new_meta_size;
2126 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
2129 buf = membuffer_create();
2130 mp4ff_set_position(f, total_base);
2131 membuffer_transfer_from_file(buf, f,
2132 (uint32_t)(udta_offset - total_base));
2134 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2135 membuffer_write_atom_name(buf, "udta");
2136 membuffer_transfer_from_file(buf, f, udta_size);
2138 membuffer_write_atom(buf, "meta", new_meta_size,
2140 free(new_meta_buffer);
2142 *out_size = membuffer_get_size(buf);
2143 *out_buffer = membuffer_detach(buf);
2144 membuffer_free(buf);
2147 meta_offset = mp4ff_position(f);
2148 meta_size = mp4ff_read_int32(f);
2149 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2150 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2151 ilst_offset = mp4ff_position(f);
2152 ilst_size = mp4ff_read_int32(f);
2154 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2157 size_delta = new_ilst_size - (ilst_size - 8);
2159 *out_size = total_size + size_delta;
2160 *out_buffer = malloc(*out_size);
2161 if (*out_buffer == 0) {
2162 free(new_ilst_buffer);
2166 p_out = (uint8_t *) * out_buffer;
2168 mp4ff_set_position(f, total_base);
2169 mp4ff_read_data(f, p_out,
2170 (uint32_t) (udta_offset - total_base));
2171 p_out += (uint32_t) (udta_offset - total_base);
2172 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2174 mp4ff_read_data(f, p_out, 4);
2176 mp4ff_read_data(f, p_out,
2177 (uint32_t) (meta_offset - udta_offset - 8));
2178 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2179 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2181 mp4ff_read_data(f, p_out, 4);
2183 mp4ff_read_data(f, p_out,
2184 (uint32_t) (ilst_offset - meta_offset - 8));
2185 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2186 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2188 mp4ff_read_data(f, p_out, 4);
2191 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2192 p_out += new_ilst_size;
2194 mp4ff_set_position(f, ilst_offset + ilst_size);
2195 mp4ff_read_data(f, p_out, (uint32_t) (total_size
2196 - (ilst_offset - total_base) - ilst_size));
2198 free(new_ilst_buffer);
2203 static int32_t mp4ff_write_data(mp4ff_t * f, void *data, uint32_t size)
2207 result = f->stream->write(f->stream->user_data, data, size);
2209 f->current_position += size;
2214 static int32_t mp4ff_write_int32(mp4ff_t * f, const uint32_t data)
2217 uint32_t a, b, c, d;
2220 *(uint32_t *) temp = data;
2221 a = (uint8_t) temp[0];
2222 b = (uint8_t) temp[1];
2223 c = (uint8_t) temp[2];
2224 d = (uint8_t) temp[3];
2226 result = (a << 24) | (b << 16) | (c << 8) | d;
2228 return mp4ff_write_data(f, (uint8_t *) & result, sizeof (result));
2231 static int32_t mp4ff_truncate(mp4ff_t * f)
2233 return f->stream->truncate(f->stream->user_data);
2236 int32_t mp4ff_meta_update(mp4ff_callback_t * f, const mp4ff_metadata_t * data)
2238 void *new_moov_data;
2239 uint32_t new_moov_size;
2241 mp4ff_t *ff = malloc(sizeof (mp4ff_t));
2243 memset(ff, 0, sizeof (mp4ff_t));
2245 mp4ff_set_position(ff, 0);
2249 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2254 /* copy moov atom to end of the file */
2255 if (ff->last_atom != ATOM_MOOV) {
2256 char *free_data = "free";
2258 /* rename old moov to free */
2259 mp4ff_set_position(ff, ff->moov_offset + 4);
2260 mp4ff_write_data(ff, free_data, 4);
2262 mp4ff_set_position(ff, ff->file_size);
2263 mp4ff_write_int32(ff, new_moov_size + 8);
2264 mp4ff_write_data(ff, "moov", 4);
2265 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2267 mp4ff_set_position(ff, ff->moov_offset);
2268 mp4ff_write_int32(ff, new_moov_size + 8);
2269 mp4ff_write_data(ff, "moov", 4);
2270 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2279 /* find a metadata item by name */
2280 /* returns 0 if item found, 1 if no such item */
2281 static int32_t mp4ff_meta_find_by_name(const mp4ff_t * f, const char *item,
2286 for (i = 0; i < f->tags.count; i++) {
2287 if (!stricmp(f->tags.tags[i].item, item)) {
2288 *value = strdup(f->tags.tags[i].value);
2299 int32_t mp4ff_meta_get_artist(const mp4ff_t * f, char **value)
2301 return mp4ff_meta_find_by_name(f, "artist", value);
2304 int32_t mp4ff_meta_get_title(const mp4ff_t * f, char **value)
2306 return mp4ff_meta_find_by_name(f, "title", value);
2309 int32_t mp4ff_meta_get_date(const mp4ff_t * f, char **value)
2311 return mp4ff_meta_find_by_name(f, "date", value);
2314 int32_t mp4ff_meta_get_album(const mp4ff_t * f, char **value)
2316 return mp4ff_meta_find_by_name(f, "album", value);
2319 int32_t mp4ff_meta_get_comment(const mp4ff_t * f, char **value)
2321 return mp4ff_meta_find_by_name(f, "comment", value);